diff options
| author | Franck Bui-Huu <fbuihuu@gmail.com> | 2010-12-20 09:18:05 -0500 |
|---|---|---|
| committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2010-12-21 14:20:13 -0500 |
| commit | 21dd9ae5a4e9f717f3957ec934dd3158129436b8 (patch) | |
| tree | 817d9db270a3179f480eeac358d43c0c8655b361 /tools/perf | |
| parent | fde52dbd7f71934aba4e150f3d1d51e826a08850 (diff) | |
perf probe: Handle gracefully some stupid and buggy line syntaxes
Currently perf probe doesn't handle those incorrect syntaxes:
$ perf probe -L sched.c:++13
$ perf probe -L sched.c:-+13
$ perf probe -L sched.c:10000000000000000000000000000+13
This patches rewrites parse_line_range_desc() to handle them.
As a bonus, it reports more useful error messages instead of: "Tailing
with invalid character...".
Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
LKML-Reference: <1292854685-8230-7-git-send-email-fbuihuu@gmail.com>
Signed-off-by: Franck Bui-Huu <fbuihuu@gmail.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf')
| -rw-r--r-- | tools/perf/util/probe-event.c | 92 |
1 files changed, 60 insertions, 32 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 80cc0bc284fd..099336ed34b4 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
| @@ -529,6 +529,19 @@ int show_available_vars(struct perf_probe_event *pevs __unused, | |||
| 529 | } | 529 | } |
| 530 | #endif | 530 | #endif |
| 531 | 531 | ||
| 532 | static int parse_line_num(char **ptr, int *val, const char *what) | ||
| 533 | { | ||
| 534 | const char *start = *ptr; | ||
| 535 | |||
| 536 | errno = 0; | ||
| 537 | *val = strtol(*ptr, ptr, 0); | ||
| 538 | if (errno || *ptr == start) { | ||
| 539 | semantic_error("'%s' is not a valid number.\n", what); | ||
| 540 | return -EINVAL; | ||
| 541 | } | ||
| 542 | return 0; | ||
| 543 | } | ||
| 544 | |||
| 532 | /* | 545 | /* |
| 533 | * Stuff 'lr' according to the line range described by 'arg'. | 546 | * Stuff 'lr' according to the line range described by 'arg'. |
| 534 | * The line range syntax is described by: | 547 | * The line range syntax is described by: |
| @@ -538,50 +551,65 @@ int show_available_vars(struct perf_probe_event *pevs __unused, | |||
| 538 | */ | 551 | */ |
| 539 | int parse_line_range_desc(const char *arg, struct line_range *lr) | 552 | int parse_line_range_desc(const char *arg, struct line_range *lr) |
| 540 | { | 553 | { |
| 541 | const char *ptr; | 554 | char *range, *name = strdup(arg); |
| 542 | char *tmp; | 555 | int err; |
| 556 | |||
| 557 | if (!name) | ||
| 558 | return -ENOMEM; | ||
| 559 | |||
| 560 | lr->start = 0; | ||
| 561 | lr->end = INT_MAX; | ||
| 562 | |||
| 563 | range = strchr(name, ':'); | ||
| 564 | if (range) { | ||
| 565 | *range++ = '\0'; | ||
| 566 | |||
| 567 | err = parse_line_num(&range, &lr->start, "start line"); | ||
| 568 | if (err) | ||
| 569 | goto err; | ||
| 570 | |||
| 571 | if (*range == '+' || *range == '-') { | ||
| 572 | const char c = *range++; | ||
| 573 | |||
| 574 | err = parse_line_num(&range, &lr->end, "end line"); | ||
| 575 | if (err) | ||
| 576 | goto err; | ||
| 577 | |||
| 578 | if (c == '+') { | ||
| 579 | lr->end += lr->start; | ||
| 580 | /* | ||
| 581 | * Adjust the number of lines here. | ||
| 582 | * If the number of lines == 1, the | ||
| 583 | * the end of line should be equal to | ||
| 584 | * the start of line. | ||
| 585 | */ | ||
| 586 | lr->end--; | ||
| 587 | } | ||
| 588 | } | ||
| 543 | 589 | ||
| 544 | ptr = strchr(arg, ':'); | ||
| 545 | if (ptr) { | ||
| 546 | lr->start = (int)strtoul(ptr + 1, &tmp, 0); | ||
| 547 | if (*tmp == '+') { | ||
| 548 | lr->end = lr->start + (int)strtoul(tmp + 1, &tmp, 0); | ||
| 549 | lr->end--; /* | ||
| 550 | * Adjust the number of lines here. | ||
| 551 | * If the number of lines == 1, the | ||
| 552 | * the end of line should be equal to | ||
| 553 | * the start of line. | ||
| 554 | */ | ||
| 555 | } else if (*tmp == '-') | ||
| 556 | lr->end = (int)strtoul(tmp + 1, &tmp, 0); | ||
| 557 | else | ||
| 558 | lr->end = INT_MAX; | ||
| 559 | pr_debug("Line range is %d to %d\n", lr->start, lr->end); | 590 | pr_debug("Line range is %d to %d\n", lr->start, lr->end); |
| 591 | |||
| 592 | err = -EINVAL; | ||
| 560 | if (lr->start > lr->end) { | 593 | if (lr->start > lr->end) { |
| 561 | semantic_error("Start line must be smaller" | 594 | semantic_error("Start line must be smaller" |
| 562 | " than end line.\n"); | 595 | " than end line.\n"); |
| 563 | return -EINVAL; | 596 | goto err; |
| 564 | } | 597 | } |
| 565 | if (*tmp != '\0') { | 598 | if (*range != '\0') { |
| 566 | semantic_error("Tailing with invalid character '%d'.\n", | 599 | semantic_error("Tailing with invalid str '%s'.\n", range); |
| 567 | *tmp); | 600 | goto err; |
| 568 | return -EINVAL; | ||
| 569 | } | 601 | } |
| 570 | tmp = strndup(arg, (ptr - arg)); | ||
| 571 | } else { | ||
| 572 | tmp = strdup(arg); | ||
| 573 | lr->end = INT_MAX; | ||
| 574 | } | 602 | } |
| 575 | 603 | ||
| 576 | if (tmp == NULL) | 604 | if (strchr(name, '.')) |
| 577 | return -ENOMEM; | 605 | lr->file = name; |
| 578 | |||
| 579 | if (strchr(tmp, '.')) | ||
| 580 | lr->file = tmp; | ||
| 581 | else | 606 | else |
| 582 | lr->function = tmp; | 607 | lr->function = name; |
| 583 | 608 | ||
| 584 | return 0; | 609 | return 0; |
| 610 | err: | ||
| 611 | free(name); | ||
| 612 | return err; | ||
| 585 | } | 613 | } |
| 586 | 614 | ||
| 587 | /* Check the name is good for event/group */ | 615 | /* Check the name is good for event/group */ |
