libdrgn: replace symbol index with object index

struct drgn_symbol doesn't really represent a symbol; it's just an
object which hasn't been fully initialized (see c2be52dff0 ("libdrgn:
rename object index to symbol index"), it used to be called a "partial
object"). For stack traces, we're going to have a notion of a symbol
that more closely represents an ELF symbol, so let's get rid of the
temporary struct drgn_symbol representation and just return an object
directly.
This commit is contained in:
Omar Sandoval 2019-07-23 16:26:29 -07:00
parent 74bd59e38a
commit 0c5df56fba
23 changed files with 353 additions and 942 deletions

View File

@ -201,18 +201,19 @@ Programs
filename)``. The filename should be matched with filename)``. The filename should be matched with
:func:`filename_matches()`. This should return a :class:`Type`. :func:`filename_matches()`. This should return a :class:`Type`.
.. method:: add_symbol_finder(fn) .. method:: add_object_finder(fn)
Register a callback for finding symbols in the program. Register a callback for finding objects in the program.
Callbacks are called in reverse order of the order they were added Callbacks are called in reverse order of the order they were added
until the symbol is found. So, more recently added callbacks take until the object is found. So, more recently added callbacks take
precedence. precedence.
:param fn: Callable taking a name (:class:`str`), :param fn: Callable taking a program (:class:`Program`), name
:class:`FindObjectFlags`, and filename (:class:`str` or ``None``): (:class:`str`), :class:`FindObjectFlags`, and filename
``(name, flags, filename)``. The filename should be matched with (:class:`str` or ``None``): ``(prog, name, flags, filename)``. The
:func:`filename_matches()`. This should return a :class:`Symbol`. filename should be matched with :func:`filename_matches()`. This
should return an :class:`Object`.
.. method:: set_core_dump(path) .. method:: set_core_dump(path)
@ -716,61 +717,6 @@ Objects
structure or union type structure or union type
:raises LookupError: If the type does not have a member with the given name :raises LookupError: If the type does not have a member with the given name
.. class:: Symbol(type, *, value=None, address=None, is_enumerator=False, byteorder=None)
A ``Symbol`` represents a variable, constant, or function loaded from a
program's debugging information. It is returned by a symbol finder (see
:meth:`Program.add_symbol_finder()`) and then converted to an
:class:`Object`.
Exactly one of *value*, *address*, or *is_enumerator* must be given. If
*value* is given, then the symbol is a constant with the given value. If
*address* is given, then the symbol is a variable or function at the given
address, and *byteorder* must also be given. If *is_enumerator* is
``True``, then the symbol is an enumerator constant; its value will be
determined from the given type based on the name that was passed to the
symbol finder.
:param Type type: The type of the symbol.
:param value: The constant value of the symbol.
:type value: int or float
:param int address: The address of the symbol in the program.
:param bool is_enumerator: Whether the symbol is an enumerator.
:param str byteorder: The byte order of the symbol. This is only valid for
non-constants. It should be ``'little'`` or ``'big'``.
.. attribute:: type
Type of this symbol
:vartype: Type
.. attribute:: value
Value of this symbol if it is a constant, ``None`` otherwise.
:vartype: int, float, or None
.. attribute:: address
Address of this symbol if it is a variable or function, ``None``
otherwise.
:vartype: int or None
.. attribute:: is_enumerator
Whether this symbol is an enumerator.
:vartype: bool
.. attribute:: byteorder
Byte order of this symbol (either ``'little'`` or ``'big'``) if it is a
variable or function, ``None`` otherwise.
:vartype: str or None
.. _api-reference-types: .. _api-reference-types:
Types Types

View File

