mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-23 17:53:07 +00:00
565e0343ef
The last piece of making the major program components pluggable.
165 lines
3.9 KiB
C
165 lines
3.9 KiB
C
// 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_create(struct drgn_symbol_index **ret)
|
|
{
|
|
struct drgn_symbol_index *sindex;
|
|
|
|
sindex = malloc(sizeof(*sindex));
|
|
if (!sindex)
|
|
return &drgn_enomem;
|
|
drgn_symbol_index_init(sindex);
|
|
*ret = sindex;
|
|
return NULL;
|
|
}
|
|
|
|
void drgn_symbol_index_destroy(struct drgn_symbol_index *sindex)
|
|
{
|
|
drgn_symbol_index_deinit(sindex);
|
|
free(sindex);
|
|
}
|
|
|
|
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)
|
|
return err;
|
|
if (ret->type) {
|
|
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;
|
|
}
|
|
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");
|
|
}
|