BPF List
 help / color / mirror / Atom feed
From: Masami Hiramatsu (Google) <mhiramat@kernel.org>
To: Steven Rostedt <rostedt@goodmis.org>
Cc: linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org,
	Florent Revest <revest@chromium.org>,
	Mark Rutland <mark.rutland@arm.com>,
	Will Deacon <will@kernel.org>,
	Mathieu Desnoyers <mathieu.desnoyers@efficios.com>,
	Martin KaFai Lau <martin.lau@linux.dev>,
	bpf@vger.kernel.org
Subject: Re: [PATCH v9.1 02/11] tracing/probes: Add fprobe events for tracing function entry and exit.
Date: Wed, 10 May 2023 00:08:39 +0900	[thread overview]
Message-ID: <20230510000839.0d223bfd5ba9e556f302596d@kernel.org> (raw)
In-Reply-To: <20230505121212.7569c9b9@gandalf.local.home>

On Fri, 5 May 2023 12:12:12 -0400
Steven Rostedt <rostedt@goodmis.org> wrote:

> On Tue,  2 May 2023 11:17:36 +0900
> "Masami Hiramatsu (Google)" <mhiramat@kernel.org> wrote:
> 
> > diff --git a/kernel/trace/trace_fprobe.c b/kernel/trace/trace_fprobe.c
> > new file mode 100644
> > index 000000000000..0049d9ef2402
> > --- /dev/null
> > +++ b/kernel/trace/trace_fprobe.c
> > @@ -0,0 +1,1053 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Fprobe-based tracing events
> > + * Copyright (C) 2022 Google LLC.
> > + */
> > +#define pr_fmt(fmt)	"trace_fprobe: " fmt
> > +
> > +#include <linux/fprobe.h>
> > +#include <linux/module.h>
> > +#include <linux/rculist.h>
> > +#include <linux/security.h>
> > +#include <linux/uaccess.h>
> > +
> > +#include "trace_dynevent.h"
> > +#include "trace_probe.h"
> > +#include "trace_probe_kernel.h"
> > +#include "trace_probe_tmpl.h"
> > +
> > +#define FPROBE_EVENT_SYSTEM "fprobes"
> > +#define RETHOOK_MAXACTIVE_MAX 4096
> > +
> > +static int trace_fprobe_create(const char *raw_command);
> > +static int trace_fprobe_show(struct seq_file *m, struct dyn_event *ev);
> > +static int trace_fprobe_release(struct dyn_event *ev);
> > +static bool trace_fprobe_is_busy(struct dyn_event *ev);
> > +static bool trace_fprobe_match(const char *system, const char *event,
> > +			int argc, const char **argv, struct dyn_event *ev);
> > +
> > +static struct dyn_event_operations trace_fprobe_ops = {
> > +	.create = trace_fprobe_create,
> > +	.show = trace_fprobe_show,
> > +	.is_busy = trace_fprobe_is_busy,
> > +	.free = trace_fprobe_release,
> > +	.match = trace_fprobe_match,
> > +};
> > +
> > +/*
> > + * Fprobe event core functions
> > + */
> > +struct trace_fprobe {
> > +	struct dyn_event	devent;
> > +	struct fprobe		fp;
> > +	const char		*symbol;
> > +	struct trace_probe	tp;
> > +};
> > +
> > +static bool is_trace_fprobe(struct dyn_event *ev)
> > +{
> > +	return ev->ops == &trace_fprobe_ops;
> > +}
> > +
> > +static struct trace_fprobe *to_trace_fprobe(struct dyn_event *ev)
> > +{
> > +	return container_of(ev, struct trace_fprobe, devent);
> > +}
> > +
> > +/**
> > + * for_each_trace_fprobe - iterate over the trace_fprobe list
> > + * @pos:	the struct trace_fprobe * for each entry
> > + * @dpos:	the struct dyn_event * to use as a loop cursor
> > + */
> > +#define for_each_trace_fprobe(pos, dpos)	\
> > +	for_each_dyn_event(dpos)		\
> > +		if (is_trace_fprobe(dpos) && (pos = to_trace_fprobe(dpos)))
> > +
> > +static bool trace_fprobe_is_return(struct trace_fprobe *tf)
> > +{
> > +	return tf->fp.exit_handler != NULL;
> > +}
> > +
> > +static const char *trace_fprobe_symbol(struct trace_fprobe *tf)
> > +{
> > +	return tf->symbol ? tf->symbol : "unknown";
> > +}
> > +
> > +static bool trace_fprobe_is_busy(struct dyn_event *ev)
> > +{
> > +	struct trace_fprobe *tf = to_trace_fprobe(ev);
> > +
> > +	return trace_probe_is_enabled(&tf->tp);
> > +}
> > +
> > +static bool trace_fprobe_match_command_head(struct trace_fprobe *tf,
> > +					    int argc, const char **argv)
> > +{
> > +	char buf[MAX_ARGSTR_LEN + 1];
> > +
> > +	if (!argc)
> > +		return true;
> > +
> > +	snprintf(buf, sizeof(buf), "%s", trace_fprobe_symbol(tf));
> > +	if (strcmp(buf, argv[0]))
> > +		return false;
> > +	argc--; argv++;
> > +
> > +	return trace_probe_match_command_args(&tf->tp, argc, argv);
> > +}
> > +
> > +static bool trace_fprobe_match(const char *system, const char *event,
> > +			int argc, const char **argv, struct dyn_event *ev)
> > +{
> > +	struct trace_fprobe *tf = to_trace_fprobe(ev);
> > +
> > +	return (event[0] == '\0' ||
> > +		strcmp(trace_probe_name(&tf->tp), event) == 0) &&
> > +	    (!system || strcmp(trace_probe_group_name(&tf->tp), system) == 0) &&
> > +	    trace_fprobe_match_command_head(tf, argc, argv);
> 
> The above is really hard to read, and Linus hates these kinds of
> statements. Please break it up (the compiler should do the right thing).
> 
> Reversing the tests to return false:
> 
> 	if (event[0] != '\0' &&
> 	    strcmp(trace_probe_name(&tf->tp), event) != 0))
> 		return false;
> 
> 	if (system && strcmp(trace_probe_group_name(&tf->tp), system) != 0))
> 		return false;
> 
> 	return trace_fprobe_match_command_head(tf, argc, argv);
> 

