aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@novell.com>2006-06-26 07:57:32 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-26 13:48:17 -0400
commitb538ed278b80641ee6d7b75497d5e14de1bb1137 (patch)
treefe508a2f950ec08c832474a253f41b188ceece75 /arch
parent4552d5dc08b79868829b4be8951b29b07284753f (diff)
[PATCH] x86_64: reliable stack trace support (x86-64)
These are the x86_64-specific pieces to enable reliable stack traces. The only restriction with this is that it currently cannot unwind across the interrupt->normal stack boundary, as that transition is lacking proper annotation. Signed-off-by: Jan Beulich <jbeulich@novell.com> Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86_64/kernel/entry.S33
-rw-r--r--arch/x86_64/kernel/process.c2
-rw-r--r--arch/x86_64/kernel/traps.c54
-rw-r--r--arch/x86_64/kernel/vmlinux.lds.S9
4 files changed, 91 insertions, 7 deletions
diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S
index 9999d703b6c4..6c68beec51b3 100644
--- a/arch/x86_64/kernel/entry.S
+++ b/arch/x86_64/kernel/entry.S
@@ -1089,3 +1089,36 @@ ENTRY(call_softirq)
1089 ret 1089 ret
1090 CFI_ENDPROC 1090 CFI_ENDPROC
1091ENDPROC(call_softirq) 1091ENDPROC(call_softirq)
1092
1093#ifdef CONFIG_STACK_UNWIND
1094ENTRY(arch_unwind_init_running)
1095 CFI_STARTPROC
1096 movq %r15, R15(%rdi)
1097 movq %r14, R14(%rdi)
1098 xchgq %rsi, %rdx
1099 movq %r13, R13(%rdi)
1100 movq %r12, R12(%rdi)
1101 xorl %eax, %eax
1102 movq %rbp, RBP(%rdi)
1103 movq %rbx, RBX(%rdi)
1104 movq (%rsp), %rcx
1105 movq %rax, R11(%rdi)
1106 movq %rax, R10(%rdi)
1107 movq %rax, R9(%rdi)
1108 movq %rax, R8(%rdi)
1109 movq %rax, RAX(%rdi)
1110 movq %rax, RCX(%rdi)
1111 movq %rax, RDX(%rdi)
1112 movq %rax, RSI(%rdi)
1113 movq %rax, RDI(%rdi)
1114 movq %rax, ORIG_RAX(%rdi)
1115 movq %rcx, RIP(%rdi)
1116 leaq 8(%rsp), %rcx
1117 movq $__KERNEL_CS, CS(%rdi)
1118 movq %rax, EFLAGS(%rdi)
1119 movq %rcx, RSP(%rdi)
1120 movq $__KERNEL_DS, SS(%rdi)
1121 jmpq *%rdx
1122 CFI_ENDPROC
1123ENDPROC(arch_unwind_init_running)
1124#endif
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
index dcb77b462348..d6fa41459c80 100644
--- a/arch/x86_64/kernel/process.c
+++ b/arch/x86_64/kernel/process.c
@@ -334,7 +334,7 @@ void show_regs(struct pt_regs *regs)
334{ 334{
335 printk("CPU %d:", smp_processor_id()); 335 printk("CPU %d:", smp_processor_id());
336 __show_regs(regs); 336 __show_regs(regs);
337 show_trace(&regs->rsp); 337 show_trace(NULL, regs, (void *)(regs + 1));
338} 338}
339 339
340/* 340/*
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
193static 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
199void show_trace(unsigned long *stack) 217void 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
265void show_stack(struct task_struct *tsk, unsigned long * rsp) 302static 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
339void 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)
305void dump_stack(void) 347void 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
311EXPORT_SYMBOL(dump_stack); 353EXPORT_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)
diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S
index 5968c2415da9..1c6a5f322919 100644
--- a/arch/x86_64/kernel/vmlinux.lds.S
+++ b/arch/x86_64/kernel/vmlinux.lds.S
@@ -45,6 +45,15 @@ SECTIONS
45 45
46 RODATA 46 RODATA
47 47
48#ifdef CONFIG_STACK_UNWIND
49 . = ALIGN(8);
50 .eh_frame : AT(ADDR(.eh_frame) - LOAD_OFFSET) {
51 __start_unwind = .;
52 *(.eh_frame)
53 __end_unwind = .;
54 }
55#endif
56
48 /* Data */ 57 /* Data */
49 .data : AT(ADDR(.data) - LOAD_OFFSET) { 58 .data : AT(ADDR(.data) - LOAD_OFFSET) {
50 *(.data) 59 *(.data)