aboutsummaryrefslogtreecommitdiff
path: root/accel/tcg
diff options
context:
space:
mode:
authorIlya Leoshkevich <iii@linux.ibm.com>2023-01-12 16:20:12 +0100
committerRichard Henderson <richard.henderson@linaro.org>2023-01-16 10:14:12 -1000
commit7c10cb38ccb86a0e56fff32bb348aa4b34e17e10 (patch)
tree56788d06412a4ffaaf1b42ae6531671415ba6181 /accel/tcg
parentda91c19202420d61e3316f5a9d4c2d66bfbaff04 (diff)
accel/tcg: Add debuginfo support
Add libdw-based functions for loading and querying debuginfo. Load debuginfo from the system and the linux-user loaders. This is useful for the upcoming perf support, which can then put human-readable guest symbols instead of raw guest PCs into perfmap and jitdump files. Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com> Message-Id: <20230112152013.125680-3-iii@linux.ibm.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'accel/tcg')
-rw-r--r--accel/tcg/debuginfo.c96
-rw-r--r--accel/tcg/debuginfo.h77
-rw-r--r--accel/tcg/meson.build1
3 files changed, 174 insertions, 0 deletions
diff --git a/accel/tcg/debuginfo.c b/accel/tcg/debuginfo.c
new file mode 100644
index 0000000000..71c66d04d1
--- /dev/null
+++ b/accel/tcg/debuginfo.c
@@ -0,0 +1,96 @@
+/*
+ * Debug information support.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#include "qemu/osdep.h"
+#include "qemu/lockable.h"
+
+#include <elfutils/libdwfl.h>
+
+#include "debuginfo.h"
+
+static QemuMutex lock;
+static Dwfl *dwfl;
+static const Dwfl_Callbacks dwfl_callbacks = {
+ .find_elf = NULL,
+ .find_debuginfo = dwfl_standard_find_debuginfo,
+ .section_address = NULL,
+ .debuginfo_path = NULL,
+};
+
+__attribute__((constructor))
+static void debuginfo_init(void)
+{
+ qemu_mutex_init(&lock);
+}
+
+void debuginfo_report_elf(const char *name, int fd, uint64_t bias)
+{
+ QEMU_LOCK_GUARD(&lock);
+
+ if (dwfl) {
+ dwfl_report_begin_add(dwfl);
+ } else {
+ dwfl = dwfl_begin(&dwfl_callbacks);
+ }
+
+ if (dwfl) {
+ dwfl_report_elf(dwfl, name, name, fd, bias, true);
+ dwfl_report_end(dwfl, NULL, NULL);
+ }
+}
+
+void debuginfo_lock(void)
+{
+ qemu_mutex_lock(&lock);
+}
+
+void debuginfo_query(struct debuginfo_query *q, size_t n)
+{
+ const char *symbol, *file;
+ Dwfl_Module *dwfl_module;
+ Dwfl_Line *dwfl_line;
+ GElf_Off dwfl_offset;
+ GElf_Sym dwfl_sym;
+ size_t i;
+ int line;
+
+ if (!dwfl) {
+ return;
+ }
+
+ for (i = 0; i < n; i++) {
+ dwfl_module = dwfl_addrmodule(dwfl, q[i].address);
+ if (!dwfl_module) {
+ continue;
+ }
+
+ if (q[i].flags & DEBUGINFO_SYMBOL) {
+ symbol = dwfl_module_addrinfo(dwfl_module, q[i].address,
+ &dwfl_offset, &dwfl_sym,
+ NULL, NULL, NULL);
+ if (symbol) {
+ q[i].symbol = symbol;
+ q[i].offset = dwfl_offset;
+ }
+ }
+
+ if (q[i].flags & DEBUGINFO_LINE) {
+ dwfl_line = dwfl_module_getsrc(dwfl_module, q[i].address);
+ if (dwfl_line) {
+ file = dwfl_lineinfo(dwfl_line, NULL, &line, 0, NULL, NULL);
+ if (file) {
+ q[i].file = file;
+ q[i].line = line;
+ }
+ }
+ }
+ }
+}
+
+void debuginfo_unlock(void)
+{
+ qemu_mutex_unlock(&lock);
+}
diff --git a/accel/tcg/debuginfo.h b/accel/tcg/debuginfo.h
new file mode 100644
index 0000000000..7542cfe6e0
--- /dev/null
+++ b/accel/tcg/debuginfo.h
@@ -0,0 +1,77 @@
+/*
+ * Debug information support.
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ */
+
+#ifndef ACCEL_TCG_DEBUGINFO_H
+#define ACCEL_TCG_DEBUGINFO_H
+
+/*
+ * Debuginfo describing a certain address.
+ */
+struct debuginfo_query {
+ uint64_t address; /* Input: address. */
+ int flags; /* Input: debuginfo subset. */
+ const char *symbol; /* Symbol that the address is part of. */
+ uint64_t offset; /* Offset from the symbol. */
+ const char *file; /* Source file associated with the address. */
+ int line; /* Line number in the source file. */
+};
+
+/*
+ * Debuginfo subsets.
+ */
+#define DEBUGINFO_SYMBOL BIT(1)
+#define DEBUGINFO_LINE BIT(2)
+
+#if defined(CONFIG_TCG) && defined(CONFIG_LIBDW)
+/*
+ * Load debuginfo for the specified guest ELF image.
+ * Return true on success, false on failure.
+ */
+void debuginfo_report_elf(const char *name, int fd, uint64_t bias);
+
+/*
+ * Take the debuginfo lock.
+ */
+void debuginfo_lock(void);
+
+/*
+ * Fill each on N Qs with the debuginfo about Q->ADDRESS as specified by
+ * Q->FLAGS:
+ *
+ * - DEBUGINFO_SYMBOL: update Q->SYMBOL and Q->OFFSET. If symbol debuginfo is
+ * missing, then leave them as is.
+ * - DEBUINFO_LINE: update Q->FILE and Q->LINE. If line debuginfo is missing,
+ * then leave them as is.
+ *
+ * This function must be called under the debuginfo lock. The results can be
+ * accessed only until the debuginfo lock is released.
+ */
+void debuginfo_query(struct debuginfo_query *q, size_t n);
+
+/*
+ * Release the debuginfo lock.
+ */
+void debuginfo_unlock(void);
+#else
+static inline void debuginfo_report_elf(const char *image_name, int image_fd,
+ uint64_t load_bias)
+{
+}
+
+static inline void debuginfo_lock(void)
+{
+}
+
+static inline void debuginfo_query(struct debuginfo_query *q, size_t n)
+{
+}
+
+static inline void debuginfo_unlock(void)
+{
+}
+#endif
+
+#endif
diff --git a/accel/tcg/meson.build b/accel/tcg/meson.build
index 75e1dffb4d..55b3b4dd7e 100644
--- a/accel/tcg/meson.build
+++ b/accel/tcg/meson.build
@@ -12,6 +12,7 @@ tcg_ss.add(files(
tcg_ss.add(when: 'CONFIG_USER_ONLY', if_true: files('user-exec.c'))
tcg_ss.add(when: 'CONFIG_SOFTMMU', if_false: files('user-exec-stub.c'))
tcg_ss.add(when: 'CONFIG_PLUGIN', if_true: [files('plugin-gen.c')])
+tcg_ss.add(when: libdw, if_true: files('debuginfo.c'))
specific_ss.add_all(when: 'CONFIG_TCG', if_true: tcg_ss)
specific_ss.add(when: ['CONFIG_SOFTMMU', 'CONFIG_TCG'], if_true: files(