diff options
Diffstat (limited to 'tools/perf/util/probe-event.c')
-rw-r--r-- | tools/perf/util/probe-event.c | 159 |
1 files changed, 126 insertions, 33 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 6e29d9c9dccc..5ddee66020a7 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <string.h> | 31 | #include <string.h> |
32 | #include <stdarg.h> | 32 | #include <stdarg.h> |
33 | #include <limits.h> | 33 | #include <limits.h> |
34 | #include <elf.h> | ||
34 | 35 | ||
35 | #undef _GNU_SOURCE | 36 | #undef _GNU_SOURCE |
36 | #include "util.h" | 37 | #include "util.h" |
@@ -111,7 +112,25 @@ static struct symbol *__find_kernel_function_by_name(const char *name, | |||
111 | NULL); | 112 | NULL); |
112 | } | 113 | } |
113 | 114 | ||
114 | const char *kernel_get_module_path(const char *module) | 115 | static struct map *kernel_get_module_map(const char *module) |
116 | { | ||
117 | struct rb_node *nd; | ||
118 | struct map_groups *grp = &machine.kmaps; | ||
119 | |||
120 | if (!module) | ||
121 | module = "kernel"; | ||
122 | |||
123 | for (nd = rb_first(&grp->maps[MAP__FUNCTION]); nd; nd = rb_next(nd)) { | ||
124 | struct map *pos = rb_entry(nd, struct map, rb_node); | ||
125 | if (strncmp(pos->dso->short_name + 1, module, | ||
126 | pos->dso->short_name_len - 2) == 0) { | ||
127 | return pos; | ||
128 | } | ||
129 | } | ||
130 | return NULL; | ||
131 | } | ||
132 | |||
133 | static struct dso *kernel_get_module_dso(const char *module) | ||
115 | { | 134 | { |
116 | struct dso *dso; | 135 | struct dso *dso; |
117 | struct map *map; | 136 | struct map *map; |
@@ -141,7 +160,13 @@ const char *kernel_get_module_path(const char *module) | |||
141 | } | 160 | } |
142 | } | 161 | } |
143 | found: | 162 | found: |
144 | return dso->long_name; | 163 | return dso; |
164 | } | ||
165 | |||
166 | const char *kernel_get_module_path(const char *module) | ||
167 | { | ||
168 | struct dso *dso = kernel_get_module_dso(module); | ||
169 | return (dso) ? dso->long_name : NULL; | ||
145 | } | 170 | } |
146 | 171 | ||
147 | #ifdef DWARF_SUPPORT | 172 | #ifdef DWARF_SUPPORT |
@@ -384,7 +409,7 @@ int show_line_range(struct line_range *lr, const char *module) | |||
384 | setup_pager(); | 409 | setup_pager(); |
385 | 410 | ||
386 | if (lr->function) | 411 | if (lr->function) |
387 | fprintf(stdout, "<%s:%d>\n", lr->function, | 412 | fprintf(stdout, "<%s@%s:%d>\n", lr->function, lr->path, |
388 | lr->start - lr->offset); | 413 | lr->start - lr->offset); |
389 | else | 414 | else |
390 | fprintf(stdout, "<%s:%d>\n", lr->path, lr->start); | 415 | fprintf(stdout, "<%s:%d>\n", lr->path, lr->start); |
@@ -426,12 +451,14 @@ end: | |||
426 | } | 451 | } |
427 | 452 | ||
428 | static int show_available_vars_at(int fd, struct perf_probe_event *pev, | 453 | static int show_available_vars_at(int fd, struct perf_probe_event *pev, |
429 | int max_vls, bool externs) | 454 | int max_vls, struct strfilter *_filter, |
455 | bool externs) | ||
430 | { | 456 | { |
431 | char *buf; | 457 | char *buf; |
432 | int ret, i; | 458 | int ret, i, nvars; |
433 | struct str_node *node; | 459 | struct str_node *node; |
434 | struct variable_list *vls = NULL, *vl; | 460 | struct variable_list *vls = NULL, *vl; |
461 | const char *var; | ||
435 | 462 | ||
436 | buf = synthesize_perf_probe_point(&pev->point); | 463 | buf = synthesize_perf_probe_point(&pev->point); |
437 | if (!buf) | 464 | if (!buf) |
@@ -439,36 +466,45 @@ static int show_available_vars_at(int fd, struct perf_probe_event *pev, | |||
439 | pr_debug("Searching variables at %s\n", buf); | 466 | pr_debug("Searching variables at %s\n", buf); |
440 | 467 | ||
441 | ret = find_available_vars_at(fd, pev, &vls, max_vls, externs); | 468 | ret = find_available_vars_at(fd, pev, &vls, max_vls, externs); |
442 | if (ret > 0) { | 469 | if (ret <= 0) { |
443 | /* Some variables were found */ | 470 | pr_err("Failed to find variables at %s (%d)\n", buf, ret); |
444 | fprintf(stdout, "Available variables at %s\n", buf); | 471 | goto end; |
445 | for (i = 0; i < ret; i++) { | 472 | } |
446 | vl = &vls[i]; | 473 | /* Some variables are found */ |
447 | /* | 474 | fprintf(stdout, "Available variables at %s\n", buf); |
448 | * A probe point might be converted to | 475 | for (i = 0; i < ret; i++) { |
449 | * several trace points. | 476 | vl = &vls[i]; |
450 | */ | 477 | /* |
451 | fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, | 478 | * A probe point might be converted to |
452 | vl->point.offset); | 479 | * several trace points. |
453 | free(vl->point.symbol); | 480 | */ |
454 | if (vl->vars) { | 481 | fprintf(stdout, "\t@<%s+%lu>\n", vl->point.symbol, |
455 | strlist__for_each(node, vl->vars) | 482 | vl->point.offset); |
483 | free(vl->point.symbol); | ||
484 | nvars = 0; | ||
485 | if (vl->vars) { | ||
486 | strlist__for_each(node, vl->vars) { | ||
487 | var = strchr(node->s, '\t') + 1; | ||
488 | if (strfilter__compare(_filter, var)) { | ||
456 | fprintf(stdout, "\t\t%s\n", node->s); | 489 | fprintf(stdout, "\t\t%s\n", node->s); |
457 | strlist__delete(vl->vars); | 490 | nvars++; |
458 | } else | 491 | } |
459 | fprintf(stdout, "(No variables)\n"); | 492 | } |
493 | strlist__delete(vl->vars); | ||
460 | } | 494 | } |
461 | free(vls); | 495 | if (nvars == 0) |
462 | } else | 496 | fprintf(stdout, "\t\t(No matched variables)\n"); |
463 | pr_err("Failed to find variables at %s (%d)\n", buf, ret); | 497 | } |
464 | 498 | free(vls); | |
499 | end: | ||
465 | free(buf); | 500 | free(buf); |
466 | return ret; | 501 | return ret; |
467 | } | 502 | } |
468 | 503 | ||
469 | /* Show available variables on given probe point */ | 504 | /* Show available variables on given probe point */ |
470 | int show_available_vars(struct perf_probe_event *pevs, int npevs, | 505 | int show_available_vars(struct perf_probe_event *pevs, int npevs, |
471 | int max_vls, const char *module, bool externs) | 506 | int max_vls, const char *module, |
507 | struct strfilter *_filter, bool externs) | ||
472 | { | 508 | { |
473 | int i, fd, ret = 0; | 509 | int i, fd, ret = 0; |
474 | 510 | ||
@@ -485,7 +521,8 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs, | |||
485 | setup_pager(); | 521 | setup_pager(); |
486 | 522 | ||
487 | for (i = 0; i < npevs && ret >= 0; i++) | 523 | for (i = 0; i < npevs && ret >= 0; i++) |
488 | ret = show_available_vars_at(fd, &pevs[i], max_vls, externs); | 524 | ret = show_available_vars_at(fd, &pevs[i], max_vls, _filter, |
525 | externs); | ||
489 | 526 | ||
490 | close(fd); | 527 | close(fd); |
491 | return ret; | 528 | return ret; |
@@ -531,7 +568,9 @@ int show_line_range(struct line_range *lr __unused, const char *module __unused) | |||
531 | 568 | ||
532 | int show_available_vars(struct perf_probe_event *pevs __unused, | 569 | int show_available_vars(struct perf_probe_event *pevs __unused, |
533 | int npevs __unused, int max_vls __unused, | 570 | int npevs __unused, int max_vls __unused, |
534 | const char *module __unused, bool externs __unused) | 571 | const char *module __unused, |
572 | struct strfilter *filter __unused, | ||
573 | bool externs __unused) | ||
535 | { | 574 | { |
536 | pr_warning("Debuginfo-analysis is not supported.\n"); | 575 | pr_warning("Debuginfo-analysis is not supported.\n"); |
537 | return -ENOSYS; | 576 | return -ENOSYS; |
@@ -556,11 +595,11 @@ static int parse_line_num(char **ptr, int *val, const char *what) | |||
556 | * The line range syntax is described by: | 595 | * The line range syntax is described by: |
557 | * | 596 | * |
558 | * SRC[:SLN[+NUM|-ELN]] | 597 | * SRC[:SLN[+NUM|-ELN]] |
559 | * FNC[:SLN[+NUM|-ELN]] | 598 | * FNC[@SRC][:SLN[+NUM|-ELN]] |
560 | */ | 599 | */ |
561 | int parse_line_range_desc(const char *arg, struct line_range *lr) | 600 | int parse_line_range_desc(const char *arg, struct line_range *lr) |
562 | { | 601 | { |
563 | char *range, *name = strdup(arg); | 602 | char *range, *file, *name = strdup(arg); |
564 | int err; | 603 | int err; |
565 | 604 | ||
566 | if (!name) | 605 | if (!name) |
@@ -610,7 +649,16 @@ int parse_line_range_desc(const char *arg, struct line_range *lr) | |||
610 | } | 649 | } |
611 | } | 650 | } |
612 | 651 | ||
613 | if (strchr(name, '.')) | 652 | file = strchr(name, '@'); |
653 | if (file) { | ||
654 | *file = '\0'; | ||
655 | lr->file = strdup(++file); | ||
656 | if (lr->file == NULL) { | ||
657 | err = -ENOMEM; | ||
658 | goto err; | ||
659 | } | ||
660 | lr->function = name; | ||
661 | } else if (strchr(name, '.')) | ||
614 | lr->file = name; | 662 | lr->file = name; |
615 | else | 663 | else |
616 | lr->function = name; | 664 | lr->function = name; |
@@ -1784,9 +1832,12 @@ int add_perf_probe_events(struct perf_probe_event *pevs, int npevs, | |||
1784 | } | 1832 | } |
1785 | 1833 | ||
1786 | /* Loop 2: add all events */ | 1834 | /* Loop 2: add all events */ |
1787 | for (i = 0; i < npevs && ret >= 0; i++) | 1835 | for (i = 0; i < npevs; i++) { |
1788 | ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs, | 1836 | ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs, |
1789 | pkgs[i].ntevs, force_add); | 1837 | pkgs[i].ntevs, force_add); |
1838 | if (ret < 0) | ||
1839 | break; | ||
1840 | } | ||
1790 | end: | 1841 | end: |
1791 | /* Loop 3: cleanup and free trace events */ | 1842 | /* Loop 3: cleanup and free trace events */ |
1792 | for (i = 0; i < npevs; i++) { | 1843 | for (i = 0; i < npevs; i++) { |
@@ -1912,4 +1963,46 @@ int del_perf_probe_events(struct strlist *dellist) | |||
1912 | 1963 | ||
1913 | return ret; | 1964 | return ret; |
1914 | } | 1965 | } |
1966 | /* TODO: don't use a global variable for filter ... */ | ||
1967 | static struct strfilter *available_func_filter; | ||
1968 | |||
1969 | /* | ||
1970 | * If a symbol corresponds to a function with global binding and | ||
1971 | * matches filter return 0. For all others return 1. | ||
1972 | */ | ||
1973 | static int filter_available_functions(struct map *map __unused, | ||
1974 | struct symbol *sym) | ||
1975 | { | ||
1976 | if (sym->binding == STB_GLOBAL && | ||
1977 | strfilter__compare(available_func_filter, sym->name)) | ||
1978 | return 0; | ||
1979 | return 1; | ||
1980 | } | ||
1981 | |||
1982 | int show_available_funcs(const char *module, struct strfilter *_filter) | ||
1983 | { | ||
1984 | struct map *map; | ||
1985 | int ret; | ||
1986 | |||
1987 | setup_pager(); | ||
1988 | |||
1989 | ret = init_vmlinux(); | ||
1990 | if (ret < 0) | ||
1991 | return ret; | ||
1915 | 1992 | ||
1993 | map = kernel_get_module_map(module); | ||
1994 | if (!map) { | ||
1995 | pr_err("Failed to find %s map.\n", (module) ? : "kernel"); | ||
1996 | return -EINVAL; | ||
1997 | } | ||
1998 | available_func_filter = _filter; | ||
1999 | if (map__load(map, filter_available_functions)) { | ||
2000 | pr_err("Failed to load map.\n"); | ||
2001 | return -EINVAL; | ||
2002 | } | ||
2003 | if (!dso__sorted_by_name(map->dso, map->type)) | ||
2004 | dso__sort_by_name(map->dso, map->type); | ||
2005 | |||
2006 | dso__fprintf_symbols_by_name(map->dso, map->type, stdout); | ||
2007 | return 0; | ||
2008 | } | ||