From bbb7f846f88df05646795854a014d73fb00f3b8b Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 7 Aug 2013 14:38:54 +0300 Subject: perf annotate: Allow disassembly using /proc/kcore Annotation with /proc/kcore is possible so the logic is adjusted to allow it. The main difference is that /proc/kcore had no symbols so the parsing logic needed a tweak to read jump offsets. The other difference is that objdump cannot always read from kcore. That seems to be a bug with objdump. Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1375875537-4509-11-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index d102716c43a..4ab2f11ee6f 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -110,10 +110,10 @@ static int jump__parse(struct ins_operands *ops) { const char *s = strchr(ops->raw, '+'); - ops->target.addr = strtoll(ops->raw, NULL, 16); + ops->target.addr = strtoull(ops->raw, NULL, 16); if (s++ != NULL) - ops->target.offset = strtoll(s, NULL, 16); + ops->target.offset = strtoull(s, NULL, 16); else ops->target.offset = UINT64_MAX; @@ -821,6 +821,10 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, if (dl == NULL) return -1; + if (dl->ops.target.offset == UINT64_MAX) + dl->ops.target.offset = dl->ops.target.addr - + map__rip_2objdump(map, sym->start); + disasm__add(¬es->src->source, dl); return 0; @@ -864,7 +868,8 @@ fallback: free_filename = false; } - if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) { + if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && + !dso__is_kcore(dso)) { char bf[BUILD_ID_SIZE * 2 + 16] = " with build id "; char *build_id_msg = NULL; @@ -898,7 +903,7 @@ fallback: snprintf(command, sizeof(command), "%s %s%s --start-address=0x%016" PRIx64 " --stop-address=0x%016" PRIx64 - " -d %s %s -C %s|grep -v %s|expand", + " -d %s %s -C %s 2>/dev/null|grep -v %s|expand", objdump_path ? objdump_path : "objdump", disassembler_style ? "-M " : "", disassembler_style ? disassembler_style : "", -- cgit v1.2.3-70-g09d2 From 484a5e7476b7ce790ba37417a4976c7f86a87231 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 7 Aug 2013 14:38:56 +0300 Subject: perf annotate: Remove nop at end of annotation When kcore is used for annotation, symbols do not have correct sizes because they come from kallsyms, that has only its start address, with the end address being the next symbol's minus one. That sometimes results in an extra nop being seen after the end of a function. Remove it. Suggested-by: Arnaldo Carvalho de Melo Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1375875537-4509-13-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 4ab2f11ee6f..646e38dad01 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -830,6 +830,30 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, return 0; } +static void delete_last_nop(struct symbol *sym) +{ + struct annotation *notes = symbol__annotation(sym); + struct list_head *list = ¬es->src->source; + struct disasm_line *dl; + + while (!list_empty(list)) { + dl = list_entry(list->prev, struct disasm_line, node); + + if (dl->ins && dl->ins->ops) { + if (dl->ins->ops != &nop_ops) + return; + } else { + if (!strstr(dl->line, " nop ") && + !strstr(dl->line, " nopl ") && + !strstr(dl->line, " nopw ")) + return; + } + + list_del(&dl->node); + disasm_line__free(dl); + } +} + int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) { struct dso *dso = map->dso; @@ -923,6 +947,13 @@ fallback: if (symbol__parse_objdump_line(sym, map, file, privsize) < 0) break; + /* + * kallsyms does not have symbol sizes so there may a nop at the end. + * Remove it. + */ + if (dso__is_kcore(dso)) + delete_last_nop(sym); + pclose(file); out_free_filename: if (free_filename) -- cgit v1.2.3-70-g09d2 From b178170a38e719cb7bc4a14d3f5e4b4ea6b7b851 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Wed, 7 Aug 2013 14:38:57 +0300 Subject: perf annotate: Add call target name if it is missing The /proc/kcore file has no symbols, so the call target name does not display. Fix by looking up the symbol name if it is on the same map. Reported-by: Arnaldo Carvalho de Melo Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1375875537-4509-14-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 646e38dad01..bfc5a27597d 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -825,6 +825,22 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, dl->ops.target.offset = dl->ops.target.addr - map__rip_2objdump(map, sym->start); + /* + * kcore has no symbols, so add the call target name if it is on the + * same map. + */ + if (dl->ins && ins__is_call(dl->ins) && !dl->ops.target.name) { + struct symbol *s; + u64 ip = dl->ops.target.addr; + + if (ip >= map->start && ip <= map->end) { + ip = map->map_ip(map, ip); + s = map__find_symbol(map, ip, NULL); + if (s && s->start == ip) + dl->ops.target.name = strdup(s->name); + } + } + disasm__add(¬es->src->source, dl); return 0; -- cgit v1.2.3-70-g09d2 From 886b37baa6274350fb271b2044dc50eb93cb1fc2 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 12 Sep 2013 21:15:21 +0300 Subject: perf annotate: Fix objdump line parsing offset validation When parsing lines from objdump a line containing source code starting with a numeric label is mistaken for a line of disassembly starting with a memory address. Current validation fails to recognise that the "memory address" is out of range and calculates an invalid offset which later causes this segfault: Program received signal SIGSEGV, Segmentation fault. 0x0000000000457315 in disasm__calc_percent (notes=0xc98970, evidx=0, offset=143705, end=2127526177, path=0x7fffffffbf50) at util/annotate.c:631 631 hits += h->addr[offset++]; (gdb) bt #0 0x0000000000457315 in disasm__calc_percent (notes=0xc98970, evidx=0, offset=143705, end=2127526177, path=0x7fffffffbf50) at util/annotate.c:631 #1 0x00000000004d65e3 in annotate_browser__calc_percent (browser=0x7fffffffd130, evsel=0xa01da0) at ui/browsers/annotate.c:364 #2 0x00000000004d7433 in annotate_browser__run (browser=0x7fffffffd130, evsel=0xa01da0, hbt=0x0) at ui/browsers/annotate.c:672 #3 0x00000000004d80c9 in symbol__tui_annotate (sym=0xc989a0, map=0xa02660, evsel=0xa01da0, hbt=0x0) at ui/browsers/annotate.c:962 #4 0x00000000004d7aa0 in hist_entry__tui_annotate (he=0xdf73f0, evsel=0xa01da0, hbt=0x0) at ui/browsers/annotate.c:823 #5 0x00000000004dd648 in perf_evsel__hists_browse (evsel=0xa01da0, nr_events=1, helpline= 0x58b768 "For a higher level overview, try: perf report --sort comm,dso", ev_name=0xa02cd0 "cycles", left_exits=false, hbt= 0x0, min_pcnt=0, env=0xa011e0) at ui/browsers/hists.c:1659 #6 0x00000000004de372 in perf_evlist__tui_browse_hists (evlist=0xa01520, help= 0x58b768 "For a higher level overview, try: perf report --sort comm,dso", hbt=0x0, min_pcnt=0, env=0xa011e0) at ui/browsers/hists.c:1950 #7 0x000000000042cf6b in __cmd_report (rep=0x7fffffffd6c0) at builtin-report.c:581 #8 0x000000000042e25d in cmd_report (argc=0, argv=0x7fffffffe4b0, prefix=0x0) at builtin-report.c:965 #9 0x000000000041a0e1 in run_builtin (p=0x801548, argc=1, argv=0x7fffffffe4b0) at perf.c:319 #10 0x000000000041a319 in handle_internal_command (argc=1, argv=0x7fffffffe4b0) at perf.c:376 #11 0x000000000041a465 in run_argv (argcp=0x7fffffffe38c, argv=0x7fffffffe380) at perf.c:420 #12 0x000000000041a707 in main (argc=1, argv=0x7fffffffe4b0) at perf.c:521 After the fix is applied the symbol can be annotated showing the problematic line "1: rep" copy_user_generic_string /usr/lib/debug/lib/modules/3.9.10-100.fc17.x86_64/vmlinux */ ENTRY(copy_user_generic_string) CFI_STARTPROC ASM_STAC andl %edx,%edx and %edx,%edx jz 4f je 37 cmpl $8,%edx cmp $0x8,%edx jb 2f /* less than 8 bytes, go to byte copy loop */ jb 33 ALIGN_DESTINATION mov %edi,%ecx and $0x7,%ecx je 28 sub $0x8,%ecx neg %ecx sub %ecx,%edx 1a: mov (%rsi),%al mov %al,(%rdi) inc %rsi inc %rdi dec %ecx jne 1a movl %edx,%ecx 28: mov %edx,%ecx shrl $3,%ecx shr $0x3,%ecx andl $7,%edx and $0x7,%edx 1: rep 100.00 rep movsq %ds:(%rsi),%es:(%rdi) movsq 2: movl %edx,%ecx 33: mov %edx,%ecx 3: rep rep movsb %ds:(%rsi),%es:(%rdi) movsb 4: xorl %eax,%eax 37: xor %eax,%eax data32 xchg %ax,%ax ASM_CLAC ret retq Signed-off-by: Adrian Hunter Cc: David Ahern Cc: Frederic Weisbecker Cc: Ingo Molnar Cc: Jiri Olsa Cc: Mike Galbraith Cc: Namhyung Kim Cc: Paul Mackerras Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/1379009721-27667-1-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools/perf/util/annotate.c') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index bfc5a27597d..7eae5488ece 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -809,7 +809,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, end = map__rip_2objdump(map, sym->end); offset = line_ip - start; - if (offset < 0 || (u64)line_ip > end) + if ((u64)line_ip < start || (u64)line_ip > end) offset = -1; else parsed_line = tmp2 + 1; -- cgit v1.2.3-70-g09d2