aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>2011-06-08 03:09:34 -0400
committerSteven Rostedt <rostedt@goodmis.org>2011-06-14 22:48:53 -0400
commit1fd8df2c3970c9e7e4e262354154ee39e58bdd7c (patch)
tree640fbc584af8870917ea6d1fab4da49d299038ad
parentc624d33f61cd05241e85b906311f0b712fdb0f32 (diff)
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_careful Note: 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. Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: yrl.pp-manager.tt@hitachi.com Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Namhyung Kim <namhyung@gmail.com> Link: http://lkml.kernel.org/r/20110608070934.17777.17116.stgit@fedora15 Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--include/linux/ftrace_event.h4
-rw-r--r--kernel/trace/trace.c34
-rw-r--r--kernel/trace/trace.h9
-rw-r--r--kernel/trace/trace_kprobe.c6
4 files changed, 46 insertions, 7 deletions
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index 59d3ef100eb9..b1e69eefc203 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -129,6 +129,10 @@ void trace_current_buffer_unlock_commit(struct ring_buffer *buffer,
129void trace_nowake_buffer_unlock_commit(struct ring_buffer *buffer, 129void trace_nowake_buffer_unlock_commit(struct ring_buffer *buffer,
130 struct ring_buffer_event *event, 130 struct ring_buffer_event *event,
131 unsigned long flags, int pc); 131 unsigned long flags, int pc);
132void trace_nowake_buffer_unlock_commit_regs(struct ring_buffer *buffer,
133 struct ring_buffer_event *event,
134 unsigned long flags, int pc,
135 struct pt_regs *regs);
132void trace_current_buffer_discard_commit(struct ring_buffer *buffer, 136void trace_current_buffer_discard_commit(struct ring_buffer *buffer,
133 struct ring_buffer_event *event); 137 struct ring_buffer_event *event);
134 138
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index c977018e87c2..d9c16123f6e2 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -1193,6 +1193,18 @@ void trace_nowake_buffer_unlock_commit(struct ring_buffer *buffer,
1193} 1193}
1194EXPORT_SYMBOL_GPL(trace_nowake_buffer_unlock_commit); 1194EXPORT_SYMBOL_GPL(trace_nowake_buffer_unlock_commit);
1195 1195
1196void trace_nowake_buffer_unlock_commit_regs(struct ring_buffer *buffer,
1197 struct ring_buffer_event *event,
1198 unsigned long flags, int pc,
1199 struct pt_regs *regs)
1200{
1201 ring_buffer_unlock_commit(buffer, event);
1202
1203 ftrace_trace_stack_regs(buffer, flags, 0, pc, regs);
1204 ftrace_trace_userstack(buffer, flags, pc);
1205}
1206EXPORT_SYMBOL_GPL(trace_nowake_buffer_unlock_commit_regs);
1207
1196void trace_current_buffer_discard_commit(struct ring_buffer *buffer, 1208void trace_current_buffer_discard_commit(struct ring_buffer *buffer,
1197 struct ring_buffer_event *event) 1209 struct ring_buffer_event *event)
1198{ 1210{
@@ -1238,7 +1250,7 @@ ftrace(struct trace_array *tr, struct trace_array_cpu *data,
1238#ifdef CONFIG_STACKTRACE 1250#ifdef CONFIG_STACKTRACE
1239static void __ftrace_trace_stack(struct ring_buffer *buffer, 1251static void __ftrace_trace_stack(struct ring_buffer *buffer,
1240 unsigned long flags, 1252 unsigned long flags,
1241 int skip, int pc) 1253 int skip, int pc, struct pt_regs *regs)
1242{ 1254{
1243 struct ftrace_event_call *call = &event_kernel_stack; 1255 struct ftrace_event_call *call = &event_kernel_stack;
1244 struct ring_buffer_event *event; 1256 struct ring_buffer_event *event;
@@ -1257,24 +1269,36 @@ static void __ftrace_trace_stack(struct ring_buffer *buffer,
1257 trace.skip = skip; 1269 trace.skip = skip;
1258 trace.entries = entry->caller; 1270 trace.entries = entry->caller;
1259 1271
1260 save_stack_trace(&trace); 1272 if (regs)
1273 save_stack_trace_regs(regs, &trace);
1274 else
1275 save_stack_trace(&trace);
1261 if (!filter_check_discard(call, entry, buffer, event)) 1276 if (!filter_check_discard(call, entry, buffer, event))
1262 ring_buffer_unlock_commit(buffer, event); 1277 ring_buffer_unlock_commit(buffer, event);
1263} 1278}
1264 1279
1280void ftrace_trace_stack_regs(struct ring_buffer *buffer, unsigned long flags,
1281 int skip, int pc, struct pt_regs *regs)
1282{
1283 if (!(trace_flags & TRACE_ITER_STACKTRACE))
1284 return;
1285
1286 __ftrace_trace_stack(buffer, flags, skip, pc, regs);
1287}
1288
1265void ftrace_trace_stack(struct ring_buffer *buffer, unsigned long flags, 1289void ftrace_trace_stack(struct ring_buffer *buffer, unsigned long flags,
1266 int skip, int pc) 1290 int skip, int pc)
1267{ 1291{
1268 if (!(trace_flags & TRACE_ITER_STACKTRACE)) 1292 if (!(trace_flags & TRACE_ITER_STACKTRACE))
1269 return; 1293 return;
1270 1294
1271 __ftrace_trace_stack(buffer, flags, skip, pc); 1295 __ftrace_trace_stack(buffer, flags, skip, pc, NULL);
1272} 1296}
1273 1297
1274void __trace_stack(struct trace_array *tr, unsigned long flags, int skip, 1298void __trace_stack(struct trace_array *tr, unsigned long flags, int skip,
1275 int pc) 1299 int pc)
1276{ 1300{
1277 __ftrace_trace_stack(tr->buffer, flags, skip, pc); 1301 __ftrace_trace_stack(tr->buffer, flags, skip, pc, NULL);
1278} 1302}
1279 1303
1280/** 1304/**
@@ -1290,7 +1314,7 @@ void trace_dump_stack(void)
1290 local_save_flags(flags); 1314 local_save_flags(flags);
1291 1315
1292 /* skipping 3 traces, seems to get us at the caller of this function */ 1316 /* skipping 3 traces, seems to get us at the caller of this function */
1293 __ftrace_trace_stack(global_trace.buffer, flags, 3, preempt_count()); 1317 __ftrace_trace_stack(global_trace.buffer, flags, 3, preempt_count(), NULL);
1294} 1318}
1295 1319
1296static DEFINE_PER_CPU(int, user_stack_count); 1320static DEFINE_PER_CPU(int, user_stack_count);
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 742f545ae185..a3e2db708072 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -389,6 +389,9 @@ void update_max_tr_single(struct trace_array *tr,
389void ftrace_trace_stack(struct ring_buffer *buffer, unsigned long flags, 389void ftrace_trace_stack(struct ring_buffer *buffer, unsigned long flags,
390 int skip, int pc); 390 int skip, int pc);
391 391
392void ftrace_trace_stack_regs(struct ring_buffer *buffer, unsigned long flags,
393 int skip, int pc, struct pt_regs *regs);
394
392void ftrace_trace_userstack(struct ring_buffer *buffer, unsigned long flags, 395void ftrace_trace_userstack(struct ring_buffer *buffer, unsigned long flags,
393 int pc); 396 int pc);
394 397
@@ -400,6 +403,12 @@ static inline void ftrace_trace_stack(struct ring_buffer *buffer,
400{ 403{
401} 404}
402 405
406static inline void ftrace_trace_stack_regs(struct ring_buffer *buffer,
407 unsigned long flags, int skip,
408 int pc, struct pt_regs *regs)
409{
410}
411
403static inline void ftrace_trace_userstack(struct ring_buffer *buffer, 412static inline void ftrace_trace_userstack(struct ring_buffer *buffer,
404 unsigned long flags, int pc) 413 unsigned long flags, int pc)
405{ 414{
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index f925c45f0afa..7053ef3d73d2 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -1397,7 +1397,8 @@ static __kprobes void kprobe_trace_func(struct kprobe *kp, struct pt_regs *regs)
1397 store_trace_args(sizeof(*entry), tp, regs, (u8 *)&entry[1], dsize); 1397 store_trace_args(sizeof(*entry), tp, regs, (u8 *)&entry[1], dsize);
1398 1398
1399 if (!filter_current_check_discard(buffer, call, entry, event)) 1399 if (!filter_current_check_discard(buffer, call, entry, event))
1400 trace_nowake_buffer_unlock_commit(buffer, event, irq_flags, pc); 1400 trace_nowake_buffer_unlock_commit_regs(buffer, event,
1401 irq_flags, pc, regs);
1401} 1402}
1402 1403
1403/* Kretprobe handler */ 1404/* Kretprobe handler */
@@ -1429,7 +1430,8 @@ static __kprobes void kretprobe_trace_func(struct kretprobe_instance *ri,
1429 store_trace_args(sizeof(*entry), tp, regs, (u8 *)&entry[1], dsize); 1430 store_trace_args(sizeof(*entry), tp, regs, (u8 *)&entry[1], dsize);
1430 1431
1431 if (!filter_current_check_discard(buffer, call, entry, event)) 1432 if (!filter_current_check_discard(buffer, call, entry, event))
1432 trace_nowake_buffer_unlock_commit(buffer, event, irq_flags, pc); 1433 trace_nowake_buffer_unlock_commit_regs(buffer, event,
1434 irq_flags, pc, regs);
1433} 1435}
1434 1436
1435/* Event entry printers */ 1437/* Event entry printers */