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