tracing/fprobe: Support raw tracepoint events on modules

Support raw tracepoint event on module by fprobe events.
Since it only uses for_each_kernel_tracepoint() to find a tracepoint,
the tracepoints on modules are not handled. Thus if user specified a
tracepoint on a module, it shows an error.
This adds new for_each_module_tracepoint() API to tracepoint subsystem,
and uses it to find tracepoints on modules.

Link: https://lore.kernel.org/all/172397779651.286558.15903703620679186867.stgit@devnote2/Reported-by: default avatardon <zds100@gmail.com>
Closes: https://lore.kernel.org/all/20240530215718.aeec973a1d0bf058d39cb1e3@kernel.org/Signed-off-by: default avatarMasami Hiramatsu (Google) <mhiramat@kernel.org>
parent d4df54f3
...@@ -385,6 +385,7 @@ static struct trace_fprobe *alloc_trace_fprobe(const char *group, ...@@ -385,6 +385,7 @@ static struct trace_fprobe *alloc_trace_fprobe(const char *group,
const char *event, const char *event,
const char *symbol, const char *symbol,
struct tracepoint *tpoint, struct tracepoint *tpoint,
struct module *mod,
int maxactive, int maxactive,
int nargs, bool is_return) int nargs, bool is_return)
{ {
...@@ -405,6 +406,7 @@ static struct trace_fprobe *alloc_trace_fprobe(const char *group, ...@@ -405,6 +406,7 @@ static struct trace_fprobe *alloc_trace_fprobe(const char *group,
tf->fp.entry_handler = fentry_dispatcher; tf->fp.entry_handler = fentry_dispatcher;
tf->tpoint = tpoint; tf->tpoint = tpoint;
tf->mod = mod;
tf->fp.nr_maxactive = maxactive; tf->fp.nr_maxactive = maxactive;
ret = trace_probe_init(&tf->tp, event, group, false, nargs); ret = trace_probe_init(&tf->tp, event, group, false, nargs);
...@@ -895,8 +897,23 @@ static struct notifier_block tracepoint_module_nb = { ...@@ -895,8 +897,23 @@ static struct notifier_block tracepoint_module_nb = {
struct __find_tracepoint_cb_data { struct __find_tracepoint_cb_data {
const char *tp_name; const char *tp_name;
struct tracepoint *tpoint; struct tracepoint *tpoint;
struct module *mod;
}; };
static void __find_tracepoint_module_cb(struct tracepoint *tp, struct module *mod, void *priv)
{
struct __find_tracepoint_cb_data *data = priv;
if (!data->tpoint && !strcmp(data->tp_name, tp->name)) {
data->tpoint = tp;
data->mod = mod;
if (!try_module_get(data->mod)) {
data->tpoint = NULL;
data->mod = NULL;
}
}
}
static void __find_tracepoint_cb(struct tracepoint *tp, void *priv) static void __find_tracepoint_cb(struct tracepoint *tp, void *priv)
{ {
struct __find_tracepoint_cb_data *data = priv; struct __find_tracepoint_cb_data *data = priv;
...@@ -905,14 +922,28 @@ static void __find_tracepoint_cb(struct tracepoint *tp, void *priv) ...@@ -905,14 +922,28 @@ static void __find_tracepoint_cb(struct tracepoint *tp, void *priv)
data->tpoint = tp; data->tpoint = tp;
} }
static struct tracepoint *find_tracepoint(const char *tp_name) /*
* Find a tracepoint from kernel and module. If the tracepoint is in a module,
* this increments the module refcount to prevent unloading until the
* trace_fprobe is registered to the list. After registering the trace_fprobe
* on the trace_fprobe list, the module refcount is decremented because
* tracepoint_probe_module_cb will handle it.
*/
static struct tracepoint *find_tracepoint(const char *tp_name,
struct module **tp_mod)
{ {
struct __find_tracepoint_cb_data data = { struct __find_tracepoint_cb_data data = {
.tp_name = tp_name, .tp_name = tp_name,
.mod = NULL,
}; };
for_each_kernel_tracepoint(__find_tracepoint_cb, &data); for_each_kernel_tracepoint(__find_tracepoint_cb, &data);
if (!data.tpoint && IS_ENABLED(CONFIG_MODULES)) {
for_each_module_tracepoint(__find_tracepoint_module_cb, &data);
*tp_mod = data.mod;
}
return data.tpoint; return data.tpoint;
} }
...@@ -996,6 +1027,7 @@ static int __trace_fprobe_create(int argc, const char *argv[]) ...@@ -996,6 +1027,7 @@ static int __trace_fprobe_create(int argc, const char *argv[])
char abuf[MAX_BTF_ARGS_LEN]; char abuf[MAX_BTF_ARGS_LEN];
char *dbuf = NULL; char *dbuf = NULL;
bool is_tracepoint = false; bool is_tracepoint = false;
struct module *tp_mod = NULL;
struct tracepoint *tpoint = NULL; struct tracepoint *tpoint = NULL;
struct traceprobe_parse_context ctx = { struct traceprobe_parse_context ctx = {
.flags = TPARG_FL_KERNEL | TPARG_FL_FPROBE, .flags = TPARG_FL_KERNEL | TPARG_FL_FPROBE,
...@@ -1080,7 +1112,7 @@ static int __trace_fprobe_create(int argc, const char *argv[]) ...@@ -1080,7 +1112,7 @@ static int __trace_fprobe_create(int argc, const char *argv[])
if (is_tracepoint) { if (is_tracepoint) {
ctx.flags |= TPARG_FL_TPOINT; ctx.flags |= TPARG_FL_TPOINT;
tpoint = find_tracepoint(symbol); tpoint = find_tracepoint(symbol, &tp_mod);
if (!tpoint) { if (!tpoint) {
trace_probe_log_set_index(1); trace_probe_log_set_index(1);
trace_probe_log_err(0, NO_TRACEPOINT); trace_probe_log_err(0, NO_TRACEPOINT);
...@@ -1110,8 +1142,8 @@ static int __trace_fprobe_create(int argc, const char *argv[]) ...@@ -1110,8 +1142,8 @@ static int __trace_fprobe_create(int argc, const char *argv[])
goto out; goto out;
/* setup a probe */ /* setup a probe */
tf = alloc_trace_fprobe(group, event, symbol, tpoint, maxactive, tf = alloc_trace_fprobe(group, event, symbol, tpoint, tp_mod,
argc, is_return); maxactive, argc, is_return);
if (IS_ERR(tf)) { if (IS_ERR(tf)) {
ret = PTR_ERR(tf); ret = PTR_ERR(tf);
/* This must return -ENOMEM, else there is a bug */ /* This must return -ENOMEM, else there is a bug */
...@@ -1119,10 +1151,6 @@ static int __trace_fprobe_create(int argc, const char *argv[]) ...@@ -1119,10 +1151,6 @@ static int __trace_fprobe_create(int argc, const char *argv[])
goto out; /* We know tf is not allocated */ goto out; /* We know tf is not allocated */
} }
if (is_tracepoint)
tf->mod = __module_text_address(
(unsigned long)tf->tpoint->probestub);
/* parse arguments */ /* parse arguments */
for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) { for (i = 0; i < argc && i < MAX_TRACE_ARGS; i++) {
trace_probe_log_set_index(i + 2); trace_probe_log_set_index(i + 2);
...@@ -1155,6 +1183,8 @@ static int __trace_fprobe_create(int argc, const char *argv[]) ...@@ -1155,6 +1183,8 @@ static int __trace_fprobe_create(int argc, const char *argv[])
} }
out: out:
if (tp_mod)
module_put(tp_mod);
traceprobe_finish_parse(&ctx); traceprobe_finish_parse(&ctx);
trace_probe_log_clear(); trace_probe_log_clear();
kfree(new_argv); kfree(new_argv);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment