diff options
Diffstat (limited to 'arch/i386/kernel/traps.c')
-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); | ||