Browse Source
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>pull/232/head
committed by
Richard Henderson
7 changed files with 191 additions and 0 deletions
@ -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); |
|||
} |
|||
@ -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 |
|||
Loading…
Reference in new issue