1use super::registers::{arm64, x86_64};
4
5pub fn arm64_reg_name(dwarf_reg: u16) -> &'static str {
11 match dwarf_reg {
12 0..=28 => {
13 const NAMES: [&str; 29] = [
14 "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8", "x9", "x10", "x11", "x12",
15 "x13", "x14", "x15", "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", "x24",
16 "x25", "x26", "x27", "x28",
17 ];
18 NAMES[dwarf_reg as usize]
19 }
20 29 => "fp",
21 30 => "lr",
22 31 => "sp",
23 32 => "pc",
24 _ => "?",
25 }
26}
27
28pub fn x86_64_reg_name(dwarf_reg: u16) -> &'static str {
30 match dwarf_reg {
31 0 => "rax",
32 1 => "rdx",
33 2 => "rcx",
34 3 => "rbx",
35 4 => "rsi",
36 5 => "rdi",
37 6 => "rbp",
38 7 => "rsp",
39 8 => "r8",
40 9 => "r9",
41 10 => "r10",
42 11 => "r11",
43 12 => "r12",
44 13 => "r13",
45 14 => "r14",
46 15 => "r15",
47 16 => "rip",
48 49 => "rflags",
49 _ => "?",
50 }
51}
52
53pub mod arm64_compact {
59 pub const MODE_MASK: u32 = 0x0F00_0000;
60 pub const MODE_FRAMELESS: u32 = 0x0200_0000;
61 pub const MODE_DWARF: u32 = 0x0300_0000;
62 pub const MODE_FRAME: u32 = 0x0400_0000;
63
64 pub const FRAME_REG_PAIRS: &[(u16, u16)] = &[
68 (19, 20), (21, 22), (23, 24), (25, 26), (27, 28), ];
75
76 pub const FRAMELESS_STACK_SIZE_MASK: u32 = 0x00FF_F000;
78 pub const FRAMELESS_STACK_SIZE_SHIFT: u32 = 12;
79
80 pub const DWARF_FDE_OFFSET_MASK: u32 = 0x00FF_FFFF;
82}
83
84pub mod x86_64_compact {
86 pub const MODE_MASK: u32 = 0x0F00_0000;
87 pub const MODE_FRAME: u32 = 0x0100_0000;
88 pub const MODE_FRAMELESS_IMMEDIATE: u32 = 0x0200_0000;
89 pub const MODE_FRAMELESS_INDIRECT: u32 = 0x0300_0000;
90 pub const MODE_DWARF: u32 = 0x0400_0000;
91
92 pub const FRAME_OFFSET_MASK: u32 = 0x00FF_0000;
94 pub const FRAME_OFFSET_SHIFT: u32 = 16;
95
96 pub const FRAME_REG_MASK: u32 = 0x0000_7FFF;
99
100 pub const FRAMELESS_STACK_SIZE_MASK: u32 = 0x00FF_0000;
102 pub const FRAMELESS_STACK_SIZE_SHIFT: u32 = 16;
103 pub const FRAMELESS_REG_COUNT_MASK: u32 = 0x0000_FC00;
105 pub const FRAMELESS_REG_COUNT_SHIFT: u32 = 10;
106 pub const FRAMELESS_PERMUTATION_MASK: u32 = 0x0000_03FF;
108
109 pub const INDIRECT_STACK_OFFSET_MASK: u32 = 0x00FF_0000;
111 pub const INDIRECT_STACK_OFFSET_SHIFT: u32 = 16;
112 pub const INDIRECT_STACK_ADJUST_MASK: u32 = 0x0000_E000;
114 pub const INDIRECT_STACK_ADJUST_SHIFT: u32 = 13;
115
116 pub const DWARF_FDE_OFFSET_MASK: u32 = 0x00FF_FFFF;
118
119 pub const FRAME_REG_MAP: [u16; 7] = [
122 0, super::x86_64::RBX,
124 super::x86_64::R12,
125 super::x86_64::R13,
126 super::x86_64::R14,
127 super::x86_64::R15,
128 super::x86_64::RBP,
129 ];
130}
131
132pub fn arm64_decode_frameless_regs(encoding: u32) -> Vec<u16> {
139 let _stack_size = ((encoding & arm64_compact::FRAMELESS_STACK_SIZE_MASK)
142 >> arm64_compact::FRAMELESS_STACK_SIZE_SHIFT) as u64
143 * 16;
144 let mut regs = Vec::new();
147 for (bit, &(r1, r2)) in arm64_compact::FRAME_REG_PAIRS.iter().enumerate() {
148 if encoding & (1 << bit) != 0 {
149 regs.push(r1);
150 regs.push(r2);
151 }
152 }
153 regs
154}
155
156pub fn x86_64_decode_permutation(encoding: u32) -> Vec<u16> {
159 let reg_count = ((encoding & x86_64_compact::FRAMELESS_REG_COUNT_MASK)
160 >> x86_64_compact::FRAMELESS_REG_COUNT_SHIFT) as usize;
161 let permutation = (encoding & x86_64_compact::FRAMELESS_PERMUTATION_MASK) as usize;
162
163 if reg_count == 0 || reg_count > 6 {
164 return Vec::new();
165 }
166
167 let all_regs: [u16; 6] = [
170 x86_64::RBX,
171 x86_64::R12,
172 x86_64::R13,
173 x86_64::R14,
174 x86_64::R15,
175 x86_64::RBP,
176 ];
177
178 let mut available: Vec<u16> = all_regs[..reg_count].to_vec();
179 let mut result = Vec::with_capacity(reg_count);
180 let mut perm = permutation;
181
182 for i in (1..=reg_count).rev() {
183 let idx = perm / factorial(i - 1);
184 perm %= factorial(i - 1);
185 if idx < available.len() {
186 result.push(available.remove(idx));
187 }
188 }
189
190 result
191}
192
193fn factorial(n: usize) -> usize {
194 match n {
195 0 | 1 => 1,
196 2 => 2,
197 3 => 6,
198 4 => 24,
199 5 => 120,
200 _ => 720,
201 }
202}
203
204pub fn return_address_register(is_arm: bool) -> u16 {
206 if is_arm { arm64::LR } else { x86_64::RIP }
207}
208
209#[cfg(test)]
210mod tests {
211 use super::*;
212
213 #[test]
214 fn arm64_reg_names() {
215 assert_eq!(arm64_reg_name(0), "x0");
216 assert_eq!(arm64_reg_name(28), "x28");
217 assert_eq!(arm64_reg_name(29), "fp");
218 assert_eq!(arm64_reg_name(30), "lr");
219 assert_eq!(arm64_reg_name(31), "sp");
220 assert_eq!(arm64_reg_name(32), "pc");
221 assert_eq!(arm64_reg_name(99), "?");
222 }
223
224 #[test]
225 fn x86_64_reg_names() {
226 assert_eq!(x86_64_reg_name(0), "rax");
227 assert_eq!(x86_64_reg_name(6), "rbp");
228 assert_eq!(x86_64_reg_name(7), "rsp");
229 assert_eq!(x86_64_reg_name(16), "rip");
230 assert_eq!(x86_64_reg_name(49), "rflags");
231 assert_eq!(x86_64_reg_name(99), "?");
232 }
233
234 #[test]
235 fn x86_64_decode_permutation_empty() {
236 let encoding = 0u32;
238 assert!(x86_64_decode_permutation(encoding).is_empty());
239 }
240
241 #[test]
242 fn x86_64_decode_permutation_single() {
243 let encoding = (1 << x86_64_compact::FRAMELESS_REG_COUNT_SHIFT) | 0;
245 let regs = x86_64_decode_permutation(encoding);
246 assert_eq!(regs, vec![x86_64::RBX]);
247 }
248
249 #[test]
250 fn return_address_register_arm64() {
251 assert_eq!(return_address_register(true), arm64::LR);
252 }
253
254 #[test]
255 fn return_address_register_x86_64() {
256 assert_eq!(return_address_register(false), x86_64::RIP);
257 }
258}