perf symbols: Cache /proc/kallsyms files by build-id
So that when we don't have a vmlinux handy we can store the kallsyms for later use by 'perf report'. Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Frédéric Weisbecker <fweisbec@gmail.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> LKML-Reference: <1263501006-14185-3-git-send-email-acme@infradead.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
8d0591f6ad
commit
9e201442de
@ -245,7 +245,7 @@ int event__synthesize_kernel_mmap(event__handler_t process,
|
|||||||
*/
|
*/
|
||||||
struct process_symbol_args args = { .name = symbol_name, };
|
struct process_symbol_args args = { .name = symbol_name, };
|
||||||
|
|
||||||
if (kallsyms__parse(&args, find_symbol_cb) <= 0)
|
if (kallsyms__parse("/proc/kallsyms", &args, find_symbol_cb) <= 0)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename),
|
size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename),
|
||||||
|
@ -237,11 +237,13 @@ static int dso__cache_build_id(struct dso *self, const char *debugdir)
|
|||||||
char *filename = malloc(size),
|
char *filename = malloc(size),
|
||||||
*linkname = malloc(size), *targetname, *sbuild_id;
|
*linkname = malloc(size), *targetname, *sbuild_id;
|
||||||
int len, err = -1;
|
int len, err = -1;
|
||||||
|
bool is_kallsyms = self->kernel && self->long_name[0] != '/';
|
||||||
|
|
||||||
if (filename == NULL || linkname == NULL)
|
if (filename == NULL || linkname == NULL)
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
|
||||||
len = snprintf(filename, size, "%s%s", debugdir, self->long_name);
|
len = snprintf(filename, size, "%s%s%s",
|
||||||
|
debugdir, is_kallsyms ? "/" : "", self->long_name);
|
||||||
if (mkdir_p(filename, 0755))
|
if (mkdir_p(filename, 0755))
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
|
||||||
@ -249,9 +251,14 @@ static int dso__cache_build_id(struct dso *self, const char *debugdir)
|
|||||||
sbuild_id = filename + len;
|
sbuild_id = filename + len;
|
||||||
build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
|
build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id);
|
||||||
|
|
||||||
if (access(filename, F_OK) && link(self->long_name, filename) &&
|
if (access(filename, F_OK)) {
|
||||||
|
if (is_kallsyms) {
|
||||||
|
if (copyfile("/proc/kallsyms", filename))
|
||||||
|
goto out_free;
|
||||||
|
} else if (link(self->long_name, filename) &&
|
||||||
copyfile(self->long_name, filename))
|
copyfile(self->long_name, filename))
|
||||||
goto out_free;
|
goto out_free;
|
||||||
|
}
|
||||||
|
|
||||||
len = snprintf(linkname, size, "%s/.build-id/%.2s",
|
len = snprintf(linkname, size, "%s/.build-id/%.2s",
|
||||||
debugdir, sbuild_id);
|
debugdir, sbuild_id);
|
||||||
|
@ -383,13 +383,14 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int kallsyms__parse(void *arg, int (*process_symbol)(void *arg, const char *name,
|
int kallsyms__parse(const char *filename, void *arg,
|
||||||
|
int (*process_symbol)(void *arg, const char *name,
|
||||||
char type, u64 start))
|
char type, u64 start))
|
||||||
{
|
{
|
||||||
char *line = NULL;
|
char *line = NULL;
|
||||||
size_t n;
|
size_t n;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
FILE *file = fopen("/proc/kallsyms", "r");
|
FILE *file = fopen(filename, "r");
|
||||||
|
|
||||||
if (file == NULL)
|
if (file == NULL)
|
||||||
goto out_failure;
|
goto out_failure;
|
||||||
@ -466,10 +467,11 @@ static int map__process_kallsym_symbol(void *arg, const char *name,
|
|||||||
* so that we can in the next step set the symbol ->end address and then
|
* so that we can in the next step set the symbol ->end address and then
|
||||||
* call kernel_maps__split_kallsyms.
|
* call kernel_maps__split_kallsyms.
|
||||||
*/
|
*/
|
||||||
static int dso__load_all_kallsyms(struct dso *self, struct map *map)
|
static int dso__load_all_kallsyms(struct dso *self, const char *filename,
|
||||||
|
struct map *map)
|
||||||
{
|
{
|
||||||
struct process_kallsyms_args args = { .map = map, .dso = self, };
|
struct process_kallsyms_args args = { .map = map, .dso = self, };
|
||||||
return kallsyms__parse(&args, map__process_kallsym_symbol);
|
return kallsyms__parse(filename, &args, map__process_kallsym_symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -556,10 +558,10 @@ discard_symbol: rb_erase(&pos->rb_node, root);
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int dso__load_kallsyms(struct dso *self, struct map *map,
|
static int dso__load_kallsyms(struct dso *self, const char *filename, struct map *map,
|
||||||
struct perf_session *session, symbol_filter_t filter)
|
struct perf_session *session, symbol_filter_t filter)
|
||||||
{
|
{
|
||||||
if (dso__load_all_kallsyms(self, map) < 0)
|
if (dso__load_all_kallsyms(self, filename, map) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
symbols__fixup_end(&self->symbols[map->type]);
|
symbols__fixup_end(&self->symbols[map->type]);
|
||||||
@ -1580,7 +1582,8 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
|
|||||||
struct perf_session *session, symbol_filter_t filter)
|
struct perf_session *session, symbol_filter_t filter)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
bool is_kallsyms;
|
const char *kallsyms_filename = NULL;
|
||||||
|
char *kallsyms_allocated_filename = NULL;
|
||||||
|
|
||||||
if (vmlinux_path != NULL) {
|
if (vmlinux_path != NULL) {
|
||||||
int i;
|
int i;
|
||||||
@ -1606,19 +1609,37 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map,
|
|||||||
*/
|
*/
|
||||||
if (self->has_build_id) {
|
if (self->has_build_id) {
|
||||||
u8 kallsyms_build_id[BUILD_ID_SIZE];
|
u8 kallsyms_build_id[BUILD_ID_SIZE];
|
||||||
|
char sbuild_id[BUILD_ID_SIZE * 2 + 1];
|
||||||
|
|
||||||
if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
|
if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id,
|
||||||
sizeof(kallsyms_build_id)) == 0) {
|
sizeof(kallsyms_build_id)) == 0) {
|
||||||
is_kallsyms = dso__build_id_equal(self, kallsyms_build_id);
|
if (dso__build_id_equal(self, kallsyms_build_id)) {
|
||||||
if (is_kallsyms)
|
kallsyms_filename = "/proc/kallsyms";
|
||||||
goto do_kallsyms;
|
goto do_kallsyms;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
build_id__sprintf(self->build_id, sizeof(self->build_id),
|
||||||
|
sbuild_id);
|
||||||
|
|
||||||
|
if (asprintf(&kallsyms_allocated_filename,
|
||||||
|
"%s/.debug/[kernel.kallsyms]/%s",
|
||||||
|
getenv("HOME"), sbuild_id) != -1) {
|
||||||
|
if (access(kallsyms_filename, F_OK)) {
|
||||||
|
kallsyms_filename = kallsyms_allocated_filename;
|
||||||
|
goto do_kallsyms;
|
||||||
|
}
|
||||||
|
free(kallsyms_allocated_filename);
|
||||||
|
kallsyms_allocated_filename = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
goto do_vmlinux;
|
goto do_vmlinux;
|
||||||
}
|
}
|
||||||
|
|
||||||
is_kallsyms = self->long_name[0] == '[';
|
if (self->long_name[0] == '[') {
|
||||||
if (is_kallsyms)
|
kallsyms_filename = "/proc/kallsyms";
|
||||||
goto do_kallsyms;
|
goto do_kallsyms;
|
||||||
|
}
|
||||||
|
|
||||||
do_vmlinux:
|
do_vmlinux:
|
||||||
err = dso__load_vmlinux(self, map, session, self->long_name, filter);
|
err = dso__load_vmlinux(self, map, session, self->long_name, filter);
|
||||||
@ -1629,9 +1650,10 @@ do_vmlinux:
|
|||||||
pr_info("The file %s cannot be used, "
|
pr_info("The file %s cannot be used, "
|
||||||
"trying to use /proc/kallsyms...", self->long_name);
|
"trying to use /proc/kallsyms...", self->long_name);
|
||||||
do_kallsyms:
|
do_kallsyms:
|
||||||
err = dso__load_kallsyms(self, map, session, filter);
|
err = dso__load_kallsyms(self, kallsyms_filename, map, session, filter);
|
||||||
if (err > 0 && !is_kallsyms)
|
if (err > 0 && kallsyms_filename == NULL)
|
||||||
dso__set_long_name(self, strdup("[kernel.kallsyms]"));
|
dso__set_long_name(self, strdup("[kernel.kallsyms]"));
|
||||||
|
free(kallsyms_allocated_filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err > 0) {
|
if (err > 0) {
|
||||||
|
@ -144,7 +144,8 @@ int filename__read_build_id(const char *filename, void *bf, size_t size);
|
|||||||
int sysfs__read_build_id(const char *filename, void *bf, size_t size);
|
int sysfs__read_build_id(const char *filename, void *bf, size_t size);
|
||||||
bool dsos__read_build_ids(void);
|
bool dsos__read_build_ids(void);
|
||||||
int build_id__sprintf(u8 *self, int len, char *bf);
|
int build_id__sprintf(u8 *self, int len, char *bf);
|
||||||
int kallsyms__parse(void *arg, int (*process_symbol)(void *arg, const char *name,
|
int kallsyms__parse(const char *filename, void *arg,
|
||||||
|
int (*process_symbol)(void *arg, const char *name,
|
||||||
char type, u64 start));
|
char type, u64 start));
|
||||||
|
|
||||||
int symbol__init(void);
|
int symbol__init(void);
|
||||||
|
@ -32,6 +32,33 @@ int mkdir_p(char *path, mode_t mode)
|
|||||||
return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
|
return (stat(path, &st) && mkdir(path, mode)) ? -1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int slow_copyfile(const char *from, const char *to)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
char *line = NULL;
|
||||||
|
size_t n;
|
||||||
|
FILE *from_fp = fopen(from, "r"), *to_fp;
|
||||||
|
|
||||||
|
if (from_fp == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
to_fp = fopen(to, "w");
|
||||||
|
if (to_fp == NULL)
|
||||||
|
goto out_fclose_from;
|
||||||
|
|
||||||
|
while (getline(&line, &n, from_fp) > 0)
|
||||||
|
if (fputs(line, to_fp) == EOF)
|
||||||
|
goto out_fclose_to;
|
||||||
|
err = 0;
|
||||||
|
out_fclose_to:
|
||||||
|
fclose(to_fp);
|
||||||
|
free(line);
|
||||||
|
out_fclose_from:
|
||||||
|
fclose(from_fp);
|
||||||
|
out:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
int copyfile(const char *from, const char *to)
|
int copyfile(const char *from, const char *to)
|
||||||
{
|
{
|
||||||
int fromfd, tofd;
|
int fromfd, tofd;
|
||||||
@ -42,6 +69,9 @@ int copyfile(const char *from, const char *to)
|
|||||||
if (stat(from, &st))
|
if (stat(from, &st))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
if (st.st_size == 0) /* /proc? do it slowly... */
|
||||||
|
return slow_copyfile(from, to);
|
||||||
|
|
||||||
fromfd = open(from, O_RDONLY);
|
fromfd = open(from, O_RDONLY);
|
||||||
if (fromfd < 0)
|
if (fromfd < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user