1 use super::X86SegmentRegs;
2 use super::X87FpuInternalRegs;
3 use super::F80;
4 use core::convert::TryInto;
5 use gdbstub::arch::Registers;
6 
7 /// 64-bit x86 core registers (+ SSE extensions).
8 ///
9 /// Source: <https://github.com/bminor/binutils-gdb/blob/master/gdb/features/i386/64bit-core.xml>
10 /// Additionally: <https://github.com/bminor/binutils-gdb/blob/master/gdb/features/i386/64bit-sse.xml>
11 #[derive(Debug, Default, Clone, PartialEq, Eq)]
12 pub struct X86_64CoreRegs {
13     /// RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP, r8-r15
14     pub regs: [u64; 16],
15     /// Status register
16     pub eflags: u32,
17     /// Instruction pointer
18     pub rip: u64,
19     /// Segment registers: CS, SS, DS, ES, FS, GS
20     pub segments: X86SegmentRegs,
21     /// FPU registers: ST0 through ST7
22     pub st: [F80; 8],
23     /// FPU internal registers
24     pub fpu: X87FpuInternalRegs,
25     /// SIMD Registers: XMM0 through XMM15
26     pub xmm: [u128; 0x10],
27     /// SSE Status/Control Register
28     pub mxcsr: u32,
29 }
30 
31 impl Registers for X86_64CoreRegs {
32     type ProgramCounter = u64;
33 
pc(&self) -> Self::ProgramCounter34     fn pc(&self) -> Self::ProgramCounter {
35         self.rip
36     }
37 
gdb_serialize(&self, mut write_byte: impl FnMut(Option<u8>))38     fn gdb_serialize(&self, mut write_byte: impl FnMut(Option<u8>)) {
39         macro_rules! write_bytes {
40             ($bytes:expr) => {
41                 for b in $bytes {
42                     write_byte(Some(*b))
43                 }
44             };
45         }
46 
47         // rax, rbx, rcx, rdx, rsi, rdi, rbp, rsp, r8-r15
48         for reg in &self.regs {
49             write_bytes!(&reg.to_le_bytes());
50         }
51 
52         // rip
53         write_bytes!(&self.rip.to_le_bytes());
54 
55         // eflags
56         write_bytes!(&self.eflags.to_le_bytes());
57 
58         self.segments.gdb_serialize(&mut write_byte);
59 
60         // st0 to st7
61         for st_reg in &self.st {
62             write_bytes!(st_reg);
63         }
64 
65         self.fpu.gdb_serialize(&mut write_byte);
66 
67         // xmm0 to xmm15
68         for xmm_reg in &self.xmm {
69             write_bytes!(&xmm_reg.to_le_bytes());
70         }
71 
72         // mxcsr
73         write_bytes!(&self.mxcsr.to_le_bytes());
74 
75         // padding?
76         // XXX: Couldn't figure out what these do and GDB doesn't actually display any
77         // registers that use these values.
78         (0..0x18).for_each(|_| write_byte(None))
79     }
80 
gdb_deserialize(&mut self, bytes: &[u8]) -> Result<(), ()>81     fn gdb_deserialize(&mut self, bytes: &[u8]) -> Result<(), ()> {
82         if bytes.len() < 0x218 {
83             return Err(());
84         }
85 
86         let mut regs = bytes[0..0x80]
87             .chunks_exact(8)
88             .map(|x| u64::from_le_bytes(x.try_into().unwrap()));
89 
90         for reg in self.regs.iter_mut() {
91             *reg = regs.next().ok_or(())?;
92         }
93 
94         self.rip = u64::from_le_bytes(bytes[0x80..0x88].try_into().unwrap());
95         self.eflags = u32::from_le_bytes(bytes[0x88..0x8C].try_into().unwrap());
96 
97         self.segments.gdb_deserialize(&bytes[0x8C..0xA4])?;
98 
99         let mut regs = bytes[0xA4..0xF4].chunks_exact(10).map(TryInto::try_into);
100 
101         for reg in self.st.iter_mut() {
102             *reg = regs.next().ok_or(())?.map_err(|_| ())?;
103         }
104 
105         self.fpu.gdb_deserialize(&bytes[0xF4..0x114])?;
106 
107         let mut regs = bytes[0x114..0x214]
108             .chunks_exact(0x10)
109             .map(|x| u128::from_le_bytes(x.try_into().unwrap()));
110 
111         for reg in self.xmm.iter_mut() {
112             *reg = regs.next().ok_or(())?;
113         }
114 
115         self.mxcsr = u32::from_le_bytes(bytes[0x214..0x218].try_into().unwrap());
116 
117         Ok(())
118     }
119 }
120