1 // SPDX-License-Identifier: BSD-2-Clause
2 /*-
3  * Copyright (c) 2023 Andes Technology Corporation
4  * Copyright (c) 2015-2019 Linaro Limited
5  * Copyright (c) 2015 The FreeBSD Foundation
6  */
7 
8 #include <compiler.h>
9 #include <string.h>
10 #include <trace.h>
11 #include <types_ext.h>
12 #include <unw/unwind.h>
13 #include <util.h>
14 
ftrace_map_lr(uint64_t * lr __unused)15 void __weak ftrace_map_lr(uint64_t *lr __unused)
16 {
17 }
18 
unwind_stack_riscv(struct unwind_state_riscv * frame,vaddr_t stack,size_t stack_size)19 bool unwind_stack_riscv(struct unwind_state_riscv *frame,
20 			vaddr_t stack, size_t stack_size)
21 {
22 	vaddr_t fp = frame->fp;
23 	struct unwind_state_riscv *caller_state = NULL;
24 
25 	if (fp < stack)
26 		return false;
27 	if (fp > stack + stack_size)
28 		return false;
29 
30 	/*
31 	 *  |    .....    |       ^  unwind upwards
32 	 *  |    .....    |       |
33 	 *  +=============+  <--+ |  +======= caller FP ==========+
34 	 *  |     RA      |     | |
35 	 *  +-------------+     | |
36 	 *  |  caller FP  |  ---|-+               ^
37 	 *  +-------------+     |          caller stack frame
38 	 *  |    .....    |     |                 v
39 	 *  |    .....    |     |
40 	 *  |    .....    |     |
41 	 *  +=============+     |    +== caller SP / trapped FP ==+
42 	 *  |     RA      |     |
43 	 *  +-------------+     |
44 	 *  |  caller FP  |  ---+                 ^
45 	 *  +-------------+               trapped stack frame
46 	 *  |    .....    |                       v
47 	 *  |    .....    |
48 	 *  |    .....    |
49 	 *  +=============+          +======== trapped SP ========+
50 	 *         |
51 	 *         |  grow downwards
52 	 *         V
53 	 */
54 
55 	/* Get caller FP and RA */
56 	caller_state = (struct unwind_state_riscv *)fp - 1;
57 	frame->fp = caller_state->fp;
58 	frame->pc = caller_state->pc;
59 
60 	ftrace_map_lr(&frame->pc);
61 
62 	frame->pc -= 4;
63 
64 	return true;
65 }
66 
print_stack_riscv(struct unwind_state_riscv * state,vaddr_t stack,size_t stack_size)67 void print_stack_riscv(struct unwind_state_riscv *state,
68 		       vaddr_t stack, size_t stack_size)
69 {
70 	int width = sizeof(unsigned long);
71 
72 	trace_printf_helper_raw(TRACE_ERROR, true, "Call stack:");
73 
74 	ftrace_map_lr(&state->pc);
75 	do {
76 		trace_printf_helper_raw(TRACE_ERROR, true, " 0x%0*"PRIxVA,
77 					width, state->pc);
78 	} while (unwind_stack_riscv(state, stack, stack_size));
79 }
80