libdrgn: dwarf_index: return indexed DIE entry from drgn_dwarf_index_iterator_next()

For namespace support, we will want to access the struct
drgn_dwarf_index_die for namespaces instead of the Dwarf_Die. Split
drgn_dwarf_index_get_die() out of drgn_dwarf_index_iterator_next().

Signed-off-by: Omar Sandoval <osandov@osandov.com>
This commit is contained in:
Omar Sandoval 2020-09-02 13:05:45 -07:00
parent d512964c1e
commit 66ad5077c9
4 changed files with 94 additions and 81 deletions

View File

@ -252,26 +252,6 @@ static inline const char *section_end(Elf_Data *data)
return (const char *)data->d_buf + data->d_size;
}
/*
* An indexed DIE.
*
* DIEs with the same name but different tags or files are considered distinct.
* We only compare the hash of the file name, not the string value, because a
* 64-bit collision is unlikely enough, especially when also considering the
* name and tag.
*/
struct drgn_dwarf_index_die {
/*
* The next DIE with the same name (as an index into
* drgn_dwarf_index_shard::dies), or UINT32_MAX if this is the last DIE.
*/
uint32_t next;
uint8_t tag;
uint64_t file_name_hash;
Dwfl_Module *module;
size_t offset;
};
DEFINE_HASH_TABLE_FUNCTIONS(drgn_dwarf_index_die_map, string_hash, string_eq)
DEFINE_VECTOR_FUNCTIONS(drgn_dwarf_index_die_vector)
DEFINE_HASH_TABLE_FUNCTIONS(drgn_dwarf_index_specification_map,
@ -2619,23 +2599,18 @@ drgn_dwarf_index_iterator_matches_tag(struct drgn_dwarf_index_iterator *it,
return false;
}
struct drgn_error *
drgn_dwarf_index_iterator_next(struct drgn_dwarf_index_iterator *it,
Dwarf_Die *die_ret, uint64_t *bias_ret)
struct drgn_dwarf_index_die *
drgn_dwarf_index_iterator_next(struct drgn_dwarf_index_iterator *it)
{
struct drgn_dwarf_index *dindex = it->dindex;
struct drgn_dwarf_index_die *die;
Dwarf *dwarf;
Dwarf_Addr bias;
if (it->any_name) {
for (;;) {
struct drgn_dwarf_index_shard *shard;
if (it->shard >= ARRAY_SIZE(dindex->shards))
return &drgn_stop;
return NULL;
shard = &dindex->shards[it->shard];
struct drgn_dwarf_index_shard *shard =
&dindex->shards[it->shard];
die = &shard->dies.data[it->index];
if (++it->index >= shard->dies.size) {
@ -2651,12 +2626,11 @@ drgn_dwarf_index_iterator_next(struct drgn_dwarf_index_iterator *it,
}
} else {
for (;;) {
struct drgn_dwarf_index_shard *shard;
if (it->index == UINT32_MAX)
return &drgn_stop;
return NULL;
shard = &dindex->shards[it->shard];
struct drgn_dwarf_index_shard *shard =
&dindex->shards[it->shard];
die = &shard->dies.data[it->index];
it->index = die->next;
@ -2665,8 +2639,15 @@ drgn_dwarf_index_iterator_next(struct drgn_dwarf_index_iterator *it,
break;
}
}
return die;
}
dwarf = dwfl_module_getdwarf(die->module, &bias);
struct drgn_error *drgn_dwarf_index_get_die(struct drgn_dwarf_index_die *die,
Dwarf_Die *die_ret,
uint64_t *bias_ret)
{
Dwarf_Addr bias;
Dwarf *dwarf = dwfl_module_getdwarf(die->module, &bias);
if (!dwarf)
return drgn_error_libdwfl();
if (!dwarf_offdie(dwarf, die->offset, die_ret))

View File

@ -62,7 +62,32 @@ extern const Dwfl_Callbacks drgn_dwfl_callbacks;
extern const Dwfl_Callbacks drgn_linux_proc_dwfl_callbacks;
extern const Dwfl_Callbacks drgn_userspace_core_dump_dwfl_callbacks;
struct drgn_dwarf_index_die;
/*
* An indexed DIE.
*
* DIEs with the same name but different tags or files are considered distinct.
* We only compare the hash of the file name, not the string value, because a
* 64-bit collision is unlikely enough, especially when also considering the
* name and tag.
*/
struct drgn_dwarf_index_die {
/*
* The next DIE with the same name (as an index into
* drgn_dwarf_index_shard::dies), or UINT32_MAX if this is the last DIE.
*/
uint32_t next;
uint8_t tag;
union {
/* If tag != DW_TAG_namespace. */
uint64_t file_name_hash;
/* TODO: explain hash */
/* If tag == DW_TAG_namespace. */
struct drgn_dwarf_index_namespace *namespace;
};
Dwfl_Module *module;
size_t offset;
};
DEFINE_HASH_MAP_TYPE(drgn_dwarf_index_die_map, struct string, uint32_t)
DEFINE_VECTOR_TYPE(drgn_dwarf_index_die_vector, struct drgn_dwarf_index_die)
@ -411,18 +436,24 @@ void drgn_dwarf_index_iterator_init(struct drgn_dwarf_index_iterator *it,
* DW_TAG_enumerator DIEs.
*
* @param[in] it DWARF index iterator.
* @return Next DIE, or @c NULL if there are no more matching DIEs.
*/
struct drgn_dwarf_index_die *
drgn_dwarf_index_iterator_next(struct drgn_dwarf_index_iterator *it);
/**
* Get a @c Dwarf_Die from a @ref drgn_dwarf_index_die.
*
* @param[in] die Indexed DIE.
* @param[out] die_ret Returned DIE.
* @param[out] bias_ret Returned difference between addresses in the loaded
* module and addresses in the debugging information. This may be @c NULL if it
* is not needed.
* @return @c NULL on success, non-@c NULL on error. In particular, when there
* are no more matching DIEs, @p die_ret is not modified and an error with code
* @ref DRGN_ERROR_STOP is returned; this @ref DRGN_ERROR_STOP error does not
* have to be passed to @ref drgn_error_destroy().
* @return @c NULL on success, non-@c NULL on error.
*/
struct drgn_error *
drgn_dwarf_index_iterator_next(struct drgn_dwarf_index_iterator *it,
Dwarf_Die *die_ret, uint64_t *bias_ret);
struct drgn_error *drgn_dwarf_index_get_die(struct drgn_dwarf_index_die *die,
Dwarf_Die *die_ret,
uint64_t *bias_ret);
/** @} */

View File

@ -346,29 +346,30 @@ drgn_dwarf_info_cache_find_complete(struct drgn_dwarf_info_cache *dicache,
struct drgn_type **ret)
{
struct drgn_error *err;
struct drgn_dwarf_index_iterator it;
Dwarf_Die die;
struct drgn_qualified_type qualified_type;
struct drgn_dwarf_index_iterator it;
drgn_dwarf_index_iterator_init(&it, &dicache->dindex, name,
strlen(name), &tag, 1);
/*
* Find a matching DIE. Note that drgn_dwarf_index does not contain DIEs
* with DW_AT_declaration, so this will always be a complete type.
*/
err = drgn_dwarf_index_iterator_next(&it, &die, NULL);
if (err)
return err;
struct drgn_dwarf_index_die *index_die =
drgn_dwarf_index_iterator_next(&it);
if (!index_die)
return &drgn_stop;
/*
* Look for another matching DIE. If there is one, then we can't be sure
* which type this is, so leave it incomplete rather than guessing.
*/
err = drgn_dwarf_index_iterator_next(&it, &die, NULL);
if (!err)
if (drgn_dwarf_index_iterator_next(&it))
return &drgn_stop;
else if (err->code != DRGN_ERROR_STOP)
return err;
Dwarf_Die die;
err = drgn_dwarf_index_get_die(index_die, &die, NULL);
if (err)
return err;
struct drgn_qualified_type qualified_type;
err = drgn_type_from_dwarf(dicache, &die, &qualified_type);
if (err)
return err;
@ -1237,10 +1238,8 @@ struct drgn_error *drgn_dwarf_type_find(enum drgn_type_kind kind,
{
struct drgn_error *err;
struct drgn_dwarf_info_cache *dicache = arg;
struct drgn_dwarf_index_iterator it;
Dwarf_Die die;
uint64_t tag;
uint64_t tag;
switch (kind) {
case DRGN_TYPE_INT:
case DRGN_TYPE_BOOL:
@ -1266,9 +1265,15 @@ struct drgn_error *drgn_dwarf_type_find(enum drgn_type_kind kind,
UNREACHABLE();
}
struct drgn_dwarf_index_iterator it;
drgn_dwarf_index_iterator_init(&it, &dicache->dindex, name, name_len,
&tag, 1);
while (!(err = drgn_dwarf_index_iterator_next(&it, &die, NULL))) {
struct drgn_dwarf_index_die *index_die;
while ((index_die = drgn_dwarf_index_iterator_next(&it))) {
Dwarf_Die die;
err = drgn_dwarf_index_get_die(index_die, &die, NULL);
if (err)
return err;
if (die_matches_filename(&die, filename)) {
err = drgn_type_from_dwarf(dicache, &die, ret);
if (err)
@ -1281,8 +1286,6 @@ struct drgn_error *drgn_dwarf_type_find(enum drgn_type_kind kind,
return NULL;
}
}
if (err && err->code != DRGN_ERROR_STOP)
return err;
return &drgn_not_found;
}
@ -1436,13 +1439,9 @@ drgn_dwarf_object_find(const char *name, size_t name_len, const char *filename,
{
struct drgn_error *err;
struct drgn_dwarf_info_cache *dicache = arg;
uint64_t tags[3];
size_t num_tags;
struct drgn_dwarf_index_iterator it;
Dwarf_Die die;
uint64_t bias;
num_tags = 0;
uint64_t tags[3];
size_t num_tags = 0;
if (flags & DRGN_FIND_OBJECT_CONSTANT)
tags[num_tags++] = DW_TAG_enumerator;
if (flags & DRGN_FIND_OBJECT_FUNCTION)
@ -1450,9 +1449,16 @@ drgn_dwarf_object_find(const char *name, size_t name_len, const char *filename,
if (flags & DRGN_FIND_OBJECT_VARIABLE)
tags[num_tags++] = DW_TAG_variable;
struct drgn_dwarf_index_iterator it;
drgn_dwarf_index_iterator_init(&it, &dicache->dindex, name,
strlen(name), tags, num_tags);
while (!(err = drgn_dwarf_index_iterator_next(&it, &die, &bias))) {
struct drgn_dwarf_index_die *index_die;
while ((index_die = drgn_dwarf_index_iterator_next(&it))) {
Dwarf_Die die;
uint64_t bias;
err = drgn_dwarf_index_get_die(index_die, &die, &bias);
if (err)
return err;
if (!die_matches_filename(&die, filename))
continue;
switch (dwarf_tag(&die)) {
@ -1470,8 +1476,6 @@ drgn_dwarf_object_find(const char *name, size_t name_len, const char *filename,
UNREACHABLE();
}
}
if (err && err->code != DRGN_ERROR_STOP)
return err;
return &drgn_not_found;
}

View File

@ -631,29 +631,26 @@ static void drgn_program_set_language_from_main(struct drgn_program *prog,
struct drgn_dwarf_index *dindex)
{
struct drgn_error *err;
struct drgn_dwarf_index_iterator it;
static const uint64_t tags[] = { DW_TAG_subprogram };
drgn_dwarf_index_iterator_init(&it, dindex, "main", strlen("main"),
tags, ARRAY_SIZE(tags));
for (;;) {
struct drgn_dwarf_index_die *index_die;
while ((index_die = drgn_dwarf_index_iterator_next(&it))) {
Dwarf_Die die;
const struct drgn_language *lang;
err = drgn_dwarf_index_iterator_next(&it, &die, NULL);
if (err == &drgn_stop) {
break;
} else if (err) {
drgn_error_destroy(err);
continue;
}
err = drgn_language_from_die(&die, &lang);
err = drgn_dwarf_index_get_die(index_die, &die, NULL);
if (err) {
drgn_error_destroy(err);
continue;
}
const struct drgn_language *lang;
err = drgn_language_from_die(&die, &lang);
if (err) {
drgn_error_destroy(err);
continue;
}
if (lang) {
prog->lang = lang;
break;