aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64/kernel/traps.c')
-rw-r--r--arch/x86_64/kernel/traps.c55
1 files changed, 31 insertions, 24 deletions
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index 0d65b22f229c..a1641ffdffcf 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -30,9 +30,9 @@
30#include <linux/kprobes.h> 30#include <linux/kprobes.h>
31#include <linux/kexec.h> 31#include <linux/kexec.h>
32#include <linux/unwind.h> 32#include <linux/unwind.h>
33#include <linux/uaccess.h>
33 34
34#include <asm/system.h> 35#include <asm/system.h>
35#include <asm/uaccess.h>
36#include <asm/io.h> 36#include <asm/io.h>
37#include <asm/atomic.h> 37#include <asm/atomic.h>
38#include <asm/debugreg.h> 38#include <asm/debugreg.h>
@@ -108,7 +108,7 @@ static inline void preempt_conditional_cli(struct pt_regs *regs)
108 preempt_enable_no_resched(); 108 preempt_enable_no_resched();
109} 109}
110 110
111static int kstack_depth_to_print = 12; 111int kstack_depth_to_print = 12;
112#ifdef CONFIG_STACK_UNWIND 112#ifdef CONFIG_STACK_UNWIND
113static int call_trace = 1; 113static int call_trace = 1;
114#else 114#else
@@ -225,16 +225,25 @@ static int dump_trace_unwind(struct unwind_frame_info *info, void *context)
225{ 225{
226 struct ops_and_data *oad = (struct ops_and_data *)context; 226 struct ops_and_data *oad = (struct ops_and_data *)context;
227 int n = 0; 227 int n = 0;
228 unsigned long sp = UNW_SP(info);
228 229
230 if (arch_unw_user_mode(info))
231 return -1;
229 while (unwind(info) == 0 && UNW_PC(info)) { 232 while (unwind(info) == 0 && UNW_PC(info)) {
230 n++; 233 n++;
231 oad->ops->address(oad->data, UNW_PC(info)); 234 oad->ops->address(oad->data, UNW_PC(info));
232 if (arch_unw_user_mode(info)) 235 if (arch_unw_user_mode(info))
233 break; 236 break;
237 if ((sp & ~(PAGE_SIZE - 1)) == (UNW_SP(info) & ~(PAGE_SIZE - 1))
238 && sp > UNW_SP(info))
239 break;
240 sp = UNW_SP(info);
234 } 241 }
235 return n; 242 return n;
236} 243}
237 244
245#define MSG(txt) ops->warning(data, txt)
246
238/* 247/*
239 * x86-64 can have upto three kernel stacks: 248 * x86-64 can have upto three kernel stacks:
240 * process stack 249 * process stack
@@ -248,11 +257,12 @@ static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
248 return p > t && p < t + THREAD_SIZE - 3; 257 return p > t && p < t + THREAD_SIZE - 3;
249} 258}
250 259
251void dump_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * stack, 260void dump_trace(struct task_struct *tsk, struct pt_regs *regs,
261 unsigned long *stack,
252 struct stacktrace_ops *ops, void *data) 262 struct stacktrace_ops *ops, void *data)
253{ 263{
254 const unsigned cpu = smp_processor_id(); 264 const unsigned cpu = get_cpu();
255 unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr; 265 unsigned long *irqstack_end = (unsigned long*)cpu_pda(cpu)->irqstackptr;
256 unsigned used = 0; 266 unsigned used = 0;
257 struct thread_info *tinfo; 267 struct thread_info *tinfo;
258 268
@@ -268,28 +278,30 @@ void dump_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s
268 if (unwind_init_frame_info(&info, tsk, regs) == 0) 278 if (unwind_init_frame_info(&info, tsk, regs) == 0)
269 unw_ret = dump_trace_unwind(&info, &oad); 279 unw_ret = dump_trace_unwind(&info, &oad);
270 } else if (tsk == current) 280 } else if (tsk == current)
271 unw_ret = unwind_init_running(&info, dump_trace_unwind, &oad); 281 unw_ret = unwind_init_running(&info, dump_trace_unwind,
282 &oad);
272 else { 283 else {
273 if (unwind_init_blocked(&info, tsk) == 0) 284 if (unwind_init_blocked(&info, tsk) == 0)
274 unw_ret = dump_trace_unwind(&info, &oad); 285 unw_ret = dump_trace_unwind(&info, &oad);
275 } 286 }
276 if (unw_ret > 0) { 287 if (unw_ret > 0) {
277 if (call_trace == 1 && !arch_unw_user_mode(&info)) { 288 if (call_trace == 1 && !arch_unw_user_mode(&info)) {
278 ops->warning_symbol(data, "DWARF2 unwinder stuck at %s\n", 289 ops->warning_symbol(data,
290 "DWARF2 unwinder stuck at %s",
279 UNW_PC(&info)); 291 UNW_PC(&info));
280 if ((long)UNW_SP(&info) < 0) { 292 if ((long)UNW_SP(&info) < 0) {
281 ops->warning(data, "Leftover inexact backtrace:\n"); 293 MSG("Leftover inexact backtrace:");
282 stack = (unsigned long *)UNW_SP(&info); 294 stack = (unsigned long *)UNW_SP(&info);
283 if (!stack) 295 if (!stack)
284 return; 296 goto out;
285 } else 297 } else
286 ops->warning(data, "Full inexact backtrace again:\n"); 298 MSG("Full inexact backtrace again:");
287 } else if (call_trace >= 1) 299 } else if (call_trace >= 1)
288 return; 300 goto out;
289 else 301 else
290 ops->warning(data, "Full inexact backtrace again:\n"); 302 MSG("Full inexact backtrace again:");
291 } else 303 } else
292 ops->warning(data, "Inexact backtrace:\n"); 304 MSG("Inexact backtrace:");
293 } 305 }
294 if (!stack) { 306 if (!stack) {
295 unsigned long dummy; 307 unsigned long dummy;
@@ -297,12 +309,6 @@ void dump_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s
297 if (tsk && tsk != current) 309 if (tsk && tsk != current)
298 stack = (unsigned long *)tsk->thread.rsp; 310 stack = (unsigned long *)tsk->thread.rsp;
299 } 311 }
300 /*
301 * Align the stack pointer on word boundary, later loops
302 * rely on that (and corruption / debug info bugs can cause
303 * unaligned values here):
304 */
305 stack = (unsigned long *)((unsigned long)stack & ~(sizeof(long)-1));
306 312
307 /* 313 /*
308 * Print function call entries within a stack. 'cond' is the 314 * Print function call entries within a stack. 'cond' is the
@@ -312,9 +318,9 @@ void dump_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s
312#define HANDLE_STACK(cond) \ 318#define HANDLE_STACK(cond) \
313 do while (cond) { \ 319 do while (cond) { \
314 unsigned long addr = *stack++; \ 320 unsigned long addr = *stack++; \
315 if (oops_in_progress ? \ 321 /* Use unlocked access here because except for NMIs \
316 __kernel_text_address(addr) : \ 322 we should be already protected against module unloads */ \
317 kernel_text_address(addr)) { \ 323 if (__kernel_text_address(addr)) { \
318 /* \ 324 /* \
319 * If the address is either in the text segment of the \ 325 * If the address is either in the text segment of the \
320 * kernel, or in the region which contains vmalloc'ed \ 326 * kernel, or in the region which contains vmalloc'ed \
@@ -380,6 +386,8 @@ void dump_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s
380 tinfo = current_thread_info(); 386 tinfo = current_thread_info();
381 HANDLE_STACK (valid_stack_ptr(tinfo, stack)); 387 HANDLE_STACK (valid_stack_ptr(tinfo, stack));
382#undef HANDLE_STACK 388#undef HANDLE_STACK
389out:
390 put_cpu();
383} 391}
384EXPORT_SYMBOL(dump_trace); 392EXPORT_SYMBOL(dump_trace);
385 393
@@ -786,8 +794,7 @@ mem_parity_error(unsigned char reason, struct pt_regs * regs)
786{ 794{
787 printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n", 795 printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n",
788 reason); 796 reason);
789 printk(KERN_EMERG "You probably have a hardware problem with your " 797 printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n");
790 "RAM chips\n");
791 798
792 if (panic_on_unrecovered_nmi) 799 if (panic_on_unrecovered_nmi)
793 panic("NMI: Not continuing"); 800 panic("NMI: Not continuing");