From 3bbd1342b295bad660929f9b49cf93d6f7e78669 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 9 Feb 2009 16:30:06 -0200 Subject: [PATCH 01/40] dwarf_loader: remove old ugly with_executable_option hack Now we use dwfl_report_offline directly, having more control about the whole process, not using anymore dwfl_standard_argp. This also, semi magicly, makes it work with the built-in.o files in the Linux kernel, that aggregates multiple object files and that previously were failing with relocation problems. Signed-off-by: Arnaldo Carvalho de Melo --- codiff.c | 11 ++-- dwarf_loader.c | 138 ++++++++++++++++++++++++++++--------------------- 2 files changed, 84 insertions(+), 65 deletions(-) diff --git a/codiff.c b/codiff.c index 1ddbee3..b1fb483 100644 --- a/codiff.c +++ b/codiff.c @@ -717,13 +717,12 @@ failure: } dwfl_argv[0] = argv[0]; - dwfl_argv[1] = "-e"; - dwfl_argv[3] = NULL; + dwfl_argv[2] = 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); + dwfl_argv[1] = old_filename; + err = cus__loadfl(old_cus, NULL, 2, dwfl_argv); if (err != 0) { cus__print_error_msg("codiff", old_cus, old_filename, err); return EXIT_FAILURE; @@ -737,8 +736,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); + dwfl_argv[1] = new_filename; + err = cus__loadfl(new_cus, NULL, 2, dwfl_argv); if (err != 0) { cus__print_error_msg("codiff", new_cus, new_filename, err); return EXIT_FAILURE; diff --git a/dwarf_loader.c b/dwarf_loader.c index 1cfa2c4..5567d31 100644 --- a/dwarf_loader.c +++ b/dwarf_loader.c @@ -991,9 +991,7 @@ static void die__process(Dwarf_Die *die, struct cu *cu) __FUNCTION__, dwarf_tag_name(tag)); } -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 +1019,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 +1132,26 @@ out: return err; } -static int with_executable_option(int argc, char *argv[]) -{ - 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 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; + int err = 0, remaining = 1; - if (argc == 1) { - argp_help(argp ? : dwfl_standard_argp(), stderr, - ARGP_HELP_SEE, argv[0]); - return -1; - } + elf_version(EV_CURRENT); - 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; - } - 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++; - } + if (argp != NULL) + argp_parse(argp, argc, argv, 0, &remaining, NULL); - 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); + int fd = open(argv[remaining], O_RDONLY); + + if (fd == -1) { + fprintf(stderr, "%s: couldn't open %s\n", __func__, + argv[remaining]); + } + cus__process_file(self, fd, argv[remaining]); + close(fd); + } while (++remaining < argc); - dwfl_end(dwfl); - err = 0; -out: - free(new_argv); return err; } From 138cc4739c7e8ffae223a34f9f3e0216b4b19e50 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 9 Feb 2009 21:43:56 -0200 Subject: [PATCH 02/40] dwarves: Don't pass argp to dwarf_loadfl Now we just pass a NULL terminated array of filenames, since we got rid of that ugly -e insertion hack. Signed-off-by: Arnaldo Carvalho de Melo --- codiff.c | 20 +++++++++----------- ctf_loader.c | 10 ++-------- ctf_loader.h | 6 +----- ctracer.c | 7 +++---- dtagnames.c | 4 ++-- dwarf_loader.c | 22 ++++++++++------------ dwarf_loader.h | 4 +--- dwarves.c | 10 +++------- dwarves.h | 5 +---- pahole.c | 10 ++++++++-- pdwtags.c | 10 ++++++++-- pfunct.c | 10 ++++++++-- pglobal.c | 10 ++++++++-- prefcnt.c | 2 +- syscse.c | 9 +++++++-- 15 files changed, 72 insertions(+), 67 deletions(-) diff --git a/codiff.c b/codiff.c index b1fb483..c38256e 100644 --- a/codiff.c +++ b/codiff.c @@ -676,7 +676,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 +684,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 +694,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,13 +715,12 @@ failure: return EXIT_FAILURE; } - dwfl_argv[0] = argv[0]; - dwfl_argv[2] = NULL; + filenames[1] = NULL; /* If old_file is a character device, leave its cus empty */ if (!S_ISCHR(st.st_mode)) { - dwfl_argv[1] = old_filename; - err = cus__loadfl(old_cus, NULL, 2, 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; @@ -736,8 +734,8 @@ failure: /* If old_file is a character device, leave its cus empty */ if (!S_ISCHR(st.st_mode)) { - dwfl_argv[1] = new_filename; - err = cus__loadfl(new_cus, NULL, 2, 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..84c4bb1 100644 --- a/ctf_loader.c +++ b/ctf_loader.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include @@ -788,18 +787,13 @@ 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) +int ctf__load(struct cus *self, char *filenames[]) { struct ctf_state state; 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"); 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..45118d9 100644 --- a/ctracer.c +++ b/ctracer.c @@ -899,9 +899,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 +909,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; } 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/dwarf_loader.c b/dwarf_loader.c index 5567d31..94e1637 100644 --- a/dwarf_loader.c +++ b/dwarf_loader.c @@ -9,7 +9,6 @@ #include #include #include -#include #include #include #include @@ -1132,26 +1131,25 @@ out: return err; } -int dwarf__load(struct cus *self, struct argp *argp, int argc, char *argv[], - bool parsed __unused) +int dwarf__load(struct cus *self, char *filenames[], bool parsed __unused) { - int err = 0, remaining = 1; + int err = 0, i = 0; elf_version(EV_CURRENT); - if (argp != NULL) - argp_parse(argp, argc, argv, 0, &remaining, NULL); - - do { - int fd = open(argv[remaining], O_RDONLY); + while (filenames[i] != NULL) { + int fd = open(filenames[i], O_RDONLY); if (fd == -1) { fprintf(stderr, "%s: couldn't open %s\n", __func__, - argv[remaining]); + filenames[i]); + ++i; + continue; } - cus__process_file(self, fd, argv[remaining]); + cus__process_file(self, fd, filenames[i]); close(fd); - } while (++remaining < argc); + ++i; + } 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..a073f32 100644 --- a/dwarves.c +++ b/dwarves.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -2568,9 +2567,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 +2578,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; } diff --git a/dwarves.h b/dwarves.h index 6b3c419..d414164 100644 --- a/dwarves.h +++ b/dwarves.h @@ -21,8 +21,6 @@ extern struct strings *strings; -struct argp; - struct cus { struct list_head cus; }; @@ -539,8 +537,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); diff --git a/pahole.c b/pahole.c index f2e911b..a0ef2a7 100644 --- a/pahole.c +++ b/pahole.c @@ -1044,7 +1044,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,7 +1052,13 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } - err = cus__loadfl(cus, &pahole__argp, argc, argv); + 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) return EXIT_FAILURE; diff --git a/pdwtags.c b/pdwtags.c index b23de30..5cfccdd 100644 --- a/pdwtags.c +++ b/pdwtags.c @@ -101,7 +101,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 +109,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..ea41854 100644 --- a/pfunct.c +++ b/pfunct.c @@ -491,7 +491,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 +499,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..07bb464 100644 --- a/pglobal.c +++ b/pglobal.c @@ -313,7 +313,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 +321,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..07cd6d1 100644 --- a/prefcnt.c +++ b/prefcnt.c @@ -157,7 +157,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/syscse.c b/syscse.c index 168e560..eadb8a9 100644 --- a/syscse.c +++ b/syscse.c @@ -144,7 +144,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 +152,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; From 698b8c136ad8468b86f7ca5df2e8bc185a19e7bd Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 10 Feb 2009 19:11:32 -0200 Subject: [PATCH 03/40] pahole: Tell the user if no debugging information was found Reported-by: Eric Paris Signed-off-by: Arnaldo Carvalho de Melo --- pahole.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pahole.c b/pahole.c index a0ef2a7..ba340cc 100644 --- a/pahole.c +++ b/pahole.c @@ -1059,8 +1059,10 @@ int main(int argc, char *argv[]) } err = cus__loadfl(cus, argv + remaining); - if (err != 0) + if (err != 0) { + fputs("pahole: No debugging information found\n", stderr); return EXIT_FAILURE; + } if (word_size != 0) cus__for_each_cu(cus, cu_fixup_word_size_iterator, NULL, NULL); From 7b6c135e7c415fe1c29c7a2bd26527722c6093ef Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Wed, 11 Feb 2009 12:19:46 -0200 Subject: [PATCH 04/40] pahole: finally the beginnings of a man page Signed-off-by: Arnaldo Carvalho de Melo --- CMakeLists.txt | 1 + MANIFEST | 6 ++ man-pages/pahole.1 | 181 +++++++++++++++++++++++++++++++++++++++++ rpm/SPECS/dwarves.spec | 3 +- 4 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 man-pages/pahole.1 diff --git a/CMakeLists.txt b/CMakeLists.txt index e05ea0d..6100f4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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/man-pages/pahole.1 b/man-pages/pahole.1 new file mode 100644 index 0000000..c0730ed --- /dev/null +++ b/man-pages/pahole.1 @@ -0,0 +1,181 @@ +.\" Man page for pahole +.\" Arnaldo Carvalho de Melo, 2009 +.\" Licensed under version 2 of the GNU General Public License. +.TH pahole 1 "February 10, 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. + +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 availabe 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 +supressed. + +.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 SEE ALSO +\fIeu-readelf\fR(1), \fIreadelf\fR(1), \fIobjdump\fR(1). +.SH AUTHOR +\fBpahole\fR was written by Arnaldo Carvalho de Melo . + +Please send bug reports to . +No\ subscription is required. diff --git a/rpm/SPECS/dwarves.spec b/rpm/SPECS/dwarves.spec index 28e1aa4..0161c39 100644 --- a/rpm/SPECS/dwarves.spec +++ b/rpm/SPECS/dwarves.spec @@ -2,7 +2,7 @@ %define libver 1 Name: dwarves -Version: 1.6 +Version: 1.6.1 Release: 1 License: GPLv2 Summary: Dwarf Tools @@ -85,6 +85,7 @@ rm -rf %{buildroot} %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 From 56be29c64940c6bb8248054bc69e4763b81b5be0 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 13 Feb 2009 10:57:23 -0200 Subject: [PATCH 05/40] all: Add the --version Using the argp tricks. Signed-off-by: Arnaldo Carvalho de Melo --- CMakeLists.txt | 2 +- codiff.c | 3 +++ ctracer.c | 3 +++ dutil.h | 11 +++++++++++ dwarves.c | 7 +++++++ dwarves.h | 4 ++++ pahole.c | 3 +++ pdwtags.c | 3 +++ pfunct.c | 3 +++ pglobal.c | 3 +++ prefcnt.c | 2 +- syscse.c | 3 +++ 12 files changed, 45 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6100f4a..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) diff --git a/codiff.c b/codiff.c index c38256e..5c7822c 100644 --- a/codiff.c +++ b/codiff.c @@ -624,6 +624,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', diff --git a/ctracer.c b/ctracer.c index 45118d9..b1145b6 100644 --- a/ctracer.c +++ b/ctracer.c @@ -821,6 +821,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', diff --git a/dutil.h b/dutil.h index d01a1ef..6bb5247 100644 --- a/dutil.h +++ b/dutil.h @@ -14,6 +14,17 @@ #define __unused __attribute__ ((unused)) #endif +/* 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/dwarves.c b/dwarves.c index a073f32..7b62ee4 100644 --- a/dwarves.c +++ b/dwarves.c @@ -2624,3 +2624,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 d414164..757f6ae 100644 --- a/dwarves.h +++ b/dwarves.h @@ -675,4 +675,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/pahole.c b/pahole.c index ba340cc..6218d2c 100644 --- a/pahole.c +++ b/pahole.c @@ -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", diff --git a/pdwtags.c b/pdwtags.c index 5cfccdd..bc041b5 100644 --- a/pdwtags.c +++ b/pdwtags.c @@ -66,6 +66,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', diff --git a/pfunct.c b/pfunct.c index ea41854..785d29e 100644 --- a/pfunct.c +++ b/pfunct.c @@ -351,6 +351,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', diff --git a/pglobal.c b/pglobal.c index 07bb464..8549a68 100644 --- a/pglobal.c +++ b/pglobal.c @@ -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', diff --git a/prefcnt.c b/prefcnt.c index 07cd6d1..909f6a7 100644 --- a/prefcnt.c +++ b/prefcnt.c @@ -147,7 +147,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(); diff --git a/syscse.c b/syscse.c index eadb8a9..18b880d 100644 --- a/syscse.c +++ b/syscse.c @@ -105,6 +105,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', From 2a5d435053153c177bb00cc3141d3598e534ca91 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 13 Feb 2009 11:35:24 -0200 Subject: [PATCH 06/40] man-pages: Add comments about CONFIG_DEBUG_INFO to pahole.1 Signed-off-by: Arnaldo Carvalho de Melo --- man-pages/pahole.1 | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/man-pages/pahole.1 b/man-pages/pahole.1 index c0730ed..832a481 100644 --- a/man-pages/pahole.1 +++ b/man-pages/pahole.1 @@ -1,7 +1,7 @@ .\" Man page for pahole .\" Arnaldo Carvalho de Melo, 2009 .\" Licensed under version 2 of the GNU General Public License. -.TH pahole 1 "February 10, 2009" "dwarves" "dwarves" +.TH pahole 1 "February 13, 2009" "dwarves" "dwarves" .\" .SH NAME pahole \- Shows and manipulates data structure layout. @@ -172,6 +172,18 @@ Include PREFIXed classes. .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 is 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). .SH AUTHOR From f9d24098fcb20ba2c3cbb2b354ac2c55a0304f25 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 13 Feb 2009 11:52:58 -0200 Subject: [PATCH 07/40] man-pages: Add URL for dwarves paper and info about where it is useful Signed-off-by: Arnaldo Carvalho de Melo --- man-pages/pahole.1 | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/man-pages/pahole.1 b/man-pages/pahole.1 index 832a481..cd56257 100644 --- a/man-pages/pahole.1 +++ b/man-pages/pahole.1 @@ -12,6 +12,11 @@ pahole \- Shows and manipulates data structure layout. 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. @@ -22,7 +27,7 @@ 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 availabe in a +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 @@ -109,7 +114,7 @@ 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 -supressed. +suppressed. .TP .B \-n, \-\-nr_members @@ -186,8 +191,11 @@ 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. From 3d2692a2b7e0e07f92344778ff91a9eebc4cf629 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 13 Feb 2009 11:53:28 -0200 Subject: [PATCH 08/40] rpm: 1.7 changelog Signed-off-by: Arnaldo Carvalho de Melo --- rpm/SPECS/dwarves.spec | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/rpm/SPECS/dwarves.spec b/rpm/SPECS/dwarves.spec index 0161c39..d9deba6 100644 --- a/rpm/SPECS/dwarves.spec +++ b/rpm/SPECS/dwarves.spec @@ -2,13 +2,13 @@ %define libver 1 Name: dwarves -Version: 1.6.1 +Version: 1.7 Release: 1 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) @@ -109,6 +109,21 @@ rm -rf %{buildroot} %{_libdir}/%{libname}_reorganize.so %changelog +* 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 From a20b498dcd4961a3029222c36ea26b72d82c74af Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 16 Feb 2009 11:04:10 -0300 Subject: [PATCH 09/40] rpm: Own %{_datadir}/dwarves/ Fixing #473645 Signed-off-by: Arnaldo Carvalho de Melo --- rpm/SPECS/dwarves.spec | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rpm/SPECS/dwarves.spec b/rpm/SPECS/dwarves.spec index d9deba6..086719d 100644 --- a/rpm/SPECS/dwarves.spec +++ b/rpm/SPECS/dwarves.spec @@ -3,7 +3,7 @@ Name: dwarves Version: 1.7 -Release: 1 +Release: 2 License: GPLv2 Summary: Dwarf Tools Group: Development/Tools @@ -82,6 +82,7 @@ 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) @@ -109,6 +110,9 @@ 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, From c3c942d730db4a25d0d51d22b975d13f95465f60 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Sun, 1 Mar 2009 20:02:14 -0300 Subject: [PATCH 10/40] ctf: Find out word size on the ELF header Signed-off-by: Arnaldo Carvalho de Melo --- ctf_loader.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/ctf_loader.c b/ctf_loader.c index 84c4bb1..4c5ba06 100644 --- a/ctf_loader.c +++ b/ctf_loader.c @@ -129,7 +129,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; @@ -162,6 +162,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; @@ -790,6 +796,7 @@ static void open_files(struct ctf_state *sp, const char *in_filename) int ctf__load(struct cus *self, char *filenames[]) { struct ctf_state state; + int wordsize; memset(&state, 0, sizeof(state)); @@ -806,10 +813,10 @@ int ctf__load(struct cus *self, char *filenames[]) 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"); From 659611ee2f319bb19950728d424782dfabf9f8b2 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 2 Mar 2009 12:22:37 -0300 Subject: [PATCH 11/40] dwarves: Implement cu__find_base_type_by_name_and_size Needed for CTF, where we can have many base types with name "unsigned", but with different bit sizes, to implement bitfields. Signed-off-by: Arnaldo Carvalho de Melo --- dwarves.c | 21 +++++++++++++++++++++ dwarves.h | 3 +++ 2 files changed, 24 insertions(+) diff --git a/dwarves.c b/dwarves.c index 7b62ee4..2466ee7 100644 --- a/dwarves.c +++ b/dwarves.c @@ -578,6 +578,27 @@ struct tag *cu__find_base_type_by_name(const struct cu *self, const char *name) return NULL; } +struct tag *cu__find_base_type_by_name_and_size(const struct cu *self, + const char *name, + size_t bit_size) +{ + struct tag *pos; + + if (self == NULL || name == NULL) + return NULL; + + list_for_each_entry(pos, &self->tags, node) + if (pos->tag == DW_TAG_base_type) { + const struct base_type *bt = tag__base_type(pos); + + if (bt->bit_size == bit_size && + bt->name && strcmp(s(bt->name), name) == 0) + return pos; + } + + return NULL; +} + struct tag *cu__find_struct_by_name(const struct cu *self, const char *name, const int include_decls) { diff --git a/dwarves.h b/dwarves.h index 757f6ae..cbd956d 100644 --- a/dwarves.h +++ b/dwarves.h @@ -548,6 +548,9 @@ 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); +struct tag *cu__find_base_type_by_name_and_size(const struct cu *self, + const char *name, + size_t bit_size); extern struct tag *cus__find_struct_by_name(const struct cus *self, struct cu **cu, const char *name, From 0e9e194cf04664232e459ba74075ef831169d1dc Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 2 Mar 2009 12:24:35 -0300 Subject: [PATCH 12/40] ctf_loader: Fix up bitfields The dwarves were implemented first for DWARF, so all the algorithms work with class_member ->bit_size, ->bit_offset and expect the ->offset field to be the same for all members of a bitfield, so fixup these fields after loading a CTF section. Signed-off-by: Arnaldo Carvalho de Melo --- ctf_loader.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 1 deletion(-) diff --git a/ctf_loader.c b/ctf_loader.c index 4c5ba06..5528cd9 100644 --- a/ctf_loader.c +++ b/ctf_loader.c @@ -793,6 +793,93 @@ static void open_files(struct ctf_state *sp, const char *in_filename) } } +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_tag_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; + + struct tag *fixed_tag; + fixed_tag = cu__find_base_type_by_name_and_size(cu, base_type__name(bt), + bit_size); + if (fixed_tag == NULL) { + fprintf(stderr, + "%s: BRAIN FART ALERT!: class: %s, member: %s\n", + __func__, type__name(type_self, cu), + 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; @@ -828,5 +915,5 @@ int ctf__load(struct cus *self, char *filenames[]) close(state.in_fd); - return 0; + return cus__fixup_ctf_bitfields(self); } From bff71347bcf208765e887add618c9c6d9b96c989 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 2 Mar 2009 16:06:15 -0300 Subject: [PATCH 13/40] ctf: No need to concat "char " if attrs & CTF_TYPE_INT_CHAR is true As most of the types comes with it already. Perhaps this was an oversight and we will have to look if the name already has "char", concat'ing only if it doesn't. We'll see... Signed-off-by: Arnaldo Carvalho de Melo --- ctf_loader.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/ctf_loader.c b/ctf_loader.c index 5528cd9..30916c3 100644 --- a/ctf_loader.c +++ b/ctf_loader.c @@ -381,8 +381,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) From bf14e0d2203596c08f240ea1cb68479b2205b399 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 2 Mar 2009 16:07:43 -0300 Subject: [PATCH 14/40] reorganize: cu__find_base_type_of_size should look for alternative CTF base type names Unfortunately the most common DWARF and CTF encoders don't agree on how the names of base types are formed, so look for an alternative name. Signed-off-by: Arnaldo Carvalho de Melo --- dwarves_reorganize.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/dwarves_reorganize.c b/dwarves_reorganize.c index 8d4f6e6..29d6053 100644 --- a/dwarves_reorganize.c +++ b/dwarves_reorganize.c @@ -469,26 +469,32 @@ 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 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); + return ret ?: cu__find_base_type_by_name(cu, type_name_alt); } static int class__demote_bitfields(struct class *class, const struct cu *cu, From 415b9d1e2875494c8ac7f18b1910ff14b54dc694 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 3 Mar 2009 09:38:27 -0300 Subject: [PATCH 15/40] dwarves: Introduce tag__has_namespace This open coded sequence appears two times already, with more to come. Signed-off-by: Arnaldo Carvalho de Melo --- dwarves.c | 11 ++--------- dwarves.h | 8 ++++++++ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/dwarves.c b/dwarves.c index 2466ee7..5ab9f2a 100644 --- a/dwarves.c +++ b/dwarves.c @@ -226,10 +226,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); } @@ -482,12 +479,8 @@ 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)); - } } free(self); } diff --git a/dwarves.h b/dwarves.h index cbd956d..11a632c 100644 --- a/dwarves.h +++ b/dwarves.h @@ -92,6 +92,14 @@ 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); +} + static inline int tag__is_type(const struct tag *self) { return tag__is_union(self) || From 585075767171d52240457eaed58e3d1eb4823f7d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 3 Mar 2009 10:31:14 -0300 Subject: [PATCH 16/40] codiff: improve detection removal and addition of members in structs Consider this case: $ codiff -V /tmp/pahole.old build/pahole /home/acme/git/pahole/pahole.c: struct tag | +0 refcnt removed: uint16_t /* 56( 0) 2( 0) */ recursivity_level from: uint16_t /* 58( 0) 2( 0) */ to: uint16_t /* 56( 0) 2(15) */ used added: uint16_t /* 56(15) 2( 1) */ 1 struct changed The number of members is the same and so is the size of the struct, but 'refcnt' was removed (in fact renamed to used) and 'used' was added. Signed-off-by: Arnaldo Carvalho de Melo --- codiff.c | 49 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/codiff.c b/codiff.c index 5c7822c..56db17d 100644 --- a/codiff.c +++ b/codiff.c @@ -163,8 +163,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 +182,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.refcnt = 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_tag_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.refcnt) { + char name[128]; + struct tag *type; + type = cu__find_tag_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; } From dc5592b84424025171bf6b12d4660de5cfef76a3 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 3 Mar 2009 10:55:25 -0300 Subject: [PATCH 17/40] codiff: Detect changes in padding and the number of holes/bit_holes $ codiff -V /tmp/pahole.old build/pahole /home/acme/git/pahole/pahole.c: struct tag | +0 padding: +2 refcnt removed: uint16_t /* 56( 0) 2( 0) */ recursivity_level from: uint16_t /* 58( 0) 2( 0) */ to: uint16_t /* 56( 0) 2(15) */ visited added: uint16_t /* 56(15) 2( 1) */ 1 struct changed Size is the same, but now we have padding (2 bytes). Signed-off-by: Arnaldo Carvalho de Melo --- codiff.c | 47 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/codiff.c b/codiff.c index 56db17d..613fd69 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; @@ -256,10 +259,16 @@ static void diff_struct(const struct cu *new_cu, struct class *structure, assert(class__is_struct(new_structure)); + class__find_holes(structure, cu); + class__find_holes(new_structure, new_cu); 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; @@ -498,8 +507,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'); } @@ -556,9 +577,29 @@ 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); } From f169bac1cf94e27d2eda155ed774c7e5b8a81b7f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 3 Mar 2009 10:56:37 -0300 Subject: [PATCH 18/40] dwarves: rename tag->refcnt to tag->visited and shrink it to 1 bit As in fact it is used as a boolean in prefcnt and codiff. $ codiff -V /tmp/pahole.old build/pahole /home/acme/git/pahole/pahole.c: struct tag | +0 padding: +2 refcnt removed: uint16_t /* 56( 0) 2( 0) */ recursivity_level from: uint16_t /* 58( 0) 2( 0) */ to: uint16_t /* 56( 0) 2(15) */ visited added: uint16_t /* 56(15) 2( 1) */ 1 struct changed Signed-off-by: Arnaldo Carvalho de Melo --- codiff.c | 4 ++-- dwarves.h | 4 ++-- prefcnt.c | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/codiff.c b/codiff.c index 613fd69..4de168b 100644 --- a/codiff.c +++ b/codiff.c @@ -192,7 +192,7 @@ static int check_print_members_changes(const struct class *structure, struct class_member *twin = class__find_member_by_name(new_structure, member_name); if (twin != NULL) { - twin->tag.refcnt = 1; + twin->tag.visited = 1; ++nr_twins_found; if (check_print_change(member, cu, twin, new_cu, print)) changes = 1; @@ -220,7 +220,7 @@ static int check_print_members_changes(const struct class *structure, goto out; type__for_each_member(&new_structure->type, member) { - if (!member->tag.refcnt) { + if (!member->tag.visited) { char name[128]; struct tag *type; type = cu__find_tag_by_id(new_cu, member->tag.type); diff --git a/dwarves.h b/dwarves.h index 11a632c..6494913 100644 --- a/dwarves.h +++ b/dwarves.h @@ -62,8 +62,8 @@ struct tag { strings_t decl_file; uint16_t decl_line; uint16_t tag; - uint16_t refcnt; - uint16_t recursivity_level; + uint16_t visited:1; + uint16_t recursivity_level:15; }; static inline int tag__is_enumeration(const struct tag *self) diff --git a/prefcnt.c b/prefcnt.c index 909f6a7..ec8ee51 100644 --- a/prefcnt.c +++ b/prefcnt.c @@ -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,7 +93,7 @@ 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 = @@ -135,7 +135,7 @@ static int cu_refcnt_iterator(struct cu *cu, void *cookie) static int lost_iterator(struct tag *tag, struct cu *cu, void *cookie __unused) { - if (tag->refcnt == 0 && tag->decl_file) { + if (!tag->visited && tag->decl_file) { tag__fprintf(tag, cu, NULL, stdout); puts(";\n"); } From d2d07eab08b274e165bfebe21cd70c3a2cf8103c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 3 Mar 2009 13:18:51 -0300 Subject: [PATCH 19/40] dwarves: Introduce tag__is_tag_type And comment the difference to tag__is_type: tag__is_type == is this tag derived from the 'type' class? tag__is_tag_type == is this tag a possible type for a tag, i.e. one we will find in struct tag->type? Signed-off-by: Arnaldo Carvalho de Melo --- dwarves.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/dwarves.h b/dwarves.h index 6494913..35c26b7 100644 --- a/dwarves.h +++ b/dwarves.h @@ -100,6 +100,10 @@ static inline bool tag__has_namespace(const struct tag *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) || @@ -107,6 +111,22 @@ static inline int tag__is_type(const struct tag *self) tag__is_typedef(self) || tag__is_enumeration(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 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_subroutine_type || + self->tag == DW_TAG_volatile_type; +} static inline const char *tag__decl_file(const struct tag *self) { From e710cca6bf6ec20258bcc0160ad2f34bbaa71c77 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 3 Mar 2009 13:37:57 -0300 Subject: [PATCH 20/40] dwarves: Introduce cu__hash So that we can then decide in what hashtable we will add it, and this also paves the way for a type array that will help us in reducing the size of struct tag by removing the id field. Signed-off-by: Arnaldo Carvalho de Melo --- ctf_loader.c | 6 +++--- dwarf_loader.c | 8 ++++---- dwarves.c | 12 ++++++++++-- dwarves.h | 10 ++++------ 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/ctf_loader.c b/ctf_loader.c index 30916c3..6cbbd1d 100644 --- a/ctf_loader.c +++ b/ctf_loader.c @@ -516,7 +516,7 @@ 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); + cu__hash(sp->cu, &member->tag); } return sizeof(*mp); @@ -543,7 +543,7 @@ 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); + cu__hash(sp->cu, &member->tag); } return sizeof(*mp); @@ -624,7 +624,7 @@ 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__hash(sp->cu, &enumerator->tag); } cu__add_tag(sp->cu, &enumeration->namespace.tag); diff --git a/dwarf_loader.c b/dwarf_loader.c index 94e1637..d21912b 100644 --- a/dwarf_loader.c +++ b/dwarf_loader.c @@ -788,7 +788,7 @@ 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); + cu__hash(cu, &enumerator->tag); } while (dwarf_siblingof(die, die) == 0); return &enumeration->namespace.tag; @@ -807,7 +807,7 @@ 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: { @@ -815,7 +815,7 @@ static void die__process_class(Dwarf_Die *die, struct type *class, if (tag != NULL) { namespace__add_tag(&class->namespace, tag); - hashtags__hash(cu->hash_tags, tag); + cu__hash(cu, tag); if (tag->tag == DW_TAG_subprogram) { struct function *fself = tag__function(tag); @@ -837,7 +837,7 @@ static void die__process_namespace(Dwarf_Die *die, if (tag != NULL) { namespace__add_tag(namespace, tag); - hashtags__hash(cu->hash_tags, tag); + cu__hash(cu, tag); } } while (dwarf_siblingof(die, die) == 0); } diff --git a/dwarves.c b/dwarves.c index 5ab9f2a..692fbcf 100644 --- a/dwarves.c +++ b/dwarves.c @@ -25,11 +25,14 @@ #include "config.h" #include "ctf_loader.h" #include "dwarf_loader.h" +#include "hash.h" #include "list.h" #include "dwarves.h" #include "dutil.h" #include "strings.h" +#define hashtags__fn(key) hash_64(key, HASHTAGS__BITS) + struct strings *strings; static inline const char *s(strings_t i) @@ -485,17 +488,22 @@ void cu__delete(struct cu *self) free(self); } -void hashtags__hash(struct list_head *hashtable, struct tag *tag) +static 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__hash(struct cu *self, struct tag *tag) +{ + hashtags__hash(self->hash_tags, tag); +} + void cu__add_tag(struct cu *self, struct tag *tag) { list_add_tail(&tag->node, &self->tags); - hashtags__hash(self->hash_tags, tag); + cu__hash(self, tag); } bool cu__same_build_id(const struct cu *self, const struct cu *other) diff --git a/dwarves.h b/dwarves.h index 35c26b7..977918e 100644 --- a/dwarves.h +++ b/dwarves.h @@ -16,7 +16,6 @@ #include #include "list.h" -#include "hash.h" #include "strings.h" extern struct strings *strings; @@ -29,11 +28,6 @@ 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 tag; - -void hashtags__hash(struct list_head *hashtable, struct tag *tag); struct cu { struct list_head node; @@ -54,6 +48,10 @@ struct cu { unsigned char build_id[0]; }; +struct tag; + +void cu__hash(struct cu *cu, struct tag *tag); + struct tag { struct list_head node; struct list_head hash_node; From 72eba672148dee24e5a1ca5067ee1c1dc73eac9a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 3 Mar 2009 13:48:07 -0300 Subject: [PATCH 21/40] dwarves: Move hashtags__find out of cu__find_tag_by_id Will be used by cu__find_type_by_id too. Signed-off-by: Arnaldo Carvalho de Melo --- dwarves.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/dwarves.c b/dwarves.c index 692fbcf..0e554d4 100644 --- a/dwarves.c +++ b/dwarves.c @@ -495,6 +495,24 @@ static void hashtags__hash(struct list_head *hashtable, struct tag *tag) list_add_tail(&tag->hash_node, head); } +static struct tag *hashtags__find(const struct list_head *hashtable, + const Dwarf_Off id) +{ + struct tag *pos; + const struct list_head *head; + + if (id == 0) + return NULL; + + head = hashtable + hashtags__fn(id); + + list_for_each_entry(pos, head, hash_node) + if (pos->id == id) + return pos; + + return NULL; +} + void cu__hash(struct cu *self, struct tag *tag) { hashtags__hash(self->hash_tags, tag); @@ -531,19 +549,7 @@ static const char *tag__prefix(const struct cu *cu, const uint32_t tag) struct tag *cu__find_tag_by_id(const struct cu *self, const Dwarf_Off id) { - struct tag *pos; - const struct list_head *head; - - 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; + return self ? hashtags__find(self->hash_tags, id) : NULL; } struct tag *cu__find_first_typedef_of_type(const struct cu *self, From 68acff0719e24c2966d45714211e05533d082abc Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 3 Mar 2009 14:56:38 -0300 Subject: [PATCH 22/40] dwarves: Add DW_TAG_reference_type to tag__is_tag_type Signed-off-by: Arnaldo Carvalho de Melo --- dwarves.h | 1 + 1 file changed, 1 insertion(+) diff --git a/dwarves.h b/dwarves.h index 977918e..3ebbf23 100644 --- a/dwarves.h +++ b/dwarves.h @@ -122,6 +122,7 @@ static inline int tag__is_tag_type(const struct tag *self) self->tag == DW_TAG_base_type || self->tag == DW_TAG_const_type || self->tag == DW_TAG_pointer_type || + self->tag == DW_TAG_reference_type || self->tag == DW_TAG_subroutine_type || self->tag == DW_TAG_volatile_type; } From 3f4e4457e26f5bf31abb6d5c420bbd6be0b8de79 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 3 Mar 2009 15:12:29 -0300 Subject: [PATCH 23/40] dwarves: Add DW_TAG_ptr_to_member_type to tag__is_tag_type Signed-off-by: Arnaldo Carvalho de Melo --- codiff.c | 10 +++---- ctf_loader.c | 2 +- ctracer.c | 12 ++++---- dwarves.c | 69 ++++++++++++++++++++++++++------------------ dwarves.h | 1 + dwarves_emit.c | 8 ++--- dwarves_reorganize.c | 4 +-- pahole.c | 12 ++++---- pfunct.c | 4 +-- prefcnt.c | 8 ++--- syscse.c | 2 +- 11 files changed, 73 insertions(+), 59 deletions(-) diff --git a/codiff.c b/codiff.c index 4de168b..99d7a45 100644 --- a/codiff.c +++ b/codiff.c @@ -129,8 +129,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) @@ -201,7 +201,7 @@ static int check_print_members_changes(const struct class *structure, if (print) { char name[128]; struct tag *type; - type = cu__find_tag_by_id(cu, member->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), @@ -223,7 +223,7 @@ static int check_print_members_changes(const struct class *structure, if (!member->tag.visited) { char name[128]; struct tag *type; - type = cu__find_tag_by_id(new_cu, member->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), @@ -444,7 +444,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); diff --git a/ctf_loader.c b/ctf_loader.c index 6cbbd1d..b035989 100644 --- a/ctf_loader.c +++ b/ctf_loader.c @@ -808,7 +808,7 @@ static int class__fixup_ctf_bitfields(struct tag *self, struct cu *cu) long last_offset = -1; type__for_each_data_member(type_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->tag != DW_TAG_base_type) continue; diff --git a/ctracer.c b/ctracer.c index b1145b6..8c86a3f 100644 --- a/ctracer.c +++ b/ctracer.c @@ -341,7 +341,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; @@ -365,7 +365,7 @@ static struct class *class__clone_base_types(const struct tag *tag_self, 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)) { @@ -508,7 +508,7 @@ static struct tag *pointer_filter(struct tag *tag, struct cu *cu, void *target_t 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) @@ -708,13 +708,13 @@ 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); + type = cu__find_type_by_id(cu, type->type); if (type == NULL || type->id != target->id) continue; @@ -780,7 +780,7 @@ static int cu_emit_pointer_probes_iterator(struct cu *cu, void *cookie) /* 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) diff --git a/dwarves.c b/dwarves.c index 0e554d4..b5714f7 100644 --- a/dwarves.c +++ b/dwarves.c @@ -133,7 +133,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); @@ -208,7 +208,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; @@ -244,7 +244,7 @@ const char *type__name(struct type *self, const struct cu *cu) /* 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); + struct tag *tag = cu__find_type_by_id(cu, self->specification); if (tag == NULL) { tag__id_not_found_fprintf(stderr, self->specification); return NULL; @@ -264,7 +264,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; @@ -295,7 +295,7 @@ reevaluate: case DW_TAG_volatile_type: { const struct tag *tag = type; - type = cu__find_tag_by_id(cu, type->id); + type = cu__find_type_by_id(cu, type->id); if (type == NULL) { tag__id_not_found_fprintf(stderr, tag->id); continue; @@ -341,7 +341,7 @@ size_t typedef__fprintf(const struct tag *tag_self, const struct cu *cu, if (tag_self->type == 0) return fprintf(fp, "typedef void %s", type__name(self, cu)); - 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); @@ -357,7 +357,7 @@ size_t typedef__fprintf(const struct tag *tag_self, const struct cu *cu, 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); @@ -450,8 +450,10 @@ struct cu *cu__new(const char *name, uint8_t addr_size, if (self != NULL) { uint32_t i; - for (i = 0; i < HASHTAGS__SIZE; ++i) + for (i = 0; i < HASHTAGS__SIZE; ++i) { INIT_LIST_HEAD(&self->hash_tags[i]); + INIT_LIST_HEAD(&self->hash_types[i]); + } INIT_LIST_HEAD(&self->tags); INIT_LIST_HEAD(&self->tool_list); @@ -515,7 +517,10 @@ static struct tag *hashtags__find(const struct list_head *hashtable, void cu__hash(struct cu *self, struct tag *tag) { - hashtags__hash(self->hash_tags, tag); + struct list_head *hashtable = tag__is_tag_type(tag) ? + self->hash_types : + self->hash_tags; + hashtags__hash(hashtable, tag); } void cu__add_tag(struct cu *self, struct tag *tag) @@ -552,6 +557,11 @@ struct tag *cu__find_tag_by_id(const struct cu *self, const Dwarf_Off id) return self ? hashtags__find(self->hash_tags, id) : NULL; } +struct tag *cu__find_type_by_id(const struct cu *self, const Dwarf_Off id) +{ + return self ? hashtags__find(self->hash_types, id) : NULL; +} + struct tag *cu__find_first_typedef_of_type(const struct cu *self, const Dwarf_Off type) { @@ -677,7 +687,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) @@ -842,7 +855,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); @@ -863,7 +876,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, @@ -909,7 +922,7 @@ 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)); @@ -924,7 +937,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 { @@ -936,7 +949,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 @@ -967,7 +980,7 @@ static struct tag *variable__type(const struct variable *self, struct variable *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); if (var) @@ -1037,7 +1050,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; @@ -1104,7 +1117,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; @@ -1143,7 +1156,7 @@ static size_t type__fprintf(struct tag *type, const struct cu *cu, type__name(ctype, cu)); 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; } @@ -1164,7 +1177,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) { @@ -1357,7 +1370,7 @@ static size_t union__fprintf(struct type *self, const struct cu *cu, 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); @@ -1505,10 +1518,10 @@ int ftype__has_parm_of_type(const struct ftype *self, const struct tag *target, ftype__for_each_parameter(self, pos) { struct tag *type = - cu__find_tag_by_id(cu, parameter__type(pos, cu)); + cu__find_type_by_id(cu, parameter__type(pos, cu)); if (type != NULL && type->tag == DW_TAG_pointer_type) { - type = cu__find_tag_by_id(cu, type->type); + type = cu__find_type_by_id(cu, type->type); if (type != NULL && type->id == target->id) return 1; } @@ -1763,7 +1776,7 @@ static size_t ftype__fprintf_parms(const struct ftype *self, } else first_parm = 0; name = parameter__name(pos, cu); - type = cu__find_tag_by_id(cu, parameter__type(pos, cu)); + type = cu__find_type_by_id(cu, parameter__type(pos, cu)); if (type == NULL) { stype = ""; goto print_it; @@ -1771,7 +1784,7 @@ static size_t ftype__fprintf_parms(const struct ftype *self, 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); @@ -1918,7 +1931,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", @@ -2086,7 +2099,7 @@ 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)); else @@ -2180,7 +2193,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); diff --git a/dwarves.h b/dwarves.h index 3ebbf23..599988a 100644 --- a/dwarves.h +++ b/dwarves.h @@ -122,6 +122,7 @@ static inline int tag__is_tag_type(const struct tag *self) 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; diff --git a/dwarves_emit.c b/dwarves_emit.c index ad3face..bf8c5e7 100644 --- a/dwarves_emit.c +++ b/dwarves_emit.c @@ -120,7 +120,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 +131,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; @@ -215,7 +215,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,7 +229,7 @@ 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; diff --git a/dwarves_reorganize.c b/dwarves_reorganize.c index 29d6053..c332f90 100644 --- a/dwarves_reorganize.c +++ b/dwarves_reorganize.c @@ -543,7 +543,7 @@ 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); + old_type_tag = cu__find_type_by_id(cu, member->tag.type); new_type_tag = cu__find_base_type_of_size(cu, bytes_needed); if (new_type_tag == NULL) { @@ -592,7 +592,7 @@ 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); new_type_tag = cu__find_base_type_of_size(cu, bytes_needed); diff --git a/pahole.c b/pahole.c index 6218d2c..f5f2786 100644 --- a/pahole.c +++ b/pahole.c @@ -525,14 +525,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); } @@ -606,7 +606,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); @@ -695,12 +695,12 @@ static int nr_methods_iterator(struct tag *tag, struct cu *cu, list_for_each_entry(pos, &tag__ftype(tag)->parms, tag.node) { struct tag *type = - cu__find_tag_by_id(cu, parameter__type(pos, cu)); + cu__find_type_by_id(cu, parameter__type(pos, cu)); 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; @@ -747,7 +747,7 @@ static void print_structs_with_pointer_to(const struct structure *s) } 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) diff --git a/pfunct.c b/pfunct.c index 785d29e..b2431df 100644 --- a/pfunct.c +++ b/pfunct.c @@ -306,13 +306,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, parameter__type(pos, cu)); 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; } diff --git a/prefcnt.c b/prefcnt.c index ec8ee51..ed2e774 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); } @@ -97,7 +97,7 @@ static void refcnt_function(struct function *function, const struct cu *cu) 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); } diff --git a/syscse.c b/syscse.c index 18b880d..c0ea2e2 100644 --- a/syscse.c +++ b/syscse.c @@ -69,7 +69,7 @@ static int emit_wrapper(struct tag *self, struct cu *cu, void *cookie __unused) 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); + struct tag *type = cu__find_type_by_id(cu, type_id); tag__assert_search_result(type); if (type->tag == DW_TAG_base_type) { From 93ae61a79beddab4cb555ff5b3c6c232e32b73f0 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 3 Mar 2009 15:29:06 -0300 Subject: [PATCH 24/40] dwarves: Add missing bits of separate hash table for types Grrr, the previous commit has the other bits, and as I already pushed it out publicly... here goes the rests. So much for bissectability. Sigh. But the regression test showed only one problem, in C++ code, that I'll fix in the next commits. Signed-off-by: Arnaldo Carvalho de Melo --- dwarves.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dwarves.h b/dwarves.h index 599988a..a1c988a 100644 --- a/dwarves.h +++ b/dwarves.h @@ -33,6 +33,7 @@ struct cu { struct list_head node; struct list_head tags; struct list_head hash_tags[HASHTAGS__SIZE]; + struct list_head hash_types[HASHTAGS__SIZE]; struct list_head tool_list; /* To be used by tools such as ctracer */ const char *name; uint8_t addr_size; @@ -596,6 +597,7 @@ extern void cu__delete(struct cu *self); void cu__add_tag(struct cu *self, struct tag *tag); extern struct tag *cu__find_tag_by_id(const struct cu *self, const Dwarf_Off id); +struct tag *cu__find_type_by_id(const struct cu *self, const Dwarf_Off id); 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, From bcb2e11dcf69ca3b1323a9e8ed839ee9f7463dbf Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 3 Mar 2009 15:32:47 -0300 Subject: [PATCH 25/40] man-pages: Fixup typo Signed-off-by: Arnaldo Carvalho de Melo --- man-pages/pahole.1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man-pages/pahole.1 b/man-pages/pahole.1 index cd56257..b2c1f00 100644 --- a/man-pages/pahole.1 +++ b/man-pages/pahole.1 @@ -180,7 +180,7 @@ 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 is can be done using make menuconfig by +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". From 913aee45fc0989fcca351a5d6ab2a8095ed5c585 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 3 Mar 2009 22:24:05 -0300 Subject: [PATCH 26/40] dwarves: Use hlist for the hashtables Reducing the struct cu footprint by 4 Kb. Signed-off-by: Arnaldo Carvalho de Melo --- dwarf_loader.c | 2 +- dwarves.c | 25 +++++++++++++------------ dwarves.h | 6 +++--- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/dwarf_loader.c b/dwarf_loader.c index d21912b..3f7e2e6 100644 --- a/dwarf_loader.c +++ b/dwarf_loader.c @@ -192,7 +192,7 @@ static void tag__init(struct tag *self, Dwarf_Die *die) dwarf_decl_line(die, &decl_line); self->decl_line = decl_line; self->recursivity_level = 0; - INIT_LIST_HEAD(&self->hash_node); + INIT_HLIST_NODE(&self->hash_node); } static struct tag *tag__new(Dwarf_Die *die) diff --git a/dwarves.c b/dwarves.c index b5714f7..177d665 100644 --- a/dwarves.c +++ b/dwarves.c @@ -451,8 +451,8 @@ struct cu *cu__new(const char *name, uint8_t addr_size, uint32_t i; for (i = 0; i < HASHTAGS__SIZE; ++i) { - INIT_LIST_HEAD(&self->hash_tags[i]); - INIT_LIST_HEAD(&self->hash_types[i]); + INIT_HLIST_HEAD(&self->hash_tags[i]); + INIT_HLIST_HEAD(&self->hash_types[i]); } INIT_LIST_HEAD(&self->tags); @@ -490,34 +490,35 @@ void cu__delete(struct cu *self) free(self); } -static void hashtags__hash(struct list_head *hashtable, struct tag *tag) +static void hashtags__hash(struct hlist_head *hashtable, struct tag *tag) { - struct list_head *head = hashtable + hashtags__fn(tag->id); + struct hlist_head *head = hashtable + hashtags__fn(tag->id); - list_add_tail(&tag->hash_node, head); + hlist_add_head(&tag->hash_node, head); } -static struct tag *hashtags__find(const struct list_head *hashtable, +static struct tag *hashtags__find(const struct hlist_head *hashtable, const Dwarf_Off id) { - struct tag *pos; - const struct list_head *head; + struct tag *tpos; + struct hlist_node *pos; + const struct hlist_head *head; if (id == 0) return NULL; head = hashtable + hashtags__fn(id); - list_for_each_entry(pos, head, hash_node) - if (pos->id == id) - return pos; + hlist_for_each_entry(tpos, pos, head, hash_node) + if (tpos->id == id) + return tpos; return NULL; } void cu__hash(struct cu *self, struct tag *tag) { - struct list_head *hashtable = tag__is_tag_type(tag) ? + struct hlist_head *hashtable = tag__is_tag_type(tag) ? self->hash_types : self->hash_tags; hashtags__hash(hashtable, tag); diff --git a/dwarves.h b/dwarves.h index a1c988a..7fa326e 100644 --- a/dwarves.h +++ b/dwarves.h @@ -32,8 +32,8 @@ struct cus *cus__new(void); struct cu { struct list_head node; struct list_head tags; - struct list_head hash_tags[HASHTAGS__SIZE]; - struct list_head hash_types[HASHTAGS__SIZE]; + struct hlist_head hash_tags[HASHTAGS__SIZE]; + struct hlist_head hash_types[HASHTAGS__SIZE]; struct list_head tool_list; /* To be used by tools such as ctracer */ const char *name; uint8_t addr_size; @@ -55,7 +55,7 @@ void cu__hash(struct cu *cu, struct tag *tag); struct tag { struct list_head node; - struct list_head hash_node; + struct hlist_node hash_node; Dwarf_Off type; Dwarf_Off id; strings_t decl_file; From 005408d72510dd562f0352145c0c727279b98a9e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 3 Mar 2009 23:16:28 -0300 Subject: [PATCH 27/40] dwarf_loader: Optimize tag__init a bit By avoiding tsearch calls, checking if the decl_file for the current tag is the same for the last one, which is likely. Signed-off-by: Arnaldo Carvalho de Melo --- dwarf_loader.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/dwarf_loader.c b/dwarf_loader.c index 3f7e2e6..da92e0b 100644 --- a/dwarf_loader.c +++ b/dwarf_loader.c @@ -178,6 +178,9 @@ static int attr_location(Dwarf_Die *die, Dwarf_Op **expr, size_t *exprlen) static void tag__init(struct tag *self, Dwarf_Die *die) { 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); @@ -188,7 +191,12 @@ static void tag__init(struct tag *self, Dwarf_Die *die) else self->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; + } + + self->decl_file = last_decl_file_idx; dwarf_decl_line(die, &decl_line); self->decl_line = decl_line; self->recursivity_level = 0; From f2a3b9afbc412c144bdce41f37c8c2a00c03c0c0 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 5 Mar 2009 13:49:30 -0300 Subject: [PATCH 28/40] dwarves: Print arrays in tag__fprintf too Signed-off-by: Arnaldo Carvalho de Melo --- dwarves.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dwarves.c b/dwarves.c index 177d665..8c13610 100644 --- a/dwarves.c +++ b/dwarves.c @@ -2457,6 +2457,9 @@ size_t tag__fprintf(struct tag *self, const struct cu *cu, 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); break; From d0404199775d59bdbc1abc5ba79a4df6d9f674c1 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 5 Mar 2009 16:46:14 -0300 Subject: [PATCH 29/40] dwarf_loader: Accept empty enums, seen in the wild Signed-off-by: Arnaldo Carvalho de Melo --- dwarf_loader.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dwarf_loader.c b/dwarf_loader.c index da92e0b..8a63da0 100644 --- a/dwarf_loader.c +++ b/dwarf_loader.c @@ -778,9 +778,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; @@ -798,7 +798,7 @@ static struct tag *die__create_new_enumeration(Dwarf_Die *die, struct cu *cu) enumeration__add(enumeration, enumerator); cu__hash(cu, &enumerator->tag); } while (dwarf_siblingof(die, die) == 0); - +out: return &enumeration->namespace.tag; } From 2118fae5b085d92b0c7e2c0f6c21f86c1db91689 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 5 Mar 2009 18:21:06 -0300 Subject: [PATCH 30/40] dwarf_loader: DW_TAG_label can have DW_AT_abstract_origin Do nothing for now, just to reduce the size of the upcoming type recoding patch, aka dwarves undwarvification. Signed-off-by: Arnaldo Carvalho de Melo --- dwarf_loader.c | 1 + dwarves.h | 1 + 2 files changed, 2 insertions(+) diff --git a/dwarf_loader.c b/dwarf_loader.c index 8a63da0..1410346 100644 --- a/dwarf_loader.c +++ b/dwarf_loader.c @@ -420,6 +420,7 @@ static struct label *label__new(Dwarf_Die *die) 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; } diff --git a/dwarves.h b/dwarves.h index 7fa326e..5b5405f 100644 --- a/dwarves.h +++ b/dwarves.h @@ -505,6 +505,7 @@ struct label { struct tag tag; strings_t name; Dwarf_Addr low_pc; + Dwarf_Off abstract_origin; }; struct enumerator { From c178f4698d467164e9dc37e6c3262ef6295d6be0 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 5 Mar 2009 20:29:35 -0300 Subject: [PATCH 31/40] dwarves: Remove some more DWARF details from the core Had to be a big sweeping change, but the regression tests shows just improvements :-) Now we stop using an id in struct tag, only storing the type, that now uses 16 bits only, as CTF does. Each format loader has to go on adding the types to the core, that figures out if it is a tag that can be on the tag->type field (tag__is_tag_type). Formats that already have the types separated and in sequence, such as CTF, just ask the core to insert in the types_table directly with its original ID. For DWARF, we ask the core to put it on the table, in sequence, and return the index, that is then stashed with the DWARF specific info (original id, type, decl_line, etc) and hashed by the original id. Later we recode everything, looking up via the original type, getting the small_id to put on the tag->type. The underlying debugging info not needed by the core is stashed in tag->priv, and the DWARF loader now just allocates sizeof(struct dwarf_tag) at the end of the core tag and points it there, and makes that info available thru cu->orig_info. In the future we can ask, when loading a cu, that this info be trown away, so that we reduce the memory footprint for big multi-cu files such as the Linux kernel. There is also a routine to ask for inserting a NULL, as we still have bugs in the CTF decoding and thus some entries are being lost, to avoid using an undefined pointer when traversing the types_table the ctf loader puts a NULL there via cu__table_nullify_type_entry() and then cu__for_each_type skips those. There is some more cleanups for leftovers that I avoided cleaning to reduce this changeset. And also while doing this I saw that enums can appear without any enumerators and that an array with DW_TAG_GNU_vector is actually a different tag, encoded this way till we get to DWARF4 ;-) So now we don't have to lookup on a hash table looking for DWARF offsets, we can do the more sensible thing of just indexing the types_tags array. Now to do some cleanups and try to get the per cu encoder done. Then order all the cus per number of type entries, pick the one with more, then go on merging/recoding the types of the others and putting the parent linkage in place. Just to show the extent of the changes: $ codiff /tmp/libdwarves.so.1.0.0 build/libdwarves.so.1.0.0 /home/acme/git/pahole/dwarves.c: struct cu | -4048 struct tag | -32 struct ptr_to_member_type | -32 struct namespace | -32 struct type | -32 struct class | -32 struct base_type | -32 struct array_type | -32 struct class_member | -32 struct lexblock | -32 struct ftype | -32 struct function | -64 struct parameter | -32 struct variable | -32 struct inline_expansion | -32 struct label | -32 struct enumerator | -32 17 structs changed tag__follow_typedef | +3 tag__fprintf_decl_info | +25 array_type__fprintf | +6 type__name | -126 type__find_first_biggest_size_base_type_member | -3 typedef__fprintf | +16 imported_declaration__fprintf | +6 imported_module__fprintf | +3 cu__new | +26 cu__delete | +26 hashtags__hash | -65 hash_64 | -124 hlist_add_head | -78 hashtags__find | -157 cu__hash | -80 cu__add_tag | +20 tag__prefix | -3 cu__find_tag_by_id | -2 cu__find_type_by_id | -3 cu__find_first_typedef_of_type | +38 cu__find_base_type_by_name | +68 cu__find_base_type_by_name_and_size | +72 cu__find_struct_by_name | +59 cus__find_struct_by_name | +8 cus__find_tag_by_id | +5 cus__find_cu_by_name | -6 lexblock__find_tag_by_id | -173 cu__find_variable_by_id | -197 list__find_tag_by_id | -308 cu__find_parameter_by_id | -60 tag__ptr_name | +6 tag__name | +15 variable__type | +13 variable__name | +7 class_member__size | +6 parameter__name | -119 tag__parameter | -14 parameter__type | -143 type__fprintf | -29 union__fprintf | +6 class__add_vtable_entry | -9 type__add_member | -6 type__clone_members | -3 enumeration__add | -6 function__name | -156 ftype__has_parm_of_type | -39 class__find_holes | -27 class__has_hole_ge | -3 type__nr_members_of_type | +3 lexblock__account_inline_expansions | +3 cu__account_inline_expansions | -18 ftype__fprintf_parms | +46 function__tag_fprintf | +24 lexblock__fprintf | -6 ftype__fprintf | +3 function__fprintf_stats | -18 function__size | -6 class__vtable_fprintf | -11 class__fprintf | -21 tag__fprintf | -35 60 functions changed, 513 bytes added, 2054 bytes removed, diff: -1541 /home/acme/git/pahole/ctf_loader.c: struct ctf_short_type | +0 14 structs changed type__init | -14 type__new | -9 class__new | -12 create_new_base_type | -7 create_new_base_type_float | -7 create_new_array | -8 create_new_subroutine_type | -9 create_full_members | -18 create_short_members | -18 create_new_class | +1 create_new_union | +1 create_new_enumeration | -19 create_new_forward_decl | -2 create_new_typedef | +3 create_new_tag | -5 load_types | +16 class__fixup_ctf_bitfields | -3 17 functions changed, 21 bytes added, 131 bytes removed, diff: -110 /home/acme/git/pahole/dwarf_loader.c: 17 structs changed zalloc | -56 tag__init | +3 array_type__new | +20 type__init | -24 class_member__new | +46 inline_expansion__new | +12 class__new | +81 lexblock__init | +19 function__new | +43 die__create_new_array | +20 die__create_new_parameter | +4 die__create_new_label | +4 die__create_new_subroutine_type | +113 die__create_new_enumeration | -21 die__process_class | +79 die__process_namespace | +76 die__create_new_inline_expansion | +4 die__process_function | +147 __die__process_tag | +34 die__process_unit | +56 die__process | +90 21 functions changed, 851 bytes added, 101 bytes removed, diff: +750 /home/acme/git/pahole/dwarves.c: struct ptr_table | +16 struct cu_orig_info | +32 2 structs changed tag__decl_line | +68 tag__decl_file | +70 tag__orig_id | +71 ptr_table__init | +46 ptr_table__exit | +37 ptr_table__add | +183 ptr_table__add_with_id | +165 ptr_table__entry | +64 cu__table_add_tag | +171 cu__table_nullify_type_entry | +38 10 functions changed, 913 bytes added, diff: +913 /home/acme/git/pahole/ctf_loader.c: 2 structs changed tag__alloc | +52 1 function changed, 52 bytes added, diff: +52 /home/acme/git/pahole/dwarf_loader.c: struct dwarf_tag | +48 struct dwarf_cu | +4104 4 structs changed dwarf_cu__init | +83 hashtags__hash | +61 hash_64 | +124 hlist_add_head | +78 hashtags__find | +161 cu__hash | +95 tag__is_tag_type | +171 tag__is_type | +85 tag__is_union | +28 tag__is_struct | +57 tag__is_typedef | +28 tag__is_enumeration | +28 dwarf_cu__find_tag_by_id | +56 dwarf_cu__find_type_by_id | +63 tag__alloc | +114 __tag__print_type_not_found | +108 namespace__recode_dwarf_types | +346 tag__namespace | +14 tag__has_namespace | +86 tag__is_namespace | +28 type__recode_dwarf_specification | +182 tag__type | +14 __tag__print_abstract_origin_not_found | +105 ftype__recode_dwarf_types | +322 tag__ftype | +14 tag__parameter | +14 lexblock__recode_dwarf_types | +736 tag__lexblock | +14 tag__label | +14 tag__recode_dwarf_type | +766 tag__ptr_to_member_type | +14 cu__recode_dwarf_types_table | +88 cu__recode_dwarf_types | +48 dwarf_tag__decl_file | +77 strings__ptr | +33 dwarf_tag__decl_line | +59 dwarf_tag__orig_id | +59 dwarf_tag__orig_type | +59 38 functions changed, 4432 bytes added, diff: +4432 build/libdwarves.so.1.0.0: 147 functions changed, 6782 bytes added, 2286 bytes removed, diff: +4496 Signed-off-by: Arnaldo Carvalho de Melo --- codiff.c | 9 +- ctf_loader.c | 105 +++--- ctracer.c | 180 +++++------ dutil.h | 2 + dwarf_loader.c | 739 +++++++++++++++++++++++++++++++++++++------ dwarves.c | 435 +++++++++++-------------- dwarves.h | 131 ++++++-- dwarves_reorganize.c | 33 +- pahole.c | 86 ++--- pdwtags.c | 53 ++-- pfunct.c | 11 +- prefcnt.c | 2 +- 12 files changed, 1183 insertions(+), 603 deletions(-) diff --git a/codiff.c b/codiff.c index 99d7a45..abe21f9 100644 --- a/codiff.c +++ b/codiff.c @@ -249,7 +249,8 @@ static void diff_struct(const struct cu *new_cu, struct class *structure, if (class__size(structure) == 0 || class__name(structure, cu) == NULL) return; - new_tag = cu__find_struct_by_name(new_cu, class__name(structure, cu), 0); + new_tag = cu__find_struct_by_name(new_cu, class__name(structure, cu), + 0, NULL); if (new_tag == NULL) return; @@ -334,7 +335,8 @@ static int find_new_classes_iterator(struct tag *tag, struct cu *cu, void *old_c if (class__size(class) == 0) return 0; - if (cu__find_struct_by_name(old_cu, class__name(class, cu), 0) != NULL) + if (cu__find_struct_by_name(old_cu, class__name(class, cu), 0, + NULL) != NULL) return 0; class->priv = diff_info__new(NULL, NULL, 1); @@ -367,8 +369,7 @@ static int cu_find_new_tags_iterator(struct cu *new_cu, void *old_cus) if (old_cu != NULL && cu__same_build_id(old_cu, new_cu)) return 0; - cu__for_each_tag(new_cu, find_new_tags_iterator, - old_cu, NULL); + cu__for_each_tag(new_cu, find_new_tags_iterator, old_cu, NULL); return 0; } diff --git a/ctf_loader.c b/ctf_loader.c index b035989..5fe00b9 100644 --- a/ctf_loader.c +++ b/ctf_loader.c @@ -37,6 +37,16 @@ static void *zalloc(const size_t size) return s; } +static void *tag__alloc(const size_t size) +{ + struct tag *self = zalloc(size); + + if (self != NULL) + self->top_level = 1; + + return self; +} + static void oom(const char *msg) { fprintf(stderr, "libclasses: out of memory(%s)\n", msg); @@ -326,7 +336,7 @@ static void dump_funcs(struct ctf_state *sp) static struct base_type *base_type__new(const char *name, size_t size) { - struct base_type *self = zalloc(sizeof(*self)); + struct base_type *self = tag__alloc(sizeof(*self)); if (self != NULL) { self->name = strings__add(strings, name); @@ -335,34 +345,32 @@ static struct base_type *base_type__new(const char *name, size_t size) return self; } -static void type__init(struct type *self, uint16_t tag, unsigned int id, +static void type__init(struct type *self, uint16_t tag, const char *name, size_t size) { INIT_LIST_HEAD(&self->node); INIT_LIST_HEAD(&self->namespace.tags); self->size = size; - self->namespace.tag.id = id; self->namespace.tag.tag = tag; self->namespace.name = strings__add(strings, name[0] == '(' ? NULL : name); } -static struct type *type__new(uint16_t tag, unsigned int id, - const char *name, size_t size) +static struct type *type__new(uint16_t tag, const char *name, size_t size) { - struct type *self = zalloc(sizeof(*self)); + struct type *self = tag__alloc(sizeof(*self)); if (self != NULL) - type__init(self, tag, id, name, size); + type__init(self, tag, name, size); return self; } -static struct class *class__new(const char *name, unsigned int id, size_t size) +static struct class *class__new(const char *name, size_t size) { - struct class *self = zalloc(sizeof(*self)); + struct class *self = tag__alloc(sizeof(*self)); if (self != NULL) { - type__init(&self->type, DW_TAG_structure_type, id, name, size); + type__init(&self->type, DW_TAG_structure_type, name, size); INIT_LIST_HEAD(&self->vtable); } @@ -371,7 +379,7 @@ static struct class *class__new(const char *name, unsigned int id, size_t size) static int create_new_base_type(struct ctf_state *sp, void *ptr, int vlen __unused, struct ctf_full_type *tp, - unsigned int id) + long id) { uint32_t *enc = ptr, name_idx; char name[64], *buf = name; @@ -393,8 +401,7 @@ static int create_new_base_type(struct ctf_state *sp, void *ptr, oom("base_type__new"); base->tag.tag = DW_TAG_base_type; - base->tag.id = id; - cu__add_tag(sp->cu, &base->tag); + cu__add_tag(sp->cu, &base->tag, &id); return sizeof(*enc); } @@ -402,7 +409,7 @@ static int create_new_base_type(struct ctf_state *sp, void *ptr, static int create_new_base_type_float(struct ctf_state *sp, void *ptr, int vlen __unused, struct ctf_full_type *tp, - unsigned int id) + long id) { uint32_t *enc = ptr, eval; char name[64]; @@ -417,8 +424,7 @@ static int create_new_base_type_float(struct ctf_state *sp, void *ptr, oom("base_type__new"); base->tag.tag = DW_TAG_base_type; - base->tag.id = id; - cu__add_tag(sp->cu, &base->tag); + cu__add_tag(sp->cu, &base->tag, &id); return sizeof(*enc); } @@ -426,10 +432,10 @@ static int create_new_base_type_float(struct ctf_state *sp, void *ptr, static int create_new_array(struct ctf_state *sp, void *ptr, int vlen __unused, struct ctf_full_type *tp __unused, - unsigned int id) + long id) { struct ctf_array *ap = ptr; - struct array_type *self = zalloc(sizeof(*self)); + struct array_type *self = tag__alloc(sizeof(*self)); if (self == NULL) oom("array_type"); @@ -444,23 +450,22 @@ static int create_new_array(struct ctf_state *sp, void *ptr, self->nr_entries[0] = ctf__get32(sp->ctf, &ap->ctf_array_nelems); self->tag.tag = DW_TAG_array_type; - self->tag.id = id; self->tag.type = ctf__get16(sp->ctf, &ap->ctf_array_type); - cu__add_tag(sp->cu, &self->tag); + cu__add_tag(sp->cu, &self->tag, &id); return sizeof(*ap); } static int create_new_subroutine_type(struct ctf_state *sp, void *ptr, int vlen, struct ctf_full_type *tp, - unsigned int id) + long id) { uint16_t *args = ptr; uint16_t i; const char *name = ctf_string(ctf__get32(sp->ctf, &tp->base.ctf_name), sp); unsigned int type = ctf__get16(sp->ctf, &tp->base.ctf_type); - struct function *self = zalloc(sizeof(*self)); + struct function *self = tag__alloc(sizeof(*self)); if (self == NULL) oom("function__new"); @@ -470,12 +475,11 @@ static int create_new_subroutine_type(struct ctf_state *sp, void *ptr, INIT_LIST_HEAD(&self->tool_node); INIT_LIST_HEAD(&self->proto.parms); self->proto.tag.tag = DW_TAG_subroutine_type; - self->proto.tag.id = id; self->proto.tag.type = type; INIT_LIST_HEAD(&self->lexblock.tags); for (i = 0; i < vlen; i++) { - struct parameter *p = zalloc(sizeof(*p)); + struct parameter *p = tag__alloc(sizeof(*p)); p->tag.tag = DW_TAG_formal_parameter; p->tag.type = ctf__get16(sp->ctf, &args[i]); @@ -490,7 +494,7 @@ static int create_new_subroutine_type(struct ctf_state *sp, void *ptr, if (vlen & 0x2) vlen += 0x2; - cu__add_tag(sp->cu, &self->proto.tag); + cu__add_tag(sp->cu, &self->proto.tag, &id); return vlen; } @@ -516,7 +520,6 @@ static unsigned long create_full_members(struct ctf_state *sp, void *ptr, member->offset = bit_offset / 8; member->bit_offset = bit_offset % 8; type__add_member(class, member); - cu__hash(sp->cu, &member->tag); } return sizeof(*mp); @@ -543,7 +546,6 @@ static unsigned long create_short_members(struct ctf_state *sp, void *ptr, member->bit_offset = bit_offset % 8; type__add_member(class, member); - cu__hash(sp->cu, &member->tag); } return sizeof(*mp); @@ -551,11 +553,11 @@ static unsigned long create_short_members(struct ctf_state *sp, void *ptr, static int create_new_class(struct ctf_state *sp, void *ptr, int vlen, struct ctf_full_type *tp, - uint64_t size, unsigned int id) + uint64_t size, long id) { unsigned long member_size; const char *name = ctf_string(ctf__get32(sp->ctf, &tp->base.ctf_name), sp); - struct class *self = class__new(name, id, size); + struct class *self = class__new(name, size); if (size >= CTF_SHORT_MEMBER_LIMIT) { member_size = create_full_members(sp, ptr, vlen, &self->type); @@ -563,18 +565,18 @@ static int create_new_class(struct ctf_state *sp, void *ptr, member_size = create_short_members(sp, ptr, vlen, &self->type); } - cu__add_tag(sp->cu, &self->type.namespace.tag); + cu__add_tag(sp->cu, &self->type.namespace.tag, &id); return (vlen * member_size); } static int create_new_union(struct ctf_state *sp, void *ptr, int vlen, struct ctf_full_type *tp, - uint64_t size, unsigned int id) + uint64_t size, long id) { unsigned long member_size; const char *name = ctf_string(ctf__get32(sp->ctf, &tp->base.ctf_name), sp); - struct type *self = type__new(DW_TAG_union_type, id, name, size); + struct type *self = type__new(DW_TAG_union_type, name, size); if (size >= CTF_SHORT_MEMBER_LIMIT) { member_size = create_full_members(sp, ptr, vlen, self); @@ -582,7 +584,7 @@ static int create_new_union(struct ctf_state *sp, void *ptr, member_size = create_short_members(sp, ptr, vlen, self); } - cu__add_tag(sp->cu, &self->namespace.tag); + cu__add_tag(sp->cu, &self->namespace.tag, &id); return (vlen * member_size); } @@ -590,7 +592,7 @@ static int create_new_union(struct ctf_state *sp, void *ptr, static struct enumerator *enumerator__new(const char *name, uint32_t value) { - struct enumerator *self = zalloc(sizeof(*self)); + struct enumerator *self = tag__alloc(sizeof(*self)); if (self != NULL) { self->name = strings__add(strings, name); @@ -603,11 +605,11 @@ static struct enumerator *enumerator__new(const char *name, static int create_new_enumeration(struct ctf_state *sp, void *ptr, int vlen, struct ctf_full_type *tp, - unsigned int id) + long id) { struct ctf_enum *ep = ptr; uint16_t i; - struct type *enumeration = type__new(DW_TAG_enumeration_type, id, + struct type *enumeration = type__new(DW_TAG_enumeration_type, ctf_string(ctf__get32(sp->ctf, &tp->base.ctf_name), sp), sizeof(int)); /* FIXME: is this always the case? */ @@ -624,32 +626,31 @@ static int create_new_enumeration(struct ctf_state *sp, void *ptr, oom("enumerator__new"); enumeration__add(enumeration, enumerator); - cu__hash(sp->cu, &enumerator->tag); } - cu__add_tag(sp->cu, &enumeration->namespace.tag); + cu__add_tag(sp->cu, &enumeration->namespace.tag, &id); return (vlen * sizeof(*ep)); } static int create_new_forward_decl(struct ctf_state *sp, void *ptr __unused, int vlen __unused, struct ctf_full_type *tp, - uint64_t size, unsigned int id) + uint64_t size, long id) { char *name = ctf_string(ctf__get32(sp->ctf, &tp->base.ctf_name), sp); - struct class *self = class__new(name, id, size); + struct class *self = class__new(name, size); if (self == NULL) oom("class foward decl"); self->type.declaration = 1; - cu__add_tag(sp->cu, &self->type.namespace.tag); + cu__add_tag(sp->cu, &self->type.namespace.tag, &id); return 0; } static int create_new_typedef(struct ctf_state *sp, int type, void *ptr __unused, int vlen __unused, struct ctf_full_type *tp, - uint64_t size, unsigned int id) + uint64_t size, long id) { const char *name = ctf_string(ctf__get32(sp->ctf, &tp->base.ctf_name), sp); unsigned int type_id = ctf__get16(sp->ctf, &tp->base.ctf_type); @@ -663,18 +664,18 @@ static int create_new_typedef(struct ctf_state *sp, int type, return 0; } - self = type__new(tag, id, name, size); + self = type__new(tag, name, size); if (self == NULL) oom("type__new"); self->namespace.tag.type = type_id; - cu__add_tag(sp->cu, &self->namespace.tag); + cu__add_tag(sp->cu, &self->namespace.tag, &id); return 0; } static int create_new_tag(struct ctf_state *sp, int type, void *ptr __unused, int vlen __unused, - struct ctf_full_type *tp, unsigned int id) + struct ctf_full_type *tp, long id) { unsigned int type_id = ctf__get16(sp->ctf, &tp->base.ctf_type); struct tag *self = zalloc(sizeof(*self)); @@ -692,9 +693,8 @@ static int create_new_tag(struct ctf_state *sp, int type, return 0; } - self->id = id; self->type = type_id; - cu__add_tag(sp->cu, self); + cu__add_tag(sp->cu, self, &id); return 0; } @@ -762,6 +762,7 @@ static void load_types(struct ctf_state *sp) type == CTF_TYPE_KIND_RESTRICT) { vlen = create_new_tag(sp, type, ptr, vlen, type_ptr, type_index); } else if (type == CTF_TYPE_KIND_UNKN) { + cu__table_nullify_type_entry(sp->cu, type_index); printf("CTF: [%#6x] %1d Unknown\n", type_index, CTF_ISROOT(val)); vlen = 0; } else { @@ -825,10 +826,10 @@ static int class__fixup_ctf_bitfields(struct tag *self, struct cu *cu) if (last_offset == -1) last_offset = pos->offset; - struct tag *fixed_tag; - fixed_tag = cu__find_base_type_by_name_and_size(cu, base_type__name(bt), - bit_size); - if (fixed_tag == NULL) { + uint16_t fixed_tag_id; + + if (cu__find_base_type_by_name_and_size(cu, base_type__name(bt), + bit_size, &fixed_tag_id) == NULL) { fprintf(stderr, "%s: BRAIN FART ALERT!: class: %s, member: %s\n", __func__, type__name(type_self, cu), @@ -837,7 +838,7 @@ static int class__fixup_ctf_bitfields(struct tag *self, struct cu *cu) } pos->offset = last_offset; - pos->tag.type = fixed_tag->id; + pos->tag.type = fixed_tag_id; pos->bit_size = bt->bit_size; pos->bit_offset = bit_offset; bit_offset += bt->bit_size; diff --git a/ctracer.c b/ctracer.c index 8c86a3f..411cc21 100644 --- a/ctracer.c +++ b/ctracer.c @@ -165,42 +165,26 @@ static int methods__add(void **table, const char *str) return 0; } -static void method__add(struct cu *cu, struct function *function) +static void method__add(struct cu *cu, struct function *function, uint32_t id) { list_add(&function->tool_node, &cu->tool_list); + function->priv = (void *)(long)id; } /* * We want just the DW_TAG_subprogram tags that have as one of its parameters * a pointer to the specified "class" (a struct, unions can be added later). */ -static struct tag *function__filter(struct tag *tag, struct cu *cu, void *cookie) +static struct function *function__filter(struct function *function, + struct cu *cu, uint16_t target_type_id) { - struct function *function; - - if (tag->tag != DW_TAG_subprogram) - return NULL; - - function = tag__function(tag); if (function__inlined(function) || function->abstract_origin != 0 || !list_empty(&function->tool_node) || - !ftype__has_parm_of_type(&function->proto, cookie, cu)) + !ftype__has_parm_of_type(&function->proto, target_type_id, cu)) return NULL; - return tag; -} - -/* - * Add the function to the list of methods since it matches function__filter - * criteria. - */ -static int find_methods_iterator(struct tag *tag, struct cu *cu, - void *cookie __unused) -{ - struct function *function = tag__function(tag); - method__add(cu, function); - return 0; + return function; } /* @@ -210,14 +194,22 @@ static int find_methods_iterator(struct tag *tag, struct cu *cu, */ static int cu_find_methods_iterator(struct cu *cu, void *cookie) { - struct tag *target = cu__find_struct_by_name(cu, cookie, 0); + uint16_t target_type_id; + uint32_t function_id; + struct function *function; + struct tag *target = cu__find_struct_by_name(cu, cookie, 0, + &target_type_id); INIT_LIST_HEAD(&cu->tool_list); if (target == NULL) return 0; - return cu__for_each_tag(cu, find_methods_iterator, target, function__filter); + cu__for_each_function(cu, function_id, function) + if (function__filter(function, cu, target_type_id)) + method__add(cu, function, function_id); + + return 0; } static struct class_member *class_member__bitfield_tail(struct class_member *head, @@ -489,9 +481,10 @@ static int class__emit_ostra_converter(struct tag *tag_self, * We want just the DW_TAG_structure_type tags that have a member that is a pointer * to the target class. */ -static struct tag *pointer_filter(struct tag *tag, struct cu *cu, void *target_tag) +static struct tag *pointer_filter(struct tag *tag, struct cu *cu, + uint16_t target_type_id) { - struct type *type, *target_type; + struct type *type; struct class_member *pos; const char *class_name; @@ -506,41 +499,36 @@ static struct tag *pointer_filter(struct tag *tag, struct cu *cu, void *target_t if (class_name == NULL || structures__find(&pointers, class_name)) return NULL; - target_type = tag__type(target_tag); type__for_each_member(type, pos) { struct tag *ctype = cu__find_type_by_id(cu, pos->tag.type); tag__assert_search_result(ctype); - if (ctype->tag == DW_TAG_pointer_type && ctype->type == target_type->namespace.tag.id) + if (ctype->tag == DW_TAG_pointer_type && + ctype->type == target_type_id) return tag; } return NULL; } -/* - * Add the struct to the list of pointers since it matches pointer_filter - * criteria. - */ -static int find_pointers_iterator(struct tag *tag, struct cu *cu, - void *cookie __unused) -{ - structures__add(&pointers, tag, cu); - return 0; -} - /* * Iterate thru all the tags in the compilation unit, looking for classes * that have as one member that is a pointer to the target type. */ static int cu_find_pointers_iterator(struct cu *cu, void *class_name) { - struct tag *target = cu__find_struct_by_name(cu, class_name, 0); + uint16_t target_type_id, id; + struct tag *target = cu__find_struct_by_name(cu, class_name, 0, + &target_type_id), *pos; if (target == NULL) return 0; - return cu__for_each_tag(cu, find_pointers_iterator, target, pointer_filter); + cu__for_each_type(cu, id, pos) + if (pointer_filter(pos, cu, target_type_id)) + structures__add(&pointers, pos, cu); + + return 0; } static void class__find_pointers(const char *class_name) @@ -552,9 +540,10 @@ static void class__find_pointers(const char *class_name) * We want just the DW_TAG_structure_type tags that have as its first member * a struct of type target. */ -static struct tag *alias_filter(struct tag *tag, struct cu *cu, void *target_tag) +static struct tag *alias_filter(struct tag *tag, + struct cu *cu, uint16_t target_type_id) { - struct type *type, *target_type; + struct type *type; struct class_member *first_member; if (!tag__is_struct(tag)) @@ -566,8 +555,7 @@ static struct tag *alias_filter(struct tag *tag, struct cu *cu, void *target_tag first_member = list_first_entry(&type->namespace.tags, struct class_member, tag.node); - target_type = tag__type(target_tag); - if (first_member->tag.type != target_type->namespace.tag.id) + if (first_member->tag.type != target_type_id) return NULL; if (structures__find(&aliases, class__name(tag__class(tag), cu))) @@ -578,45 +566,41 @@ static struct tag *alias_filter(struct tag *tag, struct cu *cu, void *target_tag static void class__find_aliases(const char *class_name); -/* - * Add the struct to the list of aliases since it matches alias_filter - * criteria. - */ -static int find_aliases_iterator(struct tag *tag, struct cu *cu, - void *cookie __unused) -{ - const char *alias_name = class__name(tag__class(tag), cu); - - structures__add(&aliases, tag, cu); - - /* - * Now find aliases to this alias, e.g.: - * - * struct tcp_sock { - * struct inet_connection_sock { - * struct inet_sock { - * struct sock { - * } - * } - * } - * } - */ - class__find_aliases(alias_name); - return 0; -} - /* * Iterate thru all the tags in the compilation unit, looking for classes * that have as its first member the specified "class" (struct). */ static int cu_find_aliases_iterator(struct cu *cu, void *class_name) { - struct tag *target = cu__find_struct_by_name(cu, class_name, 0); - + uint16_t target_type_id, id; + struct tag *target = cu__find_struct_by_name(cu, class_name, 0, + &target_type_id), *pos; if (target == NULL) return 0; - return cu__for_each_tag(cu, find_aliases_iterator, target, alias_filter); + cu__for_each_type(cu, id, pos) { + if (alias_filter(pos, cu, target_type_id)) { + const char *alias_name = class__name(tag__class(pos), cu); + + structures__add(&aliases, pos, cu); + + /* + * Now find aliases to this alias, e.g.: + * + * struct tcp_sock { + * struct inet_connection_sock { + * struct inet_sock { + * struct sock { + * } + * } + * } + * } + */ + class__find_aliases(alias_name); + } + } + + return 0; } static void class__find_aliases(const char *class_name) @@ -688,8 +672,9 @@ out: * This marks the function entry, function__emit_kretprobes will emit the * probe for the function exit. */ -static int function__emit_probes(struct function *self, const struct cu *cu, - const struct tag *target, int probe_type, +static int function__emit_probes(struct function *self, uint32_t function_id, + const struct cu *cu, + const uint16_t target_type_id, int probe_type, const char *member) { struct parameter *pos; @@ -711,11 +696,8 @@ static int function__emit_probes(struct function *self, const struct cu *cu, struct tag *type = cu__find_type_by_id(cu, pos->tag.type); tag__assert_search_result(type); - if (type->tag != DW_TAG_pointer_type) - continue; - - type = cu__find_type_by_id(cu, type->type); - if (type == NULL || type->id != target->id) + if (type->tag != DW_TAG_pointer_type || + type->type != target_type_id) continue; if (member != NULL) @@ -723,9 +705,9 @@ static int function__emit_probes(struct function *self, const struct cu *cu, parameter__name(pos, cu)); fprintf(fp_methods, - "\tctracer__method_hook(%d, %#llx, $%s%s%s, %zd);\n", + "\tctracer__method_hook(%d, %d, $%s%s%s, %zd);\n", probe_type, - (unsigned long long)self->proto.tag.id, + function_id, parameter__name(pos, cu), member ? "->" : "", member ?: "", class__size(mini_class)); @@ -744,16 +726,18 @@ static int function__emit_probes(struct function *self, const struct cu *cu, */ static int cu_emit_probes_iterator(struct cu *cu, void *cookie) { - struct tag *target = cu__find_struct_by_name(cu, cookie, 0); + uint16_t target_type_id; + struct tag *target = cu__find_struct_by_name(cu, cookie, 0, &target_type_id); struct function *pos; tag__assert_search_result(target); list_for_each_entry(pos, &cu->tool_list, tool_node) { + uint32_t function_id = (long)pos->priv; + if (methods__add(&probes_emitted, function__name(pos, cu)) != 0) continue; - pos->priv = (void *)1; /* Mark as visited, for the table iterator */ - function__emit_probes(pos, cu, target, 0, NULL); /* entry */ - function__emit_probes(pos, cu, target, 1, NULL); /* exit */ + function__emit_probes(pos, function_id, cu, target_type_id, 0, NULL); /* entry */ + function__emit_probes(pos, function_id, cu, target_type_id, 1, NULL); /* exit */ } return 0; @@ -765,6 +749,7 @@ static int cu_emit_probes_iterator(struct cu *cu, void *cookie) */ static int cu_emit_pointer_probes_iterator(struct cu *cu, void *cookie) { + uint16_t target_type_id, pointer_id; struct tag *target, *pointer; struct function *pos_tag; struct class_member *pos_member; @@ -773,8 +758,8 @@ static int cu_emit_pointer_probes_iterator(struct cu *cu, void *cookie) if (list_empty(&cu->tool_list)) return 0; - target = cu__find_struct_by_name(cu, class_name, 1); - pointer = cu__find_struct_by_name(cu, cookie, 0); + target = cu__find_struct_by_name(cu, class_name, 1, &target_type_id); + pointer = cu__find_struct_by_name(cu, cookie, 0, &pointer_id); tag__assert_search_result(target); tag__assert_search_result(pointer); @@ -783,18 +768,19 @@ static int cu_emit_pointer_probes_iterator(struct cu *cu, void *cookie) struct tag *ctype = cu__find_type_by_id(cu, pos_member->tag.type); tag__assert_search_result(ctype); - if (ctype->tag == DW_TAG_pointer_type && ctype->type == target->id) + if (ctype->tag == DW_TAG_pointer_type && ctype->type == target_type_id) break; } list_for_each_entry(pos_tag, &cu->tool_list, tool_node) { + uint32_t function_id = (long)pos_tag->priv; + if (methods__add(&probes_emitted, function__name(pos_tag, cu)) != 0) continue; - pos_tag->priv = (void *)1; /* Mark as visited, for the table iterator */ - function__emit_probes(pos_tag, cu, pointer, 0, + function__emit_probes(pos_tag, function_id, cu, target_type_id, 0, class_member__name(pos_member)); /* entry */ - function__emit_probes(pos_tag, cu, pointer, 1, + function__emit_probes(pos_tag, function_id, cu, target_type_id, 1, class_member__name(pos_member)); /* exit */ } @@ -812,8 +798,8 @@ static int cu_emit_functions_table(struct cu *cu, void *fp) list_for_each_entry(pos, &cu->tool_list, tool_node) if (pos->priv != NULL) { - fprintf(fp, "%llu:%s\n", - (unsigned long long)pos->proto.tag.id, + uint32_t function_id = (long)pos->priv; + fprintf(fp, "%d:%s\n", function_id, function__name(pos, cu)); pos->priv = NULL; } @@ -958,7 +944,7 @@ failure: /* * See if the specified struct exists: */ - class = cus__find_struct_by_name(methods_cus, &cu, class_name, 0); + class = cus__find_struct_by_name(methods_cus, &cu, class_name, 0, NULL); if (class == NULL) { fprintf(stderr, "ctracer: struct %s not found!\n", class_name); return EXIT_FAILURE; diff --git a/dutil.h b/dutil.h index 6bb5247..d2166ab 100644 --- a/dutil.h +++ b/dutil.h @@ -14,6 +14,8 @@ #define __unused __attribute__ ((unused)) #endif +#define roundup(x,y) ((((x) + ((y) - 1)) / (y)) * (y)) + /* We need define two variables, argp_program_version_hook and argp_program_bug_address, in all programs. argp.h declares these variables as non-const (which is correct in general). But we can diff --git a/dwarf_loader.c b/dwarf_loader.c index 1410346..fb0d9ae 100644 --- a/dwarf_loader.c +++ b/dwarf_loader.c @@ -25,17 +25,87 @@ #include "dwarves.h" #include "dutil.h" #include "strings.h" +#include "hash.h" + +#define hashtags__fn(key) hash_64(key, HASHTAGS__BITS) + +struct dwarf_tag { + struct hlist_node hash_node; + Dwarf_Off type; + Dwarf_Off id; + struct tag *tag; + strings_t decl_file; + uint16_t decl_line; + uint16_t small_id; +}; + +#define HASHTAGS__BITS 8 +#define HASHTAGS__SIZE (1UL << HASHTAGS__BITS) + +struct dwarf_cu { + struct hlist_head hash_tags[HASHTAGS__SIZE]; + struct hlist_head hash_types[HASHTAGS__SIZE]; + struct cu *cu; +}; + +static void dwarf_cu__init(struct dwarf_cu *self) +{ + unsigned int i; + for (i = 0; i < HASHTAGS__SIZE; ++i) { + INIT_HLIST_HEAD(&self->hash_tags[i]); + INIT_HLIST_HEAD(&self->hash_types[i]); + } +} + +static void hashtags__hash(struct hlist_head *hashtable, + struct dwarf_tag *dtag) +{ + struct hlist_head *head = hashtable + hashtags__fn(dtag->id); + hlist_add_head(&dtag->hash_node, head); +} + +static struct dwarf_tag *hashtags__find(const struct hlist_head *hashtable, + const Dwarf_Off id) +{ + if (id == 0) + return NULL; + + struct dwarf_tag *tpos; + struct hlist_node *pos; + uint16_t bucket = hashtags__fn(id); + const struct hlist_head *head = hashtable + bucket; + + hlist_for_each_entry(tpos, pos, head, hash_node) { + if (tpos->id == id) + return tpos; + } + + return NULL; +} + +static void cu__hash(struct cu *self, struct tag *tag) +{ + struct dwarf_cu *dcu = self->priv; + struct hlist_head *hashtable = tag__is_tag_type(tag) ? + dcu->hash_types : + dcu->hash_tags; + hashtags__hash(hashtable, tag->priv); +} + +static struct dwarf_tag *dwarf_cu__find_tag_by_id(const struct dwarf_cu *self, + const Dwarf_Off id) +{ + return self ? hashtags__find(self->hash_tags, id) : NULL; +} + +static struct dwarf_tag *dwarf_cu__find_type_by_id(const struct dwarf_cu *self, + const Dwarf_Off id) +{ + return self ? hashtags__find(self->hash_types, id) : NULL; +} extern struct strings *strings; -static void *zalloc(const size_t size) -{ - void *s = malloc(size); - if (s != NULL) - memset(s, 0, size); - return s; -} - static void *memdup(const void *src, size_t len) { void *s = malloc(len); @@ -175,37 +245,56 @@ static int attr_location(Dwarf_Die *die, Dwarf_Op **expr, size_t *exprlen) return 1; } +static void *tag__alloc(size_t size) +{ + struct dwarf_tag *dtag; + struct tag *self = malloc(size + sizeof(*dtag)); + + if (self != NULL) { + dtag = ((void *)self) + size; + dtag->tag = self; + self->priv = dtag; + dtag->type = 0; + self->type = 0; + self->top_level = 0; + } + + return self; +} + static void tag__init(struct tag *self, Dwarf_Die *die) { + struct dwarf_tag *dtag = self->priv; int32_t decl_line; const char *decl_file = dwarf_decl_file(die); static const char *last_decl_file; static uint32_t last_decl_file_idx; self->tag = dwarf_tag(die); - self->id = dwarf_dieoffset(die); + + dtag->id = dwarf_dieoffset(die); if (self->tag == DW_TAG_imported_module || self->tag == DW_TAG_imported_declaration) - self->type = attr_type(die, DW_AT_import); + dtag->type = attr_type(die, DW_AT_import); else - self->type = attr_type(die, DW_AT_type); + dtag->type = attr_type(die, DW_AT_type); if (decl_file != last_decl_file) { last_decl_file_idx = strings__add(strings, decl_file); last_decl_file = decl_file; } - self->decl_file = last_decl_file_idx; + dtag->decl_file = last_decl_file_idx; dwarf_decl_line(die, &decl_line); - self->decl_line = decl_line; + dtag->decl_line = decl_line; self->recursivity_level = 0; - INIT_HLIST_NODE(&self->hash_node); + INIT_HLIST_NODE(&dtag->hash_node); } static struct tag *tag__new(Dwarf_Die *die) { - struct tag *self = malloc(sizeof(*self)); + struct tag *self = tag__alloc(sizeof(*self)); if (self != NULL) tag__init(self, die); @@ -215,7 +304,7 @@ static struct tag *tag__new(Dwarf_Die *die) static struct ptr_to_member_type *ptr_to_member_type__new(Dwarf_Die *die) { - struct ptr_to_member_type *self = malloc(sizeof(*self)); + struct ptr_to_member_type *self = tag__alloc(sizeof(*self)); if (self != NULL) { tag__init(&self->tag, die); @@ -227,7 +316,7 @@ static struct ptr_to_member_type *ptr_to_member_type__new(Dwarf_Die *die) static struct base_type *base_type__new(Dwarf_Die *die) { - struct base_type *self = zalloc(sizeof(*self)); + struct base_type *self = tag__alloc(sizeof(*self)); if (self != NULL) { tag__init(&self->tag, die); @@ -240,10 +329,13 @@ static struct base_type *base_type__new(Dwarf_Die *die) static struct array_type *array_type__new(Dwarf_Die *die) { - struct array_type *self = zalloc(sizeof(*self)); + struct array_type *self = tag__alloc(sizeof(*self)); - if (self != NULL) + if (self != NULL) { tag__init(&self->tag, die); + self->dimensions = 0; + self->nr_entries = NULL; + } return self; } @@ -258,7 +350,7 @@ static void namespace__init(struct namespace *self, Dwarf_Die *die) static struct namespace *namespace__new(Dwarf_Die *die) { - struct namespace *self = malloc(sizeof(*self)); + struct namespace *self = tag__alloc(sizeof(*self)); if (self != NULL) namespace__init(self, die); @@ -281,7 +373,7 @@ static void type__init(struct type *self, Dwarf_Die *die) static struct type *type__new(Dwarf_Die *die) { - struct type *self = malloc(sizeof(*self)); + struct type *self = tag__alloc(sizeof(*self)); if (self != NULL) type__init(self, die); @@ -291,7 +383,7 @@ static struct type *type__new(Dwarf_Die *die) static struct enumerator *enumerator__new(Dwarf_Die *die) { - struct enumerator *self = zalloc(sizeof(*self)); + struct enumerator *self = tag__alloc(sizeof(*self)); if (self != NULL) { tag__init(&self->tag, die); @@ -326,7 +418,7 @@ static enum vlocation dwarf__location(Dwarf_Die *die) static struct variable *variable__new(Dwarf_Die *die) { - struct variable *self = malloc(sizeof(*self)); + struct variable *self = tag__alloc(sizeof(*self)); if (self != NULL) { tag__init(&self->tag, die); @@ -346,16 +438,20 @@ static struct variable *variable__new(Dwarf_Die *die) static struct class_member *class_member__new(Dwarf_Die *die) { - struct class_member *self = zalloc(sizeof(*self)); + struct class_member *self = tag__alloc(sizeof(*self)); if (self != NULL) { tag__init(&self->tag, die); + self->name = strings__add(strings, attr_string(die, DW_AT_name)); self->offset = attr_offset(die, DW_AT_data_member_location); - self->bit_size = attr_numeric(die, DW_AT_bit_size); self->bit_offset = attr_numeric(die, DW_AT_bit_offset); + self->bit_size = attr_numeric(die, DW_AT_bit_size); + self->bit_hole = 0; + self->bitfield_end = 0; + self->visited = 0; self->accessibility = attr_numeric(die, DW_AT_accessibility); self->virtuality = attr_numeric(die, DW_AT_virtuality); - self->name = strings__add(strings, attr_string(die, DW_AT_name)); + self->hole = 0; } return self; @@ -363,7 +459,7 @@ static struct class_member *class_member__new(Dwarf_Die *die) static struct parameter *parameter__new(Dwarf_Die *die) { - struct parameter *self = zalloc(sizeof(*self)); + struct parameter *self = tag__alloc(sizeof(*self)); if (self != NULL) { tag__init(&self->tag, die); @@ -377,14 +473,16 @@ static struct parameter *parameter__new(Dwarf_Die *die) static struct inline_expansion *inline_expansion__new(Dwarf_Die *die) { - struct inline_expansion *self = zalloc(sizeof(*self)); + struct inline_expansion *self = tag__alloc(sizeof(*self)); if (self != NULL) { + struct dwarf_tag *dtag = self->tag.priv; + tag__init(&self->tag, die); - self->tag.decl_file = + dtag->decl_file = strings__add(strings, attr_string(die, DW_AT_call_file)); - self->tag.decl_line = attr_numeric(die, DW_AT_call_line); - self->tag.type = attr_type(die, DW_AT_abstract_origin); + dtag->decl_line = attr_numeric(die, DW_AT_call_line); + dtag->type = attr_type(die, DW_AT_abstract_origin); if (dwarf_lowpc(die, &self->low_pc)) self->low_pc = 0; @@ -415,7 +513,7 @@ static struct inline_expansion *inline_expansion__new(Dwarf_Die *die) static struct label *label__new(Dwarf_Die *die) { - struct label *self = malloc(sizeof(*self)); + struct label *self = tag__alloc(sizeof(*self)); if (self != NULL) { tag__init(&self->tag, die); @@ -430,11 +528,17 @@ static struct label *label__new(Dwarf_Die *die) static struct class *class__new(Dwarf_Die *die) { - struct class *self = zalloc(sizeof(*self)); + struct class *self = tag__alloc(sizeof(*self)); if (self != NULL) { type__init(&self->type, die); INIT_LIST_HEAD(&self->vtable); + self->nr_vtable_entries = + self->nr_holes = + self->nr_bit_holes = + self->padding = + self->bit_padding = 0; + self->priv = NULL; } return self; @@ -449,6 +553,7 @@ static void lexblock__init(struct lexblock *self, Dwarf_Die *die) INIT_LIST_HEAD(&self->tags); + self->size_inline_expansions = self->nr_inline_expansions = self->nr_labels = self->nr_lexblocks = @@ -457,7 +562,7 @@ static void lexblock__init(struct lexblock *self, Dwarf_Die *die) static struct lexblock *lexblock__new(Dwarf_Die *die) { - struct lexblock *self = malloc(sizeof(*self)); + struct lexblock *self = tag__alloc(sizeof(*self)); if (self != NULL) { tag__init(&self->tag, die); @@ -480,7 +585,7 @@ static void ftype__init(struct ftype *self, Dwarf_Die *die) static struct ftype *ftype__new(Dwarf_Die *die) { - struct ftype *self = malloc(sizeof(*self)); + struct ftype *self = tag__alloc(sizeof(*self)); if (self != NULL) ftype__init(self, die); @@ -490,7 +595,7 @@ static struct ftype *ftype__new(Dwarf_Die *die) static struct function *function__new(Dwarf_Die *die) { - struct function *self = zalloc(sizeof(*self)); + struct function *self = tag__alloc(sizeof(*self)); if (self != NULL) { ftype__init(&self->proto, die); @@ -508,6 +613,9 @@ static struct function *function__new(Dwarf_Die *die) self->vtable_entry = -1; if (dwarf_hasattr(die, DW_AT_vtable_elem_location)) self->vtable_entry = attr_offset(die, DW_AT_vtable_elem_location); + self->cu_total_size_inline_expansions = 0; + self->cu_total_nr_inline_expansions = 0; + self->priv = NULL; } return self; @@ -544,9 +652,10 @@ static void __cu__tag_not_handled(Dwarf_Die *die, const char *fn) #define cu__tag_not_handled(die) __cu__tag_not_handled(die, __FUNCTION__) static struct tag *__die__process_tag(Dwarf_Die *die, struct cu *cu, - const char *fn); + int toplevel, const char *fn); -#define die__process_tag(die, cu) __die__process_tag(die, cu, __FUNCTION__) +#define die__process_tag(die, cu, toplevel) \ + __die__process_tag(die, cu, toplevel, __FUNCTION__) static struct tag *die__create_new_tag(Dwarf_Die *die) { @@ -590,7 +699,8 @@ static struct tag *die__create_new_class(Dwarf_Die *die, struct cu *cu) } static void die__process_namespace(Dwarf_Die *die, - struct namespace *namespace, struct cu *cu); + struct namespace *namespace, + struct cu *cu); static struct tag *die__create_new_namespace(Dwarf_Die *die, struct cu *cu) { @@ -660,8 +770,10 @@ static struct tag *die__create_new_array(Dwarf_Die *die) oom("array_type__new"); if (!dwarf_haschildren(die) || dwarf_child(die, &child) != 0) { - fprintf(stderr, "%s: DW_TAG_array_type with no children!\n", - __FUNCTION__); + struct dwarf_tag *dtag = array->tag.priv; + fprintf(stderr, + "%s: DW_TAG_array_type %#llx with no children!\n", + __func__, (unsigned long long)dtag->id); return NULL; } @@ -688,8 +800,9 @@ static struct tag *die__create_new_array(Dwarf_Die *die) return &array->tag; } -static void die__create_new_parameter(Dwarf_Die *die, struct ftype *ftype, - struct lexblock *lexblock) +static struct tag *die__create_new_parameter(Dwarf_Die *die, + struct ftype *ftype, + struct lexblock *lexblock) { struct parameter *parm = parameter__new(die); @@ -711,9 +824,11 @@ static void die__create_new_parameter(Dwarf_Die *die, struct ftype *ftype, lexblock__add_tag(lexblock, &parm->tag); } + return &parm->tag; } -static void die__create_new_label(Dwarf_Die *die, struct lexblock *lexblock) +static struct tag *die__create_new_label(Dwarf_Die *die, + struct lexblock *lexblock) { struct label *label = label__new(die); @@ -721,6 +836,7 @@ static void die__create_new_label(Dwarf_Die *die, struct lexblock *lexblock) oom("label__new"); lexblock__add_label(lexblock, label); + return &label->tag; } static struct tag *die__create_new_variable(Dwarf_Die *die) @@ -746,31 +862,43 @@ static struct tag *die__create_new_subroutine_type(Dwarf_Die *die, die = &child; do { + long id = -1; + struct tag *tag; + switch (dwarf_tag(die)) { case DW_TAG_formal_parameter: - die__create_new_parameter(die, ftype, NULL); + tag = die__create_new_parameter(die, ftype, NULL); break; case DW_TAG_unspecified_parameters: ftype->unspec_parms = 1; - break; - case DW_TAG_typedef: { + continue; + case DW_TAG_typedef: /* * First seen in inkscape */ - struct tag *tag = die__create_new_typedef(die); - cu__add_tag(cu, tag); - } - break; + tag = die__create_new_typedef(die); + + if (cu__add_tag(cu, tag, &id) < 0) + oom("die__create_new_subroutine_type:2"); + + goto hash; default: cu__tag_not_handled(die); - break; + continue; } + + if (cu__table_add_tag(cu, tag, &id) < 0) + oom("die__create_new_subroutine_type"); +hash: + cu__hash(cu, tag); + struct dwarf_tag *dtag = tag->priv; + dtag->small_id = id; } while (dwarf_siblingof(die, die) == 0); out: return &ftype->tag; } -static struct tag *die__create_new_enumeration(Dwarf_Die *die, struct cu *cu) +static struct tag *die__create_new_enumeration(Dwarf_Die *die) { Dwarf_Die child; struct type *enumeration = type__new(die); @@ -797,7 +925,6 @@ static struct tag *die__create_new_enumeration(Dwarf_Die *die, struct cu *cu) oom("enumerator__new"); enumeration__add(enumeration, enumerator); - cu__hash(cu, &enumerator->tag); } while (dwarf_siblingof(die, die) == 0); out: return &enumeration->namespace.tag; @@ -820,9 +947,17 @@ static void die__process_class(Dwarf_Die *die, struct type *class, } continue; default: { - struct tag *tag = die__process_tag(die, cu); + struct tag *tag = die__process_tag(die, cu, 0); if (tag != NULL) { + long id = -1; + + if (cu__table_add_tag(cu, tag, &id) < 0) + oom("die__process_class:2"); + + struct dwarf_tag *dtag = tag->priv; + dtag->small_id = id; + namespace__add_tag(&class->namespace, tag); cu__hash(cu, tag); if (tag->tag == DW_TAG_subprogram) { @@ -839,12 +974,20 @@ static void die__process_class(Dwarf_Die *die, struct type *class, } static void die__process_namespace(Dwarf_Die *die, - struct namespace *namespace, struct cu *cu) + struct namespace *namespace, + struct cu *cu) { do { - struct tag *tag = die__process_tag(die, cu); + struct tag *tag = die__process_tag(die, cu, 0); if (tag != NULL) { + long id = -1; + if (cu__table_add_tag(cu, tag, &id) < 0) + oom("die__process_namespace"); + + struct dwarf_tag *dtag = tag->priv; + dtag->small_id = id; + namespace__add_tag(namespace, tag); cu__hash(cu, tag); } @@ -865,8 +1008,8 @@ static void die__create_new_lexblock(Dwarf_Die *die, lexblock__add_lexblock(father, lexblock); } -static void die__create_new_inline_expansion(Dwarf_Die *die, - struct lexblock *lexblock) +static struct tag *die__create_new_inline_expansion(Dwarf_Die *die, + struct lexblock *lexblock) { struct inline_expansion *exp = inline_expansion__new(die); @@ -874,6 +1017,7 @@ static void die__create_new_inline_expansion(Dwarf_Die *die, oom("inline_expansion__new"); lexblock__add_inline_expansion(lexblock, exp); + return &exp->tag; } static void die__process_function(Dwarf_Die *die, struct ftype *ftype, @@ -886,34 +1030,47 @@ static void die__process_function(Dwarf_Die *die, struct ftype *ftype, die = &child; do { + long id = -1; + struct tag *tag; + switch (dwarf_tag(die)) { case DW_TAG_formal_parameter: - die__create_new_parameter(die, ftype, lexblock); - continue; - case DW_TAG_variable: { - struct tag *tag = die__create_new_variable(die); + tag = die__create_new_parameter(die, ftype, lexblock); + break; + case DW_TAG_variable: + tag = die__create_new_variable(die); lexblock__add_variable(lexblock, tag__variable(tag)); - } - continue; + break; case DW_TAG_unspecified_parameters: if (ftype != NULL) ftype->unspec_parms = 1; continue; case DW_TAG_label: - die__create_new_label(die, lexblock); - continue; + tag = die__create_new_label(die, lexblock); + break; case DW_TAG_inlined_subroutine: - die__create_new_inline_expansion(die, lexblock); - continue; + tag = die__create_new_inline_expansion(die, lexblock); + break; case DW_TAG_lexical_block: die__create_new_lexblock(die, cu, lexblock); continue; - default: { - struct tag *tag = die__process_tag(die, cu); - if (tag != NULL) - cu__add_tag(cu, tag); - } + default: + tag = die__process_tag(die, cu, 0); + if (tag == NULL) + oom("die__process_function"); + + if (cu__add_tag(cu, tag, &id) < 0) + oom("die__process_function"); + + goto hash; } + + if (cu__table_add_tag(cu, tag, &id) < 0) + oom("die__process_function"); +hash: + cu__hash(cu, tag); + struct dwarf_tag *dtag = tag->priv; + dtag->small_id = id; } while (dwarf_siblingof(die, die) == 0); } @@ -928,55 +1085,447 @@ static struct tag *die__create_new_function(Dwarf_Die *die, struct cu *cu) } static struct tag *__die__process_tag(Dwarf_Die *die, struct cu *cu, - const char *fn) + int top_level, const char *fn) { + struct tag *tag; + switch (dwarf_tag(die)) { case DW_TAG_array_type: - return die__create_new_array(die); + tag = die__create_new_array(die); break; case DW_TAG_base_type: - return die__create_new_base_type(die); + tag = die__create_new_base_type(die); break; case DW_TAG_const_type: case DW_TAG_imported_declaration: case DW_TAG_imported_module: case DW_TAG_pointer_type: case DW_TAG_reference_type: case DW_TAG_volatile_type: - return die__create_new_tag(die); + tag = die__create_new_tag(die); break; case DW_TAG_ptr_to_member_type: - return die__create_new_ptr_to_member_type(die); + tag = die__create_new_ptr_to_member_type(die); break; case DW_TAG_enumeration_type: - return die__create_new_enumeration(die, cu); + tag = die__create_new_enumeration(die); break; case DW_TAG_namespace: - return die__create_new_namespace(die, cu); + tag = die__create_new_namespace(die, cu); break; case DW_TAG_class_type: case DW_TAG_structure_type: - return die__create_new_class(die, cu); + tag = die__create_new_class(die, cu); break; case DW_TAG_subprogram: - return die__create_new_function(die, cu); + tag = die__create_new_function(die, cu); break; case DW_TAG_subroutine_type: - return die__create_new_subroutine_type(die, cu); + tag = die__create_new_subroutine_type(die, cu); break; case DW_TAG_typedef: - return die__create_new_typedef(die); + tag = die__create_new_typedef(die); break; case DW_TAG_union_type: - return die__create_new_union(die, cu); + tag = die__create_new_union(die, cu); break; case DW_TAG_variable: - return die__create_new_variable(die); + tag = die__create_new_variable(die); break; default: __cu__tag_not_handled(die, fn); + tag = NULL; + break; } - return NULL; + if (tag != NULL) + tag->top_level = top_level; + + return tag; } static void die__process_unit(Dwarf_Die *die, struct cu *cu) { do { - struct tag *tag = die__process_tag(die, cu); - if (tag != NULL) - cu__add_tag(cu, tag); + struct tag *tag = die__process_tag(die, cu, 1); + if (tag != NULL) { + long id = -1; + cu__add_tag(cu, tag, &id); + cu__hash(cu, tag); + struct dwarf_tag *dtag = tag->priv; + dtag->small_id = id; + + } } while (dwarf_siblingof(die, die) == 0); } +static void __tag__print_type_not_found(struct tag *self, const char *func) +{ + struct dwarf_tag *dtag = self->priv; + fprintf(stderr, "%s: couldn't find %#llx type for %#llx (%s)!\n", func, + (unsigned long long)dtag->type, (unsigned long long)dtag->id, + dwarf_tag_name(self->tag)); +} + +#define tag__print_type_not_found(self) \ + __tag__print_type_not_found(self, __func__) + +static void ftype__recode_dwarf_types(struct tag *self, struct cu *cu); + +static void namespace__recode_dwarf_types(struct tag *self, struct cu *cu) +{ + struct tag *pos; + struct dwarf_cu *dcu = cu->priv; + struct namespace *ns = tag__namespace(self); + + namespace__for_each_tag(ns, pos) { + struct dwarf_tag *dtype; + struct dwarf_tag *dpos = pos->priv; + + if (tag__has_namespace(pos)) { + namespace__recode_dwarf_types(pos, cu); + continue; + } + + switch (pos->tag) { + case DW_TAG_subroutine_type: + case DW_TAG_subprogram: + ftype__recode_dwarf_types(pos, cu); + break; + case DW_TAG_imported_module: + dtype = dwarf_cu__find_tag_by_id(dcu, dpos->type); + goto check_type; + /* Can be for both types and non types */ + case DW_TAG_imported_declaration: + dtype = dwarf_cu__find_tag_by_id(dcu, dpos->type); + if (dtype != NULL) + goto next; + goto find_type; + } + + if (dpos->type == 0) /* void */ + continue; +find_type: + dtype = dwarf_cu__find_type_by_id(dcu, dpos->type); +check_type: + if (dtype == NULL) { + tag__print_type_not_found(pos); + continue; + } +next: + pos->type = dtype->small_id; + } +} + +static void type__recode_dwarf_specification(struct tag *self, struct cu *cu) +{ + struct dwarf_tag *dtype; + struct type *t = tag__type(self); + + if (t->namespace.name != 0 || t->specification == 0) + return; + + dtype = dwarf_cu__find_type_by_id(cu->priv, t->specification); + if (dtype != NULL) + t->namespace.name = tag__namespace(dtype->tag)->name; + else { + struct dwarf_tag *dtag = self->priv; + + fprintf(stderr, + "%s: couldn't find name for " + "class %#llx, specification=%#llx\n", __func__, + (unsigned long long)dtag->id, + (unsigned long long)t->specification); + } +} + +static void __tag__print_abstract_origin_not_found(struct tag *self, + unsigned long long abstract_origin, + const char *func) +{ + struct dwarf_tag *dtag = self->priv; + fprintf(stderr, + "%s: couldn't find %#llx abstract_origin for %#llx (%s)!\n", + func, abstract_origin, (unsigned long long)dtag->id, + dwarf_tag_name(self->tag)); +} + +#define tag__print_abstract_origin_not_found(self, abstract_origin) \ + __tag__print_abstract_origin_not_found(self, abstract_origin, __func__) + +static void ftype__recode_dwarf_types(struct tag *self, struct cu *cu) +{ + struct parameter *pos; + struct dwarf_cu *dcu = cu->priv; + struct ftype *type = tag__ftype(self); + + ftype__for_each_parameter(type, pos) { + struct dwarf_tag *dpos = pos->tag.priv; + struct dwarf_tag *dtype; + + if (dpos->type == 0) { + if (pos->abstract_origin == 0) { + /* Function without parameters */ + pos->tag.type = 0; + continue; + } + dtype = dwarf_cu__find_tag_by_id(dcu, pos->abstract_origin); + if (dtype == NULL) { + tag__print_abstract_origin_not_found(&pos->tag, + pos->abstract_origin); + continue; + } + pos->name = tag__parameter(dtype->tag)->name; + pos->tag.type = dtype->tag->type; + continue; + } + + dtype = dwarf_cu__find_type_by_id(dcu, dpos->type); + if (dtype == NULL) { + tag__print_type_not_found(&pos->tag); + continue; + } + pos->tag.type = dtype->small_id; + } +} + +static void lexblock__recode_dwarf_types(struct lexblock *self, struct cu *cu) +{ + struct tag *pos; + struct dwarf_cu *dcu = cu->priv; + + list_for_each_entry(pos, &self->tags, node) { + struct dwarf_tag *dpos = pos->priv; + struct dwarf_tag *dtype; + + switch (pos->tag) { + case DW_TAG_lexical_block: + lexblock__recode_dwarf_types(tag__lexblock(pos), cu); + continue; + case DW_TAG_inlined_subroutine: + dtype = dwarf_cu__find_tag_by_id(dcu, dpos->type); + if (dtype == NULL) { + tag__print_type_not_found(pos); + continue; + } + ftype__recode_dwarf_types(dtype->tag, cu); + continue; + + case DW_TAG_formal_parameter: + if (dpos->type != 0) + break; + + struct parameter *fp = tag__parameter(pos); + dtype = dwarf_cu__find_tag_by_id(dcu, + fp->abstract_origin); + if (dtype == NULL) { + tag__print_abstract_origin_not_found(pos, + fp->abstract_origin); + continue; + } + fp->name = tag__parameter(dtype->tag)->name; + pos->type = dtype->tag->type; + continue; + + case DW_TAG_variable: + if (dpos->type != 0) + break; + + struct variable *var = tag__variable(pos); + + if (var->abstract_origin == 0) { + /* + * DW_TAG_variable completely empty was + * found on libQtGui.so.4.3.4.debug + * <3>: Abbrev Number: 164 (DW_TAG_variable) + */ + continue; + } + + dtype = dwarf_cu__find_tag_by_id(dcu, + var->abstract_origin); + if (dtype == NULL) { + tag__print_abstract_origin_not_found(pos, + var->abstract_origin); + continue; + } + var->name = tag__variable(dtype->tag)->name; + pos->type = dtype->tag->type; + continue; + + case DW_TAG_label: { + struct label *l = tag__label(pos); + + if (l->abstract_origin == 0) + continue; + + dtype = dwarf_cu__find_tag_by_id(dcu, l->abstract_origin); + if (dtype != NULL) + l->name = tag__label(dtype->tag)->name; + else + tag__print_abstract_origin_not_found(pos, + l->abstract_origin); + } + continue; + } + + dtype = dwarf_cu__find_type_by_id(dcu, dpos->type); + if (dtype == NULL) { + tag__print_type_not_found(pos); + continue; + } + pos->type = dtype->small_id; + } +} + +static void tag__recode_dwarf_type(struct tag *self, struct cu *cu) +{ + struct dwarf_tag *dtag = self->priv; + struct dwarf_tag *dtype; + + if (tag__is_type(self)) + type__recode_dwarf_specification(self, cu); + + if (tag__has_namespace(self)) { + namespace__recode_dwarf_types(self, cu); + return; + } + + switch (self->tag) { + case DW_TAG_subprogram: { + struct function *fn = tag__function(self); + + if (fn->name == 0) { + if (fn->abstract_origin == 0 && + fn->specification == 0) { + /* + * Found on libQtGui.so.4.3.4.debug + * <3><1423de>: Abbrev Number: 209 (DW_TAG_subprogram) + * <1423e0> DW_AT_declaration : 1 + */ + return; + } + dtype = dwarf_cu__find_tag_by_id(cu->priv, fn->abstract_origin); + if (dtype == NULL) + dtype = dwarf_cu__find_tag_by_id(cu->priv, fn->specification); + if (dtype != NULL) + fn->name = tag__function(dtype->tag)->name; + else { + fprintf(stderr, + "%s: couldn't find name for " + "function %#llx, abstract_origin=%#llx," + " specification=%#llx\n", __func__, + (unsigned long long)dtag->id, + (unsigned long long)fn->abstract_origin, + (unsigned long long)fn->specification); + } + } + lexblock__recode_dwarf_types(&fn->lexblock, cu); + } + /* Fall thru */ + + case DW_TAG_subroutine_type: + ftype__recode_dwarf_types(self, cu); + /* Fall thru, for the function return type */ + break; + + case DW_TAG_lexical_block: + lexblock__recode_dwarf_types(tag__lexblock(self), cu); + return; + + case DW_TAG_ptr_to_member_type: { + struct ptr_to_member_type *pt = tag__ptr_to_member_type(self); + + dtype = dwarf_cu__find_type_by_id(cu->priv, pt->containing_type); + if (dtype != NULL) + pt->containing_type = dtype->small_id; + else { + fprintf(stderr, + "%s: couldn't find type for " + "containing_type %#llx, containing_type=%#llx\n", + __func__, + (unsigned long long)dtag->id, + (unsigned long long)pt->containing_type); + } + } + break; + + case DW_TAG_namespace: + namespace__recode_dwarf_types(self, cu); + return; + /* Damn, DW_TAG_inlined_subroutine is an special case + as dwarf_tag->id is in fact an abtract origin, i.e. must be + looked up in the tags_table, not in the types_table. + The others also point to routines, so are in tags_table */ + case DW_TAG_inlined_subroutine: + case DW_TAG_imported_module: + dtype = dwarf_cu__find_tag_by_id(cu->priv, dtag->type); + goto check_type; + /* Can be for both types and non types */ + case DW_TAG_imported_declaration: + dtype = dwarf_cu__find_tag_by_id(cu->priv, dtag->type); + if (dtype != NULL) + goto out; + goto find_type; + } + + if (dtag->type == 0) { + self->type = 0; /* void */ + return; + } + +find_type: + dtype = dwarf_cu__find_type_by_id(cu->priv, dtag->type); +check_type: + if (dtype == NULL) { + tag__print_type_not_found(self); + return; + } +out: + self->type = dtype->small_id; +} + +static void cu__recode_dwarf_types_table(struct cu *self, struct ptr_table *pt) +{ + uint32_t i; + + for (i = 1; i < pt->nr_entries; ++i) { + struct tag *tag = pt->entries[i]; + + if (tag != NULL) /* void, see cu__new */ + tag__recode_dwarf_type(tag, self); + } +} + +static void cu__recode_dwarf_types(struct cu *self) +{ + cu__recode_dwarf_types_table(self, &self->types_table); + cu__recode_dwarf_types_table(self, &self->tags_table); +} + +static const char *dwarf_tag__decl_file(const struct tag *self, + const struct cu *cu __unused) +{ + struct dwarf_tag *dtag = self->priv; + return dtag ? strings__ptr(strings, dtag->decl_file) : NULL; +} + +static uint32_t dwarf_tag__decl_line(const struct tag *self, + const struct cu *cu __unused) +{ + struct dwarf_tag *dtag = self->priv; + return dtag ? dtag->decl_line : 0; +} + +static unsigned long long dwarf_tag__orig_id(const struct tag *self, + const struct cu *cu __unused) +{ + struct dwarf_tag *dtag = self->priv; + return dtag ? dtag->id : 0; +} + +static unsigned long long dwarf_tag__orig_type(const struct tag *self, + const struct cu *cu __unused) +{ + struct dwarf_tag *dtag = self->priv; + return dtag ? dtag->type : 0; +} + +static struct cu_orig_info dwarf_orig_info_ops = { + .tag__decl_file = dwarf_tag__decl_file, + .tag__decl_line = dwarf_tag__decl_line, + .tag__orig_id = dwarf_tag__orig_id, + .tag__orig_type = dwarf_tag__orig_type, +}; + static void die__process(Dwarf_Die *die, struct cu *cu) { Dwarf_Die child; @@ -990,6 +1539,12 @@ static void die__process(Dwarf_Die *die, struct cu *cu) cu->language = attr_numeric(die, DW_AT_language); + struct dwarf_cu dcu; + + dwarf_cu__init(&dcu); + cu->priv = &dcu; + cu->orig_info = &dwarf_orig_info_ops; + if (dwarf_child(die, &child) == 0) die__process_unit(&child, cu); @@ -997,6 +1552,8 @@ static void die__process(Dwarf_Die *die, struct cu *cu) fprintf(stderr, "%s: got %s unexpected tag after " "DW_TAG_compile_unit!\n", __FUNCTION__, dwarf_tag_name(tag)); + + cu__recode_dwarf_types(cu); } static void cus__load_module(struct cus *self, Dwfl_Module *mod, Dwarf *dw) diff --git a/dwarves.c b/dwarves.c index 8c13610..57bf37c 100644 --- a/dwarves.c +++ b/dwarves.c @@ -25,14 +25,11 @@ #include "config.h" #include "ctf_loader.h" #include "dwarf_loader.h" -#include "hash.h" #include "list.h" #include "dwarves.h" #include "dutil.h" #include "strings.h" -#define hashtags__fn(key) hash_64(key, HASHTAGS__BITS) - struct strings *strings; static inline const char *s(strings_t i) @@ -191,11 +188,12 @@ static size_t __tag__id_not_found_fprintf(FILE *fp, Dwarf_Off id, #define tag__id_not_found_fprintf(fp, id) \ __tag__id_not_found_fprintf(fp, id, __func__) -size_t tag__fprintf_decl_info(const struct tag *self, FILE *fp) +size_t tag__fprintf_decl_info(const struct tag *self, + const struct cu *cu, FILE *fp) { - return fprintf(fp, "/* <%llx> %s:%u */\n", - (unsigned long long)self->id, - s(self->decl_file), self->decl_line); + return fprintf(fp, "/* <%llx> %s:%u */\n", tag__orig_id(self, cu), + tag__decl_file(self, cu), tag__decl_line(self, cu)); + return 0; } static size_t type__fprintf(struct tag *type, const struct cu *cu, @@ -237,22 +235,8 @@ void namespace__delete(struct namespace *self) tag__delete(&self->tag); } -const char *type__name(struct type *self, const struct cu *cu) +const char *type__name(struct type *self, const struct cu *cu __unused) { - /* Check if the tag doesn't comes with a DW_AT_name attribute... */ - if (!self->namespace.name && - /* No? So it can have a DW_TAG_specification... */ - self->specification != 0 && - cu != NULL) { - struct tag *tag = cu__find_type_by_id(cu, self->specification); - if (tag == NULL) { - tag__id_not_found_fprintf(stderr, self->specification); - return NULL; - } - /* ... and now we cache the result in this tag ->name field */ - self->namespace.name = tag__type(tag)->namespace.name; - } - return s(self->namespace.name); } @@ -293,11 +277,10 @@ reevaluate: case DW_TAG_const_type: case DW_TAG_typedef: case DW_TAG_volatile_type: { - const struct tag *tag = type; - - type = cu__find_type_by_id(cu, type->id); + struct tag *tag = type; + type = cu__find_type_by_id(cu, tag->type); if (type == NULL) { - tag__id_not_found_fprintf(stderr, tag->id); + tag__id_not_found_fprintf(stderr, tag->type); continue; } } @@ -440,6 +423,93 @@ void cus__add(struct cus *self, struct cu *cu) { list_add_tail(&cu->node, &self->cus); } + +static void ptr_table__init(struct ptr_table *self) +{ + self->entries = NULL; + self->nr_entries = self->allocated_entries = 0; +} + +static void ptr_table__exit(struct ptr_table *self) +{ + free(self->entries); + self->entries = NULL; +} + +static long ptr_table__add(struct ptr_table *self, void *ptr) +{ + const uint32_t nr_entries = self->nr_entries + 1; + const long rc = self->nr_entries; + + if (nr_entries > self->allocated_entries) { + uint32_t allocated_entries = self->allocated_entries + 256; + void *entries = realloc(self->entries, + sizeof(void *) * allocated_entries); + if (entries == NULL) + return -ENOMEM; + + self->allocated_entries = allocated_entries; + self->entries = entries; + } + + self->entries[rc] = ptr; + self->nr_entries = nr_entries; + return rc; +} + +static int ptr_table__add_with_id(struct ptr_table *self, void *ptr, + uint32_t id) +{ + /* Assume we won't be fed with the same id more than once */ + if (id >= self->allocated_entries) { + uint32_t allocated_entries = roundup(id + 1, 256); + void *entries = realloc(self->entries, + sizeof(void *) * allocated_entries); + if (entries == NULL) + return -ENOMEM; + + self->allocated_entries = allocated_entries; + self->entries = entries; + } + + self->entries[id] = ptr; + ++self->nr_entries; + return 0; +} + +static void *ptr_table__entry(const struct ptr_table *self, uint32_t id) +{ + return id >= self->nr_entries ? NULL : self->entries[id]; +} + +int cu__table_add_tag(struct cu *self, struct tag *tag, long *id) +{ + struct ptr_table *pt = tag__is_tag_type(tag) ? + &self->types_table : + &self->tags_table; + if (*id < 0) { + *id = ptr_table__add(pt, tag); + if (*id < 0) + return -ENOMEM; + } else if (ptr_table__add_with_id(pt, tag, *id) < 0) + return -ENOMEM; + return 0; +} + +int cu__table_nullify_type_entry(struct cu *self, uint32_t id) +{ + return ptr_table__add_with_id(&self->types_table, NULL, id); +} + +int cu__add_tag(struct cu *self, struct tag *tag, long *id) +{ + int err = cu__table_add_tag(self, tag, id); + + if (err == 0) + list_add_tail(&tag->node, &self->tags); + + return err; +} struct cu *cu__new(const char *name, uint8_t addr_size, const unsigned char *build_id, @@ -448,17 +518,23 @@ struct cu *cu__new(const char *name, uint8_t addr_size, struct cu *self = malloc(sizeof(*self) + build_id_len); if (self != NULL) { - uint32_t i; + self->name = strdup(name); + if (self->name == NULL) + goto out_free; - for (i = 0; i < HASHTAGS__SIZE; ++i) { - INIT_HLIST_HEAD(&self->hash_tags[i]); - INIT_HLIST_HEAD(&self->hash_types[i]); - } + ptr_table__init(&self->tags_table); + ptr_table__init(&self->types_table); + /* + * the first entry is historically associated with void, + * so make sure we don't use it + */ + if (ptr_table__add(&self->types_table, NULL) < 0) + goto out_free_name; + self->orig_info = NULL; INIT_LIST_HEAD(&self->tags); INIT_LIST_HEAD(&self->tool_list); - self->name = strdup(name); self->addr_size = addr_size; self->nr_inline_expansions = 0; @@ -472,8 +548,14 @@ struct cu *cu__new(const char *name, uint8_t addr_size, if (build_id_len > 0) memcpy(self->build_id, build_id, build_id_len); } - +out: return self; +out_free_name: + free(self->name); +out_free: + free(self); + self = NULL; + goto out; } void cu__delete(struct cu *self) @@ -487,49 +569,12 @@ void cu__delete(struct cu *self) if (tag__has_namespace(pos)) namespace__delete(tag__namespace(pos)); } + + ptr_table__exit(&self->tags_table); + ptr_table__exit(&self->types_table); free(self); } -static void hashtags__hash(struct hlist_head *hashtable, struct tag *tag) -{ - struct hlist_head *head = hashtable + hashtags__fn(tag->id); - - hlist_add_head(&tag->hash_node, head); -} - -static struct tag *hashtags__find(const struct hlist_head *hashtable, - const Dwarf_Off id) -{ - struct tag *tpos; - struct hlist_node *pos; - const struct hlist_head *head; - - if (id == 0) - return NULL; - - head = hashtable + hashtags__fn(id); - - hlist_for_each_entry(tpos, pos, head, hash_node) - if (tpos->id == id) - return tpos; - - return NULL; -} - -void cu__hash(struct cu *self, struct tag *tag) -{ - struct hlist_head *hashtable = tag__is_tag_type(tag) ? - self->hash_types : - self->hash_tags; - hashtags__hash(hashtable, tag); -} - -void cu__add_tag(struct cu *self, struct tag *tag) -{ - list_add_tail(&tag->node, &self->tags); - cu__hash(self, tag); -} - bool cu__same_build_id(const struct cu *self, const struct cu *other) { return self->build_id_len != 0 && @@ -553,90 +598,118 @@ static const char *tag__prefix(const struct cu *cu, const uint32_t tag) return ""; } -struct tag *cu__find_tag_by_id(const struct cu *self, const Dwarf_Off id) +struct tag *cu__find_tag_by_id(const struct cu *self, const uint32_t id) { - return self ? hashtags__find(self->hash_tags, id) : NULL; + return self ? ptr_table__entry(&self->tags_table, id) : NULL; } -struct tag *cu__find_type_by_id(const struct cu *self, const Dwarf_Off id) +struct tag *cu__find_type_by_id(const struct cu *self, const uint16_t id) { - return self ? hashtags__find(self->hash_types, id) : NULL; + return self ? ptr_table__entry(&self->types_table, id) : NULL; } struct tag *cu__find_first_typedef_of_type(const struct cu *self, const Dwarf_Off type) { + uint16_t id; struct tag *pos; if (self == NULL || type == 0) return NULL; - list_for_each_entry(pos, &self->tags, node) + cu__for_each_type(self, id, pos) if (tag__is_typedef(pos) && pos->type == type) return pos; return NULL; } -struct tag *cu__find_base_type_by_name(const struct cu *self, const char *name) +struct tag *cu__find_base_type_by_name(const struct cu *self, + const char *name, uint16_t *idp) { + uint16_t id; struct tag *pos; if (self == NULL || name == NULL) return NULL; - list_for_each_entry(pos, &self->tags, node) + strings_t sname = strings__find(strings, name); + if (sname == 0) + return NULL; + + cu__for_each_type(self, id, pos) { if (pos->tag == DW_TAG_base_type) { const struct base_type *bt = tag__base_type(pos); - if (bt->name && strcmp(s(bt->name), name) == 0) + if (bt->name == sname) { + if (idp != NULL) + *idp = id; return pos; + } } + } return NULL; } struct tag *cu__find_base_type_by_name_and_size(const struct cu *self, const char *name, - size_t bit_size) + size_t bit_size, + uint16_t *idp) { + uint16_t id; struct tag *pos; if (self == NULL || name == NULL) return NULL; - list_for_each_entry(pos, &self->tags, node) + strings_t sname = strings__find(strings, name); + if (sname == 0) + return NULL; + + cu__for_each_type(self, id, pos) { if (pos->tag == DW_TAG_base_type) { const struct base_type *bt = tag__base_type(pos); if (bt->bit_size == bit_size && - bt->name && strcmp(s(bt->name), name) == 0) + bt->name == sname) { + if (idp != NULL) + *idp = id; return pos; + } } + } return NULL; } struct tag *cu__find_struct_by_name(const struct cu *self, const char *name, - const int include_decls) + const int include_decls, uint16_t *idp) { + uint16_t id; struct tag *pos; if (self == NULL || name == NULL) return NULL; - list_for_each_entry(pos, &self->tags, node) { + strings_t sname = strings__find(strings, name); + if (sname == 0) + return NULL; + + cu__for_each_type(self, id, pos) { struct type *type; if (!tag__is_struct(pos)) continue; type = tag__type(pos); - if (type__name(type, self) != NULL && - strcmp(type__name(type, self), name) == 0) { + if (type->namespace.name == sname) { if (type->declaration) { - if (include_decls) + if (include_decls) { + if (idp != NULL) + *idp = id; return pos; + } } else return pos; } @@ -647,13 +720,14 @@ struct tag *cu__find_struct_by_name(const struct cu *self, const char *name, struct tag *cus__find_struct_by_name(const struct cus *self, struct cu **cu, const char *name, - const int include_decls) + const int include_decls, uint16_t *id) { struct cu *pos; list_for_each_entry(pos, &self->cus, node) { struct tag *tag = cu__find_struct_by_name(pos, name, - include_decls); + include_decls, + id); if (tag != NULL) { if (cu != NULL) *cu = pos; @@ -733,98 +807,6 @@ struct tag *cu__find_function_by_name(const struct cu *self, const char *name) return NULL; } -static struct tag *lexblock__find_tag_by_id(const struct lexblock *self, - const Dwarf_Off id) -{ - struct tag *pos; - - list_for_each_entry(pos, &self->tags, node) { - /* Allow find DW_TAG_lexical_block tags */ - if (pos->id == id) - return pos; - /* - * Oh, not looking for DW_TAG_lexical_block tags? So lets look - * inside this lexblock: - */ - if (pos->tag == DW_TAG_lexical_block) { - const struct lexblock *child = tag__lexblock(pos); - struct tag *tag = lexblock__find_tag_by_id(child, id); - - if (tag != NULL) - return tag; - } - } - - return NULL; -} - -static struct variable *cu__find_variable_by_id(const struct cu *self, - const Dwarf_Off id) -{ - struct tag *pos; - - if (self == NULL) - return NULL; - - list_for_each_entry(pos, &self->tags, node) { - /* Look at global variables first */ - if (pos->id == id) - return (struct variable *)(pos); - - /* Now look inside function lexical blocks */ - if (pos->tag == DW_TAG_subprogram) { - struct function *fn = tag__function(pos); - struct tag *tag = - lexblock__find_tag_by_id(&fn->lexblock, id); - - if (tag != NULL) - return (struct variable *)(tag); - } - } - - return NULL; -} - -static struct tag *list__find_tag_by_id(const struct list_head *self, - const Dwarf_Off id) -{ - struct tag *pos, *tag; - - list_for_each_entry(pos, self, node) { - if (pos->id == id) - return pos; - - switch (pos->tag) { - case DW_TAG_namespace: - case DW_TAG_class_type: - case DW_TAG_structure_type: - case DW_TAG_union_type: - tag = list__find_tag_by_id(&tag__namespace(pos)->tags, id); - break; - case DW_TAG_subprogram: - tag = list__find_tag_by_id(&tag__ftype(pos)->parms, id); - if (tag == NULL) - tag = list__find_tag_by_id(&tag__function(pos)->lexblock.tags, id); - break; - default: - continue; - } - - if (tag != NULL) - return tag; - } - - return NULL; -} - -static struct tag *cu__find_parameter_by_id(const struct cu *self, - const Dwarf_Off id) -{ - if (self == NULL) - return NULL; - return list__find_tag_by_id(&self->tags, id); -} - static size_t array_type__nr_entries(const struct array_type *self) { int i; @@ -978,14 +960,14 @@ const char *tag__name(const struct tag *self, const struct cu *cu, static struct tag *variable__type(const struct variable *self, const struct cu *cu) { - struct variable *var; + struct tag *var; if (self->tag.type != 0) return cu__find_type_by_id(cu, self->tag.type); else if (self->abstract_origin != 0) { - var = cu__find_variable_by_id(cu, self->abstract_origin); + var = cu__find_tag_by_id(cu, self->abstract_origin); if (var) - return variable__type(var, cu); + return variable__type(tag__variable(var), cu); } return NULL; @@ -1005,10 +987,10 @@ const char *variable__name(const struct variable *self, const struct cu *cu) return s(self->name); if (self->abstract_origin != 0) { - struct variable *var = - cu__find_variable_by_id(cu, self->abstract_origin); + struct tag *var = + cu__find_tag_by_id(cu, self->abstract_origin); if (var != NULL) - return s(var->name); + return s(tag__variable(var)->name); } return NULL; } @@ -1059,40 +1041,13 @@ size_t class_member__size(const struct class_member *self, return tag__size(type, cu); } -const char *parameter__name(struct parameter *self, const struct cu *cu) +const char *parameter__name(struct parameter *self, const struct cu *cu __unused) { - /* Check if the tag doesn't comes with a DW_AT_name attribute... */ - if (!self->name && self->abstract_origin != 0) { - /* No? Does it have a DW_AT_abstract_origin? */ - struct tag *alias = - cu__find_parameter_by_id(cu, self->abstract_origin); - if (alias == NULL) { - tag__id_not_found_fprintf(stderr, self->abstract_origin); - return NULL; - } - /* Now cache the result in this tag ->name field */ - self->name = tag__parameter(alias)->name; - } - return s(self->name); } -Dwarf_Off parameter__type(struct parameter *self, const struct cu *cu) +Dwarf_Off parameter__type(struct parameter *self, const struct cu *cu __unused) { - /* Check if the tag doesn't comes with a DW_AT_type attribute... */ - if (self->tag.type == 0 && self->abstract_origin != 0) { - /* No? Does it have a DW_AT_abstract_origin? */ - struct tag *alias = - cu__find_parameter_by_id(cu, self->abstract_origin); - if (alias == NULL) { - tag__id_not_found_fprintf(stderr, self->abstract_origin); - return 0; - } - /* Now cache the result in this tag ->name and type fields */ - self->name = tag__parameter(alias)->name; - self->tag.type = tag__parameter(alias)->tag.type; - } - return self->tag.type; } @@ -1476,25 +1431,8 @@ void lexblock__add_lexblock(struct lexblock *self, struct lexblock *child) list_add_tail(&child->tag.node, &self->tags); } -const char *function__name(struct function *self, const struct cu *cu) +const char *function__name(struct function *self, const struct cu *cu __unused) { - /* Check if the tag doesn't comes with a DW_AT_name attribute... */ - if (!self->name) { - /* No? So it must have a DW_AT_abstract_origin... */ - struct tag *tag = cu__find_tag_by_id(cu, - self->abstract_origin); - if (tag == NULL) { - /* ... or a DW_TAG_specification... */ - tag = cu__find_tag_by_id(cu, self->specification); - if (tag == NULL) { - tag__id_not_found_fprintf(stderr, self->specification); - return NULL; - } - } - /* ... and now we cache the result in this tag ->name field */ - self->name = tag__function(tag)->name; - } - return s(self->name); } @@ -1512,7 +1450,7 @@ const char *function__prototype(const struct function *self, return bf; } -int ftype__has_parm_of_type(const struct ftype *self, const struct tag *target, +int ftype__has_parm_of_type(const struct ftype *self, const uint16_t target, const struct cu *cu) { struct parameter *pos; @@ -1522,8 +1460,7 @@ int ftype__has_parm_of_type(const struct ftype *self, const struct tag *target, cu__find_type_by_id(cu, parameter__type(pos, cu)); if (type != NULL && type->tag == DW_TAG_pointer_type) { - type = cu__find_type_by_id(cu, type->type); - if (type != NULL && type->id == target->id) + if (type->type == target) return 1; } } @@ -1779,7 +1716,9 @@ static size_t ftype__fprintf_parms(const struct ftype *self, name = parameter__name(pos, cu); type = cu__find_type_by_id(cu, parameter__type(pos, cu)); if (type == NULL) { - stype = ""; + snprintf(sbf, sizeof(sbf), + "", pos->tag.type); + stype = sbf; goto print_it; } if (type->tag == DW_TAG_pointer_type) { @@ -1886,14 +1825,13 @@ static size_t function__tag_fprintf(const struct tag *tag, const struct cu *cu, default: printed = fprintf(fp, "%.*s", indent, tabs); n = fprintf(fp, "%s <%llx>", dwarf_tag_name(tag->tag), - (unsigned long long)tag->id); + tag__orig_id(tag, cu)); c += n; printed += n; break; } - return printed + fprintf(fp, "%-*.*s// %5u\n", 70 - c, 70 - c, " ", - tag->decl_line); + tag__decl_line(tag, cu)); } size_t lexblock__fprintf(const struct lexblock *self, const struct cu *cu, @@ -2452,7 +2390,7 @@ size_t tag__fprintf(struct tag *self, const struct cu *cu, if (pconf->show_decl_info) { printed += fprintf(fp, "%.*s", pconf->indent, tabs); - printed += tag__fprintf_decl_info(self, fp); + printed += tag__fprintf_decl_info(self, cu, fp); } printed += fprintf(fp, "%.*s", pconf->indent, tabs); @@ -2515,16 +2453,17 @@ size_t tag__fprintf(struct tag *self, const struct cu *cu, } int cu__for_each_tag(struct cu *self, - int (*iterator)(struct tag *tag, struct cu *cu, - void *cookie), + int (*iterator)(struct tag *tag, + struct cu *cu, void *cookie), void *cookie, - struct tag *(*filter)(struct tag *tag, struct cu *cu, - void *cookie)) + struct tag *(*filter)(struct tag *tag, + struct cu *cu, void *cookie)) { struct tag *pos; list_for_each_entry(pos, &self->tags, node) { struct tag *tag = pos; + if (filter != NULL) { tag = filter(pos, self, cookie); if (tag == NULL) diff --git a/dwarves.h b/dwarves.h index 5b5405f..e42234d 100644 --- a/dwarves.h +++ b/dwarves.h @@ -26,16 +26,66 @@ struct cus { struct cus *cus__new(void); -#define HASHTAGS__BITS 8 -#define HASHTAGS__SIZE (1UL << HASHTAGS__BITS) +struct ptr_table { + void **entries; + uint32_t nr_entries; + uint32_t allocated_entries; +}; + +/** + * cu__for_each_type - iterate thru all the type tags + * @cu: struct cu instance to iterate + * @pos: struct tag iterator + * @id: uint16_t tag id + * + * See cu__table_nullify_type_entry and users for the reason for + * the NULL test (hint: CTF Unknown types) + */ +#define cu__for_each_type(cu, id, pos) \ + for (id = 1, pos = cu->types_table.entries[id]; \ + id < cu->types_table.nr_entries; \ + pos = cu->types_table.entries[++id]) \ + if (pos == NULL) \ + continue; \ + else + +/** + * cu__for_each_function - iterate thru all the function tags + * @cu: struct cu instance to iterate + * @pos: struct function iterator + * @id: uint32_t tag id + */ +#define cu__for_each_function(cu, id, pos) \ + for (id = 0, pos = tag__function(cu->tags_table.entries[id]); \ + id < cu->tags_table.nr_entries; \ + pos = tag__function(cu->tags_table.entries[++id])) \ + if (pos->proto.tag.tag != DW_TAG_subprogram) \ + continue; \ + else + +struct tag; +struct cu; + +struct cu_orig_info { + const char *(*tag__decl_file)(const struct tag *self, + const struct cu *cu); + uint32_t (*tag__decl_line)(const struct tag *self, + const struct cu *cu); + unsigned long long (*tag__orig_id)(const struct tag *self, + const struct cu *cu); + unsigned long long (*tag__orig_type)(const struct tag *self, + const struct cu *cu); +}; struct cu { struct list_head node; struct list_head tags; - struct hlist_head hash_tags[HASHTAGS__SIZE]; - struct hlist_head hash_types[HASHTAGS__SIZE]; struct list_head tool_list; /* To be used by tools such as ctracer */ - const char *name; + struct ptr_table types_table; + struct ptr_table tags_table; + char *name; + void *priv; + struct cu_orig_info *orig_info; uint8_t addr_size; uint16_t language; unsigned long nr_inline_expansions; @@ -49,20 +99,18 @@ struct cu { unsigned char build_id[0]; }; -struct tag; - -void cu__hash(struct cu *cu, struct tag *tag); - +/** struct tag - basic representation of a debug info element + * @priv - extra data, for instance, DWARF offset, id, decl_{file,line} + * @top_level - + */ struct tag { struct list_head node; - struct hlist_node hash_node; - Dwarf_Off type; - Dwarf_Off id; - strings_t decl_file; - uint16_t decl_line; + uint16_t type; uint16_t tag; uint16_t visited:1; - uint16_t recursivity_level:15; + uint16_t top_level:1; + uint16_t recursivity_level; + void *priv; }; static inline int tag__is_enumeration(const struct tag *self) @@ -129,9 +177,28 @@ static inline int tag__is_tag_type(const struct tag *self) self->tag == DW_TAG_volatile_type; } -static inline const char *tag__decl_file(const struct tag *self) +static inline const char *tag__decl_file(const struct tag *self, + const struct cu *cu) { - return strings__ptr(strings, self->decl_file); + return cu->orig_info ? cu->orig_info->tag__decl_file(self, cu) : NULL; +} + +static inline uint32_t tag__decl_line(const struct tag *self, + const struct cu *cu) +{ + return cu->orig_info ? cu->orig_info->tag__decl_line(self, cu) : 0; +} + +static inline unsigned long long tag__orig_id(const struct tag *self, + const struct cu *cu) +{ + return cu->orig_info ? cu->orig_info->tag__orig_id(self, cu) : 0; +} + +static inline unsigned long long tag__orig_type(const struct tag *self, + const struct cu *cu) +{ + return cu->orig_info ? cu->orig_info->tag__orig_type(self, cu) : 0; } struct ptr_to_member_type { @@ -508,6 +575,11 @@ struct label { Dwarf_Off abstract_origin; }; +static inline struct label *tag__label(const struct tag *self) +{ + return (struct label *)self; +} + struct enumerator { struct tag tag; strings_t name; @@ -545,7 +617,8 @@ extern size_t enumeration__fprintf(const struct tag *tag_self, const struct conf_fprintf *conf, FILE *fp); extern size_t typedef__fprintf(const struct tag *tag_self, const struct cu *cu, const struct conf_fprintf *conf, FILE *fp); -extern size_t tag__fprintf_decl_info(const struct tag *self, FILE *fp); +size_t tag__fprintf_decl_info(const struct tag *self, + const struct cu *cu, FILE *fp); extern size_t tag__fprintf(struct tag *self, const struct cu *cu, const struct conf_fprintf *conf, FILE *fp); @@ -577,14 +650,17 @@ extern void cus__print_error_msg(const char *progname, const struct cus *cus, extern struct cu *cus__find_cu_by_name(const struct cus *self, const char *name); extern struct tag *cu__find_base_type_by_name(const struct cu *self, - const char *name); + const char *name, + uint16_t *id); struct tag *cu__find_base_type_by_name_and_size(const struct cu *self, const char *name, - size_t bit_size); + size_t bit_size, + uint16_t *id); extern struct tag *cus__find_struct_by_name(const struct cus *self, struct cu **cu, const char *name, - const int include_decls); + const int include_decls, + uint16_t *id); extern struct tag *cus__find_function_by_name(const struct cus *self, struct cu **cu, const char *name); @@ -595,15 +671,18 @@ struct cu *cu__new(const char *name, uint8_t addr_size, const unsigned char *build_id, int build_id_len); extern void cu__delete(struct cu *self); -void cu__add_tag(struct cu *self, struct tag *tag); +int cu__add_tag(struct cu *self, struct tag *tag, long *id); +int cu__table_add_tag(struct cu *self, struct tag *tag, long *id); +int cu__table_nullify_type_entry(struct cu *self, uint32_t id); extern struct tag *cu__find_tag_by_id(const struct cu *self, - const Dwarf_Off id); -struct tag *cu__find_type_by_id(const struct cu *self, const Dwarf_Off id); + const uint32_t id); +struct tag *cu__find_type_by_id(const struct cu *self, const uint16_t id); extern struct tag *cu__find_first_typedef_of_type(const struct cu *self, const Dwarf_Off type); extern struct tag *cu__find_struct_by_name(const struct cu *cu, const char *name, - const int include_decls); + const int include_decls, + uint16_t *id); extern bool cu__same_build_id(const struct cu *self, const struct cu *other); extern void cu__account_inline_expansions(struct cu *self); extern int cu__for_each_tag(struct cu *self, @@ -651,7 +730,7 @@ extern size_t ftype__fprintf(const struct ftype *self, const struct cu *cu, const int is_pointer, const int type_spacing, FILE *fp); extern int ftype__has_parm_of_type(const struct ftype *self, - const struct tag *target, + const uint16_t target, const struct cu *cu); void type__add_member(struct type *self, struct class_member *member); diff --git a/dwarves_reorganize.c b/dwarves_reorganize.c index c332f90..1b2475f 100644 --- a/dwarves_reorganize.c +++ b/dwarves_reorganize.c @@ -446,7 +446,8 @@ static void class__demote_bitfield_members(struct class *class, struct class_member *from, struct class_member *to, const struct base_type *old_type, - const struct base_type *new_type) + const struct base_type *new_type, + uint16_t new_type_id) { const uint8_t bit_diff = old_type->bit_size - new_type->bit_size; struct class_member *member = @@ -459,7 +460,7 @@ static void class__demote_bitfield_members(struct class *class, * Assume IA32 bitfield layout */ member->bit_offset -= bit_diff; - member->tag.type = new_type->tag.id; + member->tag.type = new_type_id; if (member == to) break; member->bit_hole = 0; @@ -467,7 +468,7 @@ static void class__demote_bitfield_members(struct class *class, } static struct tag *cu__find_base_type_of_size(const struct cu *cu, - const size_t size) + const size_t size, uint16_t *id) { const char *type_name, *type_name_alt = NULL; @@ -493,8 +494,8 @@ static struct tag *cu__find_base_type_of_size(const struct cu *cu, return NULL; } - struct tag *ret = cu__find_base_type_by_name(cu, type_name); - return ret ?: cu__find_base_type_by_name(cu, type_name_alt); + struct tag *ret = cu__find_base_type_by_name(cu, type_name, id); + return ret ?: cu__find_base_type_by_name(cu, type_name_alt, id); } static int class__demote_bitfields(struct class *class, const struct cu *cu, @@ -543,8 +544,10 @@ static int class__demote_bitfields(struct class *class, const struct cu *cu, if (bytes_needed == size) continue; + uint16_t new_type_id; old_type_tag = cu__find_type_by_id(cu, member->tag.type); - new_type_tag = cu__find_base_type_of_size(cu, bytes_needed); + new_type_tag = cu__find_base_type_of_size(cu, bytes_needed, + &new_type_id); if (new_type_tag == NULL) { fprintf(fp, "/* BRAIN FART ALERT! couldn't find a " @@ -562,7 +565,8 @@ static int class__demote_bitfields(struct class *class, const struct cu *cu, class__demote_bitfield_members(class, bitfield_head, member, tag__base_type(old_type_tag), - tag__base_type(new_type_tag)); + tag__base_type(new_type_tag), + new_type_id); new_size = class_member__size(member, cu); member->hole = size - new_size; if (member->hole != 0) @@ -593,8 +597,10 @@ static int class__demote_bitfields(struct class *class, const struct cu *cu, if (bytes_needed < size) { old_type_tag = cu__find_type_by_id(cu, member->tag.type); + uint16_t new_type_id; new_type_tag = - cu__find_base_type_of_size(cu, bytes_needed); + cu__find_base_type_of_size(cu, bytes_needed, + &new_type_id); tag__assert_search_result(old_type_tag); tag__assert_search_result(new_type_tag); @@ -608,7 +614,8 @@ static int class__demote_bitfields(struct class *class, const struct cu *cu, class__demote_bitfield_members(class, member, member, tag__base_type(old_type_tag), - tag__base_type(new_type_tag)); + tag__base_type(new_type_tag), + new_type_id); new_size = class_member__size(member, cu); member->hole = 0; /* @@ -667,7 +674,7 @@ restart: static void class__fixup_bitfield_types(struct class *self, struct class_member *from, struct class_member *to_before, - Dwarf_Off type) + uint16_t type) { struct class_member *member = list_prepare_entry(from, class__tags(self), tag.node); @@ -733,9 +740,11 @@ static void class__fixup_member_types(struct class *self, const struct cu *cu, const size_t size = class_member__size(bitfield_head, cu); if (real_size != size) { + uint16_t new_type_id; struct tag *new_type_tag = cu__find_base_type_of_size(cu, - real_size); + real_size, + &new_type_id); if (new_type_tag == NULL) { fprintf(stderr, "pahole: couldn't find" " a base_type of %d bytes!\n", @@ -744,7 +753,7 @@ static void class__fixup_member_types(struct class *self, const struct cu *cu, } class__fixup_bitfield_types(self, bitfield_head, pos, - new_type_tag->id); + new_type_id); fixup_was_done = 1; } } diff --git a/pahole.c b/pahole.c index f5f2786..551127e 100644 --- a/pahole.c +++ b/pahole.c @@ -63,9 +63,10 @@ struct structure { const struct cu *cu; uint32_t nr_files; uint32_t nr_methods; + uint16_t id; }; -static struct structure *structure__new(struct class *class, +static struct structure *structure__new(struct class *class, uint16_t id, const struct cu *cu) { struct structure *self = malloc(sizeof(*self)); @@ -75,6 +76,7 @@ static struct structure *structure__new(struct class *class, self->cu = cu; self->nr_files = 1; self->nr_methods = 0; + self->id = id; } return self; @@ -84,9 +86,10 @@ static void *structures__tree; static LIST_HEAD(structures__anonymous_list); static LIST_HEAD(structures__named_list); -static void structures__add_anonymous(struct class *class, const struct cu *cu) +static void structures__add_anonymous(struct class *class, uint16_t id, + const struct cu *cu) { - struct structure *str = structure__new(class, cu); + struct structure *str = structure__new(class, id, cu); if (str != NULL) list_add_tail(&str->node, &structures__anonymous_list); @@ -100,7 +103,8 @@ static int structure__compare(const void *a, const void *b) return strings__cmp(strings, *key, pos->class->type.namespace.name); } -static int structures__add_named(struct class *class, const struct cu *cu) +static int structures__add_named(struct class *class, uint16_t id, + const struct cu *cu) { struct structure *str; strings_t *s = tsearch(&class->type.namespace.name, &structures__tree, @@ -113,7 +117,7 @@ static int structures__add_named(struct class *class, const struct cu *cu) * calling structures__add_named */ assert(*s != class->type.namespace.name); - str = structure__new(class, cu); + str = structure__new(class, id, cu); if (str == NULL) return -ENOMEM; @@ -125,17 +129,15 @@ static int structures__add_named(struct class *class, const struct cu *cu) return 0; } -static int structures__add(struct class *class, const struct cu *cu) +static int structures__add(struct class *class, uint16_t id, + const struct cu *cu) { - /* Let it follow abstract_origin, etc */ - class__name(class, cu); - if (!class->type.namespace.name) { - structures__add_anonymous(class, cu); + structures__add_anonymous(class, id, cu); return 0; } - return structures__add_named(class, cu); + return structures__add_named(class, id, cu); } static struct structure *structures__find_anonymous(strings_t name) @@ -144,7 +146,7 @@ static struct structure *structures__find_anonymous(strings_t name) list_for_each_entry(pos, &structures__anonymous_list, node) { struct class *c = pos->class; - const struct tag *tdef = cu__find_first_typedef_of_type(pos->cu, class__tag(c)->id); + const struct tag *tdef = cu__find_first_typedef_of_type(pos->cu, pos->id); if (tdef == NULL) continue; @@ -225,7 +227,7 @@ static void class_formatter(struct structure *self) * affected. */ typedef_alias = cu__find_first_typedef_of_type(self->cu, - tag->id); + self->id); /* * If there is no typedefs for this anonymous struct it is * found just inside another struct, and in this case it'll @@ -265,7 +267,7 @@ static void print_packable_info(struct structure *pos) /* Anonymous struct? Try finding a typedef */ if (name == NULL) { const struct tag *tdef = - cu__find_first_typedef_of_type(pos->cu, t->id); + cu__find_first_typedef_of_type(pos->cu, pos->id); if (tdef != NULL) name = class__name(tag__class(tdef), pos->cu); @@ -278,7 +280,8 @@ static void print_packable_info(struct structure *pos) savings); else printf("%s(%d)%c%zd%c%zd%c%zd\n", - tag__decl_file(t), t->decl_line, + tag__decl_file(t, pos->cu), + tag__decl_line(t, pos->cu), separator, orig_size, separator, new_size, separator, @@ -391,7 +394,7 @@ static void class__chkdupdef(struct class *self, const struct cu *cu, } static struct tag *tag__filter(struct tag *tag, struct cu *cu, - void *cookie __unused) + uint16_t tag_id) { struct structure *str; struct class *class; @@ -401,6 +404,9 @@ static struct tag *tag__filter(struct tag *tag, struct cu *cu, if (!tag__is_struct(tag)) return NULL; + if (!tag->top_level) + return NULL; + class = tag__class(tag); name = class__name(class, cu); stname = class->type.namespace.name; @@ -414,7 +420,7 @@ static struct tag *tag__filter(struct tag *tag, struct cu *cu, if (class__exclude_prefix != NULL) { if (name == NULL) { const struct tag *tdef = - cu__find_first_typedef_of_type(cu, tag->id); + cu__find_first_typedef_of_type(cu, tag_id); if (tdef != NULL) { struct class *c = tag__class(tdef); @@ -422,7 +428,6 @@ static struct tag *tag__filter(struct tag *tag, struct cu *cu, stname = c->type.namespace.name; } } - if (name != NULL && strncmp(class__exclude_prefix, name, class__exclude_prefix_len) == 0) return NULL; @@ -431,7 +436,7 @@ static struct tag *tag__filter(struct tag *tag, struct cu *cu, if (class__include_prefix != NULL) { if (name == NULL) { const struct tag *tdef = - cu__find_first_typedef_of_type(cu, tag->id); + cu__find_first_typedef_of_type(cu, tag_id); if (tdef != NULL) { struct class *c = tag__class(tdef); @@ -439,7 +444,6 @@ static struct tag *tag__filter(struct tag *tag, struct cu *cu, stname = c->type.namespace.name; } } - if (name != NULL && strncmp(class__include_prefix, name, class__include_prefix_len) != 0) return NULL; @@ -447,8 +451,8 @@ static struct tag *tag__filter(struct tag *tag, struct cu *cu, if (decl_exclude_prefix != NULL && - (!tag->decl_file || - strncmp(decl_exclude_prefix, tag__decl_file(tag), + (!tag__decl_file(tag, cu) || + strncmp(decl_exclude_prefix, tag__decl_file(tag, cu), decl_exclude_prefix_len) == 0)) return NULL; @@ -473,26 +477,23 @@ static struct tag *tag__filter(struct tag *tag, struct cu *cu, return tag; } -static int unique_iterator(struct tag *tag, struct cu *cu, - void *cookie __unused) +static int cu_unique_iterator(struct cu *cu, void *cookie __unused) { - if (structures__add(tag__class(tag), cu)) { - fprintf(stderr, "pahole: not enough memory! " - "Continuing with partial results\n"); - return -1; - } - return 0; -} + uint16_t id; + struct tag *tag; -static int cu_unique_iterator(struct cu *cu, void *cookie) -{ if (defined_in) { - struct tag *tag = cu__find_struct_by_name(cu, class_name, 0); - + tag = cu__find_struct_by_name(cu, class_name, 0, &id); if (tag != NULL) puts(cu->name); - } else - return cu__for_each_tag(cu, unique_iterator, cookie, tag__filter); + } else { + cu__for_each_type(cu, id, tag) { + if (tag__filter(tag, cu, id) && + structures__add(tag__class(tag), id, cu)) + fprintf(stderr, "pahole: not enough memory! " + "Continuing with partial results\n"); + } + } return 0; } @@ -728,7 +729,7 @@ static char tab[128]; static void print_structs_with_pointer_to(const struct structure *s) { struct structure *pos_structure; - Dwarf_Off type; + uint16_t type; const char *class_name = class__name(s->class, s->cu); const struct cu *current_cu = NULL; @@ -737,13 +738,16 @@ static void print_structs_with_pointer_to(const struct structure *s) struct class_member *pos_member; if (pos_structure->cu != current_cu) { + uint16_t class_id; struct tag *class; - class = cu__find_struct_by_name(pos_structure->cu, class_name, 1); + class = cu__find_struct_by_name(pos_structure->cu, + class_name, 1, + &class_id); if (class == NULL) continue; current_cu = pos_structure->cu; - type = class->id; + type = class_id; } type__for_each_member(&c->type, pos_member) { @@ -760,7 +764,7 @@ static void print_structs_with_pointer_to(const struct structure *s) static void print_containers(const struct structure *s, int ident) { struct structure *pos; - const Dwarf_Off type = s->class->type.namespace.tag.id; + const uint16_t type = s->id; list_for_each_entry(pos, &structures__named_list, node) { struct class *c = pos->class; diff --git a/pdwtags.c b/pdwtags.c index bc041b5..f443b51 100644 --- a/pdwtags.c +++ b/pdwtags.c @@ -18,46 +18,43 @@ static struct conf_fprintf conf = { .emit_stats = 1, }; -static int emit_tag(struct tag *self, struct cu *cu, void *cookie __unused) +static void emit_tag(struct tag *self, uint32_t tag_id, struct cu *cu) { - if (self->tag != DW_TAG_array_type && - self->tag != DW_TAG_const_type && - self->tag != DW_TAG_formal_parameter && - self->tag != DW_TAG_reference_type && - self->tag != DW_TAG_subroutine_type && - self->tag != DW_TAG_volatile_type) { - if (tag__is_struct(self)) - class__find_holes(tag__class(self), cu); + if (tag__is_struct(self)) + class__find_holes(tag__class(self), cu); - conf.no_semicolon = self->tag == DW_TAG_subprogram; + conf.no_semicolon = self->tag == DW_TAG_subprogram; - printf("%lld ", (unsigned long long)self->id); + printf("%d ", tag_id); - if (self->tag == DW_TAG_base_type) { - const char *name = base_type__name(tag__base_type(self)); + if (self->tag == DW_TAG_base_type) { + const char *name = base_type__name(tag__base_type(self)); - if (name == NULL) - printf("anonymous base_type\n"); - else - puts(name); - } else if (self->tag == DW_TAG_pointer_type) - printf("pointer to %lld\n", (unsigned long long)self->type); + if (name == NULL) + printf("anonymous base_type\n"); else - tag__fprintf(self, cu, &conf, stdout); + puts(name); + } else if (self->tag == DW_TAG_pointer_type) + printf("pointer to %lld\n", (unsigned long long)self->type); + else + tag__fprintf(self, cu, &conf, stdout); - if (self->tag == DW_TAG_subprogram) { - struct function *fn = tag__function(self); - putchar('\n'); - lexblock__fprintf(&fn->lexblock, cu, fn, 0, stdout); - } - puts("\n"); + if (self->tag == DW_TAG_subprogram) { + struct function *fn = tag__function(self); + putchar('\n'); + lexblock__fprintf(&fn->lexblock, cu, fn, 0, stdout); } - return 0; + puts("\n"); } static int cu__emit_tags(struct cu *self, void *cookie __unused) { - cu__for_each_tag(self, emit_tag, NULL, NULL); + uint16_t i; + + for (i = 1; i < self->types_table.nr_entries; ++i) { + struct tag *tag = self->types_table.entries[i]; + emit_tag(tag, i, self); + } return 0; } diff --git a/pfunct.c b/pfunct.c index b2431df..03d3c73 100644 --- a/pfunct.c +++ b/pfunct.c @@ -218,6 +218,9 @@ static struct tag *function__filter(struct tag *tag, struct cu *cu, if (tag->tag != DW_TAG_subprogram) return NULL; + if (!tag->top_level) + return NULL; + function = tag__function(tag); /* * FIXME: remove this check and try to fix the parameter abstract @@ -271,6 +274,7 @@ static int cu_unique_iterator(struct cu *cu, void *cookie) static int class_iterator(struct tag *tag, struct cu *cu, void *cookie) { + uint16_t *target_id = cookie; struct function *function; if (tag->tag != DW_TAG_subprogram) @@ -280,7 +284,7 @@ static int class_iterator(struct tag *tag, struct cu *cu, void *cookie) if (function->inlined) return 0; - if (ftype__has_parm_of_type(&function->proto, cookie, cu)) { + if (ftype__has_parm_of_type(&function->proto, *target_id, cu)) { if (verbose) tag__fprintf(tag, cu, &conf, stdout); else @@ -292,12 +296,13 @@ static int class_iterator(struct tag *tag, struct cu *cu, void *cookie) static int cu_class_iterator(struct cu *cu, void *cookie) { - struct tag *target = cu__find_struct_by_name(cu, cookie, 0); + uint16_t target_id; + struct tag *target = cu__find_struct_by_name(cu, cookie, 0, &target_id); if (target == NULL) return 0; - return cu__for_each_tag(cu, class_iterator, target, NULL); + return cu__for_each_tag(cu, class_iterator, &target_id, NULL); } static int function__emit_type_definitions(struct function *self, diff --git a/prefcnt.c b/prefcnt.c index ed2e774..a99d246 100644 --- a/prefcnt.c +++ b/prefcnt.c @@ -135,7 +135,7 @@ static int cu_refcnt_iterator(struct cu *cu, void *cookie) static int lost_iterator(struct tag *tag, struct cu *cu, void *cookie __unused) { - if (!tag->visited && tag->decl_file) { + if (!tag->visited && tag__decl_file(tag, cu)) { tag__fprintf(tag, cu, NULL, stdout); puts(";\n"); } From a2289d06068a0f87a71f1f1e6fdb27ef323c90c1 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 6 Mar 2009 09:27:40 -0300 Subject: [PATCH 32/40] dwarves: Ditch parameter__type and simplify parameter__name parameter__type was needed because the abstract_origin resolution was done later, now it is at dwarf recode time, and for debugging formats that don't have this crap, never. So it now can use the same idiom as other tags: foo->tag.type. parameter__name still exists because the tools still want a string returned, but for some what they want is indeed the string_t, so that when looking for a particular string it can be done as an string__find for the key + integer comparision instead of doing a costlier strcmp. Signed-off-by: Arnaldo Carvalho de Melo --- ctracer.c | 4 ++-- dwarves.c | 17 +++-------------- dwarves.h | 6 ++++-- pahole.c | 3 +-- pfunct.c | 2 +- syscse.c | 5 ++--- 6 files changed, 13 insertions(+), 24 deletions(-) diff --git a/ctracer.c b/ctracer.c index 411cc21..620da59 100644 --- a/ctracer.c +++ b/ctracer.c @@ -702,13 +702,13 @@ static int function__emit_probes(struct function *self, uint32_t function_id, if (member != NULL) fprintf(fp_methods, "\tif ($%s)\n\t", - parameter__name(pos, cu)); + parameter__name(pos)); fprintf(fp_methods, "\tctracer__method_hook(%d, %d, $%s%s%s, %zd);\n", probe_type, function_id, - parameter__name(pos, cu), + parameter__name(pos), member ? "->" : "", member ?: "", class__size(mini_class)); break; diff --git a/dwarves.c b/dwarves.c index 57bf37c..788a0ed 100644 --- a/dwarves.c +++ b/dwarves.c @@ -1041,16 +1041,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 __unused) -{ - return s(self->name); -} - -Dwarf_Off parameter__type(struct parameter *self, const struct cu *cu __unused) -{ - return self->tag.type; -} - static size_t union__fprintf(struct type *self, const struct cu *cu, const struct conf_fprintf *conf, FILE *fp); @@ -1456,8 +1446,7 @@ int ftype__has_parm_of_type(const struct ftype *self, const uint16_t target, struct parameter *pos; ftype__for_each_parameter(self, pos) { - struct tag *type = - cu__find_type_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) { if (type->type == target) @@ -1713,8 +1702,8 @@ static size_t ftype__fprintf_parms(const struct ftype *self, indent, tabs); } else first_parm = 0; - name = parameter__name(pos, cu); - type = cu__find_type_by_id(cu, parameter__type(pos, cu)); + name = parameter__name(pos); + type = cu__find_type_by_id(cu, pos->tag.type); if (type == NULL) { snprintf(sbf, sizeof(sbf), "", pos->tag.type); diff --git a/dwarves.h b/dwarves.h index e42234d..cb6a3d9 100644 --- a/dwarves.h +++ b/dwarves.h @@ -530,8 +530,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, diff --git a/pahole.c b/pahole.c index 551127e..83e8746 100644 --- a/pahole.c +++ b/pahole.c @@ -695,8 +695,7 @@ 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_type_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; diff --git a/pfunct.c b/pfunct.c index 03d3c73..9564d06 100644 --- a/pfunct.c +++ b/pfunct.c @@ -311,7 +311,7 @@ static int function__emit_type_definitions(struct function *self, struct parameter *pos; function__for_each_parameter(self, pos) { - struct tag *type = cu__find_type_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; diff --git a/syscse.c b/syscse.c index c0ea2e2..874eb05 100644 --- a/syscse.c +++ b/syscse.c @@ -68,7 +68,7 @@ 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); + const uint16_t type_id = parm->tag.type; struct tag *type = cu__find_type_by_id(cu, type_id); tag__assert_search_result(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; From fa82c1b62324b435a9e0e99aa4a9e296238b34d6 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 6 Mar 2009 10:57:41 -0300 Subject: [PATCH 33/40] dwarves: remove now unused 'cu' argument to {type,class}__name And also make then pure functions. Signed-off-by: Arnaldo Carvalho de Melo --- codiff.c | 27 ++++++++++---------- ctf_loader.c | 2 +- ctracer.c | 39 +++++++++++++---------------- dutil.h | 4 +++ dwarves.c | 67 +++++++++++++++++++++++--------------------------- dwarves.h | 14 ++++++----- dwarves_emit.c | 42 +++++++++++++++---------------- dwarves_emit.h | 2 +- pahole.c | 47 +++++++++++++++++------------------ 9 files changed, 117 insertions(+), 127 deletions(-) diff --git a/codiff.c b/codiff.c index abe21f9..b86e3d4 100644 --- a/codiff.c +++ b/codiff.c @@ -246,11 +246,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, NULL); + new_tag = cu__find_struct_by_name(new_cu, + class__name(structure), 0, NULL); if (new_tag == NULL) return; @@ -274,7 +274,7 @@ static void diff_struct(const struct cu *new_cu, struct class *structure, 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), @@ -329,20 +329,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) != 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; @@ -481,12 +481,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); @@ -556,7 +555,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; @@ -602,7 +601,7 @@ static void show_diffs_structure(struct class *structure, 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, @@ -625,7 +624,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); diff --git a/ctf_loader.c b/ctf_loader.c index 5fe00b9..6dc1f2c 100644 --- a/ctf_loader.c +++ b/ctf_loader.c @@ -832,7 +832,7 @@ static int class__fixup_ctf_bitfields(struct tag *self, struct cu *cu) bit_size, &fixed_tag_id) == NULL) { fprintf(stderr, "%s: BRAIN FART ALERT!: class: %s, member: %s\n", - __func__, type__name(type_self, cu), + __func__, type__name(type_self), class_member__name(pos)); continue; } diff --git a/ctracer.c b/ctracer.c index 620da59..e2f4227 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; @@ -308,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); @@ -319,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)); @@ -390,8 +389,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; @@ -403,7 +401,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"); @@ -495,7 +493,7 @@ static struct tag *pointer_filter(struct tag *tag, struct cu *cu, 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; @@ -540,8 +538,7 @@ 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, uint16_t target_type_id) +static struct tag *alias_filter(struct tag *tag, uint16_t target_type_id) { struct type *type; struct class_member *first_member; @@ -558,7 +555,7 @@ static struct tag *alias_filter(struct tag *tag, 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; @@ -579,8 +576,8 @@ static int cu_find_aliases_iterator(struct cu *cu, void *class_name) return 0; cu__for_each_type(cu, id, pos) { - if (alias_filter(pos, cu, target_type_id)) { - const char *alias_name = class__name(tag__class(pos), cu); + if (alias_filter(pos, target_type_id)) { + const char *alias_name = class__name(tag__class(pos)); structures__add(&aliases, pos, cu); @@ -619,8 +616,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; } @@ -640,7 +636,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) @@ -659,7 +655,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; @@ -951,8 +947,7 @@ 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", @@ -1005,7 +1000,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) @@ -1019,7 +1014,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); @@ -1030,7 +1025,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/dutil.h b/dutil.h index d2166ab..cc8c4a5 100644 --- a/dutil.h +++ b/dutil.h @@ -14,6 +14,10 @@ #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 diff --git a/dwarves.c b/dwarves.c index 788a0ed..65ea711 100644 --- a/dwarves.c +++ b/dwarves.c @@ -235,11 +235,6 @@ void namespace__delete(struct namespace *self) tag__delete(&self->tag); } -const char *type__name(struct type *self, const struct cu *cu __unused) -{ - return s(self->namespace.name); -} - struct class_member * type__find_first_biggest_size_base_type_member(struct type *self, const struct cu *cu) @@ -322,20 +317,20 @@ 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_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 */ @@ -344,7 +339,7 @@ size_t typedef__fprintf(const struct tag *tag_self, const struct cu *cu, 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; @@ -354,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, @@ -398,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)) @@ -908,7 +903,7 @@ const char *tag__name(const struct tag *self, const struct cu *cu, 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), @@ -950,7 +945,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; } @@ -1096,10 +1091,10 @@ 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_type_by_id(cu, type->type); @@ -1150,11 +1145,11 @@ 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); + type__name(ctype), name); else { struct class *class = tag__class(type); @@ -1165,22 +1160,22 @@ static size_t type__fprintf(struct tag *type, const struct cu *cu, 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: @@ -1225,7 +1220,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 ? @@ -1271,7 +1266,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; @@ -1310,8 +1305,8 @@ 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; @@ -1994,8 +1989,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)) @@ -2029,7 +2024,7 @@ size_t class__fprintf(struct class *self, const struct cu *cu, 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); } @@ -2388,7 +2383,7 @@ size_t tag__fprintf(struct tag *self, const struct cu *cu, 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); diff --git a/dwarves.h b/dwarves.h index cb6a3d9..78a9f24 100644 --- a/dwarves.h +++ b/dwarves.h @@ -15,6 +15,7 @@ #include #include +#include "dutil.h" #include "list.h" #include "strings.h" @@ -365,12 +366,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) @@ -615,7 +618,6 @@ 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); diff --git a/dwarves_emit.c b/dwarves_emit.c index bf8c5e7..da89ba1 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. @@ -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; } @@ -236,19 +235,18 @@ 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; } @@ -311,7 +309,7 @@ void type__emit(struct tag *tag_self, struct cu *cu, 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/pahole.c b/pahole.c index 83e8746..c15a133 100644 --- a/pahole.c +++ b/pahole.c @@ -145,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; + 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; } @@ -180,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) { /* @@ -243,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; @@ -262,7 +260,7 @@ 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) { @@ -270,7 +268,7 @@ static void print_packable_info(struct structure *pos) 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", @@ -349,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); @@ -408,7 +406,7 @@ static struct tag *tag__filter(struct tag *tag, struct cu *cu, 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)) @@ -424,7 +422,7 @@ static struct tag *tag__filter(struct tag *tag, struct cu *cu, if (tdef != NULL) { struct class *c = tag__class(tdef); - name = class__name(c, cu); + name = class__name(c); stname = c->type.namespace.name; } } @@ -440,7 +438,7 @@ static struct tag *tag__filter(struct tag *tag, struct cu *cu, if (tdef != NULL) { struct class *c = tag__class(tdef); - name = class__name(c, cu); + name = class__name(c); stname = c->type.namespace.name; } } @@ -705,10 +703,9 @@ static int nr_methods_iterator(struct tag *tag, struct cu *cu, 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; @@ -729,7 +726,7 @@ static void print_structs_with_pointer_to(const struct structure *s) { struct structure *pos_structure; uint16_t type; - const char *class_name = class__name(s->class, s->cu); + const char *class_name = class__name(s->class); const struct cu *current_cu = NULL; list_for_each_entry(pos_structure, &structures__named_list, node) { @@ -754,7 +751,7 @@ static void print_structs_with_pointer_to(const struct structure *s) 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)); } } @@ -770,7 +767,7 @@ static void print_containers(const struct structure *s, int ident) 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'); From 7cf49c14e7b006278f784703b47ad4a2d23baca1 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 6 Mar 2009 11:02:16 -0300 Subject: [PATCH 34/40] dwarves: check if the current pos is NULL in cu__for_each_function To match cu__for_each_type handling of entries set with cu__table_nullify_type_entry. Signed-off-by: Arnaldo Carvalho de Melo --- dwarves.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dwarves.h b/dwarves.h index 78a9f24..4b48d12 100644 --- a/dwarves.h +++ b/dwarves.h @@ -60,7 +60,8 @@ struct ptr_table { for (id = 0, pos = tag__function(cu->tags_table.entries[id]); \ id < cu->tags_table.nr_entries; \ pos = tag__function(cu->tags_table.entries[++id])) \ - if (pos->proto.tag.tag != DW_TAG_subprogram) \ + if (pos == NULL || \ + pos->proto.tag.tag != DW_TAG_subprogram) \ continue; \ else From b19ac641ba214e2933809786ffcdfad191ffa3c9 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 6 Mar 2009 11:12:00 -0300 Subject: [PATCH 35/40] dwarves: Introduce tag__is_function() Removing more dwarf specific knowledge (DW_TAG_subprogram) from the tools. Signed-off-by: Arnaldo Carvalho de Melo --- dwarves.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/dwarves.h b/dwarves.h index 4b48d12..247417e 100644 --- a/dwarves.h +++ b/dwarves.h @@ -515,6 +515,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 From 9fadbfffba3af323543c2593af0aa7366f6e1508 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 6 Mar 2009 11:14:26 -0300 Subject: [PATCH 36/40] dwarves: use tag__is_function in the tools Signed-off-by: Arnaldo Carvalho de Melo --- codiff.c | 10 +++------- ctracer.c | 4 ++-- dwarf_loader.c | 2 +- dwarves.c | 7 +++---- pahole.c | 2 +- pdwtags.c | 4 ++-- pfunct.c | 8 ++++---- pglobal.c | 2 +- prefcnt.c | 2 +- syscse.c | 2 +- 10 files changed, 19 insertions(+), 24 deletions(-) diff --git a/codiff.c b/codiff.c index b86e3d4..23102d0 100644 --- a/codiff.c +++ b/codiff.c @@ -72,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; @@ -285,7 +283,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; @@ -298,8 +296,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; @@ -350,7 +346,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 @@ -609,7 +605,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; } diff --git a/ctracer.c b/ctracer.c index e2f4227..807712a 100644 --- a/ctracer.c +++ b/ctracer.c @@ -172,7 +172,7 @@ static void method__add(struct cu *cu, struct function *function, uint32_t 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 function *function__filter(struct function *function, @@ -189,7 +189,7 @@ static struct function *function__filter(struct function *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) diff --git a/dwarf_loader.c b/dwarf_loader.c index fb0d9ae..4b85131 100644 --- a/dwarf_loader.c +++ b/dwarf_loader.c @@ -960,7 +960,7 @@ static void die__process_class(Dwarf_Die *die, struct type *class, namespace__add_tag(&class->namespace, tag); cu__hash(cu, tag); - if (tag->tag == DW_TAG_subprogram) { + if (tag__is_function(tag)) { struct function *fself = tag__function(tag); if (fself->vtable_entry != -1) diff --git a/dwarves.c b/dwarves.c index 65ea711..8fd3858 100644 --- a/dwarves.c +++ b/dwarves.c @@ -792,7 +792,7 @@ struct tag *cu__find_function_by_name(const struct cu *self, const char *name) return NULL; list_for_each_entry(pos, &self->tags, node) { - if (pos->tag != DW_TAG_subprogram) + if (!tag__is_function(pos)) continue; fpos = tag__function(pos); if (fpos->name && strcmp(s(fpos->name), name) == 0) @@ -1668,7 +1668,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); @@ -2421,8 +2421,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) diff --git a/pahole.c b/pahole.c index c15a133..d080343 100644 --- a/pahole.c +++ b/pahole.c @@ -676,7 +676,7 @@ static int cu_fixup_word_size_iterator(struct cu *cu, void *cookie) 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))) diff --git a/pdwtags.c b/pdwtags.c index f443b51..6b0febe 100644 --- a/pdwtags.c +++ b/pdwtags.c @@ -23,7 +23,7 @@ static void emit_tag(struct tag *self, uint32_t tag_id, struct cu *cu) if (tag__is_struct(self)) class__find_holes(tag__class(self), cu); - conf.no_semicolon = self->tag == DW_TAG_subprogram; + conf.no_semicolon = tag__is_function(self); printf("%d ", tag_id); @@ -39,7 +39,7 @@ static void emit_tag(struct tag *self, uint32_t tag_id, struct cu *cu) else tag__fprintf(self, cu, &conf, stdout); - if (self->tag == DW_TAG_subprogram) { + if (tag__is_function(self)) { struct function *fn = tag__function(self); putchar('\n'); lexblock__fprintf(&fn->lexblock, cu, fn, 0, stdout); diff --git a/pfunct.c b/pfunct.c index 9564d06..4c45f1b 100644 --- a/pfunct.c +++ b/pfunct.c @@ -215,7 +215,7 @@ 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) @@ -261,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; } @@ -277,7 +277,7 @@ 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); @@ -335,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); diff --git a/pglobal.c b/pglobal.c index 8549a68..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); diff --git a/prefcnt.c b/prefcnt.c index a99d246..af1c14e 100644 --- a/prefcnt.c +++ b/prefcnt.c @@ -120,7 +120,7 @@ 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) + else if (tag__is_function(tag)) refcnt_function_iterator(tag__function(tag), cu, cookie); return 0; diff --git a/syscse.c b/syscse.c index 874eb05..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) { From 5f606ab5e3b79634c1e45d9b9c30b7af1ccd0cd3 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 6 Mar 2009 11:23:00 -0300 Subject: [PATCH 37/40] ctracer: Remove superfluous calls to class__find_holes in class__clone_base_types The first isn't needed because class__clone will do a memcpy for the whole class struct, and that will get the hosts calculated previously for the classe beind cloned. The second isn't needed because class__reorganize will call class__find_holes at every iteration of its algorithm. Signed-off-by: Arnaldo Carvalho de Melo --- ctracer.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/ctracer.c b/ctracer.c index 807712a..4330984 100644 --- a/ctracer.c +++ b/ctracer.c @@ -353,8 +353,6 @@ 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_type_by_id(cu, pos->tag.type); @@ -364,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; From b902f563b3393a8b55cb8abebd9ab2b5a58128b9 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 6 Mar 2009 11:48:33 -0300 Subject: [PATCH 38/40] dwarves: find holes when adding a fresh compile unit To take advantage of cache effects and to avoid calling cu__find_holes more than once on the same struct. Signed-off-by: Arnaldo Carvalho de Melo --- codiff.c | 2 -- dwarves.c | 19 +++++++++++++------ dwarves.h | 15 +++++++++++++++ dwarves_emit.c | 3 --- pahole.c | 2 -- pdwtags.c | 3 --- prefcnt.c | 4 +--- 7 files changed, 29 insertions(+), 19 deletions(-) diff --git a/codiff.c b/codiff.c index 23102d0..07fb01b 100644 --- a/codiff.c +++ b/codiff.c @@ -258,8 +258,6 @@ static void diff_struct(const struct cu *new_cu, struct class *structure, assert(class__is_struct(new_structure)); - class__find_holes(structure, cu); - class__find_holes(new_structure, new_cu); diff = class__size(structure) != class__size(new_structure) || class__nr_members(structure) != class__nr_members(new_structure) || check_print_members_changes(structure, cu, diff --git a/dwarves.c b/dwarves.c index 8fd3858..0b4d549 100644 --- a/dwarves.c +++ b/dwarves.c @@ -414,9 +414,19 @@ size_t enumeration__fprintf(const struct tag *tag_self, 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) @@ -1150,12 +1160,9 @@ static size_t type__fprintf(struct tag *type, const struct cu *cu, type->tag == DW_TAG_class_type ? "class" : "struct", conf->type_spacing - 7, type__name(ctype), name); - else { - struct class *class = tag__class(type); - - class__find_holes(class, cu); - printed += class__fprintf(class, cu, &tconf, fp); - } + else + printed += class__fprintf(tag__class(type), + cu, &tconf, fp); break; case DW_TAG_union_type: ctype = tag__type(type); diff --git a/dwarves.h b/dwarves.h index 247417e..b52496c 100644 --- a/dwarves.h +++ b/dwarves.h @@ -50,6 +50,21 @@ struct ptr_table { 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 diff --git a/dwarves_emit.c b/dwarves_emit.c index da89ba1..0abdaac 100644 --- a/dwarves_emit.c +++ b/dwarves_emit.c @@ -306,9 +306,6 @@ 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) != NULL || suffix != NULL || prefix != NULL) { struct conf_fprintf conf = { diff --git a/pahole.c b/pahole.c index d080343..6bafc7a 100644 --- a/pahole.c +++ b/pahole.c @@ -454,8 +454,6 @@ static struct tag *tag__filter(struct tag *tag, struct cu *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))) diff --git a/pdwtags.c b/pdwtags.c index 6b0febe..9956cfd 100644 --- a/pdwtags.c +++ b/pdwtags.c @@ -20,9 +20,6 @@ static struct conf_fprintf conf = { static void emit_tag(struct tag *self, uint32_t tag_id, struct cu *cu) { - if (tag__is_struct(self)) - class__find_holes(tag__class(self), cu); - conf.no_semicolon = tag__is_function(self); printf("%d ", tag_id); diff --git a/prefcnt.c b/prefcnt.c index af1c14e..a14b01e 100644 --- a/prefcnt.c +++ b/prefcnt.c @@ -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__is_function(tag)) + if (tag__is_function(tag)) refcnt_function_iterator(tag__function(tag), cu, cookie); return 0; From cf20eaec3af5c376fc698f84607868ca7a927a41 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 6 Mar 2009 11:53:27 -0300 Subject: [PATCH 39/40] dwarf__loader: optimize tag__init a bit more No need to initialize hash_node, as we don't use hlist__unhashed. Signed-off-by: Arnaldo Carvalho de Melo --- dwarf_loader.c | 1 - 1 file changed, 1 deletion(-) diff --git a/dwarf_loader.c b/dwarf_loader.c index 4b85131..72d7382 100644 --- a/dwarf_loader.c +++ b/dwarf_loader.c @@ -289,7 +289,6 @@ static void tag__init(struct tag *self, Dwarf_Die *die) dwarf_decl_line(die, &decl_line); dtag->decl_line = decl_line; self->recursivity_level = 0; - INIT_HLIST_NODE(&dtag->hash_node); } static struct tag *tag__new(Dwarf_Die *die) From c550aea11cbf8c0c951b4d72918e59ddba898bbf Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 6 Mar 2009 12:41:29 -0300 Subject: [PATCH 40/40] pahole, lib: Do more strings__find + integer comparisions Replacing strcmp calls Signed-off-by: Arnaldo Carvalho de Melo --- dwarves.c | 31 ++++++++++++++++++------------- pahole.c | 27 ++++++++++++++++++++------- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/dwarves.c b/dwarves.c index 0b4d549..5fd5fe4 100644 --- a/dwarves.c +++ b/dwarves.c @@ -796,18 +796,18 @@ 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 (!tag__is_function(pos)) - continue; - fpos = tag__function(pos); - if (fpos->name && strcmp(s(fpos->name), name) == 0) + strings_t sname = strings__find(strings, name); + if (sname == 0) + return NULL; + + list_for_each_entry(pos, &self->tags, node) + if (tag__is_function(pos) && + tag__function(pos)->name == sname) return pos; - } return NULL; } @@ -1619,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; } diff --git a/pahole.c b/pahole.c index 6bafc7a..a7a3634 100644 --- a/pahole.c +++ b/pahole.c @@ -493,6 +493,8 @@ static int cu_unique_iterator(struct cu *cu, void *cookie __unused) 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); static void class__resize_LP(struct tag *tag, struct cu *cu) @@ -542,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 */ } @@ -648,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; @@ -664,11 +666,11 @@ 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, @@ -1065,8 +1067,19 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; } - if (word_size != 0) + 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; + } + cus__for_each_cu(cus, cu_fixup_word_size_iterator, NULL, NULL); + } if (class_dwarf_offset != 0) { struct cu *cu;