Enhances -F/--funcs option of "perf probe" to list possible probe points in an executable file or library. A new option -e/--exe specifies the path of the executable or library. Show last 10 functions in /bin/zsh. # perf probe -F -u -e /bin/zsh | tail zstrtol ztrcmp ztrdup ztrduppfx ztrftime ztrlen ztrncpy ztrsub zwarn zwarnnam Show first 10 functions in /lib/libc.so.6 # perf probe -u -F -e /lib/libc.so.6 | head _IO_adjust_column _IO_adjust_wcolumn _IO_default_doallocate _IO_default_finish _IO_default_pbackfail _IO_default_uflow _IO_default_xsgetn _IO_default_xsputn _IO_do_write@@GLIBC_2.2.5 _IO_doallocbuf Signed-off-by: Srikar Dronamraju <srikar@xxxxxxxxxxxxxxxxxx> --- tools/perf/builtin-probe.c | 63 +++++++++++++++++++++++++++++++++++++---- tools/perf/util/probe-event.c | 56 ++++++++++++++++++++++++++++-------- tools/perf/util/probe-event.h | 4 +-- 3 files changed, 102 insertions(+), 21 deletions(-) diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index a90ee01..6aff85c 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -185,6 +185,55 @@ static int opt_set_filter(const struct option *opt __used, return 0; } +static int opt_set_executable(const struct option *opt __used, + const char *str, int unset __used) +{ + if (params.target || !str) + return -EINVAL; + + if (params.uprobes) { + pr_err(" Error: Don't use -m with --uprobes.\n"); + return -EINVAL; + } + + if (str) { + params.target = str; + params.uprobes = true; + } + return 0; +} + +#ifdef DWARF_SUPPORT +static int opt_set_module(const struct option *opt __used, + const char *str, int unset __used) +{ + if (params.target || !str) + return -EINVAL; + + if (params.uprobes) { + pr_err(" Error: Don't use -m with --uprobes.\n"); + return -EINVAL; + } + + if (str) + params.target = str; + + return 0; +} +#endif + +static int opt_set_uprobes(const struct option *opt __used, + const char *str __used, int unset __used) +{ + if (params.target) { + pr_err(" Error: Don't use --uprobes with -x/-m.\n"); + return -EINVAL; + } + + params.uprobes = true; + return 0; +} + static const char * const probe_usage[] = { "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]", "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", @@ -243,16 +292,18 @@ static const struct option options[] = { "file", "vmlinux pathname"), OPT_STRING('s', "source", &symbol_conf.source_prefix, "directory", "path to kernel source"), - OPT_STRING('m', "module", ¶ms.target, - "modname", "target module name"), + OPT_CALLBACK('m', "module", NULL, "modname", "target module name", + opt_set_module), #endif OPT__DRY_RUN(&probe_event_dry_run), OPT_INTEGER('\0', "max-probes", ¶ms.max_probe_points, "Set how many probe points can be found for a probe."), OPT_BOOLEAN('F', "funcs", ¶ms.show_funcs, "Show potential probe-able functions."), - OPT_BOOLEAN('u', "uprobes", ¶ms.uprobes, - "user space probe events"), + OPT_CALLBACK_NOOPT('u', "uprobes", NULL, NULL, + "user space probe events", opt_set_uprobes), + OPT_CALLBACK('x', "exe", NULL, "/path/to/absolute/relative/file", + "target executable name", opt_set_executable), OPT_CALLBACK('\0', "filter", NULL, "[!]FILTER", "Set a filter (with --vars/funcs only)\n" "\t\t\t(default: \"" DEFAULT_VAR_FILTER "\" for --vars,\n" @@ -335,8 +386,8 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) if (!params.filter) params.filter = strfilter__new(DEFAULT_FUNC_FILTER, NULL); - ret = show_available_funcs(params.target, - params.filter); + ret = show_available_funcs(params.target, params.filter, + params.uprobes); strfilter__delete(params.filter); if (ret < 0) pr_err(" Error: Failed to show functions." diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 30f9e2f..d45dfb1 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -47,6 +47,7 @@ #include "trace-event.h" /* For __unused */ #include "probe-event.h" #include "probe-finder.h" +#include "session.h" #define MAX_CMDLEN 256 #define MAX_PROBE_ARGS 128 @@ -2094,6 +2095,7 @@ error: } return ret; } + /* TODO: don't use a global variable for filter ... */ static struct strfilter *available_func_filter; @@ -2110,32 +2112,60 @@ static int filter_available_functions(struct map *map __unused, return 1; } -int show_available_funcs(const char *elfobject, struct strfilter *_filter) +static int __show_available_funcs(struct map *map) +{ + if (map__load(map, filter_available_functions)) { + pr_err("Failed to load map.\n"); + return -EINVAL; + } + if (!dso__sorted_by_name(map->dso, map->type)) + dso__sort_by_name(map->dso, map->type); + + dso__fprintf_symbols_by_name(map->dso, map->type, stdout); + return 0; +} + +static int available_kernel_funcs(const char *module) { struct map *map; int ret; - setup_pager(); - ret = init_vmlinux(); if (ret < 0) return ret; - map = kernel_get_module_map(elfobject); + map = kernel_get_module_map(module); if (!map) { - pr_err("Failed to find %s map.\n", (elfobject) ? : "kernel"); + pr_err("Failed to find %s map.\n", (module) ? : "kernel"); return -EINVAL; } + return __show_available_funcs(map); +} + +int show_available_funcs(const char *elfobject, struct strfilter *_filter, + bool user) +{ + struct map *map; + int ret; + + setup_pager(); available_func_filter = _filter; - if (map__load(map, filter_available_functions)) { - pr_err("Failed to load map.\n"); - return -EINVAL; - } - if (!dso__sorted_by_name(map->dso, map->type)) - dso__sort_by_name(map->dso, map->type); - dso__fprintf_symbols_by_name(map->dso, map->type, stdout); - return 0; + if (!user) + return available_kernel_funcs(elfobject); + + symbol_conf.try_vmlinux_path = false; + symbol_conf.sort_by_name = true; + ret = symbol__init(); + if (ret < 0) { + pr_err("Failed to init symbol map.\n"); + return ret; + } + map = dso__new_map(elfobject); + ret = __show_available_funcs(map); + dso__delete(map->dso); + map__delete(map); + return ret; } #define DEFAULT_FUNC_FILTER "!_*" diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 365e016..5199df4 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h @@ -130,8 +130,8 @@ extern int show_line_range(struct line_range *lr, const char *module); extern int show_available_vars(struct perf_probe_event *pevs, int npevs, int max_probe_points, const char *module, struct strfilter *filter, bool externs); -extern int show_available_funcs(const char *module, struct strfilter *filter); - +extern int show_available_funcs(const char *module, struct strfilter *filter, + bool user); /* Maximum index number of event-name postfix */ #define MAX_EVENT_INDEX 1024 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@xxxxxxxxxx For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href=mailto:"dont@xxxxxxxxx"> email@xxxxxxxxx </a>