aboutsummaryrefslogtreecommitdiffstats
path: root/arch
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
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')
-rw-r--r--arch/i386/kernel/traps.c46
-rw-r--r--arch/x86_64/kernel/traps.c51
2 files changed, 68 insertions, 29 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);
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index eb1534ff1f5f..bd0891f4c2c7 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -107,6 +107,7 @@ static inline void preempt_conditional_cli(struct pt_regs *regs)
107} 107}
108 108
109static int kstack_depth_to_print = 10; 109static int kstack_depth_to_print = 10;
110static int call_trace = 1;
110 111
111#ifdef CONFIG_KALLSYMS 112#ifdef CONFIG_KALLSYMS
112#include <linux/kallsyms.h> 113#include <linux/kallsyms.h>
@@ -190,11 +191,12 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
190 return NULL; 191 return NULL;
191} 192}
192 193
193static void show_trace_unwind(struct unwind_frame_info *info, void *context) 194static int show_trace_unwind(struct unwind_frame_info *info, void *context)
194{ 195{
195 int i = 11; 196 int i = 11, n = 0;
196 197
197 while (unwind(info) == 0 && UNW_PC(info)) { 198 while (unwind(info) == 0 && UNW_PC(info)) {
199 ++n;
198 if (i > 50) { 200 if (i > 50) {
199 printk("\n "); 201 printk("\n ");
200 i = 7; 202 i = 7;
@@ -205,6 +207,7 @@ static void show_trace_unwind(struct unwind_frame_info *info, void *context)
205 break; 207 break;
206 } 208 }
207 printk("\n"); 209 printk("\n");
210 return n;
208} 211}
209 212
210/* 213/*
@@ -218,27 +221,32 @@ void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s
218{ 221{
219 const unsigned cpu = safe_smp_processor_id(); 222 const unsigned cpu = safe_smp_processor_id();
220 unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr; 223 unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr;
221 int i; 224 int i = 11;
222 unsigned used = 0; 225 unsigned used = 0;
223 struct unwind_frame_info info;
224 226
225 printk("\nCall Trace:"); 227 printk("\nCall Trace:");
226 228
227 if (!tsk) 229 if (!tsk)
228 tsk = current; 230 tsk = current;
229 231
230 if (regs) { 232 if (call_trace >= 0) {
231 if (unwind_init_frame_info(&info, tsk, regs) == 0) { 233 int unw_ret = 0;
232 show_trace_unwind(&info, NULL); 234 struct unwind_frame_info info;
233 return; 235
236 if (regs) {
237 if (unwind_init_frame_info(&info, tsk, regs) == 0)
238 unw_ret = show_trace_unwind(&info, NULL);
239 } else if (tsk == current)
240 unw_ret = unwind_init_running(&info, show_trace_unwind, NULL);
241 else {
242 if (unwind_init_blocked(&info, tsk) == 0)
243 unw_ret = show_trace_unwind(&info, NULL);
234 } 244 }
235 } else if (tsk == current) { 245 if (unw_ret > 0) {
236 if (unwind_init_running(&info, show_trace_unwind, NULL) == 0) 246 if (call_trace > 0)
237 return; 247 return;
238 } else { 248 printk("Legacy call trace:");
239 if (unwind_init_blocked(&info, tsk) == 0) { 249 i = 18;
240 show_trace_unwind(&info, NULL);
241 return;
242 } 250 }
243 } 251 }
244 252
@@ -264,7 +272,7 @@ void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s
264 } \ 272 } \
265 } while (0) 273 } while (0)
266 274
267 for(i = 11; ; ) { 275 for(; ; ) {
268 const char *id; 276 const char *id;
269 unsigned long *estack_end; 277 unsigned long *estack_end;
270 estack_end = in_exception_stack(cpu, (unsigned long)stack, 278 estack_end = in_exception_stack(cpu, (unsigned long)stack,
@@ -1052,3 +1060,14 @@ static int __init kstack_setup(char *s)
1052} 1060}
1053__setup("kstack=", kstack_setup); 1061__setup("kstack=", kstack_setup);
1054 1062
1063static int __init call_trace_setup(char *s)
1064{
1065 if (strcmp(s, "old") == 0)
1066 call_trace = -1;
1067 else if (strcmp(s, "both") == 0)
1068 call_trace = 0;
1069 else if (strcmp(s, "new") == 0)
1070 call_trace = 1;
1071 return 1;
1072}
1073__setup("call_trace=", call_trace_setup);