Skip to content

Commit

Permalink
Provide source code info for Symbol
Browse files Browse the repository at this point in the history
For function symbols, provide the source code file,
line number, and column.

Signed-off-by: Paul Zuchowski <[email protected]>
  • Loading branch information
PaulZ-98 committed Jul 14, 2022
1 parent a000eed commit 2181fe6
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 0 deletions.
8 changes: 8 additions & 0 deletions _drgn.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -1529,6 +1529,14 @@ class Symbol:
kind: SymbolKind
"""Kind of entity represented by this symbol."""

def source(self, long) -> Tuple[str, int, int]:
"""
Get the source code location of this function at the given offset.
:return: Location as a ``(filename, line, column)`` triple.
:raises LookupError: if the source code location is not available
"""

class SymbolBinding(enum.Enum):
"""
A ``SymbolBinding`` describes the linkage behavior and visibility of a
Expand Down
19 changes: 19 additions & 0 deletions libdrgn/debug_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,25 @@ static int drgn_dwfl_module_removed(Dwfl_Module *dwfl_module, void *userdatap,
return DWARF_CB_OK;
}

struct drgn_debug_info_module *
drgn_debug_info_module_byaddress(struct drgn_debug_info *dbinfo, uint64_t addr)
{

for (struct drgn_debug_info_module_table_iterator it =
drgn_debug_info_module_table_first(&dbinfo->modules); it.entry; ) {
struct drgn_debug_info_module *module = *it.entry;
do {
struct drgn_debug_info_module *next = module->next;
if (!next)
it = drgn_debug_info_module_table_next(it);
if (addr >= module->start && addr <= module->end)
return module;
module = next;
} while (module);
}
return NULL;
}

static void drgn_debug_info_free_modules(struct drgn_debug_info *dbinfo,
bool finish_indexing, bool free_all)
{
Expand Down
4 changes: 4 additions & 0 deletions libdrgn/debug_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,10 @@ drgn_debug_info_buffer_init(struct drgn_debug_info_buffer *buffer,
buffer->scn = scn;
}

struct drgn_debug_info_module *
drgn_debug_info_module_byaddress(struct drgn_debug_info *dbinfo, uint64_t addr);


DEFINE_HASH_TABLE_TYPE(drgn_debug_info_module_table,
struct drgn_debug_info_module *)

Expand Down
9 changes: 9 additions & 0 deletions libdrgn/drgn.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -2675,6 +2675,15 @@ void drgn_symbol_destroy(struct drgn_symbol *sym);
*/
void drgn_symbols_destroy(struct drgn_symbol **syms, size_t count);

/** Get the source code file, line, and column of a @ref drgn_symbol */
struct drgn_error *drgn_symbol_source(struct drgn_symbol *sym,
struct drgn_program *prog,
unsigned long offset,
size_t size,
char *src_file_ret,
int *line_num_ret,
int *line_col_ret);

/**
* Get the name of a @ref drgn_symbol.
*
Expand Down
28 changes: 28 additions & 0 deletions libdrgn/python/symbol.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,27 @@ static PyObject *Symbol_richcompare(Symbol *self, PyObject *other, int op)
Py_RETURN_BOOL(ret);
}

#define MAXPATHLEN 256

static PyObject *Symbol_source(Symbol *self, PyObject *arg)
{
char source[MAXPATHLEN];
Program *prgm = ((Symbol *)self)->prog;
struct drgn_program *p = &prgm->prog;
int ln_num = 0;
int ln_col = 0;
unsigned long offset = PyLong_AsLong(arg);

struct drgn_error *err;
err = drgn_symbol_source(((Symbol *)self)->sym, p,
offset, sizeof(source),
source, &ln_num, &ln_col);
if (err)
return set_drgn_error(err);

return Py_BuildValue("sii", source, ln_num, ln_col);
}

static PyObject *Symbol_get_name(Symbol *self, void *arg)
{
return PyUnicode_FromString(drgn_symbol_name(self->sym));
Expand Down Expand Up @@ -93,6 +114,12 @@ static PyObject *Symbol_repr(Symbol *self)

}

static PyMethodDef Symbol_methods[] = {
{"source", (PyCFunction)Symbol_source, METH_O,
drgn_Symbol_source_DOC},
{},
};

static PyGetSetDef Symbol_getset[] = {
{"name", (getter)Symbol_get_name, NULL, drgn_Symbol_name_DOC},
{"address", (getter)Symbol_get_address, NULL, drgn_Symbol_address_DOC},
Expand All @@ -111,5 +138,6 @@ PyTypeObject Symbol_type = {
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_doc = drgn_Symbol_DOC,
.tp_richcompare = (richcmpfunc)Symbol_richcompare,
.tp_methods = Symbol_methods,
.tp_getset = Symbol_getset,
};
44 changes: 44 additions & 0 deletions libdrgn/symbol.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,14 @@
#include <elf.h>
#include <stdlib.h>
#include <string.h>
#include <dwarf.h>
#include <elfutils/libdw.h>
#include <elfutils/libdwfl.h>

#include "debug_info.h"
#include "drgn.h"
#include "error.h"
#include "program.h"
#include "symbol.h"
#include "util.h"

Expand Down Expand Up @@ -40,6 +46,44 @@ void drgn_symbol_from_elf(const char *name, uint64_t address,
ret->kind = DRGN_SYMBOL_KIND_UNKNOWN;
}

LIBDRGN_PUBLIC struct drgn_error *
drgn_symbol_source(struct drgn_symbol *sym,
struct drgn_program *prog,
unsigned long offset,
size_t size,
char *src_file_ret,
int *line_num_ret,
int *line_col_ret)
{
if (sym->kind != DRGN_SYMBOL_KIND_FUNC)
return drgn_error_create(DRGN_ERROR_LOOKUP,
"symbol is not a function");

unsigned long sym_address = sym->address + offset;
struct drgn_debug_info_module *dim;
dim = drgn_debug_info_module_byaddress(prog->dbinfo, sym_address);
if (dim == NULL)
return drgn_error_create(DRGN_ERROR_LOOKUP,
"could not locate module from function address");


Dwfl_Line *line = dwfl_module_getsrc(dim->dwfl_module, sym_address);
if (line == NULL)
return drgn_error_create(DRGN_ERROR_LOOKUP,
"could not obtain source code information");

const char *src;
int lineno, linecol;
if ((src = dwfl_lineinfo(line, &sym_address, &lineno, &linecol,
NULL, NULL)) != NULL) {
strncpy(src_file_ret, src, size);
*line_num_ret = lineno;
*line_col_ret = linecol;
}

return NULL;
}

LIBDRGN_PUBLIC const char *drgn_symbol_name(struct drgn_symbol *sym)
{
return sym->name;
Expand Down

0 comments on commit 2181fe6

Please sign in to comment.