Perf missed the 'VirtAddr' value in elf program_headers when adjusting
symbol address for dynamic libraries. This patch considers the p_addr
value and gets the right symbol offset.

Before this patch, some symbols can not be right parsed on android phone:

  init   369 [002]   339.970607: raw_syscalls:sys_enter: NR 22 (b, 7fd9e360a0, 
10, ffffffff, 0, 8)
                     ...
                   230ac [unknown] (/system/lib64/libsurfaceflinger.so)
                    11a0 main (/system/bin/surfaceflinger)
                   1c3fc __libc_init (/system/lib64/libc.so)
                     fd0 _start (/system/bin/surfaceflinger)
                    29ec __dl__start (/system/bin/linker64)

After this patch:

  init   369 [002]   339.970607: raw_syscalls:sys_enter: NR 22 (b, 7fd9e360a0, 
10, ffffffff, 0, 8)
                     ...
                   3a0ac _ZN7android14SurfaceFlinger3runEv 
(/system/lib64/libsurfaceflinger.so)
                    11a0 main (/system/bin/surfaceflinger)
                   1c3fc __libc_init (/system/lib64/libc.so)
                     fd0 _start (/system/bin/surfaceflinger)
                    29ec __dl__start (/system/bin/linker64)

Signed-off-by: He Kuang <heku...@huawei.com>
---
 tools/perf/util/dso.c        |  6 ++++++
 tools/perf/util/dso.h        |  1 +
 tools/perf/util/event.c      |  6 +++++-
 tools/perf/util/map.h        |  7 +++++--
 tools/perf/util/symbol-elf.c | 20 ++++++++++++++++++++
 5 files changed, 37 insertions(+), 3 deletions(-)

diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index e8e9a9d..93bf13a 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -1063,6 +1063,7 @@ struct dso *dso__new(const char *name)
                dso->needs_swap = DSO_SWAP__UNSET;
                RB_CLEAR_NODE(&dso->rb_node);
                dso->root = NULL;
+               dso->vaddr = 0;
                INIT_LIST_HEAD(&dso->node);
                INIT_LIST_HEAD(&dso->data.open_entry);
                pthread_mutex_init(&dso->lock, NULL);
@@ -1367,3 +1368,8 @@ int dso__strerror_load(struct dso *dso, char *buf, size_t 
buflen)
        scnprintf(buf, buflen, "%s", dso_load__error_str[idx]);
        return 0;
 }
+
+u64 dso__get_vaddr(struct dso *dso)
+{
+       return dso->vaddr;
+}
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index 45ec4d0..b6c894f 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -166,6 +166,7 @@ struct dso {
        const char       *long_name;
        u16              long_name_len;
        u16              short_name_len;
+       u64             vaddr;
        void            *dwfl;                  /* DWARF debug info */
        struct auxtrace_cache *auxtrace_cache;
 
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index cd61bb1..ef964c0 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -1273,8 +1273,12 @@ try_again:
                 * Kernel maps might be changed when loading symbols so loading
                 * must be done prior to using kernel maps.
                 */
+               map__load(al->map, machine->symbol_filter);
+
+               /* exclude kernel kallsyms */
                if (load_map)
-                       map__load(al->map, machine->symbol_filter);
+                       al->map->dso->vaddr = 0;
+
                al->addr = al->map->map_ip(al->map, al->addr);
        }
 }
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 7309d64..68ab703 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -86,14 +86,17 @@ void map_groups__put(struct map_groups *mg);
 struct kmap *map__kmap(struct map *map);
 struct map_groups *map__kmaps(struct map *map);
 
+u64 dso__get_vaddr(struct dso *dso);
 static inline u64 map__map_ip(struct map *map, u64 ip)
 {
-       return ip - map->start + map->pgoff;
+       return ip - map->start + map->pgoff +
+               dso__get_vaddr(map->dso);
 }
 
 static inline u64 map__unmap_ip(struct map *map, u64 ip)
 {
-       return ip + map->start - map->pgoff;
+       return ip + map->start - map->pgoff -
+               dso__get_vaddr(map->dso);
 }
 
 static inline u64 identity__map_ip(struct map *map __maybe_unused, u64 ip)
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 562b8eb..de0129f 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -15,6 +15,8 @@
 #define EM_AARCH64     183  /* ARM 64 bit */
 #endif
 
+static int elf_read_maps_ex(Elf * elf, bool exe, mapfn_t mapfn, void *data,
+                           struct map *map);
 
 #ifdef HAVE_CPLUS_DEMANGLE_SUPPORT
 extern char *cplus_demangle(const char *, int);
@@ -831,6 +833,10 @@ int dso__load_sym(struct dso *dso, struct map *map,
        sec = syms_ss->symtab;
        shdr = syms_ss->symshdr;
 
+       err = elf_read_maps_ex(elf, ehdr.e_type == ET_EXEC ||
+                              ehdr.e_type == ET_REL,
+                              NULL, NULL, map);
+
        if (runtime_ss->opdsec)
                opddata = elf_rawdata(runtime_ss->opdsec, NULL);
 
@@ -1116,6 +1122,13 @@ out_elf_end:
 
 static int elf_read_maps(Elf *elf, bool exe, mapfn_t mapfn, void *data)
 {
+
+       return elf_read_maps_ex(elf, exe, mapfn, data, NULL);
+}
+
+static int elf_read_maps_ex(Elf *elf, bool exe, mapfn_t mapfn, void *data,
+                           struct map *map)
+{
        GElf_Phdr phdr;
        size_t i, phdrnum;
        int err;
@@ -1135,10 +1148,17 @@ static int elf_read_maps(Elf *elf, bool exe, mapfn_t 
mapfn, void *data)
                } else {
                        if (!(phdr.p_flags & PF_R))
                                continue;
+                       if (map && (phdr.p_flags & PF_X))
+                               map->dso->vaddr = phdr.p_vaddr;
                }
+
                sz = min(phdr.p_memsz, phdr.p_filesz);
                if (!sz)
                        continue;
+
+               if (!mapfn)
+                       continue;
+
                err = mapfn(phdr.p_vaddr, sz, phdr.p_offset, data);
                if (err)
                        return err;
-- 
1.8.5.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to