perf tools: Make it possible to read object code from kernel modules

The new "object code reading" test shows that it is not possible to read
object code from kernel modules.  That is because the mappings do not
map to the dsos.  This patch fixes that.

This involves identifying and flagging relocatable (ELF type ET_REL)
files (e.g. kernel modules) for symbol adjustment and updating
map__rip_2objdump() accordingly.  The kmodule parameter of
dso__load_sym() is taken into use and the module map altered to map to
the dso.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1375875537-4509-7-git-send-email-adrian.hunter@intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Adrian Hunter 2013-08-07 14:38:50 +03:00 коммит произвёл Arnaldo Carvalho de Melo
Родитель d380b34830
Коммит 0131c4ec79
5 изменённых файлов: 43 добавлений и 9 удалений

Просмотреть файл

@ -419,6 +419,7 @@ struct dso *dso__new(const char *name)
dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
dso->data_type = DSO_BINARY_TYPE__NOT_FOUND; dso->data_type = DSO_BINARY_TYPE__NOT_FOUND;
dso->loaded = 0; dso->loaded = 0;
dso->rel = 0;
dso->sorted_by_name = 0; dso->sorted_by_name = 0;
dso->has_build_id = 0; dso->has_build_id = 0;
dso->kernel = DSO_TYPE_USER; dso->kernel = DSO_TYPE_USER;

Просмотреть файл

@ -85,6 +85,7 @@ struct dso {
u8 lname_alloc:1; u8 lname_alloc:1;
u8 sorted_by_name; u8 sorted_by_name;
u8 loaded; u8 loaded;
u8 rel;
u8 build_id[BUILD_ID_SIZE]; u8 build_id[BUILD_ID_SIZE];
const char *short_name; const char *short_name;
char *long_name; char *long_name;

Просмотреть файл

@ -248,14 +248,18 @@ size_t map__fprintf_dsoname(struct map *map, FILE *fp)
/* /*
* objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN. * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
* map->dso->adjust_symbols==1 for ET_EXEC-like cases. * map->dso->adjust_symbols==1 for ET_EXEC-like cases except ET_REL which is
* relative to section start.
*/ */
u64 map__rip_2objdump(struct map *map, u64 rip) u64 map__rip_2objdump(struct map *map, u64 rip)
{ {
u64 addr = map->dso->adjust_symbols ? if (!map->dso->adjust_symbols)
map->unmap_ip(map, rip) : /* RIP -> IP */ return rip;
rip;
return addr; if (map->dso->rel)
return rip - map->pgoff;
return map->unmap_ip(map, rip);
} }
void map_groups__init(struct map_groups *mg) void map_groups__init(struct map_groups *mg)

Просмотреть файл

@ -599,11 +599,13 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
if (dso->kernel == DSO_TYPE_USER) { if (dso->kernel == DSO_TYPE_USER) {
GElf_Shdr shdr; GElf_Shdr shdr;
ss->adjust_symbols = (ehdr.e_type == ET_EXEC || ss->adjust_symbols = (ehdr.e_type == ET_EXEC ||
ehdr.e_type == ET_REL ||
elf_section_by_name(elf, &ehdr, &shdr, elf_section_by_name(elf, &ehdr, &shdr,
".gnu.prelink_undo", ".gnu.prelink_undo",
NULL) != NULL); NULL) != NULL);
} else { } else {
ss->adjust_symbols = ehdr.e_type == ET_EXEC; ss->adjust_symbols = ehdr.e_type == ET_EXEC ||
ehdr.e_type == ET_REL;
} }
ss->name = strdup(name); ss->name = strdup(name);
@ -676,6 +678,14 @@ int dso__load_sym(struct dso *dso, struct map *map,
bool remap_kernel = false, adjust_kernel_syms = false; bool remap_kernel = false, adjust_kernel_syms = false;
dso->symtab_type = syms_ss->type; dso->symtab_type = syms_ss->type;
dso->rel = syms_ss->ehdr.e_type == ET_REL;
/*
* Modules may already have symbols from kallsyms, but those symbols
* have the wrong values for the dso maps, so remove them.
*/
if (kmodule && syms_ss->symtab)
symbols__delete(&dso->symbols[map->type]);
if (!syms_ss->symtab) { if (!syms_ss->symtab) {
syms_ss->symtab = syms_ss->dynsym; syms_ss->symtab = syms_ss->dynsym;
@ -828,11 +838,24 @@ int dso__load_sym(struct dso *dso, struct map *map,
map_groups__insert(kmap->kmaps, map); map_groups__insert(kmap->kmaps, map);
} }
/*
* The initial module mapping is based on
* /proc/modules mapped to offset zero.
* Overwrite it to map to the module dso.
*/
if (remap_kernel && kmodule) {
remap_kernel = false;
map->pgoff = shdr.sh_offset;
}
curr_map = map; curr_map = map;
curr_dso = dso; curr_dso = dso;
goto new_symbol; goto new_symbol;
} }
if (!kmap)
goto new_symbol;
snprintf(dso_name, sizeof(dso_name), snprintf(dso_name, sizeof(dso_name),
"%s%s", dso->short_name, section_name); "%s%s", dso->short_name, section_name);

Просмотреть файл

@ -854,10 +854,15 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
if (!runtime_ss && syms_ss) if (!runtime_ss && syms_ss)
runtime_ss = syms_ss; runtime_ss = syms_ss;
if (syms_ss) if (syms_ss) {
ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, 0); int km;
else
km = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE;
ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, km);
} else {
ret = -1; ret = -1;
}
if (ret > 0) { if (ret > 0) {
int nr_plt; int nr_plt;