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

tracing/probes: Add BTF retval type support

Check the target function has non-void retval type and set the correct
fetch type if user doesn't specify it.
If the function returns void, $retval is rejected as below;

 # echo 'f unregister_kprobes%return $retval' >> dynamic_events
sh: write error: No such file or directory
 # cat error_log
[   37.488397] trace_fprobe: error: This function returns 'void' type
  Command: f unregister_kprobes%return $retval
                                       ^
Link: https://lore.kernel.org/all/168507476195.913472.16290308831790216609.stgit@mhiramat.roam.corp.google.com/



Signed-off-by: default avatarMasami Hiramatsu (Google) <mhiramat@kernel.org>
parent 18b1e870
Loading
Loading
Loading
Loading
+62 −7
Original line number Diff line number Diff line
@@ -371,15 +371,13 @@ static const char *type_from_btf_id(struct btf *btf, s32 id)
	return NULL;
}

static const struct btf_param *find_btf_func_param(const char *funcname, s32 *nr,
						   bool tracepoint)
static const struct btf_type *find_btf_func_proto(const char *funcname)
{
	struct btf *btf = traceprobe_get_btf();
	const struct btf_param *param;
	const struct btf_type *t;
	s32 id;

	if (!btf || !funcname || !nr)
	if (!btf || !funcname)
		return ERR_PTR(-EINVAL);

	id = btf_find_by_name_kind(btf, funcname, BTF_KIND_FUNC);
@@ -396,6 +394,22 @@ static const struct btf_param *find_btf_func_param(const char *funcname, s32 *nr
	if (!btf_type_is_func_proto(t))
		return ERR_PTR(-ENOENT);

	return t;
}

static const struct btf_param *find_btf_func_param(const char *funcname, s32 *nr,
						   bool tracepoint)
{
	const struct btf_param *param;
	const struct btf_type *t;

	if (!funcname || !nr)
		return ERR_PTR(-EINVAL);

	t = find_btf_func_proto(funcname);
	if (IS_ERR(t))
		return (const struct btf_param *)t;

	*nr = btf_type_vlen(t);
	param = (const struct btf_param *)(t + 1);

@@ -462,6 +476,32 @@ static const struct fetch_type *parse_btf_arg_type(int arg_idx,
	return find_fetch_type(typestr, ctx->flags);
}

static const struct fetch_type *parse_btf_retval_type(
					struct traceprobe_parse_context *ctx)
{
	struct btf *btf = traceprobe_get_btf();
	const char *typestr = NULL;
	const struct btf_type *t;

	if (btf && ctx->funcname) {
		t = find_btf_func_proto(ctx->funcname);
		if (!IS_ERR(t))
			typestr = type_from_btf_id(btf, t->type);
	}

	return find_fetch_type(typestr, ctx->flags);
}

static bool is_btf_retval_void(const char *funcname)
{
	const struct btf_type *t;

	t = find_btf_func_proto(funcname);
	if (IS_ERR(t))
		return false;

	return t->type == 0;
}
#else
static struct btf *traceprobe_get_btf(void)
{
@@ -480,8 +520,15 @@ static int parse_btf_arg(const char *varname, struct fetch_insn *code,
	trace_probe_log_err(ctx->offset, NOSUP_BTFARG);
	return -EOPNOTSUPP;
}

#define parse_btf_arg_type(idx, ctx)		\
	find_fetch_type(NULL, ctx->flags)

#define parse_btf_retval_type(ctx)		\
	find_fetch_type(NULL, ctx->flags)

#define is_btf_retval_void(funcname)	(false)

#endif

#define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long))
@@ -512,6 +559,11 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t,

	if (strcmp(arg, "retval") == 0) {
		if (ctx->flags & TPARG_FL_RETURN) {
			if ((ctx->flags & TPARG_FL_KERNEL) &&
			    is_btf_retval_void(ctx->funcname)) {
				err = TP_ERR_NO_RETVAL;
				goto inval;
			}
			code->op = FETCH_OP_RETVAL;
			return 0;
		}
@@ -912,9 +964,12 @@ static int traceprobe_parse_probe_arg_body(const char *argv, ssize_t *size,
		goto fail;

	/* Update storing type if BTF is available */
	if (IS_ENABLED(CONFIG_PROBE_EVENTS_BTF_ARGS) &&
	    !t && code->op == FETCH_OP_ARG)
	if (IS_ENABLED(CONFIG_PROBE_EVENTS_BTF_ARGS) && !t) {
		if (code->op == FETCH_OP_ARG)
			parg->type = parse_btf_arg_type(code->param, ctx);
		else if (code->op == FETCH_OP_RETVAL)
			parg->type = parse_btf_retval_type(ctx);
	}

	ret = -EINVAL;
	/* Store operation */
+1 −0
Original line number Diff line number Diff line
@@ -449,6 +449,7 @@ extern int traceprobe_define_arg_fields(struct trace_event_call *event_call,
	C(BAD_EVENT_NAME,	"Event name must follow the same rules as C identifiers"), \
	C(EVENT_EXIST,		"Given group/event name is already used by another event"), \
	C(RETVAL_ON_PROBE,	"$retval is not available on probe"),	\
	C(NO_RETVAL,		"This function returns 'void' type"),	\
	C(BAD_STACK_NUM,	"Invalid stack number"),		\
	C(BAD_ARG_NUM,		"Invalid argument number"),		\
	C(BAD_VAR,		"Invalid $-valiable specified"),	\