aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
authorMasami Hiramatsu <mhiramat@redhat.com>2010-05-19 15:57:42 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2010-07-05 17:50:27 -0400
commitb2a3c12b7442247c440f7083d48ef05716753ec1 (patch)
treec3a3d0bb442e285979b0dbeecfbf0c04a8b3743e /tools/perf/util
parent73317b954041031249e8968d2e9023ff4e960d99 (diff)
perf probe: Support tracing an entry of array
Add array-entry tracing support to perf probe. This enables to trace an entry of array which is indexed by constant value, e.g. array[0]. For example: $ perf probe -a 'bio_split bi->bi_io_vec[0]' Cc: Paul Mackerras <paulus@samba.org> Cc: Ingo Molnar <mingo@elte.hu> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Mike Galbraith <efault@gmx.de> Cc: Frederic Weisbecker <fweisbec@gmail.com> LKML-Reference: <20100519195742.2885.5344.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/util')
-rw-r--r--tools/perf/util/probe-event.c56
-rw-r--r--tools/perf/util/probe-event.h1
-rw-r--r--tools/perf/util/probe-finder.c48
3 files changed, 82 insertions, 23 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 914c67095d96..351baa9a3695 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -557,7 +557,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
557/* Parse perf-probe event argument */ 557/* Parse perf-probe event argument */
558static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg) 558static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
559{ 559{
560 char *tmp; 560 char *tmp, *goodname;
561 struct perf_probe_arg_field **fieldp; 561 struct perf_probe_arg_field **fieldp;
562 562
563 pr_debug("parsing arg: %s into ", str); 563 pr_debug("parsing arg: %s into ", str);
@@ -580,7 +580,7 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
580 pr_debug("type:%s ", arg->type); 580 pr_debug("type:%s ", arg->type);
581 } 581 }
582 582
583 tmp = strpbrk(str, "-."); 583 tmp = strpbrk(str, "-.[");
584 if (!is_c_varname(str) || !tmp) { 584 if (!is_c_varname(str) || !tmp) {
585 /* A variable, register, symbol or special value */ 585 /* A variable, register, symbol or special value */
586 arg->var = strdup(str); 586 arg->var = strdup(str);
@@ -590,10 +590,11 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
590 return 0; 590 return 0;
591 } 591 }
592 592
593 /* Structure fields */ 593 /* Structure fields or array element */
594 arg->var = strndup(str, tmp - str); 594 arg->var = strndup(str, tmp - str);
595 if (arg->var == NULL) 595 if (arg->var == NULL)
596 return -ENOMEM; 596 return -ENOMEM;
597 goodname = arg->var;
597 pr_debug("%s, ", arg->var); 598 pr_debug("%s, ", arg->var);
598 fieldp = &arg->field; 599 fieldp = &arg->field;
599 600
@@ -601,22 +602,38 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
601 *fieldp = zalloc(sizeof(struct perf_probe_arg_field)); 602 *fieldp = zalloc(sizeof(struct perf_probe_arg_field));
602 if (*fieldp == NULL) 603 if (*fieldp == NULL)
603 return -ENOMEM; 604 return -ENOMEM;
604 if (*tmp == '.') { 605 if (*tmp == '[') { /* Array */
605 str = tmp + 1; 606 str = tmp;
606 (*fieldp)->ref = false; 607 (*fieldp)->index = strtol(str + 1, &tmp, 0);
607 } else if (tmp[1] == '>') {
608 str = tmp + 2;
609 (*fieldp)->ref = true; 608 (*fieldp)->ref = true;
610 } else { 609 if (*tmp != ']' || tmp == str + 1) {
611 semantic_error("Argument parse error: %s\n", str); 610 semantic_error("Array index must be a"
612 return -EINVAL; 611 " number.\n");
612 return -EINVAL;
613 }
614 tmp++;
615 if (*tmp == '\0')
616 tmp = NULL;
617 } else { /* Structure */
618 if (*tmp == '.') {
619 str = tmp + 1;
620 (*fieldp)->ref = false;
621 } else if (tmp[1] == '>') {
622 str = tmp + 2;
623 (*fieldp)->ref = true;
624 } else {
625 semantic_error("Argument parse error: %s\n",
626 str);
627 return -EINVAL;
628 }
629 tmp = strpbrk(str, "-.[");
613 } 630 }
614
615 tmp = strpbrk(str, "-.");
616 if (tmp) { 631 if (tmp) {
617 (*fieldp)->name = strndup(str, tmp - str); 632 (*fieldp)->name = strndup(str, tmp - str);
618 if ((*fieldp)->name == NULL) 633 if ((*fieldp)->name == NULL)
619 return -ENOMEM; 634 return -ENOMEM;
635 if (*str != '[')
636 goodname = (*fieldp)->name;
620 pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref); 637 pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref);
621 fieldp = &(*fieldp)->next; 638 fieldp = &(*fieldp)->next;
622 } 639 }
@@ -624,11 +641,13 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
624 (*fieldp)->name = strdup(str); 641 (*fieldp)->name = strdup(str);
625 if ((*fieldp)->name == NULL) 642 if ((*fieldp)->name == NULL)
626 return -ENOMEM; 643 return -ENOMEM;
644 if (*str != '[')
645 goodname = (*fieldp)->name;
627 pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref); 646 pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref);
628 647
629 /* If no name is specified, set the last field name */ 648 /* If no name is specified, set the last field name (not array index)*/
630 if (!arg->name) { 649 if (!arg->name) {
631 arg->name = strdup((*fieldp)->name); 650 arg->name = strdup(goodname);
632 if (arg->name == NULL) 651 if (arg->name == NULL)
633 return -ENOMEM; 652 return -ENOMEM;
634 } 653 }
@@ -776,8 +795,11 @@ int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
776 len -= ret; 795 len -= ret;
777 796
778 while (field) { 797 while (field) {
779 ret = e_snprintf(tmp, len, "%s%s", field->ref ? "->" : ".", 798 if (field->name[0] == '[')
780 field->name); 799 ret = e_snprintf(tmp, len, "%s", field->name);
800 else
801 ret = e_snprintf(tmp, len, "%s%s",
802 field->ref ? "->" : ".", field->name);
781 if (ret <= 0) 803 if (ret <= 0)
782 goto error; 804 goto error;
783 tmp += ret; 805 tmp += ret;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index e9db1a214ca4..bc06d3e8bafa 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -50,6 +50,7 @@ struct perf_probe_point {
50struct perf_probe_arg_field { 50struct perf_probe_arg_field {
51 struct perf_probe_arg_field *next; /* Next field */ 51 struct perf_probe_arg_field *next; /* Next field */
52 char *name; /* Name of the field */ 52 char *name; /* Name of the field */
53 long index; /* Array index number */
53 bool ref; /* Referencing flag */ 54 bool ref; /* Referencing flag */
54}; 55};
55 56
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index aaea16b1c60b..308664deb857 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -485,6 +485,9 @@ static int convert_variable_type(Dwarf_Die *vr_die,
485 return -ENOENT; 485 return -ENOENT;
486 } 486 }
487 487
488 pr_debug("%s type is %s.\n",
489 dwarf_diename(vr_die), dwarf_diename(&type));
490
488 if (cast && strcmp(cast, "string") == 0) { /* String type */ 491 if (cast && strcmp(cast, "string") == 0) { /* String type */
489 ret = dwarf_tag(&type); 492 ret = dwarf_tag(&type);
490 if (ret != DW_TAG_pointer_type && 493 if (ret != DW_TAG_pointer_type &&
@@ -553,16 +556,44 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
553 struct kprobe_trace_arg_ref *ref = *ref_ptr; 556 struct kprobe_trace_arg_ref *ref = *ref_ptr;
554 Dwarf_Die type; 557 Dwarf_Die type;
555 Dwarf_Word offs; 558 Dwarf_Word offs;
556 int ret; 559 int ret, tag;
557 560
558 pr_debug("converting %s in %s\n", field->name, varname); 561 pr_debug("converting %s in %s\n", field->name, varname);
559 if (die_get_real_type(vr_die, &type) == NULL) { 562 if (die_get_real_type(vr_die, &type) == NULL) {
560 pr_warning("Failed to get the type of %s.\n", varname); 563 pr_warning("Failed to get the type of %s.\n", varname);
561 return -ENOENT; 564 return -ENOENT;
562 } 565 }
563 566 pr_debug2("Var real type: (%x)\n", (unsigned)dwarf_dieoffset(&type));
564 /* Check the pointer and dereference */ 567 tag = dwarf_tag(&type);
565 if (dwarf_tag(&type) == DW_TAG_pointer_type) { 568
569 if (field->name[0] == '[' &&
570 (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) {
571 if (field->next)
572 /* Save original type for next field */
573 memcpy(die_mem, &type, sizeof(*die_mem));
574 /* Get the type of this array */
575 if (die_get_real_type(&type, &type) == NULL) {
576 pr_warning("Failed to get the type of %s.\n", varname);
577 return -ENOENT;
578 }
579 pr_debug2("Array real type: (%x)\n",
580 (unsigned)dwarf_dieoffset(&type));
581 if (tag == DW_TAG_pointer_type) {
582 ref = zalloc(sizeof(struct kprobe_trace_arg_ref));
583 if (ref == NULL)
584 return -ENOMEM;
585 if (*ref_ptr)
586 (*ref_ptr)->next = ref;
587 else
588 *ref_ptr = ref;
589 }
590 ref->offset += die_get_byte_size(&type) * field->index;
591 if (!field->next)
592 /* Save vr_die for converting types */
593 memcpy(die_mem, vr_die, sizeof(*die_mem));
594 goto next;
595 } else if (tag == DW_TAG_pointer_type) {
596 /* Check the pointer and dereference */
566 if (!field->ref) { 597 if (!field->ref) {
567 pr_err("Semantic error: %s must be referred by '->'\n", 598 pr_err("Semantic error: %s must be referred by '->'\n",
568 field->name); 599 field->name);
@@ -588,10 +619,15 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
588 *ref_ptr = ref; 619 *ref_ptr = ref;
589 } else { 620 } else {
590 /* Verify it is a data structure */ 621 /* Verify it is a data structure */
591 if (dwarf_tag(&type) != DW_TAG_structure_type) { 622 if (tag != DW_TAG_structure_type) {
592 pr_warning("%s is not a data structure.\n", varname); 623 pr_warning("%s is not a data structure.\n", varname);
593 return -EINVAL; 624 return -EINVAL;
594 } 625 }
626 if (field->name[0] == '[') {
627 pr_err("Semantic error: %s is not a pointor nor array.",
628 varname);
629 return -EINVAL;
630 }
595 if (field->ref) { 631 if (field->ref) {
596 pr_err("Semantic error: %s must be referred by '.'\n", 632 pr_err("Semantic error: %s must be referred by '.'\n",
597 field->name); 633 field->name);
@@ -618,6 +654,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
618 } 654 }
619 ref->offset += (long)offs; 655 ref->offset += (long)offs;
620 656
657next:
621 /* Converting next field */ 658 /* Converting next field */
622 if (field->next) 659 if (field->next)
623 return convert_variable_fields(die_mem, field->name, 660 return convert_variable_fields(die_mem, field->name,
@@ -667,7 +704,6 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
667 char buf[32], *ptr; 704 char buf[32], *ptr;
668 int ret; 705 int ret;
669 706
670 /* TODO: Support arrays */
671 if (pf->pvar->name) 707 if (pf->pvar->name)
672 pf->tvar->name = strdup(pf->pvar->name); 708 pf->tvar->name = strdup(pf->pvar->name);
673 else { 709 else {