aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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