History

[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.

Jan Beulich committed 20 years ago

Commit c33bd9a1 parent fe7cacc6 files · +83 −45Browse files

Unified · Split

6 files
  1. arch/i386/kernel/traps.c +33 −13
  2. arch/x86_64/kernel/traps.c +35 −16
  3. include/asm-i386/unwind.h +4 −4
  4. include/asm-x86_64/unwind.h +4 −4
  5. include/linux/unwind.h +4 −4
  6. kernel/unwind.c +3 −4
arch/i386/kernel/traps.c+33−13
@@ -93,6 +93,7 @@ asmlinkage void spurious_interrupt_bug(void); · 92 unmodified lines
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, · 72 unmodified lines
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) · 1034 unmodified lines
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);
arch/x86_64/kernel/traps.c+35−16
@@ -107,6 +107,7 @@ static inline void preempt_conditional_cli(struct pt_regs *regs) · 106 unmodified lines
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_KALLSYMS112#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, · 77 unmodified lines
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) · 4 unmodified lines
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 · 7 unmodified lines
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 · 19 unmodified lines
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) · 781 unmodified lines
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);
include/asm-i386/unwind.h+4−4
@@ -66,10 +66,10 @@ static inline void arch_unw_init_blocked(struct unwind_frame_info *info) · 65 unmodified lines
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{
include/asm-x86_64/unwind.h+4−4
@@ -75,10 +75,10 @@ static inline void arch_unw_init_blocked(struct unwind_frame_info *info) · 74 unmodified lines
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{
include/linux/unwind.h+4−4
@@ -49,8 +49,8 @@ extern int unwind_init_blocked(struct unwind_frame_info *, · 48 unmodified lines
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, · 40 unmodified lines
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;
kernel/unwind.c+3−4
@@ -885,14 +885,13 @@ EXPORT_SYMBOL(unwind_init_blocked); · 884 unmodified lines
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