diff --git a/CMakeLists.txt b/CMakeLists.txt index e05ea0d..a49b0dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,7 @@ if (NOT CMAKE_BUILD_TYPE) FORCE) endif (NOT CMAKE_BUILD_TYPE) -add_definitions(-D_GNU_SOURCE) +add_definitions(-D_GNU_SOURCE -DDWARVES_VERSION=\\"v1.7\\") find_package(DWARF REQUIRED) find_package(ZLIB REQUIRED) @@ -89,6 +89,7 @@ install(TARGETS codiff ctracer dtagnames pahole pdwtags install(TARGETS dwarves LIBRARY DESTINATION ${LIB_INSTALL_DIR}) install(TARGETS dwarves dwarves_emit dwarves_reorganize LIBRARY DESTINATION ${LIB_INSTALL_DIR}) install(FILES dwarves.h dwarves_emit.h dwarves_reorganize.h DESTINATION ${CMAKE_INSTALL_PREFIX}/include) +install(FILES man-pages/pahole.1 DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man1/) install(PROGRAMS ostra/ostra-cg DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) install(FILES ostra/python/ostra.py DESTINATION ${CMAKE_INSTALL_PREFIX}/share/dwarves/runtime/python) install(FILES lib/Makefile lib/ctracer_relay.c lib/ctracer_relay.h lib/linux.blacklist.cu diff --git a/MANIFEST b/MANIFEST index a2f1b71..0097547 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1,3 +1,4 @@ +config.h.cmake ctf_loader.c ctf_loader.h dwarf_loader.c @@ -13,15 +14,20 @@ CMakeLists.txt codiff.c ctracer.c dtagnames.c +gobuffer.c +gobuffer.h hash.h list.h MANIFEST +man-pages/pahole.1 pahole.c pdwtags.c pfunct.c pglobal.c prefcnt.c syscse.c +strings.c +strings.h dutil.c dutil.h NEWS diff --git a/codiff.c b/codiff.c index 1ddbee3..07fb01b 100644 --- a/codiff.c +++ b/codiff.c @@ -33,6 +33,9 @@ static struct strlist *structs_printed; #define TCHANGEF__OFFSET (1 << 3) #define TCHANGEF__BIT_OFFSET (1 << 4) #define TCHANGEF__BIT_SIZE (1 << 5) +#define TCHANGEF__PADDING (1 << 6) +#define TCHANGEF__NR_HOLES (1 << 7) +#define TCHANGEF__NR_BIT_HOLES (1 << 8) static uint32_t terse_type_changes; @@ -69,8 +72,6 @@ static void diff_function(const struct cu *new_cu, struct function *function, struct tag *new_tag; const char *name; - assert(function->proto.tag.tag == DW_TAG_subprogram); - if (function->inlined || function->abstract_origin != 0) return; @@ -126,8 +127,8 @@ static int check_print_change(const struct class_member *old, { size_t old_size, new_size; char old_type_name[128], new_type_name[128]; - const struct tag *old_type = cu__find_tag_by_id(old_cu, old->tag.type); - const struct tag *new_type = cu__find_tag_by_id(new_cu, new->tag.type); + const struct tag *old_type = cu__find_type_by_id(old_cu, old->tag.type); + const struct tag *new_type = cu__find_type_by_id(new_cu, new->tag.type); int changes = 0; if (old_type == NULL || new_type == NULL) @@ -163,8 +164,8 @@ static int check_print_change(const struct class_member *old, if (changes && print && !show_terse_type_changes) printf(" %s\n" - " from: %-21s /* %5u(%u) %5zd(%d) */\n" - " to: %-21s /* %5u(%u) %5zd(%u) */\n", + " from: %-21s /* %5u(%2u) %5zd(%2d) */\n" + " to: %-21s /* %5u(%2u) %5zd(%2u) */\n", class_member__name(old), old_type_name, old->offset, old->bit_offset, old_size, old->bit_size, @@ -182,15 +183,54 @@ static int check_print_members_changes(const struct class *structure, { int changes = 0; struct class_member *member; + uint16_t nr_twins_found = 0; type__for_each_member(&structure->type, member) { + const char *member_name = class_member__name(member); struct class_member *twin = - class__find_member_by_name(new_structure, - class_member__name(member)); - if (twin != NULL) + class__find_member_by_name(new_structure, member_name); + if (twin != NULL) { + twin->tag.visited = 1; + ++nr_twins_found; if (check_print_change(member, cu, twin, new_cu, print)) changes = 1; + } else { + changes = 1; + if (print) { + char name[128]; + struct tag *type; + type = cu__find_type_by_id(cu, member->tag.type); + printf(" %s\n" + " removed: %-21s /* %5u(%2u) %5zd(%2d) */\n", + class_member__name(member), + tag__name(type, cu, name, sizeof(name)), + member->offset, member->bit_offset, + tag__size(type, cu), member->bit_size); + } + } } + + if (nr_twins_found == new_structure->type.nr_members) + goto out; + + changes = 1; + if (!print) + goto out; + + type__for_each_member(&new_structure->type, member) { + if (!member->tag.visited) { + char name[128]; + struct tag *type; + type = cu__find_type_by_id(new_cu, member->tag.type); + printf(" %s\n" + " added: %-21s /* %5u(%2u) %5zd(%2d) */\n", + class_member__name(member), + tag__name(type, new_cu, name, sizeof(name)), + member->offset, member->bit_offset, + tag__size(type, new_cu), member->bit_size); + } + } +out: return changes; } @@ -204,10 +244,11 @@ static void diff_struct(const struct cu *new_cu, struct class *structure, assert(class__is_struct(structure)); - if (class__size(structure) == 0 || class__name(structure, cu) == NULL) + if (class__size(structure) == 0 || class__name(structure) == 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), 0, NULL); if (new_tag == NULL) return; @@ -220,12 +261,16 @@ static void diff_struct(const struct cu *new_cu, struct class *structure, diff = class__size(structure) != class__size(new_structure) || class__nr_members(structure) != class__nr_members(new_structure) || check_print_members_changes(structure, cu, - new_structure, new_cu, 0); + new_structure, new_cu, 0) || + structure->padding != new_structure->padding || + structure->nr_holes != new_structure->nr_holes || + structure->nr_bit_holes != new_structure->nr_bit_holes; + if (diff == 0) return; ++cu->nr_structures_changed; - len = strlen(class__name(structure, cu)) + sizeof("struct"); + len = strlen(class__name(structure)) + sizeof("struct"); if (len > cu->max_len_changed_item) cu->max_len_changed_item = len; structure->priv = diff_info__new(class__tag(new_structure), @@ -236,7 +281,7 @@ static int diff_tag_iterator(struct tag *tag, struct cu *cu, void *new_cu) { if (tag__is_struct(tag)) diff_struct(new_cu, tag__class(tag), cu); - else if (tag->tag == DW_TAG_subprogram) + else if (tag__is_function(tag)) diff_function(new_cu, tag__function(tag), cu); return 0; @@ -249,8 +294,6 @@ static int find_new_functions_iterator(struct tag *tfunction, struct cu *cu, struct tag *old_function; const char *name; - assert(function->proto.tag.tag == DW_TAG_subprogram); - if (function->inlined) return 0; @@ -280,19 +323,20 @@ static int find_new_classes_iterator(struct tag *tag, struct cu *cu, void *old_c return 0; class = tag__class(tag); - if (class__name(class, cu) == NULL) + if (class__name(class) == NULL) return 0; 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), 0, NULL) != NULL) return 0; class->priv = diff_info__new(NULL, NULL, 1); ++cu->nr_structures_changed; - len = strlen(class__name(class, cu)) + sizeof("struct"); + len = strlen(class__name(class)) + sizeof("struct"); if (len > cu->max_len_changed_item) cu->max_len_changed_item = len; return 0; @@ -300,7 +344,7 @@ static int find_new_classes_iterator(struct tag *tag, struct cu *cu, void *old_c static int find_new_tags_iterator(struct tag *tag, struct cu *cu, void *old_cu) { - if (tag->tag == DW_TAG_subprogram) { + if (tag__is_function(tag)) { /* * We're not interested in aliases, just real function definitions, * where we'll know if the kind of inlining @@ -319,8 +363,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; } @@ -396,7 +439,7 @@ static void show_diffs_function(struct function *function, const struct cu *cu, static void show_changed_member(char change, const struct class_member *member, const struct cu *cu) { - const struct tag *type = cu__find_tag_by_id(cu, member->tag.type); + const struct tag *type = cu__find_type_by_id(cu, member->tag.type); char bf[128]; tag__assert_search_result(type); @@ -432,12 +475,11 @@ static void show_nr_members_changes(const struct class *structure, } } -static void print_terse_type_changes(struct class *structure, - const struct cu *cu) +static void print_terse_type_changes(struct class *structure) { const char *sep = ""; - printf("struct %s: ", class__name(structure, cu)); + printf("struct %s: ", class__name(structure)); if (terse_type_changes & TCHANGEF__SIZE) { fputs("size", stdout); @@ -459,8 +501,20 @@ static void print_terse_type_changes(struct class *structure, printf("%sbit_offset", sep); sep = ", "; } - if (terse_type_changes & TCHANGEF__BIT_SIZE) + if (terse_type_changes & TCHANGEF__BIT_SIZE) { printf("%sbit_size", sep); + sep = ", "; + } + if (terse_type_changes & TCHANGEF__PADDING) { + printf("%spadding", sep); + sep = ", "; + } + if (terse_type_changes & TCHANGEF__NR_HOLES) { + printf("%snr_holes", sep); + sep = ", "; + } + if (terse_type_changes & TCHANGEF__NR_BIT_HOLES) + printf("%snr_bit_holes", sep); putchar('\n'); } @@ -495,7 +549,7 @@ static void show_diffs_structure(struct class *structure, printf(" struct %-*.*s | %+4d\n", (int)(cu->max_len_changed_item - sizeof("struct")), (int)(cu->max_len_changed_item - sizeof("struct")), - class__name(structure, cu), diff); + class__name(structure), diff); if (diff != 0) terse_type_changes |= TCHANGEF__SIZE; @@ -517,11 +571,31 @@ static void show_diffs_structure(struct class *structure, new_structure, di->cu); } } - if (new_structure != NULL) + if (new_structure != NULL) { + diff = (int)new_structure->padding - (int)structure->padding; + if (diff) { + terse_type_changes |= TCHANGEF__PADDING; + if (!show_terse_type_changes) + printf(" padding: %+d\n", diff); + } + diff = (int)new_structure->nr_holes - (int)structure->nr_holes; + if (diff) { + terse_type_changes |= TCHANGEF__NR_HOLES; + if (!show_terse_type_changes) + printf(" nr_holes: %+d\n", diff); + } + diff = ((int)new_structure->nr_bit_holes - + (int)structure->nr_bit_holes); + if (structure->nr_bit_holes != new_structure->nr_bit_holes) { + terse_type_changes |= TCHANGEF__NR_BIT_HOLES; + if (!show_terse_type_changes) + printf(" nr_bit_holes: %+d\n", diff); + } check_print_members_changes(structure, cu, new_structure, di->cu, 1); + } if (show_terse_type_changes) - print_terse_type_changes(structure, cu); + print_terse_type_changes(structure); } static int show_function_diffs_iterator(struct tag *tag, struct cu *cu, @@ -529,7 +603,7 @@ static int show_function_diffs_iterator(struct tag *tag, struct cu *cu, { struct function *function = tag__function(tag); - if (tag->tag == DW_TAG_subprogram && function->priv != NULL) + if (tag__is_function(tag) && function->priv != NULL) show_diffs_function(function, cu, cookie); return 0; } @@ -544,7 +618,7 @@ static int show_structure_diffs_iterator(struct tag *tag, struct cu *cu, class = tag__class(tag); if (class->priv != NULL) { - const char *name = class__name(class, cu); + const char *name = class__name(class); if (!strlist__has_entry(structs_printed, name)) { show_diffs_structure(class, cu); strlist__add(structs_printed, name); @@ -624,6 +698,9 @@ static void print_total_function_diff(const char *filename) putchar('\n'); } +/* Name and version of program. */ +ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version; + static const struct argp_option codiff__options[] = { { .key = 's', @@ -676,7 +753,7 @@ int main(int argc, char *argv[]) int remaining, err; struct cus *old_cus, *new_cus; char *old_filename, *new_filename; - char *dwfl_argv[4]; + char *filenames[2]; struct stat st; if (dwarves__init(0)) { @@ -684,9 +761,8 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } - argp_parse(&codiff__argp, argc, argv, 0, &remaining, NULL); - - if (remaining < argc) { + if (argp_parse(&codiff__argp, argc, argv, 0, &remaining, NULL) || + remaining < argc) { switch (argc - remaining) { case 2: old_filename = argv[remaining++]; new_filename = argv[remaining++]; break; @@ -695,7 +771,7 @@ int main(int argc, char *argv[]) } } else { failure: - argp_help(&codiff__argp, stderr, ARGP_HELP_SEE, "codiff"); + argp_help(&codiff__argp, stderr, ARGP_HELP_SEE, argv[0]); return EXIT_FAILURE; } @@ -716,14 +792,12 @@ failure: return EXIT_FAILURE; } - dwfl_argv[0] = argv[0]; - dwfl_argv[1] = "-e"; - dwfl_argv[3] = NULL; + filenames[1] = NULL; /* If old_file is a character device, leave its cus empty */ if (!S_ISCHR(st.st_mode)) { - dwfl_argv[2] = old_filename; - err = cus__loadfl(old_cus, NULL, 3, dwfl_argv); + filenames[0] = old_filename; + err = cus__loadfl(old_cus, filenames); if (err != 0) { cus__print_error_msg("codiff", old_cus, old_filename, err); return EXIT_FAILURE; @@ -737,8 +811,8 @@ failure: /* If old_file is a character device, leave its cus empty */ if (!S_ISCHR(st.st_mode)) { - dwfl_argv[2] = new_filename; - err = cus__loadfl(new_cus, NULL, 3, dwfl_argv); + filenames[0] = new_filename; + err = cus__loadfl(new_cus, filenames); if (err != 0) { cus__print_error_msg("codiff", new_cus, new_filename, err); return EXIT_FAILURE; diff --git a/ctf_loader.c b/ctf_loader.c index 132cf72..6dc1f2c 100644 --- a/ctf_loader.c +++ b/ctf_loader.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include @@ -38,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); @@ -130,7 +139,7 @@ static void elf_symbol_iterate(struct ctf_state *sp, } #endif -static int parse_elf(struct ctf_state *sp) +static int parse_elf(struct ctf_state *sp, int *wordsizep) { GElf_Ehdr ehdr; GElf_Shdr shdr; @@ -163,6 +172,12 @@ static int parse_elf(struct ctf_state *sp) else sec = elf_section_by_name(sp->elf, &ehdr, &shdr, ".symtab"); + switch (ehdr.e_ident[EI_CLASS]) { + case ELFCLASS32: *wordsizep = 4; break; + case ELFCLASS64: *wordsizep = 8; break; + default: *wordsizep = 0; break; + } + if (!sec) return 0; @@ -321,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); @@ -330,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); } @@ -366,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; @@ -376,8 +389,6 @@ static int create_new_base_type(struct ctf_state *sp, void *ptr, if (attrs & CTF_TYPE_INT_SIGNED) buf += sprintf(buf, "signed "); - if (attrs & CTF_TYPE_INT_CHAR) - buf += sprintf(buf, "char "); if (attrs & CTF_TYPE_INT_BOOL) buf += sprintf(buf, "bool "); if (attrs & CTF_TYPE_INT_VARARGS) @@ -390,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); } @@ -399,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]; @@ -414,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); } @@ -423,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"); @@ -441,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"); @@ -467,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]); @@ -487,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; } @@ -513,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); - hashtags__hash(sp->cu->hash_tags, &member->tag); } return sizeof(*mp); @@ -540,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); - hashtags__hash(sp->cu->hash_tags, &member->tag); } return sizeof(*mp); @@ -548,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); @@ -560,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); @@ -579,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); } @@ -587,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); @@ -600,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? */ @@ -621,32 +626,31 @@ static int create_new_enumeration(struct ctf_state *sp, void *ptr, oom("enumerator__new"); enumeration__add(enumeration, enumerator); - hashtags__hash(sp->cu->hash_tags, &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); @@ -660,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)); @@ -689,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; } @@ -759,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 { @@ -788,18 +792,101 @@ static void open_files(struct ctf_state *sp, const char *in_filename) } } -int ctf__load(struct cus *self, struct argp *argp, int argc, char *argv[], - bool parsed) +static size_t base_type__name_to_size(struct base_type *self) +{ + if (strcmp(base_type__name(self), "unsigned") == 0) + return 32; + + /* FIXME */ + return 0; +} + +static int class__fixup_ctf_bitfields(struct tag *self, struct cu *cu) +{ + struct class_member *pos; + struct type *type_self = tag__type(self); + uint16_t bit_offset = 0; + long last_offset = -1; + + type__for_each_data_member(type_self, pos) { + struct tag *type = cu__find_type_by_id(cu, pos->tag.type); + + if (type->tag != DW_TAG_base_type) + continue; + + struct base_type *bt = tag__base_type(type); + size_t bit_size = base_type__name_to_size(bt); + + if (bit_size == 0 || bt->bit_size == bit_size) { + bit_offset = 0; + last_offset = -1; + continue; + } + + if (last_offset == -1) + last_offset = pos->offset; + + 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), + class_member__name(pos)); + continue; + } + + pos->offset = last_offset; + pos->tag.type = fixed_tag_id; + pos->bit_size = bt->bit_size; + pos->bit_offset = bit_offset; + bit_offset += bt->bit_size; + if (bit_offset == bit_size) { + bit_offset = 0; + last_offset = -1; + } + } + + return 0; +} + +static int cu__fixup_ctf_bitfields(struct cu *self) +{ + int err = 0; + struct tag *pos; + + list_for_each_entry(pos, &self->tags, node) + if (tag__is_struct(pos)) { + err = class__fixup_ctf_bitfields(pos, self); + if (err) + break; + } + + return err; +} + +static int cus__fixup_ctf_bitfields(struct cus *self) +{ + int err = 0; + struct cu *pos; + + list_for_each_entry(pos, &self->cus, node) { + err = cu__fixup_ctf_bitfields(pos); + if (err) + break; + } + return err; +} + +int ctf__load(struct cus *self, char *filenames[]) { struct ctf_state state; + int wordsize; memset(&state, 0, sizeof(state)); - if (argc > 2 && !parsed && - argp_parse(argp, argc - 1, argv, 0, NULL, NULL)) - return -1; - - open_files(&state, argv[argc - 1]); + open_files(&state, filenames[0]); if (elf_version(EV_CURRENT) == EV_NONE) { fprintf(stderr, "Cannot set libelf version.\n"); @@ -812,10 +899,10 @@ int ctf__load(struct cus *self, struct argp *argp, int argc, char *argv[], return -1; } - if (parse_elf(&state)) + if (parse_elf(&state, &wordsize)) return -1; - state.cu = cu__new("FIXME.c", 8, NULL, 0); + state.cu = cu__new("FIXME.c", wordsize, NULL, 0); if (state.cu == NULL) oom("cu__new"); @@ -827,5 +914,5 @@ int ctf__load(struct cus *self, struct argp *argp, int argc, char *argv[], close(state.in_fd); - return 0; + return cus__fixup_ctf_bitfields(self); } diff --git a/ctf_loader.h b/ctf_loader.h index 79b155c..10f2ea6 100644 --- a/ctf_loader.h +++ b/ctf_loader.h @@ -8,12 +8,8 @@ published by the Free Software Foundation. */ -#include - struct cus; -struct argp; -int ctf__load(struct cus *self, struct argp *argp, int argc, char *argv[], - bool parsed); +int ctf__load(struct cus *self, char *filenames[]); #endif /* _CTF_LOADER_H_ */ diff --git a/ctracer.c b/ctracer.c index 9ff29c5..4330984 100644 --- a/ctracer.c +++ b/ctracer.c @@ -125,7 +125,7 @@ static struct structure *structures__find(struct list_head *list, const char *na return NULL; list_for_each_entry(pos, list, node) - if (strcmp(class__name(tag__class(pos->class), pos->cu), name) == 0) + if (strcmp(class__name(tag__class(pos->class)), name) == 0) return pos; return NULL; @@ -165,59 +165,51 @@ 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 + * We want just the function 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; } /* * Iterate thru all the tags in the compilation unit, looking just for the - * DW_TAG_subprogram tags that have as one of its parameters a pointer to + * function tags that have as one of its parameters a pointer to * the specified "class" (struct). */ 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, @@ -316,8 +308,7 @@ static size_t class__find_biggest_member_name(const struct class *self) } static void class__emit_class_state_collector(struct class *self, - struct class *clone, - const struct cu *cu) + struct class *clone) { struct class_member *pos; int len = class__find_biggest_member_name(clone); @@ -327,7 +318,7 @@ static void class__emit_class_state_collector(struct class *self, "{\n" "\tconst struct %s *obj = from;\n" "\tstruct %s *mini_obj = to;\n\n", - class__name(self, cu), class__name(clone, cu)); + class__name(self), class__name(clone)); type__for_each_data_member(&clone->type, pos) fprintf(fp_collector, "\tmini_obj->%-*s = obj->%s;\n", len, class_member__name(pos), class_member__name(pos)); @@ -341,7 +332,7 @@ static int tag__is_base_type(const struct tag *self, const struct cu *cu) return 1; case DW_TAG_typedef: { - const struct tag *type = cu__find_tag_by_id(cu, self->type); + const struct tag *type = cu__find_type_by_id(cu, self->type); if (type == NULL) return 0; @@ -362,10 +353,8 @@ static struct class *class__clone_base_types(const struct tag *tag_self, if (clone == NULL) return NULL; - class__find_holes(clone, cu); - type__for_each_data_member_safe(&clone->type, pos, next) { - struct tag *member_type = cu__find_tag_by_id(cu, pos->tag.type); + struct tag *member_type = cu__find_type_by_id(cu, pos->tag.type); tag__assert_search_result(member_type); if (!tag__is_base_type(member_type, cu)) { @@ -373,7 +362,6 @@ static struct class *class__clone_base_types(const struct tag *tag_self, class_member__delete(pos); } } - class__find_holes(clone, cu); class__fixup_alignment(clone, cu); class__reorganize(clone, cu, 0, NULL); return clone; @@ -398,8 +386,7 @@ static void emit_struct_member_table_entry(FILE *fp, * ostra-cg to preprocess the raw data collected from the debugfs/relay * channel. */ -static int class__emit_ostra_converter(struct tag *tag_self, - struct cu *cu) +static int class__emit_ostra_converter(struct tag *tag_self) { struct class *self = tag__class(tag_self); struct class_member *pos; @@ -411,7 +398,7 @@ static int class__emit_ostra_converter(struct tag *tag_self, size_t n; size_t plen = sizeof(parm_list); FILE *fp_fields, *fp_converter; - const char *name = class__name(self, cu); + const char *name = class__name(self); snprintf(filename, sizeof(filename), "%s/%s.fields", src_dir, name); fp_fields = fopen(filename, "w"); @@ -489,9 +476,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; @@ -502,45 +490,40 @@ static struct tag *pointer_filter(struct tag *tag, struct cu *cu, void *target_t if (type->nr_members == 0) return NULL; - class_name = class__name(tag__class(tag), cu); + class_name = class__name(tag__class(tag)); 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_tag_by_id(cu, pos->tag.type); + 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 +535,9 @@ 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, uint16_t target_type_id) { - struct type *type, *target_type; + struct type *type; struct class_member *first_member; if (!tag__is_struct(tag)) @@ -566,11 +549,10 @@ 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))) + if (structures__find(&aliases, class__name(tag__class(tag)))) return NULL; return tag; @@ -578,45 +560,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, target_type_id)) { + const char *alias_name = class__name(tag__class(pos)); + + 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) @@ -635,8 +613,7 @@ static void emit_list_of_types(struct list_head *list) * emmited this one */ if (type_emissions__find_definition(&emissions, - class__name(tag__class(pos->class), - pos->cu))) { + class__name(tag__class(pos->class)))) { type->definition_emitted = 1; continue; } @@ -656,7 +633,7 @@ static int class__emit_classes(struct tag *tag_self, struct cu *cu) char mini_class_name[128]; snprintf(mini_class_name, sizeof(mini_class_name), "ctracer__mini_%s", - class__name(self, cu)); + class__name(self)); mini_class = class__clone_base_types(tag_self, cu, mini_class_name); if (mini_class == NULL) @@ -675,7 +652,7 @@ static int class__emit_classes(struct tag *tag_self, struct cu *cu) class__fprintf(mini_class, cu, NULL, fp_classes); fputs(";\n\n", fp_classes); - class__emit_class_state_collector(self, mini_class, cu); + class__emit_class_state_collector(self, mini_class); err = 0; out: return err; @@ -688,8 +665,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; @@ -708,25 +686,22 @@ static int function__emit_probes(struct function *self, const struct cu *cu, probe_type == 0 ? "" : "__return"); list_for_each_entry(pos, &self->proto.parms, tag.node) { - struct tag *type = cu__find_tag_by_id(cu, pos->tag.type); + 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_tag_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) fprintf(fp_methods, "\tif ($%s)\n\t", - parameter__name(pos, cu)); + parameter__name(pos)); 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, - parameter__name(pos, cu), + function_id, + parameter__name(pos), member ? "->" : "", member ?: "", class__size(mini_class)); break; @@ -744,16 +719,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 +742,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,28 +751,29 @@ 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); /* for now just for the first member that is a pointer */ type__for_each_member(tag__type(pointer), pos_member) { - struct tag *ctype = cu__find_tag_by_id(cu, pos_member->tag.type); + 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 +791,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; } @@ -821,6 +800,9 @@ static int cu_emit_functions_table(struct cu *cu, void *fp) return 0; } +/* Name and version of program. */ +ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version; + static const struct argp_option ctracer__options[] = { { .key = 'd', @@ -899,9 +881,8 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } - argp_parse(&ctracer__argp, argc, argv, 0, &remaining, NULL); - - if (remaining < argc) { + if (argp_parse(&ctracer__argp, argc, argv, 0, &remaining, NULL) || + remaining < argc) { switch (argc - remaining) { case 1: goto failure; case 2: filename = argv[remaining++]; @@ -910,7 +891,7 @@ int main(int argc, char *argv[]) } } else { failure: - argp_help(&ctracer__argp, stderr, ARGP_HELP_SEE, "ctracer"); + argp_help(&ctracer__argp, stderr, ARGP_HELP_SEE, argv[0]); return EXIT_FAILURE; } @@ -956,15 +937,14 @@ 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; } snprintf(functions_filename, sizeof(functions_filename), - "%s/%s.functions", src_dir, - class__name(tag__class(class), cu)); + "%s/%s.functions", src_dir, class__name(tag__class(class))); fp_functions = fopen(functions_filename, "w"); if (fp_functions == NULL) { fprintf(stderr, "ctracer: couldn't create %s\n", @@ -1017,7 +997,7 @@ failure: class__emit_classes(class, cu); fputc('\n', fp_collector); - class__emit_ostra_converter(class, cu); + class__emit_ostra_converter(class); cu_blacklist = strlist__new(true); if (cu_blacklist != NULL) @@ -1031,7 +1011,7 @@ failure: fp_functions, cu_filter); list_for_each_entry(pos, &aliases, node) { - const char *alias_name = class__name(tag__class(pos->class), pos->cu); + const char *alias_name = class__name(tag__class(pos->class)); cus__for_each_cu(methods_cus, cu_find_methods_iterator, (void *)alias_name, cu_filter); @@ -1042,7 +1022,7 @@ failure: } list_for_each_entry(pos, &pointers, node) { - const char *pointer_name = class__name(tag__class(pos->class), pos->cu); + const char *pointer_name = class__name(tag__class(pos->class)); cus__for_each_cu(methods_cus, cu_find_methods_iterator, (void *)pointer_name, cu_filter); cus__for_each_cu(methods_cus, cu_emit_pointer_probes_iterator, diff --git a/dtagnames.c b/dtagnames.c index fcffb14..76d2a3e 100644 --- a/dtagnames.c +++ b/dtagnames.c @@ -39,7 +39,7 @@ static void cus__dump_class_tag_names(struct cus *self) cus__for_each_cu(self, cu__dump_class_tag_names, NULL, NULL); } -int main(int argc, char *argv[]) +int main(int argc __unused, char *argv[]) { int err; struct cus *cus = cus__new(); @@ -49,7 +49,7 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } - err = cus__loadfl(cus, NULL, argc, argv); + err = cus__loadfl(cus, argv + 1); if (err != 0) return EXIT_FAILURE; diff --git a/dutil.h b/dutil.h index d01a1ef..cc8c4a5 100644 --- a/dutil.h +++ b/dutil.h @@ -14,6 +14,23 @@ #define __unused __attribute__ ((unused)) #endif +#ifndef __pure +#define __pure __attribute__ ((pure)) +#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 + do better, it is not going to change. So we want to move them into + the .rodata section. Define macros to do the trick. */ +#define ARGP_PROGRAM_VERSION_HOOK_DEF \ + void (*const apvh) (FILE *, struct argp_state *) \ + __asm ("argp_program_version_hook") +#define ARGP_PROGRAM_BUG_ADDRESS_DEF \ + const char *const apba__ __asm ("argp_program_bug_address") + struct strlist { void *entries; bool dupstr; diff --git a/dwarf_loader.c b/dwarf_loader.c index 1cfa2c4..72d7382 100644 --- a/dwarf_loader.c +++ b/dwarf_loader.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -26,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); @@ -176,29 +245,55 @@ 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); - self->decl_file = strings__add(strings, dwarf_decl_file(die)); + if (decl_file != last_decl_file) { + last_decl_file_idx = strings__add(strings, decl_file); + last_decl_file = decl_file; + } + + 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_LIST_HEAD(&self->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); @@ -208,7 +303,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); @@ -220,7 +315,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); @@ -233,10 +328,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; } @@ -251,7 +349,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); @@ -274,7 +372,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); @@ -284,7 +382,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); @@ -319,7 +417,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); @@ -339,16 +437,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; @@ -356,7 +458,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); @@ -370,14 +472,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; @@ -408,11 +512,12 @@ 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); self->name = strings__add(strings, attr_string(die, DW_AT_name)); + self->abstract_origin = attr_type(die, DW_AT_abstract_origin); if (dwarf_lowpc(die, &self->low_pc)) self->low_pc = 0; } @@ -422,11 +527,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; @@ -441,6 +552,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 = @@ -449,7 +561,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); @@ -472,7 +584,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); @@ -482,7 +594,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); @@ -500,6 +612,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; @@ -536,9 +651,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) { @@ -582,7 +698,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) { @@ -652,8 +769,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; } @@ -680,8 +799,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); @@ -703,9 +823,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); @@ -713,6 +835,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) @@ -738,31 +861,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); @@ -771,9 +906,9 @@ static struct tag *die__create_new_enumeration(Dwarf_Die *die, struct cu *cu) oom("class__new"); if (!dwarf_haschildren(die) || dwarf_child(die, &child) != 0) { - fprintf(stderr, "%s: DW_TAG_enumeration_type with no " - "children!\n", __FUNCTION__); - return NULL; + /* Seen on libQtCore.so.4.3.4.debug, + * class QAbstractFileEngineIterator, enum EntryInfoType */ + goto out; } die = &child; @@ -789,9 +924,8 @@ static struct tag *die__create_new_enumeration(Dwarf_Die *die, struct cu *cu) oom("enumerator__new"); enumeration__add(enumeration, enumerator); - hashtags__hash(cu->hash_tags, &enumerator->tag); } while (dwarf_siblingof(die, die) == 0); - +out: return &enumeration->namespace.tag; } @@ -808,16 +942,24 @@ static void die__process_class(Dwarf_Die *die, struct type *class, oom("class_member__new"); type__add_member(class, member); - hashtags__hash(cu->hash_tags, &member->tag); + cu__hash(cu, &member->tag); } 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); - hashtags__hash(cu->hash_tags, tag); - if (tag->tag == DW_TAG_subprogram) { + cu__hash(cu, tag); + if (tag__is_function(tag)) { struct function *fself = tag__function(tag); if (fself->vtable_entry != -1) @@ -831,14 +973,22 @@ 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); - hashtags__hash(cu->hash_tags, tag); + cu__hash(cu, tag); } } while (dwarf_siblingof(die, die) == 0); } @@ -857,8 +1007,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); @@ -866,6 +1016,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, @@ -878,34 +1029,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); } @@ -920,55 +1084,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; @@ -982,6 +1538,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); @@ -989,11 +1551,11 @@ 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 int cus__load_module(Dwfl_Module *mod, void **userdata __unused, - const char *name __unused, Dwarf_Addr base __unused, - Dwarf *dw, Dwarf_Addr bias __unused, void *self) +static void cus__load_module(struct cus *self, Dwfl_Module *mod, Dwarf *dw) { Dwarf_Off off = 0, noff; size_t cuhl; @@ -1021,10 +1583,75 @@ static int cus__load_module(Dwfl_Module *mod, void **userdata __unused, cus__add(self, cu); off = noff; } +} + +static int cus__process_dwflmod(Dwfl_Module *dwflmod, + void **userdata __unused, + const char *name __unused, + Dwarf_Addr base __unused, + void *arg) +{ + struct cus *self = arg; + /* + * WARNING: Don't remove the seemingly useless call to + * dwfl_module_getelf, as it will change dwflmod internal state in a + * way that is required by dwfl_module_getdwarf. + */ + GElf_Addr dwflbias; + dwfl_module_getelf(dwflmod, &dwflbias); + + Dwarf_Addr dwbias; + Dwarf *dw = dwfl_module_getdwarf(dwflmod, &dwbias); + + if (dw != NULL) + cus__load_module(self, dwflmod, dw); + /* + * XXX We will fall back to try finding other debugging + * formats (CTF), so no point in telling this to the user + * Use for debugging. + * else + * fprintf(stderr, + * "%s: can't get debug context descriptor: %s\n", + * __func__, dwfl_errmsg(-1)); + */ return DWARF_CB_OK; } +static int cus__process_file(struct cus *self, int fd, const char *filename) +{ + /* Duplicate an fd for dwfl_report_offline to swallow. */ + int dwfl_fd = dup(fd); + + if (dwfl_fd < 0) + return -1; + + /* + * Use libdwfl in a trivial way to open the libdw handle for us. + * This takes care of applying relocations to DWARF data in ET_REL + * files. + */ + + static const Dwfl_Callbacks callbacks = { + .section_address = dwfl_offline_section_address, + .find_debuginfo = dwfl_standard_find_debuginfo, + /* We use this table for core files too. */ + .find_elf = dwfl_build_id_find_elf, + }; + + Dwfl *dwfl = dwfl_begin(&callbacks); + + if (dwfl_report_offline(dwfl, filename, filename, dwfl_fd) == NULL) + return -1; + + dwfl_report_end(dwfl, NULL, NULL); + + /* Process the one or more modules gleaned from this file. */ + dwfl_getmodules(dwfl, cus__process_dwflmod, self, 0); + dwfl_end(dwfl); + return 0; +} + int dwarf__load_filename(struct cus *self, const char *filename) { Dwarf_Off offset, last_offset, abbrev_offset; @@ -1069,69 +1696,25 @@ out: return err; } -static int with_executable_option(int argc, char *argv[]) +int dwarf__load(struct cus *self, char *filenames[], bool parsed __unused) { - while (--argc != 0) - if (strcmp(argv[argc], "--help") == 0 || - strcmp(argv[argc], "-?") == 0 || - strcmp(argv[argc], "-h") == 0 || - strcmp(argv[argc], "--usage") == 0 || - strcmp(argv[argc], "--executable") == 0 || - (argv[argc][0] == '-' && argv[argc][1] != '-' && - strchr(argv[argc] + 1, 'e') != NULL)) - return 1; - return 0; -} + int err = 0, i = 0; -int dwarf__load(struct cus *self, struct argp *argp, int argc, char *argv[], - bool parsed __unused) -{ - Dwfl *dwfl = NULL; - char **new_argv = NULL; - ptrdiff_t offset; - int err = -1; + elf_version(EV_CURRENT); - if (argc == 1) { - argp_help(argp ? : dwfl_standard_argp(), stderr, - ARGP_HELP_SEE, argv[0]); - return -1; - } + while (filenames[i] != NULL) { + int fd = open(filenames[i], O_RDONLY); - if (!with_executable_option(argc, argv)) { - new_argv = malloc((argc + 2) * sizeof(char *)); - if (new_argv == NULL) { - fprintf(stderr, "%s: not enough memory!\n", __func__); - return -1; + if (fd == -1) { + fprintf(stderr, "%s: couldn't open %s\n", __func__, + filenames[i]); + ++i; + continue; } - memcpy(new_argv, argv, (argc - 1) * sizeof(char *)); - new_argv[argc - 1] = "-e"; - new_argv[argc] = argv[argc - 1]; - new_argv[argc + 1] = NULL; - argv = new_argv; - argc++; + cus__process_file(self, fd, filenames[i]); + close(fd); + ++i; } - if (argp != NULL) { - const struct argp_child argp_children[] = { - { .argp = dwfl_standard_argp(), }, - { .argp = NULL } - }; - argp->children = argp_children; - argp_parse(argp, argc, argv, 0, NULL, &dwfl); - } else - argp_parse(dwfl_standard_argp(), argc, argv, 0, NULL, &dwfl); - - if (dwfl == NULL) - goto out; - - offset = 0; - do { - offset = dwfl_getdwarf(dwfl, cus__load_module, self, offset); - } while (offset > 0); - - dwfl_end(dwfl); - err = 0; -out: - free(new_argv); return err; } diff --git a/dwarf_loader.h b/dwarf_loader.h index cd2f77a..7e10e1a 100644 --- a/dwarf_loader.h +++ b/dwarf_loader.h @@ -9,10 +9,8 @@ */ struct cus; -struct argp; int dwarf__load_filename(struct cus *self, const char *filename); -int dwarf__load(struct cus *self, struct argp *argp, int argc, char *argv[], - bool parsed); +int dwarf__load(struct cus *self, char *filenames[]); #endif /* _DWARF_LOADER_H_ */ diff --git a/dwarves.c b/dwarves.c index fcd9426..5fd5fe4 100644 --- a/dwarves.c +++ b/dwarves.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -131,7 +130,7 @@ void tag__not_found_die(const char *file, int line, const char *func) struct tag *tag__follow_typedef(struct tag *tag, const struct cu *cu) { - struct tag *type = cu__find_tag_by_id(cu, tag->type); + struct tag *type = cu__find_type_by_id(cu, tag->type); if (type != NULL && tag__is_typedef(type)) return tag__follow_typedef(type, cu); @@ -189,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, @@ -206,7 +206,7 @@ static size_t array_type__fprintf(const struct tag *tag_self, FILE *fp) { struct array_type *self = tag__array_type(tag_self); - struct tag *type = cu__find_tag_by_id(cu, tag_self->type); + struct tag *type = cu__find_type_by_id(cu, tag_self->type); size_t printed; int i; @@ -227,10 +227,7 @@ void namespace__delete(struct namespace *self) list_del_init(&pos->node); /* Look for nested namespaces */ - if (tag__is_struct(pos) || - tag__is_union(pos) || - tag__is_namespace(pos) || - tag__is_enumeration(pos)) + if (tag__has_namespace(pos)) namespace__delete(tag__namespace(pos)); tag__delete(pos); } @@ -238,25 +235,6 @@ void namespace__delete(struct namespace *self) tag__delete(&self->tag); } -const char *type__name(struct type *self, const struct cu *cu) -{ - /* 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_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->namespace.name = tag__type(tag)->namespace.name; - } - - return s(self->namespace.name); -} - struct class_member * type__find_first_biggest_size_base_type_member(struct type *self, const struct cu *cu) @@ -265,7 +243,7 @@ struct class_member * size_t result_size = 0; type__for_each_data_member(self, pos) { - struct tag *type = cu__find_tag_by_id(cu, pos->tag.type); + struct tag *type = cu__find_type_by_id(cu, pos->tag.type); size_t member_size = 0, power2; struct class_member *inner = NULL; @@ -294,11 +272,10 @@ reevaluate: case DW_TAG_const_type: case DW_TAG_typedef: case DW_TAG_volatile_type: { - const struct tag *tag = type; - - type = cu__find_tag_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; } } @@ -340,29 +317,29 @@ size_t typedef__fprintf(const struct tag *tag_self, const struct cu *cu, * to avoid all these checks? */ if (tag_self->type == 0) - return fprintf(fp, "typedef void %s", type__name(self, cu)); + return fprintf(fp, "typedef void %s", type__name(self)); - type = cu__find_tag_by_id(cu, tag_self->type); + type = cu__find_type_by_id(cu, tag_self->type); if (type == NULL) { printed = fprintf(fp, "typedef "); printed += tag__id_not_found_fprintf(fp, tag_self->type); - return printed + fprintf(fp, " %s", type__name(self, cu)); + return printed + fprintf(fp, " %s", type__name(self)); } switch (type->tag) { case DW_TAG_array_type: printed = fprintf(fp, "typedef "); return printed + array_type__fprintf(type, cu, - type__name(self, cu), + type__name(self), pconf, fp); case DW_TAG_pointer_type: if (type->type == 0) /* void pointer */ break; - ptr_type = cu__find_tag_by_id(cu, type->type); + ptr_type = cu__find_type_by_id(cu, type->type); if (ptr_type == NULL) { printed = fprintf(fp, "typedef "); printed += tag__id_not_found_fprintf(fp, type->type); - return printed + fprintf(fp, " *%s", type__name(self, cu)); + return printed + fprintf(fp, " *%s", type__name(self)); } if (ptr_type->tag != DW_TAG_subroutine_type) break; @@ -372,23 +349,23 @@ size_t typedef__fprintf(const struct tag *tag_self, const struct cu *cu, case DW_TAG_subroutine_type: printed = fprintf(fp, "typedef "); return printed + ftype__fprintf(tag__ftype(type), cu, - type__name(self, cu), + type__name(self), 0, is_pointer, 0, fp); case DW_TAG_class_type: case DW_TAG_structure_type: { struct type *ctype = tag__type(type); - if (type__name(ctype, cu) != NULL) + if (type__name(ctype) != NULL) return fprintf(fp, "typedef struct %s %s", - type__name(ctype, cu), - type__name(self, cu)); + type__name(ctype), + type__name(self)); } } return fprintf(fp, "typedef %s %s", tag__name(type, cu, bf, sizeof(bf)), - type__name(self, cu)); + type__name(self)); } static size_t imported_declaration__fprintf(const struct tag *self, @@ -416,14 +393,14 @@ static size_t imported_module__fprintf(const struct tag *self, return fprintf(fp, "using namespace %s", name); } -size_t enumeration__fprintf(const struct tag *tag_self, const struct cu *cu, +size_t enumeration__fprintf(const struct tag *tag_self, const struct conf_fprintf *conf, FILE *fp) { struct type *self = tag__type(tag_self); struct enumerator *pos; size_t printed = fprintf(fp, "enum%s%s {\n", - type__name(self, cu) ? " " : "", - type__name(self, cu) ?: ""); + type__name(self) ? " " : "", + type__name(self) ?: ""); int indent = conf->indent; if (indent >= (int)sizeof(tabs)) @@ -437,9 +414,106 @@ size_t enumeration__fprintf(const struct tag *tag_self, const struct cu *cu, conf->suffix ? " " : "", conf->suffix ?: ""); } +static void cu__find_class_holes(struct cu *self) +{ + uint16_t id; + struct class *pos; + + cu__for_each_struct(self, id, pos) + class__find_holes(pos, self); +} + void cus__add(struct cus *self, struct cu *cu) { list_add_tail(&cu->node, &self->cus); + cu__find_class_holes(cu); +} + +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, @@ -449,15 +523,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_LIST_HEAD(&self->hash_tags[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; @@ -471,8 +553,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) @@ -483,29 +571,15 @@ void cu__delete(struct cu *self) list_del_init(&pos->node); /* Look for nested namespaces */ - if (tag__is_struct(pos) || - tag__is_union(pos) || - tag__is_namespace(pos) || - tag__is_enumeration(pos)) { + if (tag__has_namespace(pos)) namespace__delete(tag__namespace(pos)); - } } + + ptr_table__exit(&self->tags_table); + ptr_table__exit(&self->types_table); free(self); } -void hashtags__hash(struct list_head *hashtable, struct tag *tag) -{ - struct list_head *head = hashtable + hashtags__fn(tag->id); - - list_add_tail(&tag->hash_node, head); -} - -void cu__add_tag(struct cu *self, struct tag *tag) -{ - list_add_tail(&tag->node, &self->tags); - hashtags__hash(self->hash_tags, tag); -} - bool cu__same_build_id(const struct cu *self, const struct cu *other) { return self->build_id_len != 0 && @@ -529,76 +603,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) { - struct tag *pos; - const struct list_head *head; + return self ? ptr_table__entry(&self->tags_table, id) : NULL; +} - if (self == NULL || id == 0) - return NULL; - - head = &self->hash_tags[hashtags__fn(id)]; - - list_for_each_entry(pos, head, hash_node) - if (pos->id == id) - return pos; - - return NULL; +struct tag *cu__find_type_by_id(const struct cu *self, const uint16_t id) +{ + 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, + uint16_t *idp) +{ + uint16_t id; + struct tag *pos; + + if (self == NULL || name == NULL) + return NULL; + + 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 == 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; } @@ -609,13 +725,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; @@ -650,7 +767,10 @@ struct tag *cus__find_tag_by_id(const struct cus *self, struct cu *pos; list_for_each_entry(pos, &self->cus, node) { - struct tag *tag = cu__find_tag_by_id(pos, id); + struct tag *tag = cu__find_type_by_id(pos, id); + + if (tag == NULL) + tag = cu__find_tag_by_id(pos, id); if (tag != NULL) { if (cu != NULL) @@ -676,114 +796,22 @@ struct cu *cus__find_cu_by_name(const struct cus *self, const char *name) struct tag *cu__find_function_by_name(const struct cu *self, const char *name) { struct tag *pos; - struct function *fpos; if (self == NULL || name == NULL) return NULL; - list_for_each_entry(pos, &self->tags, node) { - if (pos->tag != DW_TAG_subprogram) - continue; - fpos = tag__function(pos); - if (fpos->name && strcmp(s(fpos->name), name) == 0) - return pos; - } - - 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) + strings_t sname = strings__find(strings, name); + if (sname == 0) 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) + list_for_each_entry(pos, &self->tags, node) + if (tag__is_function(pos) && + tag__function(pos)->name == sname) 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; @@ -815,7 +843,7 @@ size_t tag__size(const struct tag *self, const struct cu *cu) else size = tag__type(self)->size; } else { - const struct tag *type = cu__find_tag_by_id(cu, self->type); + const struct tag *type = cu__find_type_by_id(cu, self->type); if (type == NULL) { tag__id_not_found_fprintf(stderr, self->type); @@ -836,7 +864,7 @@ static const char *tag__ptr_name(const struct tag *self, const struct cu *cu, if (self->type == 0) /* No type == void */ snprintf(bf, len, "void %s", ptr_suffix); else { - const struct tag *type = cu__find_tag_by_id(cu, self->type); + const struct tag *type = cu__find_type_by_id(cu, self->type); if (type == NULL) { size_t l = tag__id_not_found_snprintf(bf, len, @@ -882,10 +910,10 @@ const char *tag__name(const struct tag *self, const struct cu *cu, char suffix[512]; Dwarf_Off id = tag__ptr_to_member_type(self)->containing_type; - type = cu__find_tag_by_id(cu, id); + type = cu__find_type_by_id(cu, id); if (type != NULL) snprintf(suffix, sizeof(suffix), "%s::*", - class__name(tag__class(type), cu)); + class__name(tag__class(type))); else { size_t l = tag__id_not_found_snprintf(suffix, sizeof(suffix), @@ -897,7 +925,7 @@ const char *tag__name(const struct tag *self, const struct cu *cu, } case DW_TAG_volatile_type: case DW_TAG_const_type: - type = cu__find_tag_by_id(cu, self->type); + type = cu__find_type_by_id(cu, self->type); if (type == NULL && self->type != 0) tag__id_not_found_snprintf(bf, len, self->type); else { @@ -909,7 +937,7 @@ const char *tag__name(const struct tag *self, const struct cu *cu, } break; case DW_TAG_array_type: - type = cu__find_tag_by_id(cu, self->type); + type = cu__find_type_by_id(cu, self->type); if (type == NULL) tag__id_not_found_snprintf(bf, len, self->type); else @@ -927,7 +955,7 @@ const char *tag__name(const struct tag *self, const struct cu *cu, break; default: snprintf(bf, len, "%s%s", tag__prefix(cu, self->tag), - type__name(tag__type(self), cu) ?: ""); + type__name(tag__type(self)) ?: ""); break; } @@ -937,14 +965,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_tag_by_id(cu, self->tag.type); + 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; @@ -964,10 +992,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; } @@ -1010,7 +1038,7 @@ static struct class_member *class_member__clone(const struct class_member *from) size_t class_member__size(const struct class_member *self, const struct cu *cu) { - struct tag *type = cu__find_tag_by_id(cu, self->tag.type); + struct tag *type = cu__find_type_by_id(cu, self->tag.type); if (type == NULL) { tag__id_not_found_fprintf(stderr, self->tag.type); return -1; @@ -1018,43 +1046,6 @@ 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) -{ - /* 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) -{ - /* 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; -} - static size_t union__fprintf(struct type *self, const struct cu *cu, const struct conf_fprintf *conf, FILE *fp); @@ -1077,7 +1068,7 @@ static size_t type__fprintf(struct tag *type, const struct cu *cu, int nr_indirections = 0; while (type->tag == DW_TAG_pointer_type && type->type != 0) { - type = cu__find_tag_by_id(cu, type->type); + type = cu__find_type_by_id(cu, type->type); if (type == NULL) goto out_type_not_found; ++nr_indirections; @@ -1110,13 +1101,13 @@ static size_t type__fprintf(struct tag *type, const struct cu *cu, ctype = tag__type(type); if (typedef_expanded) printed += fprintf(fp, " -> %s", - type__name(ctype, cu)); + type__name(ctype)); else { printed += fprintf(fp, "/* typedef %s", - type__name(ctype, cu)); + type__name(ctype)); typedef_expanded = 1; } - type = cu__find_tag_by_id(cu, type->type); + type = cu__find_type_by_id(cu, type->type); if (type == NULL) goto out_type_not_found; } @@ -1137,7 +1128,7 @@ static size_t type__fprintf(struct tag *type, const struct cu *cu, switch (type->tag) { case DW_TAG_pointer_type: if (type->type != 0) { - struct tag *ptype = cu__find_tag_by_id(cu, type->type); + struct tag *ptype = cu__find_type_by_id(cu, type->type); if (ptype == NULL) goto out_type_not_found; if (ptype->tag == DW_TAG_subroutine_type) { @@ -1164,37 +1155,34 @@ static size_t type__fprintf(struct tag *type, const struct cu *cu, case DW_TAG_structure_type: ctype = tag__type(type); - if (type__name(ctype, cu) != NULL && !expand_types) + if (type__name(ctype) != NULL && !expand_types) printed += fprintf(fp, "%s %-*s %s", type->tag == DW_TAG_class_type ? "class" : "struct", conf->type_spacing - 7, - type__name(ctype, cu), name); - else { - struct class *class = tag__class(type); - - class__find_holes(class, cu); - printed += class__fprintf(class, cu, &tconf, fp); - } + type__name(ctype), name); + else + printed += class__fprintf(tag__class(type), + cu, &tconf, fp); break; case DW_TAG_union_type: ctype = tag__type(type); - if (type__name(ctype, cu) != NULL && !expand_types) + if (type__name(ctype) != NULL && !expand_types) printed += fprintf(fp, "union %-*s %s", conf->type_spacing - 6, - type__name(ctype, cu), name); + type__name(ctype), name); else printed += union__fprintf(ctype, cu, &tconf, fp); break; case DW_TAG_enumeration_type: ctype = tag__type(type); - if (type__name(ctype, cu) != NULL) + if (type__name(ctype) != NULL) printed += fprintf(fp, "enum %-*s %s", conf->type_spacing - 5, - type__name(ctype, cu), name); + type__name(ctype), name); else - printed += enumeration__fprintf(type, cu, &tconf, fp); + printed += enumeration__fprintf(type, &tconf, fp); break; } out: @@ -1239,7 +1227,7 @@ static size_t struct_member__fprintf(struct class_member *self, if ((tag__is_union(type) || tag__is_struct(type) || tag__is_enumeration(type)) && /* Look if is a type defined inline */ - type__name(tag__type(type), cu) == NULL) { + type__name(tag__type(type)) == NULL) { if (!sconf.suppress_offset_comment) { /* Check if this is a anonymous union */ const int slen = self->name ? @@ -1285,7 +1273,7 @@ static size_t union_member__fprintf(struct class_member *self, if ((tag__is_union(type) || tag__is_struct(type) || tag__is_enumeration(type)) && /* Look if is a type defined inline */ - type__name(tag__type(type), cu) == NULL) { + type__name(tag__type(type)) == NULL) { if (!conf->suppress_offset_comment) { /* Check if this is a anonymous union */ const int slen = self->name ? (int)strlen(s(self->name)) : -1; @@ -1324,13 +1312,13 @@ static size_t union__fprintf(struct type *self, const struct cu *cu, if (conf->prefix != NULL) printed += fprintf(fp, "%s ", conf->prefix); - printed += fprintf(fp, "union%s%s {\n", type__name(self, cu) ? " " : "", - type__name(self, cu) ?: ""); + printed += fprintf(fp, "union%s%s {\n", type__name(self) ? " " : "", + type__name(self) ?: ""); uconf = *conf; uconf.indent = indent + 1; type__for_each_member(self, pos) { - struct tag *type = cu__find_tag_by_id(cu, pos->tag.type); + struct tag *type = cu__find_type_by_id(cu, pos->tag.type); if (type == NULL) { printed += fprintf(fp, "%.*s", uconf.indent, tabs); @@ -1435,25 +1423,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); } @@ -1471,18 +1442,16 @@ 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; ftype__for_each_parameter(self, pos) { - struct tag *type = - cu__find_tag_by_id(cu, parameter__type(pos, cu)); + struct tag *type = cu__find_type_by_id(cu, pos->tag.type); if (type != NULL && type->tag == DW_TAG_pointer_type) { - type = cu__find_tag_by_id(cu, type->type); - if (type != NULL && type->id == target->id) + if (type->type == target) return 1; } } @@ -1650,12 +1619,17 @@ int class__has_hole_ge(const struct class *self, const uint16_t size) struct class_member *type__find_member_by_name(const struct type *self, const char *name) { - if (name != NULL) { - struct class_member *pos; - type__for_each_data_member(self, pos) - if (pos->name && strcmp(s(pos->name), name) == 0) - return pos; - } + if (name == NULL) + return NULL; + + strings_t sname = strings__find(strings, name); + if (sname == 0) + return NULL; + + struct class_member *pos; + type__for_each_data_member(self, pos) + if (pos->name == sname) + return pos; return NULL; } @@ -1706,7 +1680,7 @@ void cu__account_inline_expansions(struct cu *self) struct function *fpos; list_for_each_entry(pos, &self->tags, node) { - if (pos->tag != DW_TAG_subprogram) + if (!tag__is_function(pos)) continue; fpos = tag__function(pos); lexblock__account_inline_expansions(&fpos->lexblock, self); @@ -1735,16 +1709,18 @@ static size_t ftype__fprintf_parms(const struct ftype *self, indent, tabs); } else first_parm = 0; - name = parameter__name(pos, cu); - type = cu__find_tag_by_id(cu, parameter__type(pos, cu)); + name = parameter__name(pos); + type = cu__find_type_by_id(cu, pos->tag.type); if (type == NULL) { - stype = ""; + snprintf(sbf, sizeof(sbf), + "", pos->tag.type); + stype = sbf; goto print_it; } if (type->tag == DW_TAG_pointer_type) { if (type->type != 0) { struct tag *ptype = - cu__find_tag_by_id(cu, type->type); + cu__find_type_by_id(cu, type->type); if (ptype == NULL) { printed += tag__id_not_found_fprintf(fp, type->type); @@ -1845,14 +1821,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, @@ -1891,7 +1866,7 @@ size_t ftype__fprintf(const struct ftype *self, const struct cu *cu, const char *name, const int inlined, const int is_pointer, int type_spacing, FILE *fp) { - struct tag *type = cu__find_tag_by_id(cu, self->tag.type); + struct tag *type = cu__find_type_by_id(cu, self->tag.type); char sbf[128]; const char *stype = tag__name(type, cu, sbf, sizeof(sbf)); size_t printed = fprintf(fp, "%s%-*s %s%s%s%s", @@ -2026,8 +2001,8 @@ size_t class__fprintf(struct class *self, const struct cu *cu, size_t printed = fprintf(fp, "%s%s%s%s%s", cconf.prefix ?: "", cconf.prefix ? " " : "", tself->namespace.tag.tag == DW_TAG_class_type ? "class" : "struct", - type__name(tself, cu) ? " " : "", - type__name(tself, cu) ?: ""); + type__name(tself) ? " " : "", + type__name(tself) ?: ""); int indent = cconf.indent; if (indent >= (int)sizeof(tabs)) @@ -2059,9 +2034,9 @@ size_t class__fprintf(struct class *self, const struct cu *cu, if (accessibility != NULL) printed += fprintf(fp, " %s", accessibility); - type = cu__find_tag_by_id(cu, tag_pos->type); + type = cu__find_type_by_id(cu, tag_pos->type); if (type != NULL) - printed += fprintf(fp, " %s", type__name(tag__type(type), cu)); + printed += fprintf(fp, " %s", type__name(tag__type(type))); else printed += tag__id_not_found_fprintf(fp, tag_pos->type); } @@ -2153,7 +2128,7 @@ size_t class__fprintf(struct class *self, const struct cu *cu, ++printed; } - type = cu__find_tag_by_id(cu, pos->tag.type); + type = cu__find_type_by_id(cu, pos->tag.type); if (type == NULL) { printed += fprintf(fp, "%.*s", cconf.indent, tabs); printed += tag__id_not_found_fprintf(fp, pos->tag.type); @@ -2411,13 +2386,16 @@ 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); switch (self->tag) { + case DW_TAG_array_type: + printed += array_type__fprintf(self, cu, "array", pconf, fp); + break; case DW_TAG_enumeration_type: - printed += enumeration__fprintf(self, cu, pconf, fp); + printed += enumeration__fprintf(self, pconf, fp); break; case DW_TAG_typedef: printed += typedef__fprintf(self, cu, pconf, fp); @@ -2455,8 +2433,7 @@ size_t tag__fprintf(struct tag *self, const struct cu *cu, ++printed; } - if (self->tag == DW_TAG_subprogram && - !pconf->suppress_comments) { + if (tag__is_function(self) && !pconf->suppress_comments) { const struct function *fself = tag__function(self); if (fself->linkage_name) @@ -2471,16 +2448,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) @@ -2568,9 +2546,9 @@ int cus__load(struct cus *self, const char *filename) return err; } -int cus__loadfl(struct cus *self, struct argp *argp, int argc, char *argv[]) +int cus__loadfl(struct cus *self, char *filenames[]) { - int err = dwarf__load(self, argp, argc, argv, false); + int err = dwarf__load(self, filenames); /* * If dwarf__load fails, try ctf__load. Eventually we should just * register all the shared objects at some directory and ask them @@ -2579,12 +2557,9 @@ int cus__loadfl(struct cus *self, struct argp *argp, int argc, char *argv[]) * support. * FIXME: for now we just check if no DWARF info was found * by looking at the list of CUs found: - * - * XXX We have to avoid calling argp_parse twice, so tell the - * loaders if we already processed it. */ if (list_empty(&self->cus)) - err = ctf__load(self, argp, argc, argv, true); + err = ctf__load(self, filenames); return err; } @@ -2628,3 +2603,10 @@ int dwarves__init(size_t user_cacheline_size) return 0; } + +struct argp_state; + +void dwarves_print_version(FILE *fp, struct argp_state *state __unused) +{ + fprintf(fp, "%s\n", DWARVES_VERSION); +} diff --git a/dwarves.h b/dwarves.h index 6b3c419..b52496c 100644 --- a/dwarves.h +++ b/dwarves.h @@ -15,34 +15,94 @@ #include #include +#include "dutil.h" #include "list.h" -#include "hash.h" #include "strings.h" extern struct strings *strings; -struct argp; - struct cus { struct list_head cus; }; struct cus *cus__new(void); -#define HASHTAGS__BITS 8 -#define HASHTAGS__SIZE (1UL << HASHTAGS__BITS) -#define hashtags__fn(key) hash_64(key, 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_struct - iterate thru all the struct tags + * @cu: struct cu instance to iterate + * @pos: struct class iterator + * @id: uint16_t tag id + */ +#define cu__for_each_struct(cu, id, pos) \ + for (id = 0, pos = tag__class(cu->types_table.entries[id]); \ + id < cu->types_table.nr_entries; \ + pos = tag__class(cu->types_table.entries[++id])) \ + if (pos == NULL || \ + !tag__is_struct(class__tag(pos))) \ + 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 == NULL || \ + pos->proto.tag.tag != DW_TAG_subprogram) \ + continue; \ + else struct tag; +struct cu; -void hashtags__hash(struct list_head *hashtable, struct tag *tag); +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 list_head hash_tags[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; @@ -56,16 +116,18 @@ struct cu { unsigned char build_id[0]; }; +/** 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 list_head hash_node; - Dwarf_Off type; - Dwarf_Off id; - strings_t decl_file; - uint16_t decl_line; + uint16_t type; uint16_t tag; - uint16_t refcnt; + uint16_t visited:1; + uint16_t top_level:1; uint16_t recursivity_level; + void *priv; }; static inline int tag__is_enumeration(const struct tag *self) @@ -94,6 +156,18 @@ static inline int tag__is_union(const struct tag *self) return self->tag == DW_TAG_union_type; } +static inline bool tag__has_namespace(const struct tag *self) +{ + return tag__is_struct(self) || + tag__is_union(self) || + tag__is_namespace(self) || + tag__is_enumeration(self); +} + +/** + * tag__is_tag_type - is this tag derived from the 'type' class? + * @tag - tag queried + */ static inline int tag__is_type(const struct tag *self) { return tag__is_union(self) || @@ -101,10 +175,47 @@ static inline int tag__is_type(const struct tag *self) tag__is_typedef(self) || tag__is_enumeration(self); } - -static inline const char *tag__decl_file(const struct tag *self) + +/** + * tag__is_tag_type - is this one of the possible types for a tag? + * @tag - tag queried + */ +static inline int tag__is_tag_type(const struct tag *self) { - return strings__ptr(strings, self->decl_file); + return tag__is_type(self) || + tag__is_enumeration(self) || + self->tag == DW_TAG_array_type || + self->tag == DW_TAG_base_type || + self->tag == DW_TAG_const_type || + self->tag == DW_TAG_pointer_type || + self->tag == DW_TAG_ptr_to_member_type || + self->tag == DW_TAG_reference_type || + self->tag == DW_TAG_subroutine_type || + self->tag == DW_TAG_volatile_type; +} + +static inline const char *tag__decl_file(const struct tag *self, + const struct cu *cu) +{ + 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 { @@ -271,12 +382,14 @@ static inline struct list_head *class__tags(struct class *self) return &self->type.namespace.tags; } -extern const char *type__name(struct type *self, const struct cu *cu); - -static inline const char *class__name(struct class *self, - const struct cu *cu) +static __pure inline const char *type__name(const struct type *self) { - return type__name(&self->type, cu); + return strings__ptr(strings, self->namespace.name); +} + +static __pure inline const char *class__name(struct class *self) +{ + return strings__ptr(strings, self->type.namespace.name); } static inline int class__is_struct(const struct class *self) @@ -417,6 +530,11 @@ static inline struct tag *function__tag(const struct function *self) return (struct tag *)self; } +static __pure inline int tag__is_function(const struct tag *self) +{ + return self->tag == DW_TAG_subprogram; +} + /** * function__for_each_parameter - iterate thru all the parameters * @self: struct function instance to iterate @@ -436,8 +554,10 @@ static inline struct parameter *tag__parameter(const struct tag *self) return (struct parameter *)self; } -extern Dwarf_Off parameter__type(struct parameter *self, const struct cu *cu); -extern const char *parameter__name(struct parameter *self, const struct cu *cu); +static inline const char *parameter__name(const struct parameter *self) +{ + return strings__ptr(strings, self->name); +} enum vlocation { LOCATION_UNKNOWN, @@ -478,8 +598,14 @@ struct label { struct tag tag; strings_t name; Dwarf_Addr low_pc; + 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; @@ -513,11 +639,11 @@ extern size_t class__fprintf(struct class *self, const struct cu *cu, const struct conf_fprintf *conf, FILE *fp); void enumeration__add(struct type *self, struct enumerator *enumerator); extern size_t enumeration__fprintf(const struct tag *tag_self, - const struct cu *cu, 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); @@ -539,8 +665,7 @@ extern size_t lexblock__fprintf(const struct lexblock *self, const struct cu *cu, struct function *function, uint16_t indent, FILE *fp); -extern int cus__loadfl(struct cus *self, struct argp *argp, - int argc, char *argv[]); +extern int cus__loadfl(struct cus *self, char *filenames[]); extern int cus__load(struct cus *self, const char *filename); extern int cus__load_dir(struct cus *self, const char *dirname, const char *filename_mask, const int recursive); @@ -550,11 +675,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, + 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); @@ -565,14 +696,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); + 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, @@ -620,7 +755,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); @@ -678,4 +813,8 @@ extern const char *variable__type_name(const struct variable *self, extern const char *dwarf_tag_name(const uint32_t tag); +struct argp_state; + +void dwarves_print_version(FILE *fp, struct argp_state *state); + #endif /* _DWARVES_H_ */ diff --git a/dwarves_emit.c b/dwarves_emit.c index ad3face..0abdaac 100644 --- a/dwarves_emit.c +++ b/dwarves_emit.c @@ -47,8 +47,8 @@ struct type *type_emissions__find_definition(const struct type_emissions *self, return NULL; list_for_each_entry(pos, &self->definitions, node) - if (type__name(pos, NULL) != NULL && - strcmp(type__name(pos, NULL), name) == 0) + if (type__name(pos) != NULL && + strcmp(type__name(pos), name) == 0) return pos; return NULL; @@ -60,14 +60,13 @@ static struct type *type_emissions__find_fwd_decl(const struct type_emissions *s struct type *pos; list_for_each_entry(pos, &self->fwd_decls, node) - if (strcmp(type__name(pos, NULL), name) == 0) + if (strcmp(type__name(pos), name) == 0) return pos; return NULL; } static int enumeration__emit_definitions(struct tag *self, - const struct cu *cu, struct type_emissions *emissions, const struct conf_fprintf *conf, FILE *fp) @@ -80,7 +79,7 @@ static int enumeration__emit_definitions(struct tag *self, /* Ok, lets look at the previous CUs: */ if (type_emissions__find_definition(emissions, - type__name(etype, cu)) != NULL) { + type__name(etype)) != NULL) { /* * Yes, so lets mark it visited on this CU too, * to speed up the lookup. @@ -89,7 +88,7 @@ static int enumeration__emit_definitions(struct tag *self, return 0; } - enumeration__fprintf(self, cu, conf, fp); + enumeration__fprintf(self, conf, fp); fputs(";\n", fp); type_emissions__add_definition(emissions, etype); return 1; @@ -111,7 +110,7 @@ static int typedef__emit_definitions(struct tag *tdef, struct cu *cu, /* Ok, lets look at the previous CUs: */ if (type_emissions__find_definition(emissions, - type__name(def, cu)) != NULL) { + type__name(def)) != NULL) { /* * Yes, so lets mark it visited on this CU too, * to speed up the lookup. @@ -120,7 +119,7 @@ static int typedef__emit_definitions(struct tag *tdef, struct cu *cu, return 0; } - type = cu__find_tag_by_id(cu, tdef->type); + type = cu__find_type_by_id(cu, tdef->type); tag__assert_search_result(type); switch (type->tag) { @@ -131,7 +130,7 @@ static int typedef__emit_definitions(struct tag *tdef, struct cu *cu, typedef__emit_definitions(type, cu, emissions, fp); break; case DW_TAG_pointer_type: - ptr_type = cu__find_tag_by_id(cu, type->type); + ptr_type = cu__find_type_by_id(cu, type->type); tag__assert_search_result(ptr_type); if (ptr_type->tag != DW_TAG_subroutine_type) break; @@ -147,23 +146,23 @@ static int typedef__emit_definitions(struct tag *tdef, struct cu *cu, .suffix = NULL, }; - if (type__name(ctype, cu) == NULL) { + if (type__name(ctype) == NULL) { fputs("typedef ", fp); - conf.suffix = type__name(def, cu); - enumeration__emit_definitions(type, cu, emissions, &conf, fp); + conf.suffix = type__name(def); + enumeration__emit_definitions(type, emissions, &conf, fp); goto out; } else - enumeration__emit_definitions(type, cu, emissions, &conf, fp); + enumeration__emit_definitions(type, emissions, &conf, fp); } break; case DW_TAG_structure_type: case DW_TAG_union_type: { struct type *ctype = tag__type(type); - if (type__name(ctype, cu) == NULL) { + if (type__name(ctype) == NULL) { if (type__emit_definitions(type, cu, emissions, fp)) type__emit(type, cu, "typedef", - type__name(def, cu), fp); + type__name(def), fp); goto out; } else if (type__emit_definitions(type, cu, emissions, fp)) type__emit(type, cu, NULL, NULL, fp); @@ -187,7 +186,7 @@ out: return 1; } -int type__emit_fwd_decl(struct type *ctype, const struct cu *cu, +int type__emit_fwd_decl(struct type *ctype, struct type_emissions *emissions, FILE *fp) { /* Have we already emitted this in this CU? */ @@ -196,7 +195,7 @@ int type__emit_fwd_decl(struct type *ctype, const struct cu *cu, /* Ok, lets look at the previous CUs: */ if (type_emissions__find_fwd_decl(emissions, - type__name(ctype, cu)) != NULL) { + type__name(ctype)) != NULL) { /* * Yes, so lets mark it visited on this CU too, * to speed up the lookup. @@ -207,7 +206,7 @@ int type__emit_fwd_decl(struct type *ctype, const struct cu *cu, fprintf(fp, "%s %s;\n", tag__is_union(&ctype->namespace.tag) ? "union" : "struct", - type__name(ctype, cu)); + type__name(ctype)); type_emissions__add_fwd_decl(emissions, ctype); return 1; } @@ -215,7 +214,7 @@ int type__emit_fwd_decl(struct type *ctype, const struct cu *cu, static int tag__emit_definitions(struct tag *self, struct cu *cu, struct type_emissions *emissions, FILE *fp) { - struct tag *type = cu__find_tag_by_id(cu, self->type); + struct tag *type = cu__find_type_by_id(cu, self->type); int pointer = 0; if (type == NULL) @@ -229,26 +228,25 @@ next_indirection: case DW_TAG_array_type: case DW_TAG_const_type: case DW_TAG_volatile_type: - type = cu__find_tag_by_id(cu, type->type); + type = cu__find_type_by_id(cu, type->type); if (type == NULL) return 0; goto next_indirection; case DW_TAG_typedef: return typedef__emit_definitions(type, cu, emissions, fp); case DW_TAG_enumeration_type: - if (type__name(tag__type(type), cu) != NULL) { + if (type__name(tag__type(type)) != NULL) { struct conf_fprintf conf = { .suffix = NULL, }; - return enumeration__emit_definitions(type, cu, - emissions, + return enumeration__emit_definitions(type, emissions, &conf, fp); } break; case DW_TAG_structure_type: case DW_TAG_union_type: if (pointer) - return type__emit_fwd_decl(tag__type(type), cu, + return type__emit_fwd_decl(tag__type(type), emissions, fp); if (type__emit_definitions(type, cu, emissions, fp)) type__emit(type, cu, NULL, NULL, fp); @@ -289,7 +287,7 @@ int type__emit_definitions(struct tag *self, struct cu *cu, /* Ok, lets look at the previous CUs: */ if (type_emissions__find_definition(emissions, - type__name(ctype, cu)) != NULL) { + type__name(ctype)) != NULL) { ctype->definition_emitted = 1; return 0; } @@ -308,10 +306,7 @@ void type__emit(struct tag *tag_self, struct cu *cu, { struct type *ctype = tag__type(tag_self); - if (tag__is_struct(tag_self)) - class__find_holes(tag__class(tag_self), cu); - - if (type__name(ctype, cu) != NULL || + if (type__name(ctype) != NULL || suffix != NULL || prefix != NULL) { struct conf_fprintf conf = { .prefix = prefix, diff --git a/dwarves_emit.h b/dwarves_emit.h index 9b7fc85..196a7e3 100644 --- a/dwarves_emit.h +++ b/dwarves_emit.h @@ -29,7 +29,7 @@ int ftype__emit_definitions(struct ftype *self, struct cu *cu, struct type_emissions *emissions, FILE *fp); int type__emit_definitions(struct tag *self, struct cu *cu, struct type_emissions *emissions, FILE *fp); -int type__emit_fwd_decl(struct type *ctype, const struct cu *cu, +int type__emit_fwd_decl(struct type *ctype, struct type_emissions *emissions, FILE *fp); void type__emit(struct tag *tag_self, struct cu *cu, const char *prefix, const char *suffix, FILE *fp); diff --git a/dwarves_reorganize.c b/dwarves_reorganize.c index 8d4f6e6..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,28 +468,34 @@ 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; + const char *type_name, *type_name_alt = NULL; switch (size) { case sizeof(unsigned char): type_name = "unsigned char"; break; case sizeof(unsigned short int): - type_name = "short unsigned int"; break; + type_name = "short unsigned int"; + type_name = "unsigned short"; break; case sizeof(unsigned int): - type_name = "unsigned int"; break; + type_name = "unsigned int"; + type_name_alt = "unsigned"; break; case sizeof(unsigned long long): - if (cu->addr_size == 8) + if (cu->addr_size == 8) { type_name = "long unsigned int"; - else + type_name_alt = "unsigned long"; + } else { type_name = "long long unsigned int"; + type_name_alt = "unsigned long long"; + } break; default: return NULL; } - return cu__find_base_type_by_name(cu, type_name); + 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, @@ -537,8 +544,10 @@ static int class__demote_bitfields(struct class *class, const struct cu *cu, if (bytes_needed == size) continue; - old_type_tag = cu__find_tag_by_id(cu, member->tag.type); - new_type_tag = cu__find_base_type_of_size(cu, bytes_needed); + 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_id); if (new_type_tag == NULL) { fprintf(fp, "/* BRAIN FART ALERT! couldn't find a " @@ -556,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) @@ -586,9 +596,11 @@ static int class__demote_bitfields(struct class *class, const struct cu *cu, bytes_needed = (member->bit_size + 7) / 8; if (bytes_needed < size) { old_type_tag = - cu__find_tag_by_id(cu, member->tag.type); + 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); @@ -602,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; /* @@ -661,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); @@ -727,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", @@ -738,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/man-pages/pahole.1 b/man-pages/pahole.1 new file mode 100644 index 0000000..b2c1f00 --- /dev/null +++ b/man-pages/pahole.1 @@ -0,0 +1,201 @@ +.\" Man page for pahole +.\" Arnaldo Carvalho de Melo, 2009 +.\" Licensed under version 2 of the GNU General Public License. +.TH pahole 1 "February 13, 2009" "dwarves" "dwarves" +.\" +.SH NAME +pahole \- Shows and manipulates data structure layout. +.SH SYNOPSIS +\fBpahole\fR [\fIoptions\fR] \fIfiles\fR +.SH DESCRIPTION +.B pahole +shows data structure layouts encoded in debugging information formats, +DWARF and CTF being supported. + +This is useful for, among other things: optimizing important data structures by +reducing its size, figuring out what is the field sitting at an offset from the +start of a data structure, investigating ABI changes and more generally +understanding a new codebase you have to work with. + +The files must have associated debugging information. This information may be +inside the file itself, in ELF sections, or in another file. + +One way to have this information is to specify the \fB\-g\fR option to the +compiler when building it. When this is done the information will be stored in +an ELF section. For the DWARF debugging information format this, adds, among +others, the \fB.debug_info\fR ELF section. For the CTF it is found in just one +ELF section, \fB.SUNW_ctf\fR. + +The \fBdebuginfo\fR packages available in most Linux distributions are also +supported by \fBpahole\fR, where the debugging information is available in a +separate file. + +By default, \fBpahole\fR shows the layout of all named structs in the files +specified. + +.SH OPTIONS +pahole supports the following options. + +.TP +.B \-C, \-\-class_name=CLASS_NAME +Show just this class. + +.TP +.B \-c, \-\-cacheline_size=SIZE +Set cacheline size to SIZE bytes. + +.TP +.B \-E, \-\-expand_types +Expand class members. Useful to find in what member of inner structs where an +offset from the beginning of a struct is. + +.TP +.B \-r, \-\-rel_offset +Show relative offsets of members in inner structs. + +.TP +.B \-p, \-\-expand_pointers +Expand class pointer members. + +.TP +.B \-R, \-\-reorganize +Reorganize struct, demoting and combining bitfields, moving members to remove +alignment holes and padding. + +.TP +.B \-S, \-\-show_reorg_steps +Show the struct layout at each reorganization step. + +.TP +.B \-i, \-\-contains=CLASS_NAME +Show classes that contains CLASS_NAME. + +.TP +.B \-a, \-\-anon_include +Include anonymous classes. + +.TP +.B \-A, \-\-nested_anon_include +Include nested (inside other structs) anonymous classes. + +.TP +.B \-B, \-\-bit_holes=NR_HOLES +Show only structs at least NR_HOLES bit holes. + +.TP +.B \-d, \-\-recursive +Recursive mode, affects several other flags. + +.TP +.B \-D, \-\-decl_exclude=PREFIX +exclude classes declared in files with PREFIX. + +.TP +.B \-f, \-\-find_pointers_to=CLASS_NAME +Find pointers to CLASS_NAME. + +.TP +.B \-H, \-\-holes=NR_HOLES +Show only structs with at least NR_HOLES holes. + +.TP +.B \-I, \-\-show_decl_info +Show the file and line number where the tags were defined, if available in +the debugging information. + +.TP +.B \-l, \-\-show_first_biggest_size_base_type_member +Show first biggest size base_type member. + +.TP +.B \-m, \-\-nr_methods +Show number of methods. + +.TP +.B \-M, \-\-show_only_data_members +Show only the members that use space in the class layout. C++ methods will be +suppressed. + +.TP +.B \-n, \-\-nr_members +Show number of members. + +.TP +.B \-N, \-\-class_name_len +Show size of classes. + +.TP +.B \-O, \-\-dwarf_offset=OFFSET +Show tag with DWARF OFFSET. + +.TP +.B \-P, \-\-packable +Show only structs that has holes that can be packed if members are reorganized, +for instance when using the \fB\-\-reorganize\fR option. + +.TP +.B \-q, \-\-quiet +Be quieter. + +.TP +.B \-s, \-\-sizes +Show size of classes. + +.TP +.B \-t, \-\-separator=SEP +Use SEP as the field separator. + +.TP +.B \-T, \-\-nr_definitions +Show how many times struct was defined. + +.TP +.B \-u, \-\-defined_in +Show CUs where CLASS_NAME (-C) is defined. + +.TP +.B \-V, \-\-verbose +be verbose + +.TP +.B \-w, \-\-word_size=WORD_SIZE +Change the arch word size to WORD_SIZE. + +.TP +.B \-x, \-\-exclude=PREFIX +Exclude PREFIXed classes. + +.TP +.B \-X, \-\-cu_exclude=PREFIX +Exclude PREFIXed compilation units. + +.TP +.B \-y, \-\-prefix_filter=PREFIX +Include PREFIXed classes. + +.TP +.B \-z, \-\-hole_size_ge=HOLE_SIZE +Show only structs with at least one hole greater or equal to HOLE_SIZE. + +.SH NOTES + +To enable the generation of debugging information in the Linux kernel build +process select CONFIG_DEBUG_INFO. This can be done using make menuconfig by +this path: "Kernel Hacking" -> "Kernel Debugging" -> "Compile the kernel with +debug info". + +Many distributions also come with debuginfo packages, so just enable it in your +package manager repository configuration and install the kernel-debuginfo, or +any other userspace program written in a language that the compiler generates +debuginfo (C, C++, for instance). + +.SH SEE ALSO +\fIeu-readelf\fR(1), \fIreadelf\fR(1), \fIobjdump\fR(1). +.P +\fIhttp://oops.ghostprotocols.net:81/acme/7dwarves.pdf\fR. +.SH AUTHOR +\fBpahole\fR was written by Arnaldo Carvalho de Melo . + +Please send bug reports to . +.P +No\ subscription is required. diff --git a/pahole.c b/pahole.c index f2e911b..a7a3634 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) @@ -143,19 +145,17 @@ static struct structure *structures__find_anonymous(strings_t name) struct structure *pos; 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); + struct class *c; + const struct tag *tdef = cu__find_first_typedef_of_type(pos->cu, pos->id); if (tdef == NULL) continue; c = tag__class(tdef); - /* Let it follow abstract_origin, etc */ - class__name(c, pos->cu); - if (c->type.namespace.name == name) - return pos; - } + if (c->type.namespace.name == name) + return pos; + } return NULL; } @@ -178,45 +178,45 @@ static struct structure *structures__find(strings_t name) static void nr_definitions_formatter(struct structure *self) { - printf("%s%c%u\n", class__name(self->class, self->cu), separator, + printf("%s%c%u\n", class__name(self->class), separator, self->nr_files); } static void nr_members_formatter(struct structure *self) { - printf("%s%c%u\n", class__name(self->class, self->cu), separator, + printf("%s%c%u\n", class__name(self->class), separator, class__nr_members(self->class)); } static void nr_methods_formatter(struct structure *self) { - printf("%s%c%u\n", class__name(self->class, self->cu), separator, + printf("%s%c%u\n", class__name(self->class), separator, self->nr_methods); } static void size_formatter(struct structure *self) { - printf("%s%c%zd%c%u\n", class__name(self->class, self->cu), separator, + printf("%s%c%zd%c%u\n", class__name(self->class), separator, class__size(self->class), separator, self->class->nr_holes); } static void class_name_len_formatter(struct structure *self) { - const char *name = class__name(self->class, self->cu); + const char *name = class__name(self->class); printf("%s%c%zd\n", name, separator, strlen(name)); } static void class_name_formatter(struct structure *self) { - puts(class__name(self->class, self->cu)); + puts(class__name(self->class)); } static void class_formatter(struct structure *self) { struct tag *typedef_alias = NULL; struct tag *tag = class__tag(self->class); - const char *name = class__name(self->class, self->cu); + const char *name = class__name(self->class); if (name == NULL) { /* @@ -225,7 +225,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 @@ -241,7 +241,7 @@ static void class_formatter(struct structure *self) struct type *tdef = tag__type(typedef_alias); conf.prefix = "typedef"; - conf.suffix = type__name(tdef, self->cu); + conf.suffix = type__name(tdef); } else conf.prefix = conf.suffix = NULL; @@ -260,15 +260,15 @@ static void print_packable_info(struct structure *pos) const size_t orig_size = class__size(c); const size_t new_size = class__size(c->priv); const size_t savings = orig_size - new_size; - const char *name = class__name(c, pos->cu); + const char *name = class__name(c); /* 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); + name = class__name(tag__class(tdef)); } if (name != NULL) printf("%s%c%zd%c%zd%c%zd\n", @@ -278,7 +278,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, @@ -346,7 +347,7 @@ static void class__dupmsg(struct class *self, const struct cu *cu, if (!*hdr) printf("class: %s\nfirst: %s\ncurrent: %s\n", - class__name(self, cu), cu->name, dup_cu->name); + class__name(self), cu->name, dup_cu->name); va_start(args, fmt); vprintf(fmt, args); @@ -391,7 +392,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,8 +402,11 @@ 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); + name = class__name(class); stname = class->type.namespace.name; if (class__is_declaration(class)) @@ -414,15 +418,14 @@ 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); - name = class__name(c, cu); + name = class__name(c); stname = c->type.namespace.name; } } - if (name != NULL && strncmp(class__exclude_prefix, name, class__exclude_prefix_len) == 0) return NULL; @@ -431,15 +434,14 @@ 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); - name = class__name(c, cu); + name = class__name(c); stname = c->type.namespace.name; } } - if (name != NULL && strncmp(class__include_prefix, name, class__include_prefix_len) != 0) return NULL; @@ -447,13 +449,11 @@ 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; - class__find_holes(class, cu); - if (class->nr_holes < nr_holes || class->nr_bit_holes < nr_bit_holes || (hole_size_ge != 0 && !class__has_hole_ge(class, hole_size_ge))) @@ -473,28 +473,27 @@ 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; + uint16_t id; + struct tag *tag; + + if (defined_in) { + tag = cu__find_struct_by_name(cu, class_name, 0, &id); + if (tag != NULL) + puts(cu->name); + } 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; } -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); - - if (tag != NULL) - puts(cu->name); - } else - return cu__for_each_tag(cu, unique_iterator, cookie, tag__filter); - return 0; -} +static strings_t long_int_str_t, long_unsigned_int_str_t; static void union__find_new_size(struct tag *tag, struct cu *cu); @@ -525,14 +524,14 @@ static void class__resize_LP(struct tag *tag, struct cu *cu) tag_pos->tag != DW_TAG_inheritance) continue; - type = cu__find_tag_by_id(cu, tag_pos->type); + type = cu__find_type_by_id(cu, tag_pos->type); tag__assert_search_result(type); if (type->tag == DW_TAG_array_type) { int i; for (i = 0; i < tag__array_type(type)->dimensions; ++i) array_multiplier *= tag__array_type(type)->nr_entries[i]; - type = cu__find_tag_by_id(cu, type->type); + type = cu__find_type_by_id(cu, type->type); tag__assert_search_result(type); } @@ -545,8 +544,8 @@ static void class__resize_LP(struct tag *tag, struct cu *cu) case DW_TAG_base_type: { struct base_type *bt = tag__base_type(type); - if (strcmp(base_type__name(bt), "long int") != 0 && - strcmp(base_type__name(bt), "long unsigned int") != 0) + if (bt->name != long_int_str_t && + bt->name != long_unsigned_int_str_t) break; /* fallthru */ } @@ -606,7 +605,7 @@ static void union__find_new_size(struct tag *tag, struct cu *cu) tag_pos->tag != DW_TAG_inheritance) continue; - type = cu__find_tag_by_id(cu, tag_pos->type); + type = cu__find_type_by_id(cu, tag_pos->type); tag__assert_search_result(type); if (tag__is_typedef(type)) type = tag__follow_typedef(type, cu); @@ -651,8 +650,8 @@ static int tag_fixup_word_size_iterator(struct tag *tag, struct cu *cu, if (!bt->name) return 0; - if (strcmp(base_type__name(bt), "long int") == 0 || - strcmp(base_type__name(bt), "long unsigned int") == 0) + if (bt->name == long_int_str_t || + bt->name == long_unsigned_int_str_t) bt->bit_size = word_size * 8; } break; @@ -667,17 +666,17 @@ static int tag_fixup_word_size_iterator(struct tag *tag, struct cu *cu, return 0; } -static int cu_fixup_word_size_iterator(struct cu *cu, void *cookie) +static int cu_fixup_word_size_iterator(struct cu *cu, void *cookie __unused) { original_word_size = cu->addr_size; cu->addr_size = word_size; - return cu__for_each_tag(cu, tag_fixup_word_size_iterator, cookie, NULL); + return cu__for_each_tag(cu, tag_fixup_word_size_iterator, NULL, NULL); } static struct tag *nr_methods__filter(struct tag *tag, struct cu *cu __unused, void *cookie __unused) { - if (tag->tag != DW_TAG_subprogram) + if (!tag__is_function(tag)) return NULL; if (function__declared_inline(tag__function(tag))) @@ -694,21 +693,19 @@ static int nr_methods_iterator(struct tag *tag, struct cu *cu, struct type *ctype; list_for_each_entry(pos, &tag__ftype(tag)->parms, tag.node) { - struct tag *type = - cu__find_tag_by_id(cu, parameter__type(pos, cu)); + struct tag *type = cu__find_type_by_id(cu, pos->tag.type); if (type == NULL || type->tag != DW_TAG_pointer_type) continue; - type = cu__find_tag_by_id(cu, type->type); + type = cu__find_type_by_id(cu, type->type); if (type == NULL || !tag__is_struct(type)) continue; ctype = tag__type(type); - if (type__name(ctype, cu) == NULL) + if (type__name(ctype) == NULL) continue; - type__name(ctype, cu); /* Resolution of abstract_origin, etc */ str = structures__find(ctype->namespace.name); if (str != NULL) ++str->nr_methods; @@ -728,8 +725,8 @@ static char tab[128]; static void print_structs_with_pointer_to(const struct structure *s) { struct structure *pos_structure; - Dwarf_Off type; - const char *class_name = class__name(s->class, s->cu); + uint16_t type; + const char *class_name = class__name(s->class); const struct cu *current_cu = NULL; list_for_each_entry(pos_structure, &structures__named_list, node) { @@ -737,21 +734,24 @@ 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) { - struct tag *ctype = cu__find_tag_by_id(pos_structure->cu, pos_member->tag.type); + struct tag *ctype = cu__find_type_by_id(pos_structure->cu, pos_member->tag.type); tag__assert_search_result(ctype); if (ctype->tag == DW_TAG_pointer_type && ctype->type == type) - printf("%s: %s\n", class__name(c, pos_structure->cu), + printf("%s: %s\n", class__name(c), class_member__name(pos_member)); } } @@ -760,14 +760,14 @@ 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; const uint32_t n = type__nr_members_of_type(&c->type, type); if (n != 0) { - printf("%.*s%s", ident * 2, tab, class__name(c, pos->cu)); + printf("%.*s%s", ident * 2, tab, class__name(c)); if (global_verbose) printf(": %u", n); putchar('\n'); @@ -777,6 +777,9 @@ static void print_containers(const struct structure *s, int ident) } } +/* Name and version of program. */ +ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version; + static const struct argp_option pahole__options[] = { { .name = "bit_holes", @@ -1044,7 +1047,7 @@ static struct argp pahole__argp = { int main(int argc, char *argv[]) { - int err; + int err, remaining; struct cus *cus = cus__new(); if (dwarves__init(cacheline_size) || cus == NULL) { @@ -1052,12 +1055,31 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } - err = cus__loadfl(cus, &pahole__argp, argc, argv); - if (err != 0) - return EXIT_FAILURE; + if (argp_parse(&pahole__argp, argc, argv, 0, &remaining, NULL) || + remaining == argc) { + argp_help(&pahole__argp, stderr, ARGP_HELP_SEE, argv[0]); + return EXIT_FAILURE; + } + + err = cus__loadfl(cus, argv + remaining); + if (err != 0) { + fputs("pahole: No debugging information found\n", stderr); + return EXIT_FAILURE; + } + + if (word_size != 0) { + long_int_str_t = strings__find(strings, "long int"), + long_unsigned_int_str_t = + strings__find(strings, "long unsigned int"); + + if (long_int_str_t == 0 || long_unsigned_int_str_t == 0) { + fputs("pahole: couldn't find one of \"long int\" or " + "\"long unsigned int\" types", stderr); + return EXIT_FAILURE; + } - if (word_size != 0) cus__for_each_cu(cus, cu_fixup_word_size_iterator, NULL, NULL); + } if (class_dwarf_offset != 0) { struct cu *cu; diff --git a/pdwtags.c b/pdwtags.c index b23de30..9956cfd 100644 --- a/pdwtags.c +++ b/pdwtags.c @@ -18,46 +18,40 @@ 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); + conf.no_semicolon = tag__is_function(self); - conf.no_semicolon = self->tag == DW_TAG_subprogram; + printf("%d ", tag_id); - printf("%lld ", (unsigned long long)self->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 (tag__is_function(self)) { + 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; } @@ -66,6 +60,9 @@ static void cus__emit_tags(struct cus *self) cus__for_each_cu(self, cu__emit_tags, NULL, NULL); } +/* Name and version of program. */ +ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version; + static const struct argp_option pdwtags__options[] = { { .key = 'V', @@ -101,7 +98,7 @@ static struct argp pdwtags__argp = { int main(int argc, char *argv[]) { - int err; + int err, remaining; struct cus *cus = cus__new(); if (dwarves__init(0) || cus == NULL) { @@ -109,7 +106,13 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } - err = cus__loadfl(cus, &pdwtags__argp, argc, argv); + if (argp_parse(&pdwtags__argp, argc, argv, 0, &remaining, NULL) || + remaining == argc) { + argp_help(&pdwtags__argp, stderr, ARGP_HELP_SEE, argv[0]); + return EXIT_FAILURE; + } + + err = cus__loadfl(cus, argv + remaining); if (err != 0) return EXIT_FAILURE; diff --git a/pfunct.c b/pfunct.c index 980e34d..4c45f1b 100644 --- a/pfunct.c +++ b/pfunct.c @@ -215,7 +215,10 @@ static struct tag *function__filter(struct tag *tag, struct cu *cu, struct fn_stats *fstats; const char *name; - if (tag->tag != DW_TAG_subprogram) + if (!tag__is_function(tag)) + return NULL; + + if (!tag->top_level) return NULL; function = tag__function(tag); @@ -258,7 +261,7 @@ static struct tag *function__filter(struct tag *tag, struct cu *cu, static int unique_iterator(struct tag *tag, struct cu *cu, void *cookie __unused) { - if (tag->tag == DW_TAG_subprogram) + if (tag__is_function(tag)) fn_stats__add(tag, cu); return 0; } @@ -271,16 +274,17 @@ 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) + if (!tag__is_function(tag)) return 0; function = tag__function(tag); 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, @@ -306,13 +311,13 @@ static int function__emit_type_definitions(struct function *self, struct parameter *pos; function__for_each_parameter(self, pos) { - struct tag *type = cu__find_tag_by_id(cu, parameter__type(pos, cu)); + struct tag *type = cu__find_type_by_id(cu, pos->tag.type); try_again: if (type == NULL) continue; if (type->tag == DW_TAG_pointer_type) { - type = cu__find_tag_by_id(cu, type->type); + type = cu__find_type_by_id(cu, type->type); goto try_again; } @@ -330,7 +335,7 @@ static int function_iterator(struct tag *tag, struct cu *cu, void *cookie) { struct function *function; - if (tag->tag != DW_TAG_subprogram) + if (!tag__is_function(tag)) return 0; function = tag__function(tag); @@ -351,6 +356,9 @@ static int cu_function_iterator(struct cu *cu, void *cookie) return cu__for_each_tag(cu, function_iterator, cookie, NULL); } +/* Name and version of program. */ +ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version; + static const struct argp_option pfunct__options[] = { { .key = 'b', @@ -491,7 +499,7 @@ static struct argp pfunct__argp = { int main(int argc, char *argv[]) { - int err; + int err, remaining; struct cus *cus = cus__new(); if (dwarves__init(0) || cus == NULL) { @@ -499,7 +507,13 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } - err = cus__loadfl(cus, &pfunct__argp, argc, argv); + if (argp_parse(&pfunct__argp, argc, argv, 0, &remaining, NULL) || + remaining == argc) { + argp_help(&pfunct__argp, stderr, ARGP_HELP_SEE, argv[0]); + return EXIT_FAILURE; + } + + err = cus__loadfl(cus, argv + remaining); if (err != 0) return EXIT_FAILURE; diff --git a/pglobal.c b/pglobal.c index bde1f94..8066455 100644 --- a/pglobal.c +++ b/pglobal.c @@ -139,7 +139,7 @@ static struct tag *extfun__filter(struct tag *tag, struct cu *cu __unused, { struct function *fun; - if (tag->tag != DW_TAG_subprogram) + if (!tag__is_function(tag)) return NULL; fun = tag__function(tag); @@ -264,6 +264,9 @@ static void free_node(void *nodep) free(*node); } +/* Name and version of program. */ +ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version; + static const struct argp_option pglobal__options[] = { { .key = 'v', @@ -313,7 +316,7 @@ static struct argp pglobal__argp = { int main(int argc, char *argv[]) { - int err; + int err, remaining; struct cus *cus = cus__new(); if (dwarves__init(0) || cus == NULL) { @@ -321,7 +324,13 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } - err = cus__loadfl(cus, &pglobal__argp, argc, argv); + if (argp_parse(&pglobal__argp, argc, argv, 0, &remaining, NULL) || + remaining == argc) { + argp_help(&pglobal__argp, stderr, ARGP_HELP_SEE, argv[0]); + return EXIT_FAILURE; + } + + err = cus__loadfl(cus, argv + remaining); if (err != 0) return EXIT_FAILURE; diff --git a/prefcnt.c b/prefcnt.c index 6be6578..a14b01e 100644 --- a/prefcnt.c +++ b/prefcnt.c @@ -24,7 +24,7 @@ static void refcnt_member(struct class_member *member, const struct cu *cu) return; member->visited = 1; if (member->tag.type != 0) { /* if not void */ - struct tag *type = cu__find_tag_by_id(cu, member->tag.type); + struct tag *type = cu__find_type_by_id(cu, member->tag.type); if (type != NULL) refcnt_tag(type, cu); } @@ -34,7 +34,7 @@ static void refcnt_parameter(const struct parameter *parameter, const struct cu *cu) { if (parameter->tag.type != 0) { /* if not void */ - struct tag *type = cu__find_tag_by_id(cu, parameter->tag.type); + struct tag *type = cu__find_type_by_id(cu, parameter->tag.type); if (type != NULL) refcnt_tag(type, cu); } @@ -44,7 +44,7 @@ static void refcnt_variable(const struct variable *variable, const struct cu *cu) { if (variable->tag.type != 0) { /* if not void */ - struct tag *type = cu__find_tag_by_id(cu, variable->tag.type); + struct tag *type = cu__find_type_by_id(cu, variable->tag.type); if (type != NULL) refcnt_tag(type, cu); } @@ -64,7 +64,7 @@ static void refcnt_tag(struct tag *tag, const struct cu *cu) { struct class_member *member; - tag->refcnt++; + tag->visited = 1; if (tag__is_struct(tag) || tag__is_union(tag)) type__for_each_member(tag__type(tag), member) @@ -93,11 +93,11 @@ static void refcnt_function(struct function *function, const struct cu *cu) { struct parameter *parameter; - function->proto.tag.refcnt++; + function->proto.tag.visited = 1; if (function->proto.tag.type != 0) /* if not void */ { struct tag *type = - cu__find_tag_by_id(cu, function->proto.tag.type); + cu__find_type_by_id(cu, function->proto.tag.type); if (type != NULL) refcnt_tag(type, cu); } @@ -118,9 +118,7 @@ static int refcnt_function_iterator(struct function *function, static int refcnt_tag_iterator(struct tag *tag, struct cu *cu, void *cookie) { - if (tag__is_struct(tag)) - class__find_holes(tag__class(tag), cu); - else if (tag->tag == DW_TAG_subprogram) + if (tag__is_function(tag)) refcnt_function_iterator(tag__function(tag), cu, cookie); return 0; @@ -135,7 +133,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->refcnt == 0 && tag->decl_file) { + if (!tag->visited && tag__decl_file(tag, cu)) { tag__fprintf(tag, cu, NULL, stdout); puts(";\n"); } @@ -147,7 +145,7 @@ static int cu_lost_iterator(struct cu *cu, void *cookie) return cu__for_each_tag(cu, lost_iterator, cookie, NULL); } -int main(int argc, char *argv[]) +int main(int argc __unused, char *argv[]) { int err; struct cus *cus = cus__new(); @@ -157,7 +155,7 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } - err = cus__loadfl(cus, NULL, argc, argv); + err = cus__loadfl(cus, argv + 1); if (err != 0) return EXIT_FAILURE; diff --git a/rpm/SPECS/dwarves.spec b/rpm/SPECS/dwarves.spec index 28e1aa4..086719d 100644 --- a/rpm/SPECS/dwarves.spec +++ b/rpm/SPECS/dwarves.spec @@ -2,13 +2,13 @@ %define libver 1 Name: dwarves -Version: 1.6 -Release: 1 +Version: 1.7 +Release: 2 License: GPLv2 Summary: Dwarf Tools Group: Development/Tools URL: http://oops.ghostprotocols.net:81/blog -Source: http://userweb.kernel.org/~acme/dwarves/%{name}-%{version}.tar.bz2 +Source: http://fedorapeople.org/~acme/dwarves/%{name}-%{version}.tar.bz2 BuildRequires: cmake BuildRequires: elfutils-devel >= 0.130 BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) @@ -82,9 +82,11 @@ rm -rf %{buildroot} %{_bindir}/prefcnt %{_bindir}/syscse %{_bindir}/ostra-cg +%dir %{_datadir}/dwarves/ %dir %{_datadir}/dwarves/runtime/ %dir %{_datadir}/dwarves/runtime/python/ %defattr(0644,root,root,0755) +%{_mandir}/man1/pahole.1* %{_datadir}/dwarves/runtime/Makefile %{_datadir}/dwarves/runtime/linux.blacklist.cu %{_datadir}/dwarves/runtime/ctracer_relay.c @@ -108,6 +110,24 @@ rm -rf %{buildroot} %{_libdir}/%{libname}_reorganize.so %changelog +* Fri Feb 13 2009 Arnaldo Carvalho de Melo - 1.7-2 +- Own /usr/share/dwarves, fixes #473645 + +* Fri Feb 13 2009 Arnaldo Carvalho de Melo - 1.7-1 +- A CTF decoder based on work done by David S. Miller +- Handle DW_TAG_class_type, +- Add support for showing classes with a prefix +- Add support to DW_TAG_ptr_to_member_type +- Handle typedef definitions in functions +- Print the number of members in a struct/class +- Handle the empty base optimization trick (Zero sized C++ class) +- codiff detect changes in the prototype even when function size doesn't change +- pfunct: Implement --expand_types +- Reduce memory consumption by using a strings table +- Speed up struct search by name +- Several minor bug fixes and infrastructure improvements. +- Initial man page for pahole + * Mon Feb 11 2008 Arnaldo Carvalho de Melo - 1.6-1 - c83d935a4fd561a3807f520c126c2a61ae1f4d83 - [DWARVES]: Use a hash table for the tags in a CU diff --git a/syscse.c b/syscse.c index 168e560..7dd475b 100644 --- a/syscse.c +++ b/syscse.c @@ -23,7 +23,7 @@ static size_t prefix_len = 4; static struct tag *filter(struct tag *self, struct cu *cu, void *cookie __unused) { - if (self->tag == DW_TAG_subprogram) { + if (tag__is_function(self)) { struct function *f = tag__function(self); if (f->proto.nr_parms != 0) { @@ -68,8 +68,8 @@ static int emit_wrapper(struct tag *self, struct cu *cu, void *cookie __unused) int regparm = 0, needs_wrapper = 0; function__for_each_parameter(f, parm) { - const Dwarf_Off type_id = parameter__type(parm, cu); - struct tag *type = cu__find_tag_by_id(cu, type_id); + const uint16_t type_id = parm->tag.type; + struct tag *type = cu__find_type_by_id(cu, type_id); tag__assert_search_result(type); if (type->tag == DW_TAG_base_type) { @@ -81,8 +81,7 @@ static int emit_wrapper(struct tag *self, struct cu *cu, void *cookie __unused) printf("wrap_%s:\n", name); needs_wrapper = 1; } - zero_extend(regparm, bt, - parameter__name(parm, cu)); + zero_extend(regparm, bt, parameter__name(parm)); } } ++regparm; @@ -105,6 +104,9 @@ static void cus__emit_wrapper(struct cus *self) cus__for_each_cu(self, cu__emit_wrapper, NULL, NULL); } +/* Name and version of program. */ +ARGP_PROGRAM_VERSION_HOOK_DEF = dwarves_print_version; + static const struct argp_option options[] = { { .key = 'p', @@ -144,7 +146,7 @@ static struct argp argp = { int main(int argc, char *argv[]) { - int err; + int err, remaining; struct cus *cus = cus__new(); if (cus == NULL) { @@ -152,7 +154,12 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } - err = cus__loadfl(cus, &argp, argc, argv); + if (argp_parse(&argp, argc, argv, 0, &remaining, NULL) || + remaining == argc) { + argp_help(&argp, stderr, ARGP_HELP_SEE, argv[0]); + return EXIT_FAILURE; + } + err = cus__loadfl(cus, argv + remaining); if (err != 0) return EXIT_FAILURE;