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