diff options
Diffstat (limited to 'arch/x86/kernel/dumpstack.c')
-rw-r--r-- | arch/x86/kernel/dumpstack.c | 50 |
1 files changed, 39 insertions, 11 deletions
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c index 2d8a371d4339..6d817554780a 100644 --- a/arch/x86/kernel/dumpstack.c +++ b/arch/x86/kernel/dumpstack.c | |||
@@ -109,6 +109,32 @@ print_context_stack(struct thread_info *tinfo, | |||
109 | } | 109 | } |
110 | return bp; | 110 | return bp; |
111 | } | 111 | } |
112 | EXPORT_SYMBOL_GPL(print_context_stack); | ||
113 | |||
114 | unsigned long | ||
115 | print_context_stack_bp(struct thread_info *tinfo, | ||
116 | unsigned long *stack, unsigned long bp, | ||
117 | const struct stacktrace_ops *ops, void *data, | ||
118 | unsigned long *end, int *graph) | ||
119 | { | ||
120 | struct stack_frame *frame = (struct stack_frame *)bp; | ||
121 | unsigned long *ret_addr = &frame->return_address; | ||
122 | |||
123 | while (valid_stack_ptr(tinfo, ret_addr, sizeof(*ret_addr), end)) { | ||
124 | unsigned long addr = *ret_addr; | ||
125 | |||
126 | if (!__kernel_text_address(addr)) | ||
127 | break; | ||
128 | |||
129 | ops->address(data, addr, 1); | ||
130 | frame = frame->next_frame; | ||
131 | ret_addr = &frame->return_address; | ||
132 | print_ftrace_graph_addr(addr, data, ops, tinfo, graph); | ||
133 | } | ||
134 | |||
135 | return (unsigned long)frame; | ||
136 | } | ||
137 | EXPORT_SYMBOL_GPL(print_context_stack_bp); | ||
112 | 138 | ||
113 | 139 | ||
114 | static void | 140 | static void |
@@ -141,10 +167,11 @@ static void print_trace_address(void *data, unsigned long addr, int reliable) | |||
141 | } | 167 | } |
142 | 168 | ||
143 | static const struct stacktrace_ops print_trace_ops = { | 169 | static const struct stacktrace_ops print_trace_ops = { |
144 | .warning = print_trace_warning, | 170 | .warning = print_trace_warning, |
145 | .warning_symbol = print_trace_warning_symbol, | 171 | .warning_symbol = print_trace_warning_symbol, |
146 | .stack = print_trace_stack, | 172 | .stack = print_trace_stack, |
147 | .address = print_trace_address, | 173 | .address = print_trace_address, |
174 | .walk_stack = print_context_stack, | ||
148 | }; | 175 | }; |
149 | 176 | ||
150 | void | 177 | void |
@@ -188,7 +215,7 @@ void dump_stack(void) | |||
188 | } | 215 | } |
189 | EXPORT_SYMBOL(dump_stack); | 216 | EXPORT_SYMBOL(dump_stack); |
190 | 217 | ||
191 | static raw_spinlock_t die_lock = __RAW_SPIN_LOCK_UNLOCKED; | 218 | static arch_spinlock_t die_lock = __ARCH_SPIN_LOCK_UNLOCKED; |
192 | static int die_owner = -1; | 219 | static int die_owner = -1; |
193 | static unsigned int die_nest_count; | 220 | static unsigned int die_nest_count; |
194 | 221 | ||
@@ -207,11 +234,11 @@ unsigned __kprobes long oops_begin(void) | |||
207 | /* racy, but better than risking deadlock. */ | 234 | /* racy, but better than risking deadlock. */ |
208 | raw_local_irq_save(flags); | 235 | raw_local_irq_save(flags); |
209 | cpu = smp_processor_id(); | 236 | cpu = smp_processor_id(); |
210 | if (!__raw_spin_trylock(&die_lock)) { | 237 | if (!arch_spin_trylock(&die_lock)) { |
211 | if (cpu == die_owner) | 238 | if (cpu == die_owner) |
212 | /* nested oops. should stop eventually */; | 239 | /* nested oops. should stop eventually */; |
213 | else | 240 | else |
214 | __raw_spin_lock(&die_lock); | 241 | arch_spin_lock(&die_lock); |
215 | } | 242 | } |
216 | die_nest_count++; | 243 | die_nest_count++; |
217 | die_owner = cpu; | 244 | die_owner = cpu; |
@@ -231,7 +258,7 @@ void __kprobes oops_end(unsigned long flags, struct pt_regs *regs, int signr) | |||
231 | die_nest_count--; | 258 | die_nest_count--; |
232 | if (!die_nest_count) | 259 | if (!die_nest_count) |
233 | /* Nest count reaches zero, release the lock. */ | 260 | /* Nest count reaches zero, release the lock. */ |
234 | __raw_spin_unlock(&die_lock); | 261 | arch_spin_unlock(&die_lock); |
235 | raw_local_irq_restore(flags); | 262 | raw_local_irq_restore(flags); |
236 | oops_exit(); | 263 | oops_exit(); |
237 | 264 | ||
@@ -268,11 +295,12 @@ int __kprobes __die(const char *str, struct pt_regs *regs, long err) | |||
268 | 295 | ||
269 | show_registers(regs); | 296 | show_registers(regs); |
270 | #ifdef CONFIG_X86_32 | 297 | #ifdef CONFIG_X86_32 |
271 | sp = (unsigned long) (®s->sp); | 298 | if (user_mode_vm(regs)) { |
272 | savesegment(ss, ss); | ||
273 | if (user_mode(regs)) { | ||
274 | sp = regs->sp; | 299 | sp = regs->sp; |
275 | ss = regs->ss & 0xffff; | 300 | ss = regs->ss & 0xffff; |
301 | } else { | ||
302 | sp = kernel_stack_pointer(regs); | ||
303 | savesegment(ss, ss); | ||
276 | } | 304 | } |
277 | printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip); | 305 | printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip); |
278 | print_symbol("%s", regs->ip); | 306 | print_symbol("%s", regs->ip); |