diff options
author | Jan Beulich <jbeulich@novell.com> | 2006-06-26 07:57:47 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-26 13:48:18 -0400 |
commit | c33bd9aac0597eeedaaa01ea5aafe456894b2f2b (patch) | |
tree | cdac9bb99eb3943feccc2a21d09a1524a8867cb0 /arch/x86_64 | |
parent | fe7cacc1c25e286872b878c5d46880b620cd1e2d (diff) |
[PATCH] i386/x86-64: fall back to old-style call trace if no unwinding
If no unwinding is possible at all for a certain exception instance,
fall back to the old style call trace instead of not showing any trace
at all.
Also, allow setting the stack trace mode at the command line.
Signed-off-by: Jan Beulich <jbeulich@novell.com>
Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/x86_64')
-rw-r--r-- | arch/x86_64/kernel/traps.c | 51 |
1 files changed, 35 insertions, 16 deletions
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index eb1534ff1f5f..bd0891f4c2c7 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c | |||
@@ -107,6 +107,7 @@ static inline void preempt_conditional_cli(struct pt_regs *regs) | |||
107 | } | 107 | } |
108 | 108 | ||
109 | static int kstack_depth_to_print = 10; | 109 | static int kstack_depth_to_print = 10; |
110 | static int call_trace = 1; | ||
110 | 111 | ||
111 | #ifdef CONFIG_KALLSYMS | 112 | #ifdef CONFIG_KALLSYMS |
112 | #include <linux/kallsyms.h> | 113 | #include <linux/kallsyms.h> |
@@ -190,11 +191,12 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, | |||
190 | return NULL; | 191 | return NULL; |
191 | } | 192 | } |
192 | 193 | ||
193 | static void show_trace_unwind(struct unwind_frame_info *info, void *context) | 194 | static int show_trace_unwind(struct unwind_frame_info *info, void *context) |
194 | { | 195 | { |
195 | int i = 11; | 196 | int i = 11, n = 0; |
196 | 197 | ||
197 | while (unwind(info) == 0 && UNW_PC(info)) { | 198 | while (unwind(info) == 0 && UNW_PC(info)) { |
199 | ++n; | ||
198 | if (i > 50) { | 200 | if (i > 50) { |
199 | printk("\n "); | 201 | printk("\n "); |
200 | i = 7; | 202 | i = 7; |
@@ -205,6 +207,7 @@ static void show_trace_unwind(struct unwind_frame_info *info, void *context) | |||
205 | break; | 207 | break; |
206 | } | 208 | } |
207 | printk("\n"); | 209 | printk("\n"); |
210 | return n; | ||
208 | } | 211 | } |
209 | 212 | ||
210 | /* | 213 | /* |
@@ -218,27 +221,32 @@ void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s | |||
218 | { | 221 | { |
219 | const unsigned cpu = safe_smp_processor_id(); | 222 | const unsigned cpu = safe_smp_processor_id(); |
220 | unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr; | 223 | unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr; |
221 | int i; | 224 | int i = 11; |
222 | unsigned used = 0; | 225 | unsigned used = 0; |
223 | struct unwind_frame_info info; | ||
224 | 226 | ||
225 | printk("\nCall Trace:"); | 227 | printk("\nCall Trace:"); |
226 | 228 | ||
227 | if (!tsk) | 229 | if (!tsk) |
228 | tsk = current; | 230 | tsk = current; |
229 | 231 | ||
230 | if (regs) { | 232 | if (call_trace >= 0) { |
231 | if (unwind_init_frame_info(&info, tsk, regs) == 0) { | 233 | int unw_ret = 0; |
232 | show_trace_unwind(&info, NULL); | 234 | struct unwind_frame_info info; |
233 | return; | 235 | |
236 | if (regs) { | ||
237 | if (unwind_init_frame_info(&info, tsk, regs) == 0) | ||
238 | unw_ret = show_trace_unwind(&info, NULL); | ||
239 | } else if (tsk == current) | ||
240 | unw_ret = unwind_init_running(&info, show_trace_unwind, NULL); | ||
241 | else { | ||
242 | if (unwind_init_blocked(&info, tsk) == 0) | ||
243 | unw_ret = show_trace_unwind(&info, NULL); | ||
234 | } | 244 | } |
235 | } else if (tsk == current) { | 245 | if (unw_ret > 0) { |
236 | if (unwind_init_running(&info, show_trace_unwind, NULL) == 0) | 246 | if (call_trace > 0) |
237 | return; | 247 | return; |
238 | } else { | 248 | printk("Legacy call trace:"); |
239 | if (unwind_init_blocked(&info, tsk) == 0) { | 249 | i = 18; |
240 | show_trace_unwind(&info, NULL); | ||
241 | return; | ||
242 | } | 250 | } |
243 | } | 251 | } |
244 | 252 | ||
@@ -264,7 +272,7 @@ void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s | |||
264 | } \ | 272 | } \ |
265 | } while (0) | 273 | } while (0) |
266 | 274 | ||
267 | for(i = 11; ; ) { | 275 | for(; ; ) { |
268 | const char *id; | 276 | const char *id; |
269 | unsigned long *estack_end; | 277 | unsigned long *estack_end; |
270 | estack_end = in_exception_stack(cpu, (unsigned long)stack, | 278 | estack_end = in_exception_stack(cpu, (unsigned long)stack, |
@@ -1052,3 +1060,14 @@ static int __init kstack_setup(char *s) | |||
1052 | } | 1060 | } |
1053 | __setup("kstack=", kstack_setup); | 1061 | __setup("kstack=", kstack_setup); |
1054 | 1062 | ||
1063 | static int __init call_trace_setup(char *s) | ||
1064 | { | ||
1065 | if (strcmp(s, "old") == 0) | ||
1066 | call_trace = -1; | ||
1067 | else if (strcmp(s, "both") == 0) | ||
1068 | call_trace = 0; | ||
1069 | else if (strcmp(s, "new") == 0) | ||
1070 | call_trace = 1; | ||
1071 | return 1; | ||
1072 | } | ||
1073 | __setup("call_trace=", call_trace_setup); | ||