perf annotate: Use build-ids to find the right DSO

We were still using the pathname found on the MMAP event, that could not
be the one we used when recording, so use the build-id cache for that,
only falling back to use the pathname in the MMAP event if no build-ids
are available.

With this we now also are able to do secure, seamless offline annotation.

Example:

[root@doppio linux-2.6-tip]# perf report -g none -v 2> /dev/null | head -10
     8.12%     Xorg  /usr/lib64/libpixman-1.so.0.14.0       0x0000000000026d02 B [.] pixman_rasterize_edges
     4.68%  firefox  /usr/lib64/xulrunner-1.9.1/libxul.so   0x00000000005dbdba B [.] 0x000000005dbdba
     3.70%  swapper  /lib/modules/2.6.34-rc6/build/vmlinux  0xffffffff81022cea ! [k] read_hpet
     2.96%     init  /lib/modules/2.6.34-rc6/build/vmlinux  0xffffffff81022cea ! [k] read_hpet
     2.73%  swapper  /lib/modules/2.6.34-rc6/build/vmlinux  0xffffffff8100a738 ! [k] mwait_idle_with_hints
[root@doppio linux-2.6-tip]# perf annotate -v pixman_rasterize_edges 2>&1 | grep Executing
Executing: objdump --start-address=0x000000371ce26670 --stop-address=0x000000371ce2709f -dS /root/.debug/.build-id/bd/6ac5199137aaeb279f864717d8d061477466c1|grep -v /root/.debug/.build-id/bd/6ac5199137aaeb279f864717d8d061477466c1|expand
[root@doppio linux-2.6-tip]# perf buildid-list | grep libpixman-1.so.0.14.0
bd6ac5199137aaeb279f864717d8d061477466c1 /usr/lib64/libpixman-1.so.0.14.0
[root@doppio linux-2.6-tip]#
Reported-by: default avatarStephane Eranian <eranian@google.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Cc: Tom Zanussi <tzanussi@gmail.com>
LKML-Reference: <new-submission>
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 17930b40
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
* Copyright (C) 2009, 2010 Red Hat Inc. * Copyright (C) 2009, 2010 Red Hat Inc.
* Copyright (C) 2009, 2010 Arnaldo Carvalho de Melo <acme@redhat.com> * Copyright (C) 2009, 2010 Arnaldo Carvalho de Melo <acme@redhat.com>
*/ */
#include "util.h"
#include <stdio.h>
#include "build-id.h" #include "build-id.h"
#include "event.h" #include "event.h"
#include "symbol.h" #include "symbol.h"
...@@ -37,3 +39,23 @@ struct perf_event_ops build_id__mark_dso_hit_ops = { ...@@ -37,3 +39,23 @@ struct perf_event_ops build_id__mark_dso_hit_ops = {
.mmap = event__process_mmap, .mmap = event__process_mmap,
.fork = event__process_task, .fork = event__process_task,
}; };
char *dso__build_id_filename(struct dso *self, char *bf, size_t size)
{
char build_id_hex[BUILD_ID_SIZE * 2 + 1];
const char *home;
if (!self->has_build_id)
return NULL;
build_id__sprintf(self->build_id, sizeof(self->build_id), build_id_hex);
home = getenv("HOME");
if (bf == NULL) {
if (asprintf(&bf, "%s/%s/.build-id/%.2s/%s", home,
DEBUG_CACHE_DIR, build_id_hex, build_id_hex + 2) < 0)
return NULL;
} else
snprintf(bf, size, "%s/%s/.build-id/%.2s/%s", home,
DEBUG_CACHE_DIR, build_id_hex, build_id_hex + 2);
return bf;
}
...@@ -5,4 +5,6 @@ ...@@ -5,4 +5,6 @@
extern struct perf_event_ops build_id__mark_dso_hit_ops; extern struct perf_event_ops build_id__mark_dso_hit_ops;
char *dso__build_id_filename(struct dso *self, char *bf, size_t size);
#endif #endif
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <errno.h> #include <errno.h>
#include <math.h> #include <math.h>
#include "util.h"
#include "callchain.h" #include "callchain.h"
bool ip_callchain__valid(struct ip_callchain *chain, event_t *event) bool ip_callchain__valid(struct ip_callchain *chain, event_t *event)
......
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/rbtree.h> #include <linux/rbtree.h>
#include "event.h" #include "event.h"
#include "util.h"
#include "symbol.h" #include "symbol.h"
enum chain_mode { enum chain_mode {
......
#include "build-id.h"
#include "util.h" #include "util.h"
#include "hist.h" #include "hist.h"
#include "session.h" #include "session.h"
...@@ -988,22 +989,35 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head) ...@@ -988,22 +989,35 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head)
struct symbol *sym = self->ms.sym; struct symbol *sym = self->ms.sym;
struct map *map = self->ms.map; struct map *map = self->ms.map;
struct dso *dso = map->dso; struct dso *dso = map->dso;
const char *filename = dso->long_name; char *filename = dso__build_id_filename(dso, NULL, 0);
char command[PATH_MAX * 2]; char command[PATH_MAX * 2];
FILE *file; FILE *file;
int err = -1;
u64 len; u64 len;
if (!filename) if (filename == NULL) {
return -1; if (dso->has_build_id) {
pr_err("Can't annotate %s: not enough memory\n",
sym->name);
return -1;
}
/*
* If we don't have build-ids, well, lets hope that this
* DSO is the same as when 'perf record' ran.
*/
filename = dso->long_name;
}
if (dso->origin == DSO__ORIG_KERNEL) { if (dso->origin == DSO__ORIG_KERNEL) {
if (dso->annotate_warned) if (dso->annotate_warned) {
return 0; err = 0;
goto out_free_filename;
}
dso->annotate_warned = 1; dso->annotate_warned = 1;
pr_err("Can't annotate %s: No vmlinux file was found in the " pr_err("Can't annotate %s: No vmlinux file was found in the "
"path:\n", sym->name); "path:\n", sym->name);
vmlinux_path__fprintf(stderr); vmlinux_path__fprintf(stderr);
return -1; goto out_free_filename;
} }
pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__, pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__,
...@@ -1025,14 +1039,18 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head) ...@@ -1025,14 +1039,18 @@ int hist_entry__annotate(struct hist_entry *self, struct list_head *head)
file = popen(command, "r"); file = popen(command, "r");
if (!file) if (!file)
return -1; goto out_free_filename;
while (!feof(file)) while (!feof(file))
if (hist_entry__parse_objdump_line(self, file, head) < 0) if (hist_entry__parse_objdump_line(self, file, head) < 0)
break; break;
pclose(file); pclose(file);
return 0; err = 0;
out_free_filename:
if (dso->has_build_id)
free(filename);
return err;
} }
void hists__inc_nr_events(struct hists *self, u32 type) void hists__inc_nr_events(struct hists *self, u32 type)
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <sys/param.h> #include <sys/param.h>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include "build-id.h"
#include "symbol.h" #include "symbol.h"
#include "strlist.h" #include "strlist.h"
...@@ -1293,7 +1294,6 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) ...@@ -1293,7 +1294,6 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
int size = PATH_MAX; int size = PATH_MAX;
char *name; char *name;
u8 build_id[BUILD_ID_SIZE]; u8 build_id[BUILD_ID_SIZE];
char build_id_hex[BUILD_ID_SIZE * 2 + 1];
int ret = -1; int ret = -1;
int fd; int fd;
struct machine *machine; struct machine *machine;
...@@ -1325,15 +1325,8 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) ...@@ -1325,15 +1325,8 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
} }
self->origin = DSO__ORIG_BUILD_ID_CACHE; self->origin = DSO__ORIG_BUILD_ID_CACHE;
if (dso__build_id_filename(self, name, size) != NULL)
if (self->has_build_id) {
build_id__sprintf(self->build_id, sizeof(self->build_id),
build_id_hex);
snprintf(name, size, "%s/%s/.build-id/%.2s/%s",
getenv("HOME"), DEBUG_CACHE_DIR,
build_id_hex, build_id_hex + 2);
goto open_file; goto open_file;
}
more: more:
do { do {
self->origin++; self->origin++;
...@@ -1349,6 +1342,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) ...@@ -1349,6 +1342,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter)
case DSO__ORIG_BUILDID: case DSO__ORIG_BUILDID:
if (filename__read_build_id(self->long_name, build_id, if (filename__read_build_id(self->long_name, build_id,
sizeof(build_id))) { sizeof(build_id))) {
char build_id_hex[BUILD_ID_SIZE * 2 + 1];
build_id__sprintf(build_id, sizeof(build_id), build_id__sprintf(build_id, sizeof(build_id),
build_id_hex); build_id_hex);
snprintf(name, size, snprintf(name, size,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment