Commit 08c9306f authored by Masami Hiramatsu (Google)'s avatar Masami Hiramatsu (Google)
Browse files

tracing/fprobe-event: Assume fprobe is a return event by $retval

Assume the fprobe event is a return event if there is $retval is
used in the probe's argument without %return. e.g.

echo 'f:myevent vfs_read $retval' >> dynamic_events

then 'myevent' is a return probe event.

Link: https://lore.kernel.org/all/169272160261.160970.13613040161560998787.stgit@devnote2/



Suggested-by: default avatarSteven Rostedt <rostedt@goodmis.org>
Signed-off-by: default avatarMasami Hiramatsu (Google) <mhiramat@kernel.org>
Acked-by: default avatarSteven Rostedt (Google) <rostedt@goodmis.org>
parent 27973e5c
Loading
Loading
Loading
Loading
+44 −14
Original line number Diff line number Diff line
@@ -898,6 +898,46 @@ static struct tracepoint *find_tracepoint(const char *tp_name)
	return data.tpoint;
}

static int parse_symbol_and_return(int argc, const char *argv[],
				   char **symbol, bool *is_return,
				   bool is_tracepoint)
{
	char *tmp = strchr(argv[1], '%');
	int i;

	if (tmp) {
		int len = tmp - argv[1];

		if (!is_tracepoint && !strcmp(tmp, "%return")) {
			*is_return = true;
		} else {
			trace_probe_log_err(len, BAD_ADDR_SUFFIX);
			return -EINVAL;
		}
		*symbol = kmemdup_nul(argv[1], len, GFP_KERNEL);
	} else
		*symbol = kstrdup(argv[1], GFP_KERNEL);
	if (!*symbol)
		return -ENOMEM;

	if (*is_return)
		return 0;

	/* If there is $retval, this should be a return fprobe. */
	for (i = 2; i < argc; i++) {
		tmp = strstr(argv[i], "$retval");
		if (tmp && !isalnum(tmp[7]) && tmp[7] != '_') {
			*is_return = true;
			/*
			 * NOTE: Don't check is_tracepoint here, because it will
			 * be checked when the argument is parsed.
			 */
			break;
		}
	}
	return 0;
}

static int __trace_fprobe_create(int argc, const char *argv[])
{
	/*
@@ -927,7 +967,7 @@ static int __trace_fprobe_create(int argc, const char *argv[])
	struct trace_fprobe *tf = NULL;
	int i, len, new_argc = 0, ret = 0;
	bool is_return = false;
	char *symbol = NULL, *tmp = NULL;
	char *symbol = NULL;
	const char *event = NULL, *group = FPROBE_EVENT_SYSTEM;
	const char **new_argv = NULL;
	int maxactive = 0;
@@ -983,20 +1023,10 @@ static int __trace_fprobe_create(int argc, const char *argv[])
	trace_probe_log_set_index(1);

	/* a symbol(or tracepoint) must be specified */
	symbol = kstrdup(argv[1], GFP_KERNEL);
	if (!symbol)
		return -ENOMEM;

	tmp = strchr(symbol, '%');
	if (tmp) {
		if (!is_tracepoint && !strcmp(tmp, "%return")) {
			*tmp = '\0';
			is_return = true;
		} else {
			trace_probe_log_err(tmp - symbol, BAD_ADDR_SUFFIX);
	ret = parse_symbol_and_return(argc, argv, &symbol, &is_return, is_tracepoint);
	if (ret < 0)
		goto parse_error;
		}
	}

	if (!is_return && maxactive) {
		trace_probe_log_set_index(0);
		trace_probe_log_err(1, BAD_MAXACT_TYPE);
+1 −1
Original line number Diff line number Diff line
@@ -30,11 +30,11 @@ check_error 'f:^ vfs_read' # NO_EVENT_NAME
check_error 'f:foo/^12345678901234567890123456789012345678901234567890123456789012345 vfs_read'	# EVENT_TOO_LONG
check_error 'f:foo/^bar.1 vfs_read'	# BAD_EVENT_NAME

check_error 'f vfs_read ^$retval'	# RETVAL_ON_PROBE
check_error 'f vfs_read ^$stack10000'	# BAD_STACK_NUM

check_error 'f vfs_read ^$arg10000'	# BAD_ARG_NUM

check_error 'f vfs_read $retval ^$arg1' # BAD_VAR
check_error 'f vfs_read ^$none_var'	# BAD_VAR
check_error 'f vfs_read ^'$REG		# BAD_VAR