]> git.hungrycats.org Git - linux/commitdiff
[PATCH] Fix show_trace() in irq context with CONFIG_4KSTACKS
authorOleg Nesterov <oleg@tv-sign.ru>
Mon, 18 Oct 2004 16:02:14 +0000 (09:02 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Mon, 18 Oct 2004 16:02:14 +0000 (09:02 -0700)
- valid_stack_ptr() erroneously assumes that stack always lives in
  task_struct->thread_info.

- the main loop in show_trace() does not recalc ebp after stack
  switching.  With CONFIG_FRAME_POINTER every call to print_context_stack()
  will produce the same output.

With this patch, show_trace() does not use task argument in the main loop.
Instead, it converts stack to thread_info* context, and passes it to
print_context_stack() and (implicitly) to valid_stack_ptr().

valid_stack_ptr() now does bounds checking against proper context.

Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
arch/i386/kernel/traps.c

index 6529d61a5bd7bcbb717622de35c3df69b61d70a2..325aaf8610ea17124cd0e231e97a607c25a768d3 100644 (file)
@@ -105,36 +105,27 @@ int register_die_notifier(struct notifier_block *nb)
        return err;
 }
 
-static int valid_stack_ptr(struct task_struct *task, void *p)
+static inline int valid_stack_ptr(struct thread_info *tinfo, void *p)
 {
-       if (p <= (void *)task->thread_info)
-               return 0;
-       if (kstack_end(p))
-               return 0;
-       return 1;
+       return  p > (void *)tinfo &&
+               p < (void *)tinfo + THREAD_SIZE - 3;
 }
 
-#ifdef CONFIG_FRAME_POINTER
-static void print_context_stack(struct task_struct *task, unsigned long *stack,
-                        unsigned long ebp)
+static inline unsigned long print_context_stack(struct thread_info *tinfo,
+                               unsigned long *stack, unsigned long ebp)
 {
        unsigned long addr;
 
-       while (valid_stack_ptr(task, (void *)ebp)) {
+#ifdef CONFIG_FRAME_POINTER
+       while (valid_stack_ptr(tinfo, (void *)ebp)) {
                addr = *(unsigned long *)(ebp + 4);
                printk(" [<%08lx>] ", addr);
                print_symbol("%s", addr);
                printk("\n");
                ebp = *(unsigned long *)ebp;
        }
-}
 #else
-static void print_context_stack(struct task_struct *task, unsigned long *stack,
-                        unsigned long ebp)
-{
-       unsigned long addr;
-
-       while (!kstack_end(stack)) {
+       while (valid_stack_ptr(tinfo, stack)) {
                addr = *stack++;
                if (__kernel_text_address(addr)) {
                        printk(" [<%08lx>]", addr);
@@ -142,8 +133,9 @@ static void print_context_stack(struct task_struct *task, unsigned long *stack,
                        printk("\n");
                }
        }
-}
 #endif
+       return ebp;
+}
 
 void show_trace(struct task_struct *task, unsigned long * stack)
 {
@@ -152,11 +144,6 @@ void show_trace(struct task_struct *task, unsigned long * stack)
        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) : );
@@ -169,7 +156,7 @@ void show_trace(struct task_struct *task, unsigned long * stack)
                struct thread_info *context;
                context = (struct thread_info *)
                        ((unsigned long)stack & (~(THREAD_SIZE - 1)));
-               print_context_stack(task, stack, ebp);
+               ebp = print_context_stack(context, stack, ebp);
                stack = (unsigned long*)context->previous_esp;
                if (!stack)
                        break;