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, optional
line number, and optional column.

Signed-off-by: Paul Zuchowski <pzuchowski@datto.com>
  • Loading branch information
PaulZ-98 committed Jun 9, 2022
1 parent a000eed commit 0d2772a
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 0 deletions.
14 changes: 14 additions & 0 deletions _drgn.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -1529,6 +1529,20 @@ class Symbol:
kind: SymbolKind
"""Kind of entity represented by this symbol."""

def source(self, offset: int, line_number: bool, line_column: bool) -> str:
"""
Return a string with the source code file, optional line number and
optional column for the function symbol plus offset.
>>> s = prog.symbol('mutex_lock')
>>> s.source(offset=0, line_number=True, line_column=False)
'/build/linux-hwe-5.8-Ox7OXf/linux-hwe-5.8-5.8.0/kernel/locking/mutex.c: 280'
param: offset: Offset of instruction from function base address.
param: line_number: Include source code line number.
param: line_column: Include source code column.
"""

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 */
void 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
44 changes: 44 additions & 0 deletions libdrgn/python/symbol.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,43 @@ static PyObject *Symbol_richcompare(Symbol *self, PyObject *other, int op)
Py_RETURN_BOOL(ret);
}

static PyObject *Symbol_source(PyObject *self, PyObject *args, PyObject* kwargs)
{
char source[256];
char formatted[296];
Program *prgm = ((Symbol *)self)->prog;
struct drgn_program *p = &prgm->prog;
int ln_num = 0;
int ln_col = 0;
int offset, line_number, line_column;
static char* keywords[] = {"offset", "line_number", "line_column", NULL};

if (!PyArg_ParseTupleAndKeywords(args,
kwargs,
"iii",
keywords,
&offset,
&line_number,
&line_column))
return NULL;

(void) drgn_symbol_source(((Symbol *)self)->sym, p,
(unsigned long)offset,
sizeof(source), source,
&ln_num, &ln_col);
/* we do not print the column without the line number */
if (line_number && line_column)
snprintf(formatted, sizeof(formatted), "%s: %d:%d",
source, ln_num, ln_col);
else if (line_number)
snprintf(formatted, sizeof(formatted), "%s: %d",
source, ln_num);
else
snprintf(formatted, sizeof(formatted), "%s", source);

return PyUnicode_FromString(formatted);
}

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

}

static PyMethodDef Symbol_methods[] = {
{"source", (PyCFunction)Symbol_source, METH_VARARGS | METH_KEYWORDS,
"get source code reference for symbol"},
{},
};

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 +154,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,
};
38 changes: 38 additions & 0 deletions libdrgn/symbol.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@
#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 "program.h"
#include "symbol.h"
#include "util.h"

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

LIBDRGN_PUBLIC void 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;

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;

Dwfl_Line *line = dwfl_module_getsrc(dim->dwfl_module, sym_address);
if (line == NULL)
return;

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;
}

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

0 comments on commit 0d2772a

Please sign in to comment.