diff options
Diffstat (limited to 'arch/x86_64/kernel/traps.c')
-rw-r--r-- | arch/x86_64/kernel/traps.c | 204 |
1 files changed, 131 insertions, 73 deletions
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index b1249774d1e8..01f2a8d254c2 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <asm/pda.h> | 45 | #include <asm/pda.h> |
46 | #include <asm/proto.h> | 46 | #include <asm/proto.h> |
47 | #include <asm/nmi.h> | 47 | #include <asm/nmi.h> |
48 | #include <asm/stacktrace.h> | ||
48 | 49 | ||
49 | asmlinkage void divide_error(void); | 50 | asmlinkage void divide_error(void); |
50 | asmlinkage void debug(void); | 51 | asmlinkage void debug(void); |
@@ -142,7 +143,7 @@ void printk_address(unsigned long address) | |||
142 | #endif | 143 | #endif |
143 | 144 | ||
144 | static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, | 145 | static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, |
145 | unsigned *usedp, const char **idp) | 146 | unsigned *usedp, char **idp) |
146 | { | 147 | { |
147 | static char ids[][8] = { | 148 | static char ids[][8] = { |
148 | [DEBUG_STACK - 1] = "#DB", | 149 | [DEBUG_STACK - 1] = "#DB", |
@@ -161,26 +162,7 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, | |||
161 | * 'stack' is in one of them: | 162 | * 'stack' is in one of them: |
162 | */ | 163 | */ |
163 | for (k = 0; k < N_EXCEPTION_STACKS; k++) { | 164 | for (k = 0; k < N_EXCEPTION_STACKS; k++) { |
164 | unsigned long end; | 165 | unsigned long end = per_cpu(orig_ist, cpu).ist[k]; |
165 | |||
166 | /* | ||
167 | * set 'end' to the end of the exception stack. | ||
168 | */ | ||
169 | switch (k + 1) { | ||
170 | /* | ||
171 | * TODO: this block is not needed i think, because | ||
172 | * setup64.c:cpu_init() sets up t->ist[DEBUG_STACK] | ||
173 | * properly too. | ||
174 | */ | ||
175 | #if DEBUG_STKSZ > EXCEPTION_STKSZ | ||
176 | case DEBUG_STACK: | ||
177 | end = cpu_pda(cpu)->debugstack + DEBUG_STKSZ; | ||
178 | break; | ||
179 | #endif | ||
180 | default: | ||
181 | end = per_cpu(orig_ist, cpu).ist[k]; | ||
182 | break; | ||
183 | } | ||
184 | /* | 166 | /* |
185 | * Is 'stack' above this exception frame's end? | 167 | * Is 'stack' above this exception frame's end? |
186 | * If yes then skip to the next frame. | 168 | * If yes then skip to the next frame. |
@@ -234,13 +216,19 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, | |||
234 | return NULL; | 216 | return NULL; |
235 | } | 217 | } |
236 | 218 | ||
237 | static int show_trace_unwind(struct unwind_frame_info *info, void *context) | 219 | struct ops_and_data { |
220 | struct stacktrace_ops *ops; | ||
221 | void *data; | ||
222 | }; | ||
223 | |||
224 | static int dump_trace_unwind(struct unwind_frame_info *info, void *context) | ||
238 | { | 225 | { |
226 | struct ops_and_data *oad = (struct ops_and_data *)context; | ||
239 | int n = 0; | 227 | int n = 0; |
240 | 228 | ||
241 | while (unwind(info) == 0 && UNW_PC(info)) { | 229 | while (unwind(info) == 0 && UNW_PC(info)) { |
242 | n++; | 230 | n++; |
243 | printk_address(UNW_PC(info)); | 231 | oad->ops->address(oad->data, UNW_PC(info)); |
244 | if (arch_unw_user_mode(info)) | 232 | if (arch_unw_user_mode(info)) |
245 | break; | 233 | break; |
246 | } | 234 | } |
@@ -254,45 +242,53 @@ static int show_trace_unwind(struct unwind_frame_info *info, void *context) | |||
254 | * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack | 242 | * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack |
255 | */ | 243 | */ |
256 | 244 | ||
257 | void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * stack) | 245 | void dump_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * stack, |
246 | struct stacktrace_ops *ops, void *data) | ||
258 | { | 247 | { |
259 | const unsigned cpu = safe_smp_processor_id(); | 248 | const unsigned cpu = smp_processor_id(); |
260 | unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr; | 249 | unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr; |
261 | unsigned used = 0; | 250 | unsigned used = 0; |
262 | 251 | ||
263 | printk("\nCall Trace:\n"); | ||
264 | |||
265 | if (!tsk) | 252 | if (!tsk) |
266 | tsk = current; | 253 | tsk = current; |
267 | 254 | ||
268 | if (call_trace >= 0) { | 255 | if (call_trace >= 0) { |
269 | int unw_ret = 0; | 256 | int unw_ret = 0; |
270 | struct unwind_frame_info info; | 257 | struct unwind_frame_info info; |
258 | struct ops_and_data oad = { .ops = ops, .data = data }; | ||
271 | 259 | ||
272 | if (regs) { | 260 | if (regs) { |
273 | if (unwind_init_frame_info(&info, tsk, regs) == 0) | 261 | if (unwind_init_frame_info(&info, tsk, regs) == 0) |
274 | unw_ret = show_trace_unwind(&info, NULL); | 262 | unw_ret = dump_trace_unwind(&info, &oad); |
275 | } else if (tsk == current) | 263 | } else if (tsk == current) |
276 | unw_ret = unwind_init_running(&info, show_trace_unwind, NULL); | 264 | unw_ret = unwind_init_running(&info, dump_trace_unwind, &oad); |
277 | else { | 265 | else { |
278 | if (unwind_init_blocked(&info, tsk) == 0) | 266 | if (unwind_init_blocked(&info, tsk) == 0) |
279 | unw_ret = show_trace_unwind(&info, NULL); | 267 | unw_ret = dump_trace_unwind(&info, &oad); |
280 | } | 268 | } |
281 | if (unw_ret > 0) { | 269 | if (unw_ret > 0) { |
282 | if (call_trace == 1 && !arch_unw_user_mode(&info)) { | 270 | if (call_trace == 1 && !arch_unw_user_mode(&info)) { |
283 | print_symbol("DWARF2 unwinder stuck at %s\n", | 271 | ops->warning_symbol(data, "DWARF2 unwinder stuck at %s\n", |
284 | UNW_PC(&info)); | 272 | UNW_PC(&info)); |
285 | if ((long)UNW_SP(&info) < 0) { | 273 | if ((long)UNW_SP(&info) < 0) { |
286 | printk("Leftover inexact backtrace:\n"); | 274 | ops->warning(data, "Leftover inexact backtrace:\n"); |
287 | stack = (unsigned long *)UNW_SP(&info); | 275 | stack = (unsigned long *)UNW_SP(&info); |
276 | if (!stack) | ||
277 | return; | ||
288 | } else | 278 | } else |
289 | printk("Full inexact backtrace again:\n"); | 279 | ops->warning(data, "Full inexact backtrace again:\n"); |
290 | } else if (call_trace >= 1) | 280 | } else if (call_trace >= 1) |
291 | return; | 281 | return; |
292 | else | 282 | else |
293 | printk("Full inexact backtrace again:\n"); | 283 | ops->warning(data, "Full inexact backtrace again:\n"); |
294 | } else | 284 | } else |
295 | printk("Inexact backtrace:\n"); | 285 | ops->warning(data, "Inexact backtrace:\n"); |
286 | } | ||
287 | if (!stack) { | ||
288 | unsigned long dummy; | ||
289 | stack = &dummy; | ||
290 | if (tsk && tsk != current) | ||
291 | stack = (unsigned long *)tsk->thread.rsp; | ||
296 | } | 292 | } |
297 | 293 | ||
298 | /* | 294 | /* |
@@ -303,7 +299,9 @@ void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s | |||
303 | #define HANDLE_STACK(cond) \ | 299 | #define HANDLE_STACK(cond) \ |
304 | do while (cond) { \ | 300 | do while (cond) { \ |
305 | unsigned long addr = *stack++; \ | 301 | unsigned long addr = *stack++; \ |
306 | if (kernel_text_address(addr)) { \ | 302 | if (oops_in_progress ? \ |
303 | __kernel_text_address(addr) : \ | ||
304 | kernel_text_address(addr)) { \ | ||
307 | /* \ | 305 | /* \ |
308 | * If the address is either in the text segment of the \ | 306 | * If the address is either in the text segment of the \ |
309 | * kernel, or in the region which contains vmalloc'ed \ | 307 | * kernel, or in the region which contains vmalloc'ed \ |
@@ -312,7 +310,7 @@ void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s | |||
312 | * down the cause of the crash will be able to figure \ | 310 | * down the cause of the crash will be able to figure \ |
313 | * out the call path that was taken. \ | 311 | * out the call path that was taken. \ |
314 | */ \ | 312 | */ \ |
315 | printk_address(addr); \ | 313 | ops->address(data, addr); \ |
316 | } \ | 314 | } \ |
317 | } while (0) | 315 | } while (0) |
318 | 316 | ||
@@ -321,16 +319,17 @@ void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s | |||
321 | * current stack address. If the stacks consist of nested | 319 | * current stack address. If the stacks consist of nested |
322 | * exceptions | 320 | * exceptions |
323 | */ | 321 | */ |
324 | for ( ; ; ) { | 322 | for (;;) { |
325 | const char *id; | 323 | char *id; |
326 | unsigned long *estack_end; | 324 | unsigned long *estack_end; |
327 | estack_end = in_exception_stack(cpu, (unsigned long)stack, | 325 | estack_end = in_exception_stack(cpu, (unsigned long)stack, |
328 | &used, &id); | 326 | &used, &id); |
329 | 327 | ||
330 | if (estack_end) { | 328 | if (estack_end) { |
331 | printk(" <%s>", id); | 329 | if (ops->stack(data, id) < 0) |
330 | break; | ||
332 | HANDLE_STACK (stack < estack_end); | 331 | HANDLE_STACK (stack < estack_end); |
333 | printk(" <EOE>"); | 332 | ops->stack(data, "<EOE>"); |
334 | /* | 333 | /* |
335 | * We link to the next stack via the | 334 | * We link to the next stack via the |
336 | * second-to-last pointer (index -2 to end) in the | 335 | * second-to-last pointer (index -2 to end) in the |
@@ -345,7 +344,8 @@ void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s | |||
345 | (IRQSTACKSIZE - 64) / sizeof(*irqstack); | 344 | (IRQSTACKSIZE - 64) / sizeof(*irqstack); |
346 | 345 | ||
347 | if (stack >= irqstack && stack < irqstack_end) { | 346 | if (stack >= irqstack && stack < irqstack_end) { |
348 | printk(" <IRQ>"); | 347 | if (ops->stack(data, "IRQ") < 0) |
348 | break; | ||
349 | HANDLE_STACK (stack < irqstack_end); | 349 | HANDLE_STACK (stack < irqstack_end); |
350 | /* | 350 | /* |
351 | * We link to the next stack (which would be | 351 | * We link to the next stack (which would be |
@@ -354,7 +354,7 @@ void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s | |||
354 | */ | 354 | */ |
355 | stack = (unsigned long *) (irqstack_end[-1]); | 355 | stack = (unsigned long *) (irqstack_end[-1]); |
356 | irqstack_end = NULL; | 356 | irqstack_end = NULL; |
357 | printk(" <EOI>"); | 357 | ops->stack(data, "EOI"); |
358 | continue; | 358 | continue; |
359 | } | 359 | } |
360 | } | 360 | } |
@@ -362,19 +362,57 @@ void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s | |||
362 | } | 362 | } |
363 | 363 | ||
364 | /* | 364 | /* |
365 | * This prints the process stack: | 365 | * This handles the process stack: |
366 | */ | 366 | */ |
367 | HANDLE_STACK (((long) stack & (THREAD_SIZE-1)) != 0); | 367 | HANDLE_STACK (((long) stack & (THREAD_SIZE-1)) != 0); |
368 | #undef HANDLE_STACK | 368 | #undef HANDLE_STACK |
369 | } | ||
370 | EXPORT_SYMBOL(dump_trace); | ||
371 | |||
372 | static void | ||
373 | print_trace_warning_symbol(void *data, char *msg, unsigned long symbol) | ||
374 | { | ||
375 | print_symbol(msg, symbol); | ||
376 | printk("\n"); | ||
377 | } | ||
378 | |||
379 | static void print_trace_warning(void *data, char *msg) | ||
380 | { | ||
381 | printk("%s\n", msg); | ||
382 | } | ||
383 | |||
384 | static int print_trace_stack(void *data, char *name) | ||
385 | { | ||
386 | printk(" <%s> ", name); | ||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | static void print_trace_address(void *data, unsigned long addr) | ||
391 | { | ||
392 | printk_address(addr); | ||
393 | } | ||
394 | |||
395 | static struct stacktrace_ops print_trace_ops = { | ||
396 | .warning = print_trace_warning, | ||
397 | .warning_symbol = print_trace_warning_symbol, | ||
398 | .stack = print_trace_stack, | ||
399 | .address = print_trace_address, | ||
400 | }; | ||
369 | 401 | ||
402 | void | ||
403 | show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long *stack) | ||
404 | { | ||
405 | printk("\nCall Trace:\n"); | ||
406 | dump_trace(tsk, regs, stack, &print_trace_ops, NULL); | ||
370 | printk("\n"); | 407 | printk("\n"); |
371 | } | 408 | } |
372 | 409 | ||
373 | static void _show_stack(struct task_struct *tsk, struct pt_regs *regs, unsigned long * rsp) | 410 | static void |
411 | _show_stack(struct task_struct *tsk, struct pt_regs *regs, unsigned long *rsp) | ||
374 | { | 412 | { |
375 | unsigned long *stack; | 413 | unsigned long *stack; |
376 | int i; | 414 | int i; |
377 | const int cpu = safe_smp_processor_id(); | 415 | const int cpu = smp_processor_id(); |
378 | unsigned long *irqstack_end = (unsigned long *) (cpu_pda(cpu)->irqstackptr); | 416 | unsigned long *irqstack_end = (unsigned long *) (cpu_pda(cpu)->irqstackptr); |
379 | unsigned long *irqstack = (unsigned long *) (cpu_pda(cpu)->irqstackptr - IRQSTACKSIZE); | 417 | unsigned long *irqstack = (unsigned long *) (cpu_pda(cpu)->irqstackptr - IRQSTACKSIZE); |
380 | 418 | ||
@@ -428,7 +466,7 @@ void show_registers(struct pt_regs *regs) | |||
428 | int i; | 466 | int i; |
429 | int in_kernel = !user_mode(regs); | 467 | int in_kernel = !user_mode(regs); |
430 | unsigned long rsp; | 468 | unsigned long rsp; |
431 | const int cpu = safe_smp_processor_id(); | 469 | const int cpu = smp_processor_id(); |
432 | struct task_struct *cur = cpu_pda(cpu)->pcurrent; | 470 | struct task_struct *cur = cpu_pda(cpu)->pcurrent; |
433 | 471 | ||
434 | rsp = regs->rsp; | 472 | rsp = regs->rsp; |
@@ -503,9 +541,11 @@ static unsigned int die_nest_count; | |||
503 | 541 | ||
504 | unsigned __kprobes long oops_begin(void) | 542 | unsigned __kprobes long oops_begin(void) |
505 | { | 543 | { |
506 | int cpu = safe_smp_processor_id(); | 544 | int cpu = smp_processor_id(); |
507 | unsigned long flags; | 545 | unsigned long flags; |
508 | 546 | ||
547 | oops_enter(); | ||
548 | |||
509 | /* racy, but better than risking deadlock. */ | 549 | /* racy, but better than risking deadlock. */ |
510 | local_irq_save(flags); | 550 | local_irq_save(flags); |
511 | if (!spin_trylock(&die_lock)) { | 551 | if (!spin_trylock(&die_lock)) { |
@@ -534,6 +574,7 @@ void __kprobes oops_end(unsigned long flags) | |||
534 | spin_unlock_irqrestore(&die_lock, flags); | 574 | spin_unlock_irqrestore(&die_lock, flags); |
535 | if (panic_on_oops) | 575 | if (panic_on_oops) |
536 | panic("Fatal exception"); | 576 | panic("Fatal exception"); |
577 | oops_exit(); | ||
537 | } | 578 | } |
538 | 579 | ||
539 | void __kprobes __die(const char * str, struct pt_regs * regs, long err) | 580 | void __kprobes __die(const char * str, struct pt_regs * regs, long err) |
@@ -570,7 +611,7 @@ void die(const char * str, struct pt_regs * regs, long err) | |||
570 | do_exit(SIGSEGV); | 611 | do_exit(SIGSEGV); |
571 | } | 612 | } |
572 | 613 | ||
573 | void __kprobes die_nmi(char *str, struct pt_regs *regs) | 614 | void __kprobes die_nmi(char *str, struct pt_regs *regs, int do_panic) |
574 | { | 615 | { |
575 | unsigned long flags = oops_begin(); | 616 | unsigned long flags = oops_begin(); |
576 | 617 | ||
@@ -578,13 +619,12 @@ void __kprobes die_nmi(char *str, struct pt_regs *regs) | |||
578 | * We are in trouble anyway, lets at least try | 619 | * We are in trouble anyway, lets at least try |
579 | * to get a message out. | 620 | * to get a message out. |
580 | */ | 621 | */ |
581 | printk(str, safe_smp_processor_id()); | 622 | printk(str, smp_processor_id()); |
582 | show_registers(regs); | 623 | show_registers(regs); |
583 | if (kexec_should_crash(current)) | 624 | if (kexec_should_crash(current)) |
584 | crash_kexec(regs); | 625 | crash_kexec(regs); |
585 | if (panic_on_timeout || panic_on_oops) | 626 | if (do_panic || panic_on_oops) |
586 | panic("nmi watchdog"); | 627 | panic("Non maskable interrupt"); |
587 | printk("console shuts up ...\n"); | ||
588 | oops_end(flags); | 628 | oops_end(flags); |
589 | nmi_exit(); | 629 | nmi_exit(); |
590 | local_irq_enable(); | 630 | local_irq_enable(); |
@@ -730,8 +770,15 @@ asmlinkage void __kprobes do_general_protection(struct pt_regs * regs, | |||
730 | static __kprobes void | 770 | static __kprobes void |
731 | mem_parity_error(unsigned char reason, struct pt_regs * regs) | 771 | mem_parity_error(unsigned char reason, struct pt_regs * regs) |
732 | { | 772 | { |
733 | printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n"); | 773 | printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n", |
734 | printk("You probably have a hardware problem with your RAM chips\n"); | 774 | reason); |
775 | printk(KERN_EMERG "You probably have a hardware problem with your " | ||
776 | "RAM chips\n"); | ||
777 | |||
778 | if (panic_on_unrecovered_nmi) | ||
779 | panic("NMI: Not continuing"); | ||
780 | |||
781 | printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); | ||
735 | 782 | ||
736 | /* Clear and disable the memory parity error line. */ | 783 | /* Clear and disable the memory parity error line. */ |
737 | reason = (reason & 0xf) | 4; | 784 | reason = (reason & 0xf) | 4; |
@@ -754,9 +801,15 @@ io_check_error(unsigned char reason, struct pt_regs * regs) | |||
754 | 801 | ||
755 | static __kprobes void | 802 | static __kprobes void |
756 | unknown_nmi_error(unsigned char reason, struct pt_regs * regs) | 803 | unknown_nmi_error(unsigned char reason, struct pt_regs * regs) |
757 | { printk("Uhhuh. NMI received for unknown reason %02x.\n", reason); | 804 | { |
758 | printk("Dazed and confused, but trying to continue\n"); | 805 | printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x.\n", |
759 | printk("Do you have a strange power saving mode enabled?\n"); | 806 | reason); |
807 | printk(KERN_EMERG "Do you have a strange power saving mode enabled?\n"); | ||
808 | |||
809 | if (panic_on_unrecovered_nmi) | ||
810 | panic("NMI: Not continuing"); | ||
811 | |||
812 | printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); | ||
760 | } | 813 | } |
761 | 814 | ||
762 | /* Runs on IST stack. This code must keep interrupts off all the time. | 815 | /* Runs on IST stack. This code must keep interrupts off all the time. |
@@ -776,17 +829,15 @@ asmlinkage __kprobes void default_do_nmi(struct pt_regs *regs) | |||
776 | if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT) | 829 | if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT) |
777 | == NOTIFY_STOP) | 830 | == NOTIFY_STOP) |
778 | return; | 831 | return; |
779 | #ifdef CONFIG_X86_LOCAL_APIC | ||
780 | /* | 832 | /* |
781 | * Ok, so this is none of the documented NMI sources, | 833 | * Ok, so this is none of the documented NMI sources, |
782 | * so it must be the NMI watchdog. | 834 | * so it must be the NMI watchdog. |
783 | */ | 835 | */ |
784 | if (nmi_watchdog > 0) { | 836 | if (nmi_watchdog_tick(regs,reason)) |
785 | nmi_watchdog_tick(regs,reason); | ||
786 | return; | 837 | return; |
787 | } | 838 | if (!do_nmi_callback(regs,cpu)) |
788 | #endif | 839 | unknown_nmi_error(reason, regs); |
789 | unknown_nmi_error(reason, regs); | 840 | |
790 | return; | 841 | return; |
791 | } | 842 | } |
792 | if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) | 843 | if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) |
@@ -1071,6 +1122,7 @@ asmlinkage void math_state_restore(void) | |||
1071 | init_fpu(me); | 1122 | init_fpu(me); |
1072 | restore_fpu_checking(&me->thread.i387.fxsave); | 1123 | restore_fpu_checking(&me->thread.i387.fxsave); |
1073 | task_thread_info(me)->status |= TS_USEDFPU; | 1124 | task_thread_info(me)->status |= TS_USEDFPU; |
1125 | me->fpu_counter++; | ||
1074 | } | 1126 | } |
1075 | 1127 | ||
1076 | void __init trap_init(void) | 1128 | void __init trap_init(void) |
@@ -1109,24 +1161,30 @@ void __init trap_init(void) | |||
1109 | } | 1161 | } |
1110 | 1162 | ||
1111 | 1163 | ||
1112 | /* Actual parsing is done early in setup.c. */ | 1164 | static int __init oops_setup(char *s) |
1113 | static int __init oops_dummy(char *s) | ||
1114 | { | 1165 | { |
1115 | panic_on_oops = 1; | 1166 | if (!s) |
1116 | return 1; | 1167 | return -EINVAL; |
1168 | if (!strcmp(s, "panic")) | ||
1169 | panic_on_oops = 1; | ||
1170 | return 0; | ||
1117 | } | 1171 | } |
1118 | __setup("oops=", oops_dummy); | 1172 | early_param("oops", oops_setup); |
1119 | 1173 | ||
1120 | static int __init kstack_setup(char *s) | 1174 | static int __init kstack_setup(char *s) |
1121 | { | 1175 | { |
1176 | if (!s) | ||
1177 | return -EINVAL; | ||
1122 | kstack_depth_to_print = simple_strtoul(s,NULL,0); | 1178 | kstack_depth_to_print = simple_strtoul(s,NULL,0); |
1123 | return 1; | 1179 | return 0; |
1124 | } | 1180 | } |
1125 | __setup("kstack=", kstack_setup); | 1181 | early_param("kstack", kstack_setup); |
1126 | 1182 | ||
1127 | #ifdef CONFIG_STACK_UNWIND | 1183 | #ifdef CONFIG_STACK_UNWIND |
1128 | static int __init call_trace_setup(char *s) | 1184 | static int __init call_trace_setup(char *s) |
1129 | { | 1185 | { |
1186 | if (!s) | ||
1187 | return -EINVAL; | ||
1130 | if (strcmp(s, "old") == 0) | 1188 | if (strcmp(s, "old") == 0) |
1131 | call_trace = -1; | 1189 | call_trace = -1; |
1132 | else if (strcmp(s, "both") == 0) | 1190 | else if (strcmp(s, "both") == 0) |
@@ -1135,7 +1193,7 @@ static int __init call_trace_setup(char *s) | |||
1135 | call_trace = 1; | 1193 | call_trace = 1; |
1136 | else if (strcmp(s, "new") == 0) | 1194 | else if (strcmp(s, "new") == 0) |
1137 | call_trace = 2; | 1195 | call_trace = 2; |
1138 | return 1; | 1196 | return 0; |
1139 | } | 1197 | } |
1140 | __setup("call_trace=", call_trace_setup); | 1198 | early_param("call_trace", call_trace_setup); |
1141 | #endif | 1199 | #endif |