From 3d032a251605740b75decd3381dc9d496a245ca0 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Sun, 27 Jun 2021 16:18:12 +0300 Subject: [PATCH] perf script: Add option to pass arguments to dlfilters Add option --dlarg to pass arguments to dlfilters. The --dlarg option can be repeated to pass more than 1 argument. 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-5-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-dlfilter.txt | 10 +++++-- tools/perf/Documentation/perf-script.txt | 4 +++ tools/perf/builtin-script.c | 35 ++++++++++++++++++++++- tools/perf/util/dlfilter.c | 45 +++++++++++++++++++++++++----- tools/perf/util/dlfilter.h | 6 +++- tools/perf/util/perf_dlfilter.h | 4 ++- 6 files changed, 91 insertions(+), 13 deletions(-) diff --git a/tools/perf/Documentation/perf-dlfilter.txt b/tools/perf/Documentation/perf-dlfilter.txt index 8bc219f..5795ab3 100644 --- a/tools/perf/Documentation/perf-dlfilter.txt +++ b/tools/perf/Documentation/perf-dlfilter.txt @@ -9,13 +9,14 @@ object file SYNOPSIS -------- [verse] -'perf script' [--dlfilter file.so ] +'perf script' [--dlfilter file.so ] [ --dlarg arg ]... DESCRIPTION ----------- This option is used to process data through a custom filter provided by a -dynamically loaded shared object file. +dynamically loaded shared object file. Arguments can be passed using --dlarg +and retrieved using perf_dlfilter_fns.args(). If 'file.so' does not contain "/", then it will be found either in the current directory, or perf tools exec path which is ~/libexec/perf-core/dlfilters for @@ -121,7 +122,8 @@ file is loaded. The functions can be called by 'filter_event' or struct perf_dlfilter_fns { const struct perf_dlfilter_al *(*resolve_ip)(void *ctx); const struct perf_dlfilter_al *(*resolve_addr)(void *ctx); - void *(*reserved[126])(void *); + char **(*args)(void *ctx, int *dlargc); + void *(*reserved[125])(void *); }; ---- @@ -129,6 +131,8 @@ struct perf_dlfilter_fns { 'resolve_addr' returns information about addr (if addr_correlates_sym). +'args' returns arguments from --dlarg options. + The perf_dlfilter_al structure ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index d2705d6..aa3a0b2 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt @@ -102,6 +102,10 @@ OPTIONS Filter sample events using the given shared object file. Refer linkperf:perf-dlfilter[1] +--dlarg=:: + Pass 'arg' as an argument to the dlfilter. --dlarg may be repeated + to add more arguments. + --list-dlfilters=:: Display a list of available dlfilters. Use with option -v (must come before option --list-dlfilters) to show long descriptions. diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 4ffba1d..2030936 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -81,6 +81,8 @@ static struct perf_stat_config stat_config; static int max_blocks; static bool native_arch; static struct dlfilter *dlfilter; +static int dlargc; +static char **dlargv; unsigned int scripting_max_stack = PERF_MAX_STACK_DEPTH; @@ -3175,6 +3177,34 @@ static int list_available_scripts(const struct option *opt __maybe_unused, exit(0); } +static int add_dlarg(const struct option *opt __maybe_unused, + const char *s, int unset __maybe_unused) +{ + char *arg = strdup(s); + void *a; + + if (!arg) + return -1; + + a = realloc(dlargv, sizeof(dlargv[0]) * (dlargc + 1)); + if (!a) { + free(arg); + return -1; + } + + dlargv = a; + dlargv[dlargc++] = arg; + + return 0; +} + +static void free_dlarg(void) +{ + while (dlargc--) + free(dlargv[dlargc]); + free(dlargv); +} + /* * Some scripts specify the required events in their "xxx-record" file, * this function will check if the events in perf.data match those @@ -3639,6 +3669,8 @@ int cmd_script(int argc, const char **argv) OPT_STRING('g', "gen-script", &generate_script_lang, "lang", "generate perf-script.xx script in specified language"), OPT_STRING(0, "dlfilter", &dlfilter_file, "file", "filter .so file name"), + OPT_CALLBACK(0, "dlarg", NULL, "argument", "filter argument", + add_dlarg), OPT_STRING('i', "input", &input_name, "file", "input file name"), OPT_BOOLEAN('d', "debug-mode", &debug_mode, "do various checks like samples ordering and lost events"), @@ -3958,7 +3990,7 @@ script_found: } if (dlfilter_file) { - dlfilter = dlfilter__new(dlfilter_file); + dlfilter = dlfilter__new(dlfilter_file, dlargc, dlargv); if (!dlfilter) return -1; } @@ -4116,6 +4148,7 @@ out_delete: if (script_started) cleanup_scripting(); dlfilter__cleanup(dlfilter); + free_dlarg(); out: return err; } diff --git a/tools/perf/util/dlfilter.c b/tools/perf/util/dlfilter.c index 288a2b5..eaa3cea 100644 --- a/tools/perf/util/dlfilter.c +++ b/tools/perf/util/dlfilter.c @@ -133,9 +133,26 @@ static const struct perf_dlfilter_al *dlfilter__resolve_addr(void *ctx) return d_addr_al; } +static char **dlfilter__args(void *ctx, int *dlargc) +{ + struct dlfilter *d = (struct dlfilter *)ctx; + + if (dlargc) + *dlargc = 0; + else + return NULL; + + if (!d->ctx_valid && !d->in_start && !d->in_stop) + return NULL; + + *dlargc = d->dlargc; + return d->dlargv; +} + static const struct perf_dlfilter_fns perf_dlfilter_fns = { .resolve_ip = dlfilter__resolve_ip, .resolve_addr = dlfilter__resolve_addr, + .args = dlfilter__args, }; static char *find_dlfilter(const char *file) @@ -169,7 +186,7 @@ out: #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) +static int dlfilter__init(struct dlfilter *d, const char *file, int dlargc, char **dlargv) { CHECK_FLAG(BRANCH); CHECK_FLAG(CALL); @@ -189,6 +206,8 @@ static int dlfilter__init(struct dlfilter *d, const char *file) d->file = find_dlfilter(file); if (!d->file) return -1; + d->dlargc = dlargc; + d->dlargv = dlargv; return 0; } @@ -219,14 +238,14 @@ static int dlfilter__close(struct dlfilter *d) return dlclose(d->handle); } -struct dlfilter *dlfilter__new(const char *file) +struct dlfilter *dlfilter__new(const char *file, int dlargc, char **dlargv) { struct dlfilter *d = malloc(sizeof(*d)); if (!d) return NULL; - if (dlfilter__init(d, file)) + if (dlfilter__init(d, file, dlargc, dlargv)) goto err_free; if (dlfilter__open(d)) @@ -253,16 +272,28 @@ int dlfilter__start(struct dlfilter *d, struct perf_session *session) { if (d) { d->session = session; - if (d->start) - return d->start(&d->data, d); + if (d->start) { + int ret; + + d->in_start = true; + ret = d->start(&d->data, d); + d->in_start = false; + return ret; + } } return 0; } static int dlfilter__stop(struct dlfilter *d) { - if (d && d->stop) - return d->stop(d->data, d); + if (d && d->stop) { + int ret; + + d->in_stop = true; + ret = d->stop(d->data, d); + d->in_stop = false; + return ret; + } return 0; } diff --git a/tools/perf/util/dlfilter.h b/tools/perf/util/dlfilter.h index a1ed38d..5059804 100644 --- a/tools/perf/util/dlfilter.h +++ b/tools/perf/util/dlfilter.h @@ -23,6 +23,10 @@ struct dlfilter { void *data; struct perf_session *session; bool ctx_valid; + bool in_start; + bool in_stop; + int dlargc; + char **dlargv; union perf_event *event; struct perf_sample *sample; @@ -47,7 +51,7 @@ struct dlfilter { struct perf_dlfilter_fns *fns; }; -struct dlfilter *dlfilter__new(const char *file); +struct dlfilter *dlfilter__new(const char *file, int dlargc, char **dlargv); int dlfilter__start(struct dlfilter *d, struct perf_session *session); diff --git a/tools/perf/util/perf_dlfilter.h b/tools/perf/util/perf_dlfilter.h index 31ad4c1..35e03aa 100644 --- a/tools/perf/util/perf_dlfilter.h +++ b/tools/perf/util/perf_dlfilter.h @@ -90,8 +90,10 @@ struct perf_dlfilter_fns { const struct perf_dlfilter_al *(*resolve_ip)(void *ctx); /* Return information about addr (if addr_correlates_sym) */ const struct perf_dlfilter_al *(*resolve_addr)(void *ctx); + /* Return arguments from --dlarg option */ + char **(*args)(void *ctx, int *dlargc); /* Reserved */ - void *(*reserved[126])(void *); + void *(*reserved[125])(void *); }; /* -- 2.7.4