aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/stacktrace.c
diff options
context:
space:
mode:
authorTörök Edwin <edwintorok@gmail.com>2008-11-22 06:28:47 -0500
committerIngo Molnar <mingo@elte.hu>2008-11-23 03:25:15 -0500
commit02b67518e2b1c490787dac7f35e1204e74fe21ba (patch)
treea3d92846e1a09a829f300ab15726ee9c288cb49e /arch/x86/kernel/stacktrace.c
parenta0a70c735ef714fe1b6777b571630c3d50c7b008 (diff)
tracing: add support for userspace stacktraces in tracing/iter_ctrl
Impact: add new (default-off) tracing visualization feature Usage example: mount -t debugfs nodev /sys/kernel/debug cd /sys/kernel/debug/tracing echo userstacktrace >iter_ctrl echo sched_switch >current_tracer echo 1 >tracing_enabled .... run application ... echo 0 >tracing_enabled Then read one of 'trace','latency_trace','trace_pipe'. To get the best output you can compile your userspace programs with frame pointers (at least glibc + the app you are tracing). Signed-off-by: Török Edwin <edwintorok@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/stacktrace.c')
-rw-r--r--arch/x86/kernel/stacktrace.c57
1 files changed, 57 insertions, 0 deletions
diff --git a/arch/x86/kernel/stacktrace.c b/arch/x86/kernel/stacktrace.c
index a03e7f6d90c3..b15153060417 100644
--- a/arch/x86/kernel/stacktrace.c
+++ b/arch/x86/kernel/stacktrace.c
@@ -6,6 +6,7 @@
6#include <linux/sched.h> 6#include <linux/sched.h>
7#include <linux/stacktrace.h> 7#include <linux/stacktrace.h>
8#include <linux/module.h> 8#include <linux/module.h>
9#include <linux/uaccess.h>
9#include <asm/stacktrace.h> 10#include <asm/stacktrace.h>
10 11
11static void save_stack_warning(void *data, char *msg) 12static void save_stack_warning(void *data, char *msg)
@@ -83,3 +84,59 @@ void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace)
83 trace->entries[trace->nr_entries++] = ULONG_MAX; 84 trace->entries[trace->nr_entries++] = ULONG_MAX;
84} 85}
85EXPORT_SYMBOL_GPL(save_stack_trace_tsk); 86EXPORT_SYMBOL_GPL(save_stack_trace_tsk);
87
88/* Userspace stacktrace - based on kernel/trace/trace_sysprof.c */
89
90struct stack_frame {
91 const void __user *next_fp;
92 unsigned long return_address;
93};
94
95static int copy_stack_frame(const void __user *fp, struct stack_frame *frame)
96{
97 int ret;
98
99 if (!access_ok(VERIFY_READ, fp, sizeof(*frame)))
100 return 0;
101
102 ret = 1;
103 pagefault_disable();
104 if (__copy_from_user_inatomic(frame, fp, sizeof(*frame)))
105 ret = 0;
106 pagefault_enable();
107
108 return ret;
109}
110
111void save_stack_trace_user(struct stack_trace *trace)
112{
113 /*
114 * Trace user stack if we are not a kernel thread
115 */
116 if (current->mm) {
117 const struct pt_regs *regs = task_pt_regs(current);
118 const void __user *fp = (const void __user *)regs->bp;
119
120 if (trace->nr_entries < trace->max_entries)
121 trace->entries[trace->nr_entries++] = regs->ip;
122
123 while (trace->nr_entries < trace->max_entries) {
124 struct stack_frame frame;
125 frame.next_fp = NULL;
126 frame.return_address = 0;
127 if (!copy_stack_frame(fp, &frame))
128 break;
129 if ((unsigned long)fp < regs->sp)
130 break;
131 if (frame.return_address)
132 trace->entries[trace->nr_entries++] =
133 frame.return_address;
134 if (fp == frame.next_fp)
135 break;
136 fp = frame.next_fp;
137 }
138 }
139 if (trace->nr_entries < trace->max_entries)
140 trace->entries[trace->nr_entries++] = ULONG_MAX;
141}
142