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.c139
1 files changed, 25 insertions, 114 deletions
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index 0d65b22f229c..09d2e8a10a49 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,12 +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
113static int call_trace = 1;
114#else
115#define call_trace (-1)
116#endif
117 113
118#ifdef CONFIG_KALLSYMS 114#ifdef CONFIG_KALLSYMS
119void printk_address(unsigned long address) 115void printk_address(unsigned long address)
@@ -216,24 +212,7 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
216 return NULL; 212 return NULL;
217} 213}
218 214
219struct ops_and_data { 215#define MSG(txt) ops->warning(data, txt)
220 struct stacktrace_ops *ops;
221 void *data;
222};
223
224static int dump_trace_unwind(struct unwind_frame_info *info, void *context)
225{
226 struct ops_and_data *oad = (struct ops_and_data *)context;
227 int n = 0;
228
229 while (unwind(info) == 0 && UNW_PC(info)) {
230 n++;
231 oad->ops->address(oad->data, UNW_PC(info));
232 if (arch_unw_user_mode(info))
233 break;
234 }
235 return n;
236}
237 216
238/* 217/*
239 * x86-64 can have upto three kernel stacks: 218 * x86-64 can have upto three kernel stacks:
@@ -248,61 +227,24 @@ static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
248 return p > t && p < t + THREAD_SIZE - 3; 227 return p > t && p < t + THREAD_SIZE - 3;
249} 228}
250 229
251void dump_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * stack, 230void dump_trace(struct task_struct *tsk, struct pt_regs *regs,
231 unsigned long *stack,
252 struct stacktrace_ops *ops, void *data) 232 struct stacktrace_ops *ops, void *data)
253{ 233{
254 const unsigned cpu = smp_processor_id(); 234 const unsigned cpu = get_cpu();
255 unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr; 235 unsigned long *irqstack_end = (unsigned long*)cpu_pda(cpu)->irqstackptr;
256 unsigned used = 0; 236 unsigned used = 0;
257 struct thread_info *tinfo; 237 struct thread_info *tinfo;
258 238
259 if (!tsk) 239 if (!tsk)
260 tsk = current; 240 tsk = current;
261 241
262 if (call_trace >= 0) {
263 int unw_ret = 0;
264 struct unwind_frame_info info;
265 struct ops_and_data oad = { .ops = ops, .data = data };
266
267 if (regs) {
268 if (unwind_init_frame_info(&info, tsk, regs) == 0)
269 unw_ret = dump_trace_unwind(&info, &oad);
270 } else if (tsk == current)
271 unw_ret = unwind_init_running(&info, dump_trace_unwind, &oad);
272 else {
273 if (unwind_init_blocked(&info, tsk) == 0)
274 unw_ret = dump_trace_unwind(&info, &oad);
275 }
276 if (unw_ret > 0) {
277 if (call_trace == 1 && !arch_unw_user_mode(&info)) {
278 ops->warning_symbol(data, "DWARF2 unwinder stuck at %s\n",
279 UNW_PC(&info));
280 if ((long)UNW_SP(&info) < 0) {
281 ops->warning(data, "Leftover inexact backtrace:\n");
282 stack = (unsigned long *)UNW_SP(&info);
283 if (!stack)
284 return;
285 } else
286 ops->warning(data, "Full inexact backtrace again:\n");
287 } else if (call_trace >= 1)
288 return;
289 else
290 ops->warning(data, "Full inexact backtrace again:\n");
291 } else
292 ops->warning(data, "Inexact backtrace:\n");
293 }
294 if (!stack) { 242 if (!stack) {
295 unsigned long dummy; 243 unsigned long dummy;
296 stack = &dummy; 244 stack = &dummy;
297 if (tsk && tsk != current) 245 if (tsk && tsk != current)
298 stack = (unsigned long *)tsk->thread.rsp; 246 stack = (unsigned long *)tsk->thread.rsp;
299 } 247 }
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 248
307 /* 249 /*
308 * Print function call entries within a stack. 'cond' is the 250 * Print function call entries within a stack. 'cond' is the
@@ -312,9 +254,9 @@ void dump_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s
312#define HANDLE_STACK(cond) \ 254#define HANDLE_STACK(cond) \
313 do while (cond) { \ 255 do while (cond) { \
314 unsigned long addr = *stack++; \ 256 unsigned long addr = *stack++; \
315 if (oops_in_progress ? \ 257 /* Use unlocked access here because except for NMIs \
316 __kernel_text_address(addr) : \ 258 we should be already protected against module unloads */ \
317 kernel_text_address(addr)) { \ 259 if (__kernel_text_address(addr)) { \
318 /* \ 260 /* \
319 * If the address is either in the text segment of the \ 261 * If the address is either in the text segment of the \
320 * kernel, or in the region which contains vmalloc'ed \ 262 * kernel, or in the region which contains vmalloc'ed \
@@ -377,9 +319,10 @@ void dump_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s
377 /* 319 /*
378 * This handles the process stack: 320 * This handles the process stack:
379 */ 321 */
380 tinfo = current_thread_info(); 322 tinfo = task_thread_info(tsk);
381 HANDLE_STACK (valid_stack_ptr(tinfo, stack)); 323 HANDLE_STACK (valid_stack_ptr(tinfo, stack));
382#undef HANDLE_STACK 324#undef HANDLE_STACK
325 put_cpu();
383} 326}
384EXPORT_SYMBOL(dump_trace); 327EXPORT_SYMBOL(dump_trace);
385 328
@@ -516,30 +459,15 @@ bad:
516 printk("\n"); 459 printk("\n");
517} 460}
518 461
519void handle_BUG(struct pt_regs *regs) 462int is_valid_bugaddr(unsigned long rip)
520{ 463{
521 struct bug_frame f; 464 unsigned short ud2;
522 long len;
523 const char *prefix = "";
524 465
525 if (user_mode(regs)) 466 if (__copy_from_user(&ud2, (const void __user *) rip, sizeof(ud2)))
526 return; 467 return 0;
527 if (__copy_from_user(&f, (const void __user *) regs->rip, 468
528 sizeof(struct bug_frame))) 469 return ud2 == 0x0b0f;
529 return; 470}
530 if (f.filename >= 0 ||
531 f.ud2[0] != 0x0f || f.ud2[1] != 0x0b)
532 return;
533 len = __strnlen_user((char *)(long)f.filename, PATH_MAX) - 1;
534 if (len < 0 || len >= PATH_MAX)
535 f.filename = (int)(long)"unmapped filename";
536 else if (len > 50) {
537 f.filename += len - 50;
538 prefix = "...";
539 }
540 printk("----------- [cut here ] --------- [please bite here ] ---------\n");
541 printk(KERN_ALERT "Kernel BUG at %s%.50s:%d\n", prefix, (char *)(long)f.filename, f.line);
542}
543 471
544#ifdef CONFIG_BUG 472#ifdef CONFIG_BUG
545void out_of_line_bug(void) 473void out_of_line_bug(void)
@@ -619,7 +547,9 @@ void die(const char * str, struct pt_regs * regs, long err)
619{ 547{
620 unsigned long flags = oops_begin(); 548 unsigned long flags = oops_begin();
621 549
622 handle_BUG(regs); 550 if (!user_mode(regs))
551 report_bug(regs->rip);
552
623 __die(str, regs, err); 553 __die(str, regs, err);
624 oops_end(flags); 554 oops_end(flags);
625 do_exit(SIGSEGV); 555 do_exit(SIGSEGV);
@@ -786,8 +716,7 @@ mem_parity_error(unsigned char reason, struct pt_regs * regs)
786{ 716{
787 printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n", 717 printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n",
788 reason); 718 reason);
789 printk(KERN_EMERG "You probably have a hardware problem with your " 719 printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n");
790 "RAM chips\n");
791 720
792 if (panic_on_unrecovered_nmi) 721 if (panic_on_unrecovered_nmi)
793 panic("NMI: Not continuing"); 722 panic("NMI: Not continuing");
@@ -1193,21 +1122,3 @@ static int __init kstack_setup(char *s)
1193 return 0; 1122 return 0;
1194} 1123}
1195early_param("kstack", kstack_setup); 1124early_param("kstack", kstack_setup);
1196
1197#ifdef CONFIG_STACK_UNWIND
1198static int __init call_trace_setup(char *s)
1199{
1200 if (!s)
1201 return -EINVAL;
1202 if (strcmp(s, "old") == 0)
1203 call_trace = -1;
1204 else if (strcmp(s, "both") == 0)
1205 call_trace = 0;
1206 else if (strcmp(s, "newfallback") == 0)
1207 call_trace = 1;
1208 else if (strcmp(s, "new") == 0)
1209 call_trace = 2;
1210 return 0;
1211}
1212early_param("call_trace", call_trace_setup);
1213#endif