• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use gdbstub::arch::RegId;
2 
3 /// FPU register identifier.
4 #[derive(Debug, Clone, Copy)]
5 pub enum X87FpuInternalRegId {
6     /// Floating-point control register
7     Fctrl,
8     /// Floating-point status register
9     Fstat,
10     /// Tag word
11     Ftag,
12     /// FPU instruction pointer segment
13     Fiseg,
14     /// FPU instruction pointer offset
15     Fioff,
16     /// FPU operand segment
17     Foseg,
18     /// FPU operand offset
19     Fooff,
20     /// Floating-point opcode
21     Fop,
22 }
23 
24 impl X87FpuInternalRegId {
from_u8(val: u8) -> Option<Self>25     fn from_u8(val: u8) -> Option<Self> {
26         use self::X87FpuInternalRegId::*;
27 
28         let r = match val {
29             0 => Fctrl,
30             1 => Fstat,
31             2 => Ftag,
32             3 => Fiseg,
33             4 => Fioff,
34             5 => Foseg,
35             6 => Fooff,
36             7 => Fop,
37             _ => return None,
38         };
39         Some(r)
40     }
41 }
42 
43 /// Segment register identifier.
44 #[derive(Debug, Clone, Copy)]
45 #[allow(clippy::upper_case_acronyms)]
46 pub enum X86SegmentRegId {
47     /// Code Segment
48     CS,
49     /// Stack Segment
50     SS,
51     /// Data Segment
52     DS,
53     /// Extra Segment
54     ES,
55     /// General Purpose Segment
56     FS,
57     /// General Purpose Segment
58     GS,
59 }
60 
61 impl X86SegmentRegId {
from_u8(val: u8) -> Option<Self>62     fn from_u8(val: u8) -> Option<Self> {
63         use self::X86SegmentRegId::*;
64 
65         let r = match val {
66             0 => CS,
67             1 => SS,
68             2 => DS,
69             3 => ES,
70             4 => FS,
71             5 => GS,
72             _ => return None,
73         };
74         Some(r)
75     }
76 }
77 
78 /// 32-bit x86 core + SSE register identifier.
79 ///
80 /// Source: https://github.com/bminor/binutils-gdb/blob/master/gdb/features/i386/32bit-core.xml
81 /// Additionally: https://github.com/bminor/binutils-gdb/blob/master/gdb/features/i386/32bit-sse.xml
82 #[derive(Debug, Clone, Copy)]
83 #[non_exhaustive]
84 pub enum X86CoreRegId {
85     /// Accumulator
86     Eax,
87     /// Count register
88     Ecx,
89     /// Data register
90     Edx,
91     /// Base register
92     Ebx,
93     /// Stack pointer
94     Esp,
95     /// Base pointer
96     Ebp,
97     /// Source index
98     Esi,
99     /// Destination index
100     Edi,
101     /// Instruction pointer
102     Eip,
103     /// Status register
104     Eflags,
105     /// Segment registers
106     Segment(X86SegmentRegId),
107     /// FPU registers: ST0 through ST7
108     St(u8),
109     /// FPU internal registers
110     Fpu(X87FpuInternalRegId),
111     /// SIMD Registers: XMM0 through XMM7
112     Xmm(u8),
113     /// SSE Status/Control Register
114     Mxcsr,
115 }
116 
117 impl RegId for X86CoreRegId {
from_raw_id(id: usize) -> Option<(Self, usize)>118     fn from_raw_id(id: usize) -> Option<(Self, usize)> {
119         use self::X86CoreRegId::*;
120 
121         let r = match id {
122             0 => (Eax, 4),
123             1 => (Ecx, 4),
124             2 => (Edx, 4),
125             3 => (Ebx, 4),
126             4 => (Esp, 4),
127             5 => (Ebp, 4),
128             6 => (Esi, 4),
129             7 => (Edi, 4),
130             8 => (Eip, 4),
131             9 => (Eflags, 4),
132             10..=15 => (Segment(X86SegmentRegId::from_u8(id as u8 - 10)?), 4),
133             16..=23 => (St(id as u8 - 16), 10),
134             24..=31 => (Fpu(X87FpuInternalRegId::from_u8(id as u8 - 24)?), 4),
135             32..=39 => (Xmm(id as u8 - 32), 16),
136             40 => (Mxcsr, 4),
137             _ => return None,
138         };
139         Some(r)
140     }
141 }
142 
143 /// 64-bit x86 core + SSE register identifier.
144 ///
145 /// Source: https://github.com/bminor/binutils-gdb/blob/master/gdb/features/i386/64bit-core.xml
146 /// Additionally: https://github.com/bminor/binutils-gdb/blob/master/gdb/features/i386/64bit-sse.xml
147 #[derive(Debug, Clone, Copy)]
148 #[non_exhaustive]
149 pub enum X86_64CoreRegId {
150     /// General purpose registers:
151     /// RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP, r8-r15
152     Gpr(u8),
153     /// Instruction pointer
154     Rip,
155     /// Status register
156     Eflags,
157     /// Segment registers
158     Segment(X86SegmentRegId),
159     /// FPU registers: ST0 through ST7
160     St(u8),
161     /// FPU internal registers
162     Fpu(X87FpuInternalRegId),
163     /// SIMD Registers: XMM0 through XMM15
164     Xmm(u8),
165     /// SSE Status/Control Register
166     Mxcsr,
167 }
168 
169 impl RegId for X86_64CoreRegId {
from_raw_id(id: usize) -> Option<(Self, usize)>170     fn from_raw_id(id: usize) -> Option<(Self, usize)> {
171         use self::X86_64CoreRegId::*;
172 
173         let r = match id {
174             0..=15 => (Gpr(id as u8), 8),
175             16 => (Rip, 4),
176             17 => (Eflags, 8),
177             18..=23 => (Segment(X86SegmentRegId::from_u8(id as u8 - 18)?), 4),
178             24..=31 => (St(id as u8 - 24), 10),
179             32..=39 => (Fpu(X87FpuInternalRegId::from_u8(id as u8 - 32)?), 4),
180             40..=55 => (Xmm(id as u8 - 40), 16),
181             56 => (Mxcsr, 4),
182             _ => return None,
183         };
184         Some(r)
185     }
186 }
187 
188 #[cfg(test)]
189 mod tests {
190     use gdbstub::arch::RegId;
191     use gdbstub::arch::Registers;
192 
193     /// Compare the following two values which are expected to be the same:
194     /// * length of data written by `Registers::gdb_serialize()` in byte
195     /// * sum of sizes of all registers obtained by `RegId::from_raw_id()`
test<Rs: Registers, RId: RegId>()196     fn test<Rs: Registers, RId: RegId>() {
197         // Obtain the data length written by `gdb_serialize` by passing a custom
198         // closure.
199         let mut serialized_data_len = 0;
200         let counter = |b: Option<u8>| {
201             if b.is_some() {
202                 serialized_data_len += 1;
203             }
204         };
205         Rs::default().gdb_serialize(counter);
206 
207         // Accumulate register sizes returned by `from_raw_id`.
208         let mut i = 0;
209         let mut sum_reg_sizes = 0;
210         while let Some((_, size)) = RId::from_raw_id(i) {
211             sum_reg_sizes += size;
212             i += 1;
213         }
214 
215         assert_eq!(serialized_data_len, sum_reg_sizes);
216     }
217 
218     #[test]
test_x86()219     fn test_x86() {
220         test::<crate::x86::reg::X86CoreRegs, crate::x86::reg::id::X86CoreRegId>()
221     }
222 
223     #[test]
test_x86_64()224     fn test_x86_64() {
225         test::<crate::x86::reg::X86_64CoreRegs, crate::x86::reg::id::X86_64CoreRegId>()
226     }
227 }
228