Commit 066479e3 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] x86: stack dumps using frame pointers

From: Adam Litke <agl@us.ibm.com>

Teach the x86 stack tracing code to use frame pointers, if they are available.
It eliminates all the false-positives in the normal stack traces.

This is a big improvement, and -fomit-frame-pointer seems to make no
difference at all to generated code size.  Maybe we should kill off
-fomit-frame-pointer.
parent fc4c3ad2
...@@ -94,20 +94,35 @@ asmlinkage void machine_check(void); ...@@ -94,20 +94,35 @@ asmlinkage void machine_check(void);
static int kstack_depth_to_print = 24; static int kstack_depth_to_print = 24;
void show_trace(struct task_struct *task, unsigned long * stack) static int valid_stack_ptr(struct task_struct *task, void *p)
{ {
unsigned long addr; if (p <= (void *)task->thread_info)
return 0;
if (kstack_end(p))
return 0;
return 1;
}
if (!stack) #ifdef CONFIG_FRAME_POINTER
stack = (unsigned long*)&stack; void print_context_stack(struct task_struct *task, unsigned long *stack,
unsigned long ebp)
{
unsigned long addr;
printk("Call Trace:"); while (valid_stack_ptr(task, (void *)ebp)) {
#ifdef CONFIG_KALLSYMS addr = *(unsigned long *)(ebp + 4);
printk(" [<%08lx>] ", addr);
print_symbol("%s", addr);
printk("\n"); printk("\n");
#endif ebp = *(unsigned long *)ebp;
while (1) { }
struct thread_info *context; }
context = (struct thread_info*) ((unsigned long)stack & (~(THREAD_SIZE - 1))); #else
void print_context_stack(struct task_struct *task, unsigned long *stack,
unsigned long ebp)
{
unsigned long addr;
while (!kstack_end(stack)) { while (!kstack_end(stack)) {
addr = *stack++; addr = *stack++;
if (kernel_text_address(addr)) { if (kernel_text_address(addr)) {
...@@ -115,6 +130,34 @@ void show_trace(struct task_struct *task, unsigned long * stack) ...@@ -115,6 +130,34 @@ void show_trace(struct task_struct *task, unsigned long * stack)
print_symbol("%s\n", addr); print_symbol("%s\n", addr);
} }
} }
}
#endif
void show_trace(struct task_struct *task, unsigned long * stack)
{
unsigned long ebp;
if (!task)
task = current;
if (!valid_stack_ptr(task, stack)) {
printk("Stack pointer is garbage, not printing trace\n");
return;
}
if (task == current) {
/* Grab ebp right from our regs */
asm ("movl %%ebp, %0" : "=r" (ebp) : );
} else {
/* ebp is the last reg pushed by switch_to */
ebp = *(unsigned long *) task->thread.esp;
}
while (1) {
struct thread_info *context;
context = (struct thread_info *)
((unsigned long)stack & (~(THREAD_SIZE - 1)));
print_context_stack(task, stack, ebp);
stack = (unsigned long*)context->previous_esp; stack = (unsigned long*)context->previous_esp;
if (!stack) if (!stack)
break; break;
...@@ -143,7 +186,7 @@ void show_stack(struct task_struct *task, unsigned long *esp) ...@@ -143,7 +186,7 @@ void show_stack(struct task_struct *task, unsigned long *esp)
printk("\n "); printk("\n ");
printk("%08lx ", *stack++); printk("%08lx ", *stack++);
} }
printk("\n"); printk("\nCall Trace:\n");
show_trace(task, esp); show_trace(task, esp);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment