Commit 3d032a25 authored by Adrian Hunter's avatar Adrian Hunter Committed by Arnaldo Carvalho de Melo
Browse files

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: default avatarAdrian Hunter <adrian.hunter@intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Leo Yan <leo.yan@linaro.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20210627131818.810-5-adrian.hunter@intel.com


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 638e2b99
Loading
Loading
Loading
Loading
+7 −3
Original line number Diff line number Diff line
@@ -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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+4 −0
Original line number Diff line number Diff line
@@ -102,6 +102,10 @@ OPTIONS
	Filter sample events using the given shared object file.
	Refer linkperf:perf-dlfilter[1]

--dlarg=<arg>::
	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.
+34 −1
Original line number Diff line number Diff line
@@ -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 @@ int cmd_script(int argc, const char **argv)
	}

	if (dlfilter_file) {
		dlfilter = dlfilter__new(dlfilter_file);
		dlfilter = dlfilter__new(dlfilter_file, dlargc, dlargv);
		if (!dlfilter)
			return -1;
	}
@@ -4116,6 +4148,7 @@ int cmd_script(int argc, const char **argv)
	if (script_started)
		cleanup_scripting();
	dlfilter__cleanup(dlfilter);
	free_dlarg();
out:
	return err;
}
+38 −7
Original line number Diff line number Diff line
@@ -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 @@ static char *find_dlfilter(const char *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)
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;
}

+5 −1
Original line number Diff line number Diff line
@@ -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);

Loading