diff options
Diffstat (limited to 'arch/i386/kernel/traps.c')
-rw-r--r-- | arch/i386/kernel/traps.c | 70 |
1 files changed, 60 insertions, 10 deletions
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index dcc14477af1f..78464097470a 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> |
@@ -92,6 +93,7 @@ asmlinkage void spurious_interrupt_bug(void); | |||
92 | asmlinkage void machine_check(void); | 93 | asmlinkage void machine_check(void); |
93 | 94 | ||
94 | static int kstack_depth_to_print = 24; | 95 | static int kstack_depth_to_print = 24; |
96 | static int call_trace = 1; | ||
95 | ATOMIC_NOTIFIER_HEAD(i386die_chain); | 97 | ATOMIC_NOTIFIER_HEAD(i386die_chain); |
96 | 98 | ||
97 | int register_die_notifier(struct notifier_block *nb) | 99 | int register_die_notifier(struct notifier_block *nb) |
@@ -170,7 +172,23 @@ static inline unsigned long print_context_stack(struct thread_info *tinfo, | |||
170 | return ebp; | 172 | return ebp; |
171 | } | 173 | } |
172 | 174 | ||
173 | static void show_trace_log_lvl(struct task_struct *task, | 175 | static asmlinkage int show_trace_unwind(struct unwind_frame_info *info, void *log_lvl) |
176 | { | ||
177 | int n = 0; | ||
178 | int printed = 0; /* nr of entries already printed on current line */ | ||
179 | |||
180 | while (unwind(info) == 0 && UNW_PC(info)) { | ||
181 | ++n; | ||
182 | printed = print_addr_and_symbol(UNW_PC(info), log_lvl, printed); | ||
183 | if (arch_unw_user_mode(info)) | ||
184 | break; | ||
185 | } | ||
186 | if (printed) | ||
187 | printk("\n"); | ||
188 | return n; | ||
189 | } | ||
190 | |||
191 | static void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | ||
174 | unsigned long *stack, char *log_lvl) | 192 | unsigned long *stack, char *log_lvl) |
175 | { | 193 | { |
176 | unsigned long ebp; | 194 | unsigned long ebp; |
@@ -178,6 +196,26 @@ static void show_trace_log_lvl(struct task_struct *task, | |||
178 | if (!task) | 196 | if (!task) |
179 | task = current; | 197 | task = current; |
180 | 198 | ||
199 | if (call_trace >= 0) { | ||
200 | int unw_ret = 0; | ||
201 | struct unwind_frame_info info; | ||
202 | |||
203 | if (regs) { | ||
204 | if (unwind_init_frame_info(&info, task, regs) == 0) | ||
205 | unw_ret = show_trace_unwind(&info, log_lvl); | ||
206 | } else if (task == current) | ||
207 | unw_ret = unwind_init_running(&info, show_trace_unwind, log_lvl); | ||
208 | else { | ||
209 | if (unwind_init_blocked(&info, task) == 0) | ||
210 | unw_ret = show_trace_unwind(&info, log_lvl); | ||
211 | } | ||
212 | if (unw_ret > 0) { | ||
213 | if (call_trace > 0) | ||
214 | return; | ||
215 | printk("%sLegacy call trace:\n", log_lvl); | ||
216 | } | ||
217 | } | ||
218 | |||
181 | if (task == current) { | 219 | if (task == current) { |
182 | /* Grab ebp right from our regs */ | 220 | /* Grab ebp right from our regs */ |
183 | asm ("movl %%ebp, %0" : "=r" (ebp) : ); | 221 | asm ("movl %%ebp, %0" : "=r" (ebp) : ); |
@@ -198,13 +236,13 @@ static void show_trace_log_lvl(struct task_struct *task, | |||
198 | } | 236 | } |
199 | } | 237 | } |
200 | 238 | ||
201 | void show_trace(struct task_struct *task, unsigned long * stack) | 239 | void show_trace(struct task_struct *task, struct pt_regs *regs, unsigned long * stack) |
202 | { | 240 | { |
203 | show_trace_log_lvl(task, stack, ""); | 241 | show_trace_log_lvl(task, regs, stack, ""); |
204 | } | 242 | } |
205 | 243 | ||
206 | static void show_stack_log_lvl(struct task_struct *task, unsigned long *esp, | 244 | static void show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, |
207 | char *log_lvl) | 245 | unsigned long *esp, char *log_lvl) |
208 | { | 246 | { |
209 | unsigned long *stack; | 247 | unsigned long *stack; |
210 | int i; | 248 | int i; |
@@ -225,13 +263,13 @@ static void show_stack_log_lvl(struct task_struct *task, unsigned long *esp, | |||
225 | printk("%08lx ", *stack++); | 263 | printk("%08lx ", *stack++); |
226 | } | 264 | } |
227 | printk("\n%sCall Trace:\n", log_lvl); | 265 | printk("\n%sCall Trace:\n", log_lvl); |
228 | show_trace_log_lvl(task, esp, log_lvl); | 266 | show_trace_log_lvl(task, regs, esp, log_lvl); |
229 | } | 267 | } |
230 | 268 | ||
231 | void show_stack(struct task_struct *task, unsigned long *esp) | 269 | void show_stack(struct task_struct *task, unsigned long *esp) |
232 | { | 270 | { |
233 | printk(" "); | 271 | printk(" "); |
234 | show_stack_log_lvl(task, esp, ""); | 272 | show_stack_log_lvl(task, NULL, esp, ""); |
235 | } | 273 | } |
236 | 274 | ||
237 | /* | 275 | /* |
@@ -241,7 +279,7 @@ void dump_stack(void) | |||
241 | { | 279 | { |
242 | unsigned long stack; | 280 | unsigned long stack; |
243 | 281 | ||
244 | show_trace(current, &stack); | 282 | show_trace(current, NULL, &stack); |
245 | } | 283 | } |
246 | 284 | ||
247 | EXPORT_SYMBOL(dump_stack); | 285 | EXPORT_SYMBOL(dump_stack); |
@@ -285,7 +323,7 @@ void show_registers(struct pt_regs *regs) | |||
285 | u8 __user *eip; | 323 | u8 __user *eip; |
286 | 324 | ||
287 | printk("\n" KERN_EMERG "Stack: "); | 325 | printk("\n" KERN_EMERG "Stack: "); |
288 | show_stack_log_lvl(NULL, (unsigned long *)esp, KERN_EMERG); | 326 | show_stack_log_lvl(NULL, regs, (unsigned long *)esp, KERN_EMERG); |
289 | 327 | ||
290 | printk(KERN_EMERG "Code: "); | 328 | printk(KERN_EMERG "Code: "); |
291 | 329 | ||
@@ -1215,3 +1253,15 @@ static int __init kstack_setup(char *s) | |||
1215 | return 1; | 1253 | return 1; |
1216 | } | 1254 | } |
1217 | __setup("kstack=", kstack_setup); | 1255 | __setup("kstack=", kstack_setup); |
1256 | |||
1257 | static int __init call_trace_setup(char *s) | ||
1258 | { | ||
1259 | if (strcmp(s, "old") == 0) | ||
1260 | call_trace = -1; | ||
1261 | else if (strcmp(s, "both") == 0) | ||
1262 | call_trace = 0; | ||
1263 | else if (strcmp(s, "new") == 0) | ||
1264 | call_trace = 1; | ||
1265 | return 1; | ||
1266 | } | ||
1267 | __setup("call_trace=", call_trace_setup); | ||