diff options
Diffstat (limited to 'arch/x86_64')
-rw-r--r-- | arch/x86_64/kernel/traps.c | 147 |
1 files changed, 79 insertions, 68 deletions
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index f6ccf15..65a37f5 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -120,95 +120,106 @@ int printk_address(unsigned long address) } #endif -unsigned long *in_exception_stack(int cpu, unsigned long stack) -{ - int k; +static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, + unsigned *usedp, const char **idp) +{ + static const char ids[N_EXCEPTION_STACKS][8] = { + [DEBUG_STACK - 1] = "#DB", + [NMI_STACK - 1] = "NMI", + [DOUBLEFAULT_STACK - 1] = "#DF", + [STACKFAULT_STACK - 1] = "#SS", + [MCE_STACK - 1] = "#MC", + }; + unsigned k; + for (k = 0; k < N_EXCEPTION_STACKS; k++) { - struct tss_struct *tss = &per_cpu(init_tss, cpu); - unsigned long start = tss->ist[k] - EXCEPTION_STKSZ; + unsigned long end; - if (stack >= start && stack < tss->ist[k]) - return (unsigned long *)tss->ist[k]; + end = per_cpu(init_tss, cpu).ist[k]; + if (stack >= end) + continue; + if (stack >= end - EXCEPTION_STKSZ) { + if (*usedp & (1U << k)) + break; + *usedp |= 1U << k; + *idp = ids[k]; + return (unsigned long *)end; + } } return NULL; -} +} /* * x86-64 can have upto three kernel stacks: * process stack * interrupt stack - * severe exception (double fault, nmi, stack fault) hardware stack - * Check and process them in order. + * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack */ void show_trace(unsigned long *stack) { unsigned long addr; - unsigned long *irqstack, *irqstack_end, *estack_end; - const int cpu = safe_smp_processor_id(); + const unsigned cpu = safe_smp_processor_id(); + unsigned long *irqstack_end = (unsigned long *)cpu_pda[cpu].irqstackptr; int i; + unsigned used = 0; printk("\nCall Trace:"); - i = 0; - - estack_end = in_exception_stack(cpu, (unsigned long)stack); - if (estack_end) { - while (stack < estack_end) { - addr = *stack++; - if (__kernel_text_address(addr)) { - i += printk_address(addr); - i += printk(" "); - if (i > 50) { - printk("\n"); - i = 0; - } - } + +#define HANDLE_STACK(cond) \ + do while (cond) { \ + addr = *stack++; \ + if (kernel_text_address(addr)) { \ + /* \ + * If the address is either in the text segment of the \ + * kernel, or in the region which contains vmalloc'ed \ + * memory, it *may* be the address of a calling \ + * routine; if so, print it so that someone tracing \ + * down the cause of the crash will be able to figure \ + * out the call path that was taken. \ + */ \ + i += printk_address(addr); \ + if (i > 50) { \ + printk("\n "); \ + i = 0; \ + } \ + else \ + i += printk(" "); \ + } \ + } while (0) + + for(i = 0; ; ) { + const char *id; + unsigned long *estack_end; + estack_end = in_exception_stack(cpu, (unsigned long)stack, + &used, &id); + + if (estack_end) { + i += printk(" <%s> ", id); + HANDLE_STACK (stack < estack_end); + i += printk(" <EOE> "); + stack = (unsigned long *) estack_end[-2]; + continue; } - i += printk(" <EOE> "); - i += 7; - stack = (unsigned long *) estack_end[-2]; - } - - irqstack_end = (unsigned long *) (cpu_pda[cpu].irqstackptr); - irqstack = (unsigned long *) (cpu_pda[cpu].irqstackptr - IRQSTACKSIZE + 64); - - if (stack >= irqstack && stack < irqstack_end) { - printk("<IRQ> "); - while (stack < irqstack_end) { - addr = *stack++; - /* - * If the address is either in the text segment of the - * kernel, or in the region which contains vmalloc'ed - * memory, it *may* be the address of a calling - * routine; if so, print it so that someone tracing - * down the cause of the crash will be able to figure - * out the call path that was taken. - */ - if (__kernel_text_address(addr)) { - i += printk_address(addr); - i += printk(" "); - if (i > 50) { - printk("\n "); - i = 0; - } + if (irqstack_end) { + unsigned long *irqstack; + irqstack = irqstack_end - + (IRQSTACKSIZE - 64) / sizeof(*irqstack); + + if (stack >= irqstack && stack < irqstack_end) { + i += printk(" <IRQ> "); + HANDLE_STACK (stack < irqstack_end); + stack = (unsigned long *) (irqstack_end[-1]); + irqstack_end = NULL; + i += printk(" <EOI> "); + continue; } - } - stack = (unsigned long *) (irqstack_end[-1]); - printk(" <EOI> "); - i += 7; - } - - while (((long) stack & (THREAD_SIZE-1)) != 0) { - addr = *stack++; - if (__kernel_text_address(addr)) { - i += printk_address(addr); - i += printk(" "); - if (i > 50) { - printk("\n "); - i = 0; - } } + break; } + + HANDLE_STACK (((long) stack & (THREAD_SIZE-1)) != 0); +#undef HANDLE_STACK printk("\n"); } |