esp_backtrace/
riscv.rs

1use core::arch::asm;
2
3use crate::{Backtrace, BacktraceFrame};
4
5// subtract 4 from the return address
6// the return address is the address following the JALR
7// we get better results (especially if the caller was the last instruction in
8// the calling function) if we report the address of the JALR itself
9// even if it was a C.JALR we should get good results using RA - 4
10#[allow(unused)]
11pub(super) const RA_OFFSET: usize = 4;
12
13/// Registers saved in trap handler
14#[doc(hidden)]
15#[derive(Default, Clone, Copy)]
16#[cfg_attr(feature = "defmt", derive(defmt::Format))]
17#[repr(C)]
18#[cfg(feature = "exception-handler")]
19pub(crate) struct TrapFrame {
20    /// Return address, stores the address to return to after a function call or
21    /// interrupt.
22    pub ra: usize,
23    /// Temporary register t0, used for intermediate values.
24    pub t0: usize,
25    /// Temporary register t1, used for intermediate values.
26    pub t1: usize,
27    /// Temporary register t2, used for intermediate values.
28    pub t2: usize,
29    /// Temporary register t3, used for intermediate values.
30    pub t3: usize,
31    /// Temporary register t4, used for intermediate values.
32    pub t4: usize,
33    /// Temporary register t5, used for intermediate values.
34    pub t5: usize,
35    /// Temporary register t6, used for intermediate values.
36    pub t6: usize,
37    /// Argument register a0, typically used to pass the first argument to a
38    /// function.
39    pub a0: usize,
40    /// Argument register a1, typically used to pass the second argument to a
41    /// function.
42    pub a1: usize,
43    /// Argument register a2, typically used to pass the third argument to a
44    /// function.
45    pub a2: usize,
46    /// Argument register a3, typically used to pass the fourth argument to a
47    /// function.
48    pub a3: usize,
49    /// Argument register a4, typically used to pass the fifth argument to a
50    /// function.
51    pub a4: usize,
52    /// Argument register a5, typically used to pass the sixth argument to a
53    /// function.
54    pub a5: usize,
55    /// Argument register a6, typically used to pass the seventh argument to a
56    /// function.
57    pub a6: usize,
58    /// Argument register a7, typically used to pass the eighth argument to a
59    /// function.
60    pub a7: usize,
61    /// Saved register s0, used to hold values across function calls.
62    pub s0: usize,
63    /// Saved register s1, used to hold values across function calls.
64    pub s1: usize,
65    /// Saved register s2, used to hold values across function calls.
66    pub s2: usize,
67    /// Saved register s3, used to hold values across function calls.
68    pub s3: usize,
69    /// Saved register s4, used to hold values across function calls.
70    pub s4: usize,
71    /// Saved register s5, used to hold values across function calls.
72    pub s5: usize,
73    /// Saved register s6, used to hold values across function calls.
74    pub s6: usize,
75    /// Saved register s7, used to hold values across function calls.
76    pub s7: usize,
77    /// Saved register s8, used to hold values across function calls.
78    pub s8: usize,
79    /// Saved register s9, used to hold values across function calls.
80    pub s9: usize,
81    /// Saved register s10, used to hold values across function calls.
82    pub s10: usize,
83    /// Saved register s11, used to hold values across function calls.
84    pub s11: usize,
85    /// Global pointer register, holds the address of the global data area.
86    pub gp: usize,
87    /// Thread pointer register, holds the address of the thread-local storage
88    /// area.
89    pub tp: usize,
90    /// Stack pointer register, holds the address of the top of the stack.
91    pub sp: usize,
92    /// Program counter, stores the address of the next instruction to be
93    /// executed.
94    pub pc: usize,
95    /// Machine status register, holds the current status of the processor,
96    /// including interrupt enable bits and privilege mode.
97    pub mstatus: usize,
98    /// Machine cause register, contains the reason for the trap (e.g.,
99    /// exception or interrupt number).
100    pub mcause: usize,
101    /// Machine trap value register, contains additional information about the
102    /// trap (e.g., faulting address).
103    pub mtval: usize,
104}
105
106#[cfg(feature = "exception-handler")]
107impl core::fmt::Debug for TrapFrame {
108    fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
109        write!(
110            fmt,
111            "TrapFrame
112PC=0x{:08x}         RA/x1=0x{:08x}      SP/x2=0x{:08x}      GP/x3=0x{:08x}      TP/x4=0x{:08x}
113T0/x5=0x{:08x}      T1/x6=0x{:08x}      T2/x7=0x{:08x}      S0/FP/x8=0x{:08x}   S1/x9=0x{:08x}
114A0/x10=0x{:08x}     A1/x11=0x{:08x}     A2/x12=0x{:08x}     A3/x13=0x{:08x}     A4/x14=0x{:08x}
115A5/x15=0x{:08x}     A6/x16=0x{:08x}     A7/x17=0x{:08x}     S2/x18=0x{:08x}     S3/x19=0x{:08x}
116S4/x20=0x{:08x}     S5/x21=0x{:08x}     S6/x22=0x{:08x}     S7/x23=0x{:08x}     S8/x24=0x{:08x}
117S9/x25=0x{:08x}     S10/x26=0x{:08x}    S11/x27=0x{:08x}    T3/x28=0x{:08x}     T4/x29=0x{:08x}
118T5/x30=0x{:08x}     T6/x31=0x{:08x}
119
120MSTATUS=0x{:08x}
121MCAUSE=0x{:08x}
122MTVAL=0x{:08x}
123        ",
124            self.pc,
125            self.ra,
126            self.gp,
127            self.sp,
128            self.tp,
129            self.t0,
130            self.t1,
131            self.t2,
132            self.s0,
133            self.s1,
134            self.a0,
135            self.a1,
136            self.a2,
137            self.a3,
138            self.a4,
139            self.a5,
140            self.a6,
141            self.a7,
142            self.s2,
143            self.s3,
144            self.s4,
145            self.s5,
146            self.s6,
147            self.s7,
148            self.s8,
149            self.s9,
150            self.s10,
151            self.s11,
152            self.t3,
153            self.t4,
154            self.t5,
155            self.t6,
156            self.mstatus,
157            self.mcause,
158            self.mtval,
159        )
160    }
161}
162
163/// Get an array of backtrace addresses.
164///
165/// This needs `force-frame-pointers` enabled.
166#[inline(never)]
167#[cold]
168pub fn backtrace() -> Backtrace {
169    let fp = unsafe {
170        let mut _tmp: u32;
171        asm!("mv {0}, x8", out(reg) _tmp);
172        _tmp
173    };
174
175    backtrace_internal(fp, 2)
176}
177
178pub(crate) fn backtrace_internal(fp: u32, suppress: u32) -> Backtrace {
179    let mut result = Backtrace(heapless::Vec::new());
180
181    let mut fp = fp;
182    let mut suppress = suppress;
183
184    if !crate::is_valid_ram_address(fp) {
185        return result;
186    }
187
188    while !result.0.is_full() {
189        // RA/PC
190        let address = unsafe { (fp as *const u32).offset(-1).read_volatile() };
191        // next FP
192        fp = unsafe { (fp as *const u32).offset(-2).read_volatile() };
193
194        if address == 0 {
195            break;
196        }
197
198        if !crate::is_valid_ram_address(fp) {
199            break;
200        }
201
202        if suppress == 0 {
203            _ = result.0.push(BacktraceFrame {
204                pc: address as usize,
205            });
206        } else {
207            suppress -= 1;
208        }
209    }
210
211    result
212}