diff --git a/arch/x86/kernel/unwind_frame.c b/arch/x86/kernel/unwind_frame.c index bda82df34c7b1e79fa3ebcd974c676a4b9fa8001..ae0821f6c3a599b18d0ea6c1da01ca8b788faef6 100644 --- a/arch/x86/kernel/unwind_frame.c +++ b/arch/x86/kernel/unwind_frame.c @@ -91,16 +91,26 @@ static bool in_entry_code(unsigned long ip) return false; } +static inline unsigned long *last_frame(struct unwind_state *state) +{ + return (unsigned long *)task_pt_regs(state->task) - 2; +} + #ifdef CONFIG_X86_32 #define GCC_REALIGN_WORDS 3 #else #define GCC_REALIGN_WORDS 1 #endif +static inline unsigned long *last_aligned_frame(struct unwind_state *state) +{ + return last_frame(state) - GCC_REALIGN_WORDS; +} + static bool is_last_task_frame(struct unwind_state *state) { - unsigned long *last_bp = (unsigned long *)task_pt_regs(state->task) - 2; - unsigned long *aligned_bp = last_bp - GCC_REALIGN_WORDS; + unsigned long *last_bp = last_frame(state); + unsigned long *aligned_bp = last_aligned_frame(state); /* * We have to check for the last task frame at two different locations @@ -277,10 +287,14 @@ bool unwind_next_frame(struct unwind_state *state) /* * Don't warn if the unwinder got lost due to an interrupt in entry - * code before the stack was set up: + * code or in the C handler before the first frame pointer got set up: */ if (state->got_irq && in_entry_code(state->ip)) goto the_end; + if (state->regs && + state->regs->sp >= (unsigned long)last_aligned_frame(state) && + state->regs->sp < (unsigned long)task_pt_regs(state->task)) + goto the_end; if (state->regs) { printk_deferred_once(KERN_WARNING