diff options
Diffstat (limited to 'tools/perf/util/probe-event.c')
-rw-r--r-- | tools/perf/util/probe-event.c | 249 |
1 files changed, 151 insertions, 98 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 3b6a5297bf16..128aaab0aeda 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -95,7 +95,7 @@ static int init_vmlinux(void) | |||
95 | goto out; | 95 | goto out; |
96 | 96 | ||
97 | if (machine__create_kernel_maps(&machine) < 0) { | 97 | if (machine__create_kernel_maps(&machine) < 0) { |
98 | pr_debug("machine__create_kernel_maps "); | 98 | pr_debug("machine__create_kernel_maps() failed.\n"); |
99 | goto out; | 99 | goto out; |
100 | } | 100 | } |
101 | out: | 101 | out: |
@@ -114,6 +114,8 @@ static struct symbol *__find_kernel_function_by_name(const char *name, | |||
114 | const char *kernel_get_module_path(const char *module) | 114 | const char *kernel_get_module_path(const char *module) |
115 | { | 115 | { |
116 | struct dso *dso; | 116 | struct dso *dso; |
117 | struct map *map; | ||
118 | const char *vmlinux_name; | ||
117 | 119 | ||
118 | if (module) { | 120 | if (module) { |
119 | list_for_each_entry(dso, &machine.kernel_dsos, node) { | 121 | list_for_each_entry(dso, &machine.kernel_dsos, node) { |
@@ -123,10 +125,17 @@ const char *kernel_get_module_path(const char *module) | |||
123 | } | 125 | } |
124 | pr_debug("Failed to find module %s.\n", module); | 126 | pr_debug("Failed to find module %s.\n", module); |
125 | return NULL; | 127 | return NULL; |
128 | } | ||
129 | |||
130 | map = machine.vmlinux_maps[MAP__FUNCTION]; | ||
131 | dso = map->dso; | ||
132 | |||
133 | vmlinux_name = symbol_conf.vmlinux_name; | ||
134 | if (vmlinux_name) { | ||
135 | if (dso__load_vmlinux(dso, map, vmlinux_name, NULL) <= 0) | ||
136 | return NULL; | ||
126 | } else { | 137 | } else { |
127 | dso = machine.vmlinux_maps[MAP__FUNCTION]->dso; | 138 | if (dso__load_vmlinux_path(dso, map, NULL) <= 0) { |
128 | if (dso__load_vmlinux_path(dso, | ||
129 | machine.vmlinux_maps[MAP__FUNCTION], NULL) < 0) { | ||
130 | pr_debug("Failed to load kernel map.\n"); | 139 | pr_debug("Failed to load kernel map.\n"); |
131 | return NULL; | 140 | return NULL; |
132 | } | 141 | } |
@@ -140,7 +149,8 @@ static int open_vmlinux(const char *module) | |||
140 | { | 149 | { |
141 | const char *path = kernel_get_module_path(module); | 150 | const char *path = kernel_get_module_path(module); |
142 | if (!path) { | 151 | if (!path) { |
143 | pr_err("Failed to find path of %s module", module ?: "kernel"); | 152 | pr_err("Failed to find path of %s module.\n", |
153 | module ?: "kernel"); | ||
144 | return -ENOENT; | 154 | return -ENOENT; |
145 | } | 155 | } |
146 | pr_debug("Try to open %s\n", path); | 156 | pr_debug("Try to open %s\n", path); |
@@ -217,7 +227,7 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | |||
217 | pr_warning("Warning: No dwarf info found in the vmlinux - " | 227 | pr_warning("Warning: No dwarf info found in the vmlinux - " |
218 | "please rebuild kernel with CONFIG_DEBUG_INFO=y.\n"); | 228 | "please rebuild kernel with CONFIG_DEBUG_INFO=y.\n"); |
219 | if (!need_dwarf) { | 229 | if (!need_dwarf) { |
220 | pr_debug("Trying to use symbols.\nn"); | 230 | pr_debug("Trying to use symbols.\n"); |
221 | return 0; | 231 | return 0; |
222 | } | 232 | } |
223 | } | 233 | } |
@@ -286,42 +296,49 @@ static int get_real_path(const char *raw_path, const char *comp_dir, | |||
286 | #define LINEBUF_SIZE 256 | 296 | #define LINEBUF_SIZE 256 |
287 | #define NR_ADDITIONAL_LINES 2 | 297 | #define NR_ADDITIONAL_LINES 2 |
288 | 298 | ||
289 | static int show_one_line(FILE *fp, int l, bool skip, bool show_num) | 299 | static int __show_one_line(FILE *fp, int l, bool skip, bool show_num) |
290 | { | 300 | { |
291 | char buf[LINEBUF_SIZE]; | 301 | char buf[LINEBUF_SIZE]; |
292 | const char *color = PERF_COLOR_BLUE; | 302 | const char *color = show_num ? "" : PERF_COLOR_BLUE; |
293 | 303 | const char *prefix = NULL; | |
294 | if (fgets(buf, LINEBUF_SIZE, fp) == NULL) | ||
295 | goto error; | ||
296 | if (!skip) { | ||
297 | if (show_num) | ||
298 | fprintf(stdout, "%7d %s", l, buf); | ||
299 | else | ||
300 | color_fprintf(stdout, color, " %s", buf); | ||
301 | } | ||
302 | 304 | ||
303 | while (strlen(buf) == LINEBUF_SIZE - 1 && | 305 | do { |
304 | buf[LINEBUF_SIZE - 2] != '\n') { | ||
305 | if (fgets(buf, LINEBUF_SIZE, fp) == NULL) | 306 | if (fgets(buf, LINEBUF_SIZE, fp) == NULL) |
306 | goto error; | 307 | goto error; |
307 | if (!skip) { | 308 | if (skip) |
308 | if (show_num) | 309 | continue; |
309 | fprintf(stdout, "%s", buf); | 310 | if (!prefix) { |
310 | else | 311 | prefix = show_num ? "%7d " : " "; |
311 | color_fprintf(stdout, color, "%s", buf); | 312 | color_fprintf(stdout, color, prefix, l); |
312 | } | 313 | } |
313 | } | 314 | color_fprintf(stdout, color, "%s", buf); |
314 | 315 | ||
315 | return 0; | 316 | } while (strchr(buf, '\n') == NULL); |
317 | |||
318 | return 1; | ||
316 | error: | 319 | error: |
317 | if (feof(fp)) | 320 | if (ferror(fp)) { |
318 | pr_warning("Source file is shorter than expected.\n"); | ||
319 | else | ||
320 | pr_warning("File read error: %s\n", strerror(errno)); | 321 | pr_warning("File read error: %s\n", strerror(errno)); |
322 | return -1; | ||
323 | } | ||
324 | return 0; | ||
325 | } | ||
321 | 326 | ||
322 | return -1; | 327 | static int _show_one_line(FILE *fp, int l, bool skip, bool show_num) |
328 | { | ||
329 | int rv = __show_one_line(fp, l, skip, show_num); | ||
330 | if (rv == 0) { | ||
331 | pr_warning("Source file is shorter than expected.\n"); | ||
332 | rv = -1; | ||
333 | } | ||
334 | return rv; | ||
323 | } | 335 | } |
324 | 336 | ||
337 | #define show_one_line_with_num(f,l) _show_one_line(f,l,false,true) | ||
338 | #define show_one_line(f,l) _show_one_line(f,l,false,false) | ||
339 | #define skip_one_line(f,l) _show_one_line(f,l,true,false) | ||
340 | #define show_one_line_or_eof(f,l) __show_one_line(f,l,false,false) | ||
341 | |||
325 | /* | 342 | /* |
326 | * Show line-range always requires debuginfo to find source file and | 343 | * Show line-range always requires debuginfo to find source file and |
327 | * line number. | 344 | * line number. |
@@ -370,7 +387,7 @@ int show_line_range(struct line_range *lr, const char *module) | |||
370 | fprintf(stdout, "<%s:%d>\n", lr->function, | 387 | fprintf(stdout, "<%s:%d>\n", lr->function, |
371 | lr->start - lr->offset); | 388 | lr->start - lr->offset); |
372 | else | 389 | else |
373 | fprintf(stdout, "<%s:%d>\n", lr->file, lr->start); | 390 | fprintf(stdout, "<%s:%d>\n", lr->path, lr->start); |
374 | 391 | ||
375 | fp = fopen(lr->path, "r"); | 392 | fp = fopen(lr->path, "r"); |
376 | if (fp == NULL) { | 393 | if (fp == NULL) { |
@@ -379,26 +396,30 @@ int show_line_range(struct line_range *lr, const char *module) | |||
379 | return -errno; | 396 | return -errno; |
380 | } | 397 | } |
381 | /* Skip to starting line number */ | 398 | /* Skip to starting line number */ |
382 | while (l < lr->start && ret >= 0) | 399 | while (l < lr->start) { |
383 | ret = show_one_line(fp, l++, true, false); | 400 | ret = skip_one_line(fp, l++); |
384 | if (ret < 0) | 401 | if (ret < 0) |
385 | goto end; | 402 | goto end; |
403 | } | ||
386 | 404 | ||
387 | list_for_each_entry(ln, &lr->line_list, list) { | 405 | list_for_each_entry(ln, &lr->line_list, list) { |
388 | while (ln->line > l && ret >= 0) | 406 | for (; ln->line > l; l++) { |
389 | ret = show_one_line(fp, (l++) - lr->offset, | 407 | ret = show_one_line(fp, l - lr->offset); |
390 | false, false); | 408 | if (ret < 0) |
391 | if (ret >= 0) | 409 | goto end; |
392 | ret = show_one_line(fp, (l++) - lr->offset, | 410 | } |
393 | false, true); | 411 | ret = show_one_line_with_num(fp, l++ - lr->offset); |
394 | if (ret < 0) | 412 | if (ret < 0) |
395 | goto end; | 413 | goto end; |
396 | } | 414 | } |
397 | 415 | ||
398 | if (lr->end == INT_MAX) | 416 | if (lr->end == INT_MAX) |
399 | lr->end = l + NR_ADDITIONAL_LINES; | 417 | lr->end = l + NR_ADDITIONAL_LINES; |
400 | while (l <= lr->end && !feof(fp) && ret >= 0) | 418 | while (l <= lr->end) { |
401 | ret = show_one_line(fp, (l++) - lr->offset, false, false); | 419 | ret = show_one_line_or_eof(fp, l++ - lr->offset); |
420 | if (ret <= 0) | ||
421 | break; | ||
422 | } | ||
402 | end: | 423 | end: |
403 | fclose(fp); | 424 | fclose(fp); |
404 | return ret; | 425 | return ret; |
@@ -457,7 +478,7 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs, | |||
457 | 478 | ||
458 | fd = open_vmlinux(module); | 479 | fd = open_vmlinux(module); |
459 | if (fd < 0) { | 480 | if (fd < 0) { |
460 | pr_warning("Failed to open debuginfo file.\n"); | 481 | pr_warning("Failed to open debug information file.\n"); |
461 | return fd; | 482 | return fd; |
462 | } | 483 | } |
463 | 484 | ||
@@ -517,56 +538,87 @@ int show_available_vars(struct perf_probe_event *pevs __unused, | |||
517 | } | 538 | } |
518 | #endif | 539 | #endif |
519 | 540 | ||
541 | static int parse_line_num(char **ptr, int *val, const char *what) | ||
542 | { | ||
543 | const char *start = *ptr; | ||
544 | |||
545 | errno = 0; | ||
546 | *val = strtol(*ptr, ptr, 0); | ||
547 | if (errno || *ptr == start) { | ||
548 | semantic_error("'%s' is not a valid number.\n", what); | ||
549 | return -EINVAL; | ||
550 | } | ||
551 | return 0; | ||
552 | } | ||
553 | |||
554 | /* | ||
555 | * Stuff 'lr' according to the line range described by 'arg'. | ||
556 | * The line range syntax is described by: | ||
557 | * | ||
558 | * SRC[:SLN[+NUM|-ELN]] | ||
559 | * FNC[:SLN[+NUM|-ELN]] | ||
560 | */ | ||
520 | int parse_line_range_desc(const char *arg, struct line_range *lr) | 561 | int parse_line_range_desc(const char *arg, struct line_range *lr) |
521 | { | 562 | { |
522 | const char *ptr; | 563 | char *range, *name = strdup(arg); |
523 | char *tmp; | 564 | int err; |
524 | /* | 565 | |
525 | * <Syntax> | 566 | if (!name) |
526 | * SRC:SLN[+NUM|-ELN] | 567 | return -ENOMEM; |
527 | * FUNC[:SLN[+NUM|-ELN]] | 568 | |
528 | */ | 569 | lr->start = 0; |
529 | ptr = strchr(arg, ':'); | 570 | lr->end = INT_MAX; |
530 | if (ptr) { | 571 | |
531 | lr->start = (int)strtoul(ptr + 1, &tmp, 0); | 572 | range = strchr(name, ':'); |
532 | if (*tmp == '+') { | 573 | if (range) { |
533 | lr->end = lr->start + (int)strtoul(tmp + 1, &tmp, 0); | 574 | *range++ = '\0'; |
534 | lr->end--; /* | 575 | |
535 | * Adjust the number of lines here. | 576 | err = parse_line_num(&range, &lr->start, "start line"); |
536 | * If the number of lines == 1, the | 577 | if (err) |
537 | * the end of line should be equal to | 578 | goto err; |
538 | * the start of line. | 579 | |
539 | */ | 580 | if (*range == '+' || *range == '-') { |
540 | } else if (*tmp == '-') | 581 | const char c = *range++; |
541 | lr->end = (int)strtoul(tmp + 1, &tmp, 0); | 582 | |
542 | else | 583 | err = parse_line_num(&range, &lr->end, "end line"); |
543 | lr->end = INT_MAX; | 584 | if (err) |
585 | goto err; | ||
586 | |||
587 | if (c == '+') { | ||
588 | lr->end += lr->start; | ||
589 | /* | ||
590 | * Adjust the number of lines here. | ||
591 | * If the number of lines == 1, the | ||
592 | * the end of line should be equal to | ||
593 | * the start of line. | ||
594 | */ | ||
595 | lr->end--; | ||
596 | } | ||
597 | } | ||
598 | |||
544 | pr_debug("Line range is %d to %d\n", lr->start, lr->end); | 599 | pr_debug("Line range is %d to %d\n", lr->start, lr->end); |
600 | |||
601 | err = -EINVAL; | ||
545 | if (lr->start > lr->end) { | 602 | if (lr->start > lr->end) { |
546 | semantic_error("Start line must be smaller" | 603 | semantic_error("Start line must be smaller" |
547 | " than end line.\n"); | 604 | " than end line.\n"); |
548 | return -EINVAL; | 605 | goto err; |
549 | } | 606 | } |
550 | if (*tmp != '\0') { | 607 | if (*range != '\0') { |
551 | semantic_error("Tailing with invalid character '%d'.\n", | 608 | semantic_error("Tailing with invalid str '%s'.\n", range); |
552 | *tmp); | 609 | goto err; |
553 | return -EINVAL; | ||
554 | } | 610 | } |
555 | tmp = strndup(arg, (ptr - arg)); | ||
556 | } else { | ||
557 | tmp = strdup(arg); | ||
558 | lr->end = INT_MAX; | ||
559 | } | 611 | } |
560 | 612 | ||
561 | if (tmp == NULL) | 613 | if (strchr(name, '.')) |
562 | return -ENOMEM; | 614 | lr->file = name; |
563 | |||
564 | if (strchr(tmp, '.')) | ||
565 | lr->file = tmp; | ||
566 | else | 615 | else |
567 | lr->function = tmp; | 616 | lr->function = name; |
568 | 617 | ||
569 | return 0; | 618 | return 0; |
619 | err: | ||
620 | free(name); | ||
621 | return err; | ||
570 | } | 622 | } |
571 | 623 | ||
572 | /* Check the name is good for event/group */ | 624 | /* Check the name is good for event/group */ |
@@ -690,39 +742,40 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev) | |||
690 | 742 | ||
691 | /* Exclusion check */ | 743 | /* Exclusion check */ |
692 | if (pp->lazy_line && pp->line) { | 744 | if (pp->lazy_line && pp->line) { |
693 | semantic_error("Lazy pattern can't be used with line number."); | 745 | semantic_error("Lazy pattern can't be used with" |
746 | " line number.\n"); | ||
694 | return -EINVAL; | 747 | return -EINVAL; |
695 | } | 748 | } |
696 | 749 | ||
697 | if (pp->lazy_line && pp->offset) { | 750 | if (pp->lazy_line && pp->offset) { |
698 | semantic_error("Lazy pattern can't be used with offset."); | 751 | semantic_error("Lazy pattern can't be used with offset.\n"); |
699 | return -EINVAL; | 752 | return -EINVAL; |
700 | } | 753 | } |
701 | 754 | ||
702 | if (pp->line && pp->offset) { | 755 | if (pp->line && pp->offset) { |
703 | semantic_error("Offset can't be used with line number."); | 756 | semantic_error("Offset can't be used with line number.\n"); |
704 | return -EINVAL; | 757 | return -EINVAL; |
705 | } | 758 | } |
706 | 759 | ||
707 | if (!pp->line && !pp->lazy_line && pp->file && !pp->function) { | 760 | if (!pp->line && !pp->lazy_line && pp->file && !pp->function) { |
708 | semantic_error("File always requires line number or " | 761 | semantic_error("File always requires line number or " |
709 | "lazy pattern."); | 762 | "lazy pattern.\n"); |
710 | return -EINVAL; | 763 | return -EINVAL; |
711 | } | 764 | } |
712 | 765 | ||
713 | if (pp->offset && !pp->function) { | 766 | if (pp->offset && !pp->function) { |
714 | semantic_error("Offset requires an entry function."); | 767 | semantic_error("Offset requires an entry function.\n"); |
715 | return -EINVAL; | 768 | return -EINVAL; |
716 | } | 769 | } |
717 | 770 | ||
718 | if (pp->retprobe && !pp->function) { | 771 | if (pp->retprobe && !pp->function) { |
719 | semantic_error("Return probe requires an entry function."); | 772 | semantic_error("Return probe requires an entry function.\n"); |
720 | return -EINVAL; | 773 | return -EINVAL; |
721 | } | 774 | } |
722 | 775 | ||
723 | if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) { | 776 | if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe) { |
724 | semantic_error("Offset/Line/Lazy pattern can't be used with " | 777 | semantic_error("Offset/Line/Lazy pattern can't be used with " |
725 | "return probe."); | 778 | "return probe.\n"); |
726 | return -EINVAL; | 779 | return -EINVAL; |
727 | } | 780 | } |
728 | 781 | ||
@@ -996,7 +1049,7 @@ int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len) | |||
996 | 1049 | ||
997 | return tmp - buf; | 1050 | return tmp - buf; |
998 | error: | 1051 | error: |
999 | pr_debug("Failed to synthesize perf probe argument: %s", | 1052 | pr_debug("Failed to synthesize perf probe argument: %s\n", |
1000 | strerror(-ret)); | 1053 | strerror(-ret)); |
1001 | return ret; | 1054 | return ret; |
1002 | } | 1055 | } |
@@ -1024,13 +1077,13 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp) | |||
1024 | goto error; | 1077 | goto error; |
1025 | } | 1078 | } |
1026 | if (pp->file) { | 1079 | if (pp->file) { |
1027 | len = strlen(pp->file) - 31; | 1080 | tmp = pp->file; |
1028 | if (len < 0) | 1081 | len = strlen(tmp); |
1029 | len = 0; | 1082 | if (len > 30) { |
1030 | tmp = strchr(pp->file + len, '/'); | 1083 | tmp = strchr(pp->file + len - 30, '/'); |
1031 | if (!tmp) | 1084 | tmp = tmp ? tmp + 1 : pp->file + len - 30; |
1032 | tmp = pp->file + len; | 1085 | } |
1033 | ret = e_snprintf(file, 32, "@%s", tmp + 1); | 1086 | ret = e_snprintf(file, 32, "@%s", tmp); |
1034 | if (ret <= 0) | 1087 | if (ret <= 0) |
1035 | goto error; | 1088 | goto error; |
1036 | } | 1089 | } |
@@ -1046,7 +1099,7 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp) | |||
1046 | 1099 | ||
1047 | return buf; | 1100 | return buf; |
1048 | error: | 1101 | error: |
1049 | pr_debug("Failed to synthesize perf probe point: %s", | 1102 | pr_debug("Failed to synthesize perf probe point: %s\n", |
1050 | strerror(-ret)); | 1103 | strerror(-ret)); |
1051 | if (buf) | 1104 | if (buf) |
1052 | free(buf); | 1105 | free(buf); |
@@ -1787,7 +1840,7 @@ static int del_trace_probe_event(int fd, const char *group, | |||
1787 | 1840 | ||
1788 | ret = e_snprintf(buf, 128, "%s:%s", group, event); | 1841 | ret = e_snprintf(buf, 128, "%s:%s", group, event); |
1789 | if (ret < 0) { | 1842 | if (ret < 0) { |
1790 | pr_err("Failed to copy event."); | 1843 | pr_err("Failed to copy event.\n"); |
1791 | return ret; | 1844 | return ret; |
1792 | } | 1845 | } |
1793 | 1846 | ||