diff options
Diffstat (limited to 'arch/x86_64/kernel/traps.c')
-rw-r--r-- | arch/x86_64/kernel/traps.c | 54 |
1 files changed, 48 insertions, 6 deletions
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index 9f8f1eff4a6c..eb1534ff1f5f 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/nmi.h> | 29 | #include <linux/nmi.h> |
30 | #include <linux/kprobes.h> | 30 | #include <linux/kprobes.h> |
31 | #include <linux/kexec.h> | 31 | #include <linux/kexec.h> |
32 | #include <linux/unwind.h> | ||
32 | 33 | ||
33 | #include <asm/system.h> | 34 | #include <asm/system.h> |
34 | #include <asm/uaccess.h> | 35 | #include <asm/uaccess.h> |
@@ -39,7 +40,7 @@ | |||
39 | #include <asm/i387.h> | 40 | #include <asm/i387.h> |
40 | #include <asm/kdebug.h> | 41 | #include <asm/kdebug.h> |
41 | #include <asm/processor.h> | 42 | #include <asm/processor.h> |
42 | 43 | #include <asm/unwind.h> | |
43 | #include <asm/smp.h> | 44 | #include <asm/smp.h> |
44 | #include <asm/pgalloc.h> | 45 | #include <asm/pgalloc.h> |
45 | #include <asm/pda.h> | 46 | #include <asm/pda.h> |
@@ -189,6 +190,23 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, | |||
189 | return NULL; | 190 | return NULL; |
190 | } | 191 | } |
191 | 192 | ||
193 | static void show_trace_unwind(struct unwind_frame_info *info, void *context) | ||
194 | { | ||
195 | int i = 11; | ||
196 | |||
197 | while (unwind(info) == 0 && UNW_PC(info)) { | ||
198 | if (i > 50) { | ||
199 | printk("\n "); | ||
200 | i = 7; | ||
201 | } else | ||
202 | i += printk(" "); | ||
203 | i += printk_address(UNW_PC(info)); | ||
204 | if (arch_unw_user_mode(info)) | ||
205 | break; | ||
206 | } | ||
207 | printk("\n"); | ||
208 | } | ||
209 | |||
192 | /* | 210 | /* |
193 | * x86-64 can have upto three kernel stacks: | 211 | * x86-64 can have upto three kernel stacks: |
194 | * process stack | 212 | * process stack |
@@ -196,15 +214,34 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, | |||
196 | * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack | 214 | * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack |
197 | */ | 215 | */ |
198 | 216 | ||
199 | void show_trace(unsigned long *stack) | 217 | void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * stack) |
200 | { | 218 | { |
201 | const unsigned cpu = safe_smp_processor_id(); | 219 | const unsigned cpu = safe_smp_processor_id(); |
202 | unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr; | 220 | unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr; |
203 | int i; | 221 | int i; |
204 | unsigned used = 0; | 222 | unsigned used = 0; |
223 | struct unwind_frame_info info; | ||
205 | 224 | ||
206 | printk("\nCall Trace:"); | 225 | printk("\nCall Trace:"); |
207 | 226 | ||
227 | if (!tsk) | ||
228 | tsk = current; | ||
229 | |||
230 | if (regs) { | ||
231 | if (unwind_init_frame_info(&info, tsk, regs) == 0) { | ||
232 | show_trace_unwind(&info, NULL); | ||
233 | return; | ||
234 | } | ||
235 | } else if (tsk == current) { | ||
236 | if (unwind_init_running(&info, show_trace_unwind, NULL) == 0) | ||
237 | return; | ||
238 | } else { | ||
239 | if (unwind_init_blocked(&info, tsk) == 0) { | ||
240 | show_trace_unwind(&info, NULL); | ||
241 | return; | ||
242 | } | ||
243 | } | ||
244 | |||
208 | #define HANDLE_STACK(cond) \ | 245 | #define HANDLE_STACK(cond) \ |
209 | do while (cond) { \ | 246 | do while (cond) { \ |
210 | unsigned long addr = *stack++; \ | 247 | unsigned long addr = *stack++; \ |
@@ -262,7 +299,7 @@ void show_trace(unsigned long *stack) | |||
262 | printk("\n"); | 299 | printk("\n"); |
263 | } | 300 | } |
264 | 301 | ||
265 | void show_stack(struct task_struct *tsk, unsigned long * rsp) | 302 | static void _show_stack(struct task_struct *tsk, struct pt_regs *regs, unsigned long * rsp) |
266 | { | 303 | { |
267 | unsigned long *stack; | 304 | unsigned long *stack; |
268 | int i; | 305 | int i; |
@@ -296,7 +333,12 @@ void show_stack(struct task_struct *tsk, unsigned long * rsp) | |||
296 | printk("%016lx ", *stack++); | 333 | printk("%016lx ", *stack++); |
297 | touch_nmi_watchdog(); | 334 | touch_nmi_watchdog(); |
298 | } | 335 | } |
299 | show_trace((unsigned long *)rsp); | 336 | show_trace(tsk, regs, rsp); |
337 | } | ||
338 | |||
339 | void show_stack(struct task_struct *tsk, unsigned long * rsp) | ||
340 | { | ||
341 | _show_stack(tsk, NULL, rsp); | ||
300 | } | 342 | } |
301 | 343 | ||
302 | /* | 344 | /* |
@@ -305,7 +347,7 @@ void show_stack(struct task_struct *tsk, unsigned long * rsp) | |||
305 | void dump_stack(void) | 347 | void dump_stack(void) |
306 | { | 348 | { |
307 | unsigned long dummy; | 349 | unsigned long dummy; |
308 | show_trace(&dummy); | 350 | show_trace(NULL, NULL, &dummy); |
309 | } | 351 | } |
310 | 352 | ||
311 | EXPORT_SYMBOL(dump_stack); | 353 | EXPORT_SYMBOL(dump_stack); |
@@ -332,7 +374,7 @@ void show_registers(struct pt_regs *regs) | |||
332 | if (in_kernel) { | 374 | if (in_kernel) { |
333 | 375 | ||
334 | printk("Stack: "); | 376 | printk("Stack: "); |
335 | show_stack(NULL, (unsigned long*)rsp); | 377 | _show_stack(NULL, regs, (unsigned long*)rsp); |
336 | 378 | ||
337 | printk("\nCode: "); | 379 | printk("\nCode: "); |
338 | if (regs->rip < PAGE_OFFSET) | 380 | if (regs->rip < PAGE_OFFSET) |