perf report: Fix a wrong offset issue when using /proc/kcore
authorJin Yao <yao.jin@linux.intel.com>
Fri, 29 Dec 2017 16:26:52 +0000 (00:26 +0800)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Mon, 8 Jan 2018 14:11:57 +0000 (11:11 -0300)
When a valid vmlinux is not found, 'perf report' falls back to look at
/proc/kcore. In this case, it will report the impossible large offset.

For example:

  # perf record -b -e cycles:k find /etc/ > /dev/null
  # perf report --stdio --branch-history

    22.77%  _vm_normal_page+18446603336221188162
            |
            ---page_remove_rmap +18446603336221188324
               page_remove_rmap +18446603336221188487 (cycles:5)
               unlock_page_memcg +18446603336221188096
               page_remove_rmap +18446603336221188327 (cycles:1)

The issue is the value which is passed to parameter 'addr' in
__get_srcline() is the objdump address. It's not correct if we calculate
the offset by using 'addr - sym->start'.

This patch creates a new parameter 'ip' in __get_srcline(). It is not
converted to objdump address.

With this patch, the perf report output is:

    22.77%  _vm_normal_page+66
            |
            ---page_remove_rmap +228
               page_remove_rmap +391 (cycles:5)
               unlock_page_memcg +0
               page_remove_rmap +231 (cycles:1)
               page_remove_rmap +236

Committer testing:

Make sure you get any valid vmlinux out of the way, using '-v' on the
'perf report' case and deleting it from places where perf searches them,
like your kernel build dir and the build-id cache, in ~/.debug/.

Reported-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Jin Yao <yao.jin@linux.intel.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/1514564812-17344-1-git-send-email-yao.jin@linux.intel.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/annotate.c
tools/perf/util/machine.c
tools/perf/util/map.c
tools/perf/util/sort.c
tools/perf/util/srcline.c
tools/perf/util/srcline.h

index 68e687d1bf99a2d8d4e642c441e733bf3c2e0e16..28b233c3dcbe3c5ff89b445b9769061668bdef79 100644 (file)
@@ -1960,7 +1960,8 @@ static void annotation__calc_lines(struct annotation *notes, struct map *map,
                if (percent_max <= 0.5)
                        continue;
 
-               al->path = get_srcline(map->dso, start + al->offset, NULL, false, true);
+               al->path = get_srcline(map->dso, start + al->offset, NULL,
+                                      false, true, start + al->offset);
                insert_source_line(&tmp_root, al);
        }
 
index 64d255f6a5374c8ee730d759d409c789782b690a..b05a67464c03c6f3830e9a20cea4b4dc808fc4f5 100644 (file)
@@ -1726,7 +1726,7 @@ static char *callchain_srcline(struct map *map, struct symbol *sym, u64 ip)
                bool show_addr = callchain_param.key == CCKEY_ADDRESS;
 
                srcline = get_srcline(map->dso, map__rip_2objdump(map, ip),
-                                     sym, show_sym, show_addr);
+                                     sym, show_sym, show_addr, ip);
                srcline__tree_insert(&map->dso->srclines, ip, srcline);
        }
 
index 6d40efd74402732d6456bbd262a7b12dd12d613d..8fe57031e1a85ba3816b322e30526bcf9f237d14 100644 (file)
@@ -419,7 +419,7 @@ int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
        if (map && map->dso) {
                srcline = get_srcline(map->dso,
                                      map__rip_2objdump(map, addr), NULL,
-                                     true, true);
+                                     true, true, addr);
                if (srcline != SRCLINE_UNKNOWN)
                        ret = fprintf(fp, "%s%s", prefix, srcline);
                free_srcline(srcline);
index a00eacdf02ed9d826f0d9d666c12edf526f2bec6..211e7f326b9f2789c829a5c7bac176bbc68b9ccd 100644 (file)
@@ -336,7 +336,7 @@ char *hist_entry__get_srcline(struct hist_entry *he)
                return SRCLINE_UNKNOWN;
 
        return get_srcline(map->dso, map__rip_2objdump(map, he->ip),
-                          he->ms.sym, true, true);
+                          he->ms.sym, true, true, he->ip);
 }
 
 static int64_t
