aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/probe-finder.c
diff options
context:
space:
mode:
authorMasami Hiramatsu <mhiramat@redhat.com>2010-01-06 09:45:34 -0500
committerIngo Molnar <mingo@elte.hu>2010-01-13 04:09:14 -0500
commit631c9def804b2c92b5cca04fb9ff7b5df9e35094 (patch)
tree3ce09a1894f765bbea6538335ef11950287d66ee /tools/perf/util/probe-finder.c
parent6964cd2c8efe6e048401f1fe3952a06c563c34c1 (diff)
perf probe: Support --line option to show probable source-code lines
Add --line option to support showing probable source-code lines. perf probe --line SRC:LN[-LN|+NUM] or perf probe --line FUNC[:LN[-LN|+NUM]] This option shows source-code with line number if the line can be probed. Lines without line number (and blue color) means that the line can not be probed, because debuginfo doesn't have the information of those lines. The argument specifies the range of lines, "source.c:100-120" shows lines between 100th to l20th in source.c file. And "func:10+20" shows 20 lines from 10th line of func function. e.g. # ./perf probe --line kernel/sched.c:1080 <kernel/sched.c:1080> * * called with rq->lock held and irqs disabled */ static void hrtick_start(struct rq *rq, u64 delay) { struct hrtimer *timer = &rq->hrtick_timer; 1086 ktime_t time = ktime_add_ns(timer->base->get_time(), delay); hrtimer_set_expires(timer, time); 1090 if (rq == this_rq()) { 1091 hrtimer_restart(timer); 1092 } else if (!rq->hrtick_csd_pending) { 1093 __smp_call_function_single(cpu_of(rq), &rq->hrtick_csd, 1094 rq->hrtick_csd_pending = 1; If you specifying function name, this shows function-relative line number. # ./perf probe --line schedule <schedule:0> asmlinkage void __sched schedule(void) 1 { struct task_struct *prev, *next; unsigned long *switch_count; struct rq *rq; int cpu; need_resched: preempt_disable(); 9 cpu = smp_processor_id(); 10 rq = cpu_rq(cpu); 11 rcu_sched_qs(cpu); 12 prev = rq->curr; 13 switch_count = &prev->nivcsw; Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: systemtap <systemtap@sources.redhat.com> Cc: DLE <dle-develop@lists.sourceforge.net> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Mike Galbraith <efault@gmx.de> LKML-Reference: <20100106144534.27218.77939.stgit@dhcp-100-2-132.bos.redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/util/probe-finder.c')
-rw-r--r--tools/perf/util/probe-finder.c191
1 files changed, 186 insertions, 5 deletions
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 6402798337c8..1b2124d12f68 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