perf symbols: Accept symbols starting at address 0

That is the case of _text on s390, and we have some functions that return an
address, using address zero to report problems, oops.

This would lead the symbol loading routines to not use "_text" as the reference
relocation symbol, or the first symbol for the kernel, but use instead
"_stext", that is at the same address on x86_64 and others, but not on s390:

  [acme@localhost perf-4.11.0-rc6]$ head -15 /proc/kallsyms
  0000000000000000 T _text
  0000000000000418 t iplstart
  0000000000000800 T start
  000000000000080a t .base
  000000000000082e t .sk8x8
  0000000000000834 t .gotr
  0000000000000842 t .cmd
  0000000000000846 t .parm
  000000000000084a t .lowcase
  0000000000010000 T startup
  0000000000010010 T startup_kdump
  0000000000010214 t startup_kdump_relocated
  0000000000011000 T startup_continue
  00000000000112a0 T _ehead
  0000000000100000 T _stext
  [acme@localhost perf-4.11.0-rc6]$

Which in turn would make 'perf test vmlinux' to fail because it wouldn't find
the symbols before "_stext" in kallsyms.

Fix it by using the return value only for errors and storing the
address, when the symbol is successfully found, in a provided pointer
arg.

Before this patch:

After:

  [acme@localhost perf-4.11.0-rc6]$ tools/perf/perf test -v 1
   1: vmlinux symtab matches kallsyms            :
  --- start ---
  test child forked, pid 40693
  Looking at the vmlinux_path (8 entries long)
  Using /usr/lib/debug/lib/modules/3.10.0-654.el7.s390x/vmlinux for symbols
  ERR : 0: _text not on kallsyms
  ERR : 0x418: iplstart not on kallsyms
  ERR : 0x800: start not on kallsyms
  ERR : 0x80a: .base not on kallsyms
  ERR : 0x82e: .sk8x8 not on kallsyms
  ERR : 0x834: .gotr not on kallsyms
  ERR : 0x842: .cmd not on kallsyms
  ERR : 0x846: .parm not on kallsyms
  ERR : 0x84a: .lowcase not on kallsyms
  ERR : 0x10000: startup not on kallsyms
  ERR : 0x10010: startup_kdump not on kallsyms
  ERR : 0x10214: startup_kdump_relocated not on kallsyms
  ERR : 0x11000: startup_continue not on kallsyms
  ERR : 0x112a0: _ehead not on kallsyms
  <SNIP warnings>
  test child finished with -1
  ---- end ----
  vmlinux symtab matches kallsyms: FAILED!
  [acme@localhost perf-4.11.0-rc6]$

After:

  [acme@localhost perf-4.11.0-rc6]$ tools/perf/perf test -v 1
   1: vmlinux symtab matches kallsyms            :
  --- start ---
  test child forked, pid 47160
  <SNIP warnings>
  test child finished with 0
  ---- end ----
  vmlinux symtab matches kallsyms: Ok
  [acme@localhost perf-4.11.0-rc6]$
