From ea424055b771a165c9abd3ae109255a3b825c745 Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Wed, 30 Aug 2006 19:37:11 +0200 Subject: [PATCH] [PATCH] x86: Make backtracer fallback logic more bullet-proof The unwinder fallback logic still had potential for falling through to the legacy stack trace code without printing an indication (at once serving as a separator) of this. Further, the stack pointer retrieval for the fallback should be as restrictive as possible (in order to avoid having the legacy stack tracer try to access invalid memory). The patch tightens that, but this could certainly be further improved. Also making the call_trace command line option now conditional upon CONFIG_STACK_UNWIND (as it's meaningless otherwise). Signed-off-by: Jan Beulich Signed-off-by: Andi Kleen Signed-off-by: Linus Torvalds --- arch/i386/kernel/traps.c | 27 ++++++++++++++++----------- arch/x86_64/kernel/traps.c | 28 +++++++++++++++++----------- include/asm-i386/unwind.h | 1 + include/asm-x86_64/unwind.h | 1 + 4 files changed, 35 insertions(+), 22 deletions(-) diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 82e0fd02af1c..7e9edafffd8a 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -92,7 +92,11 @@ asmlinkage void spurious_interrupt_bug(void); asmlinkage void machine_check(void); static int kstack_depth_to_print = 24; +#ifdef CONFIG_STACK_UNWIND static int call_trace = 1; +#else +#define call_trace (-1) +#endif ATOMIC_NOTIFIER_HEAD(i386die_chain); int register_die_notifier(struct notifier_block *nb) @@ -187,22 +191,21 @@ static void show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, if (unwind_init_blocked(&info, task) == 0) unw_ret = show_trace_unwind(&info, log_lvl); } - if (unw_ret > 0 && !arch_unw_user_mode(&info)) { -#ifdef CONFIG_STACK_UNWIND - print_symbol("DWARF2 unwinder stuck at %s\n", - UNW_PC(&info)); - if (call_trace == 1) { - printk("Leftover inexact backtrace:\n"); - if (UNW_SP(&info)) + if (unw_ret > 0) { + if (call_trace == 1 && !arch_unw_user_mode(&info)) { + print_symbol("DWARF2 unwinder stuck at %s\n", + UNW_PC(&info)); + if (UNW_SP(&info) >= PAGE_OFFSET) { + printk("Leftover inexact backtrace:\n"); stack = (void *)UNW_SP(&info); - } else if (call_trace > 1) + } else + printk("Full inexact backtrace again:\n"); + } else if (call_trace >= 1) return; else printk("Full inexact backtrace again:\n"); -#else + } else printk("Inexact backtrace:\n"); -#endif - } } if (task == current) { @@ -1241,6 +1244,7 @@ static int __init kstack_setup(char *s) } __setup("kstack=", kstack_setup); +#ifdef CONFIG_STACK_UNWIND static int __init call_trace_setup(char *s) { if (strcmp(s, "old") == 0) @@ -1254,3 +1258,4 @@ static int __init call_trace_setup(char *s) return 1; } __setup("call_trace=", call_trace_setup); +#endif diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index 14052f089814..5e00af54af65 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -107,7 +107,11 @@ static inline void preempt_conditional_cli(struct pt_regs *regs) } static int kstack_depth_to_print = 12; +#ifdef CONFIG_STACK_UNWIND static int call_trace = 1; +#else +#define call_trace (-1) +#endif #ifdef CONFIG_KALLSYMS # include @@ -274,21 +278,21 @@ void show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s if (unwind_init_blocked(&info, tsk) == 0) unw_ret = show_trace_unwind(&info, NULL); } - if (unw_ret > 0 && !arch_unw_user_mode(&info)) { -#ifdef CONFIG_STACK_UNWIND - unsigned long rip = info.regs.rip; - print_symbol("DWARF2 unwinder stuck at %s\n", rip); - if (call_trace == 1) { - printk("Leftover inexact backtrace:\n"); - stack = (unsigned long *)info.regs.rsp; - } else if (call_trace > 1) + if (unw_ret > 0) { + if (call_trace == 1 && !arch_unw_user_mode(&info)) { + print_symbol("DWARF2 unwinder stuck at %s\n", + UNW_PC(&info)); + if ((long)UNW_SP(&info) < 0) { + printk("Leftover inexact backtrace:\n"); + stack = (unsigned long *)UNW_SP(&info); + } else + printk("Full inexact backtrace again:\n"); + } else if (call_trace >= 1) return; else printk("Full inexact backtrace again:\n"); -#else + } else printk("Inexact backtrace:\n"); -#endif - } } /* @@ -1120,6 +1124,7 @@ static int __init kstack_setup(char *s) } __setup("kstack=", kstack_setup); +#ifdef CONFIG_STACK_UNWIND static int __init call_trace_setup(char *s) { if (strcmp(s, "old") == 0) @@ -1133,3 +1138,4 @@ static int __init call_trace_setup(char *s) return 1; } __setup("call_trace=", call_trace_setup); +#endif diff --git a/include/asm-i386/unwind.h b/include/asm-i386/unwind.h index 69f0f1df6722..4c1a0b968569 100644 --- a/include/asm-i386/unwind.h +++ b/include/asm-i386/unwind.h @@ -87,6 +87,7 @@ static inline int arch_unw_user_mode(const struct unwind_frame_info *info) #else #define UNW_PC(frame) ((void)(frame), 0) +#define UNW_SP(frame) ((void)(frame), 0) static inline int arch_unw_user_mode(const void *info) { diff --git a/include/asm-x86_64/unwind.h b/include/asm-x86_64/unwind.h index f3e7124effe3..1f6e9bfb569e 100644 --- a/include/asm-x86_64/unwind.h +++ b/include/asm-x86_64/unwind.h @@ -95,6 +95,7 @@ static inline int arch_unw_user_mode(const struct unwind_frame_info *info) #else #define UNW_PC(frame) ((void)(frame), 0) +#define UNW_SP(frame) ((void)(frame), 0) static inline int arch_unw_user_mode(const void *info) {