debug_worker/gdb/arch/x86/reg/
core32.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use super::F80;
5use super::X86SegmentRegs;
6use super::X87FpuInternalRegs;
7use core::convert::TryInto;
8use gdbstub::arch::Registers;
9
10/// 32-bit x86 core registers (+ SSE extensions).
11///
12/// Source: <https://github.com/bminor/binutils-gdb/blob/master/gdb/features/i386/32bit-core.xml>
13/// Additionally: <https://github.com/bminor/binutils-gdb/blob/master/gdb/features/i386/32bit-sse.xml>
14#[derive(Debug, Default, Clone, PartialEq, Eq)]
15pub struct X86CoreRegs {
16    /// Accumulator
17    pub eax: u32,
18    /// Count register
19    pub ecx: u32,
20    /// Data register
21    pub edx: u32,
22    /// Base register
23    pub ebx: u32,
24    /// Stack pointer
25    pub esp: u32,
26    /// Base pointer
27    pub ebp: u32,
28    /// Source index
29    pub esi: u32,
30    /// Destination index
31    pub edi: u32,
32    /// Instruction pointer
33    pub eip: u32,
34    /// Status register
35    pub eflags: u32,
36    /// Segment registers: CS, SS, DS, ES, FS, GS
37    pub segments: X86SegmentRegs,
38    /// FPU registers: ST0 through ST7
39    pub st: [F80; 8],
40    /// FPU internal registers
41    pub fpu: X87FpuInternalRegs,
42    /// SIMD Registers: XMM0 through XMM7
43    pub xmm: [u128; 8],
44    /// SSE Status/Control Register
45    pub mxcsr: u32,
46}
47
48impl Registers for X86CoreRegs {
49    type ProgramCounter = u32;
50
51    fn pc(&self) -> Self::ProgramCounter {
52        self.eip
53    }
54
55    fn gdb_serialize(&self, mut write_byte: impl FnMut(Option<u8>)) {
56        macro_rules! write_bytes {
57            ($bytes:expr) => {
58                for b in $bytes {
59                    write_byte(Some(*b))
60                }
61            };
62        }
63
64        macro_rules! write_regs {
65            ($($reg:ident),*) => {
66                $(
67                    write_bytes!(&self.$reg.to_le_bytes());
68                )*
69            }
70        }
71
72        write_regs!(eax, ecx, edx, ebx, esp, ebp, esi, edi, eip, eflags);
73
74        self.segments.gdb_serialize(&mut write_byte);
75
76        // st0 to st7
77        for st_reg in &self.st {
78            write_bytes!(st_reg);
79        }
80
81        self.fpu.gdb_serialize(&mut write_byte);
82
83        // xmm0 to xmm15
84        for xmm_reg in &self.xmm {
85            write_bytes!(&xmm_reg.to_le_bytes());
86        }
87
88        // mxcsr
89        write_bytes!(&self.mxcsr.to_le_bytes());
90    }
91
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}