1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
use std::{mem, ops::Range};
use probe_rs::{Core, MemoryInterface};
/// Registers stacked on exception entry.
#[derive(Debug)]
pub(crate) struct Stacked {
// also pushed onto the stack but we don't need to read them
// r0: u32,
// r1: u32,
// r2: u32,
// r3: u32,
// r12: u32,
pub lr: u32,
pub pc: u32,
contains_fpu_regs: bool,
}
fn bounds_check(bounds: Range<u32>, start: u32, len: u32) -> Result<(), ()> {
let end = start + len;
if bounds.contains(&start) && bounds.contains(&end) {
Ok(())
} else {
Err(())
}
}
impl Stacked {
/// The size of one register / word in bytes
const REGISTER_SIZE: usize = mem::size_of::<u32>();
/// Location (as an offset) of the stacked registers we need for unwinding
const WORDS_OFFSET: usize = 5;
/// Minimum number of stacked registers that we need to read to be able to unwind an exception
const WORDS_MINIMUM: usize = 2;
/// Number of 32-bit words stacked in a basic frame.
const WORDS_BASIC: usize = 8;
/// Number of 32-bit words stacked in an extended frame.
const WORDS_EXTENDED: usize = Self::WORDS_BASIC + 17; // 16 FPU regs + 1 status word
/// Reads stacked registers from RAM
///
/// This performs bound checks and returns `None` if a invalid memory read is requested
pub fn read(
core: &mut Core<'_>,
sp: u32,
fpu: bool,
ram_bounds: Range<u32>,
) -> anyhow::Result<Option<Self>> {
let mut storage = [0; Self::WORDS_MINIMUM];
let registers: &mut [_] = &mut storage;
let start = sp + (Self::REGISTER_SIZE * Self::WORDS_OFFSET) as u32;
if bounds_check(
ram_bounds,
start,
(registers.len() * Self::REGISTER_SIZE) as u32,
)
.is_err()
{
return Ok(None);
}
core.read_32(start, registers)?;
Ok(Some(Stacked {
lr: registers[0],
pc: registers[1],
contains_fpu_regs: fpu,
}))
}
/// Returns the in-memory size of these stacked registers, in Bytes.
pub fn size(&self) -> u32 {
let num_words = if self.contains_fpu_regs {
Self::WORDS_EXTENDED
} else {
Self::WORDS_BASIC
};
num_words as u32 * 4
}
}