aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>2011-08-11 07:02:59 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2011-08-12 08:28:45 -0400
commit221d061182b8ff5507d5768aeeecbc74f01c5dfa (patch)
tree79cd224ca76fd520e089860a3a0482ed2b718b0d /tools
parent13e27d7686c457c625242fc2c20be30eef942408 (diff)
perf probe: Fix to search local variables in appropriate scope
Fix perf probe to search local variables in appropriate local inlined function scope. For example, pre_schedule() has only 2 local variables, as below; $ perf probe -L pre_schedule <pre_schedule@/home/mhiramat/ksrc/linux-2.6/kernel/sched.c:0> 0 static inline void pre_schedule(struct rq *rq, struct task_struct *prev) { 2 if (prev->sched_class->pre_schedule) 3 prev->sched_class->pre_schedule(rq, prev); } However, current perf probe shows 4 local variables on pre_schedule(), because it searches variables in the caller(schedule()) scope. $ perf probe -V pre_schedule Available variables at pre_schedule @<schedule+445> int cpu long unsigned int* switch_count struct rq* rq struct task_struct* prev This patch fixes this issue by searching variables in the local scope of the instance of inlined function. Here is the result. $ perf probe -V pre_schedule Available variables at pre_schedule @<schedule+445> struct rq* rq struct task_struct* prev Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Paul Mackerras <paulus@samba.org> Cc: Pekka Enberg <penberg@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: yrl.pp-manager.tt@hitachi.com Link: http://lkml.kernel.org/r/20110811110259.19900.85664.stgit@fedora15 Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/util/dwarf-aux.c33
-rw-r--r--tools/perf/util/dwarf-aux.h4
-rw-r--r--tools/perf/util/probe-finder.c132
-rw-r--r--tools/perf/util/probe-finder.h2
4 files changed, 144 insertions, 27 deletions
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c
index d9b8ad098498..425703a58638 100644
--- a/tools/perf/util/dwarf-aux.c
+++ b/tools/perf/util/dwarf-aux.c
@@ -96,6 +96,39 @@ int cu_find_lineinfo(Dwarf_Die *cu_die, unsigned long addr,
96 return *lineno ?: -ENOENT; 96 return *lineno ?: -ENOENT;
97} 97}
98 98
99static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data);
100
101/**
102 * cu_walk_functions_at - Walk on function DIEs at given address
103 * @cu_die: A CU DIE
104 * @addr: An address
105 * @callback: A callback which called with found DIEs
106 * @data: A user data
107 *
108 * Walk on function DIEs at given @addr in @cu_die. Passed DIEs
109 * should be subprogram or inlined-subroutines.
110 */
111int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr,
112 int (*callback)(Dwarf_Die *, void *), void *data)
113{
114 Dwarf_Die die_mem;
115 Dwarf_Die *sc_die;
116 int ret = -ENOENT;
117
118 /* Inlined function could be recursive. Trace it until fail */
119 for (sc_die = die_find_realfunc(cu_die, addr, &die_mem);
120 sc_die != NULL;
121 sc_die = die_find_child(sc_die, __die_find_inline_cb, &addr,
122 &die_mem)) {
123 ret = callback(sc_die, data);
124 if (ret)
125 break;
126 }
127
128 return ret;
129
130}
131
99/** 132/**
100 * die_compare_name - Compare diename and tname 133 * die_compare_name - Compare diename and tname
101 * @dw_die: a DIE 134 * @dw_die: a DIE
diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h
index c8e491bc133f..6f46106fd1d5 100644
--- a/tools/perf/util/dwarf-aux.h
+++ b/tools/perf/util/dwarf-aux.h
@@ -34,6 +34,10 @@ extern const char *cu_get_comp_dir(Dwarf_Die *cu_die);
34extern int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr, 34extern int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr,
35 const char **fname, int *lineno); 35 const char **fname, int *lineno);
36 36
37/* Walk on funcitons at given address */
38extern int cu_walk_functions_at(Dwarf_Die *cu_die, Dwarf_Addr addr,
39 int (*callback)(Dwarf_Die *, void *), void *data);
40
37/* Compare diename and tname */ 41/* Compare diename and tname */
38extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname); 42extern bool die_compare_name(Dwarf_Die *dw_die, const char *tname);
39 43
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index d6d57682473a..5c83b7d3d8ef 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -612,8 +612,8 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
612 return ret; 612 return ret;
613} 613}
614 614
615/* Find a variable in a subprogram die */ 615/* Find a variable in a scope DIE */
616static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) 616static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf)
617{ 617{
618 Dwarf_Die vr_die, *scopes; 618 Dwarf_Die vr_die, *scopes;
619 char buf[32], *ptr; 619 char buf[32], *ptr;
@@ -655,11 +655,11 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
655 pr_debug("Searching '%s' variable in context.\n", 655 pr_debug("Searching '%s' variable in context.\n",
656 pf->pvar->var); 656 pf->pvar->var);
657 /* Search child die for local variables and parameters. */ 657 /* Search child die for local variables and parameters. */
658 if (die_find_variable_at(sp_die, pf->pvar->var, pf->addr, &vr_die)) 658 if (die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die))
659 ret = convert_variable(&vr_die, pf); 659 ret = convert_variable(&vr_die, pf);
660 else { 660 else {
661 /* Search upper class */ 661 /* Search upper class */
662 nscopes = dwarf_getscopes_die(sp_die, &scopes); 662 nscopes = dwarf_getscopes_die(sc_die, &scopes);
663 ret = -ENOENT; 663 ret = -ENOENT;
664 while (nscopes-- > 1) { 664 while (nscopes-- > 1) {
665 pr_debug("Searching variables in %s\n", 665 pr_debug("Searching variables in %s\n",
@@ -717,26 +717,30 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
717 return 0; 717 return 0;
718} 718}
719 719
720/* Call probe_finder callback with real subprogram DIE */ 720/* Call probe_finder callback with scope DIE */
721static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf) 721static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf)
722{ 722{
723 Dwarf_Die die_mem;
724 Dwarf_Attribute fb_attr; 723 Dwarf_Attribute fb_attr;
725 size_t nops; 724 size_t nops;
726 int ret; 725 int ret;
727 726
728 /* If no real subprogram, find a real one */ 727 if (!sc_die) {
729 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { 728 pr_err("Caller must pass a scope DIE. Program error.\n");
730 sp_die = die_find_realfunc(&pf->cu_die, pf->addr, &die_mem); 729 return -EINVAL;
731 if (!sp_die) { 730 }
731
732 /* If not a real subprogram, find a real one */
733 if (dwarf_tag(sc_die) != DW_TAG_subprogram) {
734 if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) {
732 pr_warning("Failed to find probe point in any " 735 pr_warning("Failed to find probe point in any "
733 "functions.\n"); 736 "functions.\n");
734 return -ENOENT; 737 return -ENOENT;
735 } 738 }
736 } 739 } else
740 memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die));
737 741
738 /* Get the frame base attribute/ops */ 742 /* Get the frame base attribute/ops from subprogram */
739 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); 743 dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr);
740 ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); 744 ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1);
741 if (ret <= 0 || nops == 0) { 745 if (ret <= 0 || nops == 0) {
742 pf->fb_ops = NULL; 746 pf->fb_ops = NULL;
@@ -754,7 +758,7 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
754 } 758 }
755 759
756 /* Call finder's callback handler */ 760 /* Call finder's callback handler */
757 ret = pf->callback(sp_die, pf); 761 ret = pf->callback(sc_die, pf);
758 762
759 /* *pf->fb_ops will be cached in libdw. Don't free it. */ 763 /* *pf->fb_ops will be cached in libdw. Don't free it. */
760 pf->fb_ops = NULL; 764 pf->fb_ops = NULL;
@@ -762,17 +766,82 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
762 return ret; 766 return ret;
763} 767}
764 768
769struct find_scope_param {
770 const char *function;
771 const char *file;
772 int line;
773 int diff;
774 Dwarf_Die *die_mem;
775 bool found;
776};
777
778static int find_best_scope_cb(Dwarf_Die *fn_die, void *data)
779{
780 struct find_scope_param *fsp = data;
781 const char *file;
782 int lno;
783
784 /* Skip if declared file name does not match */
785 if (fsp->file) {
786 file = dwarf_decl_file(fn_die);
787 if (!file || strcmp(fsp->file, file) != 0)
788 return 0;
789 }
790 /* If the function name is given, that's what user expects */
791 if (fsp->function) {
792 if (die_compare_name(fn_die, fsp->function)) {
793 memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die));
794 fsp->found = true;
795 return 1;
796 }
797 } else {
798 /* With the line number, find the nearest declared DIE */
799 dwarf_decl_line(fn_die, &lno);
800 if (lno < fsp->line && fsp->diff > fsp->line - lno) {
801 /* Keep a candidate and continue */
802 fsp->diff = fsp->line - lno;
803 memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die));
804 fsp->found = true;
805 }
806 }
807 return 0;
808}
809
810/* Find an appropriate scope fits to given conditions */
811static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem)
812{
813 struct find_scope_param fsp = {
814 .function = pf->pev->point.function,
815 .file = pf->fname,
816 .line = pf->lno,
817 .diff = INT_MAX,
818 .die_mem = die_mem,
819 .found = false,
820 };
821
822 cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp);
823
824 return fsp.found ? die_mem : NULL;
825}
826
765static int probe_point_line_walker(const char *fname, int lineno, 827static int probe_point_line_walker(const char *fname, int lineno,
766 Dwarf_Addr addr, void *data) 828 Dwarf_Addr addr, void *data)
767{ 829{
768 struct probe_finder *pf = data; 830 struct probe_finder *pf = data;
831 Dwarf_Die *sc_die, die_mem;
769 int ret; 832 int ret;
770 833
771 if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) 834 if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0)
772 return 0; 835 return 0;
773 836
774 pf->addr = addr; 837 pf->addr = addr;
775 ret = call_probe_finder(NULL, pf); 838 sc_die = find_best_scope(pf, &die_mem);
839 if (!sc_die) {
840 pr_warning("Failed to find scope of probe point.\n");
841 return -ENOENT;
842 }
843
844 ret = call_probe_finder(sc_die, pf);
776 845
777 /* Continue if no error, because the line will be in inline function */ 846 /* Continue if no error, because the line will be in inline function */
778 return ret < 0 ? ret : 0; 847 return ret < 0 ? ret : 0;
@@ -826,6 +895,7 @@ static int probe_point_lazy_walker(const char *fname, int lineno,
826 Dwarf_Addr addr, void *data) 895 Dwarf_Addr addr, void *data)
827{ 896{
828 struct probe_finder *pf = data; 897 struct probe_finder *pf = data;
898 Dwarf_Die *sc_die, die_mem;
829 int ret; 899 int ret;
830 900
831 if (!line_list__has_line(&pf->lcache, lineno) || 901 if (!line_list__has_line(&pf->lcache, lineno) ||
@@ -835,7 +905,14 @@ static int probe_point_lazy_walker(const char *fname, int lineno,
835 pr_debug("Probe line found: line:%d addr:0x%llx\n", 905 pr_debug("Probe line found: line:%d addr:0x%llx\n",
836 lineno, (unsigned long long)addr); 906 lineno, (unsigned long long)addr);
837 pf->addr = addr; 907 pf->addr = addr;
838 ret = call_probe_finder(NULL, pf); 908 pf->lno = lineno;
909 sc_die = find_best_scope(pf, &die_mem);
910 if (!sc_die) {
911 pr_warning("Failed to find scope of probe point.\n");
912 return -ENOENT;
913 }
914
915 ret = call_probe_finder(sc_die, pf);
839 916
840 /* 917 /*
841 * Continue if no error, because the lazy pattern will match 918 * Continue if no error, because the lazy pattern will match
@@ -1059,7 +1136,7 @@ found:
1059} 1136}
1060 1137
1061/* Add a found probe point into trace event list */ 1138/* Add a found probe point into trace event list */
1062static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf) 1139static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
1063{ 1140{
1064 struct trace_event_finder *tf = 1141 struct trace_event_finder *tf =
1065 container_of(pf, struct trace_event_finder, pf); 1142 container_of(pf, struct trace_event_finder, pf);
@@ -1074,8 +1151,9 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
1074 } 1151 }
1075 tev = &tf->tevs[tf->ntevs++]; 1152 tev = &tf->tevs[tf->ntevs++];
1076 1153
1077 ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe, 1154 /* Trace point should be converted from subprogram DIE */
1078 &tev->point); 1155 ret = convert_to_trace_point(&pf->sp_die, pf->addr,
1156 pf->pev->point.retprobe, &tev->point);
1079 if (ret < 0) 1157 if (ret < 0)
1080 return ret; 1158 return ret;
1081 1159
@@ -1090,7 +1168,8 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
1090 for (i = 0; i < pf->pev->nargs; i++) { 1168 for (i = 0; i < pf->pev->nargs; i++) {
1091 pf->pvar = &pf->pev->args[i]; 1169 pf->pvar = &pf->pev->args[i];
1092 pf->tvar = &tev->args[i]; 1170 pf->tvar = &tev->args[i];
1093 ret = find_variable(sp_die, pf); 1171 /* Variable should be found from scope DIE */
1172 ret = find_variable(sc_die, pf);
1094 if (ret != 0) 1173 if (ret != 0)
1095 return ret; 1174 return ret;
1096 } 1175 }
@@ -1158,7 +1237,7 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
1158} 1237}
1159 1238
1160/* Add a found vars into available variables list */ 1239/* Add a found vars into available variables list */
1161static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf) 1240static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf)
1162{ 1241{
1163 struct available_var_finder *af = 1242 struct available_var_finder *af =
1164 container_of(pf, struct available_var_finder, pf); 1243 container_of(pf, struct available_var_finder, pf);
@@ -1173,8 +1252,9 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
1173 } 1252 }
1174 vl = &af->vls[af->nvls++]; 1253 vl = &af->vls[af->nvls++];
1175 1254
1176 ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe, 1255 /* Trace point should be converted from subprogram DIE */
1177 &vl->point); 1256 ret = convert_to_trace_point(&pf->sp_die, pf->addr,
1257 pf->pev->point.retprobe, &vl->point);
1178 if (ret < 0) 1258 if (ret < 0)
1179 return ret; 1259 return ret;
1180 1260
@@ -1186,14 +1266,14 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
1186 if (vl->vars == NULL) 1266 if (vl->vars == NULL)
1187 return -ENOMEM; 1267 return -ENOMEM;
1188 af->child = true; 1268 af->child = true;
1189 die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem); 1269 die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem);
1190 1270
1191 /* Find external variables */ 1271 /* Find external variables */
1192 if (!af->externs) 1272 if (!af->externs)
1193 goto out; 1273 goto out;
1194 /* Don't need to search child DIE for externs. */ 1274 /* Don't need to search child DIE for externs. */
1195 af->child = false; 1275 af->child = false;
1196 nscopes = dwarf_getscopes_die(sp_die, &scopes); 1276 nscopes = dwarf_getscopes_die(sc_die, &scopes);
1197 while (nscopes-- > 1) 1277 while (nscopes-- > 1)
1198 die_find_child(&scopes[nscopes], collect_variables_cb, 1278 die_find_child(&scopes[nscopes], collect_variables_cb,
1199 (void *)af, &die_mem); 1279 (void *)af, &die_mem);
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index c478b42a2473..1132c8f0ce89 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -57,7 +57,7 @@ struct probe_finder {
57 struct perf_probe_event *pev; /* Target probe event */ 57 struct perf_probe_event *pev; /* Target probe event */
58 58
59 /* Callback when a probe point is found */ 59 /* Callback when a probe point is found */
60 int (*callback)(Dwarf_Die *sp_die, struct probe_finder *pf); 60 int (*callback)(Dwarf_Die *sc_die, struct probe_finder *pf);
61 61
62 /* For function searching */ 62 /* For function searching */
63 int lno; /* Line number */ 63 int lno; /* Line number */