Commit c2634010 authored by Oleg Nesterov's avatar Oleg Nesterov Committed by Linus Torvalds

[PATCH] Fix show_trace() in irq context with CONFIG_4KSTACKS

- 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: default avatarOleg Nesterov <oleg@tv-sign.ru>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent e78a3216
...@@ -105,36 +105,27 @@ int register_die_notifier(struct notifier_block *nb) ...@@ -105,36 +105,27 @@ int register_die_notifier(struct notifier_block *nb)
return err; 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 p > (void *)tinfo &&
return 0; p < (void *)tinfo + THREAD_SIZE - 3;
if (kstack_end(p))
return 0;
return 1;
} }
#ifdef CONFIG_FRAME_POINTER static inline unsigned long print_context_stack(struct thread_info *tinfo,
static void print_context_stack(struct task_struct *task, unsigned long *stack, unsigned long *stack, unsigned long ebp)
unsigned long ebp)
{ {
unsigned long addr; 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); addr = *(unsigned long *)(ebp + 4);
printk(" [<%08lx>] ", addr); printk(" [<%08lx>] ", addr);
print_symbol("%s", addr); print_symbol("%s", addr);
printk("\n"); printk("\n");
ebp = *(unsigned long *)ebp; ebp = *(unsigned long *)ebp;
} }
}
#else #else
static void print_context_stack(struct task_struct *task, unsigned long *stack, while (valid_stack_ptr(tinfo, stack)) {
unsigned long ebp)
{
unsigned long addr;
while (!kstack_end(stack)) {
addr = *stack++; addr = *stack++;
if (__kernel_text_address(addr)) { if (__kernel_text_address(addr)) {
printk(" [<%08lx>]", addr); printk(" [<%08lx>]", addr);
...@@ -142,8 +133,9 @@ static void print_context_stack(struct task_struct *task, unsigned long *stack, ...@@ -142,8 +133,9 @@ static void print_context_stack(struct task_struct *task, unsigned long *stack,
printk("\n"); printk("\n");
} }
} }
}
#endif #endif
return ebp;
}
void show_trace(struct task_struct *task, unsigned long * stack) void show_trace(struct task_struct *task, unsigned long * stack)
{ {
...@@ -152,11 +144,6 @@ 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) if (!task)
task = current; task = current;
if (!valid_stack_ptr(task, stack)) {
printk("Stack pointer is garbage, not printing trace\n");
return;
}
if (task == current) { if (task == current) {
/* Grab ebp right from our regs */ /* Grab ebp right from our regs */
asm ("movl %%ebp, %0" : "=r" (ebp) : ); asm ("movl %%ebp, %0" : "=r" (ebp) : );
...@@ -169,7 +156,7 @@ void show_trace(struct task_struct *task, unsigned long * stack) ...@@ -169,7 +156,7 @@ void show_trace(struct task_struct *task, unsigned long * stack)
struct thread_info *context; struct thread_info *context;
context = (struct thread_info *) context = (struct thread_info *)
((unsigned long)stack & (~(THREAD_SIZE - 1))); ((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; stack = (unsigned long*)context->previous_esp;
if (!stack) if (!stack)
break; break;
......
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