diff options
Diffstat (limited to 'arch/x86_64/kernel/traps.c')
-rw-r--r-- | arch/x86_64/kernel/traps.c | 83 |
1 files changed, 72 insertions, 11 deletions
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index cea335e8746c..3d11a2fe45b7 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c | |||
@@ -6,8 +6,6 @@ | |||
6 | * | 6 | * |
7 | * Pentium III FXSR, SSE support | 7 | * Pentium III FXSR, SSE support |
8 | * Gareth Hughes <gareth@valinux.com>, May 2000 | 8 | * Gareth Hughes <gareth@valinux.com>, May 2000 |
9 | * | ||
10 | * $Id: traps.c,v 1.36 2002/03/24 11:09:10 ak Exp $ | ||
11 | */ | 9 | */ |
12 | 10 | ||
13 | /* | 11 | /* |
@@ -31,6 +29,7 @@ | |||
31 | #include <linux/nmi.h> | 29 | #include <linux/nmi.h> |
32 | #include <linux/kprobes.h> | 30 | #include <linux/kprobes.h> |
33 | #include <linux/kexec.h> | 31 | #include <linux/kexec.h> |
32 | #include <linux/unwind.h> | ||
34 | 33 | ||
35 | #include <asm/system.h> | 34 | #include <asm/system.h> |
36 | #include <asm/uaccess.h> | 35 | #include <asm/uaccess.h> |
@@ -41,7 +40,7 @@ | |||
41 | #include <asm/i387.h> | 40 | #include <asm/i387.h> |
42 | #include <asm/kdebug.h> | 41 | #include <asm/kdebug.h> |
43 | #include <asm/processor.h> | 42 | #include <asm/processor.h> |
44 | 43 | #include <asm/unwind.h> | |
45 | #include <asm/smp.h> | 44 | #include <asm/smp.h> |
46 | #include <asm/pgalloc.h> | 45 | #include <asm/pgalloc.h> |
47 | #include <asm/pda.h> | 46 | #include <asm/pda.h> |
@@ -71,6 +70,7 @@ asmlinkage void machine_check(void); | |||
71 | asmlinkage void spurious_interrupt_bug(void); | 70 | asmlinkage void spurious_interrupt_bug(void); |
72 | 71 | ||
73 | ATOMIC_NOTIFIER_HEAD(die_chain); | 72 | ATOMIC_NOTIFIER_HEAD(die_chain); |
73 | EXPORT_SYMBOL(die_chain); | ||
74 | 74 | ||
75 | int register_die_notifier(struct notifier_block *nb) | 75 | int register_die_notifier(struct notifier_block *nb) |
76 | { | 76 | { |
@@ -107,7 +107,8 @@ static inline void preempt_conditional_cli(struct pt_regs *regs) | |||
107 | preempt_enable_no_resched(); | 107 | preempt_enable_no_resched(); |
108 | } | 108 | } |
109 | 109 | ||
110 | static int kstack_depth_to_print = 10; | 110 | static int kstack_depth_to_print = 12; |
111 | static int call_trace = 1; | ||
111 | 112 | ||
112 | #ifdef CONFIG_KALLSYMS | 113 | #ifdef CONFIG_KALLSYMS |
113 | #include <linux/kallsyms.h> | 114 | #include <linux/kallsyms.h> |
@@ -191,6 +192,25 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, | |||
191 | return NULL; | 192 | return NULL; |
192 | } | 193 | } |
193 | 194 | ||
195 | static int show_trace_unwind(struct unwind_frame_info *info, void *context) | ||
196 | { | ||
197 | int i = 11, n = 0; | ||
198 | |||
199 | while (unwind(info) == 0 && UNW_PC(info)) { | ||
200 | ++n; | ||
201 | if (i > 50) { | ||
202 | printk("\n "); | ||
203 | i = 7; | ||
204 | } else | ||
205 | i += printk(" "); | ||
206 | i += printk_address(UNW_PC(info)); | ||
207 | if (arch_unw_user_mode(info)) | ||
208 | break; | ||
209 | } | ||
210 | printk("\n"); | ||
211 | return n; | ||
212 | } | ||
213 | |||
194 | /* | 214 | /* |
195 | * x86-64 can have upto three kernel stacks: | 215 | * x86-64 can have upto three kernel stacks: |
196 | * process stack | 216 | * process stack |
@@ -198,15 +218,39 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, | |||
198 | * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack | 218 | * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack |
199 | */ | 219 | */ |
200 | 220 | ||
201 | void show_trace(unsigned long *stack) | 221 | void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * stack) |
202 | { | 222 | { |
203 | const unsigned cpu = safe_smp_processor_id(); | 223 | const unsigned cpu = safe_smp_processor_id(); |
204 | unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr; | 224 | unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr; |
205 | int i; | 225 | int i = 11; |
206 | unsigned used = 0; | 226 | unsigned used = 0; |
207 | 227 | ||
208 | printk("\nCall Trace:"); | 228 | printk("\nCall Trace:"); |
209 | 229 | ||
230 | if (!tsk) | ||
231 | tsk = current; | ||
232 | |||
233 | if (call_trace >= 0) { | ||
234 | int unw_ret = 0; | ||
235 | struct unwind_frame_info info; | ||
236 | |||
237 | if (regs) { | ||
238 | if (unwind_init_frame_info(&info, tsk, regs) == 0) | ||
239 | unw_ret = show_trace_unwind(&info, NULL); | ||
240 | } else if (tsk == current) | ||
241 | unw_ret = unwind_init_running(&info, show_trace_unwind, NULL); | ||
242 | else { | ||
243 | if (unwind_init_blocked(&info, tsk) == 0) | ||
244 | unw_ret = show_trace_unwind(&info, NULL); | ||
245 | } | ||
246 | if (unw_ret > 0) { | ||
247 | if (call_trace > 0) | ||
248 | return; | ||
249 | printk("Legacy call trace:"); | ||
250 | i = 18; | ||
251 | } | ||
252 | } | ||
253 | |||
210 | #define HANDLE_STACK(cond) \ | 254 | #define HANDLE_STACK(cond) \ |
211 | do while (cond) { \ | 255 | do while (cond) { \ |
212 | unsigned long addr = *stack++; \ | 256 | unsigned long addr = *stack++; \ |
@@ -229,7 +273,7 @@ void show_trace(unsigned long *stack) | |||
229 | } \ | 273 | } \ |
230 | } while (0) | 274 | } while (0) |
231 | 275 | ||
232 | for(i = 11; ; ) { | 276 | for(; ; ) { |
233 | const char *id; | 277 | const char *id; |
234 | unsigned long *estack_end; | 278 | unsigned long *estack_end; |
235 | estack_end = in_exception_stack(cpu, (unsigned long)stack, | 279 | estack_end = in_exception_stack(cpu, (unsigned long)stack, |
@@ -264,7 +308,7 @@ void show_trace(unsigned long *stack) | |||
264 | printk("\n"); | 308 | printk("\n"); |
265 | } | 309 | } |
266 | 310 | ||
267 | void show_stack(struct task_struct *tsk, unsigned long * rsp) | 311 | static void _show_stack(struct task_struct *tsk, struct pt_regs *regs, unsigned long * rsp) |
268 | { | 312 | { |
269 | unsigned long *stack; | 313 | unsigned long *stack; |
270 | int i; | 314 | int i; |
@@ -298,7 +342,12 @@ void show_stack(struct task_struct *tsk, unsigned long * rsp) | |||
298 | printk("%016lx ", *stack++); | 342 | printk("%016lx ", *stack++); |
299 | touch_nmi_watchdog(); | 343 | touch_nmi_watchdog(); |
300 | } | 344 | } |
301 | show_trace((unsigned long *)rsp); | 345 | show_trace(tsk, regs, rsp); |
346 | } | ||
347 | |||
348 | void show_stack(struct task_struct *tsk, unsigned long * rsp) | ||
349 | { | ||
350 | _show_stack(tsk, NULL, rsp); | ||
302 | } | 351 | } |
303 | 352 | ||
304 | /* | 353 | /* |
@@ -307,7 +356,7 @@ void show_stack(struct task_struct *tsk, unsigned long * rsp) | |||
307 | void dump_stack(void) | 356 | void dump_stack(void) |
308 | { | 357 | { |
309 | unsigned long dummy; | 358 | unsigned long dummy; |
310 | show_trace(&dummy); | 359 | show_trace(NULL, NULL, &dummy); |
311 | } | 360 | } |
312 | 361 | ||
313 | EXPORT_SYMBOL(dump_stack); | 362 | EXPORT_SYMBOL(dump_stack); |
@@ -334,7 +383,7 @@ void show_registers(struct pt_regs *regs) | |||
334 | if (in_kernel) { | 383 | if (in_kernel) { |
335 | 384 | ||
336 | printk("Stack: "); | 385 | printk("Stack: "); |
337 | show_stack(NULL, (unsigned long*)rsp); | 386 | _show_stack(NULL, regs, (unsigned long*)rsp); |
338 | 387 | ||
339 | printk("\nCode: "); | 388 | printk("\nCode: "); |
340 | if (regs->rip < PAGE_OFFSET) | 389 | if (regs->rip < PAGE_OFFSET) |
@@ -383,6 +432,7 @@ void out_of_line_bug(void) | |||
383 | { | 432 | { |
384 | BUG(); | 433 | BUG(); |
385 | } | 434 | } |
435 | EXPORT_SYMBOL(out_of_line_bug); | ||
386 | #endif | 436 | #endif |
387 | 437 | ||
388 | static DEFINE_SPINLOCK(die_lock); | 438 | static DEFINE_SPINLOCK(die_lock); |
@@ -1012,3 +1062,14 @@ static int __init kstack_setup(char *s) | |||
1012 | } | 1062 | } |
1013 | __setup("kstack=", kstack_setup); | 1063 | __setup("kstack=", kstack_setup); |
1014 | 1064 | ||
1065 | static int __init call_trace_setup(char *s) | ||
1066 | { | ||
1067 | if (strcmp(s, "old") == 0) | ||
1068 | call_trace = -1; | ||
1069 | else if (strcmp(s, "both") == 0) | ||
1070 | call_trace = 0; | ||
1071 | else if (strcmp(s, "new") == 0) | ||
1072 | call_trace = 1; | ||
1073 | return 1; | ||
1074 | } | ||
1075 | __setup("call_trace=", call_trace_setup); | ||