提交 af427bf5 编写于 作者: A Arnaldo Carvalho de Melo 提交者: Ingo Molnar

perf tools: Create maps for modules when processing kallsyms

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: NArnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Mike Galbraith <efault@gmx.de>
LKML-Reference: <new-submission>
Signed-off-by: NIngo Molnar <mingo@elte.hu>
上级 5c206805
...@@ -27,6 +27,44 @@ enum dso_origin { ...@@ -27,6 +27,44 @@ enum dso_origin {
static void dsos__add(struct dso *dso); static void dsos__add(struct dso *dso);
static struct dso *dsos__find(const char *name); 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, static struct symbol *symbol__new(u64 start, u64 len, const char *name,
unsigned int priv_size, int v) unsigned int priv_size, int v)
{ {
...@@ -162,10 +200,9 @@ size_t dso__fprintf(struct dso *self, FILE *fp) ...@@ -162,10 +200,9 @@ size_t dso__fprintf(struct dso *self, FILE *fp)
return ret; return ret;
} }
static int dso__load_kallsyms(struct dso *self, struct map *map, static int maps__load_kallsyms(symbol_filter_t filter, int use_modules, int v)
symbol_filter_t filter, int v)
{ {
struct rb_node *nd, *prevnd; struct map *map = kernel_map;
char *line = NULL; char *line = NULL;
size_t n; size_t n;
FILE *file = fopen("/proc/kallsyms", "r"); FILE *file = fopen("/proc/kallsyms", "r");
...@@ -179,6 +216,7 @@ static int dso__load_kallsyms(struct dso *self, struct map *map, ...@@ -179,6 +216,7 @@ static int dso__load_kallsyms(struct dso *self, struct map *map,
struct symbol *sym; struct symbol *sym;
int line_len, len; int line_len, len;
char symbol_type; char symbol_type;
char *module, *symbol_name;
line_len = getline(&line, &n, file); line_len = getline(&line, &n, file);
if (line_len < 0) if (line_len < 0)
...@@ -201,40 +239,50 @@ static int dso__load_kallsyms(struct dso *self, struct map *map, ...@@ -201,40 +239,50 @@ static int dso__load_kallsyms(struct dso *self, struct map *map,
*/ */
if (symbol_type != 'T' && symbol_type != 'W') if (symbol_type != 'T' && symbol_type != 'W')
continue; 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. * Well fix up the end later, when we have all sorted.
*/ */
sym = symbol__new(start, 0xdead, line + len + 2, sym = symbol__new(start, 0, symbol_name,
self->sym_priv_size, v); map->dso->sym_priv_size, v);
if (sym == NULL) if (sym == NULL)
goto out_delete_line; goto out_delete_line;
if (filter && filter(map, sym)) if (filter && filter(map, sym))
symbol__delete(sym, self->sym_priv_size); symbol__delete(sym, map->dso->sym_priv_size);
else { else {
dso__insert_symbol(self, sym); dso__insert_symbol(map->dso, sym);
count++; 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); free(line);
fclose(file); fclose(file);
...@@ -246,6 +294,24 @@ static int dso__load_kallsyms(struct dso *self, struct map *map, ...@@ -246,6 +294,24 @@ static int dso__load_kallsyms(struct dso *self, struct map *map,
return -1; 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, static int dso__load_perf_map(struct dso *self, struct map *map,
symbol_filter_t filter, int v) symbol_filter_t filter, int v)
{ {
...@@ -598,6 +664,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, ...@@ -598,6 +664,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
char *demangled; char *demangled;
int is_label = elf_sym__is_label(&sym); int is_label = elf_sym__is_label(&sym);
const char *section_name; const char *section_name;
u64 sh_offset = 0;
if (!is_label && !elf_sym__is_function(&sym)) if (!is_label && !elf_sym__is_function(&sym))
continue; continue;
...@@ -613,14 +680,18 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, ...@@ -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); 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 (self->adjust_symbols) {
if (v >= 2) if (v >= 2)
printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n", 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); (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset);
sym.st_value -= shdr.sh_addr - 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 * 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 * 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, ...@@ -631,7 +702,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
if (demangled != NULL) if (demangled != NULL)
elf_name = demangled; 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); self->sym_priv_size, v);
free(demangled); free(demangled);
if (!f) if (!f)
...@@ -804,7 +875,6 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter, int v) ...@@ -804,7 +875,6 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter, int v)
return ret; return ret;
} }
static struct rb_root kernel_maps;
struct map *kernel_map; struct map *kernel_map;
static void kernel_maps__insert(struct map *map) static void kernel_maps__insert(struct map *map)
...@@ -975,8 +1045,7 @@ static struct map *map__new2(u64 start, struct dso *dso) ...@@ -975,8 +1045,7 @@ static struct map *map__new2(u64 start, struct dso *dso)
return self; return self;
} }
int dsos__load_modules(unsigned int sym_priv_size, static int dsos__load_modules(unsigned int sym_priv_size)
symbol_filter_t filter, int v)
{ {
char *line = NULL; char *line = NULL;
size_t n; size_t n;
...@@ -1034,8 +1103,7 @@ int dsos__load_modules(unsigned int sym_priv_size, ...@@ -1034,8 +1103,7 @@ int dsos__load_modules(unsigned int sym_priv_size,
free(line); free(line);
fclose(file); fclose(file);
v = 1; return 0;
return dsos__load_modules_sym(filter, v);
out_delete_line: out_delete_line:
free(line); free(line);
...@@ -1075,25 +1143,37 @@ int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, ...@@ -1075,25 +1143,37 @@ int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size,
kernel_map->map_ip = vdso__map_ip; 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) { if (vmlinux) {
err = dso__load_vmlinux(dso, kernel_map, vmlinux, filter, v); err = dso__load_vmlinux(dso, kernel_map, vmlinux, filter, v);
if (err > 0 && use_modules) { 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) { if (syms < 0)
fprintf(stderr, "dsos__load_modules failed!\n"); fprintf(stderr, "Failed to read module symbols!"
return syms; " Continuing...\n");
} else
err += syms; err += syms;
} }
} }
if (err <= 0) if (err <= 0)
err = dso__load_kallsyms(dso, kernel_map, filter, v); err = maps__load_kallsyms(filter, use_modules, v);
if (err > 0) { if (err > 0) {
struct rb_node *node = rb_first(&dso->syms); struct rb_node *node = rb_first(&dso->syms);
struct symbol *sym = rb_entry(node, struct symbol, rb_node); 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; kernel_map->start = sym->start;
node = rb_last(&dso->syms); node = rb_last(&dso->syms);
...@@ -1106,6 +1186,9 @@ int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, ...@@ -1106,6 +1186,9 @@ int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size,
* kernel_maps__insert(kernel_map) * kernel_maps__insert(kernel_map)
*/ */
dsos__add(dso); dsos__add(dso);
if (v > 0)
kernel_maps__fprintf(stderr);
} }
return err; return err;
......
...@@ -70,8 +70,6 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip); ...@@ -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, int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size,
symbol_filter_t filter, int verbose, int modules); 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 dso__load(struct dso *self, struct map *map, symbol_filter_t filter,
int verbose); int verbose);
struct dso *dsos__findnew(const char *name); struct dso *dsos__findnew(const char *name);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册