aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/traps.c
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/traps.c
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/traps.c')
-rw-r--r--arch/i386/kernel/traps.c50
1 files changed, 40 insertions, 10 deletions
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index dcc14477af1..28658466786 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