From 638e2b9984ee1b8d485366f74d579467880283b4 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Sun, 27 Jun 2021 16:18:11 +0300 Subject: perf script: Add option to list dlfilters Add option --list-dlfilters to list dlfilters in the current directory or the exec-path e.g. ~/libexec/perf-core/dlfilters. Use with option -v (must come before option --list-dlfilters) to show long descriptions. Signed-off-by: Adrian Hunter Cc: Andi Kleen Cc: Ingo Molnar Cc: Jiri Olsa Cc: Kan Liang Cc: Leo Yan Cc: Mark Rutland Cc: Namhyung Kim Cc: Peter Zijlstra Link: https://lore.kernel.org/r/20210627131818.810-4-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/dlfilter.c | 117 +++++++++++++++++++++++++++++++++++++++- tools/perf/util/dlfilter.h | 2 + tools/perf/util/perf_dlfilter.h | 6 +++ 3 files changed, 124 insertions(+), 1 deletion(-) (limited to 'tools/perf/util') diff --git a/tools/perf/util/dlfilter.c b/tools/perf/util/dlfilter.c index e93c49c07999..288a2b57378c 100644 --- a/tools/perf/util/dlfilter.c +++ b/tools/perf/util/dlfilter.c @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include #include @@ -136,6 +138,35 @@ static const struct perf_dlfilter_fns perf_dlfilter_fns = { .resolve_addr = dlfilter__resolve_addr, }; +static char *find_dlfilter(const char *file) +{ + char path[PATH_MAX]; + char *exec_path; + + if (strchr(file, '/')) + goto out; + + if (!access(file, R_OK)) { + /* + * Prepend "./" so that dlopen will find the file in the + * current directory. + */ + snprintf(path, sizeof(path), "./%s", file); + file = path; + goto out; + } + + exec_path = get_argv_exec_path(); + if (!exec_path) + goto out; + snprintf(path, sizeof(path), "%s/dlfilters/%s", exec_path, file); + free(exec_path); + if (!access(path, R_OK)) + file = path; +out: + return strdup(file); +} + #define CHECK_FLAG(x) BUILD_BUG_ON((u64)PERF_DLFILTER_FLAG_ ## x != (u64)PERF_IP_FLAG_ ## x) static int dlfilter__init(struct dlfilter *d, const char *file) @@ -155,7 +186,7 @@ static int dlfilter__init(struct dlfilter *d, const char *file) CHECK_FLAG(VMEXIT); memset(d, 0, sizeof(*d)); - d->file = strdup(file); + d->file = find_dlfilter(file); if (!d->file) return -1; return 0; @@ -333,3 +364,87 @@ int dlfilter__do_filter_event(struct dlfilter *d, return ret; } + +static bool get_filter_desc(const char *dirname, const char *name, + char **desc, char **long_desc) +{ + char path[PATH_MAX]; + void *handle; + const char *(*desc_fn)(const char **long_description); + + snprintf(path, sizeof(path), "%s/%s", dirname, name); + handle = dlopen(path, RTLD_NOW); + if (!handle || !(dlsym(handle, "filter_event") || dlsym(handle, "filter_event_early"))) + return false; + desc_fn = dlsym(handle, "filter_description"); + if (desc_fn) { + const char *dsc; + const char *long_dsc; + + dsc = desc_fn(&long_dsc); + if (dsc) + *desc = strdup(dsc); + if (long_dsc) + *long_desc = strdup(long_dsc); + } + dlclose(handle); + return true; +} + +static void list_filters(const char *dirname) +{ + struct dirent *entry; + DIR *dir; + + dir = opendir(dirname); + if (!dir) + return; + + while ((entry = readdir(dir)) != NULL) + { + size_t n = strlen(entry->d_name); + char *long_desc = NULL; + char *desc = NULL; + + if (entry->d_type == DT_DIR || n < 4 || + strcmp(".so", entry->d_name + n - 3)) + continue; + if (!get_filter_desc(dirname, entry->d_name, &desc, &long_desc)) + continue; + printf(" %-36s %s\n", entry->d_name, desc ? desc : ""); + if (verbose) { + char *p = long_desc; + char *line; + + while ((line = strsep(&p, "\n")) != NULL) + printf("%39s%s\n", "", line); + } + free(long_desc); + free(desc); + } + + closedir(dir); +} + +int list_available_dlfilters(const struct option *opt __maybe_unused, + const char *s __maybe_unused, + int unset __maybe_unused) +{ + char path[PATH_MAX]; + char *exec_path; + + printf("List of available dlfilters:\n"); + + list_filters("."); + + exec_path = get_argv_exec_path(); + if (!exec_path) + goto out; + snprintf(path, sizeof(path), "%s/dlfilters", exec_path); + + list_filters(path); + + free(exec_path); +out: + exit(0); +} diff --git a/tools/perf/util/dlfilter.h b/tools/perf/util/dlfilter.h index a994560e563d..a1ed38da3ce6 100644 --- a/tools/perf/util/dlfilter.h +++ b/tools/perf/util/dlfilter.h @@ -88,4 +88,6 @@ static inline int dlfilter__filter_event_early(struct dlfilter *d, return dlfilter__do_filter_event(d, event, sample, evsel, machine, al, addr_al, true); } +int list_available_dlfilters(const struct option *opt, const char *s, int unset); + #endif diff --git a/tools/perf/util/perf_dlfilter.h b/tools/perf/util/perf_dlfilter.h index f7a847fdee59..31ad4c100181 100644 --- a/tools/perf/util/perf_dlfilter.h +++ b/tools/perf/util/perf_dlfilter.h @@ -126,4 +126,10 @@ int filter_event(void *data, const struct perf_dlfilter_sample *sample, void *ct */ int filter_event_early(void *data, const struct perf_dlfilter_sample *sample, void *ctx); +/* + * If implemented, return a one-line description of the filter, and optionally + * a longer description. + */ +const char *filter_description(const char **long_description); + #endif -- cgit v1.2.3-59-g8ed1b