From: "Masami Hiramatsu (Google)" <mhiramat@kernel.org>
To: linux-trace-kernel@vger.kernel.org
Cc: linux-kernel@vger.kernel.org,
Steven Rostedt <rostedt@goodmis.org>,
mhiramat@kernel.org, Martin KaFai Lau <martin.lau@linux.dev>,
bpf@vger.kernel.org, Sven Schnelle <svens@linux.ibm.com>,
Alexei Starovoitov <ast@kernel.org>
Subject: [PATCH v4 1/9] tracing/probes: Support BTF argument on module functions
Date: Mon, 31 Jul 2023 16:30:14 +0900 [thread overview]
Message-ID: <169078861390.173706.6123335543895839788.stgit@devnote2> (raw)
In-Reply-To: <169078860386.173706.3091034523220945605.stgit@devnote2>
From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
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.
Suggested-by: Alexei Starovoitov <alexei.starovoitov@gmail.com>
Signed-off-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
---
Changes in v3:
- Newly added.
---
include/linux/btf.h | 1
kernel/bpf/btf.c | 2 -
kernel/trace/trace_eprobe.c | 4 --
kernel/trace/trace_fprobe.c | 1
kernel/trace/trace_kprobe.c | 1
kernel/trace/trace_probe.c | 100 +++++++++++++++++++++++++------------------
kernel/trace/trace_probe.h | 14 +++++-
kernel/trace/trace_uprobe.c | 1
8 files changed, 75 insertions(+), 49 deletions(-)
diff --git a/include/linux/btf.h b/include/linux/btf.h
index cac9f304e27a..dbfe41a09c4b 100644
--- a/include/linux/btf.h
+++ b/include/linux/btf.h
@@ -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,
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 817204d53372..b9b0eb1189bb 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -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;
diff --git a/kernel/trace/trace_eprobe.c b/kernel/trace/trace_eprobe.c
index a0a704ba27db..09bac836d72b 100644
--- a/kernel/trace/trace_eprobe.c
+++ b/kernel/trace/trace_eprobe.c
@@ -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;
}
diff --git a/kernel/trace/trace_fprobe.c b/kernel/trace/trace_fprobe.c
index dfe2e546acdc..8f43f1f65b1b 100644
--- a/kernel/trace/trace_fprobe.c
+++ b/kernel/trace/trace_fprobe.c
@@ -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);
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 23dba01831f7..cc822f69bfe8 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -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);
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index c68a72707852..ecbe28f8d676 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -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;
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 01ea148723de..4dc91460a75d 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -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);
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 688bf579f2f1..9790f8f0a32d 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -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;
}
next prev parent reply other threads:[~2023-07-31 7:31 UTC|newest]
Thread overview: 47+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-07-31 7:30 [PATCH v4 0/9] tracing: Improbe BTF support on probe events Masami Hiramatsu (Google)
2023-07-31 7:30 ` Masami Hiramatsu (Google) [this message]
2023-07-31 7:30 ` [PATCH v4 2/9] bpf/btf: tracing: Move finding func-proto API and getting func-param API to BTF Masami Hiramatsu (Google)
2023-07-31 7:30 ` [PATCH v4 3/9] bpf/btf: Add a function to search a member of a struct/union Masami Hiramatsu (Google)
2023-07-31 21:59 ` Alexei Starovoitov
2023-07-31 23:57 ` Masami Hiramatsu
2023-08-01 0:29 ` Alexei Starovoitov
2023-08-01 15:02 ` Masami Hiramatsu
2023-08-01 15:20 ` Steven Rostedt
2023-08-01 15:32 ` Steven Rostedt
2023-08-01 22:18 ` Alexei Starovoitov
2023-08-01 23:09 ` Steven Rostedt
2023-08-01 23:44 ` Alexei Starovoitov
2023-08-02 0:21 ` Masami Hiramatsu
2023-08-02 0:40 ` Steven Rostedt
2023-08-02 0:44 ` Steven Rostedt
2023-08-02 2:22 ` Alexei Starovoitov
2023-08-02 2:32 ` Steven Rostedt
2023-08-02 14:07 ` Masami Hiramatsu
2023-08-02 15:08 ` Florent Revest
2023-08-02 13:56 ` Masami Hiramatsu
2023-08-02 14:48 ` Florent Revest
2023-08-02 15:47 ` Florent Revest
2023-08-03 1:55 ` Masami Hiramatsu
2023-08-02 18:24 ` Alexei Starovoitov
2023-08-02 18:38 ` Steven Rostedt
2023-08-02 19:48 ` Alexei Starovoitov
2023-08-02 20:12 ` Steven Rostedt
2023-08-02 21:28 ` Alexei Starovoitov
2023-08-02 14:44 ` Florent Revest
2023-08-02 16:11 ` Steven Rostedt
2023-08-03 15:42 ` Masami Hiramatsu
2023-08-03 16:37 ` Florent Revest
2023-08-07 20:48 ` Jiri Olsa
2023-08-08 14:32 ` Masami Hiramatsu
2023-08-01 1:15 ` Steven Rostedt
2023-08-01 2:24 ` Alexei Starovoitov
2023-08-01 13:35 ` Steven Rostedt
2023-08-01 15:18 ` Masami Hiramatsu
2023-08-01 22:21 ` Alexei Starovoitov
2023-08-01 23:17 ` Masami Hiramatsu
2023-07-31 7:30 ` [PATCH v4 4/9] tracing/probes: Support BTF based data structure field access Masami Hiramatsu (Google)
2023-07-31 7:30 ` [PATCH v4 5/9] tracing/probes: Support BTF field access from $retval Masami Hiramatsu (Google)
2023-07-31 7:31 ` [PATCH v4 6/9] tracing/probes: Add string type check with BTF Masami Hiramatsu (Google)
2023-07-31 7:31 ` [PATCH v4 7/9] tracing/fprobe-event: Assume fprobe is a return event by $retval Masami Hiramatsu (Google)
2023-07-31 7:31 ` [PATCH v4 8/9] selftests/ftrace: Add BTF fields access testcases Masami Hiramatsu (Google)
2023-07-31 7:31 ` [PATCH v4 9/9] Documentation: tracing: Update fprobe event example with BTF field Masami Hiramatsu (Google)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=169078861390.173706.6123335543895839788.stgit@devnote2 \
--to=mhiramat@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=martin.lau@linux.dev \
--cc=rostedt@goodmis.org \
--cc=svens@linux.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).