From: Masami Hiramatsu <mhiramat@kernel.org>
To: Alan Maguire <alan.maguire@oracle.com>
Cc: Steven Rostedt <rostedt@goodmis.org>,
Jiri Olsa <jolsa@redhat.com>, Sven Schnelle <svens@linux.ibm.com>,
bpf@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: Re: [RFC PATCH] tracing/kprobe: Support $$args for function entry
Date: Sat, 25 Sep 2021 23:15:35 +0900 [thread overview]
Message-ID: <20210925231535.aba3f620efa94e2a213c558f@kernel.org> (raw)
In-Reply-To: <aba162cc-8ee5-45e1-e29b-60118bc2a980@oracle.com>
On Fri, 24 Sep 2021 18:51:04 +0100
Alan Maguire <alan.maguire@oracle.com> wrote:
> On 23/09/2021 13:39, Masami Hiramatsu wrote:
>
> > Support $$args fetch arg for function entry. This uses
> > BTF for finding the function argument. Thus it depends
> > on CONFIG_BPF_SYSCALL.
> >
> > /sys/kernel/tracing # echo 'p vfs_read $$args' >> kprobe_events
> > /sys/kernel/tracing # cat kprobe_events
> > p:kprobes/p_vfs_read_0 vfs_read file=$arg1:x64 buf=$arg2:x64 count=$arg3:u64 pos=$arg4:x64
> >
> > Note that $$args must be used without argument name.
>
> This looks great! Can I ask which tree you're building on
>
> top of so I can play around with this a bit?
This can be applied on top of Steve's tracing tree, ftrace/core branch.
git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace.git
>
>
> I also wonder if we could rework btf_show_name() to help
>
> render full type info for the args? in kernel/bpf/btf.c:
>
>
> /*
> * Populate show->state.name with type name information.
> * Format of type name is
> *
> * [.member_name = ] (type_name)
> */
>
> The (type_name) part is what we'd want from here; no reason
>
> we can't refactor that function to make the type name available
>
> as a cast. It would rework the output to be something like
>
>
> p:kprobes/p_vfs_read_0 vfs_read struct file *file=$arg1 , char *buf=$arg2 , size_t count=$arg3 , loff_t pos=$arg4
>
> ...if that's wanted of course (not sure what the constraints on format are here)? Thanks for pushing this along!
Sorry, the kprobe_events interface syntax doesn't accept such cast info.
And I want such BTF type query interface to be independent from
this kprobe-events interface.
Can we have a query interface like /sys/kernel/btf/query?
Thank you,
>
>
> Alan
>
> > Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
> > ---
> > kernel/trace/trace_kprobe.c | 60 ++++++++++++++++++++++++-
> > kernel/trace/trace_probe.c | 105 +++++++++++++++++++++++++++++++++++++++++++
> > kernel/trace/trace_probe.h | 5 ++
> > 3 files changed, 168 insertions(+), 2 deletions(-)
> >
> > diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
> > index 3dd4fb719aa3..fe88ee8c8cd8 100644
> > --- a/kernel/trace/trace_kprobe.c
> > +++ b/kernel/trace/trace_kprobe.c
> > @@ -712,6 +712,58 @@ static int trace_kprobe_module_callback(struct notifier_block *nb,
> > return NOTIFY_DONE;
> > }
> >
> > +#ifdef CONFIG_BPF_SYSCALL
> > +
> > +static int trace_kprobe_parse_btf_args(struct trace_kprobe *tk, int i,
> > + const char *arg, unsigned int flags)
> > +{
> > + struct trace_probe *tp = &tk->tp;
> > + static struct btf *btf;
> > + const struct btf_type *t;
> > + const struct btf_param *args;
> > + s32 id, nargs;
> > + int ret;
> > +
> > + if (!(flags & TPARG_FL_FENTRY))
> > + return -EINVAL;
> > + if (!tk->symbol)
> > + return -EINVAL;
> > +
> > + if (!btf)
> > + btf = btf_parse_vmlinux();
> > +
> > + id = btf_find_by_name_kind(btf, tk->symbol, BTF_KIND_FUNC);
> > + if (id <= 0)
> > + return -ENOENT;
> > +
> > + /* Get BTF_KIND_FUNC type */
> > + t = btf_type_by_id(btf, id);
> > + if (!btf_type_is_func(t))
> > + return -ENOENT;
> > +
> > + /* The type of BTF_KIND_FUNC is BTF_KIND_FUNC_PROTO */
> > + t = btf_type_by_id(btf, t->type);
> > + if (!btf_type_is_func_proto(t))
> > + return -ENOENT;
> > +
> > + args = (const struct btf_param *)(t + 1);
> > + nargs = btf_type_vlen(t);
> > + for (i = 0; i < nargs; i++) {
> > + ret = traceprobe_parse_btf_arg(tp, i, btf, &args[i]);
> > + if (ret < 0)
> > + break;
> > + }
> > +
> > + return ret;
> > +}
> > +#else
> > +static int trace_kprobe_parse_btf_args(struct trace_kprobe *tk, int i,
> > + const char *arg, unsigned int flags)
> > +{
> > + return -EOPNOTSUPP;
> > +}
> > +#endif
> > +
> > static struct notifier_block trace_kprobe_module_nb = {
> > .notifier_call = trace_kprobe_module_callback,
> > .priority = 1 /* Invoked after kprobe module callback */
> > @@ -733,12 +785,13 @@ static int __trace_kprobe_create(int argc, const char *argv[])
> > * $stack : fetch stack address
> > * $stackN : fetch Nth of stack (N:0-)
> > * $comm : fetch current task comm
> > + * $$args : fetch parameters using BTF
> > * @ADDR : fetch memory at ADDR (ADDR should be in kernel)
> > * @SYM[+|-offs] : fetch memory at SYM +|- offs (SYM is a data symbol)
> > * %REG : fetch register REG
> > * Dereferencing memory fetch:
> > * +|-offs(ARG) : fetch memory at ARG +|- offs address.
> > - * Alias name of args:
> > + * Alias name of args (except for $$args) :
> > * NAME=FETCHARG : set NAME as alias of FETCHARG.
> > * Type of args:
> > * FETCHARG:TYPE : use TYPE instead of unsigned long.
> > @@ -877,7 +930,10 @@ static int __trace_kprobe_create(int argc, const char *argv[])
> > /* parse arguments */
> > for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {
> > trace_probe_log_set_index(i + 2);
> > - ret = traceprobe_parse_probe_arg(&tk->tp, i, argv[i], flags);
> > + if (strcmp(argv[i], "$$args") == 0)
> > + ret = trace_kprobe_parse_btf_args(tk, i, argv[i], flags);
> > + else
> > + ret = traceprobe_parse_probe_arg(&tk->tp, i, argv[i], flags);
> > if (ret)
> > goto error; /* This can be -ENOMEM */
> > }
> > diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
> > index 2fe104109525..bbac261b1688 100644
> > --- a/kernel/trace/trace_probe.c
> > +++ b/kernel/trace/trace_probe.c
> > @@ -765,6 +765,111 @@ static int traceprobe_conflict_field_name(const char *name,
> > return 0;
> > }
> >
> > +#ifdef CONFIG_BPF_SYSCALL
> > +
> > +static u32 btf_type_int(const struct btf_type *t)
> > +{
> > + return *(u32 *)(t + 1);
> > +}
> > +
> > +static const char *traceprobe_type_from_btf(struct btf *btf, s32 id)
> > +{
> > + const struct btf_type *t;
> > + u32 intdata;
> > + s32 tid;
> > +
> > + /* TODO: const char * could be converted as a string */
> > + t = btf_type_skip_modifiers(btf, id, &tid);
> > +
> > + switch (BTF_INFO_KIND(t->info)) {
> > + case BTF_KIND_ENUM:
> > + /* enum is "int", so convert to "s32" */
> > + return "s32";
> > + case BTF_KIND_PTR:
> > + /* pointer will be converted to "x??" */
> > + if (IS_ENABLED(CONFIG_64BIT))
> > + return "x64";
> > + else
> > + return "x32";
> > + case BTF_KIND_INT:
> > + intdata = btf_type_int(t);
> > + if (BTF_INT_ENCODING(intdata) & BTF_INT_SIGNED) {
> > + switch (BTF_INT_BITS(intdata)) {
> > + case 8:
> > + return "s8";
> > + case 16:
> > + return "s16";
> > + case 32:
> > + return "s32";
> > + case 64:
> > + return "s64";
> > + }
> > + } else { /* unsigned */
> > + switch (BTF_INT_BITS(intdata)) {
> > + case 8:
> > + return "u8";
> > + case 16:
> > + return "u16";
> > + case 32:
> > + return "u32";
> > + case 64:
> > + return "u64";
> > + }
> > + }
> > + }
> > +
> > + /* Default type */
> > + if (IS_ENABLED(CONFIG_64BIT))
> > + return "x64";
> > + else
> > + return "x32";
> > +}
> > +
> > +int traceprobe_parse_btf_arg(struct trace_probe *tp, int i, struct btf *btf,
> > + const struct btf_param *arg)
> > +{
> > + struct probe_arg *parg = &tp->args[i];
> > + const char *name, *tname;
> > + char *body;
> > + int ret;
> > +
> > + tp->nr_args++;
> > + name = btf_name_by_offset(btf, arg->name_off);
> > + parg->name = kstrdup(name, GFP_KERNEL);
> > + if (!parg->name)
> > + return -ENOMEM;
> > +
> > + if (!is_good_name(parg->name)) {
> > + trace_probe_log_err(0, BAD_ARG_NAME);
> > + return -EINVAL;
> > + }
> > + if (traceprobe_conflict_field_name(parg->name, tp->args, i)) {
> > + trace_probe_log_err(0, USED_ARG_NAME);
> > + return -EINVAL;
> > + }
> > +
> > + /*
> > + * Since probe event needs an appropriate command for dyn_event interface,
> > + * convert BTF type to corresponding fetch-type string.
> > + */
> > + tname = traceprobe_type_from_btf(btf, arg->type);
> > + if (tname)
> > + body = kasprintf(GFP_KERNEL, "$arg%d:%s", i + 1, tname);
> > + else
> > + body = kasprintf(GFP_KERNEL, "$arg%d", i + 1);
> > +
> > + if (!body)
> > + return -ENOMEM;
> > + /* Parse fetch argument */
> > + ret = traceprobe_parse_probe_arg_body(body, &tp->size, parg,
> > + TPARG_FL_KERNEL | TPARG_FL_FENTRY, 0);
> > +
> > + kfree(body);
> > +
> > + return ret;
> > +}
> > +#endif
> > +
> > int traceprobe_parse_probe_arg(struct trace_probe *tp, int i, const char *arg,
> > unsigned int flags)
> > {
> > diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
> > index 355c78a930f8..857b946afe29 100644
> > --- a/kernel/trace/trace_probe.h
> > +++ b/kernel/trace/trace_probe.h
> > @@ -23,6 +23,7 @@
> > #include <linux/limits.h>
> > #include <linux/uaccess.h>
> > #include <linux/bitops.h>
> > +#include <linux/btf.h>
> > #include <asm/bitsperlong.h>
> >
> > #include "trace.h"
> > @@ -359,6 +360,10 @@ int trace_probe_create(const char *raw_command, int (*createfn)(int, const char
> >
> > extern int traceprobe_parse_probe_arg(struct trace_probe *tp, int i,
> > const char *argv, unsigned int flags);
> > +#ifdef CONFIG_BPF_SYSCALL
> > +int traceprobe_parse_btf_arg(struct trace_probe *tp, int i, struct btf *btf,
> > + const struct btf_param *arg);
> > +#endif
> >
> > extern int traceprobe_update_arg(struct probe_arg *arg);
> > extern void traceprobe_free_probe_arg(struct probe_arg *arg);
> >
--
Masami Hiramatsu <mhiramat@kernel.org>
next prev parent reply other threads:[~2021-09-25 14:15 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-09-23 12:39 [RFC PATCH] tracing: BTF testing for kprobe-events Masami Hiramatsu
2021-09-23 12:39 ` [RFC PATCH] tracing/kprobe: Support $$args for function entry Masami Hiramatsu
2021-09-24 17:51 ` Alan Maguire
2021-09-25 14:15 ` Masami Hiramatsu [this message]
2021-10-11 22:23 ` [RFC PATCH] tracing: BTF testing for kprobe-events Steven Rostedt
2021-10-13 12:52 ` Masami Hiramatsu
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=20210925231535.aba3f620efa94e2a213c558f@kernel.org \
--to=mhiramat@kernel.org \
--cc=alan.maguire@oracle.com \
--cc=bpf@vger.kernel.org \
--cc=jolsa@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.