OK, I'll clean it up.

> 
> > +}
> > +
> > +static bool trace_fprobe_is_registered(struct trace_fprobe *tf)
> > +{
> > +	return fprobe_is_registered(&tf->fp);
> > +}
> > +
> > +/* Note that we don't verify it, since the code does not come from user space */
> 
> Verify what?
> 
> Hmm, I see this is a copy of the comment from both trace_kprobe.c and
> trace_uprobe.c. I think this requires a bit more explanation (and also in
> those locations as well).

Yeah, sorry about this comment. I meant that this fetch process (will run
on probe handlers) did not verify the fetch_insn code because it should be
generated by parser.

/*
 * Note that we don't verify the fetch_insn code, since it does not come
 * from user space.
 */

> 
> > +static int
> > +process_fetch_insn(struct fetch_insn *code, void *rec, void *dest,
> > +		   void *base)
> > +{
> > +	struct pt_regs *regs = rec;
> > +	unsigned long val;
> > +
> > +retry:
> > +	/* 1st stage: get value from context */
> > +	switch (code->op) {
> > +	case FETCH_OP_REG:
> > +		val = regs_get_register(regs, code->param);
> > +		break;
> > +	case FETCH_OP_STACK:
> > +		val = regs_get_kernel_stack_nth(regs, code->param);
> > +		break;
> > +	case FETCH_OP_STACKP:
> > +		val = kernel_stack_pointer(regs);
> > +		break;
> > +	case FETCH_OP_RETVAL:
> > +		val = regs_return_value(regs);
> > +		break;
> 
> 
> > +	case FETCH_OP_IMM:
> > +		val = code->immediate;
> > +		break;
> > +	case FETCH_OP_COMM:
> > +		val = (unsigned long)current->comm;
> > +		break;
> > +	case FETCH_OP_DATA:
> > +		val = (unsigned long)code->data;
> > +		break;
> 
> These are new and not part of trace_kprobe.c. Should we have a version that
> the two could share?

Oh, I remember that I missed one series which did that.

https://lore.kernel.org/lkml/20230103223202.7963bfb62b4ae5827e51ee30@kernel.org/T/

Let's pick it.

> 
> Probably a helper function that can be called by these two.
> 
> > +#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
> > +	case FETCH_OP_ARG:
> > +		val = regs_get_kernel_argument(regs, code->param);
> > +		break;
> > +#endif
> > +	case FETCH_NOP_SYMBOL:	/* Ignore a place holder */
> > +		code++;
> > +		goto retry;
> > +	default:
> > +		return -EILSEQ;
> > +	}
> > +	code++;
> > +
> > +	return process_fetch_insn_bottom(code, val, dest, base);
> > +}
> > +NOKPROBE_SYMBOL(process_fetch_insn)
> > +
> > +/* function entry handler */
> > +static nokprobe_inline void
> > +__fentry_trace_func(struct trace_fprobe *tf, unsigned long entry_ip,
> > +		    struct pt_regs *regs,
> > +		    struct trace_event_file *trace_file)
> > +{
> > +	struct fentry_trace_entry_head *entry;
> > +	struct trace_event_call *call = trace_probe_event_call(&tf->tp);
> > +	struct trace_event_buffer fbuffer;
> > +	int dsize;
> > +
> > +	WARN_ON(call != trace_file->event_call);
> 
>  WARN_ON_ONCE()?
> 
> And if you are doing the check, perhaps even:
> 
> 	if (WARN_ON_ONCE(call != trace_file->event_call))
> 		return;

OK.

Thank you!

> 
> -- Steve
> 
> > +
> > +	if (trace_trigger_soft_disabled(trace_file))
> > +		return;
> > +
> > +	dsize = __get_data_size(&tf->tp, regs);
> > +
> > +	entry = trace_event_buffer_reserve(&fbuffer, trace_file,
> > +					   sizeof(*entry) + tf->tp.size + dsize);
> > +	if (!entry)
> > +		return;
> > +
> > +	fbuffer.regs = regs;
> > +	entry = fbuffer.entry = ring_buffer_event_data(fbuffer.event);
> > +	entry->ip = entry_ip;
> > +	store_trace_args(&entry[1], &tf->tp, regs, sizeof(*entry), dsize);
> > +
> > +	trace_event_buffer_commit(&fbuffer);
> > +}
> > +


