From: Adam Litke (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). Teach the x86 stack tracing code to use frame pointers, if they are available. The show_trace() for the CONFIG_FRAME_POINTER case will now be called the same way as the existing code. This brings up a question though. It doesn't appear to me that anyone is actually calling show_trace_task() yet. Am I missing something or should we change all the callers of show_trace() to use show_trace_task()? I hacked read_profile() a bit so I could catch it inside down(). This looks good to me. In fact, even the inline asm functions were recognized. cat D 00000246 0 215 212 (NOTLB) Call Trace: f296feec 00000086 f296ff60 00000246 f296ff10 f681dd60 00000004 f2b59ce8 f2b59d6c f296fed0 c04b4c80 c04b6680 f296fee4 c01d7f2a bffffafc f296ff08 002e58e9 08848a79 00000018 c1a0cbe0 f29a2160 f29a2328 f296ff18 [] __down+0x76/0xe0 00000400 00000000 0804c038 f29a2160 00000001 f29a2160 c0118c8c f296ff6c f296ff6c f296ff2c [] __down_failed+0xb/0x14 f296ff60 f296ff68 f296ff6c f296ff74 [] .text.lock.proc_misc+0xf/0x21 00000000 f2a851e0 f2a85200 000011b4 00000000 40869be4 15b4a440 40869be4 15b4a440 40869be4 00000004 ffffffff 00000001 00000001 f296ff10 f296ff10 f296ff98 [] vfs_read+0x9e/0xd0 f2a851e0 0804c038 00000400 f2a85200 f2a851e0 fffffff7 0804c038 f296ffbc [] sys_read+0x30/0x50 f2a851e0 0804c038 00000400 f2a85200 00000003 00000400 00000000 f296e000 [] syscall_call+0x7/0xb The top stack frame is defined to be all values from esp to ebp. Subsequent frames are defined as ebp to *ebp (if ebp is a valid stack address). Therefore in the worst case, a stack frame may include data from two "logical functions" if a new frame was not defined (but we will not lose any data). GCC seems to be generating frame-pointer enabled code even for inline asm calls so we should only see this "worst-case" behavior around actual assembly diff -upN reference/arch/i386/kernel/traps.c current/arch/i386/kernel/traps.c --- reference/arch/i386/kernel/traps.c 2004-04-30 12:55:11.000000000 -0700 +++ current/arch/i386/kernel/traps.c 2004-04-30 13:02:17.000000000 -0700 @@ -130,27 +130,65 @@ void breakpoint(void) static int kstack_depth_to_print = 24; -void show_trace(struct task_struct *task, unsigned long * stack) +#define valid_stack_ptr(task, p) \ + ((struct thread_info*)p > task->thread_info) && \ + !kstack_end((unsigned long*)p) + +#ifdef CONFIG_FRAME_POINTER +void print_context_stack(struct task_struct *task, unsigned long * stack, + unsigned long ebp) { unsigned long addr; - if (!stack) - stack = (unsigned long*)&stack; + while (valid_stack_ptr(task, ebp)) { + addr = *(unsigned long *) (ebp + 4); + printk(" [<%08lx>] ", addr); + print_symbol("%s", addr); + printk("\n"); + ebp = *(unsigned long *) ebp; + } +} +#else +void print_context_stack(struct task_struct *task, unsigned long * stack, + unsigned long ebp) +{ + unsigned long addr; - printk("Call Trace:"); -#ifdef CONFIG_KALLSYMS - printk("\n"); + while (!kstack_end(stack)) { + addr = *stack++; + if (kernel_text_address(addr)) { + printk(" [<%08lx>] ", 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))); - while (!kstack_end(stack)) { - addr = *stack++; - if (kernel_text_address(addr)) { - printk(" [<%08lx>] ", addr); - print_symbol("%s\n", addr); - } - } + context = (struct thread_info*) + ((unsigned long)stack & (~(THREAD_SIZE - 1))); + print_context_stack(task, stack, ebp); stack = (unsigned long*)context->previous_esp; if (!stack) break; @@ -179,7 +217,7 @@ void show_stack(struct task_struct *task printk("\n "); printk("%08lx ", *stack++); } - printk("\n"); + printk("\nCall Trace:\n"); show_trace(task, esp); }