aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/include/asm/thread_info.h5
-rw-r--r--arch/x86/kernel/dumpstack_32.c11
-rw-r--r--arch/x86/kernel/irq_32.c15
-rw-r--r--arch/x86/kernel/ptrace.c8
4 files changed, 28 insertions, 11 deletions
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 {
32 mm_segment_t addr_limit; 32 mm_segment_t addr_limit;
33 struct restart_block restart_block; 33 struct restart_block restart_block;
34 void __user *sysenter_return; 34 void __user *sysenter_return;
35 unsigned int sig_on_uaccess_error:1;
36 unsigned int uaccess_err:1; /* uaccess failed */
35#ifdef CONFIG_X86_32 37#ifdef CONFIG_X86_32
36 unsigned long previous_esp; /* ESP of the previous stack in 38 unsigned long previous_esp; /* ESP of the previous stack in
37 case of nested (IRQ) stacks 39 case of nested (IRQ) stacks
40 (Moved to end, to be removed soon)
38 */ 41 */
39#endif 42#endif
40 unsigned int sig_on_uaccess_error:1;
41 unsigned int uaccess_err:1; /* uaccess failed */
42}; 43};
43 44
44#define INIT_THREAD_INFO(tsk) \ 45#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,
22 const struct stacktrace_ops *ops, void *data) 22 const struct stacktrace_ops *ops, void *data)
23{ 23{
24 int graph = 0; 24 int graph = 0;
25 u32 *prev_esp;
25 26
26 if (!task) 27 if (!task)
27 task = current; 28 task = current;
@@ -44,9 +45,17 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
44 ((unsigned long)stack & (~(THREAD_SIZE - 1))); 45 ((unsigned long)stack & (~(THREAD_SIZE - 1)));
45 bp = ops->walk_stack(context, stack, bp, ops, data, NULL, &graph); 46 bp = ops->walk_stack(context, stack, bp, ops, data, NULL, &graph);
46 47
47 stack = (unsigned long *)context->previous_esp; 48 /* Stop if not on irq stack */
49 if (task_stack_page(task) == context)
50 break;
51
52 /* The previous esp is just above the context */
53 prev_esp = (u32 *) ((char *)context + sizeof(struct thread_info) -
54 sizeof(long));
55 stack = (unsigned long *)*prev_esp;
48 if (!stack) 56 if (!stack)
49 break; 57 break;
58
50 if (ops->stack(data, "IRQ") < 0) 59 if (ops->stack(data, "IRQ") < 0)
51 break; 60 break;
52 touch_nmi_watchdog(); 61 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
81execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq) 81execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq)
82{ 82{
83 union irq_ctx *curctx, *irqctx; 83 union irq_ctx *curctx, *irqctx;
84 u32 *isp, arg1, arg2; 84 u32 *isp, *prev_esp, arg1, arg2;
85 85
86 curctx = (union irq_ctx *) current_thread_info(); 86 curctx = (union irq_ctx *) current_thread_info();
87 irqctx = __this_cpu_read(hardirq_ctx); 87 irqctx = __this_cpu_read(hardirq_ctx);
@@ -98,7 +98,10 @@ execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq)
98 /* build the stack frame on the IRQ stack */ 98 /* build the stack frame on the IRQ stack */
99 isp = (u32 *) ((char *)irqctx + sizeof(*irqctx)); 99 isp = (u32 *) ((char *)irqctx + sizeof(*irqctx));
100 irqctx->tinfo.task = curctx->tinfo.task; 100 irqctx->tinfo.task = curctx->tinfo.task;
101 irqctx->tinfo.previous_esp = current_stack_pointer; 101 /* Save the next esp after thread_info */
102 prev_esp = (u32 *) ((char *)irqctx + sizeof(struct thread_info) -
103 sizeof(long));
104 *prev_esp = current_stack_pointer;
102 105
103 if (unlikely(overflow)) 106 if (unlikely(overflow))
104 call_on_stack(print_stack_overflow, isp); 107 call_on_stack(print_stack_overflow, isp);
@@ -149,16 +152,20 @@ void do_softirq_own_stack(void)
149{ 152{
150 struct thread_info *curctx; 153 struct thread_info *curctx;
151 union irq_ctx *irqctx; 154 union irq_ctx *irqctx;
152 u32 *isp; 155 u32 *isp, *prev_esp;
153 156
154 curctx = current_thread_info(); 157 curctx = current_thread_info();
155 irqctx = __this_cpu_read(softirq_ctx); 158 irqctx = __this_cpu_read(softirq_ctx);
156 irqctx->tinfo.task = curctx->task; 159 irqctx->tinfo.task = curctx->task;
157 irqctx->tinfo.previous_esp = current_stack_pointer;
158 160
159 /* build the stack frame on the softirq stack */ 161 /* build the stack frame on the softirq stack */
160 isp = (u32 *) ((char *)irqctx + sizeof(*irqctx)); 162 isp = (u32 *) ((char *)irqctx + sizeof(*irqctx));
161 163
164 /* Push the previous esp onto the stack */
165 prev_esp = (u32 *) ((char *)irqctx + sizeof(struct thread_info) -
166 sizeof(long));
167 *prev_esp = current_stack_pointer;
168
162 call_on_stack(__do_softirq, isp); 169 call_on_stack(__do_softirq, isp);
163} 170}
164 171
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)
184{ 184{
185 unsigned long context = (unsigned long)regs & ~(THREAD_SIZE - 1); 185 unsigned long context = (unsigned long)regs & ~(THREAD_SIZE - 1);
186 unsigned long sp = (unsigned long)&regs->sp; 186 unsigned long sp = (unsigned long)&regs->sp;
187 struct thread_info *tinfo; 187 u32 *prev_esp;
188 188
189 if (context == (sp & ~(THREAD_SIZE - 1))) 189 if (context == (sp & ~(THREAD_SIZE - 1)))
190 return sp; 190 return sp;
191 191
192 tinfo = (struct thread_info *)context; 192 prev_esp = (u32 *)(context + sizeof(struct thread_info) - sizeof(long));
193 if (tinfo->previous_esp) 193 if (prev_esp)
194 return tinfo->previous_esp; 194 return (unsigned long)prev_esp;
195 195
196 return (unsigned long)regs; 196 return (unsigned long)regs;
197} 197}