* [PATCH] tracing: eprobe: read the complete FILTER_PTR_STRING pointer
@ 2026-06-15 14:54 Martin Kaiser
2026-06-16 2:09 ` Masami Hiramatsu
0 siblings, 1 reply; 2+ messages in thread
From: Martin Kaiser @ 2026-06-15 14:54 UTC (permalink / raw)
To: Steven Rostedt, Masami Hiramatsu
Cc: linux-trace-kernel, linux-kernel, Martin Kaiser
For a char * element in an event, the FILTER_PTR_STRING filter type is
used. When the event occurs, a pointer is stored in the ringbuffer.
If an eprobe references such a char * element of a "base event" and
decodes the pointer as string, the pointer cannot be dereferenced.
$ echo 'e syscalls.sys_enter_openat $filename:string' > \
/sys/kernel/tracing/dynamic_events
$ trace-cmd start -e eprobes
$ trace-cmd show
... : sys_enter_openat: (syscalls.sys_enter_openat) arg1=(fault)
The problem is in get_event_field
val = (unsigned long)(*(char *)addr);
addr points to the position in the ringbuffer where the pointer was
stored. We must read the complete pointer, not just the lowest byte.
Fix the assignment, make the example above work.
Signed-off-by: Martin Kaiser <martin@kaiser.cx>
---
kernel/trace/trace_eprobe.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel/trace/trace_eprobe.c b/kernel/trace/trace_eprobe.c
index b66d6196338d..50518b071414 100644
--- a/kernel/trace/trace_eprobe.c
+++ b/kernel/trace/trace_eprobe.c
@@ -315,7 +315,7 @@ get_event_field(struct fetch_insn *code, void *rec)
val = (unsigned long)addr;
break;
case FILTER_PTR_STRING:
- val = (unsigned long)(*(char *)addr);
+ val = *(unsigned long *)addr;
break;
default:
WARN_ON_ONCE(1);
--
2.43.7
^ permalink raw reply related [flat|nested] 2+ messages in thread* Re: [PATCH] tracing: eprobe: read the complete FILTER_PTR_STRING pointer
2026-06-15 14:54 [PATCH] tracing: eprobe: read the complete FILTER_PTR_STRING pointer Martin Kaiser
@ 2026-06-16 2:09 ` Masami Hiramatsu
0 siblings, 0 replies; 2+ messages in thread
From: Masami Hiramatsu @ 2026-06-16 2:09 UTC (permalink / raw)
To: Martin Kaiser; +Cc: Steven Rostedt, linux-trace-kernel, linux-kernel
On Mon, 15 Jun 2026 16:54:12 +0200
Martin Kaiser <martin@kaiser.cx> wrote:
> For a char * element in an event, the FILTER_PTR_STRING filter type is
> used. When the event occurs, a pointer is stored in the ringbuffer.
>
> If an eprobe references such a char * element of a "base event" and
> decodes the pointer as string, the pointer cannot be dereferenced.
>
> $ echo 'e syscalls.sys_enter_openat $filename:string' > \
> /sys/kernel/tracing/dynamic_events
> $ trace-cmd start -e eprobes
> $ trace-cmd show
> ... : sys_enter_openat: (syscalls.sys_enter_openat) arg1=(fault)
>
> The problem is in get_event_field
>
> val = (unsigned long)(*(char *)addr);
>
> addr points to the position in the ringbuffer where the pointer was
> stored. We must read the complete pointer, not just the lowest byte.
>
> Fix the assignment, make the example above work.
>
Ah, this is a bit complicated. It seems to work with sched_switch event
as commit f04dec93466a ("tracing/eprobes: Fix reading of string fields"):
echo 'e:sw sched/sched_switch comm=$next_comm:string' > dynamic_events
# TASK-PID CPU# ||||| TIMESTAMP FUNCTION
# | | | ||||| | |
sh-162 [002] d..3. 54.027213: sw: (sched.sched_switch) comm="swapper/2"
<idle>-0 [007] d..3. 54.034573: sw: (sched.sched_switch) comm="rcu_preempt"
rcu_preempt-15 [007] d..3. 54.034589: sw: (sched.sched_switch) comm="swapper/7"
Maybe comm is stored as a fixed string information in the event record?
/sys/kernel/tracing # cat events/sched/sched_switch/format
name: sched_switch
ID: 254
format:
field:unsigned short common_type; offset:0; size:2; signed:0;
field:unsigned char common_flags; offset:2; size:1; signed:0;
field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
field:int common_pid; offset:4; size:4; signed:1;
field:char prev_comm[16]; offset:8; size:16; signed:0;
field:pid_t prev_pid; offset:24; size:4; signed:1;
field:int prev_prio; offset:28; size:4; signed:1;
field:long prev_state; offset:32; size:8; signed:1;
field:char next_comm[16]; offset:40; size:16; signed:0;
field:pid_t next_pid; offset:56; size:4; signed:1;
field:int next_prio; offset:60; size:4; signed:1;
But the filename is a pointer.
/sys/kernel/tracing # cat events/syscalls/sys_enter_openat/format
name: sys_enter_openat
ID: 705
format:
field:unsigned short common_type; offset:0; size:2; signed:0;
field:unsigned char common_flags; offset:2; size:1; signed:0;
field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
field:int common_pid; offset:4; size:4; signed:1;
field:int __syscall_nr; offset:8; size:4; signed:1;
field:int dfd; offset:16; size:8; signed:0;
field:const char * filename; offset:24; size:8; signed:0;
field:int flags; offset:32; size:8; signed:0;
field:umode_t mode; offset:40; size:8; signed:0;
field:__data_loc char[] __filename_val; offset:48; size:4; signed:0;
In this case, the filename field should use __data_loc directly instead of
pointing data on the ring buffer.
Can you try
echo 'e syscalls.sys_enter_openat $__filename_val:string' > \
/sys/kernel/tracing/dynamic_events
Instead?
I think better solution is fixing sycall tracer.
Thanks,
--
Masami Hiramatsu (Google) <mhiramat@kernel.org>
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-06-16 2:09 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-15 14:54 [PATCH] tracing: eprobe: read the complete FILTER_PTR_STRING pointer Martin Kaiser
2026-06-16 2:09 ` Masami Hiramatsu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox