perf symbols: Improve kallsyms symbol end addr calculation

For kallsyms we don't have the symbol address end, so we do an extra pass and
set the symbol end addr as being the start of the next minus one.

But this was being done just after we filtered the symbols of a
particular type (functions, variables), so the symbol end was sometimes
after what it really is.

Fixing up symbol end also was falling apart when we have symbol aliases,
then the end address of all but the last alias was being set to be
before its start.

Fix it up by checking for symbol aliases and making the kallsyms__parse
routine use the next symbol, whatever its type, as the limit for the
previous symbol, passing that end address to the callback.

This was detected by the 'perf test' synthetic paranoid regression
tests, fix it up so that even that case doesn't mislead us.

Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Stephane Eranian <eranian@google.com>
LKML-Reference: <new-submission>
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 9fb67204
...@@ -332,7 +332,8 @@ struct process_symbol_args { ...@@ -332,7 +332,8 @@ struct process_symbol_args {
u64 start; u64 start;
}; };
static int find_symbol_cb(void *arg, const char *name, char type, u64 start) static int find_symbol_cb(void *arg, const char *name, char type,
u64 start, u64 end __used)
{ {
struct process_symbol_args *args = arg; struct process_symbol_args *args = arg;
......
...@@ -22,6 +22,10 @@ ...@@ -22,6 +22,10 @@
#include <limits.h> #include <limits.h>
#include <sys/utsname.h> #include <sys/utsname.h>
#ifndef KSYM_NAME_LEN
#define KSYM_NAME_LEN 128
#endif
#ifndef NT_GNU_BUILD_ID #ifndef NT_GNU_BUILD_ID
#define NT_GNU_BUILD_ID 3 #define NT_GNU_BUILD_ID 3
#endif #endif
...@@ -93,7 +97,7 @@ static void symbols__fixup_end(struct rb_root *self) ...@@ -93,7 +97,7 @@ static void symbols__fixup_end(struct rb_root *self)
prev = curr; prev = curr;
curr = rb_entry(nd, struct symbol, rb_node); curr = rb_entry(nd, struct symbol, rb_node);
if (prev->end == prev->start) if (prev->end == prev->start && prev->end != curr->start)
prev->end = curr->start - 1; prev->end = curr->start - 1;
} }
...@@ -426,16 +430,25 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp) ...@@ -426,16 +430,25 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp)
int kallsyms__parse(const char *filename, void *arg, int kallsyms__parse(const char *filename, void *arg,
int (*process_symbol)(void *arg, const char *name, int (*process_symbol)(void *arg, const char *name,
char type, u64 start)) char type, u64 start, u64 end))
{ {
char *line = NULL; char *line = NULL;
size_t n; size_t n;
int err = 0; int err = -1;
u64 prev_start = 0;
char prev_symbol_type = 0;
char *prev_symbol_name;
FILE *file = fopen(filename, "r"); FILE *file = fopen(filename, "r");
if (file == NULL) if (file == NULL)
goto out_failure; goto out_failure;
prev_symbol_name = malloc(KSYM_NAME_LEN);
if (prev_symbol_name == NULL)
goto out_close;
err = 0;
while (!feof(file)) { while (!feof(file)) {
u64 start; u64 start;
int line_len, len; int line_len, len;
...@@ -455,14 +468,33 @@ int kallsyms__parse(const char *filename, void *arg, ...@@ -455,14 +468,33 @@ int kallsyms__parse(const char *filename, void *arg,
continue; continue;
symbol_type = toupper(line[len]); symbol_type = toupper(line[len]);
symbol_name = line + len + 2; len += 2;
symbol_name = line + len;
len = line_len - len;
err = process_symbol(arg, symbol_name, symbol_type, start); if (len >= KSYM_NAME_LEN) {
if (err) err = -1;
break; break;
}
if (prev_symbol_type) {
u64 end = start;
if (end != prev_start)
--end;
err = process_symbol(arg, prev_symbol_name,
prev_symbol_type, prev_start, end);
if (err)
break;
}
memcpy(prev_symbol_name, symbol_name, len + 1);
prev_symbol_type = symbol_type;
prev_start = start;
} }
free(prev_symbol_name);
free(line); free(line);
out_close:
fclose(file); fclose(file);
return err; return err;
...@@ -484,7 +516,7 @@ static u8 kallsyms2elf_type(char type) ...@@ -484,7 +516,7 @@ static u8 kallsyms2elf_type(char type)
} }
static int map__process_kallsym_symbol(void *arg, const char *name, static int map__process_kallsym_symbol(void *arg, const char *name,
char type, u64 start) char type, u64 start, u64 end)
{ {
struct symbol *sym; struct symbol *sym;
struct process_kallsyms_args *a = arg; struct process_kallsyms_args *a = arg;
...@@ -493,11 +525,8 @@ static int map__process_kallsym_symbol(void *arg, const char *name, ...@@ -493,11 +525,8 @@ static int map__process_kallsym_symbol(void *arg, const char *name,
if (!symbol_type__is_a(type, a->map->type)) if (!symbol_type__is_a(type, a->map->type))
return 0; return 0;
/* sym = symbol__new(start, end - start + 1,
* Will fix up the end later, when we have all symbols sorted. kallsyms2elf_type(type), name);
*/
sym = symbol__new(start, 0, kallsyms2elf_type(type), name);
if (sym == NULL) if (sym == NULL)
return -ENOMEM; return -ENOMEM;
/* /*
...@@ -650,7 +679,6 @@ int dso__load_kallsyms(struct dso *self, const char *filename, ...@@ -650,7 +679,6 @@ int dso__load_kallsyms(struct dso *self, const char *filename,
if (dso__load_all_kallsyms(self, filename, map) < 0) if (dso__load_all_kallsyms(self, filename, map) < 0)
return -1; return -1;
symbols__fixup_end(&self->symbols[map->type]);
if (self->kernel == DSO_TYPE_GUEST_KERNEL) if (self->kernel == DSO_TYPE_GUEST_KERNEL)
self->origin = DSO__ORIG_GUEST_KERNEL; self->origin = DSO__ORIG_GUEST_KERNEL;
else else
...@@ -2162,7 +2190,7 @@ struct process_args { ...@@ -2162,7 +2190,7 @@ struct process_args {
}; };
static int symbol__in_kernel(void *arg, const char *name, static int symbol__in_kernel(void *arg, const char *name,
char type __used, u64 start) char type __used, u64 start, u64 end __used)
{ {
struct process_args *args = arg; struct process_args *args = arg;
......
...@@ -215,7 +215,7 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits); ...@@ -215,7 +215,7 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits);
int build_id__sprintf(const u8 *self, int len, char *bf); int build_id__sprintf(const u8 *self, int len, char *bf);
int kallsyms__parse(const char *filename, void *arg, int kallsyms__parse(const char *filename, void *arg,
int (*process_symbol)(void *arg, const char *name, int (*process_symbol)(void *arg, const char *name,
char type, u64 start)); char type, u64 start, u64 end));
void machine__destroy_kernel_maps(struct machine *self); void machine__destroy_kernel_maps(struct machine *self);
int __machine__create_kernel_maps(struct machine *self, struct dso *kernel); int __machine__create_kernel_maps(struct machine *self, struct dso *kernel);
......
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