-- 
Masami Hiramatsu (Google) <mhiramat@kernel.org>

  reply	other threads:[~2023-05-09 15:08 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-05-02  2:17 [PATCH v9.1 00/11] tracing: Add fprobe/tracepoint events Masami Hiramatsu (Google)
2023-05-02  2:17 ` [PATCH v9.1 01/11] fprobe: Pass return address to the handlers Masami Hiramatsu (Google)
2023-05-05 15:21   ` Steven Rostedt
2023-05-09 14:51     ` Masami Hiramatsu
2023-05-02  2:17 ` [PATCH v9.1 02/11] tracing/probes: Add fprobe events for tracing function entry and exit Masami Hiramatsu (Google)
2023-05-05 16:12   ` Steven Rostedt
2023-05-09 15:08     ` Masami Hiramatsu [this message]
2023-05-02  2:17 ` [PATCH v9.1 03/11] selftests/ftrace: Add fprobe related testcases Masami Hiramatsu (Google)
2023-05-02  2:17 ` [PATCH v9.1 04/11] tracing/probes: Add tracepoint support on fprobe_events Masami Hiramatsu (Google)
2023-05-02  2:18 ` [PATCH v9.1 05/11] tracing/probes: Move event parameter fetching code to common parser Masami Hiramatsu (Google)
2023-05-05 21:40   ` Steven Rostedt
2023-05-14  4:11     ` Masami Hiramatsu
2023-05-02  2:18 ` [PATCH v9.1 06/11] tracing/probes: Support function parameters if BTF is available Masami Hiramatsu (Google)
2023-05-02  2:18 ` [PATCH v9.1 07/11] tracing/probes: Add $$args meta argument for all function args Masami Hiramatsu (Google)
2023-05-05 21:48   ` Steven Rostedt
2023-05-14  3:02     ` Masami Hiramatsu
2023-05-02  2:18 ` [PATCH v9.1 08/11] tracing/probes: Add BTF retval type support Masami Hiramatsu (Google)
2023-05-02  2:18 ` [PATCH v9.1 09/11] selftests/ftrace: Add tracepoint probe test case Masami Hiramatsu (Google)
2023-05-02  2:18 ` [PATCH v9.1 10/11] selftests/ftrace: Add BTF arguments test cases Masami Hiramatsu (Google)
2023-05-02  2:18 ` [PATCH v9.1 11/11] Documentation: tracing/probes: Add fprobe event tracing document Masami Hiramatsu (Google)
2023-05-05 15:20   ` Steven Rostedt
2023-05-09 14:58     ` 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=20230510000839.0d223bfd5ba9e556f302596d@kernel.org \
    --to=mhiramat@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-trace-kernel@vger.kernel.org \
    --cc=mark.rutland@arm.com \
    --cc=martin.lau@linux.dev \
    --cc=mathieu.desnoyers@efficios.com \
    --cc=revest@chromium.org \
    --cc=rostedt@goodmis.org \
    --cc=will@kernel.org \
    /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