From af427bf529c5991be8d1a36f43e2d0141f532f63 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 5 Oct 2009 14:26:17 -0300 Subject: [PATCH] perf tools: Create maps for modules when processing kallsyms MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit So that we get kallsyms processing closer to vmlinux + modules symtabs processing. One change in behaviour is that since when one specifies --vmlinux -m should be used to ask for modules, so it is now for kallsyms as well. Also continue if one manages to load the vmlinux data but module processing fails, so that at least some analisys can be done with part of the needed symbols. Signed-off-by: Arnaldo Carvalho de Melo Cc: Frédéric Weisbecker Cc: Peter Zijlstra Cc: Mike Galbraith LKML-Reference: Signed-off-by: Ingo Molnar --- tools/perf/util/symbol.c | 161 +++++++++++++++++++++++++++++---------- tools/perf/util/symbol.h | 2 - 2 files changed, 122 insertions(+), 41 deletions(-) diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e88296899470..4dfdefd5ec7e 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -27,6 +27,44 @@ enum dso_origin { static void dsos__add(struct dso *dso); static struct dso *dsos__find(const char *name); +static struct rb_root kernel_maps; + +static void dso__set_symbols_end(struct dso *self) +{ + struct rb_node *nd, *prevnd = rb_first(&self->syms); + + if (prevnd == NULL) + return; + + for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { + struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node), + *curr = rb_entry(nd, struct symbol, rb_node); + + if (prev->end == prev->start) + prev->end = curr->start - 1; + prevnd = nd; + } +} + +static void kernel_maps__fixup_sym_end(void) +{ + struct map *prev, *curr; + struct rb_node *nd, *prevnd = rb_first(&kernel_maps); + + if (prevnd == NULL) + return; + + curr = rb_entry(prevnd, struct map, rb_node); + dso__set_symbols_end(curr->dso); + + for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { + prev = curr; + curr = rb_entry(nd, struct map, rb_node); + prev->end = curr->start - 1; + dso__set_symbols_end(curr->dso); + } +} + static struct symbol *symbol__new(u64 start, u64 len, const char *name, unsigned int priv_size, int v) { @@ -162,10 +200,9 @@ size_t dso__fprintf(struct dso *self, FILE *fp) return ret; } -static int dso__load_kallsyms(struct dso *self, struct map *map, - symbol_filter_t filter, int v) +static int maps__load_kallsyms(symbol_filter_t filter, int use_modules, int v) { - struct rb_node *nd, *prevnd; + struct map *map = kernel_map; char *line = NULL; size_t n; FILE *file = fopen("/proc/kallsyms", "r"); @@ -179,6 +216,7 @@ static int dso__load_kallsyms(struct dso *self, struct map *map, struct symbol *sym; int line_len, len; char symbol_type; + char *module, *symbol_name; line_len = getline(&line, &n, file); if (line_len < 0) @@ -201,40 +239,50 @@ static int dso__load_kallsyms(struct dso *self, struct map *map, */ if (symbol_type != 'T' && symbol_type != 'W') continue; + + symbol_name = line + len + 2; + module = strchr(symbol_name, '\t'); + if (module) { + char *module_name_end; + + if (!use_modules) + continue; + *module = '\0'; + module = strchr(module + 1, '['); + if (!module) + continue; + module_name_end = strchr(module + 1, ']'); + if (!module_name_end) + continue; + *(module_name_end + 1) = '\0'; + if (strcmp(map->dso->name, module)) { + map = kernel_maps__find_by_dso_name(module); + if (!map) { + fputs("/proc/{kallsyms,modules} " + "inconsistency!\n", stderr); + return -1; + } + } + start = map->map_ip(map, start); + } else + map = kernel_map; /* * Well fix up the end later, when we have all sorted. */ - sym = symbol__new(start, 0xdead, line + len + 2, - self->sym_priv_size, v); + sym = symbol__new(start, 0, symbol_name, + map->dso->sym_priv_size, v); if (sym == NULL) goto out_delete_line; if (filter && filter(map, sym)) - symbol__delete(sym, self->sym_priv_size); + symbol__delete(sym, map->dso->sym_priv_size); else { - dso__insert_symbol(self, sym); + dso__insert_symbol(map->dso, sym); count++; } } - /* - * Now that we have all sorted out, just set the ->end of all - * symbols - */ - prevnd = rb_first(&self->syms); - - if (prevnd == NULL) - goto out_delete_line; - - for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { - struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node), - *curr = rb_entry(nd, struct symbol, rb_node); - - prev->end = curr->start - 1; - prevnd = nd; - } - free(line); fclose(file); @@ -246,6 +294,24 @@ out_failure: return -1; } +static size_t kernel_maps__fprintf(FILE *fp) +{ + size_t printed = fprintf(stderr, "Kernel maps:\n"); + struct rb_node *nd; + + printed += map__fprintf(kernel_map, fp); + printed += dso__fprintf(kernel_map->dso, fp); + + for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) { + struct map *pos = rb_entry(nd, struct map, rb_node); + + printed += map__fprintf(pos, fp); + printed += dso__fprintf(pos->dso, fp); + } + + return printed + fprintf(stderr, "END kernel maps\n"); +} + static int dso__load_perf_map(struct dso *self, struct map *map, symbol_filter_t filter, int v) { @@ -598,6 +664,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, char *demangled; int is_label = elf_sym__is_label(&sym); const char *section_name; + u64 sh_offset = 0; if (!is_label && !elf_sym__is_function(&sym)) continue; @@ -613,14 +680,18 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, section_name = elf_sec__name(&shdr, secstrs); + if ((kernel || kmodule)) { + if (strstr(section_name, ".init")) + sh_offset = shdr.sh_offset; + } + if (self->adjust_symbols) { if (v >= 2) printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n", (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset); sym.st_value -= shdr.sh_addr - shdr.sh_offset; - } else if (kmodule) - sym.st_value += shdr.sh_offset; + } /* * We need to figure out if the object was created from C++ sources * DWARF DW_compile_unit has this, but we don't always have access @@ -631,7 +702,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, if (demangled != NULL) elf_name = demangled; - f = symbol__new(sym.st_value, sym.st_size, elf_name, + f = symbol__new(sym.st_value + sh_offset, sym.st_size, elf_name, self->sym_priv_size, v); free(demangled); if (!f) @@ -804,7 +875,6 @@ out: return ret; } -static struct rb_root kernel_maps; struct map *kernel_map; static void kernel_maps__insert(struct map *map) @@ -975,8 +1045,7 @@ static struct map *map__new2(u64 start, struct dso *dso) return self; } -int dsos__load_modules(unsigned int sym_priv_size, - symbol_filter_t filter, int v) +static int dsos__load_modules(unsigned int sym_priv_size) { char *line = NULL; size_t n; @@ -1034,8 +1103,7 @@ int dsos__load_modules(unsigned int sym_priv_size, free(line); fclose(file); - v = 1; - return dsos__load_modules_sym(filter, v); + return 0; out_delete_line: free(line); @@ -1075,25 +1143,37 @@ int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, kernel_map->map_ip = vdso__map_ip; + if (use_modules && dsos__load_modules(sym_priv_size) < 0) { + fprintf(stderr, "Failed to load list of modules in use! " + "Continuing...\n"); + use_modules = 0; + } + if (vmlinux) { err = dso__load_vmlinux(dso, kernel_map, vmlinux, filter, v); if (err > 0 && use_modules) { - int syms = dsos__load_modules(sym_priv_size, filter, v); + int syms = dsos__load_modules_sym(filter, v); - if (syms < 0) { - fprintf(stderr, "dsos__load_modules failed!\n"); - return syms; - } - err += syms; + if (syms < 0) + fprintf(stderr, "Failed to read module symbols!" + " Continuing...\n"); + else + err += syms; } } if (err <= 0) - err = dso__load_kallsyms(dso, kernel_map, filter, v); + err = maps__load_kallsyms(filter, use_modules, v); if (err > 0) { struct rb_node *node = rb_first(&dso->syms); struct symbol *sym = rb_entry(node, struct symbol, rb_node); + /* + * Now that we have all sorted out, just set the ->end of all + * symbols that still don't have it. + */ + dso__set_symbols_end(dso); + kernel_maps__fixup_sym_end(); kernel_map->start = sym->start; node = rb_last(&dso->syms); @@ -1106,6 +1186,9 @@ int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, * kernel_maps__insert(kernel_map) */ dsos__add(dso); + + if (v > 0) + kernel_maps__fprintf(stderr); } return err; diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 5339fd82ec96..2e4522edeb07 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -70,8 +70,6 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip); int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, symbol_filter_t filter, int verbose, int modules); -int dsos__load_modules(unsigned int sym_priv_size, symbol_filter_t filter, - int verbose); int dso__load(struct dso *self, struct map *map, symbol_filter_t filter, int verbose); struct dso *dsos__findnew(const char *name); -- 2.30.2