aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/traps.c
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@novell.com>2006-06-26 07:57:47 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-26 13:48:18 -0400
commitc33bd9aac0597eeedaaa01ea5aafe456894b2f2b (patch)
treecdac9bb99eb3943feccc2a21d09a1524a8867cb0 /arch/i386/kernel/traps.c
parentfe7cacc1c25e286872b878c5d46880b620cd1e2d (diff)
[PATCH] i386/x86-64: fall back to old-style call trace if no unwinding
If no unwinding is possible at all for a certain exception instance, fall back to the old style call trace instead of not showing any trace at all. Also, allow setting the stack trace mode at the command line. 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.c46
1 files changed, 33 insertions, 13 deletions
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 286584667865..78464097470a 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -93,6 +93,7 @@ asmlinkage void spurious_interrupt_bug(void);
93asmlinkage void machine_check(void); 93asmlinkage void machine_check(void);
94 94
95static int kstack_depth_to_print = 24; 95static int kstack_depth_to_print = 24;
96static int call_trace = 1;
96ATOMIC_NOTIFIER_HEAD(i386die_chain); 97ATOMIC_NOTIFIER_HEAD(i386die_chain);
97 98
98int register_die_notifier(struct notifier_block *nb) 99int register_die_notifier(struct notifier_block *nb)
@@ -171,40 +172,47 @@ static inline unsigned long print_context_stack(struct thread_info *tinfo,
171 return ebp; 172 return ebp;
172} 173}
173 174
174static asmlinkage void show_trace_unwind(struct unwind_frame_info *info, void *log_lvl) 175static asmlinkage int show_trace_unwind(struct unwind_frame_info *info, void *log_lvl)
175{ 176{
177 int n = 0;
176 int printed = 0; /* nr of entries already printed on current line */ 178 int printed = 0; /* nr of entries already printed on current line */
177 179
178 while (unwind(info) == 0 && UNW_PC(info)) { 180 while (unwind(info) == 0 && UNW_PC(info)) {
181 ++n;
179 printed = print_addr_and_symbol(UNW_PC(info), log_lvl, printed); 182 printed = print_addr_and_symbol(UNW_PC(info), log_lvl, printed);
180 if (arch_unw_user_mode(info)) 183 if (arch_unw_user_mode(info))
181 break; 184 break;
182 } 185 }
183 if (printed) 186 if (printed)
184 printk("\n"); 187 printk("\n");
188 return n;
185} 189}
186 190
187static void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, 191static void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
188 unsigned long *stack, char *log_lvl) 192 unsigned long *stack, char *log_lvl)
189{ 193{
190 unsigned long ebp; 194 unsigned long ebp;
191 struct unwind_frame_info info;
192 195
193 if (!task) 196 if (!task)
194 task = current; 197 task = current;
195 198
196 if (regs) { 199 if (call_trace >= 0) {
197 if (unwind_init_frame_info(&info, task, regs) == 0) { 200 int unw_ret = 0;
198 show_trace_unwind(&info, log_lvl); 201 struct unwind_frame_info info;
199 return; 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);
200 } 211 }
201 } else if (task == current) { 212 if (unw_ret > 0) {
202 if (unwind_init_running(&info, show_trace_unwind, log_lvl) == 0) 213 if (call_trace > 0)
203 return; 214 return;
204 } else { 215 printk("%sLegacy call trace:\n", log_lvl);
205 if (unwind_init_blocked(&info, task) == 0) {
206 show_trace_unwind(&info, log_lvl);
207 return;
208 } 216 }
209 } 217 }
210 218
@@ -1245,3 +1253,15 @@ static int __init kstack_setup(char *s)
1245 return 1; 1253 return 1;
1246} 1254}
1247__setup("kstack=", kstack_setup); 1255__setup("kstack=", kstack_setup);
1256
1257static 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);