libdrgn: Add find_symbol_by_name to look up ELF symbols

This commit is contained in:
Jay Kamat 2020-02-07 08:43:05 -08:00 committed by Omar Sandoval
parent 054cb54a01
commit 31d544949f
4 changed files with 96 additions and 12 deletions

View File

@ -128,11 +128,13 @@ Programs
:raises LookupError: if no objects with the given name are found in
the given file
.. method:: symbol(address)
.. method:: symbol(address_or_name, /)
Get the symbol containing the given address.
Get the symbol containing the given address, or the global symbol with
the given name.
:param int address: The address.
:param address_or_name: The address or name.
:type address_or_name: str or int
:rtype: Symbol
:raises LookupError: if no symbol contains the given address

View File

@ -1325,6 +1325,17 @@ struct drgn_error *
drgn_program_find_symbol_by_address(struct drgn_program *prog, uint64_t address,
struct drgn_symbol **ret);
/**
* Get the symbol corresponding to the given name.
*
* @param[out] ret The returned symbol. It should be freed with @ref
* drgn_symbol_destroy().
* @return @c NULL on success, non-@c NULL on error.
*/
struct drgn_error *drgn_program_find_symbol_by_name(struct drgn_program *prog,
const char *name,
struct drgn_symbol **ret);
/** Element type and size. */
struct drgn_element_info {
/** Type of the element. */

View File

@ -961,6 +961,70 @@ drgn_program_find_symbol_by_address(struct drgn_program *prog, uint64_t address,
return NULL;
}
struct find_symbol_by_name_arg {
const char *name;
struct drgn_symbol **ret;
struct drgn_error *err;
bool bad_symtabs;
};
static int find_symbol_by_name_cb(Dwfl_Module *dwfl_module, void **userdatap,
const char *module_name, Dwarf_Addr base,
void *cb_arg)
{
struct find_symbol_by_name_arg *arg = cb_arg;
int symtab_len, i;
symtab_len = dwfl_module_getsymtab(dwfl_module);
i = dwfl_module_getsymtab_first_global(dwfl_module);
if (symtab_len == -1 || i == -1) {
arg->bad_symtabs = true;
return DWARF_CB_OK;
}
for (; i < symtab_len; i++) {
GElf_Sym elf_sym;
GElf_Addr elf_addr;
const char *name;
name = dwfl_module_getsym_info(dwfl_module, i, &elf_sym,
&elf_addr, NULL, NULL, NULL);
if (name && strcmp(arg->name, name) == 0) {
struct drgn_symbol *sym;
sym = malloc(sizeof(*sym));
if (sym) {
sym->name = name;
sym->address = elf_addr;
sym->size = elf_sym.st_size;
*arg->ret = sym;
} else {
arg->err = &drgn_enomem;
}
return DWARF_CB_ABORT;
}
}
return DWARF_CB_OK;
}
LIBDRGN_PUBLIC struct drgn_error *
drgn_program_find_symbol_by_name(struct drgn_program *prog,
const char *name, struct drgn_symbol **ret)
{
struct find_symbol_by_name_arg arg = {
.name = name,
.ret = ret,
};
if (prog->_dicache &&
dwfl_getmodules(prog->_dicache->dindex.dwfl, find_symbol_by_name_cb,
&arg, 0))
return arg.err;
return drgn_error_format(DRGN_ERROR_LOOKUP,
"could not find symbol with name '%s'%s", name,
arg.bad_symtabs ?
" (could not get some symbol tables)" : "");
}
LIBDRGN_PUBLIC struct drgn_error *
drgn_program_element_info(struct drgn_program *prog, struct drgn_type *type,
struct drgn_element_info *ret)

View File

@ -718,20 +718,27 @@ static StackTrace *Program_stack_trace(Program *self, PyObject *args,
return ret;
}
static PyObject *Program_symbol(Program *self, PyObject *args, PyObject *kwds)
static PyObject *Program_symbol(Program *self, PyObject *arg)
{
static char *keywords[] = {"address", NULL};
struct drgn_error *err;
struct index_arg address = {};
struct drgn_symbol *sym;
PyObject *ret;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&", keywords,
index_converter, &address))
return NULL;
if (PyUnicode_Check(arg)) {
const char *name;
err = drgn_program_find_symbol_by_address(&self->prog, address.uvalue,
&sym);
name = PyUnicode_AsUTF8(arg);
if (!name)
return NULL;
err = drgn_program_find_symbol_by_name(&self->prog, name, &sym);
} else {
struct index_arg address = {};
if (!index_converter(arg, &address))
return NULL;
err = drgn_program_find_symbol_by_address(&self->prog,
address.uvalue, &sym);
}
if (err)
return set_drgn_error(err);
ret = Symbol_wrap(sym, self);
@ -868,7 +875,7 @@ static PyMethodDef Program_methods[] = {
METH_VARARGS | METH_KEYWORDS, drgn_Program_variable_DOC},
{"stack_trace", (PyCFunction)Program_stack_trace,
METH_VARARGS | METH_KEYWORDS, drgn_Program_stack_trace_DOC},
{"symbol", (PyCFunction)Program_symbol, METH_VARARGS | METH_KEYWORDS,
{"symbol", (PyCFunction)Program_symbol, METH_O,
drgn_Program_symbol_DOC},
{},
};