diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/perf/Documentation/perf-probe.txt | 10 | ||||
| -rw-r--r-- | tools/perf/builtin-probe.c | 4 | ||||
| -rw-r--r-- | tools/perf/util/probe-event.c | 34 | ||||
| -rw-r--r-- | tools/perf/util/probe-event.h | 1 | ||||
| -rw-r--r-- | tools/perf/util/probe-finder.c | 27 |
5 files changed, 52 insertions, 24 deletions
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt index bb671b346774..e36ed4dd3868 100644 --- a/tools/perf/Documentation/perf-probe.txt +++ b/tools/perf/Documentation/perf-probe.txt | |||
| @@ -79,7 +79,15 @@ Probe points are defined by following syntax. | |||
| 79 | 'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. Currently, event group name is set as 'probe'. | 79 | 'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. Currently, event group name is set as 'probe'. |
| 80 | 'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, ':RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. And ';PTN' means lazy matching pattern (see LAZY MATCHING). Note that ';PTN' must be the end of the probe point definition. In addition, '@SRC' specifies a source file which has that function. | 80 | 'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, ':RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. And ';PTN' means lazy matching pattern (see LAZY MATCHING). Note that ';PTN' must be the end of the probe point definition. In addition, '@SRC' specifies a source file which has that function. |
| 81 | It is also possible to specify a probe point by the source line number or lazy matching by using 'SRC:ALN' or 'SRC;PTN' syntax, where 'SRC' is the source file path, ':ALN' is the line number and ';PTN' is the lazy matching pattern. | 81 | It is also possible to specify a probe point by the source line number or lazy matching by using 'SRC:ALN' or 'SRC;PTN' syntax, where 'SRC' is the source file path, ':ALN' is the line number and ';PTN' is the lazy matching pattern. |
| 82 | 'ARG' specifies the arguments of this probe point. You can use the name of local variable, or kprobe-tracer argument format (e.g. $retval, %ax, etc). | 82 | 'ARG' specifies the arguments of this probe point, (see PROBE ARGUMENT). |
| 83 | |||
| 84 | PROBE ARGUMENT | ||
| 85 | -------------- | ||
| 86 | Each probe argument follows below syntax. | ||
| 87 | |||
| 88 | [NAME=]LOCALVAR|$retval|%REG|@SYMBOL | ||
| 89 | |||
| 90 | '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). | ||
| 83 | 91 | ||
| 84 | LINE SYNTAX | 92 | LINE SYNTAX |
| 85 | ----------- | 93 | ----------- |
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index bfc47fff9c59..daf4668d2de0 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
| @@ -142,9 +142,9 @@ static const struct option options[] = { | |||
| 142 | OPT_CALLBACK('a', "add", NULL, | 142 | OPT_CALLBACK('a', "add", NULL, |
| 143 | #ifdef DWARF_SUPPORT | 143 | #ifdef DWARF_SUPPORT |
| 144 | "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT" | 144 | "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT" |
| 145 | " [ARG ...]", | 145 | " [[NAME=]ARG ...]", |
| 146 | #else | 146 | #else |
| 147 | "[EVENT=]FUNC[+OFF|%return] [ARG ...]", | 147 | "[EVENT=]FUNC[+OFF|%return] [[NAME=]ARG ...]", |
| 148 | #endif | 148 | #endif |
| 149 | "probe point definition, where\n" | 149 | "probe point definition, where\n" |
| 150 | "\t\tGROUP:\tGroup name (optional)\n" | 150 | "\t\tGROUP:\tGroup name (optional)\n" |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 3fc0be741b8e..ab6f53deabad 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
| @@ -437,22 +437,28 @@ static void parse_perf_probe_point(char *arg, struct perf_probe_event *pev) | |||
| 437 | /* Parse perf-probe event argument */ | 437 | /* Parse perf-probe event argument */ |
| 438 | static void parse_perf_probe_arg(const char *str, struct perf_probe_arg *arg) | 438 | static void parse_perf_probe_arg(const char *str, struct perf_probe_arg *arg) |
| 439 | { | 439 | { |
| 440 | const char *tmp; | 440 | char *tmp; |
| 441 | struct perf_probe_arg_field **fieldp; | 441 | struct perf_probe_arg_field **fieldp; |
| 442 | 442 | ||
| 443 | pr_debug("parsing arg: %s into ", str); | 443 | pr_debug("parsing arg: %s into ", str); |
| 444 | 444 | ||
| 445 | tmp = strchr(str, '='); | ||
| 446 | if (tmp) { | ||
| 447 | arg->name = xstrndup(str, tmp - str); | ||
| 448 | str = tmp + 1; | ||
| 449 | } | ||
| 450 | |||
| 445 | tmp = strpbrk(str, "-."); | 451 | tmp = strpbrk(str, "-."); |
| 446 | if (!is_c_varname(str) || !tmp) { | 452 | if (!is_c_varname(str) || !tmp) { |
| 447 | /* A variable, register, symbol or special value */ | 453 | /* A variable, register, symbol or special value */ |
| 448 | arg->name = xstrdup(str); | 454 | arg->var = xstrdup(str); |
| 449 | pr_debug("%s\n", arg->name); | 455 | pr_debug("%s\n", arg->var); |
| 450 | return; | 456 | return; |
| 451 | } | 457 | } |
| 452 | 458 | ||
| 453 | /* Structure fields */ | 459 | /* Structure fields */ |
| 454 | arg->name = xstrndup(str, tmp - str); | 460 | arg->var = xstrndup(str, tmp - str); |
| 455 | pr_debug("%s, ", arg->name); | 461 | pr_debug("%s, ", arg->var); |
| 456 | fieldp = &arg->field; | 462 | fieldp = &arg->field; |
| 457 | 463 | ||
| 458 | do { | 464 | do { |
| @@ -497,7 +503,7 @@ void parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev) | |||
| 497 | pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs); | 503 | pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs); |
| 498 | for (i = 0; i < pev->nargs; i++) { | 504 | for (i = 0; i < pev->nargs; i++) { |
| 499 | parse_perf_probe_arg(argv[i + 1], &pev->args[i]); | 505 | parse_perf_probe_arg(argv[i + 1], &pev->args[i]); |
| 500 | if (is_c_varname(pev->args[i].name) && pev->point.retprobe) | 506 | if (is_c_varname(pev->args[i].var) && pev->point.retprobe) |
| 501 | semantic_error("You can't specify local variable for" | 507 | semantic_error("You can't specify local variable for" |
| 502 | " kretprobe"); | 508 | " kretprobe"); |
| 503 | } | 509 | } |
| @@ -514,7 +520,7 @@ bool perf_probe_event_need_dwarf(struct perf_probe_event *pev) | |||
| 514 | return true; | 520 | return true; |
| 515 | 521 | ||
| 516 | for (i = 0; i < pev->nargs; i++) | 522 | for (i = 0; i < pev->nargs; i++) |
| 517 | if (is_c_varname(pev->args[i].name)) | 523 | if (is_c_varname(pev->args[i].var)) |
| 518 | return true; | 524 | return true; |
| 519 | 525 | ||
| 520 | return false; | 526 | return false; |
| @@ -575,7 +581,10 @@ int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len) | |||
| 575 | int ret; | 581 | int ret; |
| 576 | char *tmp = buf; | 582 | char *tmp = buf; |
| 577 | 583 | ||
| 578 | ret = e_snprintf(tmp, len, "%s", pa->name); | 584 | if (pa->name && pa->var) |
| 585 | ret = e_snprintf(tmp, len, "%s=%s", pa->name, pa->var); | ||
| 586 | else | ||
| 587 | ret = e_snprintf(tmp, len, "%s", pa->name ? pa->name : pa->var); | ||
| 579 | if (ret <= 0) | 588 | if (ret <= 0) |
| 580 | goto error; | 589 | goto error; |
| 581 | tmp += ret; | 590 | tmp += ret; |
| @@ -803,6 +812,8 @@ void clear_perf_probe_event(struct perf_probe_event *pev) | |||
| 803 | for (i = 0; i < pev->nargs; i++) { | 812 | for (i = 0; i < pev->nargs; i++) { |
| 804 | if (pev->args[i].name) | 813 | if (pev->args[i].name) |
| 805 | free(pev->args[i].name); | 814 | free(pev->args[i].name); |
| 815 | if (pev->args[i].var) | ||
| 816 | free(pev->args[i].var); | ||
| 806 | field = pev->args[i].field; | 817 | field = pev->args[i].field; |
| 807 | while (field) { | 818 | while (field) { |
| 808 | next = field->next; | 819 | next = field->next; |
| @@ -1117,8 +1128,11 @@ static int convert_to_kprobe_trace_events(struct perf_probe_event *pev, | |||
| 1117 | if (tev->nargs) { | 1128 | if (tev->nargs) { |
| 1118 | tev->args = xzalloc(sizeof(struct kprobe_trace_arg) | 1129 | tev->args = xzalloc(sizeof(struct kprobe_trace_arg) |
| 1119 | * tev->nargs); | 1130 | * tev->nargs); |
| 1120 | for (i = 0; i < tev->nargs; i++) | 1131 | for (i = 0; i < tev->nargs; i++) { |
| 1121 | tev->args[i].value = xstrdup(pev->args[i].name); | 1132 | if (pev->args[i].name) |
| 1133 | tev->args[i].name = xstrdup(pev->args[i].name); | ||
| 1134 | tev->args[i].value = xstrdup(pev->args[i].var); | ||
| 1135 | } | ||
| 1122 | } | 1136 | } |
| 1123 | 1137 | ||
| 1124 | /* Currently just checking function name from symbol map */ | 1138 | /* Currently just checking function name from symbol map */ |
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 9d99fc24c4fc..10411f596321 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h | |||
| @@ -55,6 +55,7 @@ struct perf_probe_arg_field { | |||
| 55 | /* Perf probe probing argument */ | 55 | /* Perf probe probing argument */ |
| 56 | struct perf_probe_arg { | 56 | struct perf_probe_arg { |
| 57 | char *name; /* Argument name */ | 57 | char *name; /* Argument name */ |
| 58 | char *var; /* Variable name */ | ||
| 58 | struct perf_probe_arg_field *field; /* Structure fields */ | 59 | struct perf_probe_arg_field *field; /* Structure fields */ |
| 59 | }; | 60 | }; |
| 60 | 61 | ||
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index a8513772df08..105e95c95eeb 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
| @@ -484,35 +484,40 @@ static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) | |||
| 484 | convert_location(expr, pf); | 484 | convert_location(expr, pf); |
| 485 | 485 | ||
| 486 | if (pf->pvar->field) | 486 | if (pf->pvar->field) |
| 487 | convert_variable_fields(vr_die, pf->pvar->name, | 487 | convert_variable_fields(vr_die, pf->pvar->var, |
| 488 | pf->pvar->field, &pf->tvar->ref); | 488 | pf->pvar->field, &pf->tvar->ref); |
| 489 | /* *expr will be cached in libdw. Don't free it. */ | 489 | /* *expr will be cached in libdw. Don't free it. */ |
| 490 | return ; | 490 | return ; |
| 491 | error: | 491 | error: |
| 492 | /* TODO: Support const_value */ | 492 | /* TODO: Support const_value */ |
| 493 | die("Failed to find the location of %s at this address.\n" | 493 | die("Failed to find the location of %s at this address.\n" |
| 494 | " Perhaps, it has been optimized out.", pf->pvar->name); | 494 | " Perhaps, it has been optimized out.", pf->pvar->var); |
| 495 | } | 495 | } |
| 496 | 496 | ||
| 497 | /* Find a variable in a subprogram die */ | 497 | /* Find a variable in a subprogram die */ |
| 498 | static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) | 498 | static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) |
| 499 | { | 499 | { |
| 500 | Dwarf_Die vr_die; | 500 | Dwarf_Die vr_die; |
| 501 | char buf[128]; | 501 | char buf[32]; |
| 502 | 502 | ||
| 503 | /* TODO: Support struct members and arrays */ | 503 | /* TODO: Support arrays */ |
| 504 | if (!is_c_varname(pf->pvar->name)) { | 504 | if (pf->pvar->name) |
| 505 | pf->tvar->name = xstrdup(pf->pvar->name); | ||
| 506 | else { | ||
| 507 | synthesize_perf_probe_arg(pf->pvar, buf, 32); | ||
| 508 | pf->tvar->name = xstrdup(buf); | ||
| 509 | } | ||
| 510 | |||
| 511 | if (!is_c_varname(pf->pvar->var)) { | ||
| 505 | /* Copy raw parameters */ | 512 | /* Copy raw parameters */ |
| 506 | pf->tvar->value = xstrdup(pf->pvar->name); | 513 | pf->tvar->value = xstrdup(pf->pvar->var); |
| 507 | } else { | 514 | } else { |
| 508 | synthesize_perf_probe_arg(pf->pvar, buf, 128); | ||
| 509 | pf->tvar->name = xstrdup(buf); | ||
| 510 | pr_debug("Searching '%s' variable in context.\n", | 515 | pr_debug("Searching '%s' variable in context.\n", |
| 511 | pf->pvar->name); | 516 | pf->pvar->var); |
| 512 | /* Search child die for local variables and parameters. */ | 517 | /* Search child die for local variables and parameters. */ |
| 513 | if (!die_find_variable(sp_die, pf->pvar->name, &vr_die)) | 518 | if (!die_find_variable(sp_die, pf->pvar->var, &vr_die)) |
| 514 | die("Failed to find '%s' in this function.", | 519 | die("Failed to find '%s' in this function.", |
| 515 | pf->pvar->name); | 520 | pf->pvar->var); |
| 516 | convert_variable(&vr_die, pf); | 521 | convert_variable(&vr_die, pf); |
| 517 | } | 522 | } |
| 518 | } | 523 | } |
