drgn/libdrgn/symbol_index.c
Omar Sandoval 565e0343ef libdrgn: make symbol index pluggable with callbacks
The last piece of making the major program components pluggable.
2019-05-06 14:55:34 -07:00

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