From c178f4698d467164e9dc37e6c3262ef6295d6be0 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 5 Mar 2009 20:29:35 -0300 Subject: [PATCH] dwarves: Remove some more DWARF details from the core Had to be a big sweeping change, but the regression tests shows just improvements :-) Now we stop using an id in struct tag, only storing the type, that now uses 16 bits only, as CTF does. Each format loader has to go on adding the types to the core, that figures out if it is a tag that can be on the tag->type field (tag__is_tag_type). Formats that already have the types separated and in sequence, such as CTF, just ask the core to insert in the types_table directly with its original ID. For DWARF, we ask the core to put it on the table, in sequence, and return the index, that is then stashed with the DWARF specific info (original id, type, decl_line, etc) and hashed by the original id. Later we recode everything, looking up via the original type, getting the small_id to put on the tag->type. The underlying debugging info not needed by the core is stashed in tag->priv, and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of the core tag and points it there, and makes that info available thru cu->orig_info. In the future we can ask, when loading a cu, that this info be trown away, so that we reduce the memory footprint for big multi-cu files such as the Linux kernel. There is also a routine to ask for inserting a NULL, as we still have bugs in the CTF decoding and thus some entries are being lost, to avoid using an undefined pointer when traversing the types_table the ctf loader puts a NULL there via cu__table_nullify_type_entry() and then cu__for_each_type skips those. There is some more cleanups for leftovers that I avoided cleaning to reduce this changeset. And also while doing this I saw that enums can appear without any enumerators and that an array with DW_TAG_GNU_vector is actually a different tag, encoded this way till we get to DWARF4 ;-) So now we don't have to lookup on a hash table looking for DWARF offsets, we can do the more sensible thing of just indexing the types_tags array. Now to do some cleanups and try to get the per cu encoder done. Then order all the cus per number of type entries, pick the one with more, then go on merging/recoding the types of the others and putting the parent linkage in place. Just to show the extent of the changes: $ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0 /home/acme/git/pahole/dwarves.c: struct cu | -4048 struct tag | -32 struct ptr_to_member_type | -32 struct namespace | -32 struct type | -32 struct class | -32 struct base_type | -32 struct array_type | -32 struct class_member | -32 struct lexblock | -32 struct ftype | -32 struct function | -64 struct parameter | -32 struct variable | -32 struct inline_expansion | -32 struct label | -32 struct enumerator | -32 17 structs changed tag__follow_typedef | +3 tag__fprintf_decl_info | +25 array_type__fprintf | +6 type__name | -126 type__find_first_biggest_size_base_type_member | -3 typedef__fprintf | +16 imported_declaration__fprintf | +6 imported_module__fprintf | +3 cu__new | +26 cu__delete | +26 hashtags__hash | -65 hash_64 | -124 hlist_add_head | -78 hashtags__find | -157 cu__hash | -80 cu__add_tag | +20 tag__prefix | -3 cu__find_tag_by_id | -2 cu__find_type_by_id | -3 cu__find_first_typedef_of_type | +38 cu__find_base_type_by_name | +68 cu__find_base_type_by_name_and_size | +72 cu__find_struct_by_name | +59 cus__find_struct_by_name | +8 cus__find_tag_by_id | +5 cus__find_cu_by_name | -6 lexblock__find_tag_by_id | -173 cu__find_variable_by_id | -197 list__find_tag_by_id | -308 cu__find_parameter_by_id | -60 tag__ptr_name | +6 tag__name | +15 variable__type | +13 variable__name | +7 class_member__size | +6 parameter__name | -119 tag__parameter | -14 parameter__type | -143 type__fprintf | -29 union__fprintf | +6 class__add_vtable_entry | -9 type__add_member | -6 type__clone_members | -3 enumeration__add | -6 function__name | -156 ftype__has_parm_of_type | -39 class__find_holes | -27 class__has_hole_ge | -3 type__nr_members_of_type | +3 lexblock__account_inline_expansions | +3 cu__account_inline_expansions | -18 ftype__fprintf_parms | +46 function__tag_fprintf | +24 lexblock__fprintf | -6 ftype__fprintf | +3 function__fprintf_stats | -18 function__size | -6 class__vtable_fprintf | -11 class__fprintf | -21 tag__fprintf | -35 60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541 /home/acme/git/pahole/ctf_loader.c: struct ctf_short_type | +0 14 structs changed type__init | -14 type__new | -9 class__new | -12 create_new_base_type | -7 create_new_base_type_float | -7 create_new_array | -8 create_new_subroutine_type | -9 create_full_members | -18 create_short_members | -18 create_new_class | +1 create_new_union | +1 create_new_enumeration | -19 create_new_forward_decl | -2 create_new_typedef | +3 create_new_tag | -5 load_types | +16 class__fixup_ctf_bitfields | -3 17 functions changed, 21 bytes added, 131 bytes removed, diff: -110 /home/acme/git/pahole/dwarf_loader.c: 17 structs changed zalloc | -56 tag__init | +3 array_type__new | +20 type__init | -24 class_member__new | +46 inline_expansion__new | +12 class__new | +81 lexblock__init | +19 function__new | +43 die__create_new_array | +20 die__create_new_parameter | +4 die__create_new_label | +4 die__create_new_subroutine_type | +113 die__create_new_enumeration | -21 die__process_class | +79 die__process_namespace | +76 die__create_new_inline_expansion | +4 die__process_function | +147 __die__process_tag | +34 die__process_unit | +56 die__process | +90 21 functions changed, 851 bytes added, 101 bytes removed, diff: +750 /home/acme/git/pahole/dwarves.c: struct ptr_table | +16 struct cu_orig_info | +32 2 structs changed tag__decl_line | +68 tag__decl_file | +70 tag__orig_id | +71 ptr_table__init | +46 ptr_table__exit | +37 ptr_table__add | +183 ptr_table__add_with_id | +165 ptr_table__entry | +64 cu__table_add_tag | +171 cu__table_nullify_type_entry | +38 10 functions changed, 913 bytes added, diff: +913 /home/acme/git/pahole/ctf_loader.c: 2 structs changed tag__alloc | +52 1 function changed, 52 bytes added, diff: +52 /home/acme/git/pahole/dwarf_loader.c: struct dwarf_tag | +48 struct dwarf_cu | +4104 4 structs changed dwarf_cu__init | +83 hashtags__hash | +61 hash_64 | +124 hlist_add_head | +78 hashtags__find | +161 cu__hash | +95 tag__is_tag_type | +171 tag__is_type | +85 tag__is_union | +28 tag__is_struct | +57 tag__is_typedef | +28 tag__is_enumeration | +28 dwarf_cu__find_tag_by_id | +56 dwarf_cu__find_type_by_id | +63 tag__alloc | +114 __tag__print_type_not_found | +108 namespace__recode_dwarf_types | +346 tag__namespace | +14 tag__has_namespace | +86 tag__is_namespace | +28 type__recode_dwarf_specification | +182 tag__type | +14 __tag__print_abstract_origin_not_found | +105 ftype__recode_dwarf_types | +322 tag__ftype | +14 tag__parameter | +14 lexblock__recode_dwarf_types | +736 tag__lexblock | +14 tag__label | +14 tag__recode_dwarf_type | +766 tag__ptr_to_member_type | +14 cu__recode_dwarf_types_table | +88 cu__recode_dwarf_types | +48 dwarf_tag__decl_file | +77 strings__ptr | +33 dwarf_tag__decl_line | +59 dwarf_tag__orig_id | +59 dwarf_tag__orig_type | +59 38 functions changed, 4432 bytes added, diff: +4432 build/libdwarves.so.1.0.0: 147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496 Signed-off-by: Arnaldo Carvalho de Melo --- codiff.c | 9 +- ctf_loader.c | 105 +++--- ctracer.c | 180 +++++------ dutil.h | 2 + dwarf_loader.c | 739 +++++++++++++++++++++++++++++++++++++------ dwarves.c | 435 +++++++++++-------------- dwarves.h | 131 ++++++-- dwarves_reorganize.c | 33 +- pahole.c | 86 ++--- pdwtags.c | 53 ++-- pfunct.c | 11 +- prefcnt.c | 2 +- 12 files changed, 1183 insertions(+), 603 deletions(-) diff --git a/codiff.c b/codiff.c index 99d7a45..abe21f9 100644 --- a/codiff.c +++ b/codiff.c @@ -249,7 +249,8 @@ static void diff_struct(const struct cu *new_cu, struct class *structure, if (class__size(structure) == 0 || class__name(structure, cu) == NULL) return; - new_tag = cu__find_struct_by_name(new_cu, class__name(structure, cu), 0); + new_tag = cu__find_struct_by_name(new_cu, class__name(structure, cu), + 0, NULL); if (new_tag == NULL) return; @@ -334,7 +335,8 @@ static int find_new_classes_iterator(struct tag *tag, struct cu *cu, void *old_c if (class__size(class) == 0) return 0; - if (cu__find_struct_by_name(old_cu, class__name(class, cu), 0) != NULL) + if (cu__find_struct_by_name(old_cu, class__name(class, cu), 0, + NULL) != NULL) return 0; class->priv = diff_info__new(NULL, NULL, 1); @@ -367,8 +369,7 @@ static int cu_find_new_tags_iterator(struct cu *new_cu, void *old_cus) if (old_cu != NULL && cu__same_build_id(old_cu, new_cu)) return 0; - cu__for_each_tag(new_cu, find_new_tags_iterator, - old_cu, NULL); + cu__for_each_tag(new_cu, find_new_tags_iterator, old_cu, NULL); return 0; } diff --git a/ctf_loader.c b/ctf_loader.c index b035989..5fe00b9 100644 --- a/ctf_loader.c +++ b/ctf_loader.c @@ -37,6 +37,16 @@ static void *zalloc(const size_t size) return s; } +static void *tag__alloc(const size_t size) +{ + struct tag *self = zalloc(size); + + if (self != NULL) + self->top_level = 1; + + return self; +} + static void oom(const char *msg) { fprintf(stderr, "libclasses: out of memory(%s)\n", msg); @@ -326,7 +336,7 @@ static void dump_funcs(struct ctf_state *sp) static struct base_type *base_type__new(const char *name, size_t size) { - struct base_type *self = zalloc(sizeof(*self)); + struct base_type *self = tag__alloc(sizeof(*self)); if (self != NULL) { self->name = strings__add(strings, name); @@ -335,34 +345,32 @@ static struct base_type *base_type__new(const char *name, size_t size) return self; } -static void type__init(struct type *self, uint16_t tag, unsigned int id, +static void type__init(struct type *self, uint16_t tag, const char *name, size_t size) { INIT_LIST_HEAD(&self->node); INIT_LIST_HEAD(&self->namespace.tags); self->size = size; - self->namespace.tag.id = id; self->namespace.tag.tag = tag; self->namespace.name = strings__add(strings, name[0] == '(' ? NULL : name); } -static struct type *type__new(uint16_t tag, unsigned int id, - const char *name, size_t size) +static struct type *type__new(uint16_t tag, const char *name, size_t size) { - struct type *self = zalloc(sizeof(*self)); + struct type *self = tag__alloc(sizeof(*self)); if (self != NULL) - type__init(self, tag, id, name, size); + type__init(self, tag, name, size); return self; } -static struct class *class__new(const char *name, unsigned int id, size_t size) +static struct class *class__new(const char *name, size_t size) { - struct class *self = zalloc(sizeof(*self)); + struct class *self = tag__alloc(sizeof(*self)); if (self != NULL) { - type__init(&self->type, DW_TAG_structure_type, id, name, size); + type__init(&self->type, DW_TAG_structure_type, name, size); INIT_LIST_HEAD(&self->vtable); } @@ -371,7 +379,7 @@ static struct class *class__new(const char *name, unsigned int id, size_t size) static int create_new_base_type(struct ctf_state *sp, void *ptr, int vlen __unused, struct ctf_full_type *tp, - unsigned int id) + long id) { uint32_t *enc = ptr, name_idx; char name[64], *buf = name; @@ -393,8 +401,7 @@ static int create_new_base_type(struct ctf_state *sp, void *ptr, oom("base_type__new"); base->tag.tag = DW_TAG_base_type; - base->tag.id = id; - cu__add_tag(sp->cu, &base->tag); + cu__add_tag(sp->cu, &base->tag, &id); return sizeof(*enc); } @@ -402,7 +409,7 @@ static int create_new_base_type(struct ctf_state *sp, void *ptr, static int create_new_base_type_float(struct ctf_state *sp, void *ptr, int vlen __unused, struct ctf_full_type *tp, - unsigned int id) + long id) { uint32_t *enc = ptr, eval; char name[64]; @@ -417,8 +424,7 @@ static int create_new_base_type_float(struct ctf_state *sp, void *ptr, oom("base_type__new"); base->tag.tag = DW_TAG_base_type; - base->tag.id = id; - cu__add_tag(sp->cu, &base->tag); + cu__add_tag(sp->cu, &base->tag, &id); return sizeof(*enc); } @@ -426,10 +432,10 @@ static int create_new_base_type_float(struct ctf_state *sp, void *ptr, static int create_new_array(struct ctf_state *sp, void *ptr, int vlen __unused, struct ctf_full_type *tp __unused, - unsigned int id) + long id) { struct ctf_array *ap = ptr; - struct array_type *self = zalloc(sizeof(*self)); + struct array_type *self = tag__alloc(sizeof(*self)); if (self == NULL) oom("array_type"); @@ -444,23 +450,22 @@ static int create_new_array(struct ctf_state *sp, void *ptr, self->nr_entries[0] = ctf__get32(sp->ctf, &ap->ctf_array_nelems); self->tag.tag = DW_TAG_array_type; - self->tag.id = id; self->tag.type = ctf__get16(sp->ctf, &ap->ctf_array_type); - cu__add_tag(sp->cu, &self->tag); + cu__add_tag(sp->cu, &self->tag, &id); return sizeof(*ap); } static int create_new_subroutine_type(struct ctf_state *sp, void *ptr, int vlen, struct ctf_full_type *tp, - unsigned int id) + long id) { uint16_t *args = ptr; uint16_t i; const char *name = ctf_string(ctf__get32(sp->ctf, &tp->base.ctf_name), sp); unsigned int type = ctf__get16(sp->ctf, &tp->base.ctf_type); - struct function *self = zalloc(sizeof(*self)); + struct function *self = tag__alloc(sizeof(*self)); if (self == NULL) oom("function__new"); @@ -470,12 +475,11 @@ static int create_new_subroutine_type(struct ctf_state *sp, void *ptr, INIT_LIST_HEAD(&self->tool_node); INIT_LIST_HEAD(&self->proto.parms); self->proto.tag.tag = DW_TAG_subroutine_type; - self->proto.tag.id = id; self->proto.tag.type = type; INIT_LIST_HEAD(&self->lexblock.tags); for (i = 0; i < vlen; i++) { - struct parameter *p = zalloc(sizeof(*p)); + struct parameter *p = tag__alloc(sizeof(*p)); p->tag.tag = DW_TAG_formal_parameter; p->tag.type = ctf__get16(sp->ctf, &args[i]); @@ -490,7 +494,7 @@ static int create_new_subroutine_type(struct ctf_state *sp, void *ptr, if (vlen & 0x2) vlen += 0x2; - cu__add_tag(sp->cu, &self->proto.tag); + cu__add_tag(sp->cu, &self->proto.tag, &id); return vlen; } @@ -516,7 +520,6 @@ static unsigned long create_full_members(struct ctf_state *sp, void *ptr, member->offset = bit_offset / 8; member->bit_offset = bit_offset % 8; type__add_member(class, member); - cu__hash(sp->cu, &member->tag); } return sizeof(*mp); @@ -543,7 +546,6 @@ static unsigned long create_short_members(struct ctf_state *sp, void *ptr, member->bit_offset = bit_offset % 8; type__add_member(class, member); - cu__hash(sp->cu, &member->tag); } return sizeof(*mp); @@ -551,11 +553,11 @@ static unsigned long create_short_members(struct ctf_state *sp, void *ptr, static int create_new_class(struct ctf_state *sp, void *ptr, int vlen, struct ctf_full_type *tp, - uint64_t size, unsigned int id) + uint64_t size, long id) { unsigned long member_size; const char *name = ctf_string(ctf__get32(sp->ctf, &tp->base.ctf_name), sp); - struct class *self = class__new(name, id, size); + struct class *self = class__new(name, size); if (size >= CTF_SHORT_MEMBER_LIMIT) { member_size = create_full_members(sp, ptr, vlen, &self->type); @@ -563,18 +565,18 @@ static int create_new_class(struct ctf_state *sp, void *ptr, member_size = create_short_members(sp, ptr, vlen, &self->type); } - cu__add_tag(sp->cu, &self->type.namespace.tag); + cu__add_tag(sp->cu, &self->type.namespace.tag, &id); return (vlen * member_size); } static int create_new_union(struct ctf_state *sp, void *ptr, int vlen, struct ctf_full_type *tp, - uint64_t size, unsigned int id) + uint64_t size, long id) { unsigned long member_size; const char *name = ctf_string(ctf__get32(sp->ctf, &tp->base.ctf_name), sp); - struct type *self = type__new(DW_TAG_union_type, id, name, size); + struct type *self = type__new(DW_TAG_union_type, name, size); if (size >= CTF_SHORT_MEMBER_LIMIT) { member_size = create_full_members(sp, ptr, vlen, self); @@ -582,7 +584,7 @@ static int create_new_union(struct ctf_state *sp, void *ptr, member_size = create_short_members(sp, ptr, vlen, self); } - cu__add_tag(sp->cu, &self->namespace.tag); + cu__add_tag(sp->cu, &self->namespace.tag, &id); return (vlen * member_size); } @@ -590,7 +592,7 @@ static int create_new_union(struct ctf_state *sp, void *ptr, static struct enumerator *enumerator__new(const char *name, uint32_t value) { - struct enumerator *self = zalloc(sizeof(*self)); + struct enumerator *self = tag__alloc(sizeof(*self)); if (self != NULL) { self->name = strings__add(strings, name); @@ -603,11 +605,11 @@ static struct enumerator *enumerator__new(const char *name, static int create_new_enumeration(struct ctf_state *sp, void *ptr, int vlen, struct ctf_full_type *tp, - unsigned int id) + long id) { struct ctf_enum *ep = ptr; uint16_t i; - struct type *enumeration = type__new(DW_TAG_enumeration_type, id, + struct type *enumeration = type__new(DW_TAG_enumeration_type, ctf_string(ctf__get32(sp->ctf, &tp->base.ctf_name), sp), sizeof(int)); /* FIXME: is this always the case? */ @@ -624,32 +626,31 @@ static int create_new_enumeration(struct ctf_state *sp, void *ptr, oom("enumerator__new"); enumeration__add(enumeration, enumerator); - cu__hash(sp->cu, &enumerator->tag); } - cu__add_tag(sp->cu, &enumeration->namespace.tag); + cu__add_tag(sp->cu, &enumeration->namespace.tag, &id); return (vlen * sizeof(*ep)); } static int create_new_forward_decl(struct ctf_state *sp, void *ptr __unused, int vlen __unused, struct ctf_full_type *tp, - uint64_t size, unsigned int id) + uint64_t size, long id) { char *name = ctf_string(ctf__get32(sp->ctf, &tp->base.ctf_name), sp); - struct class *self = class__new(name, id, size); + struct class *self = class__new(name, size); if (self == NULL) oom("class foward decl"); self->type.declaration = 1; - cu__add_tag(sp->cu, &self->type.namespace.tag); + cu__add_tag(sp->cu, &self->type.namespace.tag, &id); return 0; } static int create_new_typedef(struct ctf_state *sp, int type, void *ptr __unused, int vlen __unused, struct ctf_full_type *tp, - uint64_t size, unsigned int id) + uint64_t size, long id) { const char *name = ctf_string(ctf__get32(sp->ctf, &tp->base.ctf_name), sp); unsigned int type_id = ctf__get16(sp->ctf, &tp->base.ctf_type); @@ -663,18 +664,18 @@ static int create_new_typedef(struct ctf_state *sp, int type, return 0; } - self = type__new(tag, id, name, size); + self = type__new(tag, name, size); if (self == NULL) oom("type__new"); self->namespace.tag.type = type_id; - cu__add_tag(sp->cu, &self->namespace.tag); + cu__add_tag(sp->cu, &self->namespace.tag, &id); return 0; } static int create_new_tag(struct ctf_state *sp, int type, void *ptr __unused, int vlen __unused, - struct ctf_full_type *tp, unsigned int id) + struct ctf_full_type *tp, long id) { unsigned int type_id = ctf__get16(sp->ctf, &tp->base.ctf_type); struct tag *self = zalloc(sizeof(*self)); @@ -692,9 +693,8 @@ static int create_new_tag(struct ctf_state *sp, int type, return 0; } - self->id = id; self->type = type_id; - cu__add_tag(sp->cu, self); + cu__add_tag(sp->cu, self, &id); return 0; } @@ -762,6 +762,7 @@ static void load_types(struct ctf_state *sp) type == CTF_TYPE_KIND_RESTRICT) { vlen = create_new_tag(sp, type, ptr, vlen, type_ptr, type_index); } else if (type == CTF_TYPE_KIND_UNKN) { + cu__table_nullify_type_entry(sp->cu, type_index); printf("CTF: [%#6x] %1d Unknown\n", type_index, CTF_ISROOT(val)); vlen = 0; } else { @@ -825,10 +826,10 @@ static int class__fixup_ctf_bitfields(struct tag *self, struct cu *cu) if (last_offset == -1) last_offset = pos->offset; - struct tag *fixed_tag; - fixed_tag = cu__find_base_type_by_name_and_size(cu, base_type__name(bt), - bit_size); - if (fixed_tag == NULL) { + uint16_t fixed_tag_id; + + if (cu__find_base_type_by_name_and_size(cu, base_type__name(bt), + bit_size, &fixed_tag_id) == NULL) { fprintf(stderr, "%s: BRAIN FART ALERT!: class: %s, member: %s\n", __func__, type__name(type_self, cu), @@ -837,7 +838,7 @@ static int class__fixup_ctf_bitfields(struct tag *self, struct cu *cu) } pos->offset = last_offset; - pos->tag.type = fixed_tag->id; + pos->tag.type = fixed_tag_id; pos->bit_size = bt->bit_size; pos->bit_offset = bit_offset; bit_offset += bt->bit_size; diff --git a/ctracer.c b/ctracer.c index 8c86a3f..411cc21 100644 --- a/ctracer.c +++ b/ctracer.c @@ -165,42 +165,26 @@ static int methods__add(void **table, const char *str) return 0; } -static void method__add(struct cu *cu, struct function *function) +static void method__add(struct cu *cu, struct function *function, uint32_t id) { list_add(&function->tool_node, &cu->tool_list); + function->priv = (void *)(long)id; } /* * We want just the DW_TAG_subprogram tags that have as one of its parameters * a pointer to the specified "class" (a struct, unions can be added later). */ -static struct tag *function__filter(struct tag *tag, struct cu *cu, void *cookie) +static struct function *function__filter(struct function *function, + struct cu *cu, uint16_t target_type_id) { - struct function *function; - - if (tag->tag != DW_TAG_subprogram) - return NULL; - - function = tag__function(tag); if (function__inlined(function) || function->abstract_origin != 0 || !list_empty(&function->tool_node) || - !ftype__has_parm_of_type(&function->proto, cookie, cu)) + !ftype__has_parm_of_type(&function->proto, target_type_id, cu)) return NULL; - return tag; -} - -/* - * Add the function to the list of methods since it matches function__filter - * criteria. - */ -static int find_methods_iterator(struct tag *tag, struct cu *cu, - void *cookie __unused) -{ - struct function *function = tag__function(tag); - method__add(cu, function); - return 0; + return function; } /* @@ -210,14 +194,22 @@ static int find_methods_iterator(struct tag *tag, struct cu *cu, */ static int cu_find_methods_iterator(struct cu *cu, void *cookie) { - struct tag *target = cu__find_struct_by_name(cu, cookie, 0); + uint16_t target_type_id; + uint32_t function_id; + struct function *function; + struct tag *target = cu__find_struct_by_name(cu, cookie, 0, + &target_type_id); INIT_LIST_HEAD(&cu->tool_list); if (target == NULL) return 0; - return cu__for_each_tag(cu, find_methods_iterator, target, function__filter); + cu__for_each_function(cu, function_id, function) + if (function__filter(function, cu, target_type_id)) + method__add(cu, function, function_id); + + return 0; } static struct class_member *class_member__bitfield_tail(struct class_member *head, @@ -489,9 +481,10 @@ static int class__emit_ostra_converter(struct tag *tag_self, * We want just the DW_TAG_structure_type tags that have a member that is a pointer * to the target class. */ -static struct tag *pointer_filter(struct tag *tag, struct cu *cu, void *target_tag) +static struct tag *pointer_filter(struct tag *tag, struct cu *cu, + uint16_t target_type_id) { - struct type *type, *target_type; + struct type *type; struct class_member *pos; const char *class_name; @@ -506,41 +499,36 @@ static struct tag *pointer_filter(struct tag *tag, struct cu *cu, void *target_t if (class_name == NULL || structures__find(&pointers, class_name)) return NULL; - target_type = tag__type(target_tag); type__for_each_member(type, pos) { struct tag *ctype = cu__find_type_by_id(cu, pos->tag.type); tag__assert_search_result(ctype); - if (ctype->tag == DW_TAG_pointer_type && ctype->type == target_type->namespace.tag.id) + if (ctype->tag == DW_TAG_pointer_type && + ctype->type == target_type_id) return tag; } return NULL; } -/* - * Add the struct to the list of pointers since it matches pointer_filter - * criteria. - */ -static int find_pointers_iterator(struct tag *tag, struct cu *cu, - void *cookie __unused) -{ - structures__add(&pointers, tag, cu); - return 0; -} - /* * Iterate thru all the tags in the compilation unit, looking for classes * that have as one member that is a pointer to the target type. */ static int cu_find_pointers_iterator(struct cu *cu, void *class_name) { - struct tag *target = cu__find_struct_by_name(cu, class_name, 0); + uint16_t target_type_id, id; + struct tag *target = cu__find_struct_by_name(cu, class_name, 0, + &target_type_id), *pos; if (target == NULL) return 0; - return cu__for_each_tag(cu, find_pointers_iterator, target, pointer_filter); + cu__for_each_type(cu, id, pos) + if (pointer_filter(pos, cu, target_type_id)) + structures__add(&pointers, pos, cu); + + return 0; } static void class__find_pointers(const char *class_name) @@ -552,9 +540,10 @@ static void class__find_pointers(const char *class_name) * We want just the DW_TAG_structure_type tags that have as its first member * a struct of type target. */ -static struct tag *alias_filter(struct tag *tag, struct cu *cu, void *target_tag) +static struct tag *alias_filter(struct tag *tag, + struct cu *cu, uint16_t target_type_id) { - struct type *type, *target_type; + struct type *type; struct class_member *first_member; if (!tag__is_struct(tag)) @@ -566,8 +555,7 @@ static struct tag *alias_filter(struct tag *tag, struct cu *cu, void *target_tag first_member = list_first_entry(&type->namespace.tags, struct class_member, tag.node); - target_type = tag__type(target_tag); - if (first_member->tag.type != target_type->namespace.tag.id) + if (first_member->tag.type != target_type_id) return NULL; if (structures__find(&aliases, class__name(tag__class(tag), cu))) @@ -578,45 +566,41 @@ static struct tag *alias_filter(struct tag *tag, struct cu *cu, void *target_tag static void class__find_aliases(const char *class_name); -/* - * Add the struct to the list of aliases since it matches alias_filter - * criteria. - */ -static int find_aliases_iterator(struct tag *tag, struct cu *cu, - void *cookie __unused) -{ - const char *alias_name = class__name(tag__class(tag), cu); - - structures__add(&aliases, tag, cu); - - /* - * Now find aliases to this alias, e.g.: - * - * struct tcp_sock { - * struct inet_connection_sock { - * struct inet_sock { - * struct sock { - * } - * } - * } - * } - */ - class__find_aliases(alias_name); - return 0; -} - /* * Iterate thru all the tags in the compilation unit, looking for classes * that have as its first member the specified "class" (struct). */ static int cu_find_aliases_iterator(struct cu *cu, void *class_name) { - struct tag *target = cu__find_struct_by_name(cu, class_name, 0); - + uint16_t target_type_id, id; + struct tag *target = cu__find_struct_by_name(cu, class_name, 0, + &target_type_id), *pos; if (target == NULL) return 0; - return cu__for_each_tag(cu, find_aliases_iterator, target, alias_filter); + cu__for_each_type(cu, id, pos) { + if (alias_filter(pos, cu, target_type_id)) { + const char *alias_name = class__name(tag__class(pos), cu); + + structures__add(&aliases, pos, cu); + + /* + * Now find aliases to this alias, e.g.: + * + * struct tcp_sock { + * struct inet_connection_sock { + * struct inet_sock { + * struct sock { + * } + * } + * } + * } + */ + class__find_aliases(alias_name); + } + } + + return 0; } static void class__find_aliases(const char *class_name) @@ -688,8 +672,9 @@ out: * This marks the function entry, function__emit_kretprobes will emit the * probe for the function exit. */ -static int function__emit_probes(struct function *self, const struct cu *cu, - const struct tag *target, int probe_type, +static int function__emit_probes(struct function *self, uint32_t function_id, + const struct cu *cu, + const uint16_t target_type_id, int probe_type, const char *member) { struct parameter *pos; @@ -711,11 +696,8 @@ static int function__emit_probes(struct function *self, const struct cu *cu, struct tag *type = cu__find_type_by_id(cu, pos->tag.type); tag__assert_search_result(type); - if (type->tag != DW_TAG_pointer_type) - continue; - - type = cu__find_type_by_id(cu, type->type); - if (type == NULL || type->id != target->id) + if (type->tag != DW_TAG_pointer_type || + type->type != target_type_id) continue; if (member != NULL) @@ -723,9 +705,9 @@ static int function__emit_probes(struct function *self, const struct cu *cu, parameter__name(pos, cu)); fprintf(fp_methods, - "\tctracer__method_hook(%d, %#llx, $%s%s%s, %zd);\n", + "\tctracer__method_hook(%d, %d, $%s%s%s, %zd);\n", probe_type, - (unsigned long long)self->proto.tag.id, + function_id, parameter__name(pos, cu), member ? "->" : "", member ?: "", class__size(mini_class)); @@ -744,16 +726,18 @@ static int function__emit_probes(struct function *self, const struct cu *cu, */ static int cu_emit_probes_iterator(struct cu *cu, void *cookie) { - struct tag *target = cu__find_struct_by_name(cu, cookie, 0); + uint16_t target_type_id; + struct tag *target = cu__find_struct_by_name(cu, cookie, 0, &target_type_id); struct function *pos; tag__assert_search_result(target); list_for_each_entry(pos, &cu->tool_list, tool_node) { + uint32_t function_id = (long)pos->priv; + if (methods__add(&probes_emitted, function__name(pos, cu)) != 0) continue; - pos->priv = (void *)1; /* Mark as visited, for the table iterator */ - function__emit_probes(pos, cu, target, 0, NULL); /* entry */ - function__emit_probes(pos, cu, target, 1, NULL); /* exit */ + function__emit_probes(pos, function_id, cu, target_type_id, 0, NULL); /* entry */ + function__emit_probes(pos, function_id, cu, target_type_id, 1, NULL); /* exit */ } return 0; @@ -765,6 +749,7 @@ static int cu_emit_probes_iterator(struct cu *cu, void *cookie) */ static int cu_emit_pointer_probes_iterator(struct cu *cu, void *cookie) { + uint16_t target_type_id, pointer_id; struct tag *target, *pointer; struct function *pos_tag; struct class_member *pos_member; @@ -773,8 +758,8 @@ static int cu_emit_pointer_probes_iterator(struct cu *cu, void *cookie) if (list_empty(&cu->tool_list)) return 0; - target = cu__find_struct_by_name(cu, class_name, 1); - pointer = cu__find_struct_by_name(cu, cookie, 0); + target = cu__find_struct_by_name(cu, class_name, 1, &target_type_id); + pointer = cu__find_struct_by_name(cu, cookie, 0, &pointer_id); tag__assert_search_result(target); tag__assert_search_result(pointer); @@ -783,18 +768,19 @@ static int cu_emit_pointer_probes_iterator(struct cu *cu, void *cookie) struct tag *ctype = cu__find_type_by_id(cu, pos_member->tag.type); tag__assert_search_result(ctype); - if (ctype->tag == DW_TAG_pointer_type && ctype->type == target->id) + if (ctype->tag == DW_TAG_pointer_type && ctype->type == target_type_id) break; } list_for_each_entry(pos_tag, &cu->tool_list, tool_node) { + uint32_t function_id = (long)pos_tag->priv; + if (methods__add(&probes_emitted, function__name(pos_tag, cu)) != 0) continue; - pos_tag->priv = (void *)1; /* Mark as visited, for the table iterator */ - function__emit_probes(pos_tag, cu, pointer, 0, + function__emit_probes(pos_tag, function_id, cu, target_type_id, 0, class_member__name(pos_member)); /* entry */ - function__emit_probes(pos_tag, cu, pointer, 1, + function__emit_probes(pos_tag, function_id, cu, target_type_id, 1, class_member__name(pos_member)); /* exit */ } @@ -812,8 +798,8 @@ static int cu_emit_functions_table(struct cu *cu, void *fp) list_for_each_entry(pos, &cu->tool_list, tool_node) if (pos->priv != NULL) { - fprintf(fp, "%llu:%s\n", - (unsigned long long)pos->proto.tag.id, + uint32_t function_id = (long)pos->priv; + fprintf(fp, "%d:%s\n", function_id, function__name(pos, cu)); pos->priv = NULL; } @@ -958,7 +944,7 @@ failure: /* * See if the specified struct exists: */ - class = cus__find_struct_by_name(methods_cus, &cu, class_name, 0); + class = cus__find_struct_by_name(methods_cus, &cu, class_name, 0, NULL); if (class == NULL) { fprintf(stderr, "ctracer: struct %s not found!\n", class_name); return EXIT_FAILURE; diff --git a/dutil.h b/dutil.h index 6bb5247..d2166ab 100644 --- a/dutil.h +++ b/dutil.h @@ -14,6 +14,8 @@ #define __unused __attribute__ ((unused)) #endif +#define roundup(x,y) ((((x) + ((y) - 1)) / (y)) * (y)) + /* We need define two variables, argp_program_version_hook and argp_program_bug_address, in all programs. argp.h declares these variables as non-const (which is correct in general). But we can diff --git a/dwarf_loader.c b/dwarf_loader.c index 1410346..fb0d9ae 100644 --- a/dwarf_loader.c +++ b/dwarf_loader.c @@ -25,17 +25,87 @@ #include "dwarves.h" #include "dutil.h" #include "strings.h" +#include "hash.h" + +#define hashtags__fn(key) hash_64(key, HASHTAGS__BITS) + +struct dwarf_tag { + struct hlist_node hash_node; + Dwarf_Off type; + Dwarf_Off id; + struct tag *tag; + strings_t decl_file; + uint16_t decl_line; + uint16_t small_id; +}; + +#define HASHTAGS__BITS 8 +#define HASHTAGS__SIZE (1UL << HASHTAGS__BITS) + +struct dwarf_cu { + struct hlist_head hash_tags[HASHTAGS__SIZE]; + struct hlist_head hash_types[HASHTAGS__SIZE]; + struct cu *cu; +}; + +static void dwarf_cu__init(struct dwarf_cu *self) +{ + unsigned int i; + for (i = 0; i < HASHTAGS__SIZE; ++i) { + INIT_HLIST_HEAD(&self->hash_tags[i]); + INIT_HLIST_HEAD(&self->hash_types[i]); + } +} + +static void hashtags__hash(struct hlist_head *hashtable, + struct dwarf_tag *dtag) +{ + struct hlist_head *head = hashtable + hashtags__fn(dtag->id); + hlist_add_head(&dtag->hash_node, head); +} + +static struct dwarf_tag *hashtags__find(const struct hlist_head *hashtable, + const Dwarf_Off id) +{ + if (id == 0) + return NULL; + + struct dwarf_tag *tpos; + struct hlist_node *pos; + uint16_t bucket = hashtags__fn(id); + const struct hlist_head *head = hashtable + bucket; + + hlist_for_each_entry(tpos, pos, head, hash_node) { + if (tpos->id == id) + return tpos; + } + + return NULL; +} + +static void cu__hash(struct cu *self, struct tag *tag) +{ + struct dwarf_cu *dcu = self->priv; + struct hlist_head *hashtable = tag__is_tag_type(tag) ? + dcu->hash_types : + dcu->hash_tags; + hashtags__hash(hashtable, tag->priv); +} + +static struct dwarf_tag *dwarf_cu__find_tag_by_id(const struct dwarf_cu *self, + const Dwarf_Off id) +{ + return self ? hashtags__find(self->hash_tags, id) : NULL; +} + +static struct dwarf_tag *dwarf_cu__find_type_by_id(const struct dwarf_cu *self, + const Dwarf_Off id) +{ + return self ? hashtags__find(self->hash_types, id) : NULL; +} extern struct strings *strings; -static void *zalloc(const size_t size) -{ - void *s = malloc(size); - if (s != NULL) - memset(s, 0, size); - return s; -} - static void *memdup(const void *src, size_t len) { void *s = malloc(len); @@ -175,37 +245,56 @@ static int attr_location(Dwarf_Die *die, Dwarf_Op **expr, size_t *exprlen) return 1; } +static void *tag__alloc(size_t size) +{ + struct dwarf_tag *dtag; + struct tag *self = malloc(size + sizeof(*dtag)); + + if (self != NULL) { + dtag = ((void *)self) + size; + dtag->tag = self; + self->priv = dtag; + dtag->type = 0; + self->type = 0; + self->top_level = 0; + } + + return self; +} + static void tag__init(struct tag *self, Dwarf_Die *die) { + struct dwarf_tag *dtag = self->priv; int32_t decl_line; const char *decl_file = dwarf_decl_file(die); static const char *last_decl_file; static uint32_t last_decl_file_idx; self->tag = dwarf_tag(die); - self->id = dwarf_dieoffset(die); + + dtag->id = dwarf_dieoffset(die); if (self->tag == DW_TAG_imported_module || self->tag == DW_TAG_imported_declaration) - self->type = attr_type(die, DW_AT_import); + dtag->type = attr_type(die, DW_AT_import); else - self->type = attr_type(die, DW_AT_type); + dtag->type = attr_type(die, DW_AT_type); if (decl_file != last_decl_file) { last_decl_file_idx = strings__add(strings, decl_file); last_decl_file = decl_file; } - self->decl_file = last_decl_file_idx; + dtag->decl_file = last_decl_file_idx; dwarf_decl_line(die, &decl_line); - self->decl_line = decl_line; + dtag->decl_line = decl_line; self->recursivity_level = 0; - INIT_HLIST_NODE(&self->hash_node); + INIT_HLIST_NODE(&dtag->hash_node); } static struct tag *tag__new(Dwarf_Die *die) { - struct tag *self = malloc(sizeof(*self)); + struct tag *self = tag__alloc(sizeof(*self)); if (self != NULL) tag__init(self, die); @@ -215,7 +304,7 @@ static struct tag *tag__new(Dwarf_Die *die) static struct ptr_to_member_type *ptr_to_member_type__new(Dwarf_Die *die) { - struct ptr_to_member_type *self = malloc(sizeof(*self)); + struct ptr_to_member_type *self = tag__alloc(sizeof(*self)); if (self != NULL) { tag__init(&self->tag, die); @@ -227,7 +316,7 @@ static struct ptr_to_member_type *ptr_to_member_type__new(Dwarf_Die *die) static struct base_type *base_type__new(Dwarf_Die *die) { - struct base_type *self = zalloc(sizeof(*self)); + struct base_type *self = tag__alloc(sizeof(*self)); if (self != NULL) { tag__init(&self->tag, die); @@ -240,10 +329,13 @@ static struct base_type *base_type__new(Dwarf_Die *die) static struct array_type *array_type__new(Dwarf_Die *die) { - struct array_type *self = zalloc(sizeof(*self)); + struct array_type *self = tag__alloc(sizeof(*self)); - if (self != NULL) + if (self != NULL) { tag__init(&self->tag, die); + self->dimensions = 0; + self->nr_entries = NULL; + } return self; } @@ -258,7 +350,7 @@ static void namespace__init(struct namespace *self, Dwarf_Die *die) static struct namespace *namespace__new(Dwarf_Die *die) { - struct namespace *self = malloc(sizeof(*self)); + struct namespace *self = tag__alloc(sizeof(*self)); if (self != NULL) namespace__init(self, die); @@ -281,7 +373,7 @@ static void type__init(struct type *self, Dwarf_Die *die) static struct type *type__new(Dwarf_Die *die) { - struct type *self = malloc(sizeof(*self)); + struct type *self = tag__alloc(sizeof(*self)); if (self != NULL) type__init(self, die); @@ -291,7 +383,7 @@ static struct type *type__new(Dwarf_Die *die) static struct enumerator *enumerator__new(Dwarf_Die *die) { - struct enumerator *self = zalloc(sizeof(*self)); + struct enumerator *self = tag__alloc(sizeof(*self)); if (self != NULL) { tag__init(&self->tag, die); @@ -326,7 +418,7 @@ static enum vlocation dwarf__location(Dwarf_Die *die) static struct variable *variable__new(Dwarf_Die *die) { - struct variable *self = malloc(sizeof(*self)); + struct variable *self = tag__alloc(sizeof(*self)); if (self != NULL) { tag__init(&self->tag, die); @@ -346,16 +438,20 @@ static struct variable *variable__new(Dwarf_Die *die) static struct class_member *class_member__new(Dwarf_Die *die) { - struct class_member *self = zalloc(sizeof(*self)); + struct class_member *self = tag__alloc(sizeof(*self)); if (self != NULL) { tag__init(&self->tag, die); + self->name = strings__add(strings, attr_string(die, DW_AT_name)); self->offset = attr_offset(die, DW_AT_data_member_location); - self->bit_size = attr_numeric(die, DW_AT_bit_size); self->bit_offset = attr_numeric(die, DW_AT_bit_offset); + self->bit_size = attr_numeric(die, DW_AT_bit_size); + self->bit_hole = 0; + self->bitfield_end = 0; + self->visited = 0; self->accessibility = attr_numeric(die, DW_AT_accessibility); self->virtuality = attr_numeric(die, DW_AT_virtuality); - self->name = strings__add(strings, attr_string(die, DW_AT_name)); + self->hole = 0; } return self; @@ -363,7 +459,7 @@ static struct class_member *class_member__new(Dwarf_Die *die) static struct parameter *parameter__new(Dwarf_Die *die) { - struct parameter *self = zalloc(sizeof(*self)); + struct parameter *self = tag__alloc(sizeof(*self)); if (self != NULL) { tag__init(&self->tag, die); @@ -377,14 +473,16 @@ static struct parameter *parameter__new(Dwarf_Die *die) static struct inline_expansion *inline_expansion__new(Dwarf_Die *die) { - struct inline_expansion *self = zalloc(sizeof(*self)); + struct inline_expansion *self = tag__alloc(sizeof(*self)); if (self != NULL) { + struct dwarf_tag *dtag = self->tag.priv; + tag__init(&self->tag, die); - self->tag.decl_file = + dtag->decl_file = strings__add(strings, attr_string(die, DW_AT_call_file)); - self->tag.decl_line = attr_numeric(die, DW_AT_call_line); - self->tag.type = attr_type(die, DW_AT_abstract_origin); + dtag->decl_line = attr_numeric(die, DW_AT_call_line); + dtag->type = attr_type(die, DW_AT_abstract_origin); if (dwarf_lowpc(die, &self->low_pc)) self->low_pc = 0; @@ -415,7 +513,7 @@ static struct inline_expansion *inline_expansion__new(Dwarf_Die *die) static struct label *label__new(Dwarf_Die *die) { - struct label *self = malloc(sizeof(*self)); + struct label *self = tag__alloc(sizeof(*self)); if (self != NULL) { tag__init(&self->tag, die); @@ -430,11 +528,17 @@ static struct label *label__new(Dwarf_Die *die) static struct class *class__new(Dwarf_Die *die) { - struct class *self = zalloc(sizeof(*self)); + struct class *self = tag__alloc(sizeof(*self)); if (self != NULL) { type__init(&self->type, die); INIT_LIST_HEAD(&self->vtable); + self->nr_vtable_entries = + self->nr_holes = + self->nr_bit_holes = + self->padding = + self->bit_padding = 0; + self->priv = NULL; } return self; @@ -449,6 +553,7 @@ static void lexblock__init(struct lexblock *self, Dwarf_Die *die) INIT_LIST_HEAD(&self->tags); + self->size_inline_expansions = self->nr_inline_expansions = self->nr_labels = self->nr_lexblocks = @@ -457,7 +562,7 @@ static void lexblock__init(struct lexblock *self, Dwarf_Die *die) static struct lexblock *lexblock__new(Dwarf_Die *die) { - struct lexblock *self = malloc(sizeof(*self)); + struct lexblock *self = tag__alloc(sizeof(*self)); if (self != NULL) { tag__init(&self->tag, die); @@ -480,7 +585,7 @@ static void ftype__init(struct ftype *self, Dwarf_Die *die) static struct ftype *ftype__new(Dwarf_Die *die) { - struct ftype *self = malloc(sizeof(*self)); + struct ftype *self = tag__alloc(sizeof(*self)); if (self != NULL) ftype__init(self, die); @@ -490,7 +595,7 @@ static struct ftype *ftype__new(Dwarf_Die *die) static struct function *function__new(Dwarf_Die *die) { - struct function *self = zalloc(sizeof(*self)); + struct function *self = tag__alloc(sizeof(*self)); if (self != NULL) { ftype__init(&self->proto, die); @@ -508,6 +613,9 @@ static struct function *function__new(Dwarf_Die *die) self->vtable_entry = -1; if (dwarf_hasattr(die, DW_AT_vtable_elem_location)) self->vtable_entry = attr_offset(die, DW_AT_vtable_elem_location); + self->cu_total_size_inline_expansions = 0; + self->cu_total_nr_inline_expansions = 0; + self->priv = NULL; } return self; @@ -544,9 +652,10 @@ static void __cu__tag_not_handled(Dwarf_Die *die, const char *fn) #define cu__tag_not_handled(die) __cu__tag_not_handled(die, __FUNCTION__) static struct tag *__die__process_tag(Dwarf_Die *die, struct cu *cu, - const char *fn); + int toplevel, const char *fn); -#define die__process_tag(die, cu) __die__process_tag(die, cu, __FUNCTION__) +#define die__process_tag(die, cu, toplevel) \ + __die__process_tag(die, cu, toplevel, __FUNCTION__) static struct tag *die__create_new_tag(Dwarf_Die *die) { @@ -590,7 +699,8 @@ static struct tag *die__create_new_class(Dwarf_Die *die, struct cu *cu) } static void die__process_namespace(Dwarf_Die *die, - struct namespace *namespace, struct cu *cu); + struct namespace *namespace, + struct cu *cu); static struct tag *die__create_new_namespace(Dwarf_Die *die, struct cu *cu) { @@ -660,8 +770,10 @@ static struct tag *die__create_new_array(Dwarf_Die *die) oom("array_type__new"); if (!dwarf_haschildren(die) || dwarf_child(die, &child) != 0) { - fprintf(stderr, "%s: DW_TAG_array_type with no children!\n", - __FUNCTION__); + struct dwarf_tag *dtag = array->tag.priv; + fprintf(stderr, + "%s: DW_TAG_array_type %#llx with no children!\n", + __func__, (unsigned long long)dtag->id); return NULL; } @@ -688,8 +800,9 @@ static struct tag *die__create_new_array(Dwarf_Die *die) return &array->tag; } -static void die__create_new_parameter(Dwarf_Die *die, struct ftype *ftype, - struct lexblock *lexblock) +static struct tag *die__create_new_parameter(Dwarf_Die *die, + struct ftype *ftype, + struct lexblock *lexblock) { struct parameter *parm = parameter__new(die); @@ -711,9 +824,11 @@ static void die__create_new_parameter(Dwarf_Die *die, struct ftype *ftype, lexblock__add_tag(lexblock, &parm->tag); } + return &parm->tag; } -static void die__create_new_label(Dwarf_Die *die, struct lexblock *lexblock) +static struct tag *die__create_new_label(Dwarf_Die *die, + struct lexblock *lexblock) { struct label *label = label__new(die); @@ -721,6 +836,7 @@ static void die__create_new_label(Dwarf_Die *die, struct lexblock *lexblock) oom("label__new"); lexblock__add_label(lexblock, label); + return &label->tag; } static struct tag *die__create_new_variable(Dwarf_Die *die) @@ -746,31 +862,43 @@ static struct tag *die__create_new_subroutine_type(Dwarf_Die *die, die = &child; do { + long id = -1; + struct tag *tag; + switch (dwarf_tag(die)) { case DW_TAG_formal_parameter: - die__create_new_parameter(die, ftype, NULL); + tag = die__create_new_parameter(die, ftype, NULL); break; case DW_TAG_unspecified_parameters: ftype->unspec_parms = 1; - break; - case DW_TAG_typedef: { + continue; + case DW_TAG_typedef: /* * First seen in inkscape */ - struct tag *tag = die__create_new_typedef(die); - cu__add_tag(cu, tag); - } - break; + tag = die__create_new_typedef(die); + + if (cu__add_tag(cu, tag, &id) < 0) + oom("die__create_new_subroutine_type:2"); + + goto hash; default: cu__tag_not_handled(die); - break; + continue; } + + if (cu__table_add_tag(cu, tag, &id) < 0) + oom("die__create_new_subroutine_type"); +hash: + cu__hash(cu, tag); + struct dwarf_tag *dtag = tag->priv; + dtag->small_id = id; } while (dwarf_siblingof(die, die) == 0); out: return &ftype->tag; } -static struct tag *die__create_new_enumeration(Dwarf_Die *die, struct cu *cu) +static struct tag *die__create_new_enumeration(Dwarf_Die *die) { Dwarf_Die child; struct type *enumeration = type__new(die); @@ -797,7 +925,6 @@ static struct tag *die__create_new_enumeration(Dwarf_Die *die, struct cu *cu) oom("enumerator__new"); enumeration__add(enumeration, enumerator); - cu__hash(cu, &enumerator->tag); } while (dwarf_siblingof(die, die) == 0); out: return &enumeration->namespace.tag; @@ -820,9 +947,17 @@ static void die__process_class(Dwarf_Die *die, struct type *class, } continue; default: { - struct tag *tag = die__process_tag(die, cu); + struct tag *tag = die__process_tag(die, cu, 0); if (tag != NULL) { + long id = -1; + + if (cu__table_add_tag(cu, tag, &id) < 0) + oom("die__process_class:2"); + + struct dwarf_tag *dtag = tag->priv; + dtag->small_id = id; + namespace__add_tag(&class->namespace, tag); cu__hash(cu, tag); if (tag->tag == DW_TAG_subprogram) { @@ -839,12 +974,20 @@ static void die__process_class(Dwarf_Die *die, struct type *class, } static void die__process_namespace(Dwarf_Die *die, - struct namespace *namespace, struct cu *cu) + struct namespace *namespace, + struct cu *cu) { do { - struct tag *tag = die__process_tag(die, cu); + struct tag *tag = die__process_tag(die, cu, 0); if (tag != NULL) { + long id = -1; + if (cu__table_add_tag(cu, tag, &id) < 0) + oom("die__process_namespace"); + + struct dwarf_tag *dtag = tag->priv; + dtag->small_id = id; + namespace__add_tag(namespace, tag); cu__hash(cu, tag); } @@ -865,8 +1008,8 @@ static void die__create_new_lexblock(Dwarf_Die *die, lexblock__add_lexblock(father, lexblock); } -static void die__create_new_inline_expansion(Dwarf_Die *die, - struct lexblock *lexblock) +static struct tag *die__create_new_inline_expansion(Dwarf_Die *die, + struct lexblock *lexblock) { struct inline_expansion *exp = inline_expansion__new(die); @@ -874,6 +1017,7 @@ static void die__create_new_inline_expansion(Dwarf_Die *die, oom("inline_expansion__new"); lexblock__add_inline_expansion(lexblock, exp); + return &exp->tag; } static void die__process_function(Dwarf_Die *die, struct ftype *ftype, @@ -886,34 +1030,47 @@ static void die__process_function(Dwarf_Die *die, struct ftype *ftype, die = &child; do { + long id = -1; + struct tag *tag; + switch (dwarf_tag(die)) { case DW_TAG_formal_parameter: - die__create_new_parameter(die, ftype, lexblock); - continue; - case DW_TAG_variable: { - struct tag *tag = die__create_new_variable(die); + tag = die__create_new_parameter(die, ftype, lexblock); + break; + case DW_TAG_variable: + tag = die__create_new_variable(die); lexblock__add_variable(lexblock, tag__variable(tag)); - } - continue; + break; case DW_TAG_unspecified_parameters: if (ftype != NULL) ftype->unspec_parms = 1; continue; case DW_TAG_label: - die__create_new_label(die, lexblock); - continue; + tag = die__create_new_label(die, lexblock); + break; case DW_TAG_inlined_subroutine: - die__create_new_inline_expansion(die, lexblock); - continue; + tag = die__create_new_inline_expansion(die, lexblock); + break; case DW_TAG_lexical_block: die__create_new_lexblock(die, cu, lexblock); continue; - default: { - struct tag *tag = die__process_tag(die, cu); - if (tag != NULL) - cu__add_tag(cu, tag); - } + default: + tag = die__process_tag(die, cu, 0); + if (tag == NULL) + oom("die__process_function"); + + if (cu__add_tag(cu, tag, &id) < 0) + oom("die__process_function"); + + goto hash; } + + if (cu__table_add_tag(cu, tag, &id) < 0) + oom("die__process_function"); +hash: + cu__hash(cu, tag); + struct dwarf_tag *dtag = tag->priv; + dtag->small_id = id; } while (dwarf_siblingof(die, die) == 0); } @@ -928,55 +1085,447 @@ static struct tag *die__create_new_function(Dwarf_Die *die, struct cu *cu) } static struct tag *__die__process_tag(Dwarf_Die *die, struct cu *cu, - const char *fn) + int top_level, const char *fn) { + struct tag *tag; + switch (dwarf_tag(die)) { case DW_TAG_array_type: - return die__create_new_array(die); + tag = die__create_new_array(die); break; case DW_TAG_base_type: - return die__create_new_base_type(die); + tag = die__create_new_base_type(die); break; case DW_TAG_const_type: case DW_TAG_imported_declaration: case DW_TAG_imported_module: case DW_TAG_pointer_type: case DW_TAG_reference_type: case DW_TAG_volatile_type: - return die__create_new_tag(die); + tag = die__create_new_tag(die); break; case DW_TAG_ptr_to_member_type: - return die__create_new_ptr_to_member_type(die); + tag = die__create_new_ptr_to_member_type(die); break; case DW_TAG_enumeration_type: - return die__create_new_enumeration(die, cu); + tag = die__create_new_enumeration(die); break; case DW_TAG_namespace: - return die__create_new_namespace(die, cu); + tag = die__create_new_namespace(die, cu); break; case DW_TAG_class_type: case DW_TAG_structure_type: - return die__create_new_class(die, cu); + tag = die__create_new_class(die, cu); break; case DW_TAG_subprogram: - return die__create_new_function(die, cu); + tag = die__create_new_function(die, cu); break; case DW_TAG_subroutine_type: - return die__create_new_subroutine_type(die, cu); + tag = die__create_new_subroutine_type(die, cu); break; case DW_TAG_typedef: - return die__create_new_typedef(die); + tag = die__create_new_typedef(die); break; case DW_TAG_union_type: - return die__create_new_union(die, cu); + tag = die__create_new_union(die, cu); break; case DW_TAG_variable: - return die__create_new_variable(die); + tag = die__create_new_variable(die); break; default: __cu__tag_not_handled(die, fn); + tag = NULL; + break; } - return NULL; + if (tag != NULL) + tag->top_level = top_level; + + return tag; } static void die__process_unit(Dwarf_Die *die, struct cu *cu) { do { - struct tag *tag = die__process_tag(die, cu); - if (tag != NULL) - cu__add_tag(cu, tag); + struct tag *tag = die__process_tag(die, cu, 1); + if (tag != NULL) { + long id = -1; + cu__add_tag(cu, tag, &id); + cu__hash(cu, tag); + struct dwarf_tag *dtag = tag->priv; + dtag->small_id = id; + + } } while (dwarf_siblingof(die, die) == 0); } +static void __tag__print_type_not_found(struct tag *self, const char *func) +{ + struct dwarf_tag *dtag = self->priv; + fprintf(stderr, "%s: couldn't find %#llx type for %#llx (%s)!\n", func, + (unsigned long long)dtag->type, (unsigned long long)dtag->id, + dwarf_tag_name(self->tag)); +} + +#define tag__print_type_not_found(self) \ + __tag__print_type_not_found(self, __func__) + +static void ftype__recode_dwarf_types(struct tag *self, struct cu *cu); + +static void namespace__recode_dwarf_types(struct tag *self, struct cu *cu) +{ + struct tag *pos; + struct dwarf_cu *dcu = cu->priv; + struct namespace *ns = tag__namespace(self); + + namespace__for_each_tag(ns, pos) { + struct dwarf_tag *dtype; + struct dwarf_tag *dpos = pos->priv; + + if (tag__has_namespace(pos)) { + namespace__recode_dwarf_types(pos, cu); + continue; + } + + switch (pos->tag) { + case DW_TAG_subroutine_type: + case DW_TAG_subprogram: + ftype__recode_dwarf_types(pos, cu); + break; + case DW_TAG_imported_module: + dtype = dwarf_cu__find_tag_by_id(dcu, dpos->type); + goto check_type; + /* Can be for both types and non types */ + case DW_TAG_imported_declaration: + dtype = dwarf_cu__find_tag_by_id(dcu, dpos->type); + if (dtype != NULL) + goto next; + goto find_type; + } + + if (dpos->type == 0) /* void */ + continue; +find_type: + dtype = dwarf_cu__find_type_by_id(dcu, dpos->type); +check_type: + if (dtype == NULL) { + tag__print_type_not_found(pos); + continue; + } +next: + pos->type = dtype->small_id; + } +} + +static void type__recode_dwarf_specification(struct tag *self, struct cu *cu) +{ + struct dwarf_tag *dtype; + struct type *t = tag__type(self); + + if (t->namespace.name != 0 || t->specification == 0) + return; + + dtype = dwarf_cu__find_type_by_id(cu->priv, t->specification); + if (dtype != NULL) + t->namespace.name = tag__namespace(dtype->tag)->name; + else { + struct dwarf_tag *dtag = self->priv; + + fprintf(stderr, + "%s: couldn't find name for " + "class %#llx, specification=%#llx\n", __func__, + (unsigned long long)dtag->id, + (unsigned long long)t->specification); + } +} + +static void __tag__print_abstract_origin_not_found(struct tag *self, + unsigned long long abstract_origin, + const char *func) +{ + struct dwarf_tag *dtag = self->priv; + fprintf(stderr, + "%s: couldn't find %#llx abstract_origin for %#llx (%s)!\n", + func, abstract_origin, (unsigned long long)dtag->id, + dwarf_tag_name(self->tag)); +} + +#define tag__print_abstract_origin_not_found(self, abstract_origin) \ + __tag__print_abstract_origin_not_found(self, abstract_origin, __func__) + +static void ftype__recode_dwarf_types(struct tag *self, struct cu *cu) +{ + struct parameter *pos; + struct dwarf_cu *dcu = cu->priv; + struct ftype *type = tag__ftype(self); + + ftype__for_each_parameter(type, pos) { + struct dwarf_tag *dpos = pos->tag.priv; + struct dwarf_tag *dtype; + + if (dpos->type == 0) { + if (pos->abstract_origin == 0) { + /* Function without parameters */ + pos->tag.type = 0; + continue; + } + dtype = dwarf_cu__find_tag_by_id(dcu, pos->abstract_origin); + if (dtype == NULL) { + tag__print_abstract_origin_not_found(&pos->tag, + pos->abstract_origin); + continue; + } + pos->name = tag__parameter(dtype->tag)->name; + pos->tag.type = dtype->tag->type; + continue; + } + + dtype = dwarf_cu__find_type_by_id(dcu, dpos->type); + if (dtype == NULL) { + tag__print_type_not_found(&pos->tag); + continue; + } + pos->tag.type = dtype->small_id; + } +} + +static void lexblock__recode_dwarf_types(struct lexblock *self, struct cu *cu) +{ + struct tag *pos; + struct dwarf_cu *dcu = cu->priv; + + list_for_each_entry(pos, &self->tags, node) { + struct dwarf_tag *dpos = pos->priv; + struct dwarf_tag *dtype; + + switch (pos->tag) { + case DW_TAG_lexical_block: + lexblock__recode_dwarf_types(tag__lexblock(pos), cu); + continue; + case DW_TAG_inlined_subroutine: + dtype = dwarf_cu__find_tag_by_id(dcu, dpos->type); + if (dtype == NULL) { + tag__print_type_not_found(pos); + continue; + } + ftype__recode_dwarf_types(dtype->tag, cu); + continue; + + case DW_TAG_formal_parameter: + if (dpos->type != 0) + break; + + struct parameter *fp = tag__parameter(pos); + dtype = dwarf_cu__find_tag_by_id(dcu, + fp->abstract_origin); + if (dtype == NULL) { + tag__print_abstract_origin_not_found(pos, + fp->abstract_origin); + continue; + } + fp->name = tag__parameter(dtype->tag)->name; + pos->type = dtype->tag->type; + continue; + + case DW_TAG_variable: + if (dpos->type != 0) + break; + + struct variable *var = tag__variable(pos); + + if (var->abstract_origin == 0) { + /* + * DW_TAG_variable completely empty was + * found on libQtGui.so.4.3.4.debug + * <3>: Abbrev Number: 164 (DW_TAG_variable) + */ + continue; + } + + dtype = dwarf_cu__find_tag_by_id(dcu, + var->abstract_origin); + if (dtype == NULL) { + tag__print_abstract_origin_not_found(pos, + var->abstract_origin); + continue; + } + var->name = tag__variable(dtype->tag)->name; + pos->type = dtype->tag->type; + continue; + + case DW_TAG_label: { + struct label *l = tag__label(pos); + + if (l->abstract_origin == 0) + continue; + + dtype = dwarf_cu__find_tag_by_id(dcu, l->abstract_origin); + if (dtype != NULL) + l->name = tag__label(dtype->tag)->name; + else + tag__print_abstract_origin_not_found(pos, + l->abstract_origin); + } + continue; + } + + dtype = dwarf_cu__find_type_by_id(dcu, dpos->type); + if (dtype == NULL) { + tag__print_type_not_found(pos); + continue; + } + pos->type = dtype->small_id; + } +} + +static void tag__recode_dwarf_type(struct tag *self, struct cu *cu) +{ + struct dwarf_tag *dtag = self->priv; + struct dwarf_tag *dtype; + + if (tag__is_type(self)) + type__recode_dwarf_specification(self, cu); + + if (tag__has_namespace(self)) { + namespace__recode_dwarf_types(self, cu); + return; + } + + switch (self->tag) { + case DW_TAG_subprogram: { + struct function *fn = tag__function(self); + + if (fn->name == 0) { + if (fn->abstract_origin == 0 && + fn->specification == 0) { + /* + * Found on libQtGui.so.4.3.4.debug + * <3><1423de>: Abbrev Number: 209 (DW_TAG_subprogram) + * <1423e0> DW_AT_declaration : 1 + */ + return; + } + dtype = dwarf_cu__find_tag_by_id(cu->priv, fn->abstract_origin); + if (dtype == NULL) + dtype = dwarf_cu__find_tag_by_id(cu->priv, fn->specification); + if (dtype != NULL) + fn->name = tag__function(dtype->tag)->name; + else { + fprintf(stderr, + "%s: couldn't find name for " + "function %#llx, abstract_origin=%#llx," + " specification=%#llx\n", __func__, + (unsigned long long)dtag->id, + (unsigned long long)fn->abstract_origin, + (unsigned long long)fn->specification); + } + } + lexblock__recode_dwarf_types(&fn->lexblock, cu); + } + /* Fall thru */ + + case DW_TAG_subroutine_type: + ftype__recode_dwarf_types(self, cu); + /* Fall thru, for the function return type */ + break; + + case DW_TAG_lexical_block: + lexblock__recode_dwarf_types(tag__lexblock(self), cu); + return; + + case DW_TAG_ptr_to_member_type: { + struct ptr_to_member_type *pt = tag__ptr_to_member_type(self); + + dtype = dwarf_cu__find_type_by_id(cu->priv, pt->containing_type); + if (dtype != NULL) + pt->containing_type = dtype->small_id; + else { + fprintf(stderr, + "%s: couldn't find type for " + "containing_type %#llx, containing_type=%#llx\n", + __func__, + (unsigned long long)dtag->id, + (unsigned long long)pt->containing_type); + } + } + break; + + case DW_TAG_namespace: + namespace__recode_dwarf_types(self, cu); + return; + /* Damn, DW_TAG_inlined_subroutine is an special case + as dwarf_tag->id is in fact an abtract origin, i.e. must be + looked up in the tags_table, not in the types_table. + The others also point to routines, so are in tags_table */ + case DW_TAG_inlined_subroutine: + case DW_TAG_imported_module: + dtype = dwarf_cu__find_tag_by_id(cu->priv, dtag->type); + goto check_type; + /* Can be for both types and non types */ + case DW_TAG_imported_declaration: + dtype = dwarf_cu__find_tag_by_id(cu->priv, dtag->type); + if (dtype != NULL) + goto out; + goto find_type; + } + + if (dtag->type == 0) { + self->type = 0; /* void */ + return; + } + +find_type: + dtype = dwarf_cu__find_type_by_id(cu->priv, dtag->type); +check_type: + if (dtype == NULL) { + tag__print_type_not_found(self); + return; + } +out: + self->type = dtype->small_id; +} + +static void cu__recode_dwarf_types_table(struct cu *self, struct ptr_table *pt) +{ + uint32_t i; + + for (i = 1; i < pt->nr_entries; ++i) { + struct tag *tag = pt->entries[i]; + + if (tag != NULL) /* void, see cu__new */ + tag__recode_dwarf_type(tag, self); + } +} + +static void cu__recode_dwarf_types(struct cu *self) +{ + cu__recode_dwarf_types_table(self, &self->types_table); + cu__recode_dwarf_types_table(self, &self->tags_table); +} + +static const char *dwarf_tag__decl_file(const struct tag *self, + const struct cu *cu __unused) +{ + struct dwarf_tag *dtag = self->priv; + return dtag ? strings__ptr(strings, dtag->decl_file) : NULL; +} + +static uint32_t dwarf_tag__decl_line(const struct tag *self, + const struct cu *cu __unused) +{ + struct dwarf_tag *dtag = self->priv; + return dtag ? dtag->decl_line : 0; +} + +static unsigned long long dwarf_tag__orig_id(const struct tag *self, + const struct cu *cu __unused) +{ + struct dwarf_tag *dtag = self->priv; + return dtag ? dtag->id : 0; +} + +static unsigned long long dwarf_tag__orig_type(const struct tag *self, + const struct cu *cu __unused) +{ + struct dwarf_tag *dtag = self->priv; + return dtag ? dtag->type : 0; +} + +static struct cu_orig_info dwarf_orig_info_ops = { + .tag__decl_file = dwarf_tag__decl_file, + .tag__decl_line = dwarf_tag__decl_line, + .tag__orig_id = dwarf_tag__orig_id, + .tag__orig_type = dwarf_tag__orig_type, +}; + static void die__process(Dwarf_Die *die, struct cu *cu) { Dwarf_Die child; @@ -990,6 +1539,12 @@ static void die__process(Dwarf_Die *die, struct cu *cu) cu->language = attr_numeric(die, DW_AT_language); + struct dwarf_cu dcu; + + dwarf_cu__init(&dcu); + cu->priv = &dcu; + cu->orig_info = &dwarf_orig_info_ops; + if (dwarf_child(die, &child) == 0) die__process_unit(&child, cu); @@ -997,6 +1552,8 @@ static void die__process(Dwarf_Die *die, struct cu *cu) fprintf(stderr, "%s: got %s unexpected tag after " "DW_TAG_compile_unit!\n", __FUNCTION__, dwarf_tag_name(tag)); + + cu__recode_dwarf_types(cu); } static void cus__load_module(struct cus *self, Dwfl_Module *mod, Dwarf *dw) diff --git a/dwarves.c b/dwarves.c index 8c13610..57bf37c 100644 --- a/dwarves.c +++ b/dwarves.c @@ -25,14 +25,11 @@ #include "config.h" #include "ctf_loader.h" #include "dwarf_loader.h" -#include "hash.h" #include "list.h" #include "dwarves.h" #include "dutil.h" #include "strings.h" -#define hashtags__fn(key) hash_64(key, HASHTAGS__BITS) - struct strings *strings; static inline const char *s(strings_t i) @@ -191,11 +188,12 @@ static size_t __tag__id_not_found_fprintf(FILE *fp, Dwarf_Off id, #define tag__id_not_found_fprintf(fp, id) \ __tag__id_not_found_fprintf(fp, id, __func__) -size_t tag__fprintf_decl_info(const struct tag *self, FILE *fp) +size_t tag__fprintf_decl_info(const struct tag *self, + const struct cu *cu, FILE *fp) { - return fprintf(fp, "/* <%llx> %s:%u */\n", - (unsigned long long)self->id, - s(self->decl_file), self->decl_line); + return fprintf(fp, "/* <%llx> %s:%u */\n", tag__orig_id(self, cu), + tag__decl_file(self, cu), tag__decl_line(self, cu)); + return 0; } static size_t type__fprintf(struct tag *type, const struct cu *cu, @@ -237,22 +235,8 @@ void namespace__delete(struct namespace *self) tag__delete(&self->tag); } -const char *type__name(struct type *self, const struct cu *cu) +const char *type__name(struct type *self, const struct cu *cu __unused) { - /* Check if the tag doesn't comes with a DW_AT_name attribute... */ - if (!self->namespace.name && - /* No? So it can have a DW_TAG_specification... */ - self->specification != 0 && - cu != NULL) { - struct tag *tag = cu__find_type_by_id(cu, self->specification); - if (tag == NULL) { - tag__id_not_found_fprintf(stderr, self->specification); - return NULL; - } - /* ... and now we cache the result in this tag ->name field */ - self->namespace.name = tag__type(tag)->namespace.name; - } - return s(self->namespace.name); } @@ -293,11 +277,10 @@ reevaluate: case DW_TAG_const_type: case DW_TAG_typedef: case DW_TAG_volatile_type: { - const struct tag *tag = type; - - type = cu__find_type_by_id(cu, type->id); + struct tag *tag = type; + type = cu__find_type_by_id(cu, tag->type); if (type == NULL) { - tag__id_not_found_fprintf(stderr, tag->id); + tag__id_not_found_fprintf(stderr, tag->type); continue; } } @@ -440,6 +423,93 @@ void cus__add(struct cus *self, struct cu *cu) { list_add_tail(&cu->node, &self->cus); } + +static void ptr_table__init(struct ptr_table *self) +{ + self->entries = NULL; + self->nr_entries = self->allocated_entries = 0; +} + +static void ptr_table__exit(struct ptr_table *self) +{ + free(self->entries); + self->entries = NULL; +} + +static long ptr_table__add(struct ptr_table *self, void *ptr) +{ + const uint32_t nr_entries = self->nr_entries + 1; + const long rc = self->nr_entries; + + if (nr_entries > self->allocated_entries) { + uint32_t allocated_entries = self->allocated_entries + 256; + void *entries = realloc(self->entries, + sizeof(void *) * allocated_entries); + if (entries == NULL) + return -ENOMEM; + + self->allocated_entries = allocated_entries; + self->entries = entries; + } + + self->entries[rc] = ptr; + self->nr_entries = nr_entries; + return rc; +} + +static int ptr_table__add_with_id(struct ptr_table *self, void *ptr, + uint32_t id) +{ + /* Assume we won't be fed with the same id more than once */ + if (id >= self->allocated_entries) { + uint32_t allocated_entries = roundup(id + 1, 256); + void *entries = realloc(self->entries, + sizeof(void *) * allocated_entries); + if (entries == NULL) + return -ENOMEM; + + self->allocated_entries = allocated_entries; + self->entries = entries; + } + + self->entries[id] = ptr; + ++self->nr_entries; + return 0; +} + +static void *ptr_table__entry(const struct ptr_table *self, uint32_t id) +{ + return id >= self->nr_entries ? NULL : self->entries[id]; +} + +int cu__table_add_tag(struct cu *self, struct tag *tag, long *id) +{ + struct ptr_table *pt = tag__is_tag_type(tag) ? + &self->types_table : + &self->tags_table; + if (*id < 0) { + *id = ptr_table__add(pt, tag); + if (*id < 0) + return -ENOMEM; + } else if (ptr_table__add_with_id(pt, tag, *id) < 0) + return -ENOMEM; + return 0; +} + +int cu__table_nullify_type_entry(struct cu *self, uint32_t id) +{ + return ptr_table__add_with_id(&self->types_table, NULL, id); +} + +int cu__add_tag(struct cu *self, struct tag *tag, long *id) +{ + int err = cu__table_add_tag(self, tag, id); + + if (err == 0) + list_add_tail(&tag->node, &self->tags); + + return err; +} struct cu *cu__new(const char *name, uint8_t addr_size, const unsigned char *build_id, @@ -448,17 +518,23 @@ struct cu *cu__new(const char *name, uint8_t addr_size, struct cu *self = malloc(sizeof(*self) + build_id_len); if (self != NULL) { - uint32_t i; + self->name = strdup(name); + if (self->name == NULL) + goto out_free; - for (i = 0; i < HASHTAGS__SIZE; ++i) { - INIT_HLIST_HEAD(&self->hash_tags[i]); - INIT_HLIST_HEAD(&self->hash_types[i]); - } + ptr_table__init(&self->tags_table); + ptr_table__init(&self->types_table); + /* + * the first entry is historically associated with void, + * so make sure we don't use it + */ + if (ptr_table__add(&self->types_table, NULL) < 0) + goto out_free_name; + self->orig_info = NULL; INIT_LIST_HEAD(&self->tags); INIT_LIST_HEAD(&self->tool_list); - self->name = strdup(name); self->addr_size = addr_size; self->nr_inline_expansions = 0; @@ -472,8 +548,14 @@ struct cu *cu__new(const char *name, uint8_t addr_size, if (build_id_len > 0) memcpy(self->build_id, build_id, build_id_len); } - +out: return self; +out_free_name: + free(self->name); +out_free: + free(self); + self = NULL; + goto out; } void cu__delete(struct cu *self) @@ -487,49 +569,12 @@ void cu__delete(struct cu *self) if (tag__has_namespace(pos)) namespace__delete(tag__namespace(pos)); } + + ptr_table__exit(&self->tags_table); + ptr_table__exit(&self->types_table); free(self); } -static void hashtags__hash(struct hlist_head *hashtable, struct tag *tag) -{ - struct hlist_head *head = hashtable + hashtags__fn(tag->id); - - hlist_add_head(&tag->hash_node, head); -} - -static struct tag *hashtags__find(const struct hlist_head *hashtable, - const Dwarf_Off id) -{ - struct tag *tpos; - struct hlist_node *pos; - const struct hlist_head *head; - - if (id == 0) - return NULL; - - head = hashtable + hashtags__fn(id); - - hlist_for_each_entry(tpos, pos, head, hash_node) - if (tpos->id == id) - return tpos; - - return NULL; -} - -void cu__hash(struct cu *self, struct tag *tag) -{ - struct hlist_head *hashtable = tag__is_tag_type(tag) ? - self->hash_types : - self->hash_tags; - hashtags__hash(hashtable, tag); -} - -void cu__add_tag(struct cu *self, struct tag *tag) -{ - list_add_tail(&tag->node, &self->tags); - cu__hash(self, tag); -} - bool cu__same_build_id(const struct cu *self, const struct cu *other) { return self->build_id_len != 0 && @@ -553,90 +598,118 @@ static const char *tag__prefix(const struct cu *cu, const uint32_t tag) return ""; } -struct tag *cu__find_tag_by_id(const struct cu *self, const Dwarf_Off id) +struct tag *cu__find_tag_by_id(const struct cu *self, const uint32_t id) { - return self ? hashtags__find(self->hash_tags, id) : NULL; + return self ? ptr_table__entry(&self->tags_table, id) : NULL; } -struct tag *cu__find_type_by_id(const struct cu *self, const Dwarf_Off id) +struct tag *cu__find_type_by_id(const struct cu *self, const uint16_t id) { - return self ? hashtags__find(self->hash_types, id) : NULL; + return self ? ptr_table__entry(&self->types_table, id) : NULL; } struct tag *cu__find_first_typedef_of_type(const struct cu *self, const Dwarf_Off type) { + uint16_t id; struct tag *pos; if (self == NULL || type == 0) return NULL; - list_for_each_entry(pos, &self->tags, node) + cu__for_each_type(self, id, pos) if (tag__is_typedef(pos) && pos->type == type) return pos; return NULL; } -struct tag *cu__find_base_type_by_name(const struct cu *self, const char *name) +struct tag *cu__find_base_type_by_name(const struct cu *self, + const char *name, uint16_t *idp) { + uint16_t id; struct tag *pos; if (self == NULL || name == NULL) return NULL; - list_for_each_entry(pos, &self->tags, node) + strings_t sname = strings__find(strings, name); + if (sname == 0) + return NULL; + + cu__for_each_type(self, id, pos) { if (pos->tag == DW_TAG_base_type) { const struct base_type *bt = tag__base_type(pos); - if (bt->name && strcmp(s(bt->name), name) == 0) + if (bt->name == sname) { + if (idp != NULL) + *idp = id; return pos; + } } + } return NULL; } struct tag *cu__find_base_type_by_name_and_size(const struct cu *self, const char *name, - size_t bit_size) + size_t bit_size, + uint16_t *idp) { + uint16_t id; struct tag *pos; if (self == NULL || name == NULL) return NULL; - list_for_each_entry(pos, &self->tags, node) + strings_t sname = strings__find(strings, name); + if (sname == 0) + return NULL; + + cu__for_each_type(self, id, pos) { if (pos->tag == DW_TAG_base_type) { const struct base_type *bt = tag__base_type(pos); if (bt->bit_size == bit_size && - bt->name && strcmp(s(bt->name), name) == 0) + bt->name == sname) { + if (idp != NULL) + *idp = id; return pos; + } } + } return NULL; } struct tag *cu__find_struct_by_name(const struct cu *self, const char *name, - const int include_decls) + const int include_decls, uint16_t *idp) { + uint16_t id; struct tag *pos; if (self == NULL || name == NULL) return NULL; - list_for_each_entry(pos, &self->tags, node) { + strings_t sname = strings__find(strings, name); + if (sname == 0) + return NULL; + + cu__for_each_type(self, id, pos) { struct type *type; if (!tag__is_struct(pos)) continue; type = tag__type(pos); - if (type__name(type, self) != NULL && - strcmp(type__name(type, self), name) == 0) { + if (type->namespace.name == sname) { if (type->declaration) { - if (include_decls) + if (include_decls) { + if (idp != NULL) + *idp = id; return pos; + } } else return pos; } @@ -647,13 +720,14 @@ struct tag *cu__find_struct_by_name(const struct cu *self, const char *name, struct tag *cus__find_struct_by_name(const struct cus *self, struct cu **cu, const char *name, - const int include_decls) + const int include_decls, uint16_t *id) { struct cu *pos; list_for_each_entry(pos, &self->cus, node) { struct tag *tag = cu__find_struct_by_name(pos, name, - include_decls); + include_decls, + id); if (tag != NULL) { if (cu != NULL) *cu = pos; @@ -733,98 +807,6 @@ struct tag *cu__find_function_by_name(const struct cu *self, const char *name) return NULL; } -static struct tag *lexblock__find_tag_by_id(const struct lexblock *self, - const Dwarf_Off id) -{ - struct tag *pos; - - list_for_each_entry(pos, &self->tags, node) { - /* Allow find DW_TAG_lexical_block tags */ - if (pos->id == id) - return pos; - /* - * Oh, not looking for DW_TAG_lexical_block tags? So lets look - * inside this lexblock: - */ - if (pos->tag == DW_TAG_lexical_block) { - const struct lexblock *child = tag__lexblock(pos); - struct tag *tag = lexblock__find_tag_by_id(child, id); - - if (tag != NULL) - return tag; - } - } - - return NULL; -} - -static struct variable *cu__find_variable_by_id(const struct cu *self, - const Dwarf_Off id) -{ - struct tag *pos; - - if (self == NULL) - return NULL; - - list_for_each_entry(pos, &self->tags, node) { - /* Look at global variables first */ - if (pos->id == id) - return (struct variable *)(pos); - - /* Now look inside function lexical blocks */ - if (pos->tag == DW_TAG_subprogram) { - struct function *fn = tag__function(pos); - struct tag *tag = - lexblock__find_tag_by_id(&fn->lexblock, id); - - if (tag != NULL) - return (struct variable *)(tag); - } - } - - return NULL; -} - -static struct tag *list__find_tag_by_id(const struct list_head *self, - const Dwarf_Off id) -{ - struct tag *pos, *tag; - - list_for_each_entry(pos, self, node) { - if (pos->id == id) - return pos; - - switch (pos->tag) { - case DW_TAG_namespace: - case DW_TAG_class_type: - case DW_TAG_structure_type: - case DW_TAG_union_type: - tag = list__find_tag_by_id(&tag__namespace(pos)->tags, id); - break; - case DW_TAG_subprogram: - tag = list__find_tag_by_id(&tag__ftype(pos)->parms, id); - if (tag == NULL) - tag = list__find_tag_by_id(&tag__function(pos)->lexblock.tags, id); - break; - default: - continue; - } - - if (tag != NULL) - return tag; - } - - return NULL; -} - -static struct tag *cu__find_parameter_by_id(const struct cu *self, - const Dwarf_Off id) -{ - if (self == NULL) - return NULL; - return list__find_tag_by_id(&self->tags, id); -} - static size_t array_type__nr_entries(const struct array_type *self) { int i; @@ -978,14 +960,14 @@ const char *tag__name(const struct tag *self, const struct cu *cu, static struct tag *variable__type(const struct variable *self, const struct cu *cu) { - struct variable *var; + struct tag *var; if (self->tag.type != 0) return cu__find_type_by_id(cu, self->tag.type); else if (self->abstract_origin != 0) { - var = cu__find_variable_by_id(cu, self->abstract_origin); + var = cu__find_tag_by_id(cu, self->abstract_origin); if (var) - return variable__type(var, cu); + return variable__type(tag__variable(var), cu); } return NULL; @@ -1005,10 +987,10 @@ const char *variable__name(const struct variable *self, const struct cu *cu) return s(self->name); if (self->abstract_origin != 0) { - struct variable *var = - cu__find_variable_by_id(cu, self->abstract_origin); + struct tag *var = + cu__find_tag_by_id(cu, self->abstract_origin); if (var != NULL) - return s(var->name); + return s(tag__variable(var)->name); } return NULL; } @@ -1059,40 +1041,13 @@ size_t class_member__size(const struct class_member *self, return tag__size(type, cu); } -const char *parameter__name(struct parameter *self, const struct cu *cu) +const char *parameter__name(struct parameter *self, const struct cu *cu __unused) { - /* Check if the tag doesn't comes with a DW_AT_name attribute... */ - if (!self->name && self->abstract_origin != 0) { - /* No? Does it have a DW_AT_abstract_origin? */ - struct tag *alias = - cu__find_parameter_by_id(cu, self->abstract_origin); - if (alias == NULL) { - tag__id_not_found_fprintf(stderr, self->abstract_origin); - return NULL; - } - /* Now cache the result in this tag ->name field */ - self->name = tag__parameter(alias)->name; - } - return s(self->name); } -Dwarf_Off parameter__type(struct parameter *self, const struct cu *cu) +Dwarf_Off parameter__type(struct parameter *self, const struct cu *cu __unused) { - /* Check if the tag doesn't comes with a DW_AT_type attribute... */ - if (self->tag.type == 0 && self->abstract_origin != 0) { - /* No? Does it have a DW_AT_abstract_origin? */ - struct tag *alias = - cu__find_parameter_by_id(cu, self->abstract_origin); - if (alias == NULL) { - tag__id_not_found_fprintf(stderr, self->abstract_origin); - return 0; - } - /* Now cache the result in this tag ->name and type fields */ - self->name = tag__parameter(alias)->name; - self->tag.type = tag__parameter(alias)->tag.type; - } - return self->tag.type; } @@ -1476,25 +1431,8 @@ void lexblock__add_lexblock(struct lexblock *self, struct lexblock *child) list_add_tail(&child->tag.node, &self->tags); } -const char *function__name(struct function *self, const struct cu *cu) +const char *function__name(struct function *self, const struct cu *cu __unused) { - /* Check if the tag doesn't comes with a DW_AT_name attribute... */ - if (!self->name) { - /* No? So it must have a DW_AT_abstract_origin... */ - struct tag *tag = cu__find_tag_by_id(cu, - self->abstract_origin); - if (tag == NULL) { - /* ... or a DW_TAG_specification... */ - tag = cu__find_tag_by_id(cu, self->specification); - if (tag == NULL) { - tag__id_not_found_fprintf(stderr, self->specification); - return NULL; - } - } - /* ... and now we cache the result in this tag ->name field */ - self->name = tag__function(tag)->name; - } - return s(self->name); } @@ -1512,7 +1450,7 @@ const char *function__prototype(const struct function *self, return bf; } -int ftype__has_parm_of_type(const struct ftype *self, const struct tag *target, +int ftype__has_parm_of_type(const struct ftype *self, const uint16_t target, const struct cu *cu) { struct parameter *pos; @@ -1522,8 +1460,7 @@ int ftype__has_parm_of_type(const struct ftype *self, const struct tag *target, cu__find_type_by_id(cu, parameter__type(pos, cu)); if (type != NULL && type->tag == DW_TAG_pointer_type) { - type = cu__find_type_by_id(cu, type->type); - if (type != NULL && type->id == target->id) + if (type->type == target) return 1; } } @@ -1779,7 +1716,9 @@ static size_t ftype__fprintf_parms(const struct ftype *self, name = parameter__name(pos, cu); type = cu__find_type_by_id(cu, parameter__type(pos, cu)); if (type == NULL) { - stype = ""; + snprintf(sbf, sizeof(sbf), + "", pos->tag.type); + stype = sbf; goto print_it; } if (type->tag == DW_TAG_pointer_type) { @@ -1886,14 +1825,13 @@ static size_t function__tag_fprintf(const struct tag *tag, const struct cu *cu, default: printed = fprintf(fp, "%.*s", indent, tabs); n = fprintf(fp, "%s <%llx>", dwarf_tag_name(tag->tag), - (unsigned long long)tag->id); + tag__orig_id(tag, cu)); c += n; printed += n; break; } - return printed + fprintf(fp, "%-*.*s// %5u\n", 70 - c, 70 - c, " ", - tag->decl_line); + tag__decl_line(tag, cu)); } size_t lexblock__fprintf(const struct lexblock *self, const struct cu *cu, @@ -2452,7 +2390,7 @@ size_t tag__fprintf(struct tag *self, const struct cu *cu, if (pconf->show_decl_info) { printed += fprintf(fp, "%.*s", pconf->indent, tabs); - printed += tag__fprintf_decl_info(self, fp); + printed += tag__fprintf_decl_info(self, cu, fp); } printed += fprintf(fp, "%.*s", pconf->indent, tabs); @@ -2515,16 +2453,17 @@ size_t tag__fprintf(struct tag *self, const struct cu *cu, } int cu__for_each_tag(struct cu *self, - int (*iterator)(struct tag *tag, struct cu *cu, - void *cookie), + int (*iterator)(struct tag *tag, + struct cu *cu, void *cookie), void *cookie, - struct tag *(*filter)(struct tag *tag, struct cu *cu, - void *cookie)) + struct tag *(*filter)(struct tag *tag, + struct cu *cu, void *cookie)) { struct tag *pos; list_for_each_entry(pos, &self->tags, node) { struct tag *tag = pos; + if (filter != NULL) { tag = filter(pos, self, cookie); if (tag == NULL) diff --git a/dwarves.h b/dwarves.h index 5b5405f..e42234d 100644 --- a/dwarves.h +++ b/dwarves.h @@ -26,16 +26,66 @@ struct cus { struct cus *cus__new(void); -#define HASHTAGS__BITS 8 -#define HASHTAGS__SIZE (1UL << HASHTAGS__BITS) +struct ptr_table { + void **entries; + uint32_t nr_entries; + uint32_t allocated_entries; +}; + +/** + * cu__for_each_type - iterate thru all the type tags + * @cu: struct cu instance to iterate + * @pos: struct tag iterator + * @id: uint16_t tag id + * + * See cu__table_nullify_type_entry and users for the reason for + * the NULL test (hint: CTF Unknown types) + */ +#define cu__for_each_type(cu, id, pos) \ + for (id = 1, pos = cu->types_table.entries[id]; \ + id < cu->types_table.nr_entries; \ + pos = cu->types_table.entries[++id]) \ + if (pos == NULL) \ + continue; \ + else + +/** + * cu__for_each_function - iterate thru all the function tags + * @cu: struct cu instance to iterate + * @pos: struct function iterator + * @id: uint32_t tag id + */ +#define cu__for_each_function(cu, id, pos) \ + for (id = 0, pos = tag__function(cu->tags_table.entries[id]); \ + id < cu->tags_table.nr_entries; \ + pos = tag__function(cu->tags_table.entries[++id])) \ + if (pos->proto.tag.tag != DW_TAG_subprogram) \ + continue; \ + else + +struct tag; +struct cu; + +struct cu_orig_info { + const char *(*tag__decl_file)(const struct tag *self, + const struct cu *cu); + uint32_t (*tag__decl_line)(const struct tag *self, + const struct cu *cu); + unsigned long long (*tag__orig_id)(const struct tag *self, + const struct cu *cu); + unsigned long long (*tag__orig_type)(const struct tag *self, + const struct cu *cu); +}; struct cu { struct list_head node; struct list_head tags; - struct hlist_head hash_tags[HASHTAGS__SIZE]; - struct hlist_head hash_types[HASHTAGS__SIZE]; struct list_head tool_list; /* To be used by tools such as ctracer */ - const char *name; + struct ptr_table types_table; + struct ptr_table tags_table; + char *name; + void *priv; + struct cu_orig_info *orig_info; uint8_t addr_size; uint16_t language; unsigned long nr_inline_expansions; @@ -49,20 +99,18 @@ struct cu { unsigned char build_id[0]; }; -struct tag; - -void cu__hash(struct cu *cu, struct tag *tag); - +/** struct tag - basic representation of a debug info element + * @priv - extra data, for instance, DWARF offset, id, decl_{file,line} + * @top_level - + */ struct tag { struct list_head node; - struct hlist_node hash_node; - Dwarf_Off type; - Dwarf_Off id; - strings_t decl_file; - uint16_t decl_line; + uint16_t type; uint16_t tag; uint16_t visited:1; - uint16_t recursivity_level:15; + uint16_t top_level:1; + uint16_t recursivity_level; + void *priv; }; static inline int tag__is_enumeration(const struct tag *self) @@ -129,9 +177,28 @@ static inline int tag__is_tag_type(const struct tag *self) self->tag == DW_TAG_volatile_type; } -static inline const char *tag__decl_file(const struct tag *self) +static inline const char *tag__decl_file(const struct tag *self, + const struct cu *cu) { - return strings__ptr(strings, self->decl_file); + return cu->orig_info ? cu->orig_info->tag__decl_file(self, cu) : NULL; +} + +static inline uint32_t tag__decl_line(const struct tag *self, + const struct cu *cu) +{ + return cu->orig_info ? cu->orig_info->tag__decl_line(self, cu) : 0; +} + +static inline unsigned long long tag__orig_id(const struct tag *self, + const struct cu *cu) +{ + return cu->orig_info ? cu->orig_info->tag__orig_id(self, cu) : 0; +} + +static inline unsigned long long tag__orig_type(const struct tag *self, + const struct cu *cu) +{ + return cu->orig_info ? cu->orig_info->tag__orig_type(self, cu) : 0; } struct ptr_to_member_type { @@ -508,6 +575,11 @@ struct label { Dwarf_Off abstract_origin; }; +static inline struct label *tag__label(const struct tag *self) +{ + return (struct label *)self; +} + struct enumerator { struct tag tag; strings_t name; @@ -545,7 +617,8 @@ extern size_t enumeration__fprintf(const struct tag *tag_self, const struct conf_fprintf *conf, FILE *fp); extern size_t typedef__fprintf(const struct tag *tag_self, const struct cu *cu, const struct conf_fprintf *conf, FILE *fp); -extern size_t tag__fprintf_decl_info(const struct tag *self, FILE *fp); +size_t tag__fprintf_decl_info(const struct tag *self, + const struct cu *cu, FILE *fp); extern size_t tag__fprintf(struct tag *self, const struct cu *cu, const struct conf_fprintf *conf, FILE *fp); @@ -577,14 +650,17 @@ extern void cus__print_error_msg(const char *progname, const struct cus *cus, extern struct cu *cus__find_cu_by_name(const struct cus *self, const char *name); extern struct tag *cu__find_base_type_by_name(const struct cu *self, - const char *name); + const char *name, + uint16_t *id); struct tag *cu__find_base_type_by_name_and_size(const struct cu *self, const char *name, - size_t bit_size); + size_t bit_size, + uint16_t *id); extern struct tag *cus__find_struct_by_name(const struct cus *self, struct cu **cu, const char *name, - const int include_decls); + const int include_decls, + uint16_t *id); extern struct tag *cus__find_function_by_name(const struct cus *self, struct cu **cu, const char *name); @@ -595,15 +671,18 @@ struct cu *cu__new(const char *name, uint8_t addr_size, const unsigned char *build_id, int build_id_len); extern void cu__delete(struct cu *self); -void cu__add_tag(struct cu *self, struct tag *tag); +int cu__add_tag(struct cu *self, struct tag *tag, long *id); +int cu__table_add_tag(struct cu *self, struct tag *tag, long *id); +int cu__table_nullify_type_entry(struct cu *self, uint32_t id); extern struct tag *cu__find_tag_by_id(const struct cu *self, - const Dwarf_Off id); -struct tag *cu__find_type_by_id(const struct cu *self, const Dwarf_Off id); + const uint32_t id); +struct tag *cu__find_type_by_id(const struct cu *self, const uint16_t id); extern struct tag *cu__find_first_typedef_of_type(const struct cu *self, const Dwarf_Off type); extern struct tag *cu__find_struct_by_name(const struct cu *cu, const char *name, - const int include_decls); + const int include_decls, + uint16_t *id); extern bool cu__same_build_id(const struct cu *self, const struct cu *other); extern void cu__account_inline_expansions(struct cu *self); extern int cu__for_each_tag(struct cu *self, @@ -651,7 +730,7 @@ extern size_t ftype__fprintf(const struct ftype *self, const struct cu *cu, const int is_pointer, const int type_spacing, FILE *fp); extern int ftype__has_parm_of_type(const struct ftype *self, - const struct tag *target, + const uint16_t target, const struct cu *cu); void type__add_member(struct type *self, struct class_member *member); diff --git a/dwarves_reorganize.c b/dwarves_reorganize.c index c332f90..1b2475f 100644 --- a/dwarves_reorganize.c +++ b/dwarves_reorganize.c @@ -446,7 +446,8 @@ static void class__demote_bitfield_members(struct class *class, struct class_member *from, struct class_member *to, const struct base_type *old_type, - const struct base_type *new_type) + const struct base_type *new_type, + uint16_t new_type_id) { const uint8_t bit_diff = old_type->bit_size - new_type->bit_size; struct class_member *member = @@ -459,7 +460,7 @@ static void class__demote_bitfield_members(struct class *class, * Assume IA32 bitfield layout */ member->bit_offset -= bit_diff; - member->tag.type = new_type->tag.id; + member->tag.type = new_type_id; if (member == to) break; member->bit_hole = 0; @@ -467,7 +468,7 @@ static void class__demote_bitfield_members(struct class *class, } static struct tag *cu__find_base_type_of_size(const struct cu *cu, - const size_t size) + const size_t size, uint16_t *id) { const char *type_name, *type_name_alt = NULL; @@ -493,8 +494,8 @@ static struct tag *cu__find_base_type_of_size(const struct cu *cu, return NULL; } - struct tag *ret = cu__find_base_type_by_name(cu, type_name); - return ret ?: cu__find_base_type_by_name(cu, type_name_alt); + struct tag *ret = cu__find_base_type_by_name(cu, type_name, id); + return ret ?: cu__find_base_type_by_name(cu, type_name_alt, id); } static int class__demote_bitfields(struct class *class, const struct cu *cu, @@ -543,8 +544,10 @@ static int class__demote_bitfields(struct class *class, const struct cu *cu, if (bytes_needed == size) continue; + uint16_t new_type_id; old_type_tag = cu__find_type_by_id(cu, member->tag.type); - new_type_tag = cu__find_base_type_of_size(cu, bytes_needed); + new_type_tag = cu__find_base_type_of_size(cu, bytes_needed, + &new_type_id); if (new_type_tag == NULL) { fprintf(fp, "/* BRAIN FART ALERT! couldn't find a " @@ -562,7 +565,8 @@ static int class__demote_bitfields(struct class *class, const struct cu *cu, class__demote_bitfield_members(class, bitfield_head, member, tag__base_type(old_type_tag), - tag__base_type(new_type_tag)); + tag__base_type(new_type_tag), + new_type_id); new_size = class_member__size(member, cu); member->hole = size - new_size; if (member->hole != 0) @@ -593,8 +597,10 @@ static int class__demote_bitfields(struct class *class, const struct cu *cu, if (bytes_needed < size) { old_type_tag = cu__find_type_by_id(cu, member->tag.type); + uint16_t new_type_id; new_type_tag = - cu__find_base_type_of_size(cu, bytes_needed); + cu__find_base_type_of_size(cu, bytes_needed, + &new_type_id); tag__assert_search_result(old_type_tag); tag__assert_search_result(new_type_tag); @@ -608,7 +614,8 @@ static int class__demote_bitfields(struct class *class, const struct cu *cu, class__demote_bitfield_members(class, member, member, tag__base_type(old_type_tag), - tag__base_type(new_type_tag)); + tag__base_type(new_type_tag), + new_type_id); new_size = class_member__size(member, cu); member->hole = 0; /* @@ -667,7 +674,7 @@ restart: static void class__fixup_bitfield_types(struct class *self, struct class_member *from, struct class_member *to_before, - Dwarf_Off type) + uint16_t type) { struct class_member *member = list_prepare_entry(from, class__tags(self), tag.node); @@ -733,9 +740,11 @@ static void class__fixup_member_types(struct class *self, const struct cu *cu, const size_t size = class_member__size(bitfield_head, cu); if (real_size != size) { + uint16_t new_type_id; struct tag *new_type_tag = cu__find_base_type_of_size(cu, - real_size); + real_size, + &new_type_id); if (new_type_tag == NULL) { fprintf(stderr, "pahole: couldn't find" " a base_type of %d bytes!\n", @@ -744,7 +753,7 @@ static void class__fixup_member_types(struct class *self, const struct cu *cu, } class__fixup_bitfield_types(self, bitfield_head, pos, - new_type_tag->id); + new_type_id); fixup_was_done = 1; } } diff --git a/pahole.c b/pahole.c index f5f2786..551127e 100644 --- a/pahole.c +++ b/pahole.c @@ -63,9 +63,10 @@ struct structure { const struct cu *cu; uint32_t nr_files; uint32_t nr_methods; + uint16_t id; }; -static struct structure *structure__new(struct class *class, +static struct structure *structure__new(struct class *class, uint16_t id, const struct cu *cu) { struct structure *self = malloc(sizeof(*self)); @@ -75,6 +76,7 @@ static struct structure *structure__new(struct class *class, self->cu = cu; self->nr_files = 1; self->nr_methods = 0; + self->id = id; } return self; @@ -84,9 +86,10 @@ static void *structures__tree; static LIST_HEAD(structures__anonymous_list); static LIST_HEAD(structures__named_list); -static void structures__add_anonymous(struct class *class, const struct cu *cu) +static void structures__add_anonymous(struct class *class, uint16_t id, + const struct cu *cu) { - struct structure *str = structure__new(class, cu); + struct structure *str = structure__new(class, id, cu); if (str != NULL) list_add_tail(&str->node, &structures__anonymous_list); @@ -100,7 +103,8 @@ static int structure__compare(const void *a, const void *b) return strings__cmp(strings, *key, pos->class->type.namespace.name); } -static int structures__add_named(struct class *class, const struct cu *cu) +static int structures__add_named(struct class *class, uint16_t id, + const struct cu *cu) { struct structure *str; strings_t *s = tsearch(&class->type.namespace.name, &structures__tree, @@ -113,7 +117,7 @@ static int structures__add_named(struct class *class, const struct cu *cu) * calling structures__add_named */ assert(*s != class->type.namespace.name); - str = structure__new(class, cu); + str = structure__new(class, id, cu); if (str == NULL) return -ENOMEM; @@ -125,17 +129,15 @@ static int structures__add_named(struct class *class, const struct cu *cu) return 0; } -static int structures__add(struct class *class, const struct cu *cu) +static int structures__add(struct class *class, uint16_t id, + const struct cu *cu) { - /* Let it follow abstract_origin, etc */ - class__name(class, cu); - if (!class->type.namespace.name) { - structures__add_anonymous(class, cu); + structures__add_anonymous(class, id, cu); return 0; } - return structures__add_named(class, cu); + return structures__add_named(class, id, cu); } static struct structure *structures__find_anonymous(strings_t name) @@ -144,7 +146,7 @@ static struct structure *structures__find_anonymous(strings_t name) list_for_each_entry(pos, &structures__anonymous_list, node) { struct class *c = pos->class; - const struct tag *tdef = cu__find_first_typedef_of_type(pos->cu, class__tag(c)->id); + const struct tag *tdef = cu__find_first_typedef_of_type(pos->cu, pos->id); if (tdef == NULL) continue; @@ -225,7 +227,7 @@ static void class_formatter(struct structure *self) * affected. */ typedef_alias = cu__find_first_typedef_of_type(self->cu, - tag->id); + self->id); /* * If there is no typedefs for this anonymous struct it is * found just inside another struct, and in this case it'll @@ -265,7 +267,7 @@ static void print_packable_info(struct structure *pos) /* Anonymous struct? Try finding a typedef */ if (name == NULL) { const struct tag *tdef = - cu__find_first_typedef_of_type(pos->cu, t->id); + cu__find_first_typedef_of_type(pos->cu, pos->id); if (tdef != NULL) name = class__name(tag__class(tdef), pos->cu); @@ -278,7 +280,8 @@ static void print_packable_info(struct structure *pos) savings); else printf("%s(%d)%c%zd%c%zd%c%zd\n", - tag__decl_file(t), t->decl_line, + tag__decl_file(t, pos->cu), + tag__decl_line(t, pos->cu), separator, orig_size, separator, new_size, separator, @@ -391,7 +394,7 @@ static void class__chkdupdef(struct class *self, const struct cu *cu, } static struct tag *tag__filter(struct tag *tag, struct cu *cu, - void *cookie __unused) + uint16_t tag_id) { struct structure *str; struct class *class; @@ -401,6 +404,9 @@ static struct tag *tag__filter(struct tag *tag, struct cu *cu, if (!tag__is_struct(tag)) return NULL; + if (!tag->top_level) + return NULL; + class = tag__class(tag); name = class__name(class, cu); stname = class->type.namespace.name; @@ -414,7 +420,7 @@ static struct tag *tag__filter(struct tag *tag, struct cu *cu, if (class__exclude_prefix != NULL) { if (name == NULL) { const struct tag *tdef = - cu__find_first_typedef_of_type(cu, tag->id); + cu__find_first_typedef_of_type(cu, tag_id); if (tdef != NULL) { struct class *c = tag__class(tdef); @@ -422,7 +428,6 @@ static struct tag *tag__filter(struct tag *tag, struct cu *cu, stname = c->type.namespace.name; } } - if (name != NULL && strncmp(class__exclude_prefix, name, class__exclude_prefix_len) == 0) return NULL; @@ -431,7 +436,7 @@ static struct tag *tag__filter(struct tag *tag, struct cu *cu, if (class__include_prefix != NULL) { if (name == NULL) { const struct tag *tdef = - cu__find_first_typedef_of_type(cu, tag->id); + cu__find_first_typedef_of_type(cu, tag_id); if (tdef != NULL) { struct class *c = tag__class(tdef); @@ -439,7 +444,6 @@ static struct tag *tag__filter(struct tag *tag, struct cu *cu, stname = c->type.namespace.name; } } - if (name != NULL && strncmp(class__include_prefix, name, class__include_prefix_len) != 0) return NULL; @@ -447,8 +451,8 @@ static struct tag *tag__filter(struct tag *tag, struct cu *cu, if (decl_exclude_prefix != NULL && - (!tag->decl_file || - strncmp(decl_exclude_prefix, tag__decl_file(tag), + (!tag__decl_file(tag, cu) || + strncmp(decl_exclude_prefix, tag__decl_file(tag, cu), decl_exclude_prefix_len) == 0)) return NULL; @@ -473,26 +477,23 @@ static struct tag *tag__filter(struct tag *tag, struct cu *cu, return tag; } -static int unique_iterator(struct tag *tag, struct cu *cu, - void *cookie __unused) +static int cu_unique_iterator(struct cu *cu, void *cookie __unused) { - if (structures__add(tag__class(tag), cu)) { - fprintf(stderr, "pahole: not enough memory! " - "Continuing with partial results\n"); - return -1; - } - return 0; -} + uint16_t id; + struct tag *tag; -static int cu_unique_iterator(struct cu *cu, void *cookie) -{ if (defined_in) { - struct tag *tag = cu__find_struct_by_name(cu, class_name, 0); - + tag = cu__find_struct_by_name(cu, class_name, 0, &id); if (tag != NULL) puts(cu->name); - } else - return cu__for_each_tag(cu, unique_iterator, cookie, tag__filter); + } else { + cu__for_each_type(cu, id, tag) { + if (tag__filter(tag, cu, id) && + structures__add(tag__class(tag), id, cu)) + fprintf(stderr, "pahole: not enough memory! " + "Continuing with partial results\n"); + } + } return 0; } @@ -728,7 +729,7 @@ static char tab[128]; static void print_structs_with_pointer_to(const struct structure *s) { struct structure *pos_structure; - Dwarf_Off type; + uint16_t type; const char *class_name = class__name(s->class, s->cu); const struct cu *current_cu = NULL; @@ -737,13 +738,16 @@ static void print_structs_with_pointer_to(const struct structure *s) struct class_member *pos_member; if (pos_structure->cu != current_cu) { + uint16_t class_id; struct tag *class; - class = cu__find_struct_by_name(pos_structure->cu, class_name, 1); + class = cu__find_struct_by_name(pos_structure->cu, + class_name, 1, + &class_id); if (class == NULL) continue; current_cu = pos_structure->cu; - type = class->id; + type = class_id; } type__for_each_member(&c->type, pos_member) { @@ -760,7 +764,7 @@ static void print_structs_with_pointer_to(const struct structure *s) static void print_containers(const struct structure *s, int ident) { struct structure *pos; - const Dwarf_Off type = s->class->type.namespace.tag.id; + const uint16_t type = s->id; list_for_each_entry(pos, &structures__named_list, node) { struct class *c = pos->class; diff --git a/pdwtags.c b/pdwtags.c index bc041b5..f443b51 100644 --- a/pdwtags.c +++ b/pdwtags.c @@ -18,46 +18,43 @@ static struct conf_fprintf conf = { .emit_stats = 1, }; -static int emit_tag(struct tag *self, struct cu *cu, void *cookie __unused) +static void emit_tag(struct tag *self, uint32_t tag_id, struct cu *cu) { - if (self->tag != DW_TAG_array_type && - self->tag != DW_TAG_const_type && - self->tag != DW_TAG_formal_parameter && - self->tag != DW_TAG_reference_type && - self->tag != DW_TAG_subroutine_type && - self->tag != DW_TAG_volatile_type) { - if (tag__is_struct(self)) - class__find_holes(tag__class(self), cu); + if (tag__is_struct(self)) + class__find_holes(tag__class(self), cu); - conf.no_semicolon = self->tag == DW_TAG_subprogram; + conf.no_semicolon = self->tag == DW_TAG_subprogram; - printf("%lld ", (unsigned long long)self->id); + printf("%d ", tag_id); - if (self->tag == DW_TAG_base_type) { - const char *name = base_type__name(tag__base_type(self)); + if (self->tag == DW_TAG_base_type) { + const char *name = base_type__name(tag__base_type(self)); - if (name == NULL) - printf("anonymous base_type\n"); - else - puts(name); - } else if (self->tag == DW_TAG_pointer_type) - printf("pointer to %lld\n", (unsigned long long)self->type); + if (name == NULL) + printf("anonymous base_type\n"); else - tag__fprintf(self, cu, &conf, stdout); + puts(name); + } else if (self->tag == DW_TAG_pointer_type) + printf("pointer to %lld\n", (unsigned long long)self->type); + else + tag__fprintf(self, cu, &conf, stdout); - if (self->tag == DW_TAG_subprogram) { - struct function *fn = tag__function(self); - putchar('\n'); - lexblock__fprintf(&fn->lexblock, cu, fn, 0, stdout); - } - puts("\n"); + if (self->tag == DW_TAG_subprogram) { + struct function *fn = tag__function(self); + putchar('\n'); + lexblock__fprintf(&fn->lexblock, cu, fn, 0, stdout); } - return 0; + puts("\n"); } static int cu__emit_tags(struct cu *self, void *cookie __unused) { - cu__for_each_tag(self, emit_tag, NULL, NULL); + uint16_t i; + + for (i = 1; i < self->types_table.nr_entries; ++i) { + struct tag *tag = self->types_table.entries[i]; + emit_tag(tag, i, self); + } return 0; } diff --git a/pfunct.c b/pfunct.c index b2431df..03d3c73 100644 --- a/pfunct.c +++ b/pfunct.c @@ -218,6 +218,9 @@ static struct tag *function__filter(struct tag *tag, struct cu *cu, if (tag->tag != DW_TAG_subprogram) return NULL; + if (!tag->top_level) + return NULL; + function = tag__function(tag); /* * FIXME: remove this check and try to fix the parameter abstract @@ -271,6 +274,7 @@ static int cu_unique_iterator(struct cu *cu, void *cookie) static int class_iterator(struct tag *tag, struct cu *cu, void *cookie) { + uint16_t *target_id = cookie; struct function *function; if (tag->tag != DW_TAG_subprogram) @@ -280,7 +284,7 @@ static int class_iterator(struct tag *tag, struct cu *cu, void *cookie) if (function->inlined) return 0; - if (ftype__has_parm_of_type(&function->proto, cookie, cu)) { + if (ftype__has_parm_of_type(&function->proto, *target_id, cu)) { if (verbose) tag__fprintf(tag, cu, &conf, stdout); else @@ -292,12 +296,13 @@ static int class_iterator(struct tag *tag, struct cu *cu, void *cookie) static int cu_class_iterator(struct cu *cu, void *cookie) { - struct tag *target = cu__find_struct_by_name(cu, cookie, 0); + uint16_t target_id; + struct tag *target = cu__find_struct_by_name(cu, cookie, 0, &target_id); if (target == NULL) return 0; - return cu__for_each_tag(cu, class_iterator, target, NULL); + return cu__for_each_tag(cu, class_iterator, &target_id, NULL); } static int function__emit_type_definitions(struct function *self, diff --git a/prefcnt.c b/prefcnt.c index ed2e774..a99d246 100644 --- a/prefcnt.c +++ b/prefcnt.c @@ -135,7 +135,7 @@ static int cu_refcnt_iterator(struct cu *cu, void *cookie) static int lost_iterator(struct tag *tag, struct cu *cu, void *cookie __unused) { - if (!tag->visited && tag->decl_file) { + if (!tag->visited && tag__decl_file(tag, cu)) { tag__fprintf(tag, cu, NULL, stdout); puts(";\n"); }