@@ -380,7 +380,8 @@ sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right)
                                           map__rip_2objdump(map,
                                                             left->branch_info->from.al_addr),
                                                         left->branch_info->from.sym,
-                                                        true, true);
+                                                        true, true,
+                                                        left->branch_info->from.al_addr);
        }
        if (!right->branch_info->srcline_from) {
                struct map *map = right->branch_info->from.map;
@@ -391,7 +392,8 @@ sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right)
                                             map__rip_2objdump(map,
                                                               right->branch_info->from.al_addr),
                                                     right->branch_info->from.sym,
-                                                    true, true);
+                                                    true, true,
+                                                    right->branch_info->from.al_addr);
        }
        return strcmp(right->branch_info->srcline_from, left->branch_info->srcline_from);
 }
@@ -423,7 +425,8 @@ sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right)
                                           map__rip_2objdump(map,
                                                             left->branch_info->to.al_addr),
                                                         left->branch_info->from.sym,
-                                                        true, true);
+                                                        true, true,
+                                                        left->branch_info->to.al_addr);
        }
        if (!right->branch_info->srcline_to) {
                struct map *map = right->branch_info->to.map;
@@ -434,7 +437,8 @@ sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right)
                                             map__rip_2objdump(map,
                                                               right->branch_info->to.al_addr),
                                                     right->branch_info->to.sym,
-                                                    true, true);
+                                                    true, true,
+                                                    right->branch_info->to.al_addr);
        }
        return strcmp(right->branch_info->srcline_to, left->branch_info->srcline_to);
 }
@@ -465,7 +469,7 @@ static char *hist_entry__get_srcfile(struct hist_entry *e)
                return no_srcfile;
 
        sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip),
-                        e->ms.sym, false, true, true);
+                        e->ms.sym, false, true, true, e->ip);
        if (!strcmp(sf, SRCLINE_UNKNOWN))
                return no_srcfile;
        p = strchr(sf, ':');
index d19f05c56de61ff87805e9f412dbf491b2b870c3..3c21fd059b6496e61d4957ccfe1baa9e09a966e9 100644 (file)
@@ -496,7 +496,8 @@ out:
 #define A2L_FAIL_LIMIT 123
 
 char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
-                 bool show_sym, bool show_addr, bool unwind_inlines)
+                 bool show_sym, bool show_addr, bool unwind_inlines,
+                 u64 ip)
 {
        char *file = NULL;
        unsigned line = 0;
@@ -536,7 +537,7 @@ out:
 
        if (sym) {
                if (asprintf(&srcline, "%s+%" PRIu64, show_sym ? sym->name : "",
-                                       addr - sym->start) < 0)
+                                       ip - sym->start) < 0)
                        return SRCLINE_UNKNOWN;
        } else if (asprintf(&srcline, "%s[%" PRIx64 "]", dso->short_name, addr) < 0)
                return SRCLINE_UNKNOWN;
@@ -550,9 +551,9 @@ void free_srcline(char *srcline)
 }
 
 char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
-                 bool show_sym, bool show_addr)
+                 bool show_sym, bool show_addr, u64 ip)
 {
-       return __get_srcline(dso, addr, sym, show_sym, show_addr, false);
+       return __get_srcline(dso, addr, sym, show_sym, show_addr, false, ip);
 }
 
 struct srcline_node {
index 847b7086182c1ac52d293b29390c04168563e792..b2bb5502fd6286173b4f89c2352b6f54916f0792 100644 (file)
@@ -11,9 +11,10 @@ struct symbol;
 
 extern bool srcline_full_filename;
 char *get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
-                 bool show_sym, bool show_addr);
+                 bool show_sym, bool show_addr, u64 ip);
 char *__get_srcline(struct dso *dso, u64 addr, struct symbol *sym,
-                 bool show_sym, bool show_addr, bool unwind_inlines);
+                 bool show_sym, bool show_addr, bool unwind_inlines,
+                 u64 ip);
 void free_srcline(char *srcline);
 
 /* insert the srcline into the DSO, which will take ownership */