diff options
-rw-r--r-- | tools/perf/util/probe-event.c | 55 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.c | 70 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.h | 4 |
3 files changed, 116 insertions, 13 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index b44ddfb030d7..4e3c1aea7892 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -70,7 +70,6 @@ static int e_snprintf(char *str, size_t size, const char *format, ...) | |||
70 | return ret; | 70 | return ret; |
71 | } | 71 | } |
72 | 72 | ||
73 | |||
74 | static struct map_groups kmap_groups; | 73 | static struct map_groups kmap_groups; |
75 | static struct map *kmaps[MAP__NR_TYPES]; | 74 | static struct map *kmaps[MAP__NR_TYPES]; |
76 | 75 | ||
@@ -357,27 +356,39 @@ void parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev) | |||
357 | /* Compose only probe point (not argument) */ | 356 | /* Compose only probe point (not argument) */ |
358 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp) | 357 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp) |
359 | { | 358 | { |
360 | char *buf; | 359 | char *buf, *tmp; |
361 | char offs[64] = "", line[64] = ""; | 360 | char offs[32] = "", line[32] = "", file[32] = ""; |
362 | int ret; | 361 | int ret, len; |
363 | 362 | ||
364 | buf = xzalloc(MAX_CMDLEN); | 363 | buf = xzalloc(MAX_CMDLEN); |
365 | if (pp->offset) { | 364 | if (pp->offset) { |
366 | ret = e_snprintf(offs, 64, "+%lu", pp->offset); | 365 | ret = e_snprintf(offs, 32, "+%lu", pp->offset); |
367 | if (ret <= 0) | 366 | if (ret <= 0) |
368 | goto error; | 367 | goto error; |
369 | } | 368 | } |
370 | if (pp->line) { | 369 | if (pp->line) { |
371 | ret = e_snprintf(line, 64, ":%d", pp->line); | 370 | ret = e_snprintf(line, 32, ":%d", pp->line); |
371 | if (ret <= 0) | ||
372 | goto error; | ||
373 | } | ||
374 | if (pp->file) { | ||
375 | len = strlen(pp->file) - 32; | ||
376 | if (len < 0) | ||
377 | len = 0; | ||
378 | tmp = strchr(pp->file + len, '/'); | ||
379 | if (!tmp) | ||
380 | tmp = pp->file + len - 1; | ||
381 | ret = e_snprintf(file, 32, "@%s", tmp + 1); | ||
372 | if (ret <= 0) | 382 | if (ret <= 0) |
373 | goto error; | 383 | goto error; |
374 | } | 384 | } |
375 | 385 | ||
376 | if (pp->function) | 386 | if (pp->function) |
377 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s", pp->function, | 387 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s%s", pp->function, |
378 | offs, pp->retprobe ? "%return" : "", line); | 388 | offs, pp->retprobe ? "%return" : "", line, |
389 | file); | ||
379 | else | 390 | else |
380 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line); | 391 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", file, line); |
381 | if (ret <= 0) | 392 | if (ret <= 0) |
382 | goto error; | 393 | goto error; |
383 | 394 | ||
@@ -511,15 +522,32 @@ void convert_to_perf_probe_event(struct kprobe_trace_event *tev, | |||
511 | { | 522 | { |
512 | char buf[64]; | 523 | char buf[64]; |
513 | int i; | 524 | int i; |
525 | #ifndef NO_DWARF_SUPPORT | ||
526 | struct symbol *sym; | ||
527 | int fd, ret = 0; | ||
514 | 528 | ||
515 | pev->event = xstrdup(tev->event); | 529 | sym = map__find_symbol_by_name(kmaps[MAP__FUNCTION], |
516 | pev->group = xstrdup(tev->group); | 530 | tev->point.symbol, NULL); |
517 | 531 | if (sym) { | |
532 | fd = open_vmlinux(); | ||
533 | ret = find_perf_probe_point(fd, sym->start + tev->point.offset, | ||
534 | &pev->point); | ||
535 | close(fd); | ||
536 | } | ||
537 | if (ret <= 0) { | ||
538 | pev->point.function = xstrdup(tev->point.symbol); | ||
539 | pev->point.offset = tev->point.offset; | ||
540 | } | ||
541 | #else | ||
518 | /* Convert trace_point to probe_point */ | 542 | /* Convert trace_point to probe_point */ |
519 | pev->point.function = xstrdup(tev->point.symbol); | 543 | pev->point.function = xstrdup(tev->point.symbol); |
520 | pev->point.offset = tev->point.offset; | 544 | pev->point.offset = tev->point.offset; |
545 | #endif | ||
521 | pev->point.retprobe = tev->point.retprobe; | 546 | pev->point.retprobe = tev->point.retprobe; |
522 | 547 | ||
548 | pev->event = xstrdup(tev->event); | ||
549 | pev->group = xstrdup(tev->group); | ||
550 | |||
523 | /* Convert trace_arg to probe_arg */ | 551 | /* Convert trace_arg to probe_arg */ |
524 | pev->nargs = tev->nargs; | 552 | pev->nargs = tev->nargs; |
525 | pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs); | 553 | pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs); |
@@ -650,7 +678,7 @@ static void show_perf_probe_event(struct perf_probe_event *pev) | |||
650 | ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event); | 678 | ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event); |
651 | if (ret < 0) | 679 | if (ret < 0) |
652 | die("Failed to copy event: %s", strerror(-ret)); | 680 | die("Failed to copy event: %s", strerror(-ret)); |
653 | printf(" %-40s (on %s", buf, place); | 681 | printf(" %-20s (on %s", buf, place); |
654 | 682 | ||
655 | if (pev->nargs > 0) { | 683 | if (pev->nargs > 0) { |
656 | printf(" with"); | 684 | printf(" with"); |
@@ -671,6 +699,7 @@ void show_perf_probe_events(void) | |||
671 | struct str_node *ent; | 699 | struct str_node *ent; |
672 | 700 | ||
673 | setup_pager(); | 701 | setup_pager(); |
702 | init_vmlinux(); | ||
674 | 703 | ||
675 | memset(&tev, 0, sizeof(tev)); | 704 | memset(&tev, 0, sizeof(tev)); |
676 | memset(&pev, 0, sizeof(pev)); | 705 | memset(&pev, 0, sizeof(pev)); |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 251b4c49653e..e02b60770485 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -693,6 +693,76 @@ int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, | |||
693 | return pf.ntevs; | 693 | return pf.ntevs; |
694 | } | 694 | } |
695 | 695 | ||
696 | /* Reverse search */ | ||
697 | int find_perf_probe_point(int fd, unsigned long addr, | ||
698 | struct perf_probe_point *ppt) | ||
699 | { | ||
700 | Dwarf_Die cudie, spdie, indie; | ||
701 | Dwarf *dbg; | ||
702 | Dwarf_Line *line; | ||
703 | Dwarf_Addr laddr, eaddr; | ||
704 | const char *tmp; | ||
705 | int lineno, ret = 0; | ||
706 | |||
707 | dbg = dwarf_begin(fd, DWARF_C_READ); | ||
708 | if (!dbg) | ||
709 | return -ENOENT; | ||
710 | |||
711 | /* Find cu die */ | ||
712 | if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie)) | ||
713 | return -EINVAL; | ||
714 | |||
715 | /* Find a corresponding line */ | ||
716 | line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr); | ||
717 | if (line) { | ||
718 | dwarf_lineaddr(line, &laddr); | ||
719 | if ((Dwarf_Addr)addr == laddr) { | ||
720 | dwarf_lineno(line, &lineno); | ||
721 | ppt->line = lineno; | ||
722 | |||
723 | tmp = dwarf_linesrc(line, NULL, NULL); | ||
724 | DIE_IF(!tmp); | ||
725 | ppt->file = xstrdup(tmp); | ||
726 | ret = 1; | ||
727 | } | ||
728 | } | ||
729 | |||
730 | /* Find a corresponding function */ | ||
731 | if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) { | ||
732 | tmp = dwarf_diename(&spdie); | ||
733 | if (!tmp) | ||
734 | goto end; | ||
735 | |||
736 | dwarf_entrypc(&spdie, &eaddr); | ||
737 | if (!lineno) { | ||
738 | /* We don't have a line number, let's use offset */ | ||
739 | ppt->function = xstrdup(tmp); | ||
740 | ppt->offset = addr - (unsigned long)eaddr; | ||
741 | ret = 1; | ||
742 | goto end; | ||
743 | } | ||
744 | if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, &indie)) { | ||
745 | /* addr in an inline function */ | ||
746 | tmp = dwarf_diename(&indie); | ||
747 | if (!tmp) | ||
748 | goto end; | ||
749 | dwarf_decl_line(&indie, &lineno); | ||
750 | } else { | ||
751 | if (eaddr == addr) /* No offset: function entry */ | ||
752 | lineno = ppt->line; | ||
753 | else | ||
754 | dwarf_decl_line(&spdie, &lineno); | ||
755 | } | ||
756 | ppt->function = xstrdup(tmp); | ||
757 | ppt->line -= lineno; /* Make a relative line number */ | ||
758 | } | ||
759 | |||
760 | end: | ||
761 | dwarf_end(dbg); | ||
762 | return ret; | ||
763 | } | ||
764 | |||
765 | |||
696 | /* Find line range from its line number */ | 766 | /* Find line range from its line number */ |
697 | static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) | 767 | static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) |
698 | { | 768 | { |
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index 494952619b9c..2f2307d4139f 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h | |||
@@ -20,6 +20,10 @@ static inline int is_c_varname(const char *name) | |||
20 | extern int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, | 20 | extern int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, |
21 | struct kprobe_trace_event **tevs); | 21 | struct kprobe_trace_event **tevs); |
22 | 22 | ||
23 | /* Find a perf_probe_point from debuginfo */ | ||
24 | extern int find_perf_probe_point(int fd, unsigned long addr, | ||
25 | struct perf_probe_point *ppt); | ||
26 | |||
23 | extern int find_line_range(int fd, struct line_range *lr); | 27 | extern int find_line_range(int fd, struct line_range *lr); |
24 | 28 | ||
25 | #include <dwarf.h> | 29 | #include <dwarf.h> |