diff options
Diffstat (limited to 'arch/x86_64/kernel/traps.c')
-rw-r--r-- | arch/x86_64/kernel/traps.c | 55 |
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 | ||
111 | static int kstack_depth_to_print = 12; | 111 | int kstack_depth_to_print = 12; |
112 | #ifdef CONFIG_STACK_UNWIND | 112 | #ifdef CONFIG_STACK_UNWIND |
113 | static int call_trace = 1; | 113 | static 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 | ||
251 | void dump_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * stack, | 260 | void 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 |
389 | out: | ||
390 | put_cpu(); | ||
383 | } | 391 | } |
384 | EXPORT_SYMBOL(dump_trace); | 392 | EXPORT_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"); |