From: Tom Zanussi <zanussi@kernel.org>
To: rostedt@goodmis.org
Cc: artem.bityutskiy@linux.intel.com, mhiramat@kernel.org,
linux-kernel@vger.kernel.org, linux-rt-users@vger.kernel.org
Subject: [PATCH v2 10/12] tracing: Add kprobe event command generation functions
Date: Fri, 10 Jan 2020 14:35:16 -0600 [thread overview]
Message-ID: <5f052546541d6cc5ad00e28aca6376c221db5c7e.1578688120.git.zanussi@kernel.org> (raw)
In-Reply-To: <cover.1578688120.git.zanussi@kernel.org>
In-Reply-To: <cover.1578688120.git.zanussi@kernel.org>
Add functions used to generate kprobe event commands, built on top of
the dynevent_cmd interface.
gen_kprobe_cmd() is used to create a kprobe event command using a
variable arg list. add_probe_fields() can be used to add single
fields one by one or as a group. Once all desired fields are added,
create_dynevent() is used to actually execute the command and create
the event.
gen_kprobe_cmd() can be used to create kretprobe commands as well.
Signed-off-by: Tom Zanussi <zanussi@kernel.org>
---
include/linux/trace_events.h | 18 +++++
kernel/trace/trace_kprobe.c | 161 ++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 177 insertions(+), 2 deletions(-)
diff --git a/include/linux/trace_events.h b/include/linux/trace_events.h
index c25b18db84eb..7ae9ad182b0e 100644
--- a/include/linux/trace_events.h
+++ b/include/linux/trace_events.h
@@ -464,6 +464,24 @@ extern int add_synth_val(const char *field_name, u64 val,
struct synth_gen_state *gen_state);
extern int trace_synth_event_end(struct synth_gen_state *gen_state);
+extern void kprobe_dynevent_cmd_init(struct dynevent_cmd *cmd,
+ char *buf, int maxlen);
+
+#define gen_kprobe_cmd(cmd, name, loc, ...) \
+ __gen_kprobe_cmd(cmd, name, loc, false, ## __VA_ARGS__, NULL)
+
+#define gen_kretprobe_cmd(cmd, name, loc, ...) \
+ __gen_kprobe_cmd(cmd, name, loc, true, ## __VA_ARGS__, NULL)
+
+extern int __gen_kprobe_cmd(struct dynevent_cmd *cmd, const char *name,
+ const char *loc, bool kretprobe, ...);
+
+#define add_probe_fields(cmd, ...) \
+ __add_probe_fields(cmd, ## __VA_ARGS__, NULL)
+
+extern int __add_probe_fields(struct dynevent_cmd *cmd, ...);
+extern int delete_kprobe_event(const char *name);
+
/*
* Event file flags:
* ENABLED - The event is enabled
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 25dac3745afb..f911b3d74b46 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -902,11 +902,168 @@ static int create_or_delete_trace_kprobe(int argc, char **argv)
return ret == -ECANCELED ? -EINVAL : ret;
}
-int trace_kprobe_run_command(const char *command)
+static int trace_kprobe_run_command(struct dynevent_cmd *cmd)
{
- return trace_run_command(command, create_or_delete_trace_kprobe);
+ return trace_run_command(cmd->buf, create_or_delete_trace_kprobe);
}
+/**
+ * kprobe_dynevent_cmd_init - Initialize a kprobe event command object
+ * @cmd: A pointer to the dynevent_cmd struct representing the new event
+ * @buf: A pointer to the buffer used to build the command
+ * @maxlen: The length of the buffer passed in @buf
+ *
+ * Initialize a synthetic event command object. Use this before
+ * calling any of the other dyenvent_cmd functions.
+ */
+void kprobe_dynevent_cmd_init(struct dynevent_cmd *cmd, char *buf, int maxlen)
+{
+ dynevent_cmd_init(cmd, buf, maxlen, DYNEVENT_TYPE_KPROBE,
+ trace_kprobe_run_command);
+}
+EXPORT_SYMBOL_GPL(kprobe_dynevent_cmd_init);
+
+/**
+ * __gen_kprobe_cmd - Generate a synthetic event command from arg list
+ * @cmd: A pointer to the dynevent_cmd struct representing the new event
+ * @name: The name of the kprobe event
+ * @loc: The location of the kprobe event
+ * @kretprobe: Is this a return probe?
+ * @args: Variable number of arg (pairs), one pair for each field
+ *
+ * NOTE: Users normally won't want to call this function directly, but
+ * rather use the gen_kprobe_cmd() wrapper, which automatically adds a
+ * NULL to the end of the arg list. If this function is used
+ * directly, make suer he last arg in the variable arg list is NULL.
+ *
+ * Generate a kprobe event command to be executed by
+ * create_dynevent(). This function can be used to generate the
+ * complete command or only the first part of it; in the latter case,
+ * add_probe_fields() can be used to add more fields following this.
+ *
+ * Return: 0 if successful, error otherwise.
+ */
+int __gen_kprobe_cmd(struct dynevent_cmd *cmd, const char *name,
+ const char *loc, bool kretprobe, ...)
+{
+ char buf[MAX_EVENT_NAME_LEN];
+ struct dynevent_arg arg;
+ va_list args;
+ int ret;
+
+ if (cmd->type != DYNEVENT_TYPE_KPROBE)
+ return -EINVAL;
+
+ if (kretprobe)
+ snprintf(buf, MAX_EVENT_NAME_LEN, "r:%s", name);
+ else
+ snprintf(buf, MAX_EVENT_NAME_LEN, "p:%s", name);
+
+ dynevent_arg_init(&arg, NULL, 0);
+ arg.str = buf;
+ ret = add_dynevent_arg(cmd, &arg);
+ if (ret)
+ return ret;
+
+ dynevent_arg_init(&arg, NULL, 0);
+ arg.str = loc;
+ ret = add_dynevent_arg(cmd, &arg);
+ if (ret)
+ return ret;
+
+ va_start(args, kretprobe);
+ for (;;) {
+ const char *field;
+
+ field = va_arg(args, const char *);
+ if (!field)
+ break;
+
+ if (++cmd->n_fields > MAX_TRACE_ARGS) {
+ ret = -EINVAL;
+ break;
+ }
+
+ dynevent_arg_init(&arg, NULL, 0);
+ arg.str = field;
+ ret = add_dynevent_arg(cmd, &arg);
+ if (ret)
+ break;
+ }
+ va_end(args);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(__gen_kprobe_cmd);
+
+/**
+ * __add_probe_fields - Add probe fields to a kprobe command from arg list
+ * @cmd: A pointer to the dynevent_cmd struct representing the new event
+ * @args: Variable number of arg (pairs), one pair for each field
+ *
+ * NOTE: Users normally won't want to call this function directly, but
+ * rather use the add_probe_fields() wrapper, which automatically adds a
+ * NULL to the end of the arg list. If this function is used
+ * directly, make suer he last arg in the variable arg list is NULL.
+ *
+ * Add probe fields to an existing kprobe command using a variable
+ * list of args. Fields are added in the same order they're listed.
+ *
+ * Return: 0 if successful, error otherwise.
+ */
+int __add_probe_fields(struct dynevent_cmd *cmd, ...)
+{
+ struct dynevent_arg arg;
+ va_list args;
+ int ret;
+
+ if (cmd->type != DYNEVENT_TYPE_KPROBE)
+ return -EINVAL;
+
+ va_start(args, cmd);
+ for (;;) {
+ const char *field;
+
+ field = va_arg(args, const char *);
+ if (!field)
+ break;
+
+ if (++cmd->n_fields > MAX_TRACE_ARGS) {
+ ret = -EINVAL;
+ break;
+ }
+
+ dynevent_arg_init(&arg, NULL, 0);
+ arg.str = field;
+ ret = add_dynevent_arg(cmd, &arg);
+ if (ret)
+ break;
+ }
+ va_end(args);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(__add_probe_fields);
+
+/**
+ * delete_kprobe_event - Delete a kprobe event
+ * @name: The name of the kprobe event to delete
+ *
+ * Delete a kprobe event with the give @name from kernel code rather
+ * than directly from the command line.
+ *
+ * Return: 0 if successful, error otherwise.
+ */
+int delete_kprobe_event(const char *name)
+{
+ char buf[MAX_EVENT_NAME_LEN];
+
+ snprintf(buf, MAX_EVENT_NAME_LEN, "-:%s", name);
+
+ return trace_run_command(buf, create_or_delete_trace_kprobe);
+}
+EXPORT_SYMBOL_GPL(delete_kprobe_event);
+
static int trace_kprobe_release(struct dyn_event *ev)
{
struct trace_kprobe *tk = to_trace_kprobe(ev);
--
2.14.1
next prev parent reply other threads:[~2020-01-10 20:35 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-01-10 20:35 [PATCH v2 00/12] tracing: Add support for in-kernel dynamic event API Tom Zanussi
2020-01-10 20:35 ` [PATCH v2 01/12] tracing: Add trace_array_find() to find instance trace arrays Tom Zanussi
2020-01-10 20:35 ` [PATCH v2 02/12] tracing: Add get/put_event_file() Tom Zanussi
2020-01-13 13:15 ` Masami Hiramatsu
2020-01-13 15:15 ` Tom Zanussi
2020-01-10 20:35 ` [PATCH v2 03/12] tracing: Add delete_synth_event() Tom Zanussi
2020-01-10 20:35 ` [PATCH v2 04/12] tracing: Add dynamic event command creation interface Tom Zanussi
2020-01-14 12:14 ` Masami Hiramatsu
2020-01-14 15:19 ` Tom Zanussi
2020-01-10 20:35 ` [PATCH v2 05/12] tracing: Add synth_event_run_command() Tom Zanussi
2020-01-21 16:53 ` Steven Rostedt
2020-01-10 20:35 ` [PATCH v2 06/12] tracing: Add synthetic event command generation functions Tom Zanussi
2020-01-21 16:57 ` Steven Rostedt
2020-01-21 19:20 ` Tom Zanussi
2020-01-10 20:35 ` [PATCH v2 07/12] tracing: Add trace_synth_event() and related functions Tom Zanussi
2020-01-21 17:03 ` Steven Rostedt
2020-01-21 19:22 ` Tom Zanussi
2020-01-10 20:35 ` [PATCH v2 08/12] tracing: Add synth event generation test module Tom Zanussi
2020-01-10 20:35 ` [PATCH v2 09/12] tracing: Add trace_kprobe_run_command() Tom Zanussi
2020-01-10 20:35 ` Tom Zanussi [this message]
2020-01-10 20:35 ` [PATCH v2 11/12] tracing: Add kprobe event command generation test module Tom Zanussi
2020-01-10 20:35 ` [PATCH v2 12/12] tracing: Documentation for in-kernel synthetic event API Tom Zanussi
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=5f052546541d6cc5ad00e28aca6376c221db5c7e.1578688120.git.zanussi@kernel.org \
--to=zanussi@kernel.org \
--cc=artem.bityutskiy@linux.intel.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-rt-users@vger.kernel.org \
--cc=mhiramat@kernel.org \
--cc=rostedt@goodmis.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;
as well as URLs for NNTP newsgroup(s).