diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h index 1cb3501636d2..ca2de1b48fac 100644 --- a/arch/x86/include/asm/thread_info.h +++ b/arch/x86/include/asm/thread_info.h @@ -32,13 +32,14 @@ struct thread_info { mm_segment_t addr_limit; struct restart_block restart_block; void __user *sysenter_return; + unsigned int sig_on_uaccess_error:1; + unsigned int uaccess_err:1; /* uaccess failed */ #ifdef CONFIG_X86_32 unsigned long previous_esp; /* ESP of the previous stack in case of nested (IRQ) stacks + (Moved to end, to be removed soon) */ #endif - unsigned int sig_on_uaccess_error:1; - unsigned int uaccess_err:1; /* uaccess failed */ }; #define INIT_THREAD_INFO(tsk) \ diff --git a/arch/x86/kernel/dumpstack_32.c b/arch/x86/kernel/dumpstack_32.c index f2a1770ca176..187d6a749c19 100644 --- a/arch/x86/kernel/dumpstack_32.c +++ b/arch/x86/kernel/dumpstack_32.c @@ -22,6 +22,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, const struct stacktrace_ops *ops, void *data) { int graph = 0; + u32 *prev_esp; if (!task) task = current; @@ -44,9 +45,17 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, ((unsigned long)stack & (~(THREAD_SIZE - 1))); bp = ops->walk_stack(context, stack, bp, ops, data, NULL, &graph); - stack = (unsigned long *)context->previous_esp; + /* Stop if not on irq stack */ + if (task_stack_page(task) == context) + break; + + /* The previous esp is just above the context */ + prev_esp = (u32 *) ((char *)context + sizeof(struct thread_info) - + sizeof(long)); + stack = (unsigned long *)*prev_esp; if (!stack) break; + if (ops->stack(data, "IRQ") < 0) break; touch_nmi_watchdog(); diff --git a/arch/x86/kernel/irq_32.c b/arch/x86/kernel/irq_32.c index d7fcbedc9c43..f135cc2ff301 100644 --- a/arch/x86/kernel/irq_32.c +++ b/arch/x86/kernel/irq_32.c @@ -81,7 +81,7 @@ static inline int execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq) { union irq_ctx *curctx, *irqctx; - u32 *isp, arg1, arg2; + u32 *isp, *prev_esp, arg1, arg2; curctx = (union irq_ctx *) current_thread_info(); irqctx = __this_cpu_read(hardirq_ctx); @@ -98,7 +98,10 @@ execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq) /* build the stack frame on the IRQ stack */ isp = (u32 *) ((char *)irqctx + sizeof(*irqctx)); irqctx->tinfo.task = curctx->tinfo.task; - irqctx->tinfo.previous_esp = current_stack_pointer; + /* Save the next esp after thread_info */ + prev_esp = (u32 *) ((char *)irqctx + sizeof(struct thread_info) - + sizeof(long)); + *prev_esp = current_stack_pointer; if (unlikely(overflow)) call_on_stack(print_stack_overflow, isp); @@ -149,16 +152,20 @@ void do_softirq_own_stack(void) { struct thread_info *curctx; union irq_ctx *irqctx; - u32 *isp; + u32 *isp, *prev_esp; curctx = current_thread_info(); irqctx = __this_cpu_read(softirq_ctx); irqctx->tinfo.task = curctx->task; - irqctx->tinfo.previous_esp = current_stack_pointer; /* build the stack frame on the softirq stack */ isp = (u32 *) ((char *)irqctx + sizeof(*irqctx)); + /* Push the previous esp onto the stack */ + prev_esp = (u32 *) ((char *)irqctx + sizeof(struct thread_info) - + sizeof(long)); + *prev_esp = current_stack_pointer; + call_on_stack(__do_softirq, isp); } diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 7461f50d5bb1..f352a7cc43a1 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -184,14 +184,14 @@ unsigned long kernel_stack_pointer(struct pt_regs *regs) { unsigned long context = (unsigned long)regs & ~(THREAD_SIZE - 1); unsigned long sp = (unsigned long)®s->sp; - struct thread_info *tinfo; + u32 *prev_esp; if (context == (sp & ~(THREAD_SIZE - 1))) return sp; - tinfo = (struct thread_info *)context; - if (tinfo->previous_esp) - return tinfo->previous_esp; + prev_esp = (u32 *)(context + sizeof(struct thread_info) - sizeof(long)); + if (prev_esp) + return (unsigned long)prev_esp; return (unsigned long)regs; }