1use crate::types::{CpuType, ThreadState};
4
5const MAX_REGS: usize = 96;
7
8#[derive(Debug, Clone)]
12pub struct RegisterContext {
13 regs: [Option<u64>; MAX_REGS],
14 pub cpu_type: CpuType,
15 pub is_64_bit: bool,
16}
17
18pub mod arm64 {
20 pub const FP: u16 = 29; pub const LR: u16 = 30; pub const SP: u16 = 31;
24 pub const PC: u16 = 32; pub const NON_VOLATILE: &[u16] = &[19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30];
28}
29
30pub mod x86_64 {
32 pub const RAX: u16 = 0;
33 pub const RDX: u16 = 1;
34 pub const RCX: u16 = 2;
35 pub const RBX: u16 = 3;
36 pub const RSI: u16 = 4;
37 pub const RDI: u16 = 5;
38 pub const RBP: u16 = 6;
39 pub const RSP: u16 = 7;
40 pub const R8: u16 = 8;
41 pub const R9: u16 = 9;
42 pub const R10: u16 = 10;
43 pub const R11: u16 = 11;
44 pub const R12: u16 = 12;
45 pub const R13: u16 = 13;
46 pub const R14: u16 = 14;
47 pub const R15: u16 = 15;
48 pub const RIP: u16 = 16;
49 pub const RFLAGS: u16 = 49;
51
52 pub const NON_VOLATILE: &[u16] = &[3, 6, 12, 13, 14, 15];
54}
55
56impl RegisterContext {
57 pub fn new(cpu_type: CpuType) -> Self {
59 Self {
60 regs: [None; MAX_REGS],
61 cpu_type,
62 is_64_bit: cpu_type.is_64_bit(),
63 }
64 }
65
66 pub fn pc(&self) -> Option<u64> {
68 if self.is_arm() {
69 self.regs[arm64::PC as usize].or(self.regs[arm64::LR as usize])
71 } else {
72 self.regs[x86_64::RIP as usize]
73 }
74 }
75
76 pub fn sp(&self) -> Option<u64> {
78 if self.is_arm() {
79 self.regs[arm64::SP as usize]
80 } else {
81 self.regs[x86_64::RSP as usize]
82 }
83 }
84
85 pub fn fp(&self) -> Option<u64> {
87 if self.is_arm() {
88 self.regs[arm64::FP as usize]
89 } else {
90 self.regs[x86_64::RBP as usize]
91 }
92 }
93
94 pub fn lr(&self) -> Option<u64> {
96 if self.is_arm() {
97 self.regs[arm64::LR as usize]
98 } else {
99 None
100 }
101 }
102
103 pub fn get(&self, dwarf_reg: u16) -> Option<u64> {
105 if (dwarf_reg as usize) < MAX_REGS {
106 self.regs[dwarf_reg as usize]
107 } else {
108 None
109 }
110 }
111
112 pub fn set(&mut self, dwarf_reg: u16, value: u64) {
114 if (dwarf_reg as usize) < MAX_REGS {
115 self.regs[dwarf_reg as usize] = Some(value);
116 }
117 }
118
119 pub fn clear(&mut self, dwarf_reg: u16) {
121 if (dwarf_reg as usize) < MAX_REGS {
122 self.regs[dwarf_reg as usize] = None;
123 }
124 }
125
126 pub fn set_pc(&mut self, value: u64) {
128 if self.is_arm() {
129 self.regs[arm64::PC as usize] = Some(value);
130 } else {
131 self.regs[x86_64::RIP as usize] = Some(value);
132 }
133 }
134
135 pub fn set_sp(&mut self, value: u64) {
137 if self.is_arm() {
138 self.regs[arm64::SP as usize] = Some(value);
139 } else {
140 self.regs[x86_64::RSP as usize] = Some(value);
141 }
142 }
143
144 pub fn set_fp(&mut self, value: u64) {
146 if self.is_arm() {
147 self.regs[arm64::FP as usize] = Some(value);
148 } else {
149 self.regs[x86_64::RBP as usize] = Some(value);
150 }
151 }
152
153 pub fn clear_volatile(&mut self) {
155 let non_volatile = if self.is_arm() {
156 arm64::NON_VOLATILE
157 } else {
158 x86_64::NON_VOLATILE
159 };
160
161 let saved: Vec<(u16, Option<u64>)> =
162 non_volatile.iter().map(|&r| (r, self.get(r))).collect();
163 let sp = self.sp();
164 let pc = self.pc();
165
166 self.regs = [None; MAX_REGS];
167
168 for (r, v) in saved {
169 if let Some(val) = v {
170 self.set(r, val);
171 }
172 }
173 if let Some(v) = sp {
174 self.set_sp(v);
175 }
176 if let Some(v) = pc {
177 self.set_pc(v);
178 }
179 }
180
181 pub fn from_thread_state(state: &ThreadState, cpu_type: CpuType) -> Option<Self> {
183 let mut ctx = Self::new(cpu_type);
184 let regs = &state.registers;
185 let flavor = state.flavor;
186
187 if cpu_type == CpuType::ARM64 || cpu_type == CpuType::ARM {
188 ctx.populate_from_arm_thread_state(flavor, regs)?;
189 } else if cpu_type == CpuType::X86_64 || cpu_type == CpuType::X86 {
190 ctx.populate_from_x86_thread_state(flavor, regs)?;
191 } else {
192 return None;
193 }
194
195 Some(ctx)
196 }
197
198 fn populate_from_arm_thread_state(&mut self, flavor: u32, regs: &[u32]) -> Option<()> {
199 match flavor {
200 6 if regs.len() >= 68 => {
201 self.read_arm64_regs(regs, 0);
203 Some(())
204 }
205 1 if !regs.is_empty() => {
206 let sub_flavor = regs[0];
207 if sub_flavor == 2 && regs.len() >= 70 {
208 self.read_arm64_regs(regs, 2);
210 Some(())
211 } else {
212 None }
214 }
215 _ => None,
216 }
217 }
218
219 fn read_arm64_regs(&mut self, regs: &[u32], offset: usize) {
220 let r64 = |idx: usize| -> u64 {
221 let base = offset + idx * 2;
222 (regs[base] as u64) | ((regs[base + 1] as u64) << 32)
223 };
224
225 for i in 0..29 {
227 self.set(i as u16, r64(i));
228 }
229 self.set(arm64::FP, r64(29));
231 self.set(arm64::LR, r64(30));
233 self.set(arm64::SP, r64(31));
235 self.set(arm64::PC, r64(32));
237 }
238
239 fn populate_from_x86_thread_state(&mut self, flavor: u32, regs: &[u32]) -> Option<()> {
240 match flavor {
241 7 if !regs.is_empty() => {
242 let sub_flavor = regs[0];
243 if sub_flavor == 1 && regs.len() >= 18 {
244 return None;
246 }
247 if regs.len() >= 44 {
248 self.read_x86_64_regs(regs, 2);
250 return Some(());
251 }
252 None
253 }
254 _ => None,
255 }
256 }
257
258 fn read_x86_64_regs(&mut self, regs: &[u32], offset: usize) {
259 let r64 = |idx: usize| -> u64 {
260 let base = offset + idx * 2;
261 (regs[base] as u64) | ((regs[base + 1] as u64) << 32)
262 };
263
264 self.set(x86_64::RAX, r64(0));
267 self.set(x86_64::RBX, r64(1));
268 self.set(x86_64::RCX, r64(2));
269 self.set(x86_64::RDX, r64(3));
270 self.set(x86_64::RDI, r64(4));
271 self.set(x86_64::RSI, r64(5));
272 self.set(x86_64::RBP, r64(6));
273 self.set(x86_64::RSP, r64(7));
274 self.set(x86_64::R8, r64(8));
275 self.set(x86_64::R9, r64(9));
276 self.set(x86_64::R10, r64(10));
277 self.set(x86_64::R11, r64(11));
278 self.set(x86_64::R12, r64(12));
279 self.set(x86_64::R13, r64(13));
280 self.set(x86_64::R14, r64(14));
281 self.set(x86_64::R15, r64(15));
282 self.set(x86_64::RIP, r64(16));
283 self.set(x86_64::RFLAGS, r64(17));
284 }
285
286 fn is_arm(&self) -> bool {
287 self.cpu_type == CpuType::ARM64 || self.cpu_type == CpuType::ARM
288 }
289}
290
291#[cfg(test)]
292mod tests {
293 use super::*;
294
295 #[test]
296 fn new_context_is_empty() {
297 let ctx = RegisterContext::new(CpuType::ARM64);
298 assert!(ctx.pc().is_none());
299 assert!(ctx.sp().is_none());
300 assert!(ctx.fp().is_none());
301 assert!(ctx.lr().is_none());
302 }
303
304 #[test]
305 fn arm64_set_get_registers() {
306 let mut ctx = RegisterContext::new(CpuType::ARM64);
307 ctx.set(0, 0xAAAA);
308 ctx.set(arm64::FP, 0xBBBB);
309 ctx.set(arm64::LR, 0xCCCC);
310 ctx.set(arm64::SP, 0xDDDD);
311 ctx.set(arm64::PC, 0xEEEE);
312
313 assert_eq!(ctx.get(0), Some(0xAAAA));
314 assert_eq!(ctx.fp(), Some(0xBBBB));
315 assert_eq!(ctx.lr(), Some(0xCCCC));
316 assert_eq!(ctx.sp(), Some(0xDDDD));
317 assert_eq!(ctx.pc(), Some(0xEEEE));
318 }
319
320 #[test]
321 fn x86_64_set_get_registers() {
322 let mut ctx = RegisterContext::new(CpuType::X86_64);
323 ctx.set(x86_64::RAX, 0x1111);
324 ctx.set(x86_64::RBP, 0x2222);
325 ctx.set(x86_64::RSP, 0x3333);
326 ctx.set(x86_64::RIP, 0x4444);
327
328 assert_eq!(ctx.get(x86_64::RAX), Some(0x1111));
329 assert_eq!(ctx.fp(), Some(0x2222));
330 assert_eq!(ctx.sp(), Some(0x3333));
331 assert_eq!(ctx.pc(), Some(0x4444));
332 assert!(ctx.lr().is_none());
334 }
335
336 #[test]
337 fn from_thread_state_arm64_flavor6() {
338 let mut regs = vec![0u32; 68];
339 regs[0] = 0xCAFE_BABE; regs[1] = 0x0000_0001; regs[58] = 0x1111_0000; regs[59] = 0x0000_AAAA; regs[60] = 0x2222_0000; regs[61] = 0x0000_BBBB; regs[62] = 0x3333_0000; regs[63] = 0x0000_CCCC; regs[64] = 0x4444_0000; regs[65] = 0x0000_DDDD; let state = ThreadState {
351 flavor: 6,
352 registers: regs,
353 };
354 let ctx = RegisterContext::from_thread_state(&state, CpuType::ARM64).unwrap();
355 assert_eq!(ctx.get(0), Some(0x0000_0001_CAFE_BABE));
356 assert_eq!(ctx.fp(), Some(0x0000_AAAA_1111_0000));
357 assert_eq!(ctx.lr(), Some(0x0000_BBBB_2222_0000));
358 assert_eq!(ctx.sp(), Some(0x0000_CCCC_3333_0000));
359 assert_eq!(ctx.pc(), Some(0x0000_DDDD_4444_0000));
360 }
361
362 #[test]
363 fn from_thread_state_x86_64_flavor7() {
364 let mut regs = vec![0u32; 44];
365 regs[0] = 4; regs[1] = 0;
367 regs[2] = 0xDEAD_BEEF;
369 regs[3] = 0x0000_0001;
370 regs[14] = 0xAAAA_0000;
372 regs[15] = 0x0000_FFFF;
373 regs[16] = 0xBBBB_0000;
375 regs[17] = 0x0000_EEEE;
376 regs[34] = 0xCCCC_0000;
378 regs[35] = 0x0000_DDDD;
379
380 let state = ThreadState {
381 flavor: 7,
382 registers: regs,
383 };
384 let ctx = RegisterContext::from_thread_state(&state, CpuType::X86_64).unwrap();
385 assert_eq!(ctx.get(x86_64::RAX), Some(0x0000_0001_DEAD_BEEF));
386 assert_eq!(ctx.fp(), Some(0x0000_FFFF_AAAA_0000));
387 assert_eq!(ctx.sp(), Some(0x0000_EEEE_BBBB_0000));
388 assert_eq!(ctx.pc(), Some(0x0000_DDDD_CCCC_0000));
389 }
390
391 #[test]
392 fn clear_volatile_arm64() {
393 let mut ctx = RegisterContext::new(CpuType::ARM64);
394 ctx.set(0, 0x1111); ctx.set(19, 0x2222); ctx.set(arm64::FP, 0x3333);
398 ctx.set(arm64::LR, 0x4444);
399 ctx.set(arm64::SP, 0x5555);
400 ctx.set(arm64::PC, 0x6666);
401
402 ctx.clear_volatile();
403
404 assert!(ctx.get(0).is_none()); assert_eq!(ctx.get(19), Some(0x2222)); assert_eq!(ctx.fp(), Some(0x3333));
407 assert_eq!(ctx.lr(), Some(0x4444));
409 assert_eq!(ctx.sp(), Some(0x5555));
410 assert_eq!(ctx.pc(), Some(0x6666));
411 }
412
413 #[test]
414 fn clear_volatile_x86_64() {
415 let mut ctx = RegisterContext::new(CpuType::X86_64);
416 ctx.set(x86_64::RAX, 0x1111); ctx.set(x86_64::RBX, 0x2222); ctx.set(x86_64::RBP, 0x3333); ctx.set(x86_64::RSP, 0x4444);
420 ctx.set(x86_64::RIP, 0x5555);
421 ctx.set(x86_64::R12, 0x6666); ctx.clear_volatile();
424
425 assert!(ctx.get(x86_64::RAX).is_none()); assert_eq!(ctx.get(x86_64::RBX), Some(0x2222));
427 assert_eq!(ctx.fp(), Some(0x3333));
428 assert_eq!(ctx.sp(), Some(0x4444));
429 assert_eq!(ctx.pc(), Some(0x5555));
430 assert_eq!(ctx.get(x86_64::R12), Some(0x6666));
431 }
432
433 #[test]
434 fn from_thread_state_unsupported_cpu() {
435 let state = ThreadState {
436 flavor: 0,
437 registers: vec![],
438 };
439 assert!(RegisterContext::from_thread_state(&state, CpuType::POWERPC).is_none());
440 }
441}