diff options
Diffstat (limited to 'arch/arm/kernel/ftrace.c')
| -rw-r--r-- | arch/arm/kernel/ftrace.c | 17 | 
1 files changed, 15 insertions, 2 deletions
diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c index a0b6d1e3812f..e61591f33a6c 100644 --- a/arch/arm/kernel/ftrace.c +++ b/arch/arm/kernel/ftrace.c @@ -232,11 +232,24 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,  	unsigned long old;  	if (unlikely(atomic_read(¤t->tracing_graph_pause))) +err_out:  		return;  	if (IS_ENABLED(CONFIG_UNWINDER_FRAME_POINTER)) { -		/* FP points one word below parent's top of stack */ -		frame_pointer += 4; +		/* +		 * Usually, the stack frames are contiguous in memory but cases +		 * have been observed where the next stack frame does not live +		 * at 'frame_pointer + 4' as this code used to assume. +		 * +		 * Instead, dereference the field in the stack frame that +		 * stores the SP of the calling frame: to avoid unbounded +		 * recursion, this cannot involve any ftrace instrumented +		 * functions, so use the __get_kernel_nofault() primitive +		 * directly. +		 */ +		__get_kernel_nofault(&frame_pointer, +				     (unsigned long *)(frame_pointer - 8), +				     unsigned long, err_out);  	} else {  		struct stackframe frame = {  			.fp = frame_pointer,  | 
