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); asmlinkage void machine_check(void); static int kstack_depth_to_print = 24; +static int call_trace = 1; ATOMIC_NOTIFIER_HEAD(i386die_chain); int register_die_notifier(struct notifier_block *nb) @@ -171,40 +172,47 @@ static inline unsigned long print_context_stack(struct thread_info *tinfo, return ebp; } -static asmlinkage void show_trace_unwind(struct unwind_frame_info *info, void *log_lvl) +static asmlinkage int show_trace_unwind(struct unwind_frame_info *info, void *log_lvl) { + int n = 0; int printed = 0; /* nr of entries already printed on current line */ while (unwind(info) == 0 && UNW_PC(info)) { + ++n; printed = print_addr_and_symbol(UNW_PC(info), log_lvl, printed); if (arch_unw_user_mode(info)) break; } if (printed) printk("\n"); + return n; } static void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, unsigned long *stack, char *log_lvl) { unsigned long ebp; - struct unwind_frame_info info; if (!task) task = current; - if (regs) { - if (unwind_init_frame_info(&info, task, regs) == 0) { - show_trace_unwind(&info, log_lvl); - return; + if (call_trace >= 0) { + int unw_ret = 0; + struct unwind_frame_info info; + + if (regs) { + if (unwind_init_frame_info(&info, task, regs) == 0) + unw_ret = show_trace_unwind(&info, log_lvl); + } else if (task == current) + unw_ret = unwind_init_running(&info, show_trace_unwind, log_lvl); + else { + if (unwind_init_blocked(&info, task) == 0) + unw_ret = show_trace_unwind(&info, log_lvl); } - } else if (task == current) { - if (unwind_init_running(&info, show_trace_unwind, log_lvl) == 0) - return; - } else { - if (unwind_init_blocked(&info, task) == 0) { - show_trace_unwind(&info, log_lvl); - return; + if (unw_ret > 0) { + if (call_trace > 0) + return; + printk("%sLegacy call trace:\n", log_lvl); } } @@ -1245,3 +1253,15 @@ static int __init kstack_setup(char *s) return 1; } __setup("kstack=", kstack_setup); + +static int __init call_trace_setup(char *s) +{ + if (strcmp(s, "old") == 0) + call_trace = -1; + else if (strcmp(s, "both") == 0) + call_trace = 0; + else if (strcmp(s, "new") == 0) + call_trace = 1; + return 1; +} +__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) } static int kstack_depth_to_print = 10; +static int call_trace = 1; #ifdef CONFIG_KALLSYMS #include <linux/kallsyms.h> @@ -190,11 +191,12 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, return NULL; } -static void show_trace_unwind(struct unwind_frame_info *info, void *context) +static int show_trace_unwind(struct unwind_frame_info *info, void *context) { - int i = 11; + int i = 11, n = 0; while (unwind(info) == 0 && UNW_PC(info)) { + ++n; if (i > 50) { printk("\n "); i = 7; @@ -205,6 +207,7 @@ static void show_trace_unwind(struct unwind_frame_info *info, void *context) break; } printk("\n"); + return n; } /* @@ -218,27 +221,32 @@ void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s { const unsigned cpu = safe_smp_processor_id(); unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr; - int i; + int i = 11; unsigned used = 0; - struct unwind_frame_info info; printk("\nCall Trace:"); if (!tsk) tsk = current; - if (regs) { - if (unwind_init_frame_info(&info, tsk, regs) == 0) { - show_trace_unwind(&info, NULL); - return; + if (call_trace >= 0) { + int unw_ret = 0; + struct unwind_frame_info info; + + if (regs) { + if (unwind_init_frame_info(&info, tsk, regs) == 0) + unw_ret = show_trace_unwind(&info, NULL); + } else if (tsk == current) + unw_ret = unwind_init_running(&info, show_trace_unwind, NULL); + else { + if (unwind_init_blocked(&info, tsk) == 0) + unw_ret = show_trace_unwind(&info, NULL); } - } else if (tsk == current) { - if (unwind_init_running(&info, show_trace_unwind, NULL) == 0) - return; - } else { - if (unwind_init_blocked(&info, tsk) == 0) { - show_trace_unwind(&info, NULL); - return; + if (unw_ret > 0) { + if (call_trace > 0) + return; + printk("Legacy call trace:"); + i = 18; } } @@ -264,7 +272,7 @@ void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s } \ } while (0) - for(i = 11; ; ) { + for(; ; ) { const char *id; unsigned long *estack_end; estack_end = in_exception_stack(cpu, (unsigned long)stack, @@ -1052,3 +1060,14 @@ static int __init kstack_setup(char *s) } __setup("kstack=", kstack_setup); +static int __init call_trace_setup(char *s) +{ + if (strcmp(s, "old") == 0) + call_trace = -1; + else if (strcmp(s, "both") == 0) + call_trace = 0; + else if (strcmp(s, "new") == 0) + call_trace = 1; + return 1; +} +__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) info->regs.xes = __USER_DS; } -extern asmlinkage void arch_unwind_init_running(struct unwind_frame_info *, - asmlinkage void (*callback)(struct unwind_frame_info *, - void *arg), - void *arg); +extern asmlinkage int arch_unwind_init_running(struct unwind_frame_info *, + asmlinkage int (*callback)(struct unwind_frame_info *, + void *arg), + void *arg); static inline int arch_unw_user_mode(const struct unwind_frame_info *info) { 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) info->regs.ss = __KERNEL_DS; } -extern void arch_unwind_init_running(struct unwind_frame_info *, - void (*callback)(struct unwind_frame_info *, - void *arg), - void *arg); +extern int arch_unwind_init_running(struct unwind_frame_info *, + int (*callback)(struct unwind_frame_info *, + void *arg), + void *arg); static inline int arch_unw_user_mode(const struct unwind_frame_info *info) { 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 *, * Prepare to unwind the currently running thread. */ extern int unwind_init_running(struct unwind_frame_info *, - asmlinkage void (*callback)(struct unwind_frame_info *, - void *arg), + asmlinkage int (*callback)(struct unwind_frame_info *, + void *arg), void *arg); /* @@ -97,8 +97,8 @@ static inline int unwind_init_blocked(struct unwind_frame_info *info, } static inline int unwind_init_running(struct unwind_frame_info *info, - asmlinkage void (*cb)(struct unwind_frame_info *, - void *arg), + asmlinkage int (*cb)(struct unwind_frame_info *, + void *arg), void *arg) { 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); * Prepare to unwind the currently running thread. */ int unwind_init_running(struct unwind_frame_info *info, - asmlinkage void (*callback)(struct unwind_frame_info *, - void *arg), + asmlinkage int (*callback)(struct unwind_frame_info *, + void *arg), void *arg) { info->task = current; - arch_unwind_init_running(info, callback, arg); - return 0; + return arch_unwind_init_running(info, callback, arg); } EXPORT_SYMBOL(unwind_init_running); |