diff options
author | Masami Hiramatsu <mhiramat@redhat.com> | 2010-03-16 18:06:26 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-03-17 07:11:15 -0400 |
commit | 7df2f32956cf0f1a45df38cd0e0fe0c3467580e8 (patch) | |
tree | 1cccbf0d4239ebdd9c0f67762b5a2f0facbe53dc /tools/perf/util/probe-event.c | |
parent | fb1587d869a399554220e166d4b90b581a8ade01 (diff) |
perf probe: Add data structure member access support
Support accessing members in the data structures. With this,
perf-probe accepts data-structure members(IOW, it now accepts
dot '.' and arrow '->' operators) as probe arguemnts.
e.g.
./perf probe --add 'schedule:44 rq->curr'
./perf probe --add 'vfs_read file->f_op->read file->f_path.dentry'
Note that '>' can be interpreted as redirection in command-line.
Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: systemtap <systemtap@sources.redhat.com>
Cc: DLE <dle-develop@lists.sourceforge.net>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <20100316220626.32050.57552.stgit@localhost6.localdomain6>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/util/probe-event.c')
-rw-r--r-- | tools/perf/util/probe-event.c | 90 |
1 files changed, 86 insertions, 4 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 4e3c1aea7892..64dea6c3d58a 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -262,6 +262,49 @@ static void parse_perf_probe_point(char *arg, struct perf_probe_event *pev) | |||
262 | pp->lazy_line); | 262 | pp->lazy_line); |
263 | } | 263 | } |
264 | 264 | ||
265 | /* Parse perf-probe event argument */ | ||
266 | static void parse_perf_probe_arg(const char *str, struct perf_probe_arg *arg) | ||
267 | { | ||
268 | const char *tmp; | ||
269 | struct perf_probe_arg_field **fieldp; | ||
270 | |||
271 | pr_debug("parsing arg: %s into ", str); | ||
272 | |||
273 | tmp = strpbrk(str, "-."); | ||
274 | if (!is_c_varname(str) || !tmp) { | ||
275 | /* A variable, register, symbol or special value */ | ||
276 | arg->name = xstrdup(str); | ||
277 | pr_debug("%s\n", arg->name); | ||
278 | return; | ||
279 | } | ||
280 | |||
281 | /* Structure fields */ | ||
282 | arg->name = xstrndup(str, tmp - str); | ||
283 | pr_debug("%s, ", arg->name); | ||
284 | fieldp = &arg->field; | ||
285 | |||
286 | do { | ||
287 | *fieldp = xzalloc(sizeof(struct perf_probe_arg_field)); | ||
288 | if (*tmp == '.') { | ||
289 | str = tmp + 1; | ||
290 | (*fieldp)->ref = false; | ||
291 | } else if (tmp[1] == '>') { | ||
292 | str = tmp + 2; | ||
293 | (*fieldp)->ref = true; | ||
294 | } else | ||
295 | semantic_error("Argument parse error: %s", str); | ||
296 | |||
297 | tmp = strpbrk(str, "-."); | ||
298 | if (tmp) { | ||
299 | (*fieldp)->name = xstrndup(str, tmp - str); | ||
300 | pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref); | ||
301 | fieldp = &(*fieldp)->next; | ||
302 | } | ||
303 | } while (tmp); | ||
304 | (*fieldp)->name = xstrdup(str); | ||
305 | pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref); | ||
306 | } | ||
307 | |||
265 | /* Parse perf-probe event command */ | 308 | /* Parse perf-probe event command */ |
266 | void parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev) | 309 | void parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev) |
267 | { | 310 | { |
@@ -281,7 +324,7 @@ void parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev) | |||
281 | pev->nargs = argc - 1; | 324 | pev->nargs = argc - 1; |
282 | pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs); | 325 | pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs); |
283 | for (i = 0; i < pev->nargs; i++) { | 326 | for (i = 0; i < pev->nargs; i++) { |
284 | pev->args[i].name = xstrdup(argv[i + 1]); | 327 | parse_perf_probe_arg(argv[i + 1], &pev->args[i]); |
285 | if (is_c_varname(pev->args[i].name) && pev->point.retprobe) | 328 | if (is_c_varname(pev->args[i].name) && pev->point.retprobe) |
286 | semantic_error("You can't specify local variable for" | 329 | semantic_error("You can't specify local variable for" |
287 | " kretprobe"); | 330 | " kretprobe"); |
@@ -353,6 +396,33 @@ void parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev) | |||
353 | argv_free(argv); | 396 | argv_free(argv); |
354 | } | 397 | } |
355 | 398 | ||
399 | /* Compose only probe arg */ | ||
400 | int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len) | ||
401 | { | ||
402 | struct perf_probe_arg_field *field = pa->field; | ||
403 | int ret; | ||
404 | char *tmp = buf; | ||
405 | |||
406 | ret = e_snprintf(tmp, len, "%s", pa->name); | ||
407 | if (ret <= 0) | ||
408 | goto error; | ||
409 | tmp += ret; | ||
410 | len -= ret; | ||
411 | |||
412 | while (field) { | ||
413 | ret = e_snprintf(tmp, len, "%s%s", field->ref ? "->" : ".", | ||
414 | field->name); | ||
415 | if (ret <= 0) | ||
416 | goto error; | ||
417 | tmp += ret; | ||
418 | len -= ret; | ||
419 | field = field->next; | ||
420 | } | ||
421 | return tmp - buf; | ||
422 | error: | ||
423 | die("Failed to synthesize perf probe argument: %s", strerror(-ret)); | ||
424 | } | ||
425 | |||
356 | /* Compose only probe point (not argument) */ | 426 | /* Compose only probe point (not argument) */ |
357 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp) | 427 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp) |
358 | { | 428 | { |
@@ -563,6 +633,7 @@ void convert_to_perf_probe_event(struct kprobe_trace_event *tev, | |||
563 | void clear_perf_probe_event(struct perf_probe_event *pev) | 633 | void clear_perf_probe_event(struct perf_probe_event *pev) |
564 | { | 634 | { |
565 | struct perf_probe_point *pp = &pev->point; | 635 | struct perf_probe_point *pp = &pev->point; |
636 | struct perf_probe_arg_field *field, *next; | ||
566 | int i; | 637 | int i; |
567 | 638 | ||
568 | if (pev->event) | 639 | if (pev->event) |
@@ -575,9 +646,18 @@ void clear_perf_probe_event(struct perf_probe_event *pev) | |||
575 | free(pp->function); | 646 | free(pp->function); |
576 | if (pp->lazy_line) | 647 | if (pp->lazy_line) |
577 | free(pp->lazy_line); | 648 | free(pp->lazy_line); |
578 | for (i = 0; i < pev->nargs; i++) | 649 | for (i = 0; i < pev->nargs; i++) { |
579 | if (pev->args[i].name) | 650 | if (pev->args[i].name) |
580 | free(pev->args[i].name); | 651 | free(pev->args[i].name); |
652 | field = pev->args[i].field; | ||
653 | while (field) { | ||
654 | next = field->next; | ||
655 | if (field->name) | ||
656 | free(field->name); | ||
657 | free(field); | ||
658 | field = next; | ||
659 | } | ||
660 | } | ||
581 | if (pev->args) | 661 | if (pev->args) |
582 | free(pev->args); | 662 | free(pev->args); |
583 | memset(pev, 0, sizeof(*pev)); | 663 | memset(pev, 0, sizeof(*pev)); |
@@ -682,8 +762,10 @@ static void show_perf_probe_event(struct perf_probe_event *pev) | |||
682 | 762 | ||
683 | if (pev->nargs > 0) { | 763 | if (pev->nargs > 0) { |
684 | printf(" with"); | 764 | printf(" with"); |
685 | for (i = 0; i < pev->nargs; i++) | 765 | for (i = 0; i < pev->nargs; i++) { |
686 | printf(" %s", pev->args[i].name); | 766 | synthesize_perf_probe_arg(&pev->args[i], buf, 128); |
767 | printf(" %s", buf); | ||
768 | } | ||
687 | } | 769 | } |
688 | printf(")\n"); | 770 | printf(")\n"); |
689 | free(place); | 771 | free(place); |