diff options
author | Jan Beulich <jbeulich@novell.com> | 2006-06-26 07:57:47 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-26 13:48:18 -0400 |
commit | c33bd9aac0597eeedaaa01ea5aafe456894b2f2b (patch) | |
tree | cdac9bb99eb3943feccc2a21d09a1524a8867cb0 /arch/i386 | |
parent | fe7cacc1c25e286872b878c5d46880b620cd1e2d (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')
-rw-r--r-- | arch/i386/kernel/traps.c | 46 |
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); | |||
93 | asmlinkage void machine_check(void); | 93 | asmlinkage void machine_check(void); |
94 | 94 | ||
95 | static int kstack_depth_to_print = 24; | 95 | static int kstack_depth_to_print = 24; |
96 | static int call_trace = 1; | ||
96 | ATOMIC_NOTIFIER_HEAD(i386die_chain); | 97 | ATOMIC_NOTIFIER_HEAD(i386die_chain); |
97 | 98 | ||
98 | int register_die_notifier(struct notifier_block *nb) | 99 | int 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 | ||
174 | static asmlinkage void show_trace_unwind(struct unwind_frame_info *info, void *log_lvl) | 175 | static 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 | ||
187 | static void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, | 191 | static 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 | |||
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); | ||