Commit c46c2c9b authored by Russell King (Oracle)'s avatar Russell King (Oracle)
Browse files

ARM: unwind: set frame.pc correctly for current-thread unwinding



When e.g. a WARN_ON() is encountered, we attempt to unwind the current
thread. To do this, we set frame.pc to unwind_backtrace, which means it
points at the beginning of the function. However, the rest of the state
is initialised from within the function, which means the function
prologue has already been run.

This can be confusing, and with a recent patch from Ard, can result in
the unwinder misbehaving if we want to be strict about the PC value.

If we correctly initialise the state so it is self-consistent (in other
words, set frame.pc to the location we are initialising it) then we
eliminate this confusion, and avoid possible future issues.

Reviewed-by: default avatarArd Biesheuvel <ardb@kernel.org>
Signed-off-by: default avatarRussell King (Oracle) <rmk+kernel@armlinux.org.uk>
parent 6845d64d
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -41,7 +41,8 @@ void *return_address(unsigned int level)
	frame.fp = (unsigned long)__builtin_frame_address(0);
	frame.sp = current_stack_pointer;
	frame.lr = (unsigned long)__builtin_return_address(0);
	frame.pc = (unsigned long)return_address;
here:
	frame.pc = (unsigned long)&&here;
#ifdef CONFIG_KRETPROBES
	frame.kr_cur = NULL;
	frame.tsk = current;
+2 −1
Original line number Diff line number Diff line
@@ -160,7 +160,8 @@ static noinline void __save_stack_trace(struct task_struct *tsk,
		frame.fp = (unsigned long)__builtin_frame_address(0);
		frame.sp = current_stack_pointer;
		frame.lr = (unsigned long)__builtin_return_address(0);
		frame.pc = (unsigned long)__save_stack_trace;
here:
		frame.pc = (unsigned long)&&here;
	}
#ifdef CONFIG_KRETPROBES
	frame.kr_cur = NULL;
+6 −1
Original line number Diff line number Diff line
@@ -501,7 +501,12 @@ void unwind_backtrace(struct pt_regs *regs, struct task_struct *tsk,
		frame.fp = (unsigned long)__builtin_frame_address(0);
		frame.sp = current_stack_pointer;
		frame.lr = (unsigned long)__builtin_return_address(0);
		frame.pc = (unsigned long)unwind_backtrace;
		/* We are saving the stack and execution state at this
		 * point, so we should ensure that frame.pc is within
		 * this block of code.
		 */
here:
		frame.pc = (unsigned long)&&here;
	} else {
		/* task blocked in __switch_to */
		frame.fp = thread_saved_fp(tsk);