aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/traps.c
diff options
context:
space:
mode:
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);