1pub mod arch;
9pub mod compact_unwind;
10pub mod cursor;
11pub mod dwarf_cfi;
12pub mod dwarf_expr;
13pub mod frame_pointer;
14pub mod macho;
15pub mod registers;
16
17use crate::types::{CpuType, ThreadState};
18use registers::RegisterContext;
19
20#[derive(Debug, Clone, PartialEq, Eq)]
22pub enum UnwindError {
23 MemoryReadFailed(u64),
25 NoUnwindInfo(u64),
27 InvalidDwarf(String),
29 InvalidCompactUnwind(u32),
31 MaxDepthExceeded(u32),
33 NullPC,
35 BrokenFrameChain,
37}
38
39pub trait MemoryReader {
45 fn read_memory(&self, address: u64, size: usize) -> Option<Vec<u8>>;
48
49 fn read_u8(&self, address: u64) -> Option<u8> {
51 self.read_memory(address, 1).map(|b| b[0])
52 }
53
54 fn read_u16(&self, address: u64) -> Option<u16> {
56 let b = self.read_memory(address, 2)?;
57 Some(u16::from_le_bytes([b[0], b[1]]))
58 }
59
60 fn read_u32(&self, address: u64) -> Option<u32> {
62 let b = self.read_memory(address, 4)?;
63 Some(u32::from_le_bytes([b[0], b[1], b[2], b[3]]))
64 }
65
66 fn read_u64(&self, address: u64) -> Option<u64> {
68 let b = self.read_memory(address, 8)?;
69 Some(u64::from_le_bytes([
70 b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7],
71 ]))
72 }
73
74 fn read_i32(&self, address: u64) -> Option<i32> {
76 self.read_u32(address).map(|v| v as i32)
77 }
78
79 fn read_i64(&self, address: u64) -> Option<i64> {
81 self.read_u64(address).map(|v| v as i64)
82 }
83
84 fn read_pointer(&self, address: u64, is_64_bit: bool) -> Option<u64> {
86 if is_64_bit {
87 self.read_u64(address)
88 } else {
89 self.read_u32(address).map(|v| v as u64)
90 }
91 }
92}
93
94#[derive(Debug, Clone, Copy)]
96pub struct SectionRef {
97 pub vm_addr: u64,
99 pub size: u64,
101}
102
103#[derive(Debug, Clone)]
105pub struct BinaryImageInfo {
106 pub name: String,
108 pub load_address: u64,
110 pub end_address: u64,
112 pub is_64_bit: bool,
114 pub uuid: Option<[u8; 16]>,
116 pub unwind_info: Option<SectionRef>,
118 pub eh_frame: Option<SectionRef>,
120 pub text_section: Option<SectionRef>,
122 pub sections_resolved: bool,
124}
125
126impl BinaryImageInfo {
127 pub fn contains(&self, address: u64) -> bool {
129 address >= self.load_address && address < self.end_address
130 }
131
132 pub fn resolve_sections(&mut self, reader: &dyn MemoryReader) {
134 if self.sections_resolved {
135 return;
136 }
137 self.sections_resolved = true;
138
139 let sections = macho::find_sections(reader, self.load_address, self.is_64_bit);
140 self.unwind_info = sections.unwind_info;
141 self.eh_frame = sections.eh_frame;
142 self.text_section = sections.text;
143 }
144}
145
146pub fn unwind_thread(
155 reader: &dyn MemoryReader,
156 initial_state: &ThreadState,
157 cpu_type: CpuType,
158 images: &mut [BinaryImageInfo],
159) -> Vec<(u64, RegisterContext)> {
160 let is_64_bit = cpu_type.is_64_bit();
161 let Some(regs) = RegisterContext::from_thread_state(initial_state, cpu_type) else {
162 return Vec::new();
163 };
164
165 let mut frame_cursor = cursor::FrameCursor::new(reader, regs, images, is_64_bit);
166 let mut frames = Vec::new();
167
168 if let Some(pc) = frame_cursor.pc() {
170 frames.push((pc, frame_cursor.registers().clone()));
171 }
172
173 while let Ok(true) = frame_cursor.step() {
175 if let Some(pc) = frame_cursor.pc() {
176 frames.push((pc, frame_cursor.registers().clone()));
177 } else {
178 break;
179 }
180 }
181
182 frames
183}
184
185impl MemoryReader for crate::MappedMemory {
187 fn read_memory(&self, address: u64, size: usize) -> Option<Vec<u8>> {
188 let offset = address.checked_sub(self.base_address)? as usize;
189 if offset + size > self.data.len() {
190 return None;
191 }
192 Some(self.data[offset..offset + size].to_vec())
193 }
194}
195
196#[derive(Debug, Clone)]
199pub struct SliceMemoryReader {
200 pub data: Vec<u8>,
202 pub base_address: u64,
204}
205
206impl MemoryReader for SliceMemoryReader {
207 fn read_memory(&self, address: u64, size: usize) -> Option<Vec<u8>> {
208 let offset = address.checked_sub(self.base_address)? as usize;
209 if offset + size > self.data.len() {
210 return None;
211 }
212 Some(self.data[offset..offset + size].to_vec())
213 }
214}
215
216#[cfg(test)]
217mod tests {
218 use super::*;
219
220 #[test]
221 fn slice_memory_reader_basic() {
222 let reader = SliceMemoryReader {
223 data: vec![0x78, 0x56, 0x34, 0x12, 0xEF, 0xBE, 0xAD, 0xDE],
224 base_address: 0x1000,
225 };
226 assert_eq!(reader.read_u32(0x1000), Some(0x12345678));
227 assert_eq!(reader.read_u64(0x1000), Some(0xDEADBEEF_12345678));
228 assert_eq!(reader.read_u8(0x1000), Some(0x78));
229 assert_eq!(reader.read_u16(0x1000), Some(0x5678));
230 }
231
232 #[test]
233 fn slice_memory_reader_out_of_bounds() {
234 let reader = SliceMemoryReader {
235 data: vec![0u8; 4],
236 base_address: 0x1000,
237 };
238 assert!(reader.read_u64(0x1000).is_none());
239 assert!(reader.read_u32(0x1001).is_none());
240 assert!(reader.read_memory(0x0FFF, 1).is_none());
241 }
242
243 #[test]
244 fn slice_memory_reader_pointer() {
245 let reader = SliceMemoryReader {
246 data: 0xDEAD_BEEF_CAFE_BABEu64.to_le_bytes().to_vec(),
247 base_address: 0x2000,
248 };
249 assert_eq!(
250 reader.read_pointer(0x2000, true),
251 Some(0xDEAD_BEEF_CAFE_BABE)
252 );
253 assert_eq!(reader.read_pointer(0x2000, false), Some(0xCAFE_BABE));
254 }
255}