Skip to main content

ghostscope_platform/
register_mapping.rs

1/// Platform-specific register mappings and utilities for eBPF code generation
2///
3/// This module handles the mapping between DWARF register numbers and platform-specific
4/// register layouts (like pt_regs) for different architectures.
5use tracing::warn;
6
7/// pt_regs indices for x86_64 architecture
8///
9/// These indices are used to access pt_regs structure fields as a u64 array.
10/// The indices are calculated by dividing the field offset by the size of u64,
11/// which gives us the array index for accessing pt_regs as a u64 array.
12pub mod pt_regs_indices {
13    use aya_ebpf_bindings::bindings::pt_regs;
14
15    // Size of u64 in bytes for array index calculation
16    const U64_SIZE: usize = core::mem::size_of::<u64>();
17
18    // Core registers - calculated from pt_regs structure layout
19    pub const R15: usize = core::mem::offset_of!(pt_regs, r15) / U64_SIZE;
20    pub const R14: usize = core::mem::offset_of!(pt_regs, r14) / U64_SIZE;
21    pub const R13: usize = core::mem::offset_of!(pt_regs, r13) / U64_SIZE;
22    pub const R12: usize = core::mem::offset_of!(pt_regs, r12) / U64_SIZE;
23    pub const RBP: usize = core::mem::offset_of!(pt_regs, rbp) / U64_SIZE; // Frame pointer
24    pub const RBX: usize = core::mem::offset_of!(pt_regs, rbx) / U64_SIZE;
25    pub const R11: usize = core::mem::offset_of!(pt_regs, r11) / U64_SIZE;
26    pub const R10: usize = core::mem::offset_of!(pt_regs, r10) / U64_SIZE;
27    pub const R9: usize = core::mem::offset_of!(pt_regs, r9) / U64_SIZE;
28    pub const R8: usize = core::mem::offset_of!(pt_regs, r8) / U64_SIZE;
29    pub const RAX: usize = core::mem::offset_of!(pt_regs, rax) / U64_SIZE; // Return value
30    pub const RCX: usize = core::mem::offset_of!(pt_regs, rcx) / U64_SIZE; // 4th argument
31    pub const RDX: usize = core::mem::offset_of!(pt_regs, rdx) / U64_SIZE; // 3rd argument
32    pub const RSI: usize = core::mem::offset_of!(pt_regs, rsi) / U64_SIZE; // 2nd argument
33    pub const RDI: usize = core::mem::offset_of!(pt_regs, rdi) / U64_SIZE; // 1st argument
34
35    // Special registers
36    pub const ORIG_RAX: usize = core::mem::offset_of!(pt_regs, orig_rax) / U64_SIZE; // Original syscall number
37    pub const RIP: usize = core::mem::offset_of!(pt_regs, rip) / U64_SIZE; // Instruction pointer
38    pub const CS: usize = core::mem::offset_of!(pt_regs, cs) / U64_SIZE; // Code segment
39    pub const EFLAGS: usize = core::mem::offset_of!(pt_regs, eflags) / U64_SIZE; // Flags register
40    pub const RSP: usize = core::mem::offset_of!(pt_regs, rsp) / U64_SIZE; // Stack pointer
41    pub const SS: usize = core::mem::offset_of!(pt_regs, ss) / U64_SIZE; // Stack segment
42}
43
44/// Convert DWARF register number to pt_regs byte offset for x86_64
45///
46/// This function maps DWARF register numbers to the correct byte offset
47/// within the pt_regs structure for x86_64 architecture.
48///
49/// Reference: https://github.com/torvalds/linux/blob/master/arch/x86/include/asm/ptrace.h
50/// pt_regs structure layout on x86_64:
51/// ```c
52/// struct pt_regs {
53///     unsigned long r15;    // offset 0
54///     unsigned long r14;    // offset 8
55///     unsigned long r13;    // offset 16
56///     unsigned long r12;    // offset 24
57///     unsigned long bp;     // offset 32  (RBP)
58///     unsigned long bx;     // offset 40  (RBX)
59///     unsigned long r11;    // offset 48
60///     unsigned long r10;    // offset 56
61///     unsigned long r9;     // offset 64
62///     unsigned long r8;     // offset 72
63///     unsigned long ax;     // offset 80  (RAX)
64///     unsigned long cx;     // offset 88  (RCX)
65///     unsigned long dx;     // offset 96  (RDX)
66///     unsigned long si;     // offset 104 (RSI)
67///     unsigned long di;     // offset 112 (RDI)
68///     unsigned long orig_ax;// offset 120
69///     unsigned long ip;     // offset 128 (RIP)
70///     unsigned long cs;     // offset 136
71///     unsigned long flags;  // offset 144
72///     unsigned long sp;     // offset 152 (RSP)
73///     unsigned long ss;     // offset 160
74/// };
75/// ```
76pub fn dwarf_reg_to_pt_regs_byte_offset_x86_64(dwarf_reg: u16) -> Option<usize> {
77    const U64_SIZE: usize = core::mem::size_of::<u64>();
78    match dwarf_reg {
79        // x86_64 DWARF register mappings to pt_regs indices (converted to byte offsets)
80        0 => Some(pt_regs_indices::RAX * U64_SIZE), // DWARF 0 = RAX
81        1 => Some(pt_regs_indices::RDX * U64_SIZE), // DWARF 1 = RDX
82        2 => Some(pt_regs_indices::RCX * U64_SIZE), // DWARF 2 = RCX
83        3 => Some(pt_regs_indices::RBX * U64_SIZE), // DWARF 3 = RBX
84        4 => Some(pt_regs_indices::RSI * U64_SIZE), // DWARF 4 = RSI
85        5 => Some(pt_regs_indices::RDI * U64_SIZE), // DWARF 5 = RDI
86        6 => Some(pt_regs_indices::RBP * U64_SIZE), // DWARF 6 = RBP
87        7 => Some(pt_regs_indices::RSP * U64_SIZE), // DWARF 7 = RSP
88        8 => Some(pt_regs_indices::R8 * U64_SIZE),  // DWARF 8 = R8
89        9 => Some(pt_regs_indices::R9 * U64_SIZE),  // DWARF 9 = R9
90        10 => Some(pt_regs_indices::R10 * U64_SIZE), // DWARF 10 = R10
91        11 => Some(pt_regs_indices::R11 * U64_SIZE), // DWARF 11 = R11
92        12 => Some(pt_regs_indices::R12 * U64_SIZE), // DWARF 12 = R12
93        13 => Some(pt_regs_indices::R13 * U64_SIZE), // DWARF 13 = R13
94        14 => Some(pt_regs_indices::R14 * U64_SIZE), // DWARF 14 = R14
95        15 => Some(pt_regs_indices::R15 * U64_SIZE), // DWARF 15 = R15
96        16 => Some(pt_regs_indices::RIP * U64_SIZE), // DWARF 16 = RIP
97        _ => {
98            warn!("Unknown DWARF register {} for x86_64", dwarf_reg);
99            None
100        }
101    }
102}
103
104/// Convert DWARF register number to register name for x86_64
105///
106/// Maps DWARF register numbers to human-readable register names
107/// for debugging and display purposes.
108pub fn dwarf_reg_to_name_x86_64(dwarf_reg: u16) -> Option<&'static str> {
109    match dwarf_reg {
110        0 => Some("RAX"),  // DWARF 0 = RAX
111        1 => Some("RDX"),  // DWARF 1 = RDX
112        2 => Some("RCX"),  // DWARF 2 = RCX
113        3 => Some("RBX"),  // DWARF 3 = RBX
114        4 => Some("RSI"),  // DWARF 4 = RSI
115        5 => Some("RDI"),  // DWARF 5 = RDI
116        6 => Some("RBP"),  // DWARF 6 = RBP
117        7 => Some("RSP"),  // DWARF 7 = RSP
118        8 => Some("R8"),   // DWARF 8 = R8
119        9 => Some("R9"),   // DWARF 9 = R9
120        10 => Some("R10"), // DWARF 10 = R10
121        11 => Some("R11"), // DWARF 11 = R11
122        12 => Some("R12"), // DWARF 12 = R12
123        13 => Some("R13"), // DWARF 13 = R13
124        14 => Some("R14"), // DWARF 14 = R14
125        15 => Some("R15"), // DWARF 15 = R15
126        16 => Some("RIP"), // DWARF 16 = RIP
127        17 => Some("XMM0"),
128        18 => Some("XMM1"),
129        19 => Some("XMM2"),
130        20 => Some("XMM3"),
131        21 => Some("XMM4"),
132        22 => Some("XMM5"),
133        23 => Some("XMM6"),
134        24 => Some("XMM7"),
135        25 => Some("XMM8"),
136        26 => Some("XMM9"),
137        27 => Some("XMM10"),
138        28 => Some("XMM11"),
139        29 => Some("XMM12"),
140        30 => Some("XMM13"),
141        31 => Some("XMM14"),
142        32 => Some("XMM15"),
143        _ => None,
144    }
145}
146
147/// Convert DWARF register number to register name
148///
149/// Currently only supports x86_64. This function can be extended
150/// to support other architectures in the future.
151pub fn dwarf_reg_to_name(dwarf_reg: u16) -> Option<&'static str> {
152    // For now, we only support x86_64
153    // TODO: Add support for other architectures (ARM64, RISC-V, etc.)
154    dwarf_reg_to_name_x86_64(dwarf_reg)
155}
156
157/// Convert DWARF register number to pt_regs byte offset
158///
159/// Currently only supports x86_64. This function can be extended
160/// to support other architectures in the future.
161pub fn dwarf_reg_to_pt_regs_byte_offset(dwarf_reg: u16) -> Option<usize> {
162    // For now, we only support x86_64
163    // TODO: Add support for other architectures (ARM64, RISC-V, etc.)
164    dwarf_reg_to_pt_regs_byte_offset_x86_64(dwarf_reg)
165}
166
167#[cfg(test)]
168mod tests {
169    use super::*;
170
171    #[test]
172    fn test_x86_64_dwarf_to_pt_regs_mapping() {
173        // Test key registers
174        assert_eq!(dwarf_reg_to_pt_regs_byte_offset_x86_64(0), Some(80)); // RAX
175        assert_eq!(dwarf_reg_to_pt_regs_byte_offset_x86_64(6), Some(32)); // RBP
176        assert_eq!(dwarf_reg_to_pt_regs_byte_offset_x86_64(7), Some(152)); // RSP
177        assert_eq!(dwarf_reg_to_pt_regs_byte_offset_x86_64(16), Some(128)); // RIP
178        assert_eq!(dwarf_reg_to_pt_regs_byte_offset_x86_64(17), None); // XMM0
179
180        // Test invalid register
181        assert_eq!(dwarf_reg_to_pt_regs_byte_offset_x86_64(99), None);
182    }
183
184    #[test]
185    fn test_x86_64_dwarf_to_name_mapping() {
186        // Test core registers
187        assert_eq!(dwarf_reg_to_name_x86_64(0), Some("RAX"));
188        assert_eq!(dwarf_reg_to_name_x86_64(1), Some("RDX"));
189        assert_eq!(dwarf_reg_to_name_x86_64(4), Some("RSI"));
190        assert_eq!(dwarf_reg_to_name_x86_64(5), Some("RDI"));
191        assert_eq!(dwarf_reg_to_name_x86_64(6), Some("RBP"));
192        assert_eq!(dwarf_reg_to_name_x86_64(7), Some("RSP"));
193
194        // Test extended registers
195        assert_eq!(dwarf_reg_to_name_x86_64(8), Some("R8"));
196        assert_eq!(dwarf_reg_to_name_x86_64(13), Some("R13"));
197        assert_eq!(dwarf_reg_to_name_x86_64(15), Some("R15"));
198
199        // Test special registers
200        assert_eq!(dwarf_reg_to_name_x86_64(16), Some("RIP"));
201        assert_eq!(dwarf_reg_to_name_x86_64(17), Some("XMM0"));
202        assert_eq!(dwarf_reg_to_name_x86_64(32), Some("XMM15"));
203
204        // Test invalid register
205        assert_eq!(dwarf_reg_to_name_x86_64(99), None);
206    }
207
208    #[test]
209    fn test_dwarf_reg_to_name_generic() {
210        // Test the generic function (currently just calls x86_64)
211        assert_eq!(dwarf_reg_to_name(0), Some("RAX"));
212        assert_eq!(dwarf_reg_to_name(5), Some("RDI"));
213        assert_eq!(dwarf_reg_to_name(13), Some("R13"));
214        assert_eq!(dwarf_reg_to_name(99), None);
215    }
216
217    #[test]
218    fn test_dwarf_reg_to_pt_regs_byte_offset_generic() {
219        // Test the generic function (currently just calls x86_64)
220        assert_eq!(dwarf_reg_to_pt_regs_byte_offset(0), Some(80)); // RAX
221        assert_eq!(dwarf_reg_to_pt_regs_byte_offset(5), Some(112)); // RDI
222        assert_eq!(dwarf_reg_to_pt_regs_byte_offset(99), None);
223    }
224}