aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/probe-event.c100
-rw-r--r--tools/perf/util/probe-event.h2
-rw-r--r--tools/perf/util/probe-finder.c191
-rw-r--r--tools/perf/util/probe-finder.h31
4 files changed, 319 insertions, 5 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index a22141a773b..71b0dd590a3 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -38,6 +38,7 @@
38#include "strlist.h" 38#include "strlist.h"
39#include "debug.h" 39#include "debug.h"
40#include "cache.h" 40#include "cache.h"
41#include "color.h"
41#include "parse-events.h" /* For debugfs_path */ 42#include "parse-events.h" /* For debugfs_path */
42#include "probe-event.h" 43#include "probe-event.h"
43 44
@@ -63,6 +64,42 @@ static int e_snprintf(char *str, size_t size, const char *format, ...)
63 return ret; 64 return ret;
64} 65}
65 66
67void parse_line_range_desc(const char *arg, struct line_range *lr)
68{
69 const char *ptr;
70 char *tmp;
71 /*
72 * <Syntax>
73 * SRC:SLN[+NUM|-ELN]
74 * FUNC[:SLN[+NUM|-ELN]]
75 */
76 ptr = strchr(arg, ':');
77 if (ptr) {
78 lr->start = (unsigned int)strtoul(ptr + 1, &tmp, 0);
79 if (*tmp == '+')
80 lr->end = lr->start + (unsigned int)strtoul(tmp + 1,
81 &tmp, 0);
82 else if (*tmp == '-')
83 lr->end = (unsigned int)strtoul(tmp + 1, &tmp, 0);
84 else
85 lr->end = 0;
86 pr_debug("Line range is %u to %u\n", lr->start, lr->end);
87 if (lr->end && lr->start > lr->end)
88 semantic_error("Start line must be smaller"
89 " than end line.");
90 if (*tmp != '\0')
91 semantic_error("Tailing with invalid character '%d'.",
92 *tmp);
93 tmp = strndup(arg, (ptr - arg));
94 } else
95 tmp = strdup(arg);
96
97 if (strchr(tmp, '.'))
98 lr->file = tmp;
99 else
100 lr->function = tmp;
101}
102
66/* Check the name is good for event/group */ 103/* Check the name is good for event/group */
67static bool check_event_name(const char *name) 104static bool check_event_name(const char *name)
68{ 105{
@@ -678,3 +715,66 @@ void del_trace_kprobe_events(struct strlist *dellist)
678 close(fd); 715 close(fd);
679} 716}
680 717
718#define LINEBUF_SIZE 256
719
720static void show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num)
721{
722 char buf[LINEBUF_SIZE];
723 const char *color = PERF_COLOR_BLUE;
724
725 if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
726 goto error;
727 if (!skip) {
728 if (show_num)
729 fprintf(stdout, "%7u %s", l, buf);
730 else
731 color_fprintf(stdout, color, " %s", buf);
732 }
733
734 while (strlen(buf) == LINEBUF_SIZE - 1 &&
735 buf[LINEBUF_SIZE - 2] != '\n') {
736 if (fgets(buf, LINEBUF_SIZE, fp) == NULL)
737 goto error;
738 if (!skip) {
739 if (show_num)
740 fprintf(stdout, "%s", buf);
741 else
742 color_fprintf(stdout, color, "%s", buf);
743 }
744 }
745 return;
746error:
747 if (feof(fp))
748 die("Source file is shorter than expected.");
749 else
750 die("File read error: %s", strerror(errno));
751}
752
753void show_line_range(struct line_range *lr)
754{
755 unsigned int l = 1;
756 struct line_node *ln;
757 FILE *fp;
758
759 setup_pager();
760
761 if (lr->function)
762 fprintf(stdout, "<%s:%d>\n", lr->function,
763 lr->start - lr->offset);
764 else
765 fprintf(stdout, "<%s:%d>\n", lr->file, lr->start);
766
767 fp = fopen(lr->path, "r");
768 if (fp == NULL)
769 die("Failed to open %s: %s", lr->path, strerror(errno));
770 /* Skip to starting line number */
771 while (l < lr->start)
772 show_one_line(fp, l++, true, false);
773
774 list_for_each_entry(ln, &lr->line_list, list) {
775 while (ln->line > l)
776 show_one_line(fp, (l++) - lr->offset, false, false);
777 show_one_line(fp, (l++) - lr->offset, false, true);
778 }
779 fclose(fp);
780}
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 7f1d499118c..711287d4bae 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -5,6 +5,7 @@
5#include "probe-finder.h" 5#include "probe-finder.h"
6#include "strlist.h" 6#include "strlist.h"
7 7
8extern void parse_line_range_desc(const char *arg, struct line_range *lr);
8extern void parse_perf_probe_event(const char *str, struct probe_point *pp, 9extern void parse_perf_probe_event(const char *str, struct probe_point *pp,
9 bool *need_dwarf); 10 bool *need_dwarf);
10extern int synthesize_perf_probe_point(struct probe_point *pp); 11extern int synthesize_perf_probe_point(struct probe_point *pp);
@@ -15,6 +16,7 @@ extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes,
15 bool force_add); 16 bool force_add);
16extern void del_trace_kprobe_events(struct strlist *dellist); 17extern void del_trace_kprobe_events(struct strlist *dellist);
17extern void show_perf_probe_events(void); 18extern void show_perf_probe_events(void);
19extern void show_line_range(struct line_range *lr);
18 20
19/* Maximum index number of event-name postfix */ 21/* Maximum index number of event-name postfix */
20#define MAX_EVENT_INDEX 1024 22#define MAX_EVENT_INDEX 1024
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 6402798337c..1b2124d12f6 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -140,6 +140,31 @@ static Dwarf_Unsigned cu_find_fileno(Dwarf_Die cu_die, const char *fname)
140 return found; 140 return found;
141} 141}
142 142
143static int cu_get_filename(Dwarf_Die cu_die, Dwarf_Unsigned fno, char **buf)
144{
145 Dwarf_Signed cnt, i;
146 char **srcs;
147 int ret = 0;
148
149 if (!buf || !fno)
150 return -EINVAL;
151
152 ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error);
153 if (ret == DW_DLV_OK) {
154 if ((Dwarf_Unsigned)cnt > fno - 1) {
155 *buf = strdup(srcs[fno - 1]);
156 ret = 0;
157 pr_debug("found filename: %s\n", *buf);
158 } else
159 ret = -ENOENT;
160 for (i = 0; i < cnt; i++)
161 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING);
162 dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST);
163 } else
164 ret = -EINVAL;
165 return ret;
166}
167
143/* Compare diename and tname */ 168/* Compare diename and tname */
144static int die_compare_name(Dwarf_Die dw_die, const char *tname) 169static int die_compare_name(Dwarf_Die dw_die, const char *tname)
145{ 170{
@@ -567,7 +592,7 @@ static int probeaddr_callback(struct die_link *dlink, void *data)
567} 592}
568 593
569/* Find probe point from its line number */ 594/* Find probe point from its line number */
570static void find_by_line(struct probe_finder *pf) 595static void find_probe_point_by_line(struct probe_finder *pf)
571{ 596{
572 Dwarf_Signed cnt, i, clm; 597 Dwarf_Signed cnt, i, clm;
573 Dwarf_Line *lines; 598 Dwarf_Line *lines;
@@ -626,7 +651,7 @@ static int probefunc_callback(struct die_link *dlink, void *data)
626 pf->fno = die_get_decl_file(dlink->die); 651 pf->fno = die_get_decl_file(dlink->die);
627 pf->lno = die_get_decl_line(dlink->die) 652 pf->lno = die_get_decl_line(dlink->die)
628 + pp->line; 653 + pp->line;
629 find_by_line(pf); 654 find_probe_point_by_line(pf);
630 return 1; 655 return 1;
631 } 656 }
632 if (die_inlined_subprogram(dlink->die)) { 657 if (die_inlined_subprogram(dlink->die)) {
@@ -673,7 +698,7 @@ found:
673 return 0; 698 return 0;
674} 699}
675 700
676static void find_by_func(struct probe_finder *pf) 701static void find_probe_point_by_func(struct probe_finder *pf)
677{ 702{
678 search_die_from_children(pf->cu_die, probefunc_callback, pf); 703 search_die_from_children(pf->cu_die, probefunc_callback, pf);
679} 704}
@@ -714,10 +739,10 @@ int find_probepoint(int fd, struct probe_point *pp)
714 if (ret == DW_DLV_NO_ENTRY) 739 if (ret == DW_DLV_NO_ENTRY)
715 pf.cu_base = 0; 740 pf.cu_base = 0;
716 if (pp->function) 741 if (pp->function)
717 find_by_func(&pf); 742 find_probe_point_by_func(&pf);
718 else { 743 else {
719 pf.lno = pp->line; 744 pf.lno = pp->line;
720 find_by_line(&pf); 745 find_probe_point_by_line(&pf);
721 } 746 }
722 } 747 }
723 dwarf_dealloc(__dw_debug, pf.cu_die, DW_DLA_DIE); 748 dwarf_dealloc(__dw_debug, pf.cu_die, DW_DLA_DIE);
@@ -728,3 +753,159 @@ int find_probepoint(int fd, struct probe_point *pp)
728 return pp->found; 753 return pp->found;
729} 754}
730 755
756
757static void line_range_add_line(struct line_range *lr, unsigned int line)
758{
759 struct line_node *ln;
760 struct list_head *p;
761
762 /* Reverse search, because new line will be the last one */
763 list_for_each_entry_reverse(ln, &lr->line_list, list) {
764 if (ln->line < line) {
765 p = &ln->list;
766 goto found;
767 } else if (ln->line == line) /* Already exist */
768 return ;
769 }
770 /* List is empty, or the smallest entry */
771 p = &lr->line_list;
772found:
773 pr_debug("Debug: add a line %u\n", line);
774 ln = zalloc(sizeof(struct line_node));
775 DIE_IF(ln == NULL);
776 ln->line = line;
777 INIT_LIST_HEAD(&ln->list);
778 list_add(&ln->list, p);
779}
780
781/* Find line range from its line number */
782static void find_line_range_by_line(struct line_finder *lf)
783{
784 Dwarf_Signed cnt, i;
785 Dwarf_Line *lines;
786 Dwarf_Unsigned lineno = 0;
787 Dwarf_Unsigned fno;
788 Dwarf_Addr addr;
789 int ret;
790
791 ret = dwarf_srclines(lf->cu_die, &lines, &cnt, &__dw_error);
792 DIE_IF(ret != DW_DLV_OK);
793
794 for (i = 0; i < cnt; i++) {
795 ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error);
796 DIE_IF(ret != DW_DLV_OK);
797 if (fno != lf->fno)
798 continue;
799
800 ret = dwarf_lineno(lines[i], &lineno, &__dw_error);
801 DIE_IF(ret != DW_DLV_OK);
802 if (lf->lno_s > lineno || lf->lno_e < lineno)
803 continue;
804
805 /* Filter line in the function address range */
806 if (lf->addr_s && lf->addr_e) {
807 ret = dwarf_lineaddr(lines[i], &addr, &__dw_error);
808 DIE_IF(ret != DW_DLV_OK);
809 if (lf->addr_s > addr || lf->addr_e <= addr)
810 continue;
811 }
812 line_range_add_line(lf->lr, (unsigned int)lineno);
813 }
814 dwarf_srclines_dealloc(__dw_debug, lines, cnt);
815 if (!list_empty(&lf->lr->line_list))
816 lf->found = 1;
817}
818
819/* Search function from function name */
820static int linefunc_callback(struct die_link *dlink, void *data)
821{
822 struct line_finder *lf = (struct line_finder *)data;
823 struct line_range *lr = lf->lr;
824 Dwarf_Half tag;
825 int ret;
826
827 ret = dwarf_tag(dlink->die, &tag, &__dw_error);
828 DIE_IF(ret == DW_DLV_ERROR);
829 if (tag == DW_TAG_subprogram &&
830 die_compare_name(dlink->die, lr->function) == 0) {
831 /* Get the address range of this function */
832 ret = dwarf_highpc(dlink->die, &lf->addr_e, &__dw_error);
833 if (ret == DW_DLV_OK)
834 ret = dwarf_lowpc(dlink->die, &lf->addr_s, &__dw_error);
835 DIE_IF(ret == DW_DLV_ERROR);
836 if (ret == DW_DLV_NO_ENTRY) {
837 lf->addr_s = 0;
838 lf->addr_e = 0;
839 }
840
841 lf->fno = die_get_decl_file(dlink->die);
842 lr->offset = die_get_decl_line(dlink->die);;
843 lf->lno_s = lr->offset + lr->start;
844 if (!lr->end)
845 lf->lno_e = (Dwarf_Unsigned)-1;
846 else
847 lf->lno_e = lr->offset + lr->end;
848 lr->start = lf->lno_s;
849 lr->end = lf->lno_e;
850 find_line_range_by_line(lf);
851 /* If we find a target function, this should be end. */
852 lf->found = 1;
853 return 1;
854 }
855 return 0;
856}
857
858static void find_line_range_by_func(struct line_finder *lf)
859{
860 search_die_from_children(lf->cu_die, linefunc_callback, lf);
861}
862
863int find_line_range(int fd, struct line_range *lr)
864{
865 Dwarf_Half addr_size = 0;
866 Dwarf_Unsigned next_cuh = 0;
867 int ret;
868 struct line_finder lf = {.lr = lr};
869
870 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error);
871 if (ret != DW_DLV_OK)
872 return -ENOENT;
873
874 while (!lf.found) {
875 /* Search CU (Compilation Unit) */
876 ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL,
877 &addr_size, &next_cuh, &__dw_error);
878 DIE_IF(ret == DW_DLV_ERROR);
879 if (ret == DW_DLV_NO_ENTRY)
880 break;
881
882 /* Get the DIE(Debugging Information Entry) of this CU */
883 ret = dwarf_siblingof(__dw_debug, 0, &lf.cu_die, &__dw_error);
884 DIE_IF(ret != DW_DLV_OK);
885
886 /* Check if target file is included. */
887 if (lr->file)
888 lf.fno = cu_find_fileno(lf.cu_die, lr->file);
889
890 if (!lr->file || lf.fno) {
891 if (lr->function)
892 find_line_range_by_func(&lf);
893 else {
894 lf.lno_s = lr->start;
895 if (!lr->end)
896 lf.lno_e = (Dwarf_Unsigned)-1;
897 else
898 lf.lno_e = lr->end;
899 find_line_range_by_line(&lf);
900 }
901 /* Get the real file path */
902 if (lf.found)
903 cu_get_filename(lf.cu_die, lf.fno, &lr->path);
904 }
905 dwarf_dealloc(__dw_debug, lf.cu_die, DW_DLA_DIE);
906 }
907 ret = dwarf_finish(__dw_debug, &__dw_error);
908 DIE_IF(ret != DW_DLV_OK);
909 return lf.found;
910}
911
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index e3f396806e6..972b386116f 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -34,8 +34,26 @@ struct probe_point {
34 char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/ 34 char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/
35}; 35};
36 36
37/* Line number container */
38struct line_node {
39 struct list_head list;
40 unsigned int line;
41};
42
43/* Line range */
44struct line_range {
45 char *file; /* File name */
46 char *function; /* Function name */
47 unsigned int start; /* Start line number */
48 unsigned int end; /* End line number */
49 unsigned int offset; /* Start line offset */
50 char *path; /* Real path name */
51 struct list_head line_list; /* Visible lines */
52};
53
37#ifndef NO_LIBDWARF 54#ifndef NO_LIBDWARF
38extern int find_probepoint(int fd, struct probe_point *pp); 55extern int find_probepoint(int fd, struct probe_point *pp);
56extern int find_line_range(int fd, struct line_range *lr);
39 57
40/* Workaround for undefined _MIPS_SZLONG bug in libdwarf.h: */ 58/* Workaround for undefined _MIPS_SZLONG bug in libdwarf.h: */
41#ifndef _MIPS_SZLONG 59#ifndef _MIPS_SZLONG
@@ -62,6 +80,19 @@ struct probe_finder {
62 char *buf; /* Current output buffer */ 80 char *buf; /* Current output buffer */
63 int len; /* Length of output buffer */ 81 int len; /* Length of output buffer */
64}; 82};
83
84struct line_finder {
85 struct line_range *lr; /* Target line range */
86
87 Dwarf_Unsigned fno; /* File number */
88 Dwarf_Unsigned lno_s; /* Start line number */
89 Dwarf_Unsigned lno_e; /* End line number */
90 Dwarf_Addr addr_s; /* Start address */
91 Dwarf_Addr addr_e; /* End address */
92 Dwarf_Die cu_die; /* Current CU */
93 int found;
94};
95
65#endif /* NO_LIBDWARF */ 96#endif /* NO_LIBDWARF */
66 97
67#endif /*_PROBE_FINDER_H */ 98#endif /*_PROBE_FINDER_H */