tracing: tprobe-events: Fixes for tprobe events
Masami Hiramatsu (Google)
maintainercover tracing: tprobe-events: Fixes for tprobe events
Hi,
Beau reported tprobe example in the document does not work on 6.17 kernel.
---
echo "t sched_switch preempt prev_pid=prev->pid next_pid=next->pid" > /sys/kernel/tracing/dynamic_events echo 1 > /sys/kernel/tracing/events/tracepoints/sched_switch/enable
cat /sys/kernel/tracing/trace_pipe
---
It seems that the tracepoint callback is not correctly set. So I tried to trace the actual function calls and the local variables. (I need to enable CONFIG_KPROBE_EVENTS_ON_NOTRACE for tracing ftrace code itself.)
With the below commands, I got some probe definitions for debug:
$ perf probe -k vmlinux -D "tracepoint_user_find_get name:string" $ perf probe -k vmlinux -D '__regsiter_tracepoint_fprobe:13 tuser tuser->tpoint' $ perf probe -k vmlinux -D 'register_fprobe_ips addrs[1]' $ perf probe -k vmlinux -D 'register_fprobe_ips%return ret=$retval' $ perf probe -k vmlinux -D '__regsiter_tracepoint_fprobe tf->tprobe' $ perf probe -k vmlinux -D 'tracepoint_probe_register_prio_may_exist tp' $ perf probe -k vmlinux -D 'tracepoint_probe_register_prio_may_exist%return ret=$retval' $ perf probe -k vmlinux -D '__tracepoint_user_init name:string'
And run below commands on the machine:
-----
$ cat > /sys/kernel/tracing/dynamic_events << EOF p:probe/tracepoint_user_find_get enable_trace_fprobe+271 name_string=+0(%bp):string p:probe/regsiter_tracepoint_fprobe_L13 enable_trace_fprobe+692 tuser=%r13 tpoint=+24(%r13) p:probe/regsiter_tracepoint_fprobe_L13_1 enable_trace_fprobe+685 tuser=%r13 tpoint=+24(%r13) p:probe/register_fprobe_ips register_fprobe_ips+0 addrs=+8(%si):u64 r:probe/register_fprobe_ips__return register_fprobe_ips+0 ret=\$retval p:probe/regsiter_tracepoint_fprobe enable_trace_fprobe+247 tprobe=+80(-96(%r14)):u8 p:probe/tracepoint_probe_register_prio_may_exist tracepoint_probe_register_prio_may_exist+0 tp=%di r:probe/tracepoint_probe_register_prio_may_exist__return tracepoint_probe_register_prio_may_exist+0 ret=\$retval p:probe/tracepoint_user_init enable_trace_fprobe+440 name_string=+0(%bp):string EOF $ echo 1 > /sys/kernel/tracing/events/probe/enable
$ echo "t sched_switch preempt prev_pid=prev->pid next_pid=next->pid" >> /sys/kernel/tracing/dynamic_events $ echo 1 > /sys/kernel/tracing/events/tracepoints/sched_switch/enable $ cat /sys/kernel/tracing/trace -----
And I got below trace data:
-----
# TASK-PID CPU# ||||| TIMESTAMP FUNCTION
# | | | ||||| | |
sh-107 [005] ..Zff 7.290496: regsiter_tracepoint_fprobe: (enable_trace_fprobe+0xf7/0x3a0) tprobe=0
sh-107 [005] ..Zff 7.290547: tracepoint_user_find_get: (enable_trace_fprobe+0x10f/0x3a0) name_string="sched_switch"
sh-107 [005] ..Zff 7.290680: tracepoint_user_init: (enable_trace_fprobe+0x1b8/0x3a0) name_string="sched_switch"
sh-107 [005] ..Zff 7.290727: regsiter_tracepoint_fprobe_L13_1: (enable_trace_fprobe+0x2ad/0x3a0) tuser=0xffff88800538b280 tpoint=0xffffffff82a4ac10
sh-107 [005] ..Zff 7.290730: regsiter_tracepoint_fprobe_L13: (enable_trace_fprobe+0x2b4/0x3a0) tuser=0xffff88800538b280 tpoint=0xffffffff82a4ac10
sh-107 [005] ..Zff 7.290735: register_fprobe_ips: (register_fprobe_ips+0x4/0x310) addrs=18446612682157410880
sh-107 [005] ..... 7.311345: register_fprobe_ips__return: (enable_trace_fprobe+0x2f6/0x3a0 <- register_fprobe_ips) ret=0-----
No tracepoint_probe_register_prio_may_exist event is recorded, but tracepoint_user_init and regsiter_tracepoint_fprobe_L13_1 (call-site of tracepoint_user_init()) are recorded and tuser and tpoint are not NULL or error.
This means when the tprobe is enabled, the register_tracepoint_fprobe() eventually calls tracepoint_user_init() correctly. However, it does not call tracepoint_probe_register_prio_may_exist() to register tracepoint callback. So the bug is inside tracepoint_user_init(), not NULL return path.
-----
static struct tracepoint_user *__tracepoint_user_init(const char *name, struct tracepoint *tpoint)
{
struct tracepoint_user *tuser __free(tuser_free) = NULL;
int ret;
tuser = kzalloc(sizeof(*tuser), GFP_KERNEL);
if (!tuser)
return NULL;
tuser->name = kstrdup(name, GFP_KERNEL);
if (!tuser->name)
return NULL;
if (tpoint) {
ret = tracepoint_user_register(tuser); /* forgot to set tuser->tpoint */
if (ret)
return ERR_PTR(ret);
}-----
And found it forgot to set tuser->tpoint before calling tracepoint_user_register() which calls tracepoint_probe_register_prio_may_exist(tuser->tpoint). To fix that, I just moved the tuser->tpoint setting line right before tracepoint_user_register() call [1/2].
I also found another issue when I switched enable and disable[2/2].
I hope this report will help someone to do similar debug by tracing.
Thank you,
---
Masami Hiramatsu (Google) (2):
tracing: tprobe-events: Fix to register tracepoint correctly
tracing: tprobe-events: Fix to put tracepoint_user when disable the tprobe
kernel/trace/trace_fprobe.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
--
Masami Hiramatsu (Google) <[email protected]>
Masami Hiramatsu (Google)
maintainerPATCH 1/2 tracing: tprobe-events: Fix to register tracepoint correctly
From: Masami Hiramatsu (Google) <[email protected]>
Since __tracepoint_user_init() calls tracepoint_user_register() without initializing tuser->tpoint with given tracpoint, it does not register tracepoint stub function as callback correctly, and tprobe does not work.
Initializing tuser->tpoint correctly before tracepoint_user_register() so that it sets up tracepoint callback.
I confirmed below example works fine again.
echo "t sched_switch preempt prev_pid=prev->pid next_pid=next->pid" > /sys/kernel/tracing/dynamic_events echo 1 > /sys/kernel/tracing/events/tracepoints/sched_switch/enable
cat /sys/kernel/tracing/trace_pipe
--- kernel/trace/trace_fprobe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/trace/trace_fprobe.c +2 -1
@@ -106,13 +106,14 @@ static struct tracepoint_user *__tracepoint_user_init(const char *name, struct tif (!tuser->name)return NULL ; +/* Register tracepoint if it is loaded. */ if (tpoint) { + tuser->tpoint = tpoint; ret =tracepoint_user_register (tuser);if (ret)return ERR_PTR (ret); } - tuser->tpoint = tpoint; tuser->refcount =1 ;INIT_LIST_HEAD (&tuser->list);list_add (&tuser->list, &tracepoint_user_list);
Masami Hiramatsu (Google)
maintainerPATCH 2/2 tracing: tprobe-events: Fix to put tracepoint_user when disable the tprobe
In reply to Masami Hiramatsu (Google)From: Masami Hiramatsu (Google) <[email protected]>
__unregister_trace_fprobe() checks tf->tuser to put it when removing tprobe. However, disable_trace_fprobe() does not use it and only calls unregister_fprobe(). Thus it forgets to disable tracepoint_user.
If the trace_fprobe has tuser, put it for unregistering the tracepoint callbacks when disabling tprobe correctly.
--- kernel/trace/trace_fprobe.c | 4 ++++ 1 file changed, 4 insertions(+)
kernel/trace/trace_fprobe.c +4 -0
@@ -1512,6 +1512,10 @@ static int disable_trace_fprobe(struct trace_event_call *call,if (!trace_probe_is_enabled (tp)) {list_for_each_entry (tf,trace_probe_probe_list (tp), tp.list) {unregister_fprobe (&tf->fp); +if (tf->tuser) { +tracepoint_user_put (tf->tuser); + tf->tuser =NULL ; + } } }
Quoted 5 lines · Masami Hiramatsu (Google)
Hi,
Beau reported tprobe example in the document does not work on 6.17 kernel.
Thanks! I've applied this series locally and tested this. Everything works well in our environment.
Quoted 9 lines
And found it forgot to set
tuser->tpointbefore callingtracepoint_user_register()which callstracepoint_probe_register_prio_may_exist(tuser->tpoint). To fix that, I just moved thetuser->tpointsetting line right beforetracepoint_user_register()call [1/2].I also found another issue when I switched enable and disable[2/2].
Thanks! I've validated no bad dmesg, etc. and can delete the tprobe without issues after we disable it.
Quoted 2 lines
I hope this report will help someone to do similar debug by tracing.
I will reference this, it's very useful.
For the series:
Thanks,
-Beau
Quoted 14 lines
Thank you,
---
Masami Hiramatsu (Google) (2):
tracing: tprobe-events: Fix to register tracepoint correctly
tracing: tprobe-events: Fix to puttracepoint_userwhen disable the tprobekernel/trace/trace_fprobe.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)--
Masami Hiramatsu (Google) <[email protected]>
Masami Hiramatsu (Google)
maintainerQuoted 9 lines · On Thu, 6 Nov 2025 17:55:13 +0000 Beau Belgrave <[email protected]>…
Quoted 5 lines · Masami Hiramatsu (Google)
Hi,
Beau reported tprobe example in the document does not work on 6.17 kernel.
Thanks! I've applied this series locally and tested this. Everything works well in our environment.
Great!
Quoted 14 lines
Quoted 10 lines
And found it forgot to set
tuser->tpointbefore callingtracepoint_user_register()which callstracepoint_probe_register_prio_may_exist(tuser->tpoint). To fix that, I just moved thetuser->tpointsetting line right beforetracepoint_user_register()call [1/2].I also found another issue when I switched enable and disable[2/2].
Thanks! I've validated no bad dmesg, etc. and can delete the tprobe without issues after we disable it.
Quoted 8 lines
Quoted 2 lines
I hope this report will help someone to do similar debug by tracing.
I will reference this, it's very useful.
For the series:
Tested-by Beau Belgrave <[email protected]>Reviewed-by Beau Belgrave <[email protected]>
Thanks!
Quoted 17 lines
Thanks,
-BeauQuoted 14 lines
Thank you,
---
Masami Hiramatsu (Google) (2):
tracing: tprobe-events: Fix to register tracepoint correctly
tracing: tprobe-events: Fix to puttracepoint_userwhen disable the tprobekernel/trace/trace_fprobe.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)--
Masami Hiramatsu (Google) <[email protected]>
Signature · 1 line
Masami Hiramatsu (Google) <[email protected]>