diff options
Diffstat (limited to 'tools/perf/util/probe-event.c')
-rw-r--r-- | tools/perf/util/probe-event.c | 71 |
1 files changed, 51 insertions, 20 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 914c67095d96..09cf5465e10a 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 */ |
558 | static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg) | 558 | static 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; |
@@ -904,6 +926,7 @@ out: | |||
904 | static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg, | 926 | static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg, |
905 | char *buf, size_t buflen) | 927 | char *buf, size_t buflen) |
906 | { | 928 | { |
929 | struct kprobe_trace_arg_ref *ref = arg->ref; | ||
907 | int ret, depth = 0; | 930 | int ret, depth = 0; |
908 | char *tmp = buf; | 931 | char *tmp = buf; |
909 | 932 | ||
@@ -917,16 +940,24 @@ static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg, | |||
917 | buf += ret; | 940 | buf += ret; |
918 | buflen -= ret; | 941 | buflen -= ret; |
919 | 942 | ||
943 | /* Special case: @XXX */ | ||
944 | if (arg->value[0] == '@' && arg->ref) | ||
945 | ref = ref->next; | ||
946 | |||
920 | /* Dereferencing arguments */ | 947 | /* Dereferencing arguments */ |
921 | if (arg->ref) { | 948 | if (ref) { |
922 | depth = __synthesize_kprobe_trace_arg_ref(arg->ref, &buf, | 949 | depth = __synthesize_kprobe_trace_arg_ref(ref, &buf, |
923 | &buflen, 1); | 950 | &buflen, 1); |
924 | if (depth < 0) | 951 | if (depth < 0) |
925 | return depth; | 952 | return depth; |
926 | } | 953 | } |
927 | 954 | ||
928 | /* Print argument value */ | 955 | /* Print argument value */ |
929 | ret = e_snprintf(buf, buflen, "%s", arg->value); | 956 | if (arg->value[0] == '@' && arg->ref) |
957 | ret = e_snprintf(buf, buflen, "%s%+ld", arg->value, | ||
958 | arg->ref->offset); | ||
959 | else | ||
960 | ret = e_snprintf(buf, buflen, "%s", arg->value); | ||
930 | if (ret < 0) | 961 | if (ret < 0) |
931 | return ret; | 962 | return ret; |
932 | buf += ret; | 963 | buf += ret; |