aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>2010-10-21 06:13:23 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2010-10-21 13:59:06 -0400
commitcf6eb489e5c04c8f8d5fd7bf90b8346c987688bc (patch)
tree3da471c3ae3f99cdcbec26cc95412a4b44506f3c
parent632941c4f8fbd5b90dcb1672cd0422dfd7332bc9 (diff)
perf probe: Show accessible local variables
Add -V (--vars) option for listing accessible local variables at given probe point. This will help finding which local variables are available for event arguments. e.g.) # perf probe -V call_timer_fn:23 Available variables at call_timer_fn:23 @<run_timer_softirq+345> function_type* fn int preempt_count long unsigned int data struct list_head work_list struct list_head* head struct timer_list* timer struct tvec_base* base Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Paul Mackerras <paulus@samba.org> Cc: Ingo Molnar <mingo@elte.hu> Cc: Frederic Weisbecker <fweisbec@gmail.com> LKML-Reference: <20101021101323.3542.40282.stgit@ltc236.sdl.hitachi.co.jp> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/perf/Documentation/perf-probe.txt7
-rw-r--r--tools/perf/builtin-probe.c61
-rw-r--r--tools/perf/util/probe-event.c72
-rw-r--r--tools/perf/util/probe-event.h8
-rw-r--r--tools/perf/util/probe-finder.c412
-rw-r--r--tools/perf/util/probe-finder.h25
6 files changed, 480 insertions, 105 deletions
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 27d52dae5a43..72f5d9e21432 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -17,6 +17,8 @@ or
17'perf probe' --list 17'perf probe' --list
18or 18or
19'perf probe' --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]' 19'perf probe' --line='FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]'
20or
21'perf probe' --vars='PROBEPOINT'
20 22
21DESCRIPTION 23DESCRIPTION
22----------- 24-----------
@@ -57,6 +59,11 @@ OPTIONS
57 Show source code lines which can be probed. This needs an argument 59 Show source code lines which can be probed. This needs an argument
58 which specifies a range of the source code. (see LINE SYNTAX for detail) 60 which specifies a range of the source code. (see LINE SYNTAX for detail)
59 61
62-V::
63--vars=::
64 Show available local variables at given probe point. The argument
65 syntax is same as PROBE SYNTAX, but NO ARGs.
66
60-f:: 67-f::
61--force:: 68--force::
62 Forcibly add events with existing name. 69 Forcibly add events with existing name.
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 199d5e19554f..91bb6cf4e025 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -50,6 +50,8 @@ static struct {
50 bool list_events; 50 bool list_events;
51 bool force_add; 51 bool force_add;
52 bool show_lines; 52 bool show_lines;
53 bool show_vars;
54 bool mod_events;
53 int nevents; 55 int nevents;
54 struct perf_probe_event events[MAX_PROBES]; 56 struct perf_probe_event events[MAX_PROBES];
55 struct strlist *dellist; 57 struct strlist *dellist;
@@ -57,7 +59,6 @@ static struct {
57 int max_probe_points; 59 int max_probe_points;
58} params; 60} params;
59 61
60
61/* Parse an event definition. Note that any error must die. */ 62/* Parse an event definition. Note that any error must die. */
62static int parse_probe_event(const char *str) 63static int parse_probe_event(const char *str)
63{ 64{
@@ -92,6 +93,7 @@ static int parse_probe_event_argv(int argc, const char **argv)
92 len = 0; 93 len = 0;
93 for (i = 0; i < argc; i++) 94 for (i = 0; i < argc; i++)
94 len += sprintf(&buf[len], "%s ", argv[i]); 95 len += sprintf(&buf[len], "%s ", argv[i]);
96 params.mod_events = true;
95 ret = parse_probe_event(buf); 97 ret = parse_probe_event(buf);
96 free(buf); 98 free(buf);
97 return ret; 99 return ret;
@@ -100,9 +102,10 @@ static int parse_probe_event_argv(int argc, const char **argv)
100static int opt_add_probe_event(const struct option *opt __used, 102static int opt_add_probe_event(const struct option *opt __used,
101 const char *str, int unset __used) 103 const char *str, int unset __used)
102{ 104{
103 if (str) 105 if (str) {
106 params.mod_events = true;
104 return parse_probe_event(str); 107 return parse_probe_event(str);
105 else 108 } else
106 return 0; 109 return 0;
107} 110}
108 111
@@ -110,6 +113,7 @@ static int opt_del_probe_event(const struct option *opt __used,
110 const char *str, int unset __used) 113 const char *str, int unset __used)
111{ 114{
112 if (str) { 115 if (str) {
116 params.mod_events = true;
113 if (!params.dellist) 117 if (!params.dellist)
114 params.dellist = strlist__new(true, NULL); 118 params.dellist = strlist__new(true, NULL);
115 strlist__add(params.dellist, str); 119 strlist__add(params.dellist, str);
@@ -130,6 +134,25 @@ static int opt_show_lines(const struct option *opt __used,
130 134
131 return ret; 135 return ret;
132} 136}
137
138static int opt_show_vars(const struct option *opt __used,
139 const char *str, int unset __used)
140{
141 struct perf_probe_event *pev = &params.events[params.nevents];
142 int ret;
143
144 if (!str)
145 return 0;
146
147 ret = parse_probe_event(str);
148 if (!ret && pev->nargs != 0) {
149 pr_err(" Error: '--vars' doesn't accept arguments.\n");
150 return -EINVAL;
151 }
152 params.show_vars = true;
153
154 return ret;
155}
133#endif 156#endif
134 157
135static const char * const probe_usage[] = { 158static const char * const probe_usage[] = {
@@ -139,6 +162,7 @@ static const char * const probe_usage[] = {
139 "perf probe --list", 162 "perf probe --list",
140#ifdef DWARF_SUPPORT 163#ifdef DWARF_SUPPORT
141 "perf probe --line 'LINEDESC'", 164 "perf probe --line 'LINEDESC'",
165 "perf probe --vars 'PROBEPOINT'",
142#endif 166#endif
143 NULL 167 NULL
144}; 168};
@@ -180,6 +204,9 @@ static const struct option options[] = {
180 OPT_CALLBACK('L', "line", NULL, 204 OPT_CALLBACK('L', "line", NULL,
181 "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]", 205 "FUNC[:RLN[+NUM|-RLN2]]|SRC:ALN[+NUM|-ALN2]",
182 "Show source code lines.", opt_show_lines), 206 "Show source code lines.", opt_show_lines),
207 OPT_CALLBACK('V', "vars", NULL,
208 "FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT",
209 "Show accessible variables on PROBEDEF", opt_show_vars),
183 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 210 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
184 "file", "vmlinux pathname"), 211 "file", "vmlinux pathname"),
185 OPT_STRING('s', "source", &symbol_conf.source_prefix, 212 OPT_STRING('s', "source", &symbol_conf.source_prefix,
@@ -217,7 +244,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
217 usage_with_options(probe_usage, options); 244 usage_with_options(probe_usage, options);
218 245
219 if (params.list_events) { 246 if (params.list_events) {
220 if (params.nevents != 0 || params.dellist) { 247 if (params.mod_events) {
221 pr_err(" Error: Don't use --list with --add/--del.\n"); 248 pr_err(" Error: Don't use --list with --add/--del.\n");
222 usage_with_options(probe_usage, options); 249 usage_with_options(probe_usage, options);
223 } 250 }
@@ -225,6 +252,10 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
225 pr_err(" Error: Don't use --list with --line.\n"); 252 pr_err(" Error: Don't use --list with --line.\n");
226 usage_with_options(probe_usage, options); 253 usage_with_options(probe_usage, options);
227 } 254 }
255 if (params.show_vars) {
256 pr_err(" Error: Don't use --list with --vars.\n");
257 usage_with_options(probe_usage, options);
258 }
228 ret = show_perf_probe_events(); 259 ret = show_perf_probe_events();
229 if (ret < 0) 260 if (ret < 0)
230 pr_err(" Error: Failed to show event list. (%d)\n", 261 pr_err(" Error: Failed to show event list. (%d)\n",
@@ -234,9 +265,13 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
234 265
235#ifdef DWARF_SUPPORT 266#ifdef DWARF_SUPPORT
236 if (params.show_lines) { 267 if (params.show_lines) {
237 if (params.nevents != 0 || params.dellist) { 268 if (params.mod_events) {
238 pr_warning(" Error: Don't use --line with" 269 pr_err(" Error: Don't use --line with"
239 " --add/--del.\n"); 270 " --add/--del.\n");
271 usage_with_options(probe_usage, options);
272 }
273 if (params.show_vars) {
274 pr_err(" Error: Don't use --line with --vars.\n");
240 usage_with_options(probe_usage, options); 275 usage_with_options(probe_usage, options);
241 } 276 }
242 277
@@ -245,6 +280,18 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
245 pr_err(" Error: Failed to show lines. (%d)\n", ret); 280 pr_err(" Error: Failed to show lines. (%d)\n", ret);
246 return ret; 281 return ret;
247 } 282 }
283 if (params.show_vars) {
284 if (params.mod_events) {
285 pr_err(" Error: Don't use --vars with"
286 " --add/--del.\n");
287 usage_with_options(probe_usage, options);
288 }
289 ret = show_available_vars(params.events, params.nevents,
290 params.max_probe_points);
291 if (ret < 0)
292 pr_err(" Error: Failed to show vars. (%d)\n", ret);
293 return ret;
294 }
248#endif 295#endif
249 296
250 if (params.dellist) { 297 if (params.dellist) {
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index fcc16e4349df..288ebe8279d2 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -378,6 +378,72 @@ end:
378 return ret; 378 return ret;
379} 379}
380 380
381static int show_available_vars_at(int fd, struct perf_probe_event *pev,
382 int max_vls)
383{
384 char *buf;
385 int ret, i;
386 struct str_node *node;
387 struct variable_list *vls = NULL, *vl;
388
389 buf = synthesize_perf_probe_point(&pev->point);
390 if (!buf)
391 return -EINVAL;
392 pr_debug("Searching variables at %s\n", buf);
393
394 ret = find_available_vars_at(fd, pev, &vls, max_vls);
395 if (ret > 0) {
396 /* Some variables were found */
397 fprintf(stdout, "Available variables at %s\n", buf);
398 for (i = 0; i < ret; i++) {
399 vl = &vls[i];
400 /*
401 * A probe point might be converted to
402 * several trace points.
403 */
404 fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol,
405 vl->point.offset);
406 free(vl->point.symbol);
407 if (vl->vars) {
408 strlist__for_each(node, vl->vars)
409 fprintf(stdout, "\t\t%s\n", node->s);
410 strlist__delete(vl->vars);
411 } else
412 fprintf(stdout, "(No variables)\n");
413 }
414 free(vls);
415 } else
416 pr_err("Failed to find variables at %s (%d)\n", buf, ret);
417
418 free(buf);
419 return ret;
420}
421
422/* Show available variables on given probe point */
423int show_available_vars(struct perf_probe_event *pevs, int npevs,
424 int max_vls)
425{
426 int i, fd, ret = 0;
427
428 ret = init_vmlinux();
429 if (ret < 0)
430 return ret;
431
432 fd = open_vmlinux();
433 if (fd < 0) {
434 pr_warning("Failed to open debuginfo file.\n");
435 return fd;
436 }
437
438 setup_pager();
439
440 for (i = 0; i < npevs && ret >= 0; i++)
441 ret = show_available_vars_at(fd, &pevs[i], max_vls);
442
443 close(fd);
444 return ret;
445}
446
381#else /* !DWARF_SUPPORT */ 447#else /* !DWARF_SUPPORT */
382 448
383static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp, 449static int kprobe_convert_to_perf_probe(struct probe_trace_point *tp,
@@ -409,6 +475,12 @@ int show_line_range(struct line_range *lr __unused)
409 return -ENOSYS; 475 return -ENOSYS;
410} 476}
411 477
478int show_available_vars(struct perf_probe_event *pevs __unused,
479 int npevs __unused, int max_probe_points __unused)
480{
481 pr_warning("Debuginfo-analysis is not supported.\n");
482 return -ENOSYS;
483}
412#endif 484#endif
413 485
414int parse_line_range_desc(const char *arg, struct line_range *lr) 486int parse_line_range_desc(const char *arg, struct line_range *lr)
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 5af39243a25b..727a7fe81a02 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -90,6 +90,12 @@ struct line_range {
90 struct list_head line_list; /* Visible lines */ 90 struct list_head line_list; /* Visible lines */
91}; 91};
92 92
93/* List of variables */
94struct variable_list {
95 struct probe_trace_point point; /* Actual probepoint */
96 struct strlist *vars; /* Available variables */
97};
98
93/* Command string to events */ 99/* Command string to events */
94extern int parse_perf_probe_command(const char *cmd, 100extern int parse_perf_probe_command(const char *cmd,
95 struct perf_probe_event *pev); 101 struct perf_probe_event *pev);
@@ -115,6 +121,8 @@ extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
115extern int del_perf_probe_events(struct strlist *dellist); 121extern int del_perf_probe_events(struct strlist *dellist);
116extern int show_perf_probe_events(void); 122extern int show_perf_probe_events(void);
117extern int show_line_range(struct line_range *lr); 123extern int show_line_range(struct line_range *lr);
124extern int show_available_vars(struct perf_probe_event *pevs, int npevs,
125 int max_probe_points);
118 126
119 127
120/* Maximum index number of event-name postfix */ 128/* Maximum index number of event-name postfix */
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index c6fe80ebb262..986027fa495f 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -172,8 +172,8 @@ static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
172 return NULL; 172 return NULL;
173} 173}
174 174
175/* Get type die, but skip qualifiers and typedef */ 175/* Get a type die, but skip qualifiers */
176static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) 176static Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
177{ 177{
178 int tag; 178 int tag;
179 179
@@ -185,8 +185,17 @@ static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
185 } while (tag == DW_TAG_const_type || 185 } while (tag == DW_TAG_const_type ||
186 tag == DW_TAG_restrict_type || 186 tag == DW_TAG_restrict_type ||
187 tag == DW_TAG_volatile_type || 187 tag == DW_TAG_volatile_type ||
188 tag == DW_TAG_shared_type || 188 tag == DW_TAG_shared_type);
189 tag == DW_TAG_typedef); 189
190 return vr_die;
191}
192
193/* Get a type die, but skip qualifiers and typedef */
194static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
195{
196 do {
197 vr_die = __die_get_real_type(vr_die, die_mem);
198 } while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef);
190 199
191 return vr_die; 200 return vr_die;
192} 201}
@@ -380,6 +389,60 @@ static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
380 die_mem); 389 die_mem);
381} 390}
382 391
392/* Get the name of given variable DIE */
393static int die_get_typename(Dwarf_Die *vr_die, char *buf, int len)
394{
395 Dwarf_Die type;
396 int tag, ret, ret2;
397 const char *tmp = "";
398
399 if (__die_get_real_type(vr_die, &type) == NULL)
400 return -ENOENT;
401
402 tag = dwarf_tag(&type);
403 if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)
404 tmp = "*";
405 else if (tag == DW_TAG_subroutine_type) {
406 /* Function pointer */
407 ret = snprintf(buf, len, "(function_type)");
408 return (ret >= len) ? -E2BIG : ret;
409 } else {
410 if (!dwarf_diename(&type))
411 return -ENOENT;
412 if (tag == DW_TAG_union_type)
413 tmp = "union ";
414 else if (tag == DW_TAG_structure_type)
415 tmp = "struct ";
416 /* Write a base name */
417 ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type));
418 return (ret >= len) ? -E2BIG : ret;
419 }
420 ret = die_get_typename(&type, buf, len);
421 if (ret > 0) {
422 ret2 = snprintf(buf + ret, len - ret, "%s", tmp);
423 ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
424 }
425 return ret;
426}
427
428/* Get the name and type of given variable DIE, stored as "type\tname" */
429static int die_get_varname(Dwarf_Die *vr_die, char *buf, int len)
430{
431 int ret, ret2;
432
433 ret = die_get_typename(vr_die, buf, len);
434 if (ret < 0) {
435 pr_debug("Failed to get type, make it unknown.\n");
436 ret = snprintf(buf, len, "(unknown_type)");
437 }
438 if (ret > 0) {
439 ret2 = snprintf(buf + ret, len - ret, "\t%s",
440 dwarf_diename(vr_die));
441 ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
442 }
443 return ret;
444}
445
383/* 446/*
384 * Probe finder related functions 447 * Probe finder related functions
385 */ 448 */
@@ -393,8 +456,13 @@ static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs)
393 return ref; 456 return ref;
394} 457}
395 458
396/* Show a location */ 459/*
397static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf) 460 * Convert a location into trace_arg.
461 * If tvar == NULL, this just checks variable can be converted.
462 */
463static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr,
464 Dwarf_Op *fb_ops,
465 struct probe_trace_arg *tvar)
398{ 466{
399 Dwarf_Attribute attr; 467 Dwarf_Attribute attr;
400 Dwarf_Op *op; 468 Dwarf_Op *op;
@@ -403,7 +471,6 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
403 Dwarf_Word offs = 0; 471 Dwarf_Word offs = 0;
404 bool ref = false; 472 bool ref = false;
405 const char *regs; 473 const char *regs;
406 struct probe_trace_arg *tvar = pf->tvar;
407 int ret; 474 int ret;
408 475
409 if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL) 476 if (dwarf_attr(vr_die, DW_AT_external, &attr) != NULL)
@@ -411,16 +478,16 @@ static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
411 478
412 /* TODO: handle more than 1 exprs */ 479 /* TODO: handle more than 1 exprs */
413 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL || 480 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL ||
414 dwarf_getlocation_addr(&attr, pf->addr, &op, &nops, 1) <= 0 || 481 dwarf_getlocation_addr(&attr, addr, &op, &nops, 1) <= 0 ||
415 nops == 0) { 482 nops == 0) {
416 /* TODO: Support const_value */ 483 /* TODO: Support const_value */
417 pr_err("Failed to find the location of %s at this address.\n"
418 " Perhaps, it has been optimized out.\n", pf->pvar->var);
419 return -ENOENT; 484 return -ENOENT;
420 } 485 }
421 486
422 if (op->atom == DW_OP_addr) { 487 if (op->atom == DW_OP_addr) {
423static_var: 488static_var:
489 if (!tvar)
490 return 0;
424 /* Static variables on memory (not stack), make @varname */ 491 /* Static variables on memory (not stack), make @varname */
425 ret = strlen(dwarf_diename(vr_die)); 492 ret = strlen(dwarf_diename(vr_die));
426 tvar->value = zalloc(ret + 2); 493 tvar->value = zalloc(ret + 2);
@@ -435,14 +502,11 @@ static_var:
435 502
436 /* If this is based on frame buffer, set the offset */ 503 /* If this is based on frame buffer, set the offset */
437 if (op->atom == DW_OP_fbreg) { 504 if (op->atom == DW_OP_fbreg) {
438 if (pf->fb_ops == NULL) { 505 if (fb_ops == NULL)
439 pr_warning("The attribute of frame base is not "
440 "supported.\n");
441 return -ENOTSUP; 506 return -ENOTSUP;
442 }
443 ref = true; 507 ref = true;
444 offs = op->number; 508 offs = op->number;
445 op = &pf->fb_ops[0]; 509 op = &fb_ops[0];
446 } 510 }
447 511
448 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { 512 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
@@ -458,13 +522,18 @@ static_var:
458 } else if (op->atom == DW_OP_regx) { 522 } else if (op->atom == DW_OP_regx) {
459 regn = op->number; 523 regn = op->number;
460 } else { 524 } else {
461 pr_warning("DW_OP %x is not supported.\n", op->atom); 525 pr_debug("DW_OP %x is not supported.\n", op->atom);
462 return -ENOTSUP; 526 return -ENOTSUP;
463 } 527 }
464 528
529 if (!tvar)
530 return 0;
531
465 regs = get_arch_regstr(regn); 532 regs = get_arch_regstr(regn);
466 if (!regs) { 533 if (!regs) {
467 pr_warning("Mapping for DWARF register number %u missing on this architecture.", regn); 534 /* This should be a bug in DWARF or this tool */
535 pr_warning("Mapping for DWARF register number %u "
536 "missing on this architecture.", regn);
468 return -ERANGE; 537 return -ERANGE;
469 } 538 }
470 539
@@ -689,8 +758,14 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
689 pr_debug("Converting variable %s into trace event.\n", 758 pr_debug("Converting variable %s into trace event.\n",
690 dwarf_diename(vr_die)); 759 dwarf_diename(vr_die));
691 760
692 ret = convert_variable_location(vr_die, pf); 761 ret = convert_variable_location(vr_die, pf->addr, pf->fb_ops,
693 if (ret == 0 && pf->pvar->field) { 762 pf->tvar);
763 if (ret == -ENOENT)
764 pr_err("Failed to find the location of %s at this address.\n"
765 " Perhaps, it has been optimized out.\n", pf->pvar->var);
766 else if (ret == -ENOTSUP)
767 pr_err("Sorry, we don't support this variable location yet.\n");
768 else if (pf->pvar->field) {
694 ret = convert_variable_fields(vr_die, pf->pvar->var, 769 ret = convert_variable_fields(vr_die, pf->pvar->var,
695 pf->pvar->field, &pf->tvar->ref, 770 pf->pvar->field, &pf->tvar->ref,
696 &die_mem); 771 &die_mem);
@@ -772,34 +847,12 @@ found:
772 return ret; 847 return ret;
773} 848}
774 849
775/* Show a probe point to output buffer */ 850/* Convert subprogram DIE to trace point */
776static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) 851static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr,
852 bool retprobe, struct probe_trace_point *tp)
777{ 853{
778 struct probe_trace_event *tev;
779 Dwarf_Addr eaddr; 854 Dwarf_Addr eaddr;
780 Dwarf_Die die_mem;
781 const char *name; 855 const char *name;
782 int ret, i;
783 Dwarf_Attribute fb_attr;
784 size_t nops;
785
786 if (pf->ntevs == pf->max_tevs) {
787 pr_warning("Too many( > %d) probe point found.\n",
788 pf->max_tevs);
789 return -ERANGE;
790 }
791 tev = &pf->tevs[pf->ntevs++];
792
793 /* If no real subprogram, find a real one */
794 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
795 sp_die = die_find_real_subprogram(&pf->cu_die,
796 pf->addr, &die_mem);
797 if (!sp_die) {
798 pr_warning("Failed to find probe point in any "
799 "functions.\n");
800 return -ENOENT;
801 }
802 }
803 856
804 /* Copy the name of probe point */ 857 /* Copy the name of probe point */
805 name = dwarf_diename(sp_die); 858 name = dwarf_diename(sp_die);
@@ -809,26 +862,45 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
809 dwarf_diename(sp_die)); 862 dwarf_diename(sp_die));
810 return -ENOENT; 863 return -ENOENT;
811 } 864 }
812 tev->point.symbol = strdup(name); 865 tp->symbol = strdup(name);
813 if (tev->point.symbol == NULL) 866 if (tp->symbol == NULL)
814 return -ENOMEM; 867 return -ENOMEM;
815 tev->point.offset = (unsigned long)(pf->addr - eaddr); 868 tp->offset = (unsigned long)(paddr - eaddr);
816 } else 869 } else
817 /* This function has no name. */ 870 /* This function has no name. */
818 tev->point.offset = (unsigned long)pf->addr; 871 tp->offset = (unsigned long)paddr;
819 872
820 /* Return probe must be on the head of a subprogram */ 873 /* Return probe must be on the head of a subprogram */
821 if (pf->pev->point.retprobe) { 874 if (retprobe) {
822 if (tev->point.offset != 0) { 875 if (eaddr != paddr) {
823 pr_warning("Return probe must be on the head of" 876 pr_warning("Return probe must be on the head of"
824 " a real function\n"); 877 " a real function\n");
825 return -EINVAL; 878 return -EINVAL;
826 } 879 }
827 tev->point.retprobe = true; 880 tp->retprobe = true;
828 } 881 }
829 882
830 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, 883 return 0;
831 tev->point.offset); 884}
885
886/* Call probe_finder callback with real subprogram DIE */
887static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
888{
889 Dwarf_Die die_mem;
890 Dwarf_Attribute fb_attr;
891 size_t nops;
892 int ret;
893
894 /* If no real subprogram, find a real one */
895 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
896 sp_die = die_find_real_subprogram(&pf->cu_die,
897 pf->addr, &die_mem);
898 if (!sp_die) {
899 pr_warning("Failed to find probe point in any "
900 "functions.\n");
901 return -ENOENT;
902 }
903 }
832 904
833 /* Get the frame base attribute/ops */ 905 /* Get the frame base attribute/ops */
834 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); 906 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
@@ -848,22 +920,13 @@ static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
848#endif 920#endif
849 } 921 }
850 922
851 /* Find each argument */ 923 /* Call finder's callback handler */
852 tev->nargs = pf->pev->nargs; 924 ret = pf->callback(sp_die, pf);
853 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
854 if (tev->args == NULL)
855 return -ENOMEM;
856 for (i = 0; i < pf->pev->nargs; i++) {
857 pf->pvar = &pf->pev->args[i];
858 pf->tvar = &tev->args[i];
859 ret = find_variable(sp_die, pf);
860 if (ret != 0)
861 return ret;
862 }
863 925
864 /* *pf->fb_ops will be cached in libdw. Don't free it. */ 926 /* *pf->fb_ops will be cached in libdw. Don't free it. */
865 pf->fb_ops = NULL; 927 pf->fb_ops = NULL;
866 return 0; 928
929 return ret;
867} 930}
868 931
869/* Find probe point from its line number */ 932/* Find probe point from its line number */
@@ -899,7 +962,7 @@ static int find_probe_point_by_line(struct probe_finder *pf)
899 (int)i, lineno, (uintmax_t)addr); 962 (int)i, lineno, (uintmax_t)addr);
900 pf->addr = addr; 963 pf->addr = addr;
901 964
902 ret = convert_probe_point(NULL, pf); 965 ret = call_probe_finder(NULL, pf);
903 /* Continuing, because target line might be inlined. */ 966 /* Continuing, because target line might be inlined. */
904 } 967 }
905 return ret; 968 return ret;
@@ -1012,7 +1075,7 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
1012 (int)i, lineno, (unsigned long long)addr); 1075 (int)i, lineno, (unsigned long long)addr);
1013 pf->addr = addr; 1076 pf->addr = addr;
1014 1077
1015 ret = convert_probe_point(sp_die, pf); 1078 ret = call_probe_finder(sp_die, pf);
1016 /* Continuing, because target line might be inlined. */ 1079 /* Continuing, because target line might be inlined. */
1017 } 1080 }
1018 /* TODO: deallocate lines, but how? */ 1081 /* TODO: deallocate lines, but how? */
@@ -1047,7 +1110,7 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
1047 pr_debug("found inline addr: 0x%jx\n", 1110 pr_debug("found inline addr: 0x%jx\n",
1048 (uintmax_t)pf->addr); 1111 (uintmax_t)pf->addr);
1049 1112
1050 param->retval = convert_probe_point(in_die, pf); 1113 param->retval = call_probe_finder(in_die, pf);
1051 if (param->retval < 0) 1114 if (param->retval < 0)
1052 return DWARF_CB_ABORT; 1115 return DWARF_CB_ABORT;
1053 } 1116 }
@@ -1085,7 +1148,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
1085 } 1148 }
1086 pf->addr += pp->offset; 1149 pf->addr += pp->offset;
1087 /* TODO: Check the address in this function */ 1150 /* TODO: Check the address in this function */
1088 param->retval = convert_probe_point(sp_die, pf); 1151 param->retval = call_probe_finder(sp_die, pf);
1089 } 1152 }
1090 } else { 1153 } else {
1091 struct dwarf_callback_param _param = {.data = (void *)pf, 1154 struct dwarf_callback_param _param = {.data = (void *)pf,
@@ -1107,70 +1170,229 @@ static int find_probe_point_by_func(struct probe_finder *pf)
1107 return _param.retval; 1170 return _param.retval;
1108} 1171}
1109 1172
1110/* Find probe_trace_events specified by perf_probe_event from debuginfo */ 1173/* Find probe points from debuginfo */
1111int find_probe_trace_events(int fd, struct perf_probe_event *pev, 1174static int find_probes(int fd, struct probe_finder *pf)
1112 struct probe_trace_event **tevs, int max_tevs)
1113{ 1175{
1114 struct probe_finder pf = {.pev = pev, .max_tevs = max_tevs}; 1176 struct perf_probe_point *pp = &pf->pev->point;
1115 struct perf_probe_point *pp = &pev->point;
1116 Dwarf_Off off, noff; 1177 Dwarf_Off off, noff;
1117 size_t cuhl; 1178 size_t cuhl;
1118 Dwarf_Die *diep; 1179 Dwarf_Die *diep;
1119 Dwarf *dbg; 1180 Dwarf *dbg;
1120 int ret = 0; 1181 int ret = 0;
1121 1182
1122 pf.tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs);
1123 if (pf.tevs == NULL)
1124 return -ENOMEM;
1125 *tevs = pf.tevs;
1126 pf.ntevs = 0;
1127
1128 dbg = dwarf_begin(fd, DWARF_C_READ); 1183 dbg = dwarf_begin(fd, DWARF_C_READ);
1129 if (!dbg) { 1184 if (!dbg) {
1130 pr_warning("No dwarf info found in the vmlinux - " 1185 pr_warning("No dwarf info found in the vmlinux - "
1131 "please rebuild with CONFIG_DEBUG_INFO=y.\n"); 1186 "please rebuild with CONFIG_DEBUG_INFO=y.\n");
1132 free(pf.tevs);
1133 *tevs = NULL;
1134 return -EBADF; 1187 return -EBADF;
1135 } 1188 }
1136 1189
1137#if _ELFUTILS_PREREQ(0, 142) 1190#if _ELFUTILS_PREREQ(0, 142)
1138 /* Get the call frame information from this dwarf */ 1191 /* Get the call frame information from this dwarf */
1139 pf.cfi = dwarf_getcfi(dbg); 1192 pf->cfi = dwarf_getcfi(dbg);
1140#endif 1193#endif
1141 1194
1142 off = 0; 1195 off = 0;
1143 line_list__init(&pf.lcache); 1196 line_list__init(&pf->lcache);
1144 /* Loop on CUs (Compilation Unit) */ 1197 /* Loop on CUs (Compilation Unit) */
1145 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) && 1198 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) &&
1146 ret >= 0) { 1199 ret >= 0) {
1147 /* Get the DIE(Debugging Information Entry) of this CU */ 1200 /* Get the DIE(Debugging Information Entry) of this CU */
1148 diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die); 1201 diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die);
1149 if (!diep) 1202 if (!diep)
1150 continue; 1203 continue;
1151 1204
1152 /* Check if target file is included. */ 1205 /* Check if target file is included. */
1153 if (pp->file) 1206 if (pp->file)
1154 pf.fname = cu_find_realpath(&pf.cu_die, pp->file); 1207 pf->fname = cu_find_realpath(&pf->cu_die, pp->file);
1155 else 1208 else
1156 pf.fname = NULL; 1209 pf->fname = NULL;
1157 1210
1158 if (!pp->file || pf.fname) { 1211 if (!pp->file || pf->fname) {
1159 if (pp->function) 1212 if (pp->function)
1160 ret = find_probe_point_by_func(&pf); 1213 ret = find_probe_point_by_func(pf);
1161 else if (pp->lazy_line) 1214 else if (pp->lazy_line)
1162 ret = find_probe_point_lazy(NULL, &pf); 1215 ret = find_probe_point_lazy(NULL, pf);
1163 else { 1216 else {
1164 pf.lno = pp->line; 1217 pf->lno = pp->line;
1165 ret = find_probe_point_by_line(&pf); 1218 ret = find_probe_point_by_line(pf);
1166 } 1219 }
1167 } 1220 }
1168 off = noff; 1221 off = noff;
1169 } 1222 }
1170 line_list__free(&pf.lcache); 1223 line_list__free(&pf->lcache);
1171 dwarf_end(dbg); 1224 dwarf_end(dbg);
1172 1225
1173 return (ret < 0) ? ret : pf.ntevs; 1226 return ret;
1227}
1228
1229/* Add a found probe point into trace event list */
1230static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf)
1231{
1232 struct trace_event_finder *tf =
1233 container_of(pf, struct trace_event_finder, pf);
1234 struct probe_trace_event *tev;
1235 int ret, i;
1236
1237 /* Check number of tevs */
1238 if (tf->ntevs == tf->max_tevs) {
1239 pr_warning("Too many( > %d) probe point found.\n",
1240 tf->max_tevs);
1241 return -ERANGE;
1242 }
1243 tev = &tf->tevs[tf->ntevs++];
1244
1245 ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe,
1246 &tev->point);
1247 if (ret < 0)
1248 return ret;
1249
1250 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
1251 tev->point.offset);
1252
1253 /* Find each argument */
1254 tev->nargs = pf->pev->nargs;
1255 tev->args = zalloc(sizeof(struct probe_trace_arg) * tev->nargs);
1256 if (tev->args == NULL)
1257 return -ENOMEM;
1258 for (i = 0; i < pf->pev->nargs; i++) {
1259 pf->pvar = &pf->pev->args[i];
1260 pf->tvar = &tev->args[i];
1261 ret = find_variable(sp_die, pf);
1262 if (ret != 0)
1263 return ret;
1264 }
1265
1266 return 0;
1267}
1268
1269/* Find probe_trace_events specified by perf_probe_event from debuginfo */
1270int find_probe_trace_events(int fd, struct perf_probe_event *pev,
1271 struct probe_trace_event **tevs, int max_tevs)
1272{
1273 struct trace_event_finder tf = {
1274 .pf = {.pev = pev, .callback = add_probe_trace_event},
1275 .max_tevs = max_tevs};
1276 int ret;
1277
1278 /* Allocate result tevs array */
1279 *tevs = zalloc(sizeof(struct probe_trace_event) * max_tevs);
1280 if (*tevs == NULL)
1281 return -ENOMEM;
1282
1283 tf.tevs = *tevs;
1284 tf.ntevs = 0;
1285
1286 ret = find_probes(fd, &tf.pf);
1287 if (ret < 0) {
1288 free(*tevs);
1289 *tevs = NULL;
1290 return ret;
1291 }
1292
1293 return (ret < 0) ? ret : tf.ntevs;
1294}
1295
1296#define MAX_VAR_LEN 64
1297
1298/* Collect available variables in this scope */
1299static int collect_variables_cb(Dwarf_Die *die_mem, void *data)
1300{
1301 struct available_var_finder *af = data;
1302 struct variable_list *vl;
1303 char buf[MAX_VAR_LEN];
1304 int tag, ret;
1305
1306 vl = &af->vls[af->nvls - 1];
1307
1308 tag = dwarf_tag(die_mem);
1309 if (tag == DW_TAG_formal_parameter ||
1310 tag == DW_TAG_variable) {
1311 ret = convert_variable_location(die_mem, af->pf.addr,
1312 af->pf.fb_ops, NULL);
1313 if (ret == 0) {
1314 ret = die_get_varname(die_mem, buf, MAX_VAR_LEN);
1315 if (ret > 0)
1316 strlist__add(vl->vars, buf);
1317 }
1318 }
1319
1320 if (dwarf_haspc(die_mem, af->pf.addr))
1321 return DIE_FIND_CB_CONTINUE;
1322 else
1323 return DIE_FIND_CB_SIBLING;
1324}
1325
1326/* Add a found vars into available variables list */
1327static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf)
1328{
1329 struct available_var_finder *af =
1330 container_of(pf, struct available_var_finder, pf);
1331 struct variable_list *vl;
1332 Dwarf_Die die_mem;
1333 int ret;
1334
1335 /* Check number of tevs */
1336 if (af->nvls == af->max_vls) {
1337 pr_warning("Too many( > %d) probe point found.\n", af->max_vls);
1338 return -ERANGE;
1339 }
1340 vl = &af->vls[af->nvls++];
1341
1342 ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe,
1343 &vl->point);
1344 if (ret < 0)
1345 return ret;
1346
1347 pr_debug("Probe point found: %s+%lu\n", vl->point.symbol,
1348 vl->point.offset);
1349
1350 /* Find local variables */
1351 vl->vars = strlist__new(true, NULL);
1352 if (vl->vars == NULL)
1353 return -ENOMEM;
1354 die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem);
1355
1356 if (strlist__empty(vl->vars)) {
1357 strlist__delete(vl->vars);
1358 vl->vars = NULL;
1359 }
1360
1361 return ret;
1362}
1363
1364/* Find available variables at given probe point */
1365int find_available_vars_at(int fd, struct perf_probe_event *pev,
1366 struct variable_list **vls, int max_vls)
1367{
1368 struct available_var_finder af = {
1369 .pf = {.pev = pev, .callback = add_available_vars},
1370 .max_vls = max_vls};
1371 int ret;
1372
1373 /* Allocate result vls array */
1374 *vls = zalloc(sizeof(struct variable_list) * max_vls);
1375 if (*vls == NULL)
1376 return -ENOMEM;
1377
1378 af.vls = *vls;
1379 af.nvls = 0;
1380
1381 ret = find_probes(fd, &af.pf);
1382 if (ret < 0) {
1383 /* Free vlist for error */
1384 while (af.nvls--) {
1385 if (af.vls[af.nvls].point.symbol)
1386 free(af.vls[af.nvls].point.symbol);
1387 if (af.vls[af.nvls].vars)
1388 strlist__delete(af.vls[af.nvls].vars);
1389 }
1390 free(af.vls);
1391 *vls = NULL;
1392 return ret;
1393 }
1394
1395 return (ret < 0) ? ret : af.nvls;
1174} 1396}
1175 1397
1176/* Reverse search */ 1398/* Reverse search */
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 4507d519f183..baffd25f39c9 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -25,17 +25,22 @@ extern int find_probe_trace_events(int fd, struct perf_probe_event *pev,
25extern int find_perf_probe_point(int fd, unsigned long addr, 25extern int find_perf_probe_point(int fd, unsigned long addr,
26 struct perf_probe_point *ppt); 26 struct perf_probe_point *ppt);
27 27
28/* Find a line range */
28extern int find_line_range(int fd, struct line_range *lr); 29extern int find_line_range(int fd, struct line_range *lr);
29 30
31/* Find available variables */
32extern int find_available_vars_at(int fd, struct perf_probe_event *pev,
33 struct variable_list **vls, int max_points);
34
30#include <dwarf.h> 35#include <dwarf.h>
31#include <libdw.h> 36#include <libdw.h>
32#include <version.h> 37#include <version.h>
33 38
34struct probe_finder { 39struct probe_finder {
35 struct perf_probe_event *pev; /* Target probe event */ 40 struct perf_probe_event *pev; /* Target probe event */
36 struct probe_trace_event *tevs; /* Result trace events */ 41
37 int ntevs; /* Number of trace events */ 42 /* Callback when a probe point is found */
38 int max_tevs; /* Max number of trace events */ 43 int (*callback)(Dwarf_Die *sp_die, struct probe_finder *pf);
39 44
40 /* For function searching */ 45 /* For function searching */
41 int lno; /* Line number */ 46 int lno; /* Line number */
@@ -53,6 +58,20 @@ struct probe_finder {
53 struct probe_trace_arg *tvar; /* Current result variable */ 58 struct probe_trace_arg *tvar; /* Current result variable */
54}; 59};
55 60
61struct trace_event_finder {
62 struct probe_finder pf;
63 struct probe_trace_event *tevs; /* Found trace events */
64 int ntevs; /* Number of trace events */
65 int max_tevs; /* Max number of trace events */
66};
67
68struct available_var_finder {
69 struct probe_finder pf;
70 struct variable_list *vls; /* Found variable lists */
71 int nvls; /* Number of variable lists */
72 int max_vls; /* Max no. of variable lists */
73};
74
56struct line_finder { 75struct line_finder {
57 struct line_range *lr; /* Target line range */ 76 struct line_range *lr; /* Target line range */
58 77