summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/perf/util/symbol.c161
-rw-r--r--tools/perf/util/symbol.h2
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);