1 use super::X86SegmentRegs;
2 use super::X87FpuInternalRegs;
3 use super::F80;
4 use core::convert::TryInto;
5 use gdbstub::arch::Registers;
6 
7 /// 32-bit x86 core registers (+ SSE extensions).
8 ///
9 /// Source: <https://github.com/bminor/binutils-gdb/blob/master/gdb/features/i386/32bit-core.xml>
10 /// Additionally: <https://github.com/bminor/binutils-gdb/blob/master/gdb/features/i386/32bit-sse.xml>
11 #[derive(Debug, Default, Clone, PartialEq, Eq)]
12 pub struct X86CoreRegs {
13     /// Accumulator
14     pub eax: u32,
15     /// Count register
16     pub ecx: u32,
17     /// Data register
18     pub edx: u32,
19     /// Base register
20     pub ebx: u32,
21     /// Stack pointer
22     pub esp: u32,
23     /// Base pointer
24     pub ebp: u32,
25     /// Source index
26     pub esi: u32,
27     /// Destination index
28     pub edi: u32,
29     /// Instruction pointer
30     pub eip: u32,
31     /// Status register
32     pub eflags: u32,
33     /// Segment registers: CS, SS, DS, ES, FS, GS
34     pub segments: X86SegmentRegs,
35     /// FPU registers: ST0 through ST7
36     pub st: [F80; 8],
37     /// FPU internal registers
38     pub fpu: X87FpuInternalRegs,
39     /// SIMD Registers: XMM0 through XMM7
40     pub xmm: [u128; 8],
41     /// SSE Status/Control Register
42     pub mxcsr: u32,
43 }
44 
45 impl Registers for X86CoreRegs {
46     type ProgramCounter = u32;
47 
pc(&self) -> Self::ProgramCounter48     fn pc(&self) -> Self::ProgramCounter {
49         self.eip
50     }
51 
gdb_serialize(&self, mut write_byte: impl FnMut(Option<u8>))52     fn gdb_serialize(&self, mut write_byte: impl FnMut(Option<u8>)) {
53         macro_rules! write_bytes {
54             ($bytes:expr) => {
55                 for b in $bytes {
56                     write_byte(Some(*b))
57                 }
58             };
59         }
60 
61         macro_rules! write_regs {
62             ($($reg:ident),*) => {
63                 $(
64                     write_bytes!(&self.$reg.to_le_bytes());
65                 )*
66             }
67         }
68 
69         write_regs!(eax, ecx, edx, ebx, esp, ebp, esi, edi, eip, eflags);
70 
71         self.segments.gdb_serialize(&mut write_byte);
72 
73         // st0 to st7
74         for st_reg in &self.st {
75             write_bytes!(st_reg);
76         }
77 
78         self.fpu.gdb_serialize(&mut write_byte);
79 
80         // xmm0 to xmm15
81         for xmm_reg in &self.xmm {
82             write_bytes!(&xmm_reg.to_le_bytes());
83         }
84 
85         // mxcsr
86         write_bytes!(&self.mxcsr.to_le_bytes());
87 
88         // padding
89         (0..4).for_each(|_| write_byte(None))
90     }
91 
gdb_deserialize(&mut self, bytes: &[u8]) -> Result<(), ()>92     fn gdb_deserialize(&mut self, bytes: &[u8]) -> Result<(), ()> {
93         if bytes.len() < 0x138 {
94             return Err(());
95         }
96 
97         macro_rules! parse_regs {
98             ($($reg:ident),*) => {
99                 let mut regs = bytes[0..0x28]
100                     .chunks_exact(4)
101                     .map(|x| u32::from_le_bytes(x.try_into().unwrap()));
102                 $(
103                     self.$reg = regs.next().ok_or(())?;
104                 )*
105             }
106         }
107 
108         parse_regs!(eax, ecx, edx, ebx, esp, ebp, esi, edi, eip, eflags);
109 
110         self.segments.gdb_deserialize(&bytes[0x28..0x40])?;
111 
112         let mut regs = bytes[0x40..0x90].chunks_exact(10).map(TryInto::try_into);
113 
114         for reg in self.st.iter_mut() {
115             *reg = regs.next().ok_or(())?.map_err(|_| ())?;
116         }
117 
118         self.fpu.gdb_deserialize(&bytes[0x90..0xb0])?;
119 
120         let mut regs = bytes[0xb0..0x130]
121             .chunks_exact(0x10)
122             .map(|x| u128::from_le_bytes(x.try_into().unwrap()));
123 
124         for reg in self.xmm.iter_mut() {
125             *reg = regs.next().ok_or(())?;
126         }
127 
128         self.mxcsr = u32::from_le_bytes(bytes[0x130..0x134].try_into().unwrap());
129 
130         Ok(())
131     }
132 }
133 
134 #[cfg(test)]
135 mod tests {
136     use super::*;
137 
138     #[test]
x86_core_round_trip()139     fn x86_core_round_trip() {
140         let regs_before = X86CoreRegs {
141             eax: 1,
142             ecx: 2,
143             edx: 3,
144             ebx: 4,
145             esp: 5,
146             ebp: 6,
147             esi: 7,
148             edi: 8,
149             eip: 9,
150             eflags: 10,
151             segments: X86SegmentRegs {
152                 cs: 11,
153                 ss: 12,
154                 ds: 13,
155                 es: 14,
156                 fs: 15,
157                 gs: 16,
158             },
159             st: Default::default(),
160             fpu: X87FpuInternalRegs {
161                 fctrl: 17,
162                 fstat: 18,
163                 ftag: 19,
164                 fiseg: 20,
165                 fioff: 21,
166                 foseg: 22,
167                 fooff: 23,
168                 fop: 24,
169             },
170             xmm: Default::default(),
171             mxcsr: 99,
172         };
173 
174         let mut data = vec![];
175 
176         regs_before.gdb_serialize(|x| {
177             data.push(x.unwrap_or(b'x'));
178         });
179 
180         let mut regs_after = X86CoreRegs::default();
181         regs_after.gdb_deserialize(&data).unwrap();
182 
183         assert_eq!(regs_before, regs_after);
184     }
185 }
186