blob: ec2f1be89065fddb03497db1c0311631f5160d81 [file] [log] [blame]
use core::num::NonZeroUsize;
use gdbstub::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 instruction pointer offset
Fioff,
/// FPU operand segment
Foseg,
/// FPU operand offset
Fooff,
/// Floating-point opcode
Fop,
}
impl X87FpuInternalRegId {
fn from_u8(val: u8) -> Option<Self> {
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)
}
}
/// Segment register identifier.
#[derive(Debug, Clone, Copy)]
#[allow(clippy::upper_case_acronyms)]
pub enum X86SegmentRegId {
/// Code Segment
CS,
/// Stack Segment
SS,
/// Data Segment
DS,
/// Extra Segment
ES,
/// General Purpose Segment
FS,
/// General Purpose Segment
GS,
}
impl X86SegmentRegId {
fn from_u8(val: u8) -> Option<Self> {
use self::X86SegmentRegId::*;
let r = match val {
0 => CS,
1 => SS,
2 => DS,
3 => ES,
4 => FS,
5 => GS,
_ => 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
Segment(X86SegmentRegId),
/// 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, Option<NonZeroUsize>)> {
use self::X86CoreRegId::*;
let (r, sz): (X86CoreRegId, usize) = 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(X86SegmentRegId::from_u8(id as u8 - 10)?), 4),
16..=23 => (St(id as u8 - 16), 10),
24..=31 => (Fpu(X87FpuInternalRegId::from_u8(id as u8 - 24)?), 4),
32..=39 => (Xmm(id as u8 - 32), 16),
40 => (Mxcsr, 4),
_ => return None,
};
Some((r, Some(NonZeroUsize::new(sz)?)))
}
}
/// 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
Segment(X86SegmentRegId),
/// 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, Option<NonZeroUsize>)> {
use self::X86_64CoreRegId::*;
let (r, sz): (X86_64CoreRegId, usize) = match id {
0..=15 => (Gpr(id as u8), 8),
16 => (Rip, 8),
17 => (Eflags, 4),
18..=23 => (Segment(X86SegmentRegId::from_u8(id as u8 - 18)?), 4),
24..=31 => (St(id as u8 - 24), 10),
32..=39 => (Fpu(X87FpuInternalRegId::from_u8(id as u8 - 32)?), 4),
40..=55 => (Xmm(id as u8 - 40), 16),
56 => (Mxcsr, 4),
_ => return None,
};
Some((r, Some(NonZeroUsize::new(sz)?)))
}
}
#[cfg(test)]
mod tests {
use gdbstub::arch::RegId;
use gdbstub::arch::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<Rs: Registers, RId: RegId>() {
// Obtain the data length written by `gdb_serialize` by passing a custom
// closure.
let mut serialized_data_len = 0;
let counter = |b: Option<u8>| {
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.unwrap().get();
i += 1;
}
assert_eq!(serialized_data_len, sum_reg_sizes);
}
#[test]
fn test_x86() {
test::<crate::x86::reg::X86CoreRegs, crate::x86::reg::id::X86CoreRegId>()
}
#[test]
fn test_x86_64() {
test::<crate::x86::reg::X86_64CoreRegs, crate::x86::reg::id::X86_64CoreRegId>()
}
}