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; 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_HASH_TABLE_FUNCTIONS(drgn_dwarf_index_die_map, string_hash, string_eq)
DEFINE_VECTOR_FUNCTIONS(drgn_dwarf_index_die_vector) DEFINE_VECTOR_FUNCTIONS(drgn_dwarf_index_die_vector)
DEFINE_HASH_TABLE_FUNCTIONS(drgn_dwarf_index_specification_map, 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; return false;
} }
struct drgn_error * struct drgn_dwarf_index_die *
drgn_dwarf_index_iterator_next(struct drgn_dwarf_index_iterator *it, drgn_dwarf_index_iterator_next(struct drgn_dwarf_index_iterator *it)
Dwarf_Die *die_ret, uint64_t *bias_ret)
{ {
struct drgn_dwarf_index *dindex = it->dindex; struct drgn_dwarf_index *dindex = it->dindex;
struct drgn_dwarf_index_die *die; struct drgn_dwarf_index_die *die;
Dwarf *dwarf;
Dwarf_Addr bias;
if (it->any_name) { if (it->any_name) {
for (;;) { for (;;) {
struct drgn_dwarf_index_shard *shard;
if (it->shard >= ARRAY_SIZE(dindex->shards)) 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]; die = &shard->dies.data[it->index];
if (++it->index >= shard->dies.size) { if (++it->index >= shard->dies.size) {
@ -2651,12 +2626,11 @@ drgn_dwarf_index_iterator_next(struct drgn_dwarf_index_iterator *it,
} }
} else { } else {
for (;;) { for (;;) {
struct drgn_dwarf_index_shard *shard;
if (it->index == UINT32_MAX) 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]; die = &shard->dies.data[it->index];
it->index = die->next; it->index = die->next;
@ -2665,8 +2639,15 @@ drgn_dwarf_index_iterator_next(struct drgn_dwarf_index_iterator *it,
break; 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) if (!dwarf)
return drgn_error_libdwfl(); return drgn_error_libdwfl();
if (!dwarf_offdie(dwarf, die->offset, die_ret)) 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_linux_proc_dwfl_callbacks;
extern const Dwfl_Callbacks drgn_userspace_core_dump_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_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) 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. * DW_TAG_enumerator DIEs.
* *
* @param[in] it DWARF index iterator. * @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] die_ret Returned DIE.
* @param[out] bias_ret Returned difference between addresses in the loaded * @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 * module and addresses in the debugging information. This may be @c NULL if it
* is not needed. * is not needed.
* @return @c NULL on success, non-@c NULL on error. In particular, when there * @return @c NULL on success, non-@c NULL on error.
* 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().
*/ */
struct drgn_error * struct drgn_error *drgn_dwarf_index_get_die(struct drgn_dwarf_index_die *die,
drgn_dwarf_index_iterator_next(struct drgn_dwarf_index_iterator *it, Dwarf_Die *die_ret,
Dwarf_Die *die_ret, uint64_t *bias_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_type **ret)
{ {
struct drgn_error *err; 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, drgn_dwarf_index_iterator_init(&it, &dicache->dindex, name,
strlen(name), &tag, 1); strlen(name), &tag, 1);
/* /*
* Find a matching DIE. Note that drgn_dwarf_index does not contain DIEs * 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. * with DW_AT_declaration, so this will always be a complete type.
*/ */
err = drgn_dwarf_index_iterator_next(&it, &die, NULL); struct drgn_dwarf_index_die *index_die =
if (err) drgn_dwarf_index_iterator_next(&it);
return err; if (!index_die)
return &drgn_stop;
/* /*
* Look for another matching DIE. If there is one, then we can't be sure * 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. * which type this is, so leave it incomplete rather than guessing.
*/ */
err = drgn_dwarf_index_iterator_next(&it, &die, NULL); if (drgn_dwarf_index_iterator_next(&it))
if (!err)
return &drgn_stop; 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); err = drgn_type_from_dwarf(dicache, &die, &qualified_type);
if (err) if (err)
return 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_error *err;
struct drgn_dwarf_info_cache *dicache = arg; struct drgn_dwarf_info_cache *dicache = arg;
struct drgn_dwarf_index_iterator it;
Dwarf_Die die;
uint64_t tag;
uint64_t tag;
switch (kind) { switch (kind) {
case DRGN_TYPE_INT: case DRGN_TYPE_INT:
case DRGN_TYPE_BOOL: case DRGN_TYPE_BOOL:
@ -1266,9 +1265,15 @@ struct drgn_error *drgn_dwarf_type_find(enum drgn_type_kind kind,
UNREACHABLE(); UNREACHABLE();
} }
struct drgn_dwarf_index_iterator it;
drgn_dwarf_index_iterator_init(&it, &dicache->dindex, name, name_len, drgn_dwarf_index_iterator_init(&it, &dicache->dindex, name, name_len,
&tag, 1); &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)) { if (die_matches_filename(&die, filename)) {
err = drgn_type_from_dwarf(dicache, &die, ret); err = drgn_type_from_dwarf(dicache, &die, ret);
if (err) if (err)
@ -1281,8 +1286,6 @@ struct drgn_error *drgn_dwarf_type_find(enum drgn_type_kind kind,
return NULL; return NULL;
} }
} }
if (err && err->code != DRGN_ERROR_STOP)
return err;
return &drgn_not_found; 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_error *err;
struct drgn_dwarf_info_cache *dicache = arg; 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) if (flags & DRGN_FIND_OBJECT_CONSTANT)
tags[num_tags++] = DW_TAG_enumerator; tags[num_tags++] = DW_TAG_enumerator;
if (flags & DRGN_FIND_OBJECT_FUNCTION) 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) if (flags & DRGN_FIND_OBJECT_VARIABLE)
tags[num_tags++] = DW_TAG_variable; tags[num_tags++] = DW_TAG_variable;
struct drgn_dwarf_index_iterator it;
drgn_dwarf_index_iterator_init(&it, &dicache->dindex, name, drgn_dwarf_index_iterator_init(&it, &dicache->dindex, name,
strlen(name), tags, num_tags); 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)) if (!die_matches_filename(&die, filename))
continue; continue;
switch (dwarf_tag(&die)) { switch (dwarf_tag(&die)) {
@ -1470,8 +1476,6 @@ drgn_dwarf_object_find(const char *name, size_t name_len, const char *filename,
UNREACHABLE(); UNREACHABLE();
} }
} }
if (err && err->code != DRGN_ERROR_STOP)
return err;
return &drgn_not_found; 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_dwarf_index *dindex)
{ {
struct drgn_error *err; struct drgn_error *err;
struct drgn_dwarf_index_iterator it; struct drgn_dwarf_index_iterator it;
static const uint64_t tags[] = { DW_TAG_subprogram }; static const uint64_t tags[] = { DW_TAG_subprogram };
drgn_dwarf_index_iterator_init(&it, dindex, "main", strlen("main"), drgn_dwarf_index_iterator_init(&it, dindex, "main", strlen("main"),
tags, ARRAY_SIZE(tags)); tags, ARRAY_SIZE(tags));
for (;;) { struct drgn_dwarf_index_die *index_die;
while ((index_die = drgn_dwarf_index_iterator_next(&it))) {
Dwarf_Die die; Dwarf_Die die;
const struct drgn_language *lang; err = drgn_dwarf_index_get_die(index_die, &die, NULL);
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);
if (err) { if (err) {
drgn_error_destroy(err); drgn_error_destroy(err);
continue; continue;
} }
const struct drgn_language *lang;
err = drgn_language_from_die(&die, &lang);
if (err) {
drgn_error_destroy(err);
continue;
}
if (lang) { if (lang) {
prog->lang = lang; prog->lang = lang;
break; break;