diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2022-11-25 18:37:11 -0300 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2022-11-25 18:37:11 -0300 |
commit | 392c13c917735e151e3430df2e74f9bae10de0fb (patch) | |
tree | b703604cedda2a326fdb2da17f6172ec131103e8 | |
parent | c48d6d094b3cfc48f52641a4e08aba9985b414ee (diff) | |
download | pahole-WIP-imported-unit.tar.gz |
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r-- | dwarf_loader.c | 238 | ||||
-rw-r--r-- | dwarves.c | 5 | ||||
-rw-r--r-- | dwarves.h | 6 |
3 files changed, 215 insertions, 34 deletions
diff --git a/dwarf_loader.c b/dwarf_loader.c index 42b6bfe0..e650e43c 100644 --- a/dwarf_loader.c +++ b/dwarf_loader.c @@ -11,6 +11,7 @@ #include <errno.h> #include <fcntl.h> #include <fnmatch.h> +#include <inttypes.h> #include <libelf.h> #include <limits.h> #include <pthread.h> @@ -83,6 +84,7 @@ static void __tag__print_not_supported(uint32_t tag, const char *func) struct dwarf_off_ref { unsigned int from_types : 1; + unsigned int from_alt : 1; Dwarf_Off off; }; @@ -112,12 +114,13 @@ static void dwarf_tag__set_spec(struct dwarf_tag *dtag, dwarf_off_ref spec) *(dwarf_off_ref *)(dtag + 1) = spec; } +// alt: Alternative DWARF file, i.e. .dwz struct dwarf_cu { struct hlist_head *hash_tags; struct hlist_head *hash_types; struct dwarf_tag *last_type_lookup; struct cu *cu; - struct dwarf_cu *type_unit; + struct dwarf_cu *type_unit, *alt; }; static int dwarf_cu__init(struct dwarf_cu *dcu, struct cu *cu) @@ -175,8 +178,8 @@ static void dwarf_cu__delete(struct cu *cu) static void __tag__print_type_not_found(struct tag *tag, const char *func) { struct dwarf_tag *dtag = tag->priv; - fprintf(stderr, "%s: couldn't find %#llx type for %#llx (%s)!\n", func, - (unsigned long long)dtag->type.off, (unsigned long long)dtag->id, + fprintf(stderr, "%s: couldn't find %#llx (from_alt=%u) type for %#llx (%s)!\n", func, + (unsigned long long)dtag->type.off, dtag->type.from_alt, (unsigned long long)dtag->id, dwarf_tag_name(tag->tag)); } @@ -215,6 +218,9 @@ static void cu__hash(struct cu *cu, struct tag *tag) struct hlist_head *hashtable = tag__is_tag_type(tag) ? dcu->hash_types : dcu->hash_tags; + + struct dwarf_tag *dtag = tag->priv; + fprintf(stderr, "%30s:%4d cu: %p off %#" PRIx64 " tag %p type: %#" PRIx64 " dtag->type.from_alt:%d %s\n", __func__, __LINE__, cu, dtag->id, tag, dtag->type.off, dtag->type.from_alt, dwarf_tag_name(tag->tag)); hashtags__hash(hashtable, tag->priv); } @@ -225,7 +231,9 @@ static struct dwarf_tag *dwarf_cu__find_tag_by_ref(const struct dwarf_cu *cu, return NULL; if (ref->from_types) { return NULL; - } + } else if (ref->from_alt) + cu = cu->alt; + return hashtags__find(cu->hash_tags, ref->off); } @@ -239,6 +247,11 @@ static struct dwarf_tag *dwarf_cu__find_type_by_ref(struct dwarf_cu *dcu, if (dcu == NULL) { return NULL; } + } else if (ref->from_alt) { + fprintf(stderr, "%s:%d from_alt: off=%#" PRIx64 " dcu=%p, dcu->alt=%p!!!!\n", __func__, __LINE__, ref->off, dcu, dcu->alt); + dcu = dcu->alt; + if (dcu == NULL) + return NULL; } if (dcu->last_type_lookup->id == ref->off) @@ -418,6 +431,10 @@ static struct dwarf_off_ref attr_type(Dwarf_Die *die, uint32_t attr_name, struct if (dwarf_formref_die(&attr, &type_die) != NULL) { ref.from_types = attr.form == DW_FORM_ref_sig8; ref.off = dwarf_dieoffset(&type_die); + + // We mark its from alt so that when doing type lookups we use dcu->alt + if (attr.form == DW_FORM_GNU_ref_alt || conf->alt_dwarf || conf->from_imported_unit_expansion_from_alt) + ref.from_alt = 1; return ref; } } @@ -514,6 +531,9 @@ static void tag__init(struct tag *tag, struct cu *cu, Dwarf_Die *die, struct con } INIT_LIST_HEAD(&tag->node); + + fprintf(stderr, "%30s:%4d cu: %p off %#" PRIx64 " tag %p type: %#" PRIx64 " dtag->type.from_alt:%d dtag->abstract_origin.from_alt:%d conf->alt_dwarf:%d %s\n", + __func__, __LINE__, cu, dtag->id, tag, dtag->type.off, dtag->type.from_alt, dtag->abstract_origin.from_alt, conf->alt_dwarf, dwarf_tag_name(tag->tag)); } static struct tag *tag__new(Dwarf_Die *die, struct cu *cu, struct conf_load *conf) @@ -1994,8 +2014,6 @@ static struct tag *__die__process_tag(Dwarf_Die *die, struct cu *cu, struct tag *tag = NULL; switch (dwarf_tag(die)) { - case DW_TAG_imported_unit: - break; // We don't support imported units yet, so to avoid segfaults case DW_TAG_array_type: tag = die__create_new_array(die, cu, conf); break; case DW_TAG_string_type: // FORTRAN stuff, looks like an array @@ -2059,12 +2077,70 @@ static struct tag *__die__process_tag(Dwarf_Die *die, struct cu *cu, return tag; } -static int die__process_unit(Dwarf_Die *die, struct cu *cu, struct conf_load *conf) +static int __die__process_unit(Dwarf_Die *die, struct cu *cu, bool from_imported_unit_expansion_from_alt, struct conf_load *conf); + +static int die__process_imported_unit(Dwarf_Die *die, struct cu *cu, struct conf_load *conf) +{ + Dwarf_Attribute attr_mem, *attr = dwarf_attr(die, DW_AT_import, &attr_mem); + int err = 0; + + fprintf(stderr, "> %30s:%4d cu: %p off %#" PRIx64 " imported_unit\n", __func__, __LINE__, cu, dwarf_dieoffset(die)); + + if (attr == NULL) { + fprintf(stderr, "%s: dwarf_attr(die, DW_AT_import, &attr_mem)\n", __func__); + return -ENOMEM; + } + + Dwarf_Die child; + + if (dwarf_formref_die(attr, &child) != NULL && + dwarf_tag(&child) == DW_TAG_partial_unit && + dwarf_child(&child, &child) == 0) { + // Check if we need to use the DWARF offset to DIE hashtables for the alternate DWARF + // aka .dwz + bool from_imported_unit_expansion_from_alt = attr->form == DW_FORM_GNU_ref_alt; + + err = __die__process_unit(&child, cu, from_imported_unit_expansion_from_alt, conf); + } + + fprintf(stderr, "< %30s:%4d cu: %p off %#" PRIx64 " imported_unit\n", __func__, __LINE__, cu, dwarf_dieoffset(die)); + + return err; +} + +static int __die__process_unit(Dwarf_Die *die, struct cu *cu, bool from_imported_unit_expansion_from_alt, struct conf_load *conf) { + int err = 0; + + fprintf(stderr, "> %30s:%4d from_imported_unit_expansion_from_alt=%d, conf->alt_dwarf=%d\n", __func__, __LINE__, from_imported_unit_expansion_from_alt, conf->alt_dwarf); + + // Here if from_imported_unit_expansion_from_alt is set that is because + // we're processing tags from a DW_TAG_imported_unit from an alt DWARF + // file, so since they are coming from an alternate DWARF we need to + // mark their offsets as such so that lookups will use the alternative + // DWARF offset-queued hashtable, otherwise their offsets will clash + // with the offsets in the main CU. + + // And since we add subtags we can't just set its dtag->type.from_alt to true here, we need + // to tweak conf->alt_dwarf and then restore its previous value. + + conf->from_imported_unit_expansion_from_alt = from_imported_unit_expansion_from_alt; + do { + if (dwarf_tag(die) == DW_TAG_imported_unit) { + err = die__process_imported_unit(die, cu, conf); + + if (err) + goto out; + + continue; + } + struct tag *tag = die__process_tag(die, cu, 1, conf); - if (tag == NULL) - return -ENOMEM; + if (tag == NULL) { + err = -ENOMEM; + goto out; + } if (tag == &unsupported_tag) { // XXX special case DW_TAG_dwarf_procedure, appears when looking at a recent ~/bin/perf @@ -2077,16 +2153,37 @@ static int die__process_unit(Dwarf_Die *die, struct cu *cu, struct conf_load *co uint32_t id; cu__add_tag(cu, tag, &id); - cu__hash(cu, tag); + + // We will load the whole alt file, then we will hash it there, no need to do it on the main cu + if (!from_imported_unit_expansion_from_alt || conf->alt_dwarf) + cu__hash(cu, tag, conf); + + // XXX we need to make this decision about hashing or not in cu__hash() as we need to take care + // of DW_TAG_member and other sub tags, not just the ones we see here... So get conf down to cu__hash() + // and call it here uncoditionally, cu__hash() will look at both conf->from_imported_unit_expansion_from_alt and + // conf->alt_dwarf and decide if it should or not really hash the tag. CONTINUE FROM HERE + struct dwarf_tag *dtag = tag->priv; + + fprintf(stderr, "%30s:%4d cu: %p off %#" PRIx64 " tag %p type: %#" PRIx64 " dtag->type.from_alt:%d conf->alt_dwarf:%d %s\n", __func__, __LINE__, cu, dtag->id, tag, dtag->type.off, dtag->type.from_alt, conf->alt_dwarf, dwarf_tag_name(tag->tag)); + dtag->small_id = id; if (tag->tag == DW_TAG_unspecified_type) cu->unspecified_type.type = id; } while (dwarf_siblingof(die, die) == 0); +out: + conf->from_imported_unit_expansion_from_alt = 0; + + fprintf(stderr, "< %30s:%4d from_imported_unit_expansion_from_alt=%d\n", __func__, __LINE__, from_imported_unit_expansion_from_alt); return 0; } +static int die__process_unit(Dwarf_Die *die, struct cu *cu, struct conf_load *conf) +{ + return __die__process_unit(die, cu, /*from_imported_unit_expansion_from_alt=*/false, conf); +} + static void ftype__recode_dwarf_types(struct tag *tag, struct cu *cu); static int namespace__recode_dwarf_types(struct tag *tag, struct cu *cu) @@ -2141,6 +2238,15 @@ find_type: check_type: if (dtype == NULL) { tag__print_type_not_found(pos); + { + struct dwarf_cu *alt_dcu = cu->alt_cu->priv; + + fprintf(stderr, "WARNING %s:%d looking up on alt_cu! dcu->alt=%p, cu->alt_cu->priv=%p\n", __func__, __LINE__, dcu->alt, cu->alt_cu->priv); + dtype = dwarf_cu__find_type_by_ref(alt_dcu, &dpos->type); + if (dtype != NULL) + fprintf(stderr, "WARNING %s:%d found on alt_cu!\n", __func__, __LINE__); + + } continue; } next: @@ -2469,6 +2575,15 @@ find_type: check_type: if (dtype == NULL) { tag__print_type_not_found(tag); + { + struct dwarf_cu *alt_dcu = cu->alt_cu->priv; + + fprintf(stderr, "WARNING %s:%d looking up on alt_cu!\n", __func__, __LINE__); + dtype = dwarf_cu__find_type_by_ref(alt_dcu, &dtag->type); + if (dtype != NULL) + fprintf(stderr, "WARNING %s:%d found on alt_cu!\n", __func__, __LINE__); + + } return 0; } out: @@ -2571,24 +2686,6 @@ static int die__process(Dwarf_Die *die, struct cu *cu, struct conf_load *conf) return 0; // so that other units can be processed } - if (tag == DW_TAG_partial_unit) { - static bool warned; - - if (!warned) { - fprintf(stderr, "WARNING: DW_TAG_partial_unit used, some types will not be considered!\n" - " Probably this was optimized using a tool like 'dwz'\n" - " A future version of pahole will support this.\n"); - warned = true; - } - return 0; // so that other units can be processed - } - - if (tag != DW_TAG_compile_unit && tag != DW_TAG_type_unit) { - fprintf(stderr, "%s: DW_TAG_compile_unit, DW_TAG_type_unit, DW_TAG_partial_unit or DW_TAG_skeleton_unit expected got %s (0x%x)!\n", - __FUNCTION__, dwarf_tag_name(tag), tag); - return -EINVAL; - } - cu->language = attr_numeric(die, DW_AT_language); if (dwarf_child(die, &child) == 0) { @@ -2751,10 +2848,10 @@ static int cu__set_common(struct cu *cu, struct conf_load *conf, cu->has_addr_info = conf ? conf->get_addr_info : 0; GElf_Ehdr ehdr; - if (gelf_getehdr(elf, &ehdr) == NULL) + if (elf && gelf_getehdr(elf, &ehdr) == NULL) return DWARF_CB_ABORT; - - cu->little_endian = ehdr.e_ident[EI_DATA] == ELFDATA2LSB; + else + cu->little_endian = ehdr.e_ident[EI_DATA] == ELFDATA2LSB; return 0; } @@ -2925,7 +3022,7 @@ static int dwarf_cus__create_and_process_cu(struct dwarf_cus *dcus, Dwarf_Die *c if (die__process_and_recode(cu_die, cu, dcus->conf) != 0 || cus__finalize(dcus->cus, cu, dcus->conf, thr_data) == LSK__STOP_LOADING) - return DWARF_CB_ABORT; + return DWARF_CB_OK; return DWARF_CB_OK; } @@ -3060,6 +3157,62 @@ static int dwarf_cus__process_cus(struct dwarf_cus *dcus) return __dwarf_cus__process_cus(dcus); } +static struct cu *cu__new_alt(struct conf_load *conf, Dwarf *alt_dw, struct tag_tables *tables) +{ + struct conf_load alt_conf = *conf; + uint8_t pointer_size, offset_size; + struct dwarf_cu *dcu = NULL; + Dwarf_Off off = 0, noff; + struct cu *cu = NULL; + size_t cuhl; + + fprintf(stderr, "> %30s:%4d\n", __func__, __LINE__); + + alt_conf.alt_dwarf = true; + + while (dwarf_nextcu(alt_dw, off, &noff, &cuhl, NULL, &pointer_size, &offset_size) == 0) { + Dwarf_Die die_mem, *cu_die = dwarf_offdie(alt_dw, off + cuhl, &die_mem); + + if (cu_die == NULL) + break; + + if (cu == NULL) { + cu = cu__new_merge_tables(tables, pointer_size, alt_conf.use_obstack); + if (cu == NULL || cu__set_common(cu, &alt_conf, NULL, NULL) != 0) + goto out_abort; + + dcu = zalloc(sizeof(*dcu)); + if (dcu == NULL) + goto out_abort; + + if (dwarf_cu__init(dcu, cu)) + goto out_abort; + + dcu->cu = cu; + dcu->type_unit = NULL; + cu->priv = dcu; + cu->dfops = &dwarf__ops; + cu->language = attr_numeric(cu_die, DW_AT_language); + } + + Dwarf_Die child; + if (dwarf_child(cu_die, &child) == 0) { + if (die__process_unit(&child, cu, &alt_conf) != 0) + goto out_abort; + } + + off = noff; + } + + fprintf(stderr, "< %30s:%4d OK\n", __func__, __LINE__); + return cu; +out_abort: + dwarf_cu__delete(cu); + cu__delete(cu); + fprintf(stderr, "< %30s:%4d FAILURE\n", __func__, __LINE__); + return NULL; +} + static int cus__merge_and_process_cu(struct cus *cus, struct conf_load *conf, Dwfl_Module *mod, Dwarf *dw, Elf *elf, const char *filename, @@ -3070,7 +3223,7 @@ static int cus__merge_and_process_cu(struct cus *cus, struct conf_load *conf, uint8_t pointer_size, offset_size; struct dwarf_cu *dcu = NULL; Dwarf_Off off = 0, noff; - struct cu *cu = NULL; + struct cu *cu = NULL, *alt_cu = NULL; size_t cuhl; while (dwarf_nextcu(dw, off, &noff, &cuhl, NULL, &pointer_size, @@ -3124,6 +3277,22 @@ static int cus__merge_and_process_cu(struct cus *cus, struct conf_load *conf, if (cu == NULL) return 0; + // See if this is a dwo, i.e. if we have partial units that have + // types pointing to this alternative DWARF file + Dwarf *alt_dw = dwarf_getalt(dw); + if (alt_dw != NULL) { + fprintf(stderr, "%s:%d alt_dw is set!\n", __func__, __LINE__); + fprintf(stderr, "%s:%d dcu->alt=%p!\n", __func__, __LINE__, dcu->alt); + alt_cu = cu->alt_cu = cu__new_alt(conf, alt_dw, cu->tables); + fprintf(stderr, "%s: cu->alt_cu=%p!\n", __func__, cu->alt_cu); + if (cu->alt_cu == NULL) + goto out_abort; + + if (dcu->alt == NULL) + dcu->alt = alt_cu->priv; + + } + /* process merged cu */ if (cu__recode_dwarf_types(cu) != LSK__KEEPIT) goto out_abort; @@ -3144,6 +3313,7 @@ static int cus__merge_and_process_cu(struct cus *cus, struct conf_load *conf, out_abort: dwarf_cu__delete(cu); + cu__delete(alt_cu); cu__delete(cu); return DWARF_CB_ABORT; } @@ -3175,7 +3345,7 @@ static int cus__load_module(struct cus *cus, struct conf_load *conf, } } - if (cus__merging_cu(dw, elf)) { + if (1 || cus__merging_cu(dw, elf)) { res = cus__merge_and_process_cu(cus, conf, mod, dw, elf, filename, build_id, build_id_len, type_cu ? &type_dcu : NULL); @@ -731,6 +731,11 @@ struct cu *cu__new(const char *name, uint8_t addr_size, const char *filename, bo return cu__new_build_id(name, addr_size, NULL, 0, filename, use_obstack); } +struct cu *cu__new_merge_tables(struct tag_tables *tables, uint8_t addr_size, bool use_obstack) +{ + return __cu__new("", addr_size, NULL, 0, "", use_obstack, tables, /*delete_tables:*/ false); +} + void cu__delete(struct cu *cu) { if (cu == NULL) @@ -45,6 +45,8 @@ struct conf_fprintf; * @nr_jobs - -j argument, number of threads to use * @ptr_table_stats - print developer oriented ptr_table statistics. * @skip_missing - skip missing types rather than bailing out. + * @alt_dwarf - is this an alt dwarf? i.e. a .dwz file? + * @from_imported_unit_expansion_from_alt - is this from an the expansion we do when processing DW_TAG_imported_unit with a alt DWARF? */ struct conf_load { enum load_steal_kind (*steal)(struct cu *cu, @@ -55,6 +57,8 @@ struct conf_load { char *format_path; int nr_jobs; bool extra_dbg_info; + bool alt_dwarf; + bool from_imported_unit_expansion_from_alt; bool use_obstack; bool fixup_silly_bitfields; bool get_addr_info; @@ -258,6 +262,7 @@ struct cu { struct debug_fmt_ops *dfops; Elf *elf; Dwfl_Module *dwfl; + struct cu *alt_cu; struct obstack obstack; uint32_t cached_symtab_nr_entries; bool use_obstack; @@ -284,6 +289,7 @@ struct cu *cu__new(const char *name, uint8_t addr_size, struct cu *cu__new_build_id(const char *name, uint8_t addr_size, const unsigned char *build_id, int build_id_len, const char *filename, bool use_obstack); +struct cu *cu__new_merge_tables(struct tag_tables *tables, uint8_t addr_size, bool use_obstack); void cu__delete(struct cu *cu); void *cu__malloc(struct cu *cu, size_t size); |