Reported-by: default avatarMichael Petlan <mpetlan@redhat.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Wang Nan <wangnan0@huawei.com>
Link: http://lkml.kernel.org/n/tip-9x9bwgd3btwdk1u51xie93fz@git.kernel.orgSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 96395cbb
......@@ -49,19 +49,22 @@ static bool same_kallsyms_reloc(const char *from_dir, char *to_dir)
char to[PATH_MAX];
const char *name;
u64 addr1 = 0, addr2 = 0;
int i;
int i, err = -1;
scnprintf(from, sizeof(from), "%s/kallsyms", from_dir);
scnprintf(to, sizeof(to), "%s/kallsyms", to_dir);
for (i = 0; (name = ref_reloc_sym_names[i]) != NULL; i++) {
addr1 = kallsyms__get_function_start(from, name);
if (addr1)
err = kallsyms__get_function_start(from, name, &addr1);
if (!err)
break;
}
if (name)
addr2 = kallsyms__get_function_start(to, name);
if (err)
return false;
if (kallsyms__get_function_start(to, name, &addr2))
return false;
return addr1 == addr2;
}
......
......@@ -768,15 +768,16 @@ static int find_symbol_cb(void *arg, const char *name, char type,
return 1;
}
u64 kallsyms__get_function_start(const char *kallsyms_filename,
const char *symbol_name)
int kallsyms__get_function_start(const char *kallsyms_filename,
const char *symbol_name, u64 *addr)
{
struct process_symbol_args args = { .name = symbol_name, };
if (kallsyms__parse(kallsyms_filename, &args, find_symbol_cb) <= 0)
return 0;
return -1;
return args.start;
*addr = args.start;
return 0;
}
int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
......
......@@ -675,8 +675,8 @@ size_t perf_event__fprintf_cpu_map(union perf_event *event, FILE *fp);
size_t perf_event__fprintf_namespaces(union perf_event *event, FILE *fp);
size_t perf_event__fprintf(union perf_event *event, FILE *fp);
u64 kallsyms__get_function_start(const char *kallsyms_filename,
const char *symbol_name);
int kallsyms__get_function_start(const char *kallsyms_filename,
const char *symbol_name, u64 *addr);
void *cpu_map_data__alloc(struct cpu_map *map, size_t *size, u16 *type, int *max);
void cpu_map_data__synthesize(struct cpu_map_data *data, struct cpu_map *map,
......
......@@ -796,11 +796,11 @@ const char *ref_reloc_sym_names[] = {"_text", "_stext", NULL};
* Returns the name of the start symbol in *symbol_name. Pass in NULL as
* symbol_name if it's not that important.
*/
static u64 machine__get_running_kernel_start(struct machine *machine,
const char **symbol_name)
static int machine__get_running_kernel_start(struct machine *machine,
const char **symbol_name, u64 *start)
{
char filename[PATH_MAX];
int i;
int i, err = -1;
const char *name;
u64 addr = 0;
......@@ -810,21 +810,28 @@ static u64 machine__get_running_kernel_start(struct machine *machine,
return 0;
for (i = 0; (name = ref_reloc_sym_names[i]) != NULL; i++) {
addr = kallsyms__get_function_start(filename, name);
if (addr)
err = kallsyms__get_function_start(filename, name, &addr);
if (!err)
break;
}
if (err)
return -1;
if (symbol_name)
*symbol_name = name;
return addr;
*start = addr;
return 0;
}
int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel)
{
int type;
u64 start = machine__get_running_kernel_start(machine, NULL);
u64 start = 0;
if (machine__get_running_kernel_start(machine, NULL, &start))
return -1;
/* In case of renewal the kernel map, destroy previous one */
machine__destroy_kernel_maps(machine);
......@@ -1185,8 +1192,8 @@ static int machine__create_modules(struct machine *machine)
int machine__create_kernel_maps(struct machine *machine)
{
struct dso *kernel = machine__get_kernel(machine);
const char *name;
u64 addr;
const char *name = NULL;
u64 addr = 0;
int ret;
if (kernel == NULL)
......@@ -1211,8 +1218,7 @@ int machine__create_kernel_maps(struct machine *machine)
*/
map_groups__fixup_end(&machine->kmaps);
addr = machine__get_running_kernel_start(machine, &name);
if (!addr) {
if (machine__get_running_kernel_start(machine, &name, &addr)) {
} else if (maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, name, addr)) {
machine__destroy_kernel_maps(machine);
return -1;
......
......@@ -466,7 +466,7 @@ void dso__insert_symbol(struct dso *dso, enum map_type type, struct symbol *sym)
struct symbol *dso__find_symbol(struct dso *dso,
enum map_type type, u64 addr)
{
if (dso->last_find_result[type].addr != addr) {
if (dso->last_find_result[type].addr != addr || dso->last_find_result[type].symbol == NULL) {
dso->last_find_result[type].addr = addr;
dso->last_find_result[type].symbol = symbols__find(&dso->symbols[type], addr);
}
......@@ -1075,8 +1075,9 @@ static int validate_kcore_addresses(const char *kallsyms_filename,
if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) {
u64 start;
start = kallsyms__get_function_start(kallsyms_filename,
kmap->ref_reloc_sym->name);
if (kallsyms__get_function_start(kallsyms_filename,
kmap->ref_reloc_sym->name, &start))
return -ENOENT;
if (start != kmap->ref_reloc_sym->addr)
return -EINVAL;
}
......@@ -1248,9 +1249,7 @@ static int kallsyms__delta(struct map *map, const char *filename, u64 *delta)
if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name)
return 0;
addr = kallsyms__get_function_start(filename,
kmap->ref_reloc_sym->name);
if (!addr)
if (kallsyms__get_function_start(filename, kmap->ref_reloc_sym->name, &addr))
return -1;
*delta = addr - kmap->ref_reloc_sym->addr;
......
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