mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-29 17:25:38 +00:00
tracing/probes: Support BTF argument on module functions
Since the btf returned from bpf_get_btf_vmlinux() only covers functions in the vmlinux, BTF argument is not available on the functions in the modules. Use bpf_find_btf_id() instead of bpf_get_btf_vmlinux()+btf_find_name_kind() so that BTF argument can find the correct struct btf and btf_type in it. With this fix, fprobe events can use `$arg*` on module functions as below # grep nf_log_ip_packet /proc/kallsyms ffffffffa0005c00 t nf_log_ip_packet [nf_log_syslog] ffffffffa0005bf0 t __pfx_nf_log_ip_packet [nf_log_syslog] # echo 'f nf_log_ip_packet $arg*' > dynamic_events # cat dynamic_events f:fprobes/nf_log_ip_packet__entry nf_log_ip_packet net=net pf=pf hooknum=hooknum skb=skb in=in out=out loginfo=loginfo prefix=prefix To support the module's btf which is removable, the struct btf needs to be ref-counted. So this also records the btf in the traceprobe_parse_context and returns the refcount when the parse has done. Link: https://lore.kernel.org/all/169272154223.160970.3507930084247934031.stgit@devnote2/ Suggested-by: Alexei Starovoitov <alexei.starovoitov@gmail.com> Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org> Acked-by: Steven Rostedt (Google) <rostedt@goodmis.org>
This commit is contained in:
parent
f8bbf8b990
commit
b1d1e90490
@ -211,6 +211,7 @@ struct btf_record *btf_parse_fields(const struct btf *btf, const struct btf_type
|
||||
int btf_check_and_fixup_fields(const struct btf *btf, struct btf_record *rec);
|
||||
bool btf_type_is_void(const struct btf_type *t);
|
||||
s32 btf_find_by_name_kind(const struct btf *btf, const char *name, u8 kind);
|
||||
s32 bpf_find_btf_id(const char *name, u32 kind, struct btf **btf_p);
|
||||
const struct btf_type *btf_type_skip_modifiers(const struct btf *btf,
|
||||
u32 id, u32 *res_id);
|
||||
const struct btf_type *btf_type_resolve_ptr(const struct btf *btf,
|
||||
|
@ -552,7 +552,7 @@ s32 btf_find_by_name_kind(const struct btf *btf, const char *name, u8 kind)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static s32 bpf_find_btf_id(const char *name, u32 kind, struct btf **btf_p)
|
||||
s32 bpf_find_btf_id(const char *name, u32 kind, struct btf **btf_p)
|
||||
{
|
||||
struct btf *btf;
|
||||
s32 ret;
|
||||
|
@ -807,13 +807,11 @@ static int trace_eprobe_tp_update_arg(struct trace_eprobe *ep, const char *argv[
|
||||
int ret;
|
||||
|
||||
ret = traceprobe_parse_probe_arg(&ep->tp, i, argv[i], &ctx);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Handle symbols "@" */
|
||||
if (!ret)
|
||||
ret = traceprobe_update_arg(&ep->tp.args[i]);
|
||||
|
||||
traceprobe_finish_parse(&ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1096,6 +1096,7 @@ static int __trace_fprobe_create(int argc, const char *argv[])
|
||||
}
|
||||
|
||||
out:
|
||||
traceprobe_finish_parse(&ctx);
|
||||
trace_probe_log_clear();
|
||||
kfree(new_argv);
|
||||
kfree(symbol);
|
||||
|
@ -907,6 +907,7 @@ static int __trace_kprobe_create(int argc, const char *argv[])
|
||||
}
|
||||
|
||||
out:
|
||||
traceprobe_finish_parse(&ctx);
|
||||
trace_probe_log_clear();
|
||||
kfree(new_argv);
|
||||
kfree(symbol);
|
||||
|
@ -304,16 +304,6 @@ static int parse_trace_event_arg(char *arg, struct fetch_insn *code,
|
||||
|
||||
#ifdef CONFIG_PROBE_EVENTS_BTF_ARGS
|
||||
|
||||
static struct btf *traceprobe_get_btf(void)
|
||||
{
|
||||
struct btf *btf = bpf_get_btf_vmlinux();
|
||||
|
||||
if (IS_ERR_OR_NULL(btf))
|
||||
return NULL;
|
||||
|
||||
return btf;
|
||||
}
|
||||
|
||||
static u32 btf_type_int(const struct btf_type *t)
|
||||
{
|
||||
return *(u32 *)(t + 1);
|
||||
@ -371,42 +361,49 @@ static const char *type_from_btf_id(struct btf *btf, s32 id)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const struct btf_type *find_btf_func_proto(const char *funcname)
|
||||
static const struct btf_type *find_btf_func_proto(const char *funcname,
|
||||
struct btf **btf_p)
|
||||
{
|
||||
struct btf *btf = traceprobe_get_btf();
|
||||
const struct btf_type *t;
|
||||
struct btf *btf = NULL;
|
||||
s32 id;
|
||||
|
||||
if (!btf || !funcname)
|
||||
if (!funcname)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
id = btf_find_by_name_kind(btf, funcname, BTF_KIND_FUNC);
|
||||
id = bpf_find_btf_id(funcname, BTF_KIND_FUNC, &btf);
|
||||
if (id <= 0)
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
/* Get BTF_KIND_FUNC type */
|
||||
t = btf_type_by_id(btf, id);
|
||||
if (!t || !btf_type_is_func(t))
|
||||
return ERR_PTR(-ENOENT);
|
||||
goto err;
|
||||
|
||||
/* The type of BTF_KIND_FUNC is BTF_KIND_FUNC_PROTO */
|
||||
t = btf_type_by_id(btf, t->type);
|
||||
if (!t || !btf_type_is_func_proto(t))
|
||||
return ERR_PTR(-ENOENT);
|
||||
goto err;
|
||||
|
||||
*btf_p = btf;
|
||||
return t;
|
||||
|
||||
err:
|
||||
btf_put(btf);
|
||||
return ERR_PTR(-ENOENT);
|
||||
}
|
||||
|
||||
static const struct btf_param *find_btf_func_param(const char *funcname, s32 *nr,
|
||||
bool tracepoint)
|
||||
struct btf **btf_p, bool tracepoint)
|
||||
{
|
||||
const struct btf_param *param;
|
||||
const struct btf_type *t;
|
||||
struct btf *btf;
|
||||
|
||||
if (!funcname || !nr)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
t = find_btf_func_proto(funcname);
|
||||
t = find_btf_func_proto(funcname, &btf);
|
||||
if (IS_ERR(t))
|
||||
return (const struct btf_param *)t;
|
||||
|
||||
@ -419,29 +416,37 @@ static const struct btf_param *find_btf_func_param(const char *funcname, s32 *nr
|
||||
param++;
|
||||
}
|
||||
|
||||
if (*nr > 0)
|
||||
if (*nr > 0) {
|
||||
*btf_p = btf;
|
||||
return param;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
btf_put(btf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void clear_btf_context(struct traceprobe_parse_context *ctx)
|
||||
{
|
||||
if (ctx->btf) {
|
||||
btf_put(ctx->btf);
|
||||
ctx->btf = NULL;
|
||||
ctx->params = NULL;
|
||||
ctx->nr_params = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_btf_arg(const char *varname, struct fetch_insn *code,
|
||||
struct traceprobe_parse_context *ctx)
|
||||
{
|
||||
struct btf *btf = traceprobe_get_btf();
|
||||
const struct btf_param *params;
|
||||
int i;
|
||||
|
||||
if (!btf) {
|
||||
trace_probe_log_err(ctx->offset, NOSUP_BTFARG);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (WARN_ON_ONCE(!ctx->funcname))
|
||||
return -EINVAL;
|
||||
|
||||
if (!ctx->params) {
|
||||
params = find_btf_func_param(ctx->funcname, &ctx->nr_params,
|
||||
params = find_btf_func_param(ctx->funcname,
|
||||
&ctx->nr_params, &ctx->btf,
|
||||
ctx->flags & TPARG_FL_TPOINT);
|
||||
if (IS_ERR_OR_NULL(params)) {
|
||||
trace_probe_log_err(ctx->offset, NO_BTF_ENTRY);
|
||||
@ -452,7 +457,7 @@ static int parse_btf_arg(const char *varname, struct fetch_insn *code,
|
||||
params = ctx->params;
|
||||
|
||||
for (i = 0; i < ctx->nr_params; i++) {
|
||||
const char *name = btf_name_by_offset(btf, params[i].name_off);
|
||||
const char *name = btf_name_by_offset(ctx->btf, params[i].name_off);
|
||||
|
||||
if (name && !strcmp(name, varname)) {
|
||||
code->op = FETCH_OP_ARG;
|
||||
@ -470,7 +475,7 @@ static int parse_btf_arg(const char *varname, struct fetch_insn *code,
|
||||
static const struct fetch_type *parse_btf_arg_type(int arg_idx,
|
||||
struct traceprobe_parse_context *ctx)
|
||||
{
|
||||
struct btf *btf = traceprobe_get_btf();
|
||||
struct btf *btf = ctx->btf;
|
||||
const char *typestr = NULL;
|
||||
|
||||
if (btf && ctx->params) {
|
||||
@ -485,14 +490,17 @@ static const struct fetch_type *parse_btf_arg_type(int arg_idx,
|
||||
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;
|
||||
struct btf *btf;
|
||||
|
||||
if (btf && ctx->funcname) {
|
||||
t = find_btf_func_proto(ctx->funcname);
|
||||
if (!IS_ERR(t))
|
||||
if (ctx->funcname) {
|
||||
/* Do not use ctx->btf, because it must be used with ctx->param */
|
||||
t = find_btf_func_proto(ctx->funcname, &btf);
|
||||
if (!IS_ERR(t)) {
|
||||
typestr = type_from_btf_id(btf, t->type);
|
||||
btf_put(btf);
|
||||
}
|
||||
}
|
||||
|
||||
return find_fetch_type(typestr, ctx->flags);
|
||||
@ -501,21 +509,25 @@ static const struct fetch_type *parse_btf_retval_type(
|
||||
static bool is_btf_retval_void(const char *funcname)
|
||||
{
|
||||
const struct btf_type *t;
|
||||
struct btf *btf;
|
||||
bool ret;
|
||||
|
||||
t = find_btf_func_proto(funcname);
|
||||
t = find_btf_func_proto(funcname, &btf);
|
||||
if (IS_ERR(t))
|
||||
return false;
|
||||
|
||||
return t->type == 0;
|
||||
ret = (t->type == 0);
|
||||
btf_put(btf);
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
static struct btf *traceprobe_get_btf(void)
|
||||
static void clear_btf_context(struct traceprobe_parse_context *ctx)
|
||||
{
|
||||
return NULL;
|
||||
ctx->btf = NULL;
|
||||
}
|
||||
|
||||
static const struct btf_param *find_btf_func_param(const char *funcname, s32 *nr,
|
||||
bool tracepoint)
|
||||
struct btf **btf_p, bool tracepoint)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
}
|
||||
@ -1231,7 +1243,6 @@ static int sprint_nth_btf_arg(int idx, const char *type,
|
||||
char *buf, int bufsize,
|
||||
struct traceprobe_parse_context *ctx)
|
||||
{
|
||||
struct btf *btf = traceprobe_get_btf();
|
||||
const char *name;
|
||||
int ret;
|
||||
|
||||
@ -1239,7 +1250,7 @@ static int sprint_nth_btf_arg(int idx, const char *type,
|
||||
trace_probe_log_err(0, NO_BTFARG);
|
||||
return -ENOENT;
|
||||
}
|
||||
name = btf_name_by_offset(btf, ctx->params[idx].name_off);
|
||||
name = btf_name_by_offset(ctx->btf, ctx->params[idx].name_off);
|
||||
if (!name) {
|
||||
trace_probe_log_err(0, NO_BTF_ENTRY);
|
||||
return -ENOENT;
|
||||
@ -1271,7 +1282,7 @@ const char **traceprobe_expand_meta_args(int argc, const char *argv[],
|
||||
return NULL;
|
||||
}
|
||||
|
||||
params = find_btf_func_param(ctx->funcname, &nr_params,
|
||||
params = find_btf_func_param(ctx->funcname, &nr_params, &ctx->btf,
|
||||
ctx->flags & TPARG_FL_TPOINT);
|
||||
if (IS_ERR_OR_NULL(params)) {
|
||||
if (args_idx != -1) {
|
||||
@ -1337,6 +1348,11 @@ const char **traceprobe_expand_meta_args(int argc, const char *argv[],
|
||||
return ERR_PTR(ret);
|
||||
}
|
||||
|
||||
void traceprobe_finish_parse(struct traceprobe_parse_context *ctx)
|
||||
{
|
||||
clear_btf_context(ctx);
|
||||
}
|
||||
|
||||
int traceprobe_update_arg(struct probe_arg *arg)
|
||||
{
|
||||
struct fetch_insn *code = arg->code;
|
||||
|
@ -383,9 +383,11 @@ static inline bool tparg_is_function_entry(unsigned int flags)
|
||||
|
||||
struct traceprobe_parse_context {
|
||||
struct trace_event_call *event;
|
||||
const struct btf_param *params;
|
||||
s32 nr_params;
|
||||
const char *funcname;
|
||||
/* BTF related parameters */
|
||||
const char *funcname; /* Function name in BTF */
|
||||
const struct btf_param *params; /* Parameter of the function */
|
||||
s32 nr_params; /* The number of the parameters */
|
||||
struct btf *btf; /* The BTF to be used */
|
||||
unsigned int flags;
|
||||
int offset;
|
||||
};
|
||||
@ -400,6 +402,12 @@ const char **traceprobe_expand_meta_args(int argc, const char *argv[],
|
||||
extern int traceprobe_update_arg(struct probe_arg *arg);
|
||||
extern void traceprobe_free_probe_arg(struct probe_arg *arg);
|
||||
|
||||
/*
|
||||
* If either traceprobe_parse_probe_arg() or traceprobe_expand_meta_args() is called,
|
||||
* this MUST be called for clean up the context and return a resource.
|
||||
*/
|
||||
void traceprobe_finish_parse(struct traceprobe_parse_context *ctx);
|
||||
|
||||
extern int traceprobe_split_symbol_offset(char *symbol, long *offset);
|
||||
int traceprobe_parse_event_name(const char **pevent, const char **pgroup,
|
||||
char *buf, int offset);
|
||||
|
@ -693,6 +693,7 @@ static int __trace_uprobe_create(int argc, const char **argv)
|
||||
|
||||
trace_probe_log_set_index(i + 2);
|
||||
ret = traceprobe_parse_probe_arg(&tu->tp, i, argv[i], &ctx);
|
||||
traceprobe_finish_parse(&ctx);
|
||||
if (ret)
|
||||
goto error;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user