diff options
-rw-r--r-- | arch/x86/include/asm/thread_info.h | 5 | ||||
-rw-r--r-- | arch/x86/kernel/dumpstack_32.c | 11 | ||||
-rw-r--r-- | arch/x86/kernel/irq_32.c | 15 | ||||
-rw-r--r-- | arch/x86/kernel/ptrace.c | 8 |
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 | |||
81 | execute_on_irq_stack(int overflow, struct irq_desc *desc, int irq) | 81 | execute_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)®s->sp; | 186 | unsigned long sp = (unsigned long)®s->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 | } |