From 66ad5077c9fea5c8ce30b71693389b957b8dff38 Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Wed, 2 Sep 2020 13:05:45 -0700 Subject: [PATCH] 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 --- libdrgn/dwarf_index.c | 51 +++++++++++------------------------ libdrgn/dwarf_index.h | 47 +++++++++++++++++++++++++++------ libdrgn/dwarf_info_cache.c | 54 ++++++++++++++++++++------------------ libdrgn/program.c | 23 +++++++--------- 4 files changed, 94 insertions(+), 81 deletions(-) diff --git a/libdrgn/dwarf_index.c b/libdrgn/dwarf_index.c index 215dabcc..e8d52079 100644 --- a/libdrgn/dwarf_index.c +++ b/libdrgn/dwarf_index.c @@ -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)) diff --git a/libdrgn/dwarf_index.h b/libdrgn/dwarf_index.h index 83f05a06..86db7cdf 100644 --- a/libdrgn/dwarf_index.h +++ b/libdrgn/dwarf_index.h @@ -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); /** @} */ diff --git a/libdrgn/dwarf_info_cache.c b/libdrgn/dwarf_info_cache.c index d8d2d6f9..da729f98 100644 --- a/libdrgn/dwarf_info_cache.c +++ b/libdrgn/dwarf_info_cache.c @@ -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; } diff --git a/libdrgn/program.c b/libdrgn/program.c index f92f2a35..db3d3d33 100644 --- a/libdrgn/program.c +++ b/libdrgn/program.c @@ -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;