[PATCH] x86_64: Rewrite exception stack backtracing
Exceptions and hardware interrupts can, to a certain degree, nest, so when attempting to follow the sequence of stacks used in order to dump their contents this has to be accounted for. Also, IST stacks have their tops stored in the TSS, so there's no need to add the stack size to get to their ends. Minor changes from AK. Signed-off-by: Jan Beulich <jbeulich@novell.com> Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
Родитель
635186447d
Коммит
0a65800243
|
@ -120,95 +120,106 @@ int printk_address(unsigned long address)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
unsigned long *in_exception_stack(int cpu, unsigned long stack)
|
static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
|
||||||
{
|
unsigned *usedp, const char **idp)
|
||||||
int k;
|
{
|
||||||
for (k = 0; k < N_EXCEPTION_STACKS; k++) {
|
static const char ids[N_EXCEPTION_STACKS][8] = {
|
||||||
struct tss_struct *tss = &per_cpu(init_tss, cpu);
|
[DEBUG_STACK - 1] = "#DB",
|
||||||
unsigned long start = tss->ist[k] - EXCEPTION_STKSZ;
|
[NMI_STACK - 1] = "NMI",
|
||||||
|
[DOUBLEFAULT_STACK - 1] = "#DF",
|
||||||
|
[STACKFAULT_STACK - 1] = "#SS",
|
||||||
|
[MCE_STACK - 1] = "#MC",
|
||||||
|
};
|
||||||
|
unsigned k;
|
||||||
|
|
||||||
if (stack >= start && stack < tss->ist[k])
|
for (k = 0; k < N_EXCEPTION_STACKS; k++) {
|
||||||
return (unsigned long *)tss->ist[k];
|
unsigned long end;
|
||||||
|
|
||||||
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* x86-64 can have upto three kernel stacks:
|
* x86-64 can have upto three kernel stacks:
|
||||||
* process stack
|
* process stack
|
||||||
* interrupt stack
|
* interrupt stack
|
||||||
* severe exception (double fault, nmi, stack fault) hardware stack
|
* severe exception (double fault, nmi, stack fault, debug, mce) hardware stack
|
||||||
* Check and process them in order.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void show_trace(unsigned long *stack)
|
void show_trace(unsigned long *stack)
|
||||||
{
|
{
|
||||||
unsigned long addr;
|
unsigned long addr;
|
||||||
unsigned long *irqstack, *irqstack_end, *estack_end;
|
const unsigned cpu = safe_smp_processor_id();
|
||||||
const int cpu = safe_smp_processor_id();
|
unsigned long *irqstack_end = (unsigned long *)cpu_pda[cpu].irqstackptr;
|
||||||
int i;
|
int i;
|
||||||
|
unsigned used = 0;
|
||||||
|
|
||||||
printk("\nCall Trace:");
|
printk("\nCall Trace:");
|
||||||
i = 0;
|
|
||||||
|
#define HANDLE_STACK(cond) \
|
||||||
estack_end = in_exception_stack(cpu, (unsigned long)stack);
|
do while (cond) { \
|
||||||
if (estack_end) {
|
addr = *stack++; \
|
||||||
while (stack < estack_end) {
|
if (kernel_text_address(addr)) { \
|
||||||
addr = *stack++;
|
/* \
|
||||||
if (__kernel_text_address(addr)) {
|
* If the address is either in the text segment of the \
|
||||||
i += printk_address(addr);
|
* kernel, or in the region which contains vmalloc'ed \
|
||||||
i += printk(" ");
|
* memory, it *may* be the address of a calling \
|
||||||
if (i > 50) {
|
* routine; if so, print it so that someone tracing \
|
||||||
printk("\n");
|
* down the cause of the crash will be able to figure \
|
||||||
i = 0;
|
* 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;
|
||||||
|
}
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i += printk(" <EOE> ");
|
break;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HANDLE_STACK (((long) stack & (THREAD_SIZE-1)) != 0);
|
||||||
|
#undef HANDLE_STACK
|
||||||
printk("\n");
|
printk("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче