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