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