Re: stack dumps, CONFIG_FRAME_POINTER and i386 (was Re: sysrq shows impossible call stack)

From: Adam Litke (agl_at_us.ibm.com)
Date: 04/20/04

  • Next message: Hubert Tonneau: "The missing RAID level"
    To: Roland Dreier <roland@topspin.com>
    Date:	Tue, 20 Apr 2004 13:26:41 -0700
    
    

    On Tue, 2004-04-20 at 10:51, Roland Dreier wrote:
    > Your question prompted me to look at show_trace() in
    > arch/i386/kernel/traps.c. I see that even in kernels as new as 2.6.5,
    > there is no attempt to use frame pointers for stack dumps even when
    > CONFIG_FRAME_POINTER is set. I seem to remember some patches to do
    > this floating around a while ago. How did that discussion end up?

    This problem was annoying me a few months ago so I coded up a stack
    trace patch that actually uses the frame pointer. It is currently
    maintained in -mjb but I have pasted below. Hope this helps.

    diff -upN reference/arch/i386/kernel/traps.c current/arch/i386/kernel/traps.c
    --- reference/arch/i386/kernel/traps.c 2004-04-09 11:53:00.000000000 -0700
    +++ current/arch/i386/kernel/traps.c 2004-04-09 11:53:04.000000000 -0700
    @@ -124,20 +124,62 @@ void breakpoint(void)
     #define CHK_REMOTE_DEBUG(trapnr,signr,error_code,regs,after)
     #endif
     
    +#define STACK_PRINT_DEPTH 32
     
    -static int kstack_depth_to_print = 24;
    +#ifdef CONFIG_FRAME_POINTER
    +#define valid_stack_ptr(task, p) \
    + ((p > (unsigned long)task->thread_info) && \
    + (p < (unsigned long)task->thread_info+THREAD_SIZE))
     
    -void show_trace(struct task_struct *task, unsigned long * stack)
    +void show_stack_frame(unsigned long start, unsigned long end)
    +{
    + int i;
    +
    + printk(" ");
    + for (i = start; i < end; i += 4) {
    + if ((i - start) && ((i - start)%24 == 0))
    + printk("\n ");
    + printk("%08lx ", *(unsigned long *) i);
    + }
    + printk("\n");
    +}
    +
    +void show_trace_fp(struct task_struct *task, unsigned long * stack)
    +{
    + unsigned long addr, ebp;
    +
    + if (!task)
    + task = current;
    +
    + 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;
    + }
    +
    + show_stack_frame((unsigned long) stack, ebp+4);
    + while (valid_stack_ptr(task, ebp)) {
    + addr = *(unsigned long *) (ebp + 4);
    + printk(" [<%08lx>] ", addr);
    + print_symbol("%s\n", addr);
    +
    + /* Show the stack frame starting with args */
    + show_stack_frame(ebp + 8, (*(unsigned long *) ebp) + 4);
    + ebp = *(unsigned long *) ebp;
    + }
    +}
    +
    +#else /* !CONFIG_FRAME_POINTER */
    +
    +void show_trace_guess(unsigned long * stack)
     {
             unsigned long addr;
     
             if (!stack)
                     stack = (unsigned long*)&stack;
     
    - printk("Call Trace:");
    -#ifdef CONFIG_KALLSYMS
    - printk("\n");
    -#endif
             while (1) {
                     struct thread_info *context;
                     context = (struct thread_info*) ((unsigned long)stack & (~(THREAD_SIZE - 1)));
    @@ -153,6 +195,20 @@ void show_trace(struct task_struct *task
                             break;
                     printk(" =======================\n");
             }
    +}
    +#endif
    +
    +void show_trace(struct task_struct *task, unsigned long * stack)
    +{
    + printk("Call Trace:");
    +#ifdef CONFIG_KALLSYMS
    + printk("\n");
    +#endif
    +#ifdef CONFIG_FRAME_POINTER
    + show_trace_fp(task, stack);
    +#else
    + show_trace_guess(stack);
    +#endif
             printk("\n");
     }
     
    @@ -168,8 +224,10 @@ void show_trace_task(struct task_struct
     
     void show_stack(struct task_struct *task, unsigned long *esp)
     {
    +#ifndef CONFIG_FRAME_POINTER
             unsigned long *stack;
             int i;
    +#endif
     
             if (esp == NULL) {
                     if (task)
    @@ -178,8 +236,9 @@ void show_stack(struct task_struct *task
                             esp = (unsigned long *)&esp;
             }
     
    +#ifndef CONFIG_FRAME_POINTER
             stack = esp;
    - for(i = 0; i < kstack_depth_to_print; i++) {
    + for(i = 0; i < STACK_PRINT_DEPTH; i++) {
                     if (kstack_end(stack))
                             break;
                     if (i && ((i % 8) == 0))
    @@ -187,6 +246,7 @@ void show_stack(struct task_struct *task
                     printk("%08lx ", *stack++);
             }
             printk("\n");
    +#endif
             show_trace(task, esp);
     }
     

    -- 
    Adam Litke - (agl at us.ibm.com)
    IBM Linux Technology Center
    -
    To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
    the body of a message to majordomo@vger.kernel.org
    More majordomo info at  http://vger.kernel.org/majordomo-info.html
    Please read the FAQ at  http://www.tux.org/lkml/
    

  • Next message: Hubert Tonneau: "The missing RAID level"

    Relevant Pages