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)
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;
......
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