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 | } |
