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