aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@novell.com>2006-06-26 07:57:41 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-26 13:48:17 -0400
commit176a2718f408ce92788b29127050b04dfd6e4f68 (patch)
treebb637b13098f821551d07d3a13d140a908e7bc04 /arch/i386/kernel
parentdffead4e421e289c8434351400d24fd35723e874 (diff)
[PATCH] i386: reliable stack trace support (i386)
These are the i386-specific pieces to enable reliable stack traces. This is going to be even more useful once CFI annotations get added to he assembly code, namely to entry.S. 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/i386/kernel')
-rw-r--r--arch/i386/kernel/entry.S29
-rw-r--r--arch/i386/kernel/process.c2
-rw-r--r--arch/i386/kernel/traps.c50
-rw-r--r--arch/i386/kernel/vmlinux.lds.S9
4 files changed, 79 insertions, 11 deletions
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
index cfc683f153b9..e802f3cac7e3 100644
--- a/arch/i386/kernel/entry.S
+++ b/arch/i386/kernel/entry.S
@@ -663,6 +663,35 @@ ENTRY(spurious_interrupt_bug)
663 pushl $do_spurious_interrupt_bug 663 pushl $do_spurious_interrupt_bug
664 jmp error_code 664 jmp error_code
665 665
666#ifdef CONFIG_STACK_UNWIND
667ENTRY(arch_unwind_init_running)
668 movl 4(%esp), %edx
669 movl (%esp), %ecx
670 leal 4(%esp), %eax
671 movl %ebx, EBX(%edx)
672 xorl %ebx, %ebx
673 movl %ebx, ECX(%edx)
674 movl %ebx, EDX(%edx)
675 movl %esi, ESI(%edx)
676 movl %edi, EDI(%edx)
677 movl %ebp, EBP(%edx)
678 movl %ebx, EAX(%edx)
679 movl $__USER_DS, DS(%edx)
680 movl $__USER_DS, ES(%edx)
681 movl %ebx, ORIG_EAX(%edx)
682 movl %ecx, EIP(%edx)
683 movl 12(%esp), %ecx
684 movl $__KERNEL_CS, CS(%edx)
685 movl %ebx, EFLAGS(%edx)
686 movl %eax, OLDESP(%edx)
687 movl 8(%esp), %eax
688 movl %ecx, 8(%esp)
689 movl EBX(%edx), %ebx
690 movl $__KERNEL_DS, OLDSS(%edx)
691 jmpl *%eax
692ENDPROC(arch_unwind_init_running)
693#endif
694
666.section .rodata,"a" 695.section .rodata,"a"
667#include "syscall_table.S" 696#include "syscall_table.S"
668 697
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 6259afea46d1..525432e3fef7 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -312,7 +312,7 @@ void show_regs(struct pt_regs * regs)
312 cr3 = read_cr3(); 312 cr3 = read_cr3();
313 cr4 = read_cr4_safe(); 313 cr4 = read_cr4_safe();
314 printk("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4); 314 printk("CR0: %08lx CR2: %08lx CR3: %08lx CR4: %08lx\n", cr0, cr2, cr3, cr4);
315 show_trace(NULL, &regs->esp); 315 show_trace(NULL, regs, &regs->esp);
316} 316}
317 317
318/* 318/*
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index dcc14477af1f..286584667865 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -28,6 +28,7 @@
28#include <linux/utsname.h> 28#include <linux/utsname.h>
29#include <linux/kprobes.h> 29#include <linux/kprobes.h>
30#include <linux/kexec.h> 30#include <linux/kexec.h>
31#include <linux/unwind.h>
31 32
32#ifdef CONFIG_EISA 33#ifdef CONFIG_EISA
33#include <linux/ioport.h> 34#include <linux/ioport.h>
@@ -47,7 +48,7 @@
47#include <asm/desc.h> 48#include <asm/desc.h>
48#include <asm/i387.h> 49#include <asm/i387.h>
49#include <asm/nmi.h> 50#include <asm/nmi.h>
50 51#include <asm/unwind.h>
51#include <asm/smp.h> 52#include <asm/smp.h>
52#include <asm/arch_hooks.h> 53#include <asm/arch_hooks.h>
53#include <asm/kdebug.h> 54#include <asm/kdebug.h>
@@ -170,14 +171,43 @@ static inline unsigned long print_context_stack(struct thread_info *tinfo,
170 return ebp; 171 return ebp;
171} 172}
172 173
173static void show_trace_log_lvl(struct task_struct *task, 174static asmlinkage void show_trace_unwind(struct unwind_frame_info *info, void *log_lvl)
175{
176 int printed = 0; /* nr of entries already printed on current line */
177
178 while (unwind(info) == 0 && UNW_PC(info)) {
179 printed = print_addr_and_symbol(UNW_PC(info), log_lvl, printed);
180 if (arch_unw_user_mode(info))
181 break;
182 }
183 if (printed)
184 printk("\n");
185}
186
187static void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
174 unsigned long *stack, char *log_lvl) 188 unsigned long *stack, char *log_lvl)
175{ 189{
176 unsigned long ebp; 190 unsigned long ebp;
191 struct unwind_frame_info info;
177 192
178 if (!task) 193 if (!task)
179 task = current; 194 task = current;
180 195
196 if (regs) {
197 if (unwind_init_frame_info(&info, task, regs) == 0) {
198 show_trace_unwind(&info, log_lvl);
199 return;
200 }
201 } else if (task == current) {
202 if (unwind_init_running(&info, show_trace_unwind, log_lvl) == 0)
203 return;
204 } else {
205 if (unwind_init_blocked(&info, task) == 0) {
206 show_trace_unwind(&info, log_lvl);
207 return;
208 }
209 }
210
181 if (task == current) { 211 if (task == current) {
182 /* Grab ebp right from our regs */ 212 /* Grab ebp right from our regs */
183 asm ("movl %%ebp, %0" : "=r" (ebp) : ); 213 asm ("movl %%ebp, %0" : "=r" (ebp) : );
@@ -198,13 +228,13 @@ static void show_trace_log_lvl(struct task_struct *task,
198 } 228 }
199} 229}
200 230
201void show_trace(struct task_struct *task, unsigned long * stack) 231void show_trace(struct task_struct *task, struct pt_regs *regs, unsigned long * stack)
202{ 232{
203 show_trace_log_lvl(task, stack, ""); 233 show_trace_log_lvl(task, regs, stack, "");
204} 234}
205 235
206static void show_stack_log_lvl(struct task_struct *task, unsigned long *esp, 236static void show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
207 char *log_lvl) 237 unsigned long *esp, char *log_lvl)
208{ 238{
209 unsigned long *stack; 239 unsigned long *stack;
210 int i; 240 int i;
@@ -225,13 +255,13 @@ static void show_stack_log_lvl(struct task_struct *task, unsigned long *esp,
225 printk("%08lx ", *stack++); 255 printk("%08lx ", *stack++);
226 } 256 }
227 printk("\n%sCall Trace:\n", log_lvl); 257 printk("\n%sCall Trace:\n", log_lvl);
228 show_trace_log_lvl(task, esp, log_lvl); 258 show_trace_log_lvl(task, regs, esp, log_lvl);
229} 259}
230 260
231void show_stack(struct task_struct *task, unsigned long *esp) 261void show_stack(struct task_struct *task, unsigned long *esp)
232{ 262{
233 printk(" "); 263 printk(" ");
234 show_stack_log_lvl(task, esp, ""); 264 show_stack_log_lvl(task, NULL, esp, "");
235} 265}
236 266
237/* 267/*
@@ -241,7 +271,7 @@ void dump_stack(void)
241{ 271{
242 unsigned long stack; 272 unsigned long stack;
243 273
244 show_trace(current, &stack); 274 show_trace(current, NULL, &stack);
245} 275}
246 276
247EXPORT_SYMBOL(dump_stack); 277EXPORT_SYMBOL(dump_stack);
@@ -285,7 +315,7 @@ void show_registers(struct pt_regs *regs)
285 u8 __user *eip; 315 u8 __user *eip;
286 316
287 printk("\n" KERN_EMERG "Stack: "); 317 printk("\n" KERN_EMERG "Stack: ");
288 show_stack_log_lvl(NULL, (unsigned long *)esp, KERN_EMERG); 318 show_stack_log_lvl(NULL, regs, (unsigned long *)esp, KERN_EMERG);
289 319
290 printk(KERN_EMERG "Code: "); 320 printk(KERN_EMERG "Code: ");
291 321
diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S
index 7512f39c9f25..2d4f1386e2b1 100644
--- a/arch/i386/kernel/vmlinux.lds.S
+++ b/arch/i386/kernel/vmlinux.lds.S
@@ -71,6 +71,15 @@ SECTIONS
71 .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) { *(.data.read_mostly) } 71 .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) { *(.data.read_mostly) }
72 _edata = .; /* End of data section */ 72 _edata = .; /* End of data section */
73 73
74#ifdef CONFIG_STACK_UNWIND
75 . = ALIGN(4);
76 .eh_frame : AT(ADDR(.eh_frame) - LOAD_OFFSET) {
77 __start_unwind = .;
78 *(.eh_frame)
79 __end_unwind = .;
80 }
81#endif
82
74 . = ALIGN(THREAD_SIZE); /* init_task */ 83 . = ALIGN(THREAD_SIZE); /* init_task */
75 .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) { 84 .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) {
76 *(.data.init_task) 85 *(.data.init_task)