summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86_64/kernel/traps.c147
1 files changed, 79 insertions, 68 deletions
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index f6ccf155e3e5..65a37f52c56e 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");
}
OpenPOWER on IntegriCloud