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.c95
1 files changed, 52 insertions, 43 deletions
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index 7819022a8db5..b54ccc07f379 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -30,9 +30,10 @@
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>
34#include <linux/bug.h>
33 35
34#include <asm/system.h> 36#include <asm/system.h>
35#include <asm/uaccess.h>
36#include <asm/io.h> 37#include <asm/io.h>
37#include <asm/atomic.h> 38#include <asm/atomic.h>
38#include <asm/debugreg.h> 39#include <asm/debugreg.h>
@@ -108,7 +109,7 @@ static inline void preempt_conditional_cli(struct pt_regs *regs)
108 preempt_enable_no_resched(); 109 preempt_enable_no_resched();
109} 110}
110 111
111static int kstack_depth_to_print = 12; 112int kstack_depth_to_print = 12;
112#ifdef CONFIG_STACK_UNWIND 113#ifdef CONFIG_STACK_UNWIND
113static int call_trace = 1; 114static int call_trace = 1;
114#else 115#else
@@ -225,16 +226,25 @@ static int dump_trace_unwind(struct unwind_frame_info *info, void *context)
225{ 226{
226 struct ops_and_data *oad = (struct ops_and_data *)context; 227 struct ops_and_data *oad = (struct ops_and_data *)context;
227 int n = 0; 228 int n = 0;
229 unsigned long sp = UNW_SP(info);
228 230
231 if (arch_unw_user_mode(info))
232 return -1;
229 while (unwind(info) == 0 && UNW_PC(info)) { 233 while (unwind(info) == 0 && UNW_PC(info)) {
230 n++; 234 n++;
231 oad->ops->address(oad->data, UNW_PC(info)); 235 oad->ops->address(oad->data, UNW_PC(info));
232 if (arch_unw_user_mode(info)) 236 if (arch_unw_user_mode(info))
233 break; 237 break;
238 if ((sp & ~(PAGE_SIZE - 1)) == (UNW_SP(info) & ~(PAGE_SIZE - 1))
239 && sp > UNW_SP(info))
240 break;
241 sp = UNW_SP(info);
234 } 242 }
235 return n; 243 return n;
236} 244}
237 245
246#define MSG(txt) ops->warning(data, txt)
247
238/* 248/*
239 * x86-64 can have upto three kernel stacks: 249 * x86-64 can have upto three kernel stacks:
240 * process stack 250 * process stack
@@ -242,12 +252,20 @@ static int dump_trace_unwind(struct unwind_frame_info *info, void *context)
242 * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack 252 * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
243 */ 253 */
244 254
245void dump_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * stack, 255static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
256{
257 void *t = (void *)tinfo;
258 return p > t && p < t + THREAD_SIZE - 3;
259}
260
261void dump_trace(struct task_struct *tsk, struct pt_regs *regs,
262 unsigned long *stack,
246 struct stacktrace_ops *ops, void *data) 263 struct stacktrace_ops *ops, void *data)
247{ 264{
248 const unsigned cpu = smp_processor_id(); 265 const unsigned cpu = get_cpu();
249 unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr; 266 unsigned long *irqstack_end = (unsigned long*)cpu_pda(cpu)->irqstackptr;
250 unsigned used = 0; 267 unsigned used = 0;
268 struct thread_info *tinfo;
251 269
252 if (!tsk) 270 if (!tsk)
253 tsk = current; 271 tsk = current;
@@ -261,28 +279,30 @@ void dump_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s
261 if (unwind_init_frame_info(&info, tsk, regs) == 0) 279 if (unwind_init_frame_info(&info, tsk, regs) == 0)
262 unw_ret = dump_trace_unwind(&info, &oad); 280 unw_ret = dump_trace_unwind(&info, &oad);
263 } else if (tsk == current) 281 } else if (tsk == current)
264 unw_ret = unwind_init_running(&info, dump_trace_unwind, &oad); 282 unw_ret = unwind_init_running(&info, dump_trace_unwind,
283 &oad);
265 else { 284 else {
266 if (unwind_init_blocked(&info, tsk) == 0) 285 if (unwind_init_blocked(&info, tsk) == 0)
267 unw_ret = dump_trace_unwind(&info, &oad); 286 unw_ret = dump_trace_unwind(&info, &oad);
268 } 287 }
269 if (unw_ret > 0) { 288 if (unw_ret > 0) {
270 if (call_trace == 1 && !arch_unw_user_mode(&info)) { 289 if (call_trace == 1 && !arch_unw_user_mode(&info)) {
271 ops->warning_symbol(data, "DWARF2 unwinder stuck at %s\n", 290 ops->warning_symbol(data,
291 "DWARF2 unwinder stuck at %s",
272 UNW_PC(&info)); 292 UNW_PC(&info));
273 if ((long)UNW_SP(&info) < 0) { 293 if ((long)UNW_SP(&info) < 0) {
274 ops->warning(data, "Leftover inexact backtrace:\n"); 294 MSG("Leftover inexact backtrace:");
275 stack = (unsigned long *)UNW_SP(&info); 295 stack = (unsigned long *)UNW_SP(&info);
276 if (!stack) 296 if (!stack)
277 return; 297 goto out;
278 } else 298 } else
279 ops->warning(data, "Full inexact backtrace again:\n"); 299 MSG("Full inexact backtrace again:");
280 } else if (call_trace >= 1) 300 } else if (call_trace >= 1)
281 return; 301 goto out;
282 else 302 else
283 ops->warning(data, "Full inexact backtrace again:\n"); 303 MSG("Full inexact backtrace again:");
284 } else 304 } else
285 ops->warning(data, "Inexact backtrace:\n"); 305 MSG("Inexact backtrace:");
286 } 306 }
287 if (!stack) { 307 if (!stack) {
288 unsigned long dummy; 308 unsigned long dummy;
@@ -299,9 +319,9 @@ void dump_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s
299#define HANDLE_STACK(cond) \ 319#define HANDLE_STACK(cond) \
300 do while (cond) { \ 320 do while (cond) { \
301 unsigned long addr = *stack++; \ 321 unsigned long addr = *stack++; \
302 if (oops_in_progress ? \ 322 /* Use unlocked access here because except for NMIs \
303 __kernel_text_address(addr) : \ 323 we should be already protected against module unloads */ \
304 kernel_text_address(addr)) { \ 324 if (__kernel_text_address(addr)) { \
305 /* \ 325 /* \
306 * If the address is either in the text segment of the \ 326 * If the address is either in the text segment of the \
307 * kernel, or in the region which contains vmalloc'ed \ 327 * kernel, or in the region which contains vmalloc'ed \
@@ -364,8 +384,11 @@ void dump_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s
364 /* 384 /*
365 * This handles the process stack: 385 * This handles the process stack:
366 */ 386 */
367 HANDLE_STACK (((long) stack & (THREAD_SIZE-1)) != 0); 387 tinfo = current_thread_info();
388 HANDLE_STACK (valid_stack_ptr(tinfo, stack));
368#undef HANDLE_STACK 389#undef HANDLE_STACK
390out:
391 put_cpu();
369} 392}
370EXPORT_SYMBOL(dump_trace); 393EXPORT_SYMBOL(dump_trace);
371 394
@@ -502,30 +525,15 @@ bad:
502 printk("\n"); 525 printk("\n");
503} 526}
504 527
505void handle_BUG(struct pt_regs *regs) 528int is_valid_bugaddr(unsigned long rip)
506{ 529{
507 struct bug_frame f; 530 unsigned short ud2;
508 long len;
509 const char *prefix = "";
510 531
511 if (user_mode(regs)) 532 if (__copy_from_user(&ud2, (const void __user *) rip, sizeof(ud2)))
512 return; 533 return 0;
513 if (__copy_from_user(&f, (const void __user *) regs->rip, 534
514 sizeof(struct bug_frame))) 535 return ud2 == 0x0b0f;
515 return; 536}
516 if (f.filename >= 0 ||
517 f.ud2[0] != 0x0f || f.ud2[1] != 0x0b)
518 return;
519 len = __strnlen_user((char *)(long)f.filename, PATH_MAX) - 1;
520 if (len < 0 || len >= PATH_MAX)
521 f.filename = (int)(long)"unmapped filename";
522 else if (len > 50) {
523 f.filename += len - 50;
524 prefix = "...";
525 }
526 printk("----------- [cut here ] --------- [please bite here ] ---------\n");
527 printk(KERN_ALERT "Kernel BUG at %s%.50s:%d\n", prefix, (char *)(long)f.filename, f.line);
528}
529 537
530#ifdef CONFIG_BUG 538#ifdef CONFIG_BUG
531void out_of_line_bug(void) 539void out_of_line_bug(void)
@@ -605,7 +613,9 @@ void die(const char * str, struct pt_regs * regs, long err)
605{ 613{
606 unsigned long flags = oops_begin(); 614 unsigned long flags = oops_begin();
607 615
608 handle_BUG(regs); 616 if (!user_mode(regs))
617 report_bug(regs->rip);
618
609 __die(str, regs, err); 619 __die(str, regs, err);
610 oops_end(flags); 620 oops_end(flags);
611 do_exit(SIGSEGV); 621 do_exit(SIGSEGV);
@@ -772,8 +782,7 @@ mem_parity_error(unsigned char reason, struct pt_regs * regs)
772{ 782{
773 printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n", 783 printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n",
774 reason); 784 reason);
775 printk(KERN_EMERG "You probably have a hardware problem with your " 785 printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n");
776 "RAM chips\n");
777 786
778 if (panic_on_unrecovered_nmi) 787 if (panic_on_unrecovered_nmi)
779 panic("NMI: Not continuing"); 788 panic("NMI: Not continuing");