diff options
-rw-r--r-- | arch/i386/kernel/traps.c | 46 | ||||
-rw-r--r-- | arch/x86_64/kernel/traps.c | 51 | ||||
-rw-r--r-- | include/asm-i386/unwind.h | 8 | ||||
-rw-r--r-- | include/asm-x86_64/unwind.h | 8 | ||||
-rw-r--r-- | include/linux/unwind.h | 8 | ||||
-rw-r--r-- | kernel/unwind.c | 7 |
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); | |||
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); | ||
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 | ||
109 | static int kstack_depth_to_print = 10; | 109 | static int kstack_depth_to_print = 10; |
110 | static 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 | ||
193 | static void show_trace_unwind(struct unwind_frame_info *info, void *context) | 194 | static 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 | ||
1063 | static 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 | ||
69 | extern asmlinkage void arch_unwind_init_running(struct unwind_frame_info *, | 69 | extern 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 | ||
74 | static inline int arch_unw_user_mode(const struct unwind_frame_info *info) | 74 | static 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 | ||
78 | extern void arch_unwind_init_running(struct unwind_frame_info *, | 78 | extern 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 | ||
83 | static inline int arch_unw_user_mode(const struct unwind_frame_info *info) | 83 | static 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 | */ |
51 | extern int unwind_init_running(struct unwind_frame_info *, | 51 | extern 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 | ||
99 | static inline int unwind_init_running(struct unwind_frame_info *info, | 99 | static 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 | */ |
887 | int unwind_init_running(struct unwind_frame_info *info, | 887 | int 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 | } |
897 | EXPORT_SYMBOL(unwind_init_running); | 896 | EXPORT_SYMBOL(unwind_init_running); |
898 | 897 | ||