aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Documentation/perf-probe.txt2
-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
4 files changed, 83 insertions, 24 deletions
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 394016d33ce3..27d52dae5a43 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -94,7 +94,7 @@ Each probe argument follows below syntax.
94 94
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), local array with fixed index (e.g. array[1], var->array[0], var->pointer[2]), 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. 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. 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
100LINE SYNTAX 100LINE SYNTAX
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 {