Support stacktrace with dynamic event
v2 cover Support stacktrace with dynamic event
Hi,
Here is the stacktrace support with dynamic event tracer.
This series also includes save_stack_trace_regs() API cleanup and an weak symbol for the arch which doesn't support it.
Thank you,
---
Masami Hiramatsu (3):
[BUGFIX]tracing/kprobes: Fix kprobe-tracer to support stack trace Add weak save_stack_trace_regs()
[CLEANUP]x86: Swap save_stack_trace_regs parameters
arch/x86/kernel/stacktrace.c | 2 +- arch/x86/mm/kmemcheck/error.c | 2 +- include/linux/ftrace_event.h | 4 ++++ include/linux/stacktrace.h | 4 ++-- kernel/stacktrace.c | 13 ++++++++++--- kernel/trace/trace.c | 35 ++++++++++++++++++++++++++++++----- kernel/trace/trace.h | 9 +++++++++ kernel/trace/trace_kprobe.c | 6 ++++-- 8 files changed, 61 insertions(+), 14 deletions(-)
Signature · 4 lines
Masami HIRAMATSU Software Platform Research Dept. Linux Technology Center Hitachi, Ltd., Yokohama Research Laboratory E-mail: [email protected]
PATCH v2 1/3 x86: Swap save_stack_trace_regs parameters
Swap the 1st and 2nd parameters of save_stack_trace_regs() as same as the parameters of save_stack_trace_tsk().
---
arch/x86/kernel/stacktrace.c | 2 +- arch/x86/mm/kmemcheck/error.c | 2 +- include/linux/stacktrace.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-)
arch/x86/kernel/stacktrace.c +1 -1
@@ -66,7 +66,7 @@ void save_stack_trace(struct stack_trace *trace) }EXPORT_SYMBOL_GPL (save_stack_trace); -void save_stack_trace_regs (struct stack_trace *trace,struct pt_regs *regs) +void save_stack_trace_regs (struct pt_regs *regs,struct stack_trace *trace) {dump_trace (current, regs,NULL ,0 , &save_stack_ops, trace);if (trace->nr_entries < trace->max_entries)
arch/x86/mm/kmemcheck/error.c +1 -1
@@ -185,7 +185,7 @@ void kmemcheck_error_save(enum kmemcheck_shadow state, e->trace.entries = e->trace_entries; e->trace.max_entries =ARRAY_SIZE (e->trace_entries); e->trace.skip =0 ; -save_stack_trace_regs (&e->trace, regs); +save_stack_trace_regs (regs, &e->trace);/* Round address down to nearest 16 bytes */ shadow_copy = kmemcheck_shadow_lookup(address
include/linux/stacktrace.h +2 -2
@@ -14,8 +14,8 @@ struct stack_trace { };extern void save_stack_trace (struct stack_trace *trace); -extern void save_stack_trace_regs (struct stack_trace *trace, -struct pt_regs *regs); +extern void save_stack_trace_regs (struct pt_regs *regs, +struct stack_trace *trace);extern void save_stack_trace_tsk (struct task_struct *tsk,struct stack_trace *trace);
[tip:perf/core] x86: Swap save_stack_trace_regs parameters
Commit-ID: 395810627b6a43c8d0ec948884043946fa162308 Gitweb: http://git.kernel.org/tip/395810627b6a43c8d0ec948884043946fa162308 Author: Masami Hiramatsu <[email protected]> AuthorDate: Wed, 8 Jun 2011 16:09:21 +0900 Committer: Steven Rostedt <[email protected]> CommitDate: Tue, 14 Jun 2011 22:48:51 -0400
x86: Swap save_stack_trace_regs parameters
Swap the 1st and 2nd parameters of save_stack_trace_regs() as same as the parameters of save_stack_trace_tsk().
--- arch/x86/kernel/stacktrace.c | 2 +- arch/x86/mm/kmemcheck/error.c | 2 +- include/linux/stacktrace.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-)
arch/x86/kernel/stacktrace.c +1 -1
@@ -66,7 +66,7 @@ void save_stack_trace(struct stack_trace *trace) }EXPORT_SYMBOL_GPL (save_stack_trace); -void save_stack_trace_regs (struct stack_trace *trace,struct pt_regs *regs) +void save_stack_trace_regs (struct pt_regs *regs,struct stack_trace *trace) {dump_trace (current, regs,NULL ,0 , &save_stack_ops, trace);if (trace->nr_entries < trace->max_entries)
arch/x86/mm/kmemcheck/error.c +1 -1
@@ -185,7 +185,7 @@ void kmemcheck_error_save(enum kmemcheck_shadow state, e->trace.entries = e->trace_entries; e->trace.max_entries =ARRAY_SIZE (e->trace_entries); e->trace.skip =0 ; -save_stack_trace_regs (&e->trace, regs); +save_stack_trace_regs (regs, &e->trace);/* Round address down to nearest 16 bytes */ shadow_copy = kmemcheck_shadow_lookup(address
include/linux/stacktrace.h +2 -2
@@ -14,8 +14,8 @@ struct stack_trace { };extern void save_stack_trace (struct stack_trace *trace); -extern void save_stack_trace_regs (struct stack_trace *trace, -struct pt_regs *regs); +extern void save_stack_trace_regs (struct pt_regs *regs, +struct stack_trace *trace);extern void save_stack_trace_tsk (struct task_struct *tsk,struct stack_trace *trace);
PATCH v2 2/3 Add weak save_stack_trace_regs()
In reply to Masami HiramatsuAdd weak symbol of save_stack_trace_regs() as same as save_stack_trace_tsk() since that is not implemented except x86 yet.
---
kernel/stacktrace.c | 13 ++++++++++--- 1 files changed, 10 insertions(+), 3 deletions(-)
kernel/stacktrace.c +10 -3
@@ -26,12 +26,19 @@ void print_stack_trace(struct stack_trace *trace, int spaces)EXPORT_SYMBOL_GPL (print_stack_trace);/* -* Architectures that do not implement save_stack_trace_tsk get this -* weak alias and a once-per-bootup warning (whenever this facility -* is utilized - for example by procfs): +* Architectures that do not implement save_stack_trace_tsk or +* save_stack_trace_regs get this weak alias and a once-per-bootup warning +* (whenever this facility is utilized - for example by procfs): */ __weak void save_stack_trace_tsk (struct task_struct *tsk,struct stack_trace *trace) {WARN_ONCE (1 ,KERN_INFO "save_stack_trace_tsk() not implemented yet.\n" ); } + +__weak void +save_stack_trace_regs (struct pt_regs *regs,struct stack_trace *trace) +{ +WARN_ONCE (1 , +KERN_INFO "save_stack_trace_regs() not implemented yet.\n" ); +}
[tip:perf/core] stack_trace: Add weak save_stack_trace_regs()
Commit-ID: c624d33f61cd05241e85b906311f0b712fdb0f32 Gitweb: http://git.kernel.org/tip/c624d33f61cd05241e85b906311f0b712fdb0f32 Author: Masami Hiramatsu <[email protected]> AuthorDate: Wed, 8 Jun 2011 16:09:27 +0900 Committer: Steven Rostedt <[email protected]> CommitDate: Tue, 14 Jun 2011 22:48:52 -0400
stack_trace: Add weak save_stack_trace_regs()
Add weak symbol of save_stack_trace_regs() as same as save_stack_trace_tsk() since that is not implemented except x86 yet.
--- kernel/stacktrace.c | 12 +++++++++--- 1 files changed, 9 insertions(+), 3 deletions(-)
kernel/stacktrace.c +9 -3
@@ -26,12 +26,18 @@ void print_stack_trace(struct stack_trace *trace, int spaces)EXPORT_SYMBOL_GPL (print_stack_trace);/* -* Architectures that do not implement save_stack_trace_tsk get this -* weak alias and a once-per-bootup warning (whenever this facility -* is utilized - for example by procfs): +* Architectures that do not implement save_stack_trace_tsk or +* save_stack_trace_regs get this weak alias and a once-per-bootup warning +* (whenever this facility is utilized - for example by procfs): */ __weak void save_stack_trace_tsk (struct task_struct *tsk,struct stack_trace *trace) {WARN_ONCE (1 ,KERN_INFO "save_stack_trace_tsk() not implemented yet.\n" ); } + +__weak void +save_stack_trace_regs (struct pt_regs *regs,struct stack_trace *trace) +{ +WARN_ONCE (1 ,KERN_INFO "save_stack_trace_regs() not implemented yet.\n" ); +}
PATCH v2 3/3 tracing/kprobes: Fix kprobe-tracer to support stack trace
In reply to Masami HiramatsuFix to support kernel stack trace correctly on kprobe-tracer. Since the execution path of kprobe-based dynamic events is different from other tracepoint-based events, normal ftrace_trace_stack() doesn't work correctly. To fix that, this introduces ftrace_trace_stack_regs() which traces stack via pt_regs instead of current stack register.
e.g.
# echo p schedule+4 > /sys/kernel/debug/tracing/kprobe_events
# echo 1 > /sys/kernel/debug/tracing/options/stacktrace
# echo 1 > /sys/kernel/debug/tracing/events/kprobes/enable
# head -n 20 /sys/kernel/debug/tracing/trace
# tracer: nop
#
# TASK-PID CPU# TIMESTAMP FUNCTION
# | | | | |
bash-2968 [000] 10297.050245: p_schedule_4: (schedule+0x4/0x4ca)
bash-2968 [000] 10297.050247: <stack trace>
=> schedule_timeout
=> n_tty_read
=> tty_read
=> vfs_read
=> sys_read
=> system_call_fastpath
kworker/0:1-2940 [000] 10297.050265: p_schedule_4: (schedule+0x4/0x4ca)
kworker/0:1-2940 [000] 10297.050266: <stack trace>
=> worker_thread
=> kthread
=> kernel_thread_helper
sshd-1132 [000] 10297.050365: p_schedule_4: (schedule+0x4/0x4ca)
sshd-1132 [000] 10297.050365: <stack trace>
=> sysret_carefulNote: Even with this fix, the first entry will be skipped if the probe is put on the function entry area before the frame pointer is set up (usually, that is 4 bytes
(push %bp; mov %sp %bp) on x86), because stack unwinder
depends on the frame pointer.
---
include/linux/ftrace_event.h | 4 ++++ kernel/trace/trace.c | 35 ++++++++++++++++++++++++++++++----- kernel/trace/trace.h | 9 +++++++++ kernel/trace/trace_kprobe.c | 6 ++++-- 4 files changed, 47 insertions(+), 7 deletions(-)
include/linux/ftrace_event.h +4 -0
@@ -129,6 +129,10 @@ void trace_current_buffer_unlock_commit(struct ring_buffer *buffer,void trace_nowake_buffer_unlock_commit (struct ring_buffer *buffer,struct ring_buffer_event *event,unsigned long flags,int pc); +void trace_nowake_buffer_unlock_commit_regs (struct ring_buffer *buffer, +struct ring_buffer_event *event, +unsigned long flags,int pc, +struct pt_regs *regs);void trace_current_buffer_discard_commit (struct ring_buffer *buffer,struct ring_buffer_event *event);
kernel/trace/trace.c +30 -5
@@ -1191,6 +1191,18 @@ void trace_nowake_buffer_unlock_commit(struct ring_buffer *buffer, }EXPORT_SYMBOL_GPL (trace_nowake_buffer_unlock_commit); +void trace_nowake_buffer_unlock_commit_regs (struct ring_buffer *buffer, +struct ring_buffer_event *event, +unsigned long flags,int pc, +struct pt_regs *regs) +{ +ring_buffer_unlock_commit (buffer, event); + +ftrace_trace_stack_regs (buffer, flags,0 , pc, regs); +ftrace_trace_userstack (buffer, flags, pc); +} +EXPORT_SYMBOL_GPL (trace_nowake_buffer_unlock_commit_regs); +void trace_current_buffer_discard_commit (struct ring_buffer *buffer,struct ring_buffer_event *event) {
@@ -1236,7 +1248,7 @@ ftrace(struct trace_array *tr, struct trace_array_cpu *data,#ifdef CONFIG_STACKTRACE static void __ftrace_trace_stack (struct ring_buffer *buffer,unsigned long flags, -int skip,int pc) +int skip,int pc,struct pt_regs *regs) {struct ftrace_event_call *call = &event_kernel_stack;struct ring_buffer_event *event;
@@ -1255,24 +1267,36 @@ static void __ftrace_trace_stack(struct ring_buffer *buffer, trace.skip = skip; trace.entries = entry->caller; -save_stack_trace (&trace); +if (regs) +save_stack_trace_regs (regs, &trace); +else +save_stack_trace (&trace);if (!filter_check_discard (call, entry, buffer, event))ring_buffer_unlock_commit (buffer, event); } +void ftrace_trace_stack_regs (struct ring_buffer *buffer,unsigned long flags, +int skip,int pc,struct pt_regs *regs) +{ +if (!(trace_flags &TRACE_ITER_STACKTRACE )) +return ; + +__ftrace_trace_stack (buffer, flags, skip, pc, regs); +} +void ftrace_trace_stack (struct ring_buffer *buffer,unsigned long flags,int skip,int pc) {if (!(trace_flags &TRACE_ITER_STACKTRACE ))return ; -__ftrace_trace_stack (buffer, flags, skip, pc); +__ftrace_trace_stack (buffer, flags, skip, pc,NULL ); }void __trace_stack (struct trace_array *tr,unsigned long flags,int skip,int pc) { -__ftrace_trace_stack (tr->buffer, flags, skip, pc); +__ftrace_trace_stack (tr->buffer, flags, skip, pc,NULL ); }/**
@@ -1288,7 +1312,8 @@ void trace_dump_stack(void)local_save_flags (flags);/* skipping 3 traces, seems to get us at the caller of this function */ -__ftrace_trace_stack (global_trace.buffer, flags,3 ,preempt_count ()); +__ftrace_trace_stack (global_trace.buffer, flags,3 ,preempt_count (), +NULL ); } static DEFINE_PER_CPU(int, user_stack_count);
kernel/trace/trace.h +9 -0
@@ -389,6 +389,9 @@ void update_max_tr_single(struct trace_array *tr,void ftrace_trace_stack (struct ring_buffer *buffer,unsigned long flags,int skip,int pc); +void ftrace_trace_stack_regs (struct ring_buffer *buffer,unsigned long flags, +int skip,int pc,struct pt_regs *regs); +void ftrace_trace_userstack (struct ring_buffer *buffer,unsigned long flags,int pc);
@@ -400,6 +403,12 @@ static inline void ftrace_trace_stack(struct ring_buffer *buffer, { } +static inline void ftrace_trace_stack_regs (struct ring_buffer *buffer, +unsigned long flags,int skip, +int pc,struct pt_regs *regs) +{ +} +static inline void ftrace_trace_userstack (struct ring_buffer *buffer,unsigned long flags,int pc) {
kernel/trace/trace_kprobe.c +4 -2
@@ -1397,7 +1397,8 @@ static __kprobes void kprobe_trace_func(struct kprobe *kp, struct pt_regs *regs)store_trace_args (sizeof (*entry), tp, regs, (u8 *)&entry[1 ], dsize);if (!filter_current_check_discard (buffer, call, entry, event)) -trace_nowake_buffer_unlock_commit (buffer, event, irq_flags, pc); +trace_nowake_buffer_unlock_commit_regs (buffer, event, + irq_flags, pc, regs); }/* Kretprobe handler */
@@ -1429,7 +1430,8 @@ static __kprobes void kretprobe_trace_func(struct kretprobe_instance *ri,store_trace_args (sizeof (*entry), tp, regs, (u8 *)&entry[1 ], dsize);if (!filter_current_check_discard (buffer, call, entry, event)) -trace_nowake_buffer_unlock_commit (buffer, event, irq_flags, pc); +trace_nowake_buffer_unlock_commit_regs (buffer, event, + irq_flags, pc, regs); }/* Event entry printers */
[tip:perf/core] tracing/kprobes: Fix kprobe-tracer to support stack trace
Commit-ID: 1fd8df2c3970c9e7e4e262354154ee39e58bdd7c Gitweb: http://git.kernel.org/tip/1fd8df2c3970c9e7e4e262354154ee39e58bdd7c Author: Masami Hiramatsu <[email protected]> AuthorDate: Wed, 8 Jun 2011 16:09:34 +0900 Committer: Steven Rostedt <[email protected]> CommitDate: Tue, 14 Jun 2011 22:48:53 -0400
tracing/kprobes: Fix kprobe-tracer to support stack trace
Fix to support kernel stack trace correctly on kprobe-tracer. Since the execution path of kprobe-based dynamic events is different from other tracepoint-based events, normal ftrace_trace_stack() doesn't work correctly. To fix that, this introduces ftrace_trace_stack_regs() which traces stack via pt_regs instead of current stack register.
e.g.
# echo p schedule+4 > /sys/kernel/debug/tracing/kprobe_events
# echo 1 > /sys/kernel/debug/tracing/options/stacktrace
# echo 1 > /sys/kernel/debug/tracing/events/kprobes/enable
# head -n 20 /sys/kernel/debug/tracing/trace
bash-2968 [000] 10297.050245: p_schedule_4: (schedule+0x4/0x4ca)
bash-2968 [000] 10297.050247: <stack trace>
=> schedule_timeout
=> n_tty_read
=> tty_read
=> vfs_read
=> sys_read
=> system_call_fastpath
kworker/0:1-2940 [000] 10297.050265: p_schedule_4: (schedule+0x4/0x4ca)
kworker/0:1-2940 [000] 10297.050266: <stack trace>
=> worker_thread
=> kthread
=> kernel_thread_helper
sshd-1132 [000] 10297.050365: p_schedule_4: (schedule+0x4/0x4ca)
sshd-1132 [000] 10297.050365: <stack trace>
=> sysret_carefulNote: Even with this fix, the first entry will be skipped if the probe is put on the function entry area before the frame pointer is set up (usually, that is 4 bytes
(push %bp; mov %sp %bp) on x86), because stack unwinder
depends on the frame pointer.
--- include/linux/ftrace_event.h | 4 ++++ kernel/trace/trace.c | 34 +++++++++++++++++++++++++++++----- kernel/trace/trace.h | 9 +++++++++ kernel/trace/trace_kprobe.c | 6 ++++-- 4 files changed, 46 insertions(+), 7 deletions(-)
include/linux/ftrace_event.h +4 -0
@@ -129,6 +129,10 @@ void trace_current_buffer_unlock_commit(struct ring_buffer *buffer,void trace_nowake_buffer_unlock_commit (struct ring_buffer *buffer,struct ring_buffer_event *event,unsigned long flags,int pc); +void trace_nowake_buffer_unlock_commit_regs (struct ring_buffer *buffer, +struct ring_buffer_event *event, +unsigned long flags,int pc, +struct pt_regs *regs);void trace_current_buffer_discard_commit (struct ring_buffer *buffer,struct ring_buffer_event *event);
kernel/trace/trace.c +29 -5
@@ -1193,6 +1193,18 @@ void trace_nowake_buffer_unlock_commit(struct ring_buffer *buffer, }EXPORT_SYMBOL_GPL (trace_nowake_buffer_unlock_commit); +void trace_nowake_buffer_unlock_commit_regs (struct ring_buffer *buffer, +struct ring_buffer_event *event, +unsigned long flags,int pc, +struct pt_regs *regs) +{ +ring_buffer_unlock_commit (buffer, event); + +ftrace_trace_stack_regs (buffer, flags,0 , pc, regs); +ftrace_trace_userstack (buffer, flags, pc); +} +EXPORT_SYMBOL_GPL (trace_nowake_buffer_unlock_commit_regs); +void trace_current_buffer_discard_commit (struct ring_buffer *buffer,struct ring_buffer_event *event) {
@@ -1238,7 +1250,7 @@ ftrace(struct trace_array *tr, struct trace_array_cpu *data,#ifdef CONFIG_STACKTRACE static void __ftrace_trace_stack (struct ring_buffer *buffer,unsigned long flags, -int skip,int pc) +int skip,int pc,struct pt_regs *regs) {struct ftrace_event_call *call = &event_kernel_stack;struct ring_buffer_event *event;
@@ -1257,24 +1269,36 @@ static void __ftrace_trace_stack(struct ring_buffer *buffer, trace.skip = skip; trace.entries = entry->caller; -save_stack_trace (&trace); +if (regs) +save_stack_trace_regs (regs, &trace); +else +save_stack_trace (&trace);if (!filter_check_discard (call, entry, buffer, event))ring_buffer_unlock_commit (buffer, event); } +void ftrace_trace_stack_regs (struct ring_buffer *buffer,unsigned long flags, +int skip,int pc,struct pt_regs *regs) +{ +if (!(trace_flags &TRACE_ITER_STACKTRACE )) +return ; + +__ftrace_trace_stack (buffer, flags, skip, pc, regs); +} +void ftrace_trace_stack (struct ring_buffer *buffer,unsigned long flags,int skip,int pc) {if (!(trace_flags &TRACE_ITER_STACKTRACE ))return ; -__ftrace_trace_stack (buffer, flags, skip, pc); +__ftrace_trace_stack (buffer, flags, skip, pc,NULL ); }void __trace_stack (struct trace_array *tr,unsigned long flags,int skip,int pc) { -__ftrace_trace_stack (tr->buffer, flags, skip, pc); +__ftrace_trace_stack (tr->buffer, flags, skip, pc,NULL ); }/**
@@ -1290,7 +1314,7 @@ void trace_dump_stack(void)local_save_flags (flags);/* skipping 3 traces, seems to get us at the caller of this function */ -__ftrace_trace_stack (global_trace.buffer, flags,3 ,preempt_count ()); +__ftrace_trace_stack (global_trace.buffer, flags,3 ,preempt_count (),NULL ); } static DEFINE_PER_CPU(int, user_stack_count);
kernel/trace/trace.h +9 -0
@@ -389,6 +389,9 @@ void update_max_tr_single(struct trace_array *tr,void ftrace_trace_stack (struct ring_buffer *buffer,unsigned long flags,int skip,int pc); +void ftrace_trace_stack_regs (struct ring_buffer *buffer,unsigned long flags, +int skip,int pc,struct pt_regs *regs); +void ftrace_trace_userstack (struct ring_buffer *buffer,unsigned long flags,int pc);
@@ -400,6 +403,12 @@ static inline void ftrace_trace_stack(struct ring_buffer *buffer, { } +static inline void ftrace_trace_stack_regs (struct ring_buffer *buffer, +unsigned long flags,int skip, +int pc,struct pt_regs *regs) +{ +} +static inline void ftrace_trace_userstack (struct ring_buffer *buffer,unsigned long flags,int pc) {
kernel/trace/trace_kprobe.c +4 -2
@@ -1397,7 +1397,8 @@ static __kprobes void kprobe_trace_func(struct kprobe *kp, struct pt_regs *regs)store_trace_args (sizeof (*entry), tp, regs, (u8 *)&entry[1 ], dsize);if (!filter_current_check_discard (buffer, call, entry, event)) -trace_nowake_buffer_unlock_commit (buffer, event, irq_flags, pc); +trace_nowake_buffer_unlock_commit_regs (buffer, event, + irq_flags, pc, regs); }/* Kretprobe handler */
@@ -1429,7 +1430,8 @@ static __kprobes void kretprobe_trace_func(struct kretprobe_instance *ri,store_trace_args (sizeof (*entry), tp, regs, (u8 *)&entry[1 ], dsize);if (!filter_current_check_discard (buffer, call, entry, event)) -trace_nowake_buffer_unlock_commit (buffer, event, irq_flags, pc); +trace_nowake_buffer_unlock_commit_regs (buffer, event, + irq_flags, pc, regs); }/* Event entry printers */