perf report: Add debug help for the finding of symbol bugs - show the symtab origin (DSO, build-id, kernel, etc)
Used with perf report --verbose: [acme@doppio linux-2.6-tip]$ perf report -v | head -16 5.17% firefox /usr/lib64/xulrunner-1.9.1/libxul.so 0x00000000005d8eee f [.] imgContainer::DrawFrameTo(gfxIImageFrame*, gfxIImageFrame*, nsRect&) 2.56% firefox /lib64/libpthread-2.10.1.so 0x0000000000008e02 d [.] __pthread_mutex_lock_internal 1.94% firefox /usr/lib64/xulrunner-1.9.1/libxul.so 0x0000000000d0af8f f [.] SearchTable 1.75% firefox [kernel] 0xffffffffff60013b k [.] vread_hpet 1.63% firefox /lib64/libpthread-2.10.1.so 0x000000000000a404 d [.] __pthread_mutex_unlock 1.47% firefox /usr/lib64/xulrunner-1.9.1/libmozjs.so 0x00000000000482ea f [.] js_Interpret 1.42% firefox /usr/lib64/xulrunner-1.9.1/libmozjs.so 0x000000000003eda3 f [.] JS_CallTracer 1.24% firefox [kernel] 0xffffffff8102ca4a k [k] read_hpet 1.16% firefox [kernel] 0xffffffff810f3dd4 k [k] fget_light 1.11% firefox /usr/lib64/xulrunner-1.9.1/libmozjs.so 0x00000000000567ff f [.] js_TraceObject 0.98% firefox /usr/lib64/firefox-3.5.2/firefox 0x000000000000dd23 b [.] arena_ralloc [acme@doppio linux-2.6-tip]$ The new field is just after the symbol address. To help in figuring out symbol resolution bugs. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Acked-by: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
8f18aec535
commit
94cb9e385d
@ -700,7 +700,8 @@ sort__sym_print(FILE *fp, struct hist_entry *self, unsigned int width __used)
|
|||||||
size_t ret = 0;
|
size_t ret = 0;
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
ret += repsep_fprintf(fp, "%#018llx ", (u64)self->ip);
|
ret += repsep_fprintf(fp, "%#018llx %c ", (u64)self->ip,
|
||||||
|
dso__symtab_origin(self->dso));
|
||||||
|
|
||||||
ret += repsep_fprintf(fp, "[%c] ", self->level);
|
ret += repsep_fprintf(fp, "[%c] ", self->level);
|
||||||
if (self->sym) {
|
if (self->sym) {
|
||||||
|
@ -24,6 +24,16 @@ const char *sym_hist_filter;
|
|||||||
#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
|
#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum dso_origin {
|
||||||
|
DSO__ORIG_KERNEL = 0,
|
||||||
|
DSO__ORIG_JAVA_JIT,
|
||||||
|
DSO__ORIG_FEDORA,
|
||||||
|
DSO__ORIG_UBUNTU,
|
||||||
|
DSO__ORIG_BUILDID,
|
||||||
|
DSO__ORIG_DSO,
|
||||||
|
DSO__ORIG_NOT_FOUND,
|
||||||
|
};
|
||||||
|
|
||||||
static struct symbol *symbol__new(u64 start, u64 len,
|
static struct symbol *symbol__new(u64 start, u64 len,
|
||||||
const char *name, unsigned int priv_size,
|
const char *name, unsigned int priv_size,
|
||||||
u64 obj_start, int verbose)
|
u64 obj_start, int verbose)
|
||||||
@ -81,6 +91,7 @@ struct dso *dso__new(const char *name, unsigned int sym_priv_size)
|
|||||||
self->sym_priv_size = sym_priv_size;
|
self->sym_priv_size = sym_priv_size;
|
||||||
self->find_symbol = dso__find_symbol;
|
self->find_symbol = dso__find_symbol;
|
||||||
self->slen_calculated = 0;
|
self->slen_calculated = 0;
|
||||||
|
self->origin = DSO__ORIG_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@ -710,7 +721,7 @@ static char *dso__read_build_id(struct dso *self, int verbose)
|
|||||||
++raw;
|
++raw;
|
||||||
bid += 2;
|
bid += 2;
|
||||||
}
|
}
|
||||||
if (verbose)
|
if (verbose >= 2)
|
||||||
printf("%s(%s): %s\n", __func__, self->name, build_id);
|
printf("%s(%s): %s\n", __func__, self->name, build_id);
|
||||||
out_elf_end:
|
out_elf_end:
|
||||||
elf_end(elf);
|
elf_end(elf);
|
||||||
@ -720,11 +731,26 @@ out:
|
|||||||
return build_id;
|
return build_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char dso__symtab_origin(const struct dso *self)
|
||||||
|
{
|
||||||
|
static const char origin[] = {
|
||||||
|
[DSO__ORIG_KERNEL] = 'k',
|
||||||
|
[DSO__ORIG_JAVA_JIT] = 'j',
|
||||||
|
[DSO__ORIG_FEDORA] = 'f',
|
||||||
|
[DSO__ORIG_UBUNTU] = 'u',
|
||||||
|
[DSO__ORIG_BUILDID] = 'b',
|
||||||
|
[DSO__ORIG_DSO] = 'd',
|
||||||
|
};
|
||||||
|
|
||||||
|
if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND)
|
||||||
|
return '!';
|
||||||
|
return origin[self->origin];
|
||||||
|
}
|
||||||
|
|
||||||
int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
|
int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
|
||||||
{
|
{
|
||||||
int size = PATH_MAX;
|
int size = PATH_MAX;
|
||||||
char *name = malloc(size), *build_id = NULL;
|
char *name = malloc(size), *build_id = NULL;
|
||||||
int variant = 0;
|
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
@ -733,19 +759,26 @@ int dso__load(struct dso *self, symbol_filter_t filter, int verbose)
|
|||||||
|
|
||||||
self->adjust_symbols = 0;
|
self->adjust_symbols = 0;
|
||||||
|
|
||||||
if (strncmp(self->name, "/tmp/perf-", 10) == 0)
|
if (strncmp(self->name, "/tmp/perf-", 10) == 0) {
|
||||||
return dso__load_perf_map(self, filter, verbose);
|
ret = dso__load_perf_map(self, filter, verbose);
|
||||||
|
self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT :
|
||||||
|
DSO__ORIG_NOT_FOUND;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
self->origin = DSO__ORIG_FEDORA - 1;
|
||||||
|
|
||||||
more:
|
more:
|
||||||
do {
|
do {
|
||||||
switch (variant) {
|
self->origin++;
|
||||||
case 0: /* Fedora */
|
switch (self->origin) {
|
||||||
|
case DSO__ORIG_FEDORA:
|
||||||
snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
|
snprintf(name, size, "/usr/lib/debug%s.debug", self->name);
|
||||||
break;
|
break;
|
||||||
case 1: /* Ubuntu */
|
case DSO__ORIG_UBUNTU:
|
||||||
snprintf(name, size, "/usr/lib/debug%s", self->name);
|
snprintf(name, size, "/usr/lib/debug%s", self->name);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case DSO__ORIG_BUILDID:
|
||||||
build_id = dso__read_build_id(self, verbose);
|
build_id = dso__read_build_id(self, verbose);
|
||||||
if (build_id != NULL) {
|
if (build_id != NULL) {
|
||||||
snprintf(name, size,
|
snprintf(name, size,
|
||||||
@ -754,16 +787,15 @@ more:
|
|||||||
free(build_id);
|
free(build_id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
variant++;
|
self->origin++;
|
||||||
/* Fall thru */
|
/* Fall thru */
|
||||||
case 3: /* Sane people */
|
case DSO__ORIG_DSO:
|
||||||
snprintf(name, size, "%s", self->name);
|
snprintf(name, size, "%s", self->name);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
variant++;
|
|
||||||
|
|
||||||
fd = open(name, O_RDONLY);
|
fd = open(name, O_RDONLY);
|
||||||
} while (fd < 0);
|
} while (fd < 0);
|
||||||
@ -899,6 +931,9 @@ int dso__load_kernel(struct dso *self, const char *vmlinux,
|
|||||||
if (err <= 0)
|
if (err <= 0)
|
||||||
err = dso__load_kallsyms(self, filter, verbose);
|
err = dso__load_kallsyms(self, filter, verbose);
|
||||||
|
|
||||||
|
if (err > 0)
|
||||||
|
self->origin = DSO__ORIG_KERNEL;
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ struct dso {
|
|||||||
unsigned int sym_priv_size;
|
unsigned int sym_priv_size;
|
||||||
unsigned char adjust_symbols;
|
unsigned char adjust_symbols;
|
||||||
unsigned char slen_calculated;
|
unsigned char slen_calculated;
|
||||||
|
unsigned char origin;
|
||||||
char name[0];
|
char name[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -49,6 +50,7 @@ int dso__load_modules(struct dso *self, symbol_filter_t filter, int verbose);
|
|||||||
int dso__load(struct dso *self, symbol_filter_t filter, int verbose);
|
int dso__load(struct dso *self, symbol_filter_t filter, int verbose);
|
||||||
|
|
||||||
size_t dso__fprintf(struct dso *self, FILE *fp);
|
size_t dso__fprintf(struct dso *self, FILE *fp);
|
||||||
|
char dso__symtab_origin(const struct dso *self);
|
||||||
|
|
||||||
void symbol__init(void);
|
void symbol__init(void);
|
||||||
#endif /* _PERF_SYMBOL_ */
|
#endif /* _PERF_SYMBOL_ */
|
||||||
|
Loading…
Reference in New Issue
Block a user