aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--arch/i386/kernel/traps.c46
-rw-r--r--arch/x86_64/kernel/traps.c51
-rw-r--r--include/asm-i386/unwind.h8
-rw-r--r--include/asm-x86_64/unwind.h8
-rw-r--r--include/linux/unwind.h8
-rw-r--r--kernel/unwind.c7
6 files changed, 83 insertions, 45 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);
diff --git a/include/asm-i386/unwind.h b/include/asm-i386/unwind.h
index 1c076897ac21..d480f2e38215 100644
--- a/include/asm-i386/unwind.h
+++ b/include/asm-i386/unwind.h
@@ -66,10 +66,10 @@ static inline void arch_unw_init_blocked(struct unwind_frame_info *info)
66 info->regs.xes = __USER_DS; 66 info->regs.xes = __USER_DS;
67} 67}
68 68
69extern asmlinkage void arch_unwind_init_running(struct unwind_frame_info *, 69extern asmlinkage int arch_unwind_init_running(struct unwind_frame_info *,
70 asmlinkage void (*callback)(struct unwind_frame_info *, 70 asmlinkage int (*callback)(struct unwind_frame_info *,
71 void *arg), 71 void *arg),
72 void *arg); 72 void *arg);
73 73
74static inline int arch_unw_user_mode(const struct unwind_frame_info *info) 74static inline int arch_unw_user_mode(const struct unwind_frame_info *info)
75{ 75{
diff --git a/include/asm-x86_64/unwind.h b/include/asm-x86_64/unwind.h
index 4f61de246179..f3e7124effe3 100644
--- a/include/asm-x86_64/unwind.h
+++ b/include/asm-x86_64/unwind.h
@@ -75,10 +75,10 @@ static inline void arch_unw_init_blocked(struct unwind_frame_info *info)
75 info->regs.ss = __KERNEL_DS; 75 info->regs.ss = __KERNEL_DS;
76} 76}
77 77
78extern void arch_unwind_init_running(struct unwind_frame_info *, 78extern int arch_unwind_init_running(struct unwind_frame_info *,
79 void (*callback)(struct unwind_frame_info *, 79 int (*callback)(struct unwind_frame_info *,
80 void *arg), 80 void *arg),
81 void *arg); 81 void *arg);
82 82
83static inline int arch_unw_user_mode(const struct unwind_frame_info *info) 83static inline int arch_unw_user_mode(const struct unwind_frame_info *info)
84{ 84{
diff --git a/include/linux/unwind.h b/include/linux/unwind.h
index 0295aa789ab4..13c7b2cd87ce 100644
--- a/include/linux/unwind.h
+++ b/include/linux/unwind.h
@@ -49,8 +49,8 @@ extern int unwind_init_blocked(struct unwind_frame_info *,
49 * Prepare to unwind the currently running thread. 49 * Prepare to unwind the currently running thread.
50 */ 50 */
51extern int unwind_init_running(struct unwind_frame_info *, 51extern int unwind_init_running(struct unwind_frame_info *,
52 asmlinkage void (*callback)(struct unwind_frame_info *, 52 asmlinkage int (*callback)(struct unwind_frame_info *,
53 void *arg), 53 void *arg),
54 void *arg); 54 void *arg);
55 55
56/* 56/*
@@ -97,8 +97,8 @@ static inline int unwind_init_blocked(struct unwind_frame_info *info,
97} 97}
98 98
99static inline int unwind_init_running(struct unwind_frame_info *info, 99static inline int unwind_init_running(struct unwind_frame_info *info,
100 asmlinkage void (*cb)(struct unwind_frame_info *, 100 asmlinkage int (*cb)(struct unwind_frame_info *,
101 void *arg), 101 void *arg),
102 void *arg) 102 void *arg)
103{ 103{
104 return -ENOSYS; 104 return -ENOSYS;
diff --git a/kernel/unwind.c b/kernel/unwind.c
index d36bcd3ad3b5..0421035272d9 100644
--- a/kernel/unwind.c
+++ b/kernel/unwind.c
@@ -885,14 +885,13 @@ EXPORT_SYMBOL(unwind_init_blocked);
885 * Prepare to unwind the currently running thread. 885 * Prepare to unwind the currently running thread.
886 */ 886 */
887int unwind_init_running(struct unwind_frame_info *info, 887int unwind_init_running(struct unwind_frame_info *info,
888 asmlinkage void (*callback)(struct unwind_frame_info *, 888 asmlinkage int (*callback)(struct unwind_frame_info *,
889 void *arg), 889 void *arg),
890 void *arg) 890 void *arg)
891{ 891{
892 info->task = current; 892 info->task = current;
893 arch_unwind_init_running(info, callback, arg);
894 893
895 return 0; 894 return arch_unwind_init_running(info, callback, arg);
896} 895}
897EXPORT_SYMBOL(unwind_init_running); 896EXPORT_SYMBOL(unwind_init_running);
898 897