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