mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-22 17:23:06 +00:00
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:
parent
74bd59e38a
commit
0c5df56fba
@ -201,18 +201,19 @@ Programs
|
||||
filename)``. The filename should be matched with
|
||||
: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
|
||||
until the symbol is found. So, more recently added callbacks take
|
||||
until the object is found. So, more recently added callbacks take
|
||||
precedence.
|
||||
|
||||
:param fn: Callable taking a name (:class:`str`),
|
||||
:class:`FindObjectFlags`, and filename (:class:`str` or ``None``):
|
||||
``(name, flags, filename)``. The filename should be matched with
|
||||
:func:`filename_matches()`. This should return a :class:`Symbol`.
|
||||
:param fn: Callable taking a program (:class:`Program`), name
|
||||
(:class:`str`), :class:`FindObjectFlags`, and filename
|
||||
(:class:`str` or ``None``): ``(prog, name, flags, filename)``. The
|
||||
filename should be matched with :func:`filename_matches()`. This
|
||||
should return an :class:`Object`.
|
||||
|
||||
.. method:: set_core_dump(path)
|
||||
|
||||
@ -716,61 +717,6 @@ Objects
|
||||
structure or union type
|
||||
: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:
|
||||
|
||||
Types
|
||||
|
@ -55,7 +55,6 @@ from _drgn import (
|
||||
Program,
|
||||
ProgramFlags,
|
||||
Qualifiers,
|
||||
Symbol,
|
||||
Type,
|
||||
TypeKind,
|
||||
__version__,
|
||||
@ -93,7 +92,6 @@ __all__ = [
|
||||
'Program',
|
||||
'ProgramFlags',
|
||||
'Qualifiers',
|
||||
'Symbol',
|
||||
'Type',
|
||||
'TypeKind',
|
||||
'array_type',
|
||||
|
@ -28,6 +28,8 @@ libdrgnimpl_la_SOURCES = binary_search_tree.h \
|
||||
memory_reader.h \
|
||||
object.c \
|
||||
object.h \
|
||||
object_index.c \
|
||||
object_index.h \
|
||||
path.c \
|
||||
program.c \
|
||||
program.h \
|
||||
@ -38,8 +40,6 @@ libdrgnimpl_la_SOURCES = binary_search_tree.h \
|
||||
splay_tree.c \
|
||||
string_builder.c \
|
||||
string_builder.h \
|
||||
symbol_index.c \
|
||||
symbol_index.h \
|
||||
type.c \
|
||||
type.h \
|
||||
type_index.c \
|
||||
@ -70,7 +70,6 @@ _drgn_la_SOURCES = python/docstrings.h \
|
||||
python/module.c \
|
||||
python/object.c \
|
||||
python/program.c \
|
||||
python/symbol.c \
|
||||
python/test.c \
|
||||
python/type.c \
|
||||
python/util.c
|
||||
|
@ -127,7 +127,7 @@ extern struct drgn_error drgn_enomem;
|
||||
* Non-fatal lookup @ref drgn_error.
|
||||
*
|
||||
* 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
|
||||
* drgn_error_destroy() (but it can be).
|
||||
*/
|
||||
@ -1019,93 +1019,38 @@ enum drgn_find_object_flags {
|
||||
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.
|
||||
* Callback for finding an object.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* This is the result of a lookup by a @ref drgn_symbol_find_fn. It is typically
|
||||
* 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 Name of object. This is @em not null-terminated.
|
||||
* @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().
|
||||
* @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[out] ret Returned symbol.
|
||||
* @param[in] arg Argument passed to @ref drgn_program_add_object_finder().
|
||||
* @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
|
||||
* 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.
|
||||
*/
|
||||
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,
|
||||
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
|
||||
* 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] arg Argument to pass to @p fn.
|
||||
* @return @c NULL on success, non-@c NULL on error.
|
||||
*/
|
||||
struct drgn_error *
|
||||
drgn_program_add_symbol_finder(struct drgn_program *prog,
|
||||
drgn_symbol_find_fn fn, void *arg);
|
||||
drgn_program_add_object_finder(struct drgn_program *prog,
|
||||
drgn_object_find_fn fn, void *arg);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* is returned arbitrarily.
|
||||
* @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
|
||||
* object's existence without returning it. If not @c NULL, this must have
|
||||
* already been initialized with @ref drgn_object_init().
|
||||
* @param[out] ret Returned object. This must have already been initialized with
|
||||
* @ref drgn_object_init().
|
||||
* @return @c NULL on success, non-@c NULL on error.
|
||||
*/
|
||||
struct drgn_error *drgn_program_find_object(struct drgn_program *prog,
|
||||
|
@ -10,7 +10,7 @@
|
||||
#include "dwarf_index.h"
|
||||
#include "dwarf_info_cache.h"
|
||||
#include "hash_table.h"
|
||||
#include "symbol_index.h"
|
||||
#include "object_index.h"
|
||||
#include "type_index.h"
|
||||
#include "vector.h"
|
||||
|
||||
@ -1406,9 +1406,40 @@ struct drgn_error *drgn_dwarf_type_find(enum drgn_type_kind kind,
|
||||
}
|
||||
|
||||
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,
|
||||
const char *name, struct drgn_symbol *ret)
|
||||
const char *name, struct drgn_object *ret)
|
||||
{
|
||||
struct drgn_error *err;
|
||||
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);
|
||||
if (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) {
|
||||
return drgn_error_format(DRGN_ERROR_LOOKUP,
|
||||
"could not find address of '%s'",
|
||||
name);
|
||||
}
|
||||
ret->address = low_pc + bias;
|
||||
ret->little_endian = dwarf_die_is_little_endian(die);
|
||||
return NULL;
|
||||
return drgn_object_set_reference(ret, qualified_type, low_pc + bias, 0,
|
||||
0, dwarf_die_byte_order(die));
|
||||
}
|
||||
|
||||
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,
|
||||
struct drgn_symbol *ret)
|
||||
struct drgn_object *ret)
|
||||
{
|
||||
struct drgn_error *err;
|
||||
struct drgn_qualified_type qualified_type;
|
||||
@ -1447,10 +1473,6 @@ drgn_symbol_from_dwarf_variable(struct drgn_dwarf_info_cache *dicache,
|
||||
&qualified_type);
|
||||
if (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))) {
|
||||
return drgn_error_format(DRGN_ERROR_LOOKUP,
|
||||
"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))
|
||||
return drgn_error_libdw();
|
||||
|
||||
if (nloc != 1 || loc[0].atom != DW_OP_addr) {
|
||||
return drgn_error_create(DRGN_ERROR_DWARF_FORMAT,
|
||||
"DW_AT_location has unimplemented operation");
|
||||
}
|
||||
ret->address = loc[0].number + bias;
|
||||
ret->little_endian = dwarf_die_is_little_endian(die);
|
||||
return NULL;
|
||||
return drgn_object_set_reference(ret, qualified_type,
|
||||
loc[0].number + bias, 0, 0,
|
||||
dwarf_die_byte_order(die));
|
||||
}
|
||||
|
||||
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,
|
||||
struct drgn_symbol *ret)
|
||||
struct drgn_object *ret)
|
||||
{
|
||||
struct drgn_error *err;
|
||||
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))
|
||||
continue;
|
||||
switch (dwarf_tag(&die)) {
|
||||
case DW_TAG_enumeration_type: {
|
||||
struct drgn_qualified_type qualified_type;
|
||||
|
||||
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_enumeration_type:
|
||||
return drgn_object_from_dwarf_enumerator(dicache, &die,
|
||||
name, ret);
|
||||
case DW_TAG_subprogram:
|
||||
return drgn_symbol_from_dwarf_subprogram(dicache, &die,
|
||||
return drgn_object_from_dwarf_subprogram(dicache, &die,
|
||||
bias, name,
|
||||
ret);
|
||||
case DW_TAG_variable:
|
||||
return drgn_symbol_from_dwarf_variable(dicache, &die,
|
||||
return drgn_object_from_dwarf_variable(dicache, &die,
|
||||
bias, name, ret);
|
||||
default:
|
||||
DRGN_UNREACHABLE();
|
||||
|
@ -24,7 +24,7 @@
|
||||
*
|
||||
* @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_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);
|
||||
|
||||
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
|
||||
* drgn_dwarf_symbol_find().
|
||||
* drgn_dwarf_object_find().
|
||||
*/
|
||||
struct drgn_dwarf_info_cache {
|
||||
/** 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,
|
||||
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 *
|
||||
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,
|
||||
struct drgn_symbol *ret);
|
||||
struct drgn_object *ret);
|
||||
|
||||
/** @} */
|
||||
|
||||
|
@ -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)));
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/**
|
||||
|
@ -228,52 +228,49 @@ out:
|
||||
}
|
||||
|
||||
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,
|
||||
struct drgn_symbol *ret)
|
||||
struct drgn_object *ret)
|
||||
{
|
||||
struct drgn_error *err;
|
||||
struct drgn_program *prog = arg;
|
||||
|
||||
if (filename)
|
||||
goto not_found;
|
||||
if (!filename && (flags & DRGN_FIND_OBJECT_CONSTANT)) {
|
||||
struct drgn_qualified_type qualified_type = {};
|
||||
|
||||
if (flags & DRGN_FIND_OBJECT_CONSTANT) {
|
||||
if (name_len == strlen("PAGE_SHIFT") &&
|
||||
memcmp(name, "PAGE_SHIFT", name_len) == 0) {
|
||||
err = drgn_type_index_find_primitive(&prog->tindex,
|
||||
DRGN_C_TYPE_INT,
|
||||
&ret->type);
|
||||
&qualified_type.type);
|
||||
if (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") &&
|
||||
memcmp(name, "PAGE_SIZE", name_len) == 0) {
|
||||
err = drgn_type_index_find_primitive(&prog->tindex,
|
||||
DRGN_C_TYPE_UNSIGNED_LONG,
|
||||
&ret->type);
|
||||
&qualified_type.type);
|
||||
if (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") &&
|
||||
memcmp(name, "PAGE_MASK", name_len) == 0) {
|
||||
err = drgn_type_index_find_primitive(&prog->tindex,
|
||||
DRGN_C_TYPE_UNSIGNED_LONG,
|
||||
&ret->type);
|
||||
&qualified_type.type);
|
||||
if (err)
|
||||
return err;
|
||||
ret->uvalue = ~(prog->vmcoreinfo.page_size - 1);
|
||||
} else {
|
||||
goto not_found;
|
||||
return drgn_object_set_unsigned(ret, qualified_type,
|
||||
~(prog->vmcoreinfo.page_size - 1),
|
||||
0);
|
||||
}
|
||||
ret->qualifiers = 0;
|
||||
ret->kind = DRGN_SYMBOL_CONSTANT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
not_found:
|
||||
ret->type = NULL;
|
||||
return NULL;
|
||||
return &drgn_not_found;
|
||||
}
|
||||
|
||||
struct kernel_module_iterator {
|
||||
@ -1598,13 +1595,13 @@ linux_kernel_load_default_debug_info(struct drgn_program *prog)
|
||||
{
|
||||
struct drgn_error *err;
|
||||
|
||||
if (!prog->added_vmcoreinfo_symbol_finder) {
|
||||
err = drgn_program_add_symbol_finder(prog,
|
||||
vmcoreinfo_symbol_find,
|
||||
if (!prog->added_vmcoreinfo_object_finder) {
|
||||
err = drgn_program_add_object_finder(prog,
|
||||
vmcoreinfo_object_find,
|
||||
prog);
|
||||
if (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);
|
||||
}
|
||||
|
93
libdrgn/object_index.c
Normal file
93
libdrgn/object_index.c
Normal 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
83
libdrgn/object_index.h
Normal 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 */
|
@ -19,10 +19,10 @@
|
||||
#include "language.h"
|
||||
#include "linux_kernel.h"
|
||||
#include "memory_reader.h"
|
||||
#include "object_index.h"
|
||||
#include "program.h"
|
||||
#include "read.h"
|
||||
#include "string_builder.h"
|
||||
#include "symbol_index.h"
|
||||
#include "type_index.h"
|
||||
#include "vector.h"
|
||||
|
||||
@ -68,7 +68,7 @@ void drgn_program_init(struct drgn_program *prog,
|
||||
memset(prog, 0, sizeof(*prog));
|
||||
drgn_memory_reader_init(&prog->reader);
|
||||
drgn_type_index_init(&prog->tindex);
|
||||
drgn_symbol_index_init(&prog->sindex);
|
||||
drgn_object_index_init(&prog->oindex);
|
||||
prog->core_fd = -1;
|
||||
prog->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)
|
||||
{
|
||||
drgn_symbol_index_deinit(&prog->sindex);
|
||||
drgn_object_index_deinit(&prog->oindex);
|
||||
drgn_type_index_deinit(&prog->tindex);
|
||||
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 *
|
||||
drgn_program_add_symbol_finder(struct drgn_program *prog,
|
||||
drgn_symbol_find_fn fn, void *arg)
|
||||
drgn_program_add_object_finder(struct drgn_program *prog,
|
||||
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)
|
||||
@ -484,8 +484,8 @@ struct drgn_error *drgn_program_update_dwarf_index(struct drgn_program *prog)
|
||||
drgn_dwarf_info_cache_destroy(dicache);
|
||||
return err;
|
||||
}
|
||||
err = drgn_program_add_symbol_finder(prog,
|
||||
drgn_dwarf_symbol_find,
|
||||
err = drgn_program_add_object_finder(prog,
|
||||
drgn_dwarf_object_find,
|
||||
dicache);
|
||||
if (err) {
|
||||
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,
|
||||
struct drgn_object *ret)
|
||||
{
|
||||
struct drgn_error *err;
|
||||
struct drgn_symbol sym;
|
||||
struct drgn_qualified_type qualified_type;
|
||||
|
||||
if (ret && ret->prog != prog) {
|
||||
return drgn_error_create(DRGN_ERROR_INVALID_ARGUMENT,
|
||||
"object is from wrong program");
|
||||
}
|
||||
|
||||
err = drgn_symbol_index_find(&prog->sindex, name, filename, flags,
|
||||
&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);
|
||||
}
|
||||
return drgn_object_index_find(&prog->oindex, name, filename, flags,
|
||||
ret);
|
||||
}
|
||||
|
||||
LIBDRGN_PUBLIC struct drgn_error *
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include <elfutils/libdwfl.h>
|
||||
|
||||
#include "memory_reader.h"
|
||||
#include "symbol_index.h"
|
||||
#include "object_index.h"
|
||||
#include "type_index.h"
|
||||
|
||||
/**
|
||||
@ -51,7 +51,7 @@ struct drgn_program {
|
||||
/** @privatesection */
|
||||
struct drgn_memory_reader reader;
|
||||
struct drgn_type_index tindex;
|
||||
struct drgn_symbol_index sindex;
|
||||
struct drgn_object_index oindex;
|
||||
struct drgn_memory_file_segment *file_segments;
|
||||
size_t num_file_segments;
|
||||
/*
|
||||
@ -69,7 +69,7 @@ struct drgn_program {
|
||||
int core_fd;
|
||||
enum drgn_program_flags flags;
|
||||
enum drgn_architecture_flags arch;
|
||||
bool added_vmcoreinfo_symbol_finder;
|
||||
bool added_vmcoreinfo_object_finder;
|
||||
};
|
||||
|
||||
/** Initialize a @ref drgn_program. */
|
||||
|
@ -113,8 +113,8 @@ extern const char drgn_Program___getitem___DOC[];
|
||||
#define drgn_Program___getitem___DOC (char *)drgn_Program___getitem___DOC
|
||||
extern const 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[];
|
||||
#define drgn_Program_add_symbol_finder_DOC (char *)drgn_Program_add_symbol_finder_DOC
|
||||
extern const char drgn_Program_add_object_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[];
|
||||
#define drgn_Program_add_type_finder_DOC (char *)drgn_Program_add_type_finder_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
|
||||
extern const 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[];
|
||||
#define drgn_Type_DOC (char *)drgn_Type_DOC
|
||||
extern const char drgn_Type_enumerators_DOC[];
|
||||
|
@ -78,12 +78,6 @@ typedef struct {
|
||||
PyObject *cache;
|
||||
} Program;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
struct drgn_symbol sym;
|
||||
DrgnType *type_obj;
|
||||
} Symbol;
|
||||
|
||||
extern PyObject *Architecture_class;
|
||||
extern PyObject *FindObjectFlags_class;
|
||||
extern PyObject *PrimitiveType_class;
|
||||
@ -94,7 +88,6 @@ extern PyTypeObject DrgnObject_type;
|
||||
extern PyTypeObject DrgnType_type;
|
||||
extern PyTypeObject ObjectIterator_type;
|
||||
extern PyTypeObject Program_type;
|
||||
extern PyTypeObject Symbol_type;
|
||||
extern PyObject *FaultError;
|
||||
extern PyObject *FileFormatError;
|
||||
extern PyObject *MissingDebugInfoError;
|
||||
|
@ -159,11 +159,6 @@ DRGNPY_PUBLIC PyMODINIT_FUNC PyInit__drgn(void)
|
||||
Py_INCREF(&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;
|
||||
|
||||
err:
|
||||
|
@ -281,15 +281,15 @@ static PyObject *Program_add_type_finder(Program *self, PyObject *args,
|
||||
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,
|
||||
enum drgn_find_object_flags flags,
|
||||
void *arg, struct drgn_symbol *ret)
|
||||
void *arg, struct drgn_object *ret)
|
||||
{
|
||||
struct drgn_error *err;
|
||||
PyGILState_STATE gstate;
|
||||
PyObject *name_obj, *flags_obj;
|
||||
PyObject *sym_obj;
|
||||
PyObject *obj;
|
||||
|
||||
gstate = PyGILState_Ensure();
|
||||
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();
|
||||
goto out_name_obj;
|
||||
}
|
||||
sym_obj = PyObject_CallFunction(PyTuple_GET_ITEM(arg, 1), "OOs",
|
||||
name_obj, flags_obj, filename);
|
||||
if (!sym_obj) {
|
||||
obj = PyObject_CallFunction(PyTuple_GET_ITEM(arg, 1), "OOOs",
|
||||
PyTuple_GET_ITEM(arg, 0), name_obj,
|
||||
flags_obj, filename);
|
||||
if (!obj) {
|
||||
err = drgn_error_from_python();
|
||||
goto out_flags_obj;
|
||||
}
|
||||
if (sym_obj == Py_None) {
|
||||
if (obj == Py_None) {
|
||||
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,
|
||||
"symbol find callback must return Symbol or None");
|
||||
"object find callback must return Object or None");
|
||||
err = drgn_error_from_python();
|
||||
goto out_sym_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;
|
||||
goto out_obj;
|
||||
}
|
||||
|
||||
*ret = ((Symbol *)sym_obj)->sym;
|
||||
err = NULL;
|
||||
out_sym_obj:
|
||||
Py_DECREF(sym_obj);
|
||||
err = drgn_object_copy(ret, &((DrgnObject *)obj)->obj);
|
||||
out_obj:
|
||||
Py_DECREF(obj);
|
||||
out_flags_obj:
|
||||
Py_DECREF(flags_obj);
|
||||
out_name_obj:
|
||||
@ -338,7 +333,7 @@ out_gstate:
|
||||
return err;
|
||||
}
|
||||
|
||||
static PyObject *Program_add_symbol_finder(Program *self, PyObject *args,
|
||||
static PyObject *Program_add_object_finder(Program *self, PyObject *args,
|
||||
PyObject *kwds)
|
||||
{
|
||||
static char *keywords[] = {"fn", NULL};
|
||||
@ -346,7 +341,7 @@ static PyObject *Program_add_symbol_finder(Program *self, PyObject *args,
|
||||
PyObject *fn, *arg;
|
||||
int ret;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:add_symbol_finder",
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:add_object_finder",
|
||||
keywords, &fn))
|
||||
return NULL;
|
||||
|
||||
@ -363,7 +358,7 @@ static PyObject *Program_add_symbol_finder(Program *self, PyObject *args,
|
||||
if (ret == -1)
|
||||
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);
|
||||
if (err)
|
||||
return set_drgn_error(err);
|
||||
@ -711,6 +706,7 @@ static int Program_contains(Program *self, PyObject *key)
|
||||
{
|
||||
struct drgn_error *err;
|
||||
const char *name;
|
||||
struct drgn_object tmp;
|
||||
bool clear;
|
||||
|
||||
if (!PyUnicode_Check(key)) {
|
||||
@ -722,11 +718,13 @@ static int Program_contains(Program *self, PyObject *key)
|
||||
if (!name)
|
||||
return -1;
|
||||
|
||||
drgn_object_init(&tmp, &self->prog);
|
||||
clear = set_drgn_in_python();
|
||||
err = drgn_program_find_object(&self->prog, name, NULL,
|
||||
DRGN_FIND_OBJECT_ANY, NULL);
|
||||
DRGN_FIND_OBJECT_ANY, &tmp);
|
||||
if (clear)
|
||||
clear_drgn_in_python();
|
||||
drgn_object_deinit(&tmp);
|
||||
if (err) {
|
||||
if (err->code == DRGN_ERROR_LOOKUP) {
|
||||
drgn_error_destroy(err);
|
||||
@ -756,8 +754,8 @@ static PyMethodDef Program_methods[] = {
|
||||
METH_VARARGS | METH_KEYWORDS, drgn_Program_add_memory_segment_DOC},
|
||||
{"add_type_finder", (PyCFunction)Program_add_type_finder,
|
||||
METH_VARARGS | METH_KEYWORDS, drgn_Program_add_type_finder_DOC},
|
||||
{"add_symbol_finder", (PyCFunction)Program_add_symbol_finder,
|
||||
METH_VARARGS | METH_KEYWORDS, drgn_Program_add_symbol_finder_DOC},
|
||||
{"add_object_finder", (PyCFunction)Program_add_object_finder,
|
||||
METH_VARARGS | METH_KEYWORDS, drgn_Program_add_object_finder_DOC},
|
||||
{"set_core_dump", (PyCFunction)Program_set_core_dump,
|
||||
METH_VARARGS | METH_KEYWORDS, drgn_Program_set_core_dump_DOC},
|
||||
{"set_kernel", (PyCFunction)Program_set_kernel, METH_NOARGS,
|
||||
|
@ -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 */
|
||||
};
|
@ -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");
|
||||
}
|
@ -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 */
|
@ -1,5 +1,5 @@
|
||||
import functools
|
||||
from typing import NamedTuple, Optional
|
||||
from typing import Any, NamedTuple, Optional
|
||||
import unittest
|
||||
|
||||
from drgn import (
|
||||
@ -7,6 +7,7 @@ from drgn import (
|
||||
FindObjectFlags,
|
||||
Object,
|
||||
Program,
|
||||
Type,
|
||||
TypeKind,
|
||||
enum_type,
|
||||
float_type,
|
||||
@ -48,7 +49,14 @@ def mock_memory_read(data, address, count, offset, physical):
|
||||
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):
|
||||
if filename:
|
||||
return None
|
||||
@ -65,22 +73,22 @@ def mock_program(arch=MOCK_ARCH, *, segments=None, types=None, symbols=None):
|
||||
return type
|
||||
return None
|
||||
|
||||
def mock_symbol_find(name, flags, filename):
|
||||
def mock_object_find(prog, name, flags, filename):
|
||||
if filename:
|
||||
return None
|
||||
for sym_name, sym in symbols:
|
||||
if sym_name == name:
|
||||
if sym.value is not None or sym.is_enumerator:
|
||||
for obj in objects:
|
||||
if obj.name == name:
|
||||
if obj.value is not None:
|
||||
if flags & FindObjectFlags.CONSTANT:
|
||||
break
|
||||
elif sym.type.kind == TypeKind.FUNCTION:
|
||||
elif obj.type.kind == TypeKind.FUNCTION:
|
||||
if flags & FindObjectFlags.FUNCTION:
|
||||
break
|
||||
elif flags & FindObjectFlags.VARIABLE:
|
||||
break
|
||||
else:
|
||||
return None
|
||||
return sym
|
||||
return Object(prog, obj.type, address=obj.address, value=obj.value)
|
||||
|
||||
prog = Program(arch)
|
||||
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)
|
||||
if types is not None:
|
||||
prog.add_type_finder(mock_find_type)
|
||||
if symbols is not None:
|
||||
prog.add_symbol_finder(mock_symbol_find)
|
||||
if objects is not None:
|
||||
prog.add_object_finder(mock_object_find)
|
||||
return prog
|
||||
|
||||
|
||||
|
@ -28,6 +28,7 @@ from tests import (
|
||||
line_segment_type,
|
||||
mock_program,
|
||||
option_type,
|
||||
pid_type,
|
||||
point_type,
|
||||
)
|
||||
|
||||
|
@ -13,7 +13,6 @@ from drgn import (
|
||||
Program,
|
||||
ProgramFlags,
|
||||
Qualifiers,
|
||||
Symbol,
|
||||
array_type,
|
||||
bool_type,
|
||||
float_type,
|
||||
@ -27,6 +26,7 @@ from tests import (
|
||||
MOCK_32BIT_ARCH,
|
||||
MOCK_ARCH,
|
||||
MockMemorySegment,
|
||||
MockObject,
|
||||
ObjectTestCase,
|
||||
color_type,
|
||||
mock_program,
|
||||
@ -473,22 +473,23 @@ class TestTypes(unittest.TestCase):
|
||||
|
||||
class TestObjects(ObjectTestCase):
|
||||
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.add_symbol_finder(lambda name, flags, filename: 'foo')
|
||||
prog.add_object_finder(lambda prog, name, flags, filename: 'foo')
|
||||
self.assertRaises(TypeError, prog.object, 'foo')
|
||||
|
||||
def test_not_found(self):
|
||||
prog = mock_program()
|
||||
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.assertFalse('foo' in prog)
|
||||
|
||||
def test_constant(self):
|
||||
sym = Symbol(int_type('int', 4, True), value=4096)
|
||||
prog = mock_program(symbols=[('PAGE_SIZE', sym)])
|
||||
mock_obj = MockObject('PAGE_SIZE', int_type('int', 4, True),
|
||||
value=4096)
|
||||
prog = mock_program(objects=[mock_obj])
|
||||
self.assertEqual(prog['PAGE_SIZE'],
|
||||
Object(prog, int_type('int', 4, True), value=4096))
|
||||
self.assertEqual(prog.object('PAGE_SIZE', FindObjectFlags.CONSTANT),
|
||||
@ -496,9 +497,9 @@ class TestObjects(ObjectTestCase):
|
||||
self.assertTrue('PAGE_SIZE' in prog)
|
||||
|
||||
def test_function(self):
|
||||
sym = Symbol(function_type(void_type(), (), False), address=0xffff0000,
|
||||
byteorder='little')
|
||||
prog = mock_program(symbols=[('func', sym)])
|
||||
mock_obj = MockObject('func', function_type(void_type(), (), False),
|
||||
address=0xffff0000)
|
||||
prog = mock_program(objects=[mock_obj])
|
||||
self.assertEqual(prog['func'],
|
||||
Object(prog, function_type(void_type(), (), False),
|
||||
address=0xffff0000))
|
||||
@ -507,9 +508,9 @@ class TestObjects(ObjectTestCase):
|
||||
self.assertTrue('func' in prog)
|
||||
|
||||
def test_variable(self):
|
||||
sym = Symbol(int_type('int', 4, True), address=0xffff0000,
|
||||
byteorder='little')
|
||||
prog = mock_program(symbols=[('counter', sym)])
|
||||
mock_obj = MockObject('counter', int_type('int', 4, True),
|
||||
address=0xffff0000)
|
||||
prog = mock_program(objects=[mock_obj])
|
||||
self.assertEqual(prog['counter'],
|
||||
Object(prog, int_type('int', 4, True),
|
||||
address=0xffff0000))
|
||||
|
@ -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))
|
Loading…
Reference in New Issue
Block a user