@ -55,7 +55,6 @@ from _drgn import (
Program, Program,
ProgramFlags, ProgramFlags,
Qualifiers, Qualifiers,
Symbol,
Type, Type,
TypeKind, TypeKind,
__version__, __version__,
@ -93,7 +92,6 @@ __all__ = [
'Program', 'Program',
'ProgramFlags', 'ProgramFlags',
'Qualifiers', 'Qualifiers',
'Symbol',
'Type', 'Type',
'TypeKind', 'TypeKind',
'array_type', 'array_type',

View File

@ -28,6 +28,8 @@ libdrgnimpl_la_SOURCES = binary_search_tree.h \
memory_reader.h \ memory_reader.h \
object.c \ object.c \
object.h \ object.h \
object_index.c \
object_index.h \
path.c \ path.c \
program.c \ program.c \
program.h \ program.h \
@ -38,8 +40,6 @@ libdrgnimpl_la_SOURCES = binary_search_tree.h \
splay_tree.c \ splay_tree.c \
string_builder.c \ string_builder.c \
string_builder.h \ string_builder.h \
symbol_index.c \
symbol_index.h \
type.c \ type.c \
type.h \ type.h \
type_index.c \ type_index.c \
@ -70,7 +70,6 @@ _drgn_la_SOURCES = python/docstrings.h \
python/module.c \ python/module.c \
python/object.c \ python/object.c \
python/program.c \ python/program.c \
python/symbol.c \
python/test.c \ python/test.c \
python/type.c \ python/type.c \
python/util.c python/util.c

View File

@ -127,7 +127,7 @@ extern struct drgn_error drgn_enomem;
* Non-fatal lookup @ref drgn_error. * Non-fatal lookup @ref drgn_error.
* *
* This has a code of @ref DRGN_ERROR_LOOKUP. It should be returned from a @ref * This has a code of @ref DRGN_ERROR_LOOKUP. It should be returned from a @ref
* drgn_type_find_fn() or @ref drgn_symbol_find_fn() to indicate that the entity * drgn_type_find_fn() or @ref drgn_object_find_fn() to indicate that the entity
* in question could not be found. It does not need to be passed to @ref * in question could not be found. It does not need to be passed to @ref
* drgn_error_destroy() (but it can be). * drgn_error_destroy() (but it can be).
*/ */
@ -1019,93 +1019,38 @@ enum drgn_find_object_flags {
DRGN_FIND_OBJECT_ANY = (1 << 3) - 1, DRGN_FIND_OBJECT_ANY = (1 << 3) - 1,
}; };
/** Kind of symbol. */
enum drgn_symbol_kind {
/**
* A symbol with an address in the program. @ref drgn_symbol::address is
* set to the address.
*/
DRGN_SYMBOL_ADDRESS,
/**
* A symbol with a constant value. One of @ref drgn_symbol::svalue, @ref
* drgn_symbol::uvalue, or @ref drgn_symbol::fvalue is set, depending on
* @ref drgn_symbol::type.
*/
DRGN_SYMBOL_CONSTANT,
/**
* An enumerator. No address or value is set.
*
* A symbol with this kind may be returned by a @ref
* drgn_symbol_find_fn(); it is converted to a constant.
*/
DRGN_SYMBOL_ENUMERATOR,
} __attribute__((packed));
/** /**
* An indexed symbol in a program. * Callback for finding an object.
* *
* This is the result of a lookup by a @ref drgn_symbol_find_fn. It is typically * @param[in] name Name of object. This is @em not null-terminated.
* converted to a @ref drgn_object.
*/
struct drgn_symbol {
/** Type of this symbol. */
struct drgn_type *type;
/** Qualifiers on @ref drgn_symbol::type. */
enum drgn_qualifiers qualifiers;
/** Kind of this symbol. */
enum drgn_symbol_kind kind;
/**
* Whether the symbol is little-endian.
*
* This is ignored for constants and enumerators.
*/
bool little_endian;
union {
/**
* If not a constant or enumerator, the address of the symbol.
*/
uint64_t address;
/** If a signed constant, the value. */
int64_t svalue;
/** If an unsigned constant, the value. */
uint64_t uvalue;
/** If a floating-point constant, the value. */
double fvalue;
};
};
/**
* Callback for finding a symbol.
*
* @param[in] name Name of symbol. This is @em not null-terminated.
* @param[in] name_len Length of @p name. * @param[in] name_len Length of @p name.
* @param[in] filename Filename containing the symbol definition or @c NULL. * @param[in] filename Filename containing the object definition or @c NULL.
* This should be matched with @ref drgn_filename_matches(). * This should be matched with @ref drgn_filename_matches().
* @param[in] flags Flags indicating what kind of object to look for. * @param[in] flags Flags indicating what kind of object to look for.
* @param[in] arg Argument passed to @ref drgn_program_add_symbol_finder(). * @param[in] arg Argument passed to @ref drgn_program_add_object_finder().
* @param[out] ret Returned symbol. * @param[out] ret Returned object. This must only be modified on success.
* @return @c NULL on success, non-@c NULL on error. In particular, if the * @return @c NULL on success, non-@c NULL on error. In particular, if the
* symbol is not found, this should return &@ref drgn_not_found; any other * object is not found, this should return &@ref drgn_not_found; any other
* errors are considered fatal. * errors are considered fatal.
*/ */
typedef struct drgn_error * typedef struct drgn_error *
(*drgn_symbol_find_fn)(const char *name, size_t name_len, const char *filename, (*drgn_object_find_fn)(const char *name, size_t name_len, const char *filename,
enum drgn_find_object_flags flags, void *arg, enum drgn_find_object_flags flags, void *arg,
struct drgn_symbol *ret); struct drgn_object *ret);
/** /**
* Register a symbol finding callback. * Register a object finding callback.
* *
* Callbacks are called in reverse order of the order they were added until the * Callbacks are called in reverse order of the order they were added until the
* symbol is found. So, more recently added callbacks take precedence. * object is found. So, more recently added callbacks take precedence.
* *
* @param[in] fn The callback. * @param[in] fn The callback.
* @param[in] arg Argument to pass to @p fn. * @param[in] arg Argument to pass to @p fn.
* @return @c NULL on success, non-@c NULL on error. * @return @c NULL on success, non-@c NULL on error.
*/ */
struct drgn_error * struct drgn_error *
drgn_program_add_symbol_finder(struct drgn_program *prog, drgn_program_add_object_finder(struct drgn_program *prog,
drgn_symbol_find_fn fn, void *arg); drgn_object_find_fn fn, void *arg);
/** /**
* Set a @ref drgn_program to a core dump. * Set a @ref drgn_program to a core dump.
@ -1250,9 +1195,8 @@ struct drgn_error *drgn_program_find_type(struct drgn_program *prog,
* matched with @ref drgn_filename_matches(). If multiple definitions match, one * matched with @ref drgn_filename_matches(). If multiple definitions match, one
* is returned arbitrarily. * is returned arbitrarily.
* @param[in] flags Flags indicating what kind of object to look for. * @param[in] flags Flags indicating what kind of object to look for.
* @param[out] ret Returned object. This can be @c NULL to check for the * @param[out] ret Returned object. This must have already been initialized with
* object's existence without returning it. If not @c NULL, this must have * @ref drgn_object_init().
* already been initialized with @ref drgn_object_init().
* @return @c NULL on success, non-@c NULL on error. * @return @c NULL on success, non-@c NULL on error.
*/ */
struct drgn_error *drgn_program_find_object(struct drgn_program *prog, struct drgn_error *drgn_program_find_object(struct drgn_program *prog,

View File

@ -10,7 +10,7 @@
#include "dwarf_index.h" #include "dwarf_index.h"
#include "dwarf_info_cache.h" #include "dwarf_info_cache.h"
#include "hash_table.h" #include "hash_table.h"
#include "symbol_index.h" #include "object_index.h"
#include "type_index.h" #include "type_index.h"
#include "vector.h" #include "vector.h"
@ -1406,9 +1406,40 @@ struct drgn_error *drgn_dwarf_type_find(enum drgn_type_kind kind,
} }
static struct drgn_error * static struct drgn_error *
drgn_symbol_from_dwarf_subprogram(struct drgn_dwarf_info_cache *dicache, drgn_object_from_dwarf_enumerator(struct drgn_dwarf_info_cache *dicache,
Dwarf_Die *die, const char *name,
struct drgn_object *ret)
{
struct drgn_error *err;
struct drgn_qualified_type qualified_type;
const struct drgn_type_enumerator *enumerators;
size_t num_enumerators, i;
err = drgn_type_from_dwarf(dicache, die, &qualified_type);
if (err)
return err;
enumerators = drgn_type_enumerators(qualified_type.type);
num_enumerators = drgn_type_num_enumerators(qualified_type.type);
for (i = 0; i < num_enumerators; i++) {
if (strcmp(enumerators[i].name, name) != 0)
continue;
if (drgn_enum_type_is_signed(qualified_type.type)) {
return drgn_object_set_signed(ret, qualified_type,
enumerators[i].svalue, 0);
} else {
return drgn_object_set_unsigned(ret, qualified_type,
enumerators[i].uvalue,
0);
}
}
DRGN_UNREACHABLE();
}
static struct drgn_error *
drgn_object_from_dwarf_subprogram(struct drgn_dwarf_info_cache *dicache,
Dwarf_Die *die, uint64_t bias, Dwarf_Die *die, uint64_t bias,
const char *name, struct drgn_symbol *ret) const char *name, struct drgn_object *ret)
{ {
struct drgn_error *err; struct drgn_error *err;
struct drgn_qualified_type qualified_type; struct drgn_qualified_type qualified_type;
@ -1417,24 +1448,19 @@ drgn_symbol_from_dwarf_subprogram(struct drgn_dwarf_info_cache *dicache,
err = drgn_type_from_dwarf(dicache, die, &qualified_type); err = drgn_type_from_dwarf(dicache, die, &qualified_type);
if (err) if (err)
return err; return err;
ret->type = qualified_type.type;
ret->qualifiers = qualified_type.qualifiers;
ret->kind = DRGN_SYMBOL_ADDRESS;
if (dwarf_lowpc(die, &low_pc) == -1) { if (dwarf_lowpc(die, &low_pc) == -1) {
return drgn_error_format(DRGN_ERROR_LOOKUP, return drgn_error_format(DRGN_ERROR_LOOKUP,
"could not find address of '%s'", "could not find address of '%s'",
name); name);
} }
ret->address = low_pc + bias; return drgn_object_set_reference(ret, qualified_type, low_pc + bias, 0,
ret->little_endian = dwarf_die_is_little_endian(die); 0, dwarf_die_byte_order(die));
return NULL;
} }
static struct drgn_error * static struct drgn_error *
drgn_symbol_from_dwarf_variable(struct drgn_dwarf_info_cache *dicache, drgn_object_from_dwarf_variable(struct drgn_dwarf_info_cache *dicache,
Dwarf_Die *die, uint64_t bias, const char *name, Dwarf_Die *die, uint64_t bias, const char *name,
struct drgn_symbol *ret) struct drgn_object *ret)
{ {
struct drgn_error *err; struct drgn_error *err;
struct drgn_qualified_type qualified_type; struct drgn_qualified_type qualified_type;
@ -1447,10 +1473,6 @@ drgn_symbol_from_dwarf_variable(struct drgn_dwarf_info_cache *dicache,
&qualified_type); &qualified_type);
if (err) if (err)
return err; return err;
ret->type = qualified_type.type;
ret->qualifiers = qualified_type.qualifiers;
ret->kind = DRGN_SYMBOL_ADDRESS;
if (!(attr = dwarf_attr_integrate(die, DW_AT_location, &attr_mem))) { if (!(attr = dwarf_attr_integrate(die, DW_AT_location, &attr_mem))) {
return drgn_error_format(DRGN_ERROR_LOOKUP, return drgn_error_format(DRGN_ERROR_LOOKUP,
"could not find address of '%s'", "could not find address of '%s'",
@ -1458,20 +1480,19 @@ drgn_symbol_from_dwarf_variable(struct drgn_dwarf_info_cache *dicache,
} }
if (dwarf_getlocation(attr, &loc, &nloc)) if (dwarf_getlocation(attr, &loc, &nloc))
return drgn_error_libdw(); return drgn_error_libdw();
if (nloc != 1 || loc[0].atom != DW_OP_addr) { if (nloc != 1 || loc[0].atom != DW_OP_addr) {
return drgn_error_create(DRGN_ERROR_DWARF_FORMAT, return drgn_error_create(DRGN_ERROR_DWARF_FORMAT,
"DW_AT_location has unimplemented operation"); "DW_AT_location has unimplemented operation");
} }
ret->address = loc[0].number + bias; return drgn_object_set_reference(ret, qualified_type,
ret->little_endian = dwarf_die_is_little_endian(die); loc[0].number + bias, 0, 0,
return NULL; dwarf_die_byte_order(die));
} }
struct drgn_error * struct drgn_error *
drgn_dwarf_symbol_find(const char *name, size_t name_len, const char *filename, drgn_dwarf_object_find(const char *name, size_t name_len, const char *filename,
enum drgn_find_object_flags flags, void *arg, enum drgn_find_object_flags flags, void *arg,
struct drgn_symbol *ret) struct drgn_object *ret)
{ {
struct drgn_error *err; struct drgn_error *err;
struct drgn_dwarf_info_cache *dicache = arg; struct drgn_dwarf_info_cache *dicache = arg;
@ -1495,24 +1516,15 @@ drgn_dwarf_symbol_find(const char *name, size_t name_len, const char *filename,
if (!die_matches_filename(&die, filename)) if (!die_matches_filename(&die, filename))
continue; continue;
switch (dwarf_tag(&die)) { switch (dwarf_tag(&die)) {
case DW_TAG_enumeration_type: { case DW_TAG_enumeration_type:
struct drgn_qualified_type qualified_type; return drgn_object_from_dwarf_enumerator(dicache, &die,
name, ret);
ret->kind = DRGN_SYMBOL_ENUMERATOR;
err = drgn_type_from_dwarf(dicache, &die,
&qualified_type);
if (err)
return err;
ret->type = qualified_type.type;
ret->qualifiers = qualified_type.qualifiers;
return NULL;
}
case DW_TAG_subprogram: case DW_TAG_subprogram:
return drgn_symbol_from_dwarf_subprogram(dicache, &die, return drgn_object_from_dwarf_subprogram(dicache, &die,
bias, name, bias, name,
ret); ret);
case DW_TAG_variable: case DW_TAG_variable:
return drgn_symbol_from_dwarf_variable(dicache, &die, return drgn_object_from_dwarf_variable(dicache, &die,
bias, name, ret); bias, name, ret);
default: default:
DRGN_UNREACHABLE(); DRGN_UNREACHABLE();

View File

@ -24,7 +24,7 @@
* *
* @ref drgn_dwarf_info_cache bridges the raw DWARF information indexed by @ref * @ref drgn_dwarf_info_cache bridges the raw DWARF information indexed by @ref
* drgn_dwarf_index to the higher-level @ref drgn_type_index and @ref * drgn_dwarf_index to the higher-level @ref drgn_type_index and @ref
* drgn_symbol_index. * drgn_object_index.
* *
* @{ * @{
*/ */
@ -47,14 +47,12 @@ struct drgn_dwarf_type {
DEFINE_HASH_MAP_TYPE(dwarf_type_map, const void *, struct drgn_dwarf_type); DEFINE_HASH_MAP_TYPE(dwarf_type_map, const void *, struct drgn_dwarf_type);
struct drgn_dwarf_index; struct drgn_dwarf_index;
struct drgn_program;
struct drgn_symbol;
/** /**
* Cache of types and symbols from DWARF debugging information. * Cache of types and objects from DWARF debugging information.
* *
* This is the argument for @ref drgn_dwarf_type_find() and @ref * This is the argument for @ref drgn_dwarf_type_find() and @ref
* drgn_dwarf_symbol_find(). * drgn_dwarf_object_find().
*/ */
struct drgn_dwarf_info_cache { struct drgn_dwarf_info_cache {
/** Index of DWARF debugging information. */ /** Index of DWARF debugging information. */
@ -93,11 +91,11 @@ struct drgn_error *drgn_dwarf_type_find(enum drgn_type_kind kind,
const char *filename, void *arg, const char *filename, void *arg,
struct drgn_qualified_type *ret); struct drgn_qualified_type *ret);
/** @ref drgn_symbol_find_fn() that uses DWARF debugging information. */ /** @ref drgn_object_find_fn() that uses DWARF debugging information. */
struct drgn_error * struct drgn_error *
drgn_dwarf_symbol_find(const char *name, size_t name_len, const char *filename, drgn_dwarf_object_find(const char *name, size_t name_len, const char *filename,
enum drgn_find_object_flags flags, void *arg, enum drgn_find_object_flags flags, void *arg,
struct drgn_symbol *ret); struct drgn_object *ret);
/** @} */ /** @} */

View File

@ -202,6 +202,12 @@ static inline bool dwarf_die_is_little_endian(Dwarf_Die *die)
return elf_is_little_endian(dwarf_getelf(dwarf_cu_getdwarf(die->cu))); return elf_is_little_endian(dwarf_getelf(dwarf_cu_getdwarf(die->cu)));
} }
static inline enum drgn_byte_order dwarf_die_byte_order(Dwarf_Die *die)
{
return (dwarf_die_is_little_endian(die) ?
DRGN_LITTLE_ENDIAN : DRGN_BIG_ENDIAN);
}
bool die_matches_filename(Dwarf_Die *die, const char *filename); bool die_matches_filename(Dwarf_Die *die, const char *filename);
/** /**

View File

@ -228,52 +228,49 @@ out:
} }
static struct drgn_error * static struct drgn_error *
vmcoreinfo_symbol_find(const char *name, size_t name_len, const char *filename, vmcoreinfo_object_find(const char *name, size_t name_len, const char *filename,
enum drgn_find_object_flags flags, void *arg, enum drgn_find_object_flags flags, void *arg,
struct drgn_symbol *ret) struct drgn_object *ret)
{ {
struct drgn_error *err; struct drgn_error *err;
struct drgn_program *prog = arg; struct drgn_program *prog = arg;
if (filename) if (!filename && (flags & DRGN_FIND_OBJECT_CONSTANT)) {
goto not_found; struct drgn_qualified_type qualified_type = {};
if (flags & DRGN_FIND_OBJECT_CONSTANT) {
if (name_len == strlen("PAGE_SHIFT") && if (name_len == strlen("PAGE_SHIFT") &&
memcmp(name, "PAGE_SHIFT", name_len) == 0) { memcmp(name, "PAGE_SHIFT", name_len) == 0) {
err = drgn_type_index_find_primitive(&prog->tindex, err = drgn_type_index_find_primitive(&prog->tindex,
DRGN_C_TYPE_INT, DRGN_C_TYPE_INT,
&ret->type); &qualified_type.type);
if (err) if (err)
return err; return err;
ret->svalue = ctz(prog->vmcoreinfo.page_size); return drgn_object_set_signed(ret, qualified_type,
ctz(prog->vmcoreinfo.page_size),
0);
} else if (name_len == strlen("PAGE_SIZE") && } else if (name_len == strlen("PAGE_SIZE") &&
memcmp(name, "PAGE_SIZE", name_len) == 0) { memcmp(name, "PAGE_SIZE", name_len) == 0) {
err = drgn_type_index_find_primitive(&prog->tindex, err = drgn_type_index_find_primitive(&prog->tindex,
DRGN_C_TYPE_UNSIGNED_LONG, DRGN_C_TYPE_UNSIGNED_LONG,
&ret->type); &qualified_type.type);
if (err) if (err)
return err; return err;
ret->uvalue = prog->vmcoreinfo.page_size; return drgn_object_set_unsigned(ret, qualified_type,
prog->vmcoreinfo.page_size,
0);
} else if (name_len == strlen("PAGE_MASK") && } else if (name_len == strlen("PAGE_MASK") &&
memcmp(name, "PAGE_MASK", name_len) == 0) { memcmp(name, "PAGE_MASK", name_len) == 0) {
err = drgn_type_index_find_primitive(&prog->tindex, err = drgn_type_index_find_primitive(&prog->tindex,
DRGN_C_TYPE_UNSIGNED_LONG, DRGN_C_TYPE_UNSIGNED_LONG,
&ret->type); &qualified_type.type);
if (err) if (err)
return err; return err;
ret->uvalue = ~(prog->vmcoreinfo.page_size - 1); return drgn_object_set_unsigned(ret, qualified_type,
} else { ~(prog->vmcoreinfo.page_size - 1),
goto not_found; 0);
} }
ret->qualifiers = 0;
ret->kind = DRGN_SYMBOL_CONSTANT;
return NULL;
} }
return &drgn_not_found;
not_found:
ret->type = NULL;
return NULL;
} }
struct kernel_module_iterator { struct kernel_module_iterator {
@ -1598,13 +1595,13 @@ linux_kernel_load_default_debug_info(struct drgn_program *prog)
{ {
struct drgn_error *err; struct drgn_error *err;
if (!prog->added_vmcoreinfo_symbol_finder) { if (!prog->added_vmcoreinfo_object_finder) {
err = drgn_program_add_symbol_finder(prog, err = drgn_program_add_object_finder(prog,
vmcoreinfo_symbol_find, vmcoreinfo_object_find,
prog); prog);
if (err) if (err)
return err; return err;
prog->added_vmcoreinfo_symbol_finder = true; prog->added_vmcoreinfo_object_finder = true;
} }
return linux_kernel_load_debug_info_internal(prog, NULL, 0, 0, true); return linux_kernel_load_debug_info_internal(prog, NULL, 0, 0, true);
} }

93
libdrgn/object_index.c Normal file
View File

@ -0,0 +1,93 @@
// Copyright 2018-2019 - Omar Sandoval
// SPDX-License-Identifier: GPL-3.0+
#include <string.h>
#include "internal.h"
#include "object_index.h"
#include "type.h"
void drgn_object_index_init(struct drgn_object_index *oindex)
{
oindex->finders = NULL;
}
void drgn_object_index_deinit(struct drgn_object_index *oindex)
{
struct drgn_object_finder *finder;
finder = oindex->finders;
while (finder) {
struct drgn_object_finder *next = finder->next;
free(finder);
finder = next;
}
}
struct drgn_error *
drgn_object_index_add_finder(struct drgn_object_index *oindex,
drgn_object_find_fn fn, void *arg)
{
struct drgn_object_finder *finder;
finder = malloc(sizeof(*finder));
if (!finder)
return &drgn_enomem;
finder->fn = fn;
finder->arg = arg;
finder->next = oindex->finders;
oindex->finders = finder;
return NULL;
}
struct drgn_error *drgn_object_index_find(struct drgn_object_index *oindex,
const char *name,
const char *filename,
enum drgn_find_object_flags flags,
struct drgn_object *ret)
{
struct drgn_error *err;
size_t name_len;
struct drgn_object_finder *finder;
const char *kind_str;
if ((flags & ~DRGN_FIND_OBJECT_ANY) || !flags) {
return drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT,
"invalid find object flags");
}
name_len = strlen(name);
finder = oindex->finders;
while (finder) {
err = finder->fn(name, name_len, filename, flags, finder->arg,
ret);
if (err != &drgn_not_found)
return err;
finder = finder->next;
}
switch (flags) {
case DRGN_FIND_OBJECT_CONSTANT:
kind_str = "constant ";
break;
case DRGN_FIND_OBJECT_FUNCTION:
kind_str = "function ";
break;
case DRGN_FIND_OBJECT_VARIABLE:
kind_str = "variable ";
break;
default:
kind_str = "";
break;
}
if (filename) {
return drgn_error_format(DRGN_ERROR_LOOKUP,
"could not find %s'%s' in '%s'",
kind_str, name, filename);
} else {
return drgn_error_format(DRGN_ERROR_LOOKUP,
"could not find %s'%s'", kind_str,
name);
}
}

83
libdrgn/object_index.h Normal file
View File

@ -0,0 +1,83 @@
// Copyright 2018-2019 - Omar Sandoval
// SPDX-License-Identifier: GPL-3.0+
/**
* @file
*
* Object lookup.
*
* See @ref ObjectIndex.
*/
#ifndef DRGN_OBJECT_INDEX_H
#define DRGN_OBJECT_INDEX_H
#include "drgn.h"
/**
* @ingroup Internals
*
* @defgroup ObjectIndex Object index
*
* Object lookup.
*
* @ref drgn_object_index provides a common interface for finding objects (e.g.,
* variables, constants, and functions) in a program.
*
* @{
*/
/** Registered callback in a @ref drgn_object_index. */
struct drgn_object_finder {
/** The callback. */
drgn_object_find_fn fn;
/** Argument to pass to @ref drgn_object_finder::fn. */
void *arg;
/** Next callback to try. */
struct drgn_object_finder *next;
};
/**
* Object index.
*
* A object index is used to find objects (variables, constants, and functions)
* by name. The types are found using callbacks which are registered with @ref
* drgn_object_index_add_finder(). @ref drgn_object_index_find() searches for an
* object.
*/
struct drgn_object_index {
/** Callbacks for finding objects. */
struct drgn_object_finder *finders;
};
/** Initialize a @ref drgn_object_index. */
void drgn_object_index_init(struct drgn_object_index *oindex);
/** Deinitialize a @ref drgn_object_index. */
void drgn_object_index_deinit(struct drgn_object_index *oindex);
/** @sa drgn_program_add_object_finder() */
struct drgn_error *
drgn_object_index_add_finder(struct drgn_object_index *oindex,
drgn_object_find_fn fn, void *arg);
/**
* Find an object in a @ref drgn_object_index.
*
* @param[in] oindex Object index.
* @param[in] name Name of the object.
* @param[in] filename Exact filename containing the object definition, or @c
* NULL for any definition.
* @param[in] flags Bitmask of @ref drgn_find_object_flags.
* @param[out] ret Returned object.
* @return @c NULL on success, non-@c NULL on error.
*/
struct drgn_error *drgn_object_index_find(struct drgn_object_index *oindex,
const char *name,
const char *filename,
enum drgn_find_object_flags flags,
struct drgn_object *ret);
/** @} */
#endif /* DRGN_OBJECT_INDEX_H */

View File

@ -19,10 +19,10 @@
#include "language.h" #include "language.h"
#include "linux_kernel.h" #include "linux_kernel.h"
#include "memory_reader.h" #include "memory_reader.h"
#include "object_index.h"
#include "program.h" #include "program.h"
#include "read.h" #include "read.h"
#include "string_builder.h" #include "string_builder.h"
#include "symbol_index.h"
#include "type_index.h" #include "type_index.h"
#include "vector.h" #include "vector.h"
@ -68,7 +68,7 @@ void drgn_program_init(struct drgn_program *prog,
memset(prog, 0, sizeof(*prog)); memset(prog, 0, sizeof(*prog));
drgn_memory_reader_init(&prog->reader); drgn_memory_reader_init(&prog->reader);
drgn_type_index_init(&prog->tindex); drgn_type_index_init(&prog->tindex);
drgn_symbol_index_init(&prog->sindex); drgn_object_index_init(&prog->oindex);
prog->core_fd = -1; prog->core_fd = -1;
prog->arch = DRGN_ARCH_AUTO; prog->arch = DRGN_ARCH_AUTO;
if (arch != DRGN_ARCH_AUTO) if (arch != DRGN_ARCH_AUTO)
@ -77,7 +77,7 @@ void drgn_program_init(struct drgn_program *prog,
void drgn_program_deinit(struct drgn_program *prog) void drgn_program_deinit(struct drgn_program *prog)
{ {
drgn_symbol_index_deinit(&prog->sindex); drgn_object_index_deinit(&prog->oindex);
drgn_type_index_deinit(&prog->tindex); drgn_type_index_deinit(&prog->tindex);
drgn_memory_reader_deinit(&prog->reader); drgn_memory_reader_deinit(&prog->reader);
@ -136,10 +136,10 @@ drgn_program_add_type_finder(struct drgn_program *prog, drgn_type_find_fn fn,
} }
LIBDRGN_PUBLIC struct drgn_error * LIBDRGN_PUBLIC struct drgn_error *
drgn_program_add_symbol_finder(struct drgn_program *prog, drgn_program_add_object_finder(struct drgn_program *prog,
drgn_symbol_find_fn fn, void *arg) drgn_object_find_fn fn, void *arg)
{ {
return drgn_symbol_index_add_finder(&prog->sindex, fn, arg); return drgn_object_index_add_finder(&prog->oindex, fn, arg);
} }
static enum drgn_architecture_flags drgn_architecture_from_elf(Elf *elf) static enum drgn_architecture_flags drgn_architecture_from_elf(Elf *elf)
@ -484,8 +484,8 @@ struct drgn_error *drgn_program_update_dwarf_index(struct drgn_program *prog)
drgn_dwarf_info_cache_destroy(dicache); drgn_dwarf_info_cache_destroy(dicache);
return err; return err;
} }
err = drgn_program_add_symbol_finder(prog, err = drgn_program_add_object_finder(prog,
drgn_dwarf_symbol_find, drgn_dwarf_object_find,
dicache); dicache);
if (err) { if (err) {
drgn_type_index_remove_finder(&prog->tindex); drgn_type_index_remove_finder(&prog->tindex);
@ -753,42 +753,12 @@ drgn_program_find_object(struct drgn_program *prog, const char *name,
enum drgn_find_object_flags flags, enum drgn_find_object_flags flags,
struct drgn_object *ret) struct drgn_object *ret)
{ {
struct drgn_error *err;
struct drgn_symbol sym;
struct drgn_qualified_type qualified_type;
if (ret && ret->prog != prog) { if (ret && ret->prog != prog) {
return drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT, return drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT,
"object is from wrong program"); "object is from wrong program");
} }
return drgn_object_index_find(&prog->oindex, name, filename, flags,
err = drgn_symbol_index_find(&prog->sindex, name, filename, flags, ret);
&sym);
if (err || !ret)
return err;
qualified_type.type = sym.type;
qualified_type.qualifiers = sym.qualifiers;
if (sym.kind == DRGN_SYMBOL_CONSTANT) {
switch (drgn_type_object_kind(sym.type)) {
case DRGN_OBJECT_SIGNED:
return drgn_object_set_signed(ret, qualified_type,
sym.svalue, 0);
case DRGN_OBJECT_UNSIGNED:
return drgn_object_set_unsigned(ret, qualified_type,
sym.uvalue, 0);
case DRGN_OBJECT_FLOAT:
return drgn_object_set_float(ret, qualified_type,
sym.fvalue);
default:
return drgn_type_error("cannot create '%s' constant",
sym.type);
}
} else {
assert(sym.kind == DRGN_SYMBOL_ADDRESS);
return drgn_object_set_reference(ret, qualified_type,
sym.address, 0, 0,
sym.little_endian);
}
} }
LIBDRGN_PUBLIC struct drgn_error * LIBDRGN_PUBLIC struct drgn_error *

View File

@ -15,7 +15,7 @@
#include <elfutils/libdwfl.h> #include <elfutils/libdwfl.h>
#include "memory_reader.h" #include "memory_reader.h"
#include "symbol_index.h" #include "object_index.h"
#include "type_index.h" #include "type_index.h"
/** /**
@ -51,7 +51,7 @@ struct drgn_program {
/** @privatesection */ /** @privatesection */
struct drgn_memory_reader reader; struct drgn_memory_reader reader;
struct drgn_type_index tindex; struct drgn_type_index tindex;
struct drgn_symbol_index sindex; struct drgn_object_index oindex;
struct drgn_memory_file_segment *file_segments; struct drgn_memory_file_segment *file_segments;
size_t num_file_segments; size_t num_file_segments;
/* /*
@ -69,7 +69,7 @@ struct drgn_program {
int core_fd; int core_fd;
enum drgn_program_flags flags; enum drgn_program_flags flags;
enum drgn_architecture_flags arch; enum drgn_architecture_flags arch;
bool added_vmcoreinfo_symbol_finder; bool added_vmcoreinfo_object_finder;
}; };
/** Initialize a @ref drgn_program. */ /** Initialize a @ref drgn_program. */

View File

@ -113,8 +113,8 @@ extern const char drgn_Program___getitem___DOC[];
#define drgn_Program___getitem___DOC (char *)drgn_Program___getitem___DOC #define drgn_Program___getitem___DOC (char *)drgn_Program___getitem___DOC
extern const char drgn_Program_add_memory_segment_DOC[]; extern const char drgn_Program_add_memory_segment_DOC[];
#define drgn_Program_add_memory_segment_DOC (char *)drgn_Program_add_memory_segment_DOC #define drgn_Program_add_memory_segment_DOC (char *)drgn_Program_add_memory_segment_DOC
extern const char drgn_Program_add_symbol_finder_DOC[]; extern const char drgn_Program_add_object_finder_DOC[];
#define drgn_Program_add_symbol_finder_DOC (char *)drgn_Program_add_symbol_finder_DOC #define drgn_Program_add_object_finder_DOC (char *)drgn_Program_add_object_finder_DOC
extern const char drgn_Program_add_type_finder_DOC[]; extern const char drgn_Program_add_type_finder_DOC[];
#define drgn_Program_add_type_finder_DOC (char *)drgn_Program_add_type_finder_DOC #define drgn_Program_add_type_finder_DOC (char *)drgn_Program_add_type_finder_DOC
extern const char drgn_Program_arch_DOC[]; extern const char drgn_Program_arch_DOC[];
@ -163,18 +163,6 @@ extern const char drgn_Qualifiers_RESTRICT_DOC[];
#define drgn_Qualifiers_RESTRICT_DOC (char *)drgn_Qualifiers_RESTRICT_DOC #define drgn_Qualifiers_RESTRICT_DOC (char *)drgn_Qualifiers_RESTRICT_DOC
extern const char drgn_Qualifiers_VOLATILE_DOC[]; extern const char drgn_Qualifiers_VOLATILE_DOC[];
#define drgn_Qualifiers_VOLATILE_DOC (char *)drgn_Qualifiers_VOLATILE_DOC #define drgn_Qualifiers_VOLATILE_DOC (char *)drgn_Qualifiers_VOLATILE_DOC
extern const char drgn_Symbol_DOC[];
#define drgn_Symbol_DOC (char *)drgn_Symbol_DOC
extern const char drgn_Symbol_address_DOC[];
#define drgn_Symbol_address_DOC (char *)drgn_Symbol_address_DOC
extern const char drgn_Symbol_byteorder_DOC[];
#define drgn_Symbol_byteorder_DOC (char *)drgn_Symbol_byteorder_DOC
extern const char drgn_Symbol_is_enumerator_DOC[];
#define drgn_Symbol_is_enumerator_DOC (char *)drgn_Symbol_is_enumerator_DOC
extern const char drgn_Symbol_type_DOC[];
#define drgn_Symbol_type_DOC (char *)drgn_Symbol_type_DOC
extern const char drgn_Symbol_value_DOC[];
#define drgn_Symbol_value_DOC (char *)drgn_Symbol_value_DOC
extern const char drgn_Type_DOC[]; extern const char drgn_Type_DOC[];
#define drgn_Type_DOC (char *)drgn_Type_DOC #define drgn_Type_DOC (char *)drgn_Type_DOC
extern const char drgn_Type_enumerators_DOC[]; extern const char drgn_Type_enumerators_DOC[];

View File

@ -78,12 +78,6 @@ typedef struct {
PyObject *cache; PyObject *cache;
} Program; } Program;
typedef struct {
PyObject_HEAD
struct drgn_symbol sym;
DrgnType *type_obj;
} Symbol;
extern PyObject *Architecture_class; extern PyObject *Architecture_class;
extern PyObject *FindObjectFlags_class; extern PyObject *FindObjectFlags_class;
extern PyObject *PrimitiveType_class; extern PyObject *PrimitiveType_class;
@ -94,7 +88,6 @@ extern PyTypeObject DrgnObject_type;
extern PyTypeObject DrgnType_type; extern PyTypeObject DrgnType_type;
extern PyTypeObject ObjectIterator_type; extern PyTypeObject ObjectIterator_type;
extern PyTypeObject Program_type; extern PyTypeObject Program_type;
extern PyTypeObject Symbol_type;
extern PyObject *FaultError; extern PyObject *FaultError;
extern PyObject *FileFormatError; extern PyObject *FileFormatError;
extern PyObject *MissingDebugInfoError; extern PyObject *MissingDebugInfoError;

View File

@ -159,11 +159,6 @@ DRGNPY_PUBLIC PyMODINIT_FUNC PyInit__drgn(void)
Py_INCREF(&DrgnType_type); Py_INCREF(&DrgnType_type);
PyModule_AddObject(m, "Type", (PyObject *)&DrgnType_type); PyModule_AddObject(m, "Type", (PyObject *)&DrgnType_type);
if (PyType_Ready(&Symbol_type) < 0)
goto err;
Py_INCREF(&Symbol_type);
PyModule_AddObject(m, "Symbol", (PyObject *)&Symbol_type);
return m; return m;
err: err:

View File

@ -281,15 +281,15 @@ static PyObject *Program_add_type_finder(Program *self, PyObject *args,
Py_RETURN_NONE; Py_RETURN_NONE;
} }
static struct drgn_error *py_symbol_find_fn(const char *name, size_t name_len, static struct drgn_error *py_object_find_fn(const char *name, size_t name_len,
const char *filename, const char *filename,
enum drgn_find_object_flags flags, enum drgn_find_object_flags flags,
void *arg, struct drgn_symbol *ret) void *arg, struct drgn_object *ret)
{ {
struct drgn_error *err; struct drgn_error *err;
PyGILState_STATE gstate; PyGILState_STATE gstate;
PyObject *name_obj, *flags_obj; PyObject *name_obj, *flags_obj;
PyObject *sym_obj; PyObject *obj;
gstate = PyGILState_Ensure(); gstate = PyGILState_Ensure();
name_obj = PyUnicode_FromStringAndSize(name, name_len); name_obj = PyUnicode_FromStringAndSize(name, name_len);
@ -303,32 +303,27 @@ static struct drgn_error *py_symbol_find_fn(const char *name, size_t name_len,
err = drgn_error_from_python(); err = drgn_error_from_python();
goto out_name_obj; goto out_name_obj;
} }
sym_obj = PyObject_CallFunction(PyTuple_GET_ITEM(arg, 1), "OOs", obj = PyObject_CallFunction(PyTuple_GET_ITEM(arg, 1), "OOOs",
name_obj, flags_obj, filename); PyTuple_GET_ITEM(arg, 0), name_obj,
if (!sym_obj) { flags_obj, filename);
if (!obj) {
err = drgn_error_from_python(); err = drgn_error_from_python();
goto out_flags_obj; goto out_flags_obj;
} }
if (sym_obj == Py_None) { if (obj == Py_None) {
err = &drgn_not_found; err = &drgn_not_found;
goto out_sym_obj; goto out_obj;
} }
if (!PyObject_TypeCheck(sym_obj, &Symbol_type)) { if (!PyObject_TypeCheck(obj, &DrgnObject_type)) {
PyErr_SetString(PyExc_TypeError, PyErr_SetString(PyExc_TypeError,
"symbol find callback must return Symbol or None"); "object find callback must return Object or None");
err = drgn_error_from_python(); err = drgn_error_from_python();
goto out_sym_obj; goto out_obj;
}
if (Program_hold_type((Program *)PyTuple_GET_ITEM(arg, 0),
((Symbol *)sym_obj)->type_obj) == -1) {
err = drgn_error_from_python();
goto out_sym_obj;
} }
*ret = ((Symbol *)sym_obj)->sym; err = drgn_object_copy(ret, &((DrgnObject *)obj)->obj);
err = NULL; out_obj:
out_sym_obj: Py_DECREF(obj);
Py_DECREF(sym_obj);
out_flags_obj: out_flags_obj:
Py_DECREF(flags_obj); Py_DECREF(flags_obj);
out_name_obj: out_name_obj:
@ -338,7 +333,7 @@ out_gstate:
return err; return err;
} }
static PyObject *Program_add_symbol_finder(Program *self, PyObject *args, static PyObject *Program_add_object_finder(Program *self, PyObject *args,
PyObject *kwds) PyObject *kwds)
{ {
static char *keywords[] = {"fn", NULL}; static char *keywords[] = {"fn", NULL};
@ -346,7 +341,7 @@ static PyObject *Program_add_symbol_finder(Program *self, PyObject *args,
PyObject *fn, *arg; PyObject *fn, *arg;
int ret; int ret;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:add_symbol_finder", if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:add_object_finder",
keywords, &fn)) keywords, &fn))
return NULL; return NULL;
@ -363,7 +358,7 @@ static PyObject *Program_add_symbol_finder(Program *self, PyObject *args,
if (ret == -1) if (ret == -1)
return NULL; return NULL;
err = drgn_program_add_symbol_finder(&self->prog, py_symbol_find_fn, err = drgn_program_add_object_finder(&self->prog, py_object_find_fn,
arg); arg);
if (err) if (err)
return set_drgn_error(err); return set_drgn_error(err);
@ -711,6 +706,7 @@ static int Program_contains(Program *self, PyObject *key)
{ {
struct drgn_error *err; struct drgn_error *err;
const char *name; const char *name;
struct drgn_object tmp;
bool clear; bool clear;
if (!PyUnicode_Check(key)) { if (!PyUnicode_Check(key)) {
@ -722,11 +718,13 @@ static int Program_contains(Program *self, PyObject *key)
if (!name) if (!name)
return -1; return -1;
drgn_object_init(&tmp, &self->prog);
clear = set_drgn_in_python(); clear = set_drgn_in_python();
err = drgn_program_find_object(&self->prog, name, NULL, err = drgn_program_find_object(&self->prog, name, NULL,
DRGN_FIND_OBJECT_ANY, NULL); DRGN_FIND_OBJECT_ANY, &tmp);
if (clear) if (clear)
clear_drgn_in_python(); clear_drgn_in_python();
drgn_object_deinit(&tmp);
if (err) { if (err) {
if (err->code == DRGN_ERROR_LOOKUP) { if (err->code == DRGN_ERROR_LOOKUP) {
drgn_error_destroy(err); drgn_error_destroy(err);
@ -756,8 +754,8 @@ static PyMethodDef Program_methods[] = {
METH_VARARGS | METH_KEYWORDS, drgn_Program_add_memory_segment_DOC}, METH_VARARGS | METH_KEYWORDS, drgn_Program_add_memory_segment_DOC},
{"add_type_finder", (PyCFunction)Program_add_type_finder, {"add_type_finder", (PyCFunction)Program_add_type_finder,
METH_VARARGS | METH_KEYWORDS, drgn_Program_add_type_finder_DOC}, METH_VARARGS | METH_KEYWORDS, drgn_Program_add_type_finder_DOC},
{"add_symbol_finder", (PyCFunction)Program_add_symbol_finder, {"add_object_finder", (PyCFunction)Program_add_object_finder,
METH_VARARGS | METH_KEYWORDS, drgn_Program_add_symbol_finder_DOC}, METH_VARARGS | METH_KEYWORDS, drgn_Program_add_object_finder_DOC},
{"set_core_dump", (PyCFunction)Program_set_core_dump, {"set_core_dump", (PyCFunction)Program_set_core_dump,
METH_VARARGS | METH_KEYWORDS, drgn_Program_set_core_dump_DOC}, METH_VARARGS | METH_KEYWORDS, drgn_Program_set_core_dump_DOC},
{"set_kernel", (PyCFunction)Program_set_kernel, METH_NOARGS, {"set_kernel", (PyCFunction)Program_set_kernel, METH_NOARGS,

View File

@ -1,302 +0,0 @@
// Copyright 2018-2019 - Omar Sandoval
// SPDX-License-Identifier: GPL-3.0+
#include "drgnpy.h"
#include "../symbol_index.h"
Symbol *Symbol_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
{
static char *keywords[] = {
"type", "value", "address", "is_enumerator", "byteorder", NULL,
};
DrgnType *type_obj;
struct drgn_qualified_type qualified_type;
PyObject *value_obj = Py_None, *address_obj = Py_None;
int is_enumerator = 0;
const char *byteorder = NULL;
Symbol *sym;
int num_given;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|$OOpz:Symbol", keywords,
&DrgnType_type, &type_obj, &value_obj,
&address_obj, &is_enumerator,
&byteorder)) {
fprintf(stderr, "ya\n");
return NULL;
}
qualified_type.type = type_obj->type;
qualified_type.qualifiers = type_obj->qualifiers;
num_given = ((value_obj != Py_None) + (address_obj != Py_None) +
is_enumerator);
if (num_given == 0) {
PyErr_SetString(PyExc_ValueError,
"one of value, address, or is_enumerator is required");
return NULL;
} else if (num_given > 1) {
PyErr_SetString(PyExc_ValueError,
"only one of value, address, or is_enumerator may be given");
return NULL;
}
if (address_obj != Py_None && !byteorder) {
PyErr_SetString(PyExc_ValueError,
"byteorder must be given with address");
return NULL;
} else if (address_obj == Py_None && byteorder) {
PyErr_SetString(PyExc_ValueError,
"byteorder may only be given with address");
return NULL;
}
sym = (Symbol *)subtype->tp_alloc(subtype, 0);
if (!sym)
return NULL;
sym->sym.type = type_obj->type;
sym->sym.qualifiers = type_obj->qualifiers;
if (value_obj != Py_None) {
enum drgn_object_kind kind;
sym->sym.kind = DRGN_SYMBOL_CONSTANT;
kind = drgn_type_object_kind(qualified_type.type);
switch (kind) {
case DRGN_OBJECT_SIGNED:
case DRGN_OBJECT_UNSIGNED: {
union {
int64_t svalue;
uint64_t uvalue;
} tmp;
if (!PyNumber_Check(value_obj)) {
set_error_type_name("'%s' value must be number",
qualified_type);
goto err;
}
tmp.uvalue = PyLong_AsUnsignedLongLongMask(value_obj);
if (tmp.uvalue == (unsigned long long)-1 &&
PyErr_Occurred())
goto err;
if (kind == DRGN_OBJECT_SIGNED)
sym->sym.svalue = tmp.svalue;
else
sym->sym.uvalue = tmp.uvalue;
break;
}
case DRGN_OBJECT_FLOAT: {
double fvalue;
if (!PyNumber_Check(value_obj)) {
set_error_type_name("'%s' value must be number",
qualified_type);
goto err;
}
fvalue = PyFloat_AsDouble(value_obj);
if (fvalue == -1.0 && PyErr_Occurred())
goto err;
sym->sym.fvalue = fvalue;
break;
}
default:
set_error_type_name("cannot have '%s' constant",
qualified_type);
goto err;
}
} else if (address_obj != Py_None) {
sym->sym.kind = DRGN_SYMBOL_ADDRESS;
sym->sym.address =
index_arg(address_obj, "address must be integer");
if (sym->sym.address == (unsigned long long)-1 &&
PyErr_Occurred())
goto err;
if (parse_byteorder(byteorder, &sym->sym.little_endian) == -1)
goto err;
} else {
sym->sym.kind = DRGN_SYMBOL_ENUMERATOR;
}
Py_INCREF(type_obj);
sym->type_obj = type_obj;
return sym;
err:
Py_DECREF(sym);
return NULL;
}
static void Symbol_dealloc(Symbol *self)
{
Py_XDECREF(self->type_obj);
Py_TYPE(self)->tp_free((PyObject *)self);
}
static struct drgn_error *drgn_symbol_eq(struct drgn_symbol *a,
struct drgn_symbol *b,
bool *ret)
{
struct drgn_error *err;
struct drgn_qualified_type type_a, type_b;
if (a->kind != b->kind) {
*ret = false;
return NULL;
}
type_a.type = a->type;
type_a.qualifiers = a->qualifiers;
type_b.type = b->type;
type_b.qualifiers = b->qualifiers;
err = drgn_qualified_type_eq(type_a, type_b, ret);
if (err || !*ret)
return err;
switch (a->kind) {
case DRGN_SYMBOL_CONSTANT:
switch (drgn_type_object_kind(a->type)) {
case DRGN_OBJECT_SIGNED:
*ret = a->svalue == b->svalue;
break;
case DRGN_OBJECT_UNSIGNED:
*ret = a->uvalue == b->uvalue;
break;
case DRGN_OBJECT_FLOAT:
*ret = a->fvalue == b->fvalue;
break;
default:
return drgn_type_error("cannot create '%s' constant",
a->type);
}
return NULL;
case DRGN_SYMBOL_ADDRESS:
*ret = (a->address == b->address &&
a->little_endian == b->little_endian);
return NULL;
case DRGN_SYMBOL_ENUMERATOR:
*ret = true;
return NULL;
}
DRGN_UNREACHABLE();
}
static PyObject *Symbol_richcompare(Symbol *left, PyObject *right, int op)
{
struct drgn_error *err;
bool clear, ret;
if (!PyObject_TypeCheck(right, &Symbol_type) ||
(op != Py_EQ && op != Py_NE))
Py_RETURN_NOTIMPLEMENTED;
clear = set_drgn_in_python();
err = drgn_symbol_eq(&left->sym, &((Symbol *)right)->sym, &ret);
if (clear)
clear_drgn_in_python();
if (err)
return set_drgn_error(err);
if (op == Py_NE)
ret = !ret;
if (ret)
Py_RETURN_TRUE;
else
Py_RETURN_FALSE;
}
static PyObject *Symbol_get_type(Symbol *self, void *arg)
{
Py_INCREF(self->type_obj);
return (PyObject *)self->type_obj;
}
static PyObject *Symbol_get_value(Symbol *self, void *arg)
{
if (self->sym.kind != DRGN_SYMBOL_CONSTANT)
Py_RETURN_NONE;
switch (drgn_type_object_kind(self->sym.type)) {
case DRGN_OBJECT_SIGNED:
return PyLong_FromLongLong(self->sym.svalue);
case DRGN_OBJECT_UNSIGNED:
return PyLong_FromUnsignedLongLong(self->sym.uvalue);
case DRGN_OBJECT_FLOAT:
return PyFloat_FromDouble(self->sym.fvalue);
default:
DRGN_UNREACHABLE();
}
}
static PyObject *Symbol_get_address(Symbol *self, void *arg)
{
if (self->sym.kind == DRGN_SYMBOL_ADDRESS)
return PyLong_FromUnsignedLongLong(self->sym.address);
else
Py_RETURN_NONE;
}
static PyObject *Symbol_get_is_enumerator(Symbol *self, void *arg)
{
if (self->sym.kind == DRGN_SYMBOL_ENUMERATOR)
Py_RETURN_TRUE;
else
Py_RETURN_FALSE;
}
static PyObject *Symbol_get_byteorder(Symbol *self, void *arg)
{
if (self->sym.kind == DRGN_SYMBOL_ADDRESS)
return byteorder_string(self->sym.little_endian);
else
Py_RETURN_NONE;
}
static PyGetSetDef Symbol_getset[] = {
{"type", (getter)Symbol_get_type, NULL, drgn_Symbol_type_DOC},
{"value", (getter)Symbol_get_value, NULL, drgn_Symbol_value_DOC},
{"address", (getter)Symbol_get_address, NULL, drgn_Symbol_address_DOC},
{"is_enumerator", (getter)Symbol_get_is_enumerator, NULL,
drgn_Symbol_is_enumerator_DOC},
{"byteorder", (getter)Symbol_get_byteorder, NULL,
drgn_Symbol_byteorder_DOC},
{},
};
PyTypeObject Symbol_type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_drgn.Symbol", /* tp_name */
sizeof(Symbol), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)Symbol_dealloc, /* tp_dealloc */
NULL, /* tp_print */
NULL, /* tp_getattr */
NULL, /* tp_setattr */
NULL, /* tp_as_async */
NULL, /* tp_repr */
NULL, /* tp_as_number */
NULL, /* tp_as_sequence */
NULL, /* tp_as_mapping */
NULL, /* tp_hash */
NULL, /* tp_call */
NULL, /* tp_str */
NULL, /* tp_getattro */
NULL, /* tp_setattro */
NULL, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
drgn_Symbol_DOC, /* tp_doc */
NULL, /* tp_traverse */
NULL, /* tp_clear */
(richcmpfunc)Symbol_richcompare, /* tp_richcompare */
0, /* tp_weaklistoffset */
NULL, /* tp_iter */
NULL, /* tp_iternext */
NULL, /* tp_methods */
NULL, /* tp_members */
Symbol_getset, /* tp_getset */
NULL, /* tp_base */
NULL, /* tp_dict */
NULL, /* tp_descr_get */
NULL, /* tp_descr_set */
0, /* tp_dictoffset */
NULL, /* tp_init */
NULL, /* tp_alloc */
(newfunc)Symbol_new, /* tp_new */
};

View File

@ -1,146 +0,0 @@
// Copyright 2018-2019 - Omar Sandoval
// SPDX-License-Identifier: GPL-3.0+
#include <string.h>
#include "internal.h"
#include "symbol_index.h"
#include "type.h"
void drgn_symbol_index_init(struct drgn_symbol_index *sindex)
{
sindex->finders = NULL;
}
void drgn_symbol_index_deinit(struct drgn_symbol_index *sindex)
{
struct drgn_symbol_finder *finder;
finder = sindex->finders;
while (finder) {
struct drgn_symbol_finder *next = finder->next;
free(finder);
finder = next;
}
}
struct drgn_error *
drgn_symbol_index_add_finder(struct drgn_symbol_index *sindex,
drgn_symbol_find_fn fn, void *arg)
{
struct drgn_symbol_finder *finder;
finder = malloc(sizeof(*finder));
if (!finder)
return &drgn_enomem;
finder->fn = fn;
finder->arg = arg;
finder->next = sindex->finders;
sindex->finders = finder;
return NULL;
}
static struct drgn_error *drgn_symbol_from_enumerator(struct drgn_symbol *sym,
const char *name)
{
const struct drgn_type_enumerator *enumerators;
size_t num_enumerators, i;
if (drgn_type_kind(sym->type) != DRGN_TYPE_ENUM) {
return drgn_type_error("'%s' is not an enumerated type",
sym->type);
}
enumerators = drgn_type_enumerators(sym->type);
num_enumerators = drgn_type_num_enumerators(sym->type);
for (i = 0; i < num_enumerators; i++) {
if (strcmp(enumerators[i].name, name) != 0)
continue;
if (drgn_enum_type_is_signed(sym->type))
sym->svalue = enumerators[i].svalue;
else
sym->uvalue = enumerators[i].uvalue;
sym->kind = DRGN_SYMBOL_CONSTANT;
return NULL;
}
return drgn_error_format(DRGN_ERROR_LOOKUP,
"could not find '%s' in 'enum %s'", name,
drgn_type_is_anonymous(sym->type) ?
"<anonymous>" : drgn_type_tag(sym->type));
}
struct drgn_error *drgn_symbol_index_find(struct drgn_symbol_index *sindex,
const char *name,
const char *filename,
enum drgn_find_object_flags flags,
struct drgn_symbol *ret)
{
struct drgn_error *err;
size_t name_len;
struct drgn_symbol_finder *finder;
const char *kind_str;
if ((flags & ~DRGN_FIND_OBJECT_ANY) || !flags) {
return drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT,
"invalid find object flags");
}
name_len = strlen(name);
finder = sindex->finders;
while (finder) {
err = finder->fn(name, name_len, filename, flags, finder->arg,
ret);
if (!err) {
if (ret->kind == DRGN_SYMBOL_ENUMERATOR ||
ret->kind == DRGN_SYMBOL_CONSTANT) {
if (!(flags & DRGN_FIND_OBJECT_CONSTANT))
goto wrong_kind;
} else if (!(flags &
(DRGN_FIND_OBJECT_FUNCTION | DRGN_FIND_OBJECT_VARIABLE))) {
goto wrong_kind;
}
if (ret->kind == DRGN_SYMBOL_ENUMERATOR) {
err = drgn_symbol_from_enumerator(ret, name);
if (err)
return err;
}
if (ret->kind == DRGN_SYMBOL_CONSTANT) {
ret->little_endian = (__BYTE_ORDER__ ==
__ORDER_LITTLE_ENDIAN__);
}
return NULL;
}
if (err != &drgn_not_found)
return err;
finder = finder->next;
}
switch (flags) {
case DRGN_FIND_OBJECT_CONSTANT:
kind_str = "constant ";
break;
case DRGN_FIND_OBJECT_FUNCTION:
kind_str = "function ";
break;
case DRGN_FIND_OBJECT_VARIABLE:
kind_str = "variable ";
break;
default:
kind_str = "";
break;
}
if (filename) {
return drgn_error_format(DRGN_ERROR_LOOKUP,
"could not find %s'%s' in '%s'",
kind_str, name, filename);
} else {
return drgn_error_format(DRGN_ERROR_LOOKUP,
"could not find %s'%s'", kind_str,
name);
}
wrong_kind:
return drgn_error_create(DRGN_ERROR_TYPE,
"symbol find callback returned wrong kind of symbol");
}

View File

@ -1,83 +0,0 @@
// Copyright 2018-2019 - Omar Sandoval
// SPDX-License-Identifier: GPL-3.0+
/**
* @file
*
* Symbol lookup.
*
* See @ref SymbolIndex.
*/
#ifndef DRGN_SYMBOL_INDEX_H
#define DRGN_SYMBOL_INDEX_H
#include "drgn.h"
/**
* @ingroup Internals
*
* @defgroup SymbolIndex Symbol index
*
* Symbol lookup.
*
* @ref drgn_symbol_index provides a common interface for finding symbols (e.g.,
* variables, constants, and functions) in a program.
*
* @{
*/
/** Registered callback in a @ref drgn_symbol_index. */
struct drgn_symbol_finder {
/** The callback. */
drgn_symbol_find_fn fn;
/** Argument to pass to @ref drgn_symbol_finder::fn. */
void *arg;
/** Next callback to try. */
struct drgn_symbol_finder *next;
};
/**
* Symbol index.
*
* A symbol index is used to find symbols (variables, constants, and functions)
* by name. The types are found using callbacks which are registered with @ref
* drgn_symbol_index_add_finder(). @ref drgn_symbol_index_find() searches for an
* symbol.
*/
struct drgn_symbol_index {
/** Callbacks for finding symbols. */
struct drgn_symbol_finder *finders;
};
/** Initialize a @ref drgn_symbol_index. */
void drgn_symbol_index_init(struct drgn_symbol_index *sindex);
/** Deinitialize a @ref drgn_symbol_index. */
void drgn_symbol_index_deinit(struct drgn_symbol_index *sindex);
/** @sa drgn_program_add_symbol_finder() */
struct drgn_error *
drgn_symbol_index_add_finder(struct drgn_symbol_index *sindex,
drgn_symbol_find_fn fn, void *arg);
/**
* Find a symbol in a @ref drgn_symbol_index.
*
* @param[in] sindex Symbol index.
* @param[in] name Name of the symbol.
* @param[in] filename Exact filename containing the symbol definition, or @c
* NULL for any definition.
* @param[in] flags Bitmask of @ref drgn_find_object_flags.
* @param[out] ret Returned symbol.
* @return @c NULL on success, non-@c NULL on error.
*/
struct drgn_error *drgn_symbol_index_find(struct drgn_symbol_index *sindex,
const char *name,
const char *filename,
enum drgn_find_object_flags flags,
struct drgn_symbol *ret);
/** @} */
#endif /* DRGN_SYMBOL_INDEX_H */

View File

@ -1,5 +1,5 @@
import functools import functools
from typing import NamedTuple, Optional from typing import Any, NamedTuple, Optional
import unittest import unittest
from drgn import ( from drgn import (
@ -7,6 +7,7 @@ from drgn import (
FindObjectFlags, FindObjectFlags,
Object, Object,
Program, Program,
Type,
TypeKind, TypeKind,
enum_type, enum_type,
float_type, float_type,
@ -48,7 +49,14 @@ def mock_memory_read(data, address, count, offset, physical):
return data[offset:offset + count] return data[offset:offset + count]
def mock_program(arch=MOCK_ARCH, *, segments=None, types=None, symbols=None): class MockObject(NamedTuple):
name: str
type: Type
address: Optional[int] = None
value: Any = None
def mock_program(arch=MOCK_ARCH, *, segments=None, types=None, objects=None):
def mock_find_type(kind, name, filename): def mock_find_type(kind, name, filename):
if filename: if filename:
return None return None
@ -65,22 +73,22 @@ def mock_program(arch=MOCK_ARCH, *, segments=None, types=None, symbols=None):
return type return type
return None return None
def mock_symbol_find(name, flags, filename): def mock_object_find(prog, name, flags, filename):
if filename: if filename:
return None return None
for sym_name, sym in symbols: for obj in objects:
if sym_name == name: if obj.name == name:
if sym.value is not None or sym.is_enumerator: if obj.value is not None:
if flags & FindObjectFlags.CONSTANT: if flags & FindObjectFlags.CONSTANT:
break break
elif sym.type.kind == TypeKind.FUNCTION: elif obj.type.kind == TypeKind.FUNCTION:
if flags & FindObjectFlags.FUNCTION: if flags & FindObjectFlags.FUNCTION:
break break
elif flags & FindObjectFlags.VARIABLE: elif flags & FindObjectFlags.VARIABLE:
break break
else: else:
return None return None
return sym return Object(prog, obj.type, address=obj.address, value=obj.value)
prog = Program(arch) prog = Program(arch)
if segments is not None: if segments is not None:
@ -95,8 +103,8 @@ def mock_program(arch=MOCK_ARCH, *, segments=None, types=None, symbols=None):
functools.partial(mock_memory_read, segment.buf), True) functools.partial(mock_memory_read, segment.buf), True)
if types is not None: if types is not None:
prog.add_type_finder(mock_find_type) prog.add_type_finder(mock_find_type)
if symbols is not None: if objects is not None:
prog.add_symbol_finder(mock_symbol_find) prog.add_object_finder(mock_object_find)
return prog return prog

View File

@ -28,6 +28,7 @@ from tests import (
line_segment_type, line_segment_type,
mock_program, mock_program,
option_type, option_type,
pid_type,
point_type, point_type,
) )

View File

@ -13,7 +13,6 @@ from drgn import (
Program, Program,
ProgramFlags, ProgramFlags,
Qualifiers, Qualifiers,
Symbol,
array_type, array_type,
bool_type, bool_type,
float_type, float_type,
@ -27,6 +26,7 @@ from tests import (
MOCK_32BIT_ARCH, MOCK_32BIT_ARCH,
MOCK_ARCH, MOCK_ARCH,
MockMemorySegment, MockMemorySegment,
MockObject,
ObjectTestCase, ObjectTestCase,
color_type, color_type,
mock_program, mock_program,
@ -473,22 +473,23 @@ class TestTypes(unittest.TestCase):
class TestObjects(ObjectTestCase): class TestObjects(ObjectTestCase):
def test_invalid_finder(self): def test_invalid_finder(self):
self.assertRaises(TypeError, mock_program().add_symbol_finder, 'foo') self.assertRaises(TypeError, mock_program().add_object_finder, 'foo')
prog = mock_program() prog = mock_program()
prog.add_symbol_finder(lambda name, flags, filename: 'foo') prog.add_object_finder(lambda prog, name, flags, filename: 'foo')
self.assertRaises(TypeError, prog.object, 'foo') self.assertRaises(TypeError, prog.object, 'foo')
def test_not_found(self): def test_not_found(self):
prog = mock_program() prog = mock_program()
self.assertRaises(LookupError, prog.object, 'foo') self.assertRaises(LookupError, prog.object, 'foo')
prog.add_symbol_finder(lambda name, flags, filename: None) prog.add_object_finder(lambda prog, name, flags, filename: None)
self.assertRaises(LookupError, prog.object, 'foo') self.assertRaises(LookupError, prog.object, 'foo')
self.assertFalse('foo' in prog) self.assertFalse('foo' in prog)
def test_constant(self): def test_constant(self):
sym = Symbol(int_type('int', 4, True), value=4096) mock_obj = MockObject('PAGE_SIZE', int_type('int', 4, True),
prog = mock_program(symbols=[('PAGE_SIZE', sym)]) value=4096)
prog = mock_program(objects=[mock_obj])
self.assertEqual(prog['PAGE_SIZE'], self.assertEqual(prog['PAGE_SIZE'],
Object(prog, int_type('int', 4, True), value=4096)) Object(prog, int_type('int', 4, True), value=4096))
self.assertEqual(prog.object('PAGE_SIZE', FindObjectFlags.CONSTANT), self.assertEqual(prog.object('PAGE_SIZE', FindObjectFlags.CONSTANT),
@ -496,9 +497,9 @@ class TestObjects(ObjectTestCase):
self.assertTrue('PAGE_SIZE' in prog) self.assertTrue('PAGE_SIZE' in prog)
def test_function(self): def test_function(self):
sym = Symbol(function_type(void_type(), (), False), address=0xffff0000, mock_obj = MockObject('func', function_type(void_type(), (), False),
byteorder='little') address=0xffff0000)
prog = mock_program(symbols=[('func', sym)]) prog = mock_program(objects=[mock_obj])
self.assertEqual(prog['func'], self.assertEqual(prog['func'],
Object(prog, function_type(void_type(), (), False), Object(prog, function_type(void_type(), (), False),
address=0xffff0000)) address=0xffff0000))
@ -507,9 +508,9 @@ class TestObjects(ObjectTestCase):
self.assertTrue('func' in prog) self.assertTrue('func' in prog)
def test_variable(self): def test_variable(self):
sym = Symbol(int_type('int', 4, True), address=0xffff0000, mock_obj = MockObject('counter', int_type('int', 4, True),
byteorder='little') address=0xffff0000)
prog = mock_program(symbols=[('counter', sym)]) prog = mock_program(objects=[mock_obj])
self.assertEqual(prog['counter'], self.assertEqual(prog['counter'],
Object(prog, int_type('int', 4, True), Object(prog, int_type('int', 4, True),
address=0xffff0000)) address=0xffff0000))

View File

@ -1,88 +0,0 @@
import unittest
from drgn import enum_type, float_type, int_type
from _drgn import Symbol
from tests import color_type, line_segment_type, point_type
class TestSymbol(unittest.TestCase):
def test_init(self):
self.assertRaisesRegex(ValueError, 'one of.*is required', Symbol,
int_type('int', 4, True))
self.assertRaisesRegex(ValueError, 'only one of', Symbol,
int_type('int', 4, True), value=1, address=0)
self.assertRaisesRegex(ValueError, 'only one of', Symbol,
int_type('int', 4, True), value=1,
is_enumerator=True)
self.assertRaisesRegex(ValueError, 'only one of', Symbol,
int_type('int', 4, True), address=0,
is_enumerator=True)
self.assertRaisesRegex(ValueError,
'byteorder must be given with address', Symbol,
int_type('int', 4, True), address=0)
self.assertRaisesRegex(ValueError,
'byteorder may only be given with address',
Symbol, int_type('int', 4, True), value=1,
byteorder='little')
def test_constant(self):
sym = Symbol(int_type('int', 4, True), value=1)
self.assertEqual(sym.type, int_type('int', 4, True))
self.assertEqual(sym.value, 1)
self.assertIsNone(sym.address)
self.assertFalse(sym.is_enumerator)
self.assertIsNone(sym.byteorder)
self.assertRaises(TypeError, Symbol, int_type('int', 4, True),
value='foo')
self.assertEqual(sym, Symbol(int_type('int', 4, True), value=1))
self.assertNotEqual(sym, Symbol(int_type('int', 4, True), value=2))
self.assertNotEqual(sym, Symbol(int_type('unsigned int', 4, False),
value=1))
sym = Symbol(float_type('double', 8), value=3.14)
self.assertEqual(sym.type, float_type('double', 8))
self.assertEqual(sym.value, 3.14)
self.assertIsNone(sym.address)
self.assertFalse(sym.is_enumerator)
self.assertIsNone(sym.byteorder)
self.assertRaises(TypeError, Symbol, float_type('double', 8),
value='foo')
self.assertNotEqual(sym, Symbol(float_type('double', 8),
address=0xffff0000,
byteorder='little'))
def test_address(self):
sym = Symbol(point_type, address=0xffff0000, byteorder='little')
self.assertEqual(sym.type, point_type)
self.assertIsNone(sym.value)
self.assertEqual(sym.address, 0xffff0000)
self.assertFalse(sym.is_enumerator)
self.assertEqual(sym.byteorder, 'little')
self.assertRaises(TypeError, Symbol, point_type, address='foo',
byteorder='little')
self.assertEqual(sym, Symbol(point_type, address=0xffff0000,
byteorder='little'))
self.assertNotEqual(sym, Symbol(line_segment_type, address=0xffff0000,
byteorder='little'))
self.assertNotEqual(sym, Symbol(point_type, address=0xfffeffe0,
byteorder='little'))
self.assertNotEqual(sym, Symbol(point_type, address=0xffff0000,
byteorder='big'))
self.assertEqual(
Symbol(point_type, address=0xffff0000, byteorder='big').byteorder,
'big')
def test_enumerator(self):
sym = Symbol(color_type, is_enumerator=True)
self.assertEqual(sym.type, color_type)
self.assertIsNone(sym.value)
self.assertIsNone(sym.value)
self.assertTrue(sym.is_enumerator)
self.assertIsNone(sym.byteorder)
self.assertEqual(sym, Symbol(color_type, is_enumerator=True))
self.assertNotEqual(sym, Symbol(enum_type('color2'), is_enumerator=True))
self.assertNotEqual(sym, Symbol(color_type, value=1))
def test_cmp(self):
self.assertNotEqual(Symbol(color_type, is_enumerator=True), 1)
self.assertNotEqual(1, Symbol(color_type, is_enumerator=True))