diff options
author | Masami Hiramatsu <mhiramat@redhat.com> | 2010-05-19 15:57:35 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2010-07-05 17:47:28 -0400 |
commit | 73317b954041031249e8968d2e9023ff4e960d99 (patch) | |
tree | 44768b7724bacbb15c54057710c70accce1cd8c3 /tools/perf | |
parent | e09c8614b32915c16f68e039ac7040e602d73e35 (diff) |
perf probe: Support "string" type
Support string type casting to event argument. If perf-probe finds an argument
casted as string, it ensures the target variable is "(unsigned/signed) char
*(or []). perf-probe also adds dereference if the target is a pointer.
So, both of 'char buf[10];' and 'char *buf;' can be accessed by 'buf:string'
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
LKML-Reference: <20100519195734.2885.1666.stgit@localhost6.localdomain6>
Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/Documentation/perf-probe.txt | 2 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.c | 59 |
2 files changed, 49 insertions, 12 deletions
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index ea531d9d975c..394016d33ce3 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt | |||
@@ -95,7 +95,7 @@ Each probe argument follows below syntax. | |||
95 | [NAME=]LOCALVAR|$retval|%REG|@SYMBOL[:TYPE] | 95 | [NAME=]LOCALVAR|$retval|%REG|@SYMBOL[:TYPE] |
96 | 96 | ||
97 | 'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.) | 97 | 'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.) |
98 | 'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo. | 98 | 'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo. You can specify 'string' type only for the local variable or structure member which is an array of or a pointer to 'char' or 'unsigned char' type. |
99 | 99 | ||
100 | LINE SYNTAX | 100 | LINE SYNTAX |
101 | ----------- | 101 | ----------- |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index baf665383498..aaea16b1c60b 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -464,18 +464,61 @@ static int convert_location(Dwarf_Op *op, struct probe_finder *pf) | |||
464 | } | 464 | } |
465 | 465 | ||
466 | static int convert_variable_type(Dwarf_Die *vr_die, | 466 | static int convert_variable_type(Dwarf_Die *vr_die, |
467 | struct kprobe_trace_arg *targ) | 467 | struct kprobe_trace_arg *tvar, |
468 | const char *cast) | ||
468 | { | 469 | { |
470 | struct kprobe_trace_arg_ref **ref_ptr = &tvar->ref; | ||
469 | Dwarf_Die type; | 471 | Dwarf_Die type; |
470 | char buf[16]; | 472 | char buf[16]; |
471 | int ret; | 473 | int ret; |
472 | 474 | ||
475 | /* TODO: check all types */ | ||
476 | if (cast && strcmp(cast, "string") != 0) { | ||
477 | /* Non string type is OK */ | ||
478 | tvar->type = strdup(cast); | ||
479 | return (tvar->type == NULL) ? -ENOMEM : 0; | ||
480 | } | ||
481 | |||
473 | if (die_get_real_type(vr_die, &type) == NULL) { | 482 | if (die_get_real_type(vr_die, &type) == NULL) { |
474 | pr_warning("Failed to get a type information of %s.\n", | 483 | pr_warning("Failed to get a type information of %s.\n", |
475 | dwarf_diename(vr_die)); | 484 | dwarf_diename(vr_die)); |
476 | return -ENOENT; | 485 | return -ENOENT; |
477 | } | 486 | } |
478 | 487 | ||
488 | if (cast && strcmp(cast, "string") == 0) { /* String type */ | ||
489 | ret = dwarf_tag(&type); | ||
490 | if (ret != DW_TAG_pointer_type && | ||
491 | ret != DW_TAG_array_type) { | ||
492 | pr_warning("Failed to cast into string: " | ||
493 | "%s(%s) is not a pointer nor array.", | ||
494 | dwarf_diename(vr_die), dwarf_diename(&type)); | ||
495 | return -EINVAL; | ||
496 | } | ||
497 | if (ret == DW_TAG_pointer_type) { | ||
498 | if (die_get_real_type(&type, &type) == NULL) { | ||
499 | pr_warning("Failed to get a type information."); | ||
500 | return -ENOENT; | ||
501 | } | ||
502 | while (*ref_ptr) | ||
503 | ref_ptr = &(*ref_ptr)->next; | ||
504 | /* Add new reference with offset +0 */ | ||
505 | *ref_ptr = zalloc(sizeof(struct kprobe_trace_arg_ref)); | ||
506 | if (*ref_ptr == NULL) { | ||
507 | pr_warning("Out of memory error\n"); | ||
508 | return -ENOMEM; | ||
509 | } | ||
510 | } | ||
511 | if (die_compare_name(&type, "char") != 0 && | ||
512 | die_compare_name(&type, "unsigned char") != 0) { | ||
513 | pr_warning("Failed to cast into string: " | ||
514 | "%s is not (unsigned) char *.", | ||
515 | dwarf_diename(vr_die)); | ||
516 | return -EINVAL; | ||
517 | } | ||
518 | tvar->type = strdup(cast); | ||
519 | return (tvar->type == NULL) ? -ENOMEM : 0; | ||
520 | } | ||
521 | |||
479 | ret = die_get_byte_size(&type) * 8; | 522 | ret = die_get_byte_size(&type) * 8; |
480 | if (ret) { | 523 | if (ret) { |
481 | /* Check the bitwidth */ | 524 | /* Check the bitwidth */ |
@@ -495,8 +538,8 @@ static int convert_variable_type(Dwarf_Die *vr_die, | |||
495 | strerror(-ret)); | 538 | strerror(-ret)); |
496 | return ret; | 539 | return ret; |
497 | } | 540 | } |
498 | targ->type = strdup(buf); | 541 | tvar->type = strdup(buf); |
499 | if (targ->type == NULL) | 542 | if (tvar->type == NULL) |
500 | return -ENOMEM; | 543 | return -ENOMEM; |
501 | } | 544 | } |
502 | return 0; | 545 | return 0; |
@@ -606,14 +649,8 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) | |||
606 | &die_mem); | 649 | &die_mem); |
607 | vr_die = &die_mem; | 650 | vr_die = &die_mem; |
608 | } | 651 | } |
609 | if (ret == 0) { | 652 | if (ret == 0) |
610 | if (pf->pvar->type) { | 653 | ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type); |
611 | pf->tvar->type = strdup(pf->pvar->type); | ||
612 | if (pf->tvar->type == NULL) | ||
613 | ret = -ENOMEM; | ||
614 | } else | ||
615 | ret = convert_variable_type(vr_die, pf->tvar); | ||
616 | } | ||
617 | /* *expr will be cached in libdw. Don't free it. */ | 654 | /* *expr will be cached in libdw. Don't free it. */ |
618 | return ret; | 655 | return ret; |
619 | error: | 656 | error: |