162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci#include <linux/export.h>
362306a36Sopenharmony_ci#include <linux/kprobes.h>
462306a36Sopenharmony_ci#include <linux/sched.h>
562306a36Sopenharmony_ci#include <linux/sched/debug.h>
662306a36Sopenharmony_ci#include <linux/stacktrace.h>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <asm/sections.h>
962306a36Sopenharmony_ci#include <asm/stacktrace.h>
1062306a36Sopenharmony_ci#include <asm/traps.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "reboot.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND)
1562306a36Sopenharmony_ci/*
1662306a36Sopenharmony_ci * Unwind the current stack frame and store the new register values in the
1762306a36Sopenharmony_ci * structure passed as argument. Unwinding is equivalent to a function return,
1862306a36Sopenharmony_ci * hence the new PC value rather than LR should be used for backtrace.
1962306a36Sopenharmony_ci *
2062306a36Sopenharmony_ci * With framepointer enabled, a simple function prologue looks like this:
2162306a36Sopenharmony_ci *	mov	ip, sp
2262306a36Sopenharmony_ci *	stmdb	sp!, {fp, ip, lr, pc}
2362306a36Sopenharmony_ci *	sub	fp, ip, #4
2462306a36Sopenharmony_ci *
2562306a36Sopenharmony_ci * A simple function epilogue looks like this:
2662306a36Sopenharmony_ci *	ldm	sp, {fp, sp, pc}
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci * When compiled with clang, pc and sp are not pushed. A simple function
2962306a36Sopenharmony_ci * prologue looks like this when built with clang:
3062306a36Sopenharmony_ci *
3162306a36Sopenharmony_ci *	stmdb	{..., fp, lr}
3262306a36Sopenharmony_ci *	add	fp, sp, #x
3362306a36Sopenharmony_ci *	sub	sp, sp, #y
3462306a36Sopenharmony_ci *
3562306a36Sopenharmony_ci * A simple function epilogue looks like this when built with clang:
3662306a36Sopenharmony_ci *
3762306a36Sopenharmony_ci *	sub	sp, fp, #x
3862306a36Sopenharmony_ci *	ldm	{..., fp, pc}
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci *
4162306a36Sopenharmony_ci * Note that with framepointer enabled, even the leaf functions have the same
4262306a36Sopenharmony_ci * prologue and epilogue, therefore we can ignore the LR value in this case.
4362306a36Sopenharmony_ci */
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ciextern unsigned long call_with_stack_end;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic int frame_pointer_check(struct stackframe *frame)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	unsigned long high, low;
5062306a36Sopenharmony_ci	unsigned long fp = frame->fp;
5162306a36Sopenharmony_ci	unsigned long pc = frame->pc;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	/*
5462306a36Sopenharmony_ci	 * call_with_stack() is the only place we allow SP to jump from one
5562306a36Sopenharmony_ci	 * stack to another, with FP and SP pointing to different stacks,
5662306a36Sopenharmony_ci	 * skipping the FP boundary check at this point.
5762306a36Sopenharmony_ci	 */
5862306a36Sopenharmony_ci	if (pc >= (unsigned long)&call_with_stack &&
5962306a36Sopenharmony_ci			pc < (unsigned long)&call_with_stack_end)
6062306a36Sopenharmony_ci		return 0;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	/* only go to a higher address on the stack */
6362306a36Sopenharmony_ci	low = frame->sp;
6462306a36Sopenharmony_ci	high = ALIGN(low, THREAD_SIZE);
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	/* check current frame pointer is within bounds */
6762306a36Sopenharmony_ci#ifdef CONFIG_CC_IS_CLANG
6862306a36Sopenharmony_ci	if (fp < low + 4 || fp > high - 4)
6962306a36Sopenharmony_ci		return -EINVAL;
7062306a36Sopenharmony_ci#else
7162306a36Sopenharmony_ci	if (fp < low + 12 || fp > high - 4)
7262306a36Sopenharmony_ci		return -EINVAL;
7362306a36Sopenharmony_ci#endif
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	return 0;
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ciint notrace unwind_frame(struct stackframe *frame)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	unsigned long fp = frame->fp;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	if (frame_pointer_check(frame))
8362306a36Sopenharmony_ci		return -EINVAL;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	/*
8662306a36Sopenharmony_ci	 * When we unwind through an exception stack, include the saved PC
8762306a36Sopenharmony_ci	 * value into the stack trace.
8862306a36Sopenharmony_ci	 */
8962306a36Sopenharmony_ci	if (frame->ex_frame) {
9062306a36Sopenharmony_ci		struct pt_regs *regs = (struct pt_regs *)frame->sp;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci		/*
9362306a36Sopenharmony_ci		 * We check that 'regs + sizeof(struct pt_regs)' (that is,
9462306a36Sopenharmony_ci		 * &regs[1]) does not exceed the bottom of the stack to avoid
9562306a36Sopenharmony_ci		 * accessing data outside the task's stack. This may happen
9662306a36Sopenharmony_ci		 * when frame->ex_frame is a false positive.
9762306a36Sopenharmony_ci		 */
9862306a36Sopenharmony_ci		if ((unsigned long)&regs[1] > ALIGN(frame->sp, THREAD_SIZE))
9962306a36Sopenharmony_ci			return -EINVAL;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci		frame->pc = regs->ARM_pc;
10262306a36Sopenharmony_ci		frame->ex_frame = false;
10362306a36Sopenharmony_ci		return 0;
10462306a36Sopenharmony_ci	}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	/* restore the registers from the stack frame */
10762306a36Sopenharmony_ci#ifdef CONFIG_CC_IS_CLANG
10862306a36Sopenharmony_ci	frame->sp = frame->fp;
10962306a36Sopenharmony_ci	frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp));
11062306a36Sopenharmony_ci	frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp + 4));
11162306a36Sopenharmony_ci#else
11262306a36Sopenharmony_ci	frame->fp = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 12));
11362306a36Sopenharmony_ci	frame->sp = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 8));
11462306a36Sopenharmony_ci	frame->pc = READ_ONCE_NOCHECK(*(unsigned long *)(fp - 4));
11562306a36Sopenharmony_ci#endif
11662306a36Sopenharmony_ci#ifdef CONFIG_KRETPROBES
11762306a36Sopenharmony_ci	if (is_kretprobe_trampoline(frame->pc))
11862306a36Sopenharmony_ci		frame->pc = kretprobe_find_ret_addr(frame->tsk,
11962306a36Sopenharmony_ci					(void *)frame->fp, &frame->kr_cur);
12062306a36Sopenharmony_ci#endif
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	if (in_entry_text(frame->pc))
12362306a36Sopenharmony_ci		frame->ex_frame = true;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	return 0;
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci#endif
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_civoid notrace walk_stackframe(struct stackframe *frame,
13062306a36Sopenharmony_ci		     bool (*fn)(void *, unsigned long), void *data)
13162306a36Sopenharmony_ci{
13262306a36Sopenharmony_ci	while (1) {
13362306a36Sopenharmony_ci		int ret;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci		if (!fn(data, frame->pc))
13662306a36Sopenharmony_ci			break;
13762306a36Sopenharmony_ci		ret = unwind_frame(frame);
13862306a36Sopenharmony_ci		if (ret < 0)
13962306a36Sopenharmony_ci			break;
14062306a36Sopenharmony_ci	}
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ciEXPORT_SYMBOL(walk_stackframe);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci#ifdef CONFIG_STACKTRACE
14562306a36Sopenharmony_cistatic void start_stack_trace(struct stackframe *frame, struct task_struct *task,
14662306a36Sopenharmony_ci			      unsigned long fp, unsigned long sp,
14762306a36Sopenharmony_ci			      unsigned long lr, unsigned long pc)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	frame->fp = fp;
15062306a36Sopenharmony_ci	frame->sp = sp;
15162306a36Sopenharmony_ci	frame->lr = lr;
15262306a36Sopenharmony_ci	frame->pc = pc;
15362306a36Sopenharmony_ci#ifdef CONFIG_KRETPROBES
15462306a36Sopenharmony_ci	frame->kr_cur = NULL;
15562306a36Sopenharmony_ci	frame->tsk = task;
15662306a36Sopenharmony_ci#endif
15762306a36Sopenharmony_ci#ifdef CONFIG_UNWINDER_FRAME_POINTER
15862306a36Sopenharmony_ci	frame->ex_frame = in_entry_text(frame->pc);
15962306a36Sopenharmony_ci#endif
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_civoid arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
16362306a36Sopenharmony_ci		     struct task_struct *task, struct pt_regs *regs)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	struct stackframe frame;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	if (regs) {
16862306a36Sopenharmony_ci		start_stack_trace(&frame, NULL, regs->ARM_fp, regs->ARM_sp,
16962306a36Sopenharmony_ci				  regs->ARM_lr, regs->ARM_pc);
17062306a36Sopenharmony_ci	} else if (task != current) {
17162306a36Sopenharmony_ci#ifdef CONFIG_SMP
17262306a36Sopenharmony_ci		/*
17362306a36Sopenharmony_ci		 * What guarantees do we have here that 'tsk' is not
17462306a36Sopenharmony_ci		 * running on another CPU?  For now, ignore it as we
17562306a36Sopenharmony_ci		 * can't guarantee we won't explode.
17662306a36Sopenharmony_ci		 */
17762306a36Sopenharmony_ci		return;
17862306a36Sopenharmony_ci#else
17962306a36Sopenharmony_ci		start_stack_trace(&frame, task, thread_saved_fp(task),
18062306a36Sopenharmony_ci				  thread_saved_sp(task), 0,
18162306a36Sopenharmony_ci				  thread_saved_pc(task));
18262306a36Sopenharmony_ci#endif
18362306a36Sopenharmony_ci	} else {
18462306a36Sopenharmony_cihere:
18562306a36Sopenharmony_ci		start_stack_trace(&frame, task,
18662306a36Sopenharmony_ci				  (unsigned long)__builtin_frame_address(0),
18762306a36Sopenharmony_ci				  current_stack_pointer,
18862306a36Sopenharmony_ci				  (unsigned long)__builtin_return_address(0),
18962306a36Sopenharmony_ci				  (unsigned long)&&here);
19062306a36Sopenharmony_ci		/* skip this function */
19162306a36Sopenharmony_ci		if (unwind_frame(&frame))
19262306a36Sopenharmony_ci			return;
19362306a36Sopenharmony_ci	}
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	walk_stackframe(&frame, consume_entry, cookie);
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci#endif
198