diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/util/symbol.c | 161 | ||||
-rw-r--r-- | 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 e8829689947..4dfdefd5ec7 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 5339fd82ec9..2e4522edeb0 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); |