aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2018-03-23 09:50:35 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2018-03-23 15:46:18 -0400
commite4cc91b8027dbbb8a1f7c24cdecf58cd0b50375f (patch)
tree10039de12a54dbdc896966ae2a3eded7c7da19d5
parent2eff061162819e00ec6379874ceb47caef17bcba (diff)
perf annotate: Support jumping from one function to another
For instance: entry_SYSCALL_64 /lib/modules/4.16.0-rc5-00086-gdf09348f78dc/build/vmlinux 5.50 │ → callq do_syscall_64 14.56 │ mov 0x58(%rsp),%rcx 7.44 │ mov 0x80(%rsp),%r11 0.32 │ cmp %rcx,%r11 │ → jne swapgs_restore_regs_and_return_to_usermode 0.32 │ shl $0x10,%rcx 0.32 │ sar $0x10,%rcx 3.24 │ cmp %rcx,%r11 │ → jne swapgs_restore_regs_and_return_to_usermode 2.27 │ cmpq $0x33,0x88(%rsp) 1.29 │ → jne swapgs_restore_regs_and_return_to_usermode │ mov 0x30(%rsp),%r11 8.74 │ cmp %r11,0x90(%rsp) │ → jne swapgs_restore_regs_and_return_to_usermode 0.32 │ test $0x10100,%r11 │ → jne swapgs_restore_regs_and_return_to_usermode 0.32 │ cmpq $0x2b,0xa0(%rsp) 0.65 │ → jne swapgs_restore_regs_and_return_to_usermode It'll behave just like a "call" instruction, i.e. press enter or right arrow over one such line and the browser will navigate to the annotated disassembly of that function, which when exited, via left arrow or esc, will come back to the calling function. Now to support jump to an offset on a different function... Reported-by: Linus Torvalds <torvalds@linux-foundation.org> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: David Ahern <dsahern@gmail.com> Cc: Jin Yao <yao.jin@linux.intel.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Wang Nan <wangnan0@huawei.com> Link: https://lkml.kernel.org/n/tip-78o508mqvr8inhj63ddtw7mo@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/perf/ui/browsers/annotate.c23
-rw-r--r--tools/perf/util/annotate.c6
2 files changed, 22 insertions, 7 deletions
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index d77896a99570..c02fb437ac8e 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -384,6 +384,15 @@ static int sym_title(struct symbol *sym, struct map *map, char *title,
384 return snprintf(title, sz, "%s %s", sym->name, map->dso->long_name); 384 return snprintf(title, sz, "%s %s", sym->name, map->dso->long_name);
385} 385}
386 386
387/*
388 * This can be called from external jumps, i.e. jumps from one functon
389 * to another, like from the kernel's entry_SYSCALL_64 function to the
390 * swapgs_restore_regs_and_return_to_usermode() function.
391 *
392 * So all we check here is that dl->ops.target.sym is set, if it is, just
393 * go to that function and when exiting from its disassembly, come back
394 * to the calling function.
395 */
387static bool annotate_browser__callq(struct annotate_browser *browser, 396static bool annotate_browser__callq(struct annotate_browser *browser,
388 struct perf_evsel *evsel, 397 struct perf_evsel *evsel,
389 struct hist_browser_timer *hbt) 398 struct hist_browser_timer *hbt)
@@ -393,9 +402,6 @@ static bool annotate_browser__callq(struct annotate_browser *browser,
393 struct annotation *notes; 402 struct annotation *notes;
394 char title[SYM_TITLE_MAX_SIZE]; 403 char title[SYM_TITLE_MAX_SIZE];
395 404
396 if (!ins__is_call(&dl->ins))
397 return false;
398
399 if (!dl->ops.target.sym) { 405 if (!dl->ops.target.sym) {
400 ui_helpline__puts("The called function was not found."); 406 ui_helpline__puts("The called function was not found.");
401 return true; 407 return true;
@@ -436,7 +442,9 @@ struct disasm_line *annotate_browser__find_offset(struct annotate_browser *brows
436 return NULL; 442 return NULL;
437} 443}
438 444
439static bool annotate_browser__jump(struct annotate_browser *browser) 445static bool annotate_browser__jump(struct annotate_browser *browser,
446 struct perf_evsel *evsel,
447 struct hist_browser_timer *hbt)
440{ 448{
441 struct disasm_line *dl = disasm_line(browser->selection); 449 struct disasm_line *dl = disasm_line(browser->selection);
442 u64 offset; 450 u64 offset;
@@ -445,6 +453,11 @@ static bool annotate_browser__jump(struct annotate_browser *browser)
445 if (!ins__is_jump(&dl->ins)) 453 if (!ins__is_jump(&dl->ins))
446 return false; 454 return false;
447 455
456 if (dl->ops.target.outside) {
457 annotate_browser__callq(browser, evsel, hbt);
458 return true;
459 }
460
448 offset = dl->ops.target.offset; 461 offset = dl->ops.target.offset;
449 dl = annotate_browser__find_offset(browser, offset, &idx); 462 dl = annotate_browser__find_offset(browser, offset, &idx);
450 if (dl == NULL) { 463 if (dl == NULL) {
@@ -731,7 +744,7 @@ show_help:
731 goto show_sup_ins; 744 goto show_sup_ins;
732 else if (ins__is_ret(&dl->ins)) 745 else if (ins__is_ret(&dl->ins))
733 goto out; 746 goto out;
734 else if (!(annotate_browser__jump(browser) || 747 else if (!(annotate_browser__jump(browser, evsel, hbt) ||
735 annotate_browser__callq(browser, evsel, hbt))) { 748 annotate_browser__callq(browser, evsel, hbt))) {
736show_sup_ins: 749show_sup_ins:
737 ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions."); 750 ui_helpline__puts("Actions are only available for function call/return & jump/branch instructions.");
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 9524f322f597..5fa270b24eea 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -332,11 +332,10 @@ static int jump__parse(struct arch *arch __maybe_unused, struct ins_operands *op
332 * 332 *
333 * Actual navigation will come next, with further understanding of how 333 * Actual navigation will come next, with further understanding of how
334 * the symbol searching and disassembly should be done. 334 * the symbol searching and disassembly should be done.
335 335 */
336 if (map_groups__find_ams(&target) == 0 && 336 if (map_groups__find_ams(&target) == 0 &&
337 map__rip_2objdump(target.map, map->map_ip(target.map, target.addr)) == ops->target.addr) 337 map__rip_2objdump(target.map, map->map_ip(target.map, target.addr)) == ops->target.addr)
338 ops->target.sym = target.sym; 338 ops->target.sym = target.sym;
339 */
340 339
341 if (s++ != NULL) { 340 if (s++ != NULL) {
342 ops->target.offset = strtoull(s, NULL, 16); 341 ops->target.offset = strtoull(s, NULL, 16);
@@ -356,6 +355,9 @@ static int jump__scnprintf(struct ins *ins, char *bf, size_t size,
356 if (!ops->target.addr || ops->target.offset < 0) 355 if (!ops->target.addr || ops->target.offset < 0)
357 return ins__raw_scnprintf(ins, bf, size, ops); 356 return ins__raw_scnprintf(ins, bf, size, ops);
358 357
358 if (ops->target.outside && ops->target.sym != NULL)
359 return scnprintf(bf, size, "%-6s %s", ins->name, ops->target.sym->name);
360
359 if (c != NULL) { 361 if (c != NULL) {
360 const char *c2 = strchr(c + 1, ','); 362 const char *c2 = strchr(c + 1, ',');
361 363