diff options
Diffstat (limited to 'arch/riscv/kernel/stacktrace.c')
| -rw-r--r-- | arch/riscv/kernel/stacktrace.c | 20 | 
1 files changed, 14 insertions, 6 deletions
diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c index 64a9c093aef9..528ec7cc9a62 100644 --- a/arch/riscv/kernel/stacktrace.c +++ b/arch/riscv/kernel/stacktrace.c @@ -18,6 +18,16 @@  extern asmlinkage void ret_from_exception(void); +static inline int fp_is_valid(unsigned long fp, unsigned long sp) +{ +	unsigned long low, high; + +	low = sp + sizeof(struct stackframe); +	high = ALIGN(sp, THREAD_SIZE); + +	return !(fp < low || fp > high || fp & 0x07); +} +  void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,  			     bool (*fn)(void *, unsigned long), void *arg)  { @@ -41,21 +51,19 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,  	}  	for (;;) { -		unsigned long low, high;  		struct stackframe *frame;  		if (unlikely(!__kernel_text_address(pc) || (level++ >= 0 && !fn(arg, pc))))  			break; -		/* Validate frame pointer */ -		low = sp + sizeof(struct stackframe); -		high = ALIGN(sp, THREAD_SIZE); -		if (unlikely(fp < low || fp > high || fp & 0x7)) +		if (unlikely(!fp_is_valid(fp, sp)))  			break; +  		/* Unwind stack frame */  		frame = (struct stackframe *)fp - 1;  		sp = fp; -		if (regs && (regs->epc == pc) && (frame->fp & 0x7)) { +		if (regs && (regs->epc == pc) && fp_is_valid(frame->ra, sp)) { +			/* We hit function where ra is not saved on the stack */  			fp = frame->ra;  			pc = regs->ra;  		} else {  |