perf tools: Make it possible to read object code from kernel modules
authorAdrian Hunter <adrian.hunter@intel.com>
Wed, 7 Aug 2013 11:38:50 +0000 (14:38 +0300)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Wed, 7 Aug 2013 20:35:32 +0000 (17:35 -0300)
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>
tools/perf/util/dso.c
tools/perf/util/dso.h
tools/perf/util/map.c
tools/perf/util/symbol-elf.c
tools/perf/util/symbol.c

index 121583dbf34bb3792a3c42406cc636892a67d7a1..1955804e82ff83bbdb97701b3a00e626b7576125 100644 (file)
@@ -419,6 +419,7 @@ struct dso *dso__new(const char *name)
                dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND;
                dso->data_type   = DSO_BINARY_TYPE__NOT_FOUND;
                dso->loaded = 0;
+               dso->rel = 0;
                dso->sorted_by_name = 0;
                dso->has_build_id = 0;
                dso->kernel = DSO_TYPE_USER;
index 02aadaf45c63fc2a1e3eb607b5502ff93ca64cfb..735a83751b19fd1cf41733cd1d364f1f18219ae7 100644 (file)
@@ -85,6 +85,7 @@ struct dso {
        u8               lname_alloc:1;
        u8               sorted_by_name;
        u8               loaded;
+       u8               rel;
        u8               build_id[BUILD_ID_SIZE];
        const char       *short_name;
        char             *long_name;
index 5f662a3a0163b3d06569b93a35c373b895c90b27..4d599febfb0b3735ec2a09707f5fb199552f9ea0 100644 (file)
@@ -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.
- * 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 addr = map->dso->adjust_symbols ?
-                       map->unmap_ip(map, rip) :       /* RIP -> IP */
-                       rip;
-       return addr;
+       if (!map->dso->adjust_symbols)
+               return rip;
+
+       if (map->dso->rel)
+               return rip - map->pgoff;
+
+       return map->unmap_ip(map, rip);
 }
 
 void map_groups__init(struct map_groups *mg)
index ed6f443a3e101bcee36a185d3b66832b4bdc16c3..3eaa7b486e2e04badec9f6e4603e8f78da86e50a 100644 (file)
@@ -599,11 +599,13 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
        if (dso->kernel == DSO_TYPE_USER) {
                GElf_Shdr shdr;
                ss->adjust_symbols = (ehdr.e_type == ET_EXEC ||
+                               ehdr.e_type == ET_REL ||
                                elf_section_by_name(elf, &ehdr, &shdr,
                                                     ".gnu.prelink_undo",
                                                     NULL) != NULL);
        } 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);
@@ -676,6 +678,14 @@ int dso__load_sym(struct dso *dso, struct map *map,
        bool remap_kernel = false, adjust_kernel_syms = false;
 
        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) {
                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);
                                }
 
+                               /*
+                                * 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_dso = dso;
                                goto new_symbol;
                        }
 
+                       if (!kmap)
+                               goto new_symbol;
+
                        snprintf(dso_name, sizeof(dso_name),
                                 "%s%s", dso->short_name, section_name);
 
index 04300dd5221fd4a7ee93e1e0cd520db533cccc13..b9056a8c16203c5374bb7da845d4c78a0a2e5c99 100644 (file)
@@ -854,10 +854,15 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
        if (!runtime_ss && syms_ss)
                runtime_ss = syms_ss;
 
-       if (syms_ss)
-               ret = dso__load_sym(dso, map, syms_ss, runtime_ss, filter, 0);
-       else
+       if (syms_ss) {
+               int km;
+
+               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;
+       }
 
        if (ret > 0) {
                int nr_plt;