use crate::arch::RegId; /// FPU register identifier. #[derive(Debug, Clone, Copy)] pub enum X87FpuInternalRegId { /// Floating-point control register Fctrl, /// Floating-point status register Fstat, /// Tag word Ftag, /// FPU instruction pointer segment Fiseg, /// FPU intstruction pointer offset Fioff, /// FPU operand segment Foseg, /// FPU operand offset Fooff, /// Floating-point opcode Fop, } impl X87FpuInternalRegId { fn from_u8(val: u8) -> Option { use self::X87FpuInternalRegId::*; let r = match val { 0 => Fctrl, 1 => Fstat, 2 => Ftag, 3 => Fiseg, 4 => Fioff, 5 => Foseg, 6 => Fooff, 7 => Fop, _ => return None, }; Some(r) } } /// 32-bit x86 core + SSE register identifier. /// /// Source: https://github.com/bminor/binutils-gdb/blob/master/gdb/features/i386/32bit-core.xml /// Additionally: https://github.com/bminor/binutils-gdb/blob/master/gdb/features/i386/32bit-sse.xml #[derive(Debug, Clone, Copy)] #[non_exhaustive] pub enum X86CoreRegId { /// Accumulator Eax, /// Count register Ecx, /// Data register Edx, /// Base register Ebx, /// Stack pointer Esp, /// Base pointer Ebp, /// Source index Esi, /// Destination index Edi, /// Instruction pointer Eip, /// Status register Eflags, /// Segment registers: CS, SS, DS, ES, FS, GS Segment(u8), /// FPU registers: ST0 through ST7 St(u8), /// FPU internal registers Fpu(X87FpuInternalRegId), /// SIMD Registers: XMM0 through XMM7 Xmm(u8), /// SSE Status/Control Register Mxcsr, } impl RegId for X86CoreRegId { fn from_raw_id(id: usize) -> Option<(Self, usize)> { use self::X86CoreRegId::*; let r = match id { 0 => (Eax, 4), 1 => (Ecx, 4), 2 => (Edx, 4), 3 => (Ebx, 4), 4 => (Esp, 4), 5 => (Ebp, 4), 6 => (Esi, 4), 7 => (Edi, 4), 8 => (Eip, 4), 9 => (Eflags, 4), 10..=15 => (Segment(id as u8 - 10), 4), 16..=23 => (St(id as u8 - 16), 10), 24..=31 => match X87FpuInternalRegId::from_u8(id as u8 - 24) { Some(r) => (Fpu(r), 4), None => unreachable!(), }, 32..=39 => (Xmm(id as u8 - 32), 16), 40 => (Mxcsr, 4), _ => return None, }; Some(r) } } /// 64-bit x86 core + SSE register identifier. /// /// Source: https://github.com/bminor/binutils-gdb/blob/master/gdb/features/i386/64bit-core.xml /// Additionally: https://github.com/bminor/binutils-gdb/blob/master/gdb/features/i386/64bit-sse.xml #[derive(Debug, Clone, Copy)] #[non_exhaustive] pub enum X86_64CoreRegId { /// General purpose registers: /// RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP, r8-r15 Gpr(u8), /// Instruction pointer Rip, /// Status register Eflags, /// Segment registers: CS, SS, DS, ES, FS, GS Segment(u8), /// FPU registers: ST0 through ST7 St(u8), /// FPU internal registers Fpu(X87FpuInternalRegId), /// SIMD Registers: XMM0 through XMM15 Xmm(u8), /// SSE Status/Control Register Mxcsr, } impl RegId for X86_64CoreRegId { fn from_raw_id(id: usize) -> Option<(Self, usize)> { use self::X86_64CoreRegId::*; let r = match id { 0..=15 => (Gpr(id as u8), 8), 16 => (Rip, 4), 17 => (Eflags, 8), 18..=23 => (Segment(id as u8 - 18), 4), 24..=31 => (St(id as u8 - 24), 10), 32..=39 => match X87FpuInternalRegId::from_u8(id as u8 - 32) { Some(r) => (Fpu(r), 4), None => unreachable!(), }, 40..=55 => (Xmm(id as u8 - 40), 16), 56 => (Mxcsr, 4), _ => return None, }; Some(r) } } #[cfg(test)] mod tests { use crate::arch::traits::RegId; use crate::arch::traits::Registers; /// Compare the following two values which are expected to be the same: /// * length of data written by `Registers::gdb_serialize()` in byte /// * sum of sizes of all registers obtained by `RegId::from_raw_id()` fn test() { // Obtain the data length written by `gdb_serialize` by passing a custom // closure. let mut serialized_data_len = 0; let counter = |b: Option| { if b.is_some() { serialized_data_len += 1; } }; Rs::default().gdb_serialize(counter); // Accumulate register sizes returned by `from_raw_id`. let mut i = 0; let mut sum_reg_sizes = 0; while let Some((_, size)) = RId::from_raw_id(i) { sum_reg_sizes += size; i += 1; } assert_eq!(serialized_data_len, sum_reg_sizes); } #[test] fn test_x86() { test::() } #[test] fn test_x86_64() { test::() } }