#![allow(dead_code)]
use crate::gdb::{RegisterInfo, RegisterMap};
pub const CONTEXT_SIZE: usize = 1232;
pub const REGISTER_BUFFER_SIZE: usize = CONTEXT_SIZE + 5 * 8;
pub const CONTEXT_AMD64: u32 = 0x0010_0000;
pub const CONTEXT_CONTROL: u32 = CONTEXT_AMD64 | 0x0000_0001;
pub const CONTEXT_INTEGER: u32 = CONTEXT_AMD64 | 0x0000_0002;
pub const CONTEXT_SEGMENTS: u32 = CONTEXT_AMD64 | 0x0000_0004;
pub const CONTEXT_FLOATING_POINT: u32 = CONTEXT_AMD64 | 0x0000_0008;
pub const CONTEXT_DEBUG_REGISTERS: u32 = CONTEXT_AMD64 | 0x0000_0010;
pub const CONTEXT_FULL: u32 = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT;
pub const CONTEXT_ALL: u32 = CONTEXT_CONTROL
| CONTEXT_INTEGER
| CONTEXT_SEGMENTS
| CONTEXT_FLOATING_POINT
| CONTEXT_DEBUG_REGISTERS;
pub const OFFSET_CONTEXT_FLAGS: usize = 0x30;
pub const OFFSET_MX_CSR: usize = 0x34;
pub const OFFSET_SEG_CS: usize = 0x38;
pub const OFFSET_SEG_DS: usize = 0x3A;
pub const OFFSET_SEG_ES: usize = 0x3C;
pub const OFFSET_SEG_FS: usize = 0x3E;
pub const OFFSET_SEG_GS: usize = 0x40;
pub const OFFSET_SEG_SS: usize = 0x42;
pub const OFFSET_EFLAGS: usize = 0x44;
pub const OFFSET_DR0: usize = 0x48;
pub const OFFSET_DR1: usize = 0x50;
pub const OFFSET_DR2: usize = 0x58;
pub const OFFSET_DR3: usize = 0x60;
pub const OFFSET_DR6: usize = 0x68;
pub const OFFSET_DR7: usize = 0x70;
pub const OFFSET_RAX: usize = 0x78;
pub const OFFSET_RCX: usize = 0x80;
pub const OFFSET_RDX: usize = 0x88;
pub const OFFSET_RBX: usize = 0x90;
pub const OFFSET_RSP: usize = 0x98;
pub const OFFSET_RBP: usize = 0xA0;
pub const OFFSET_RSI: usize = 0xA8;
pub const OFFSET_RDI: usize = 0xB0;
pub const OFFSET_R8: usize = 0xB8;
pub const OFFSET_R9: usize = 0xC0;
pub const OFFSET_R10: usize = 0xC8;
pub const OFFSET_R11: usize = 0xD0;
pub const OFFSET_R12: usize = 0xD8;
pub const OFFSET_R13: usize = 0xE0;
pub const OFFSET_R14: usize = 0xE8;
pub const OFFSET_R15: usize = 0xF0;
pub const OFFSET_RIP: usize = 0xF8;
pub const OFFSET_CR0: usize = CONTEXT_SIZE;
pub const OFFSET_CR2: usize = OFFSET_CR0 + 8;
pub const OFFSET_CR3: usize = OFFSET_CR2 + 8;
pub const OFFSET_CR4: usize = OFFSET_CR3 + 8;
pub const OFFSET_CR8: usize = OFFSET_CR4 + 8;
pub fn build_register_map() -> RegisterMap {
let mut regnum = 0usize;
let mut next_reg = |name: &str, offset: usize, size: usize| -> RegisterInfo {
let info = RegisterInfo {
name: name.to_string(),
offset,
size,
regnum,
};
regnum += 1;
info
};
let registers = vec![
next_reg("rax", OFFSET_RAX, 8),
next_reg("rbx", OFFSET_RBX, 8),
next_reg("rcx", OFFSET_RCX, 8),
next_reg("rdx", OFFSET_RDX, 8),
next_reg("rsi", OFFSET_RSI, 8),
next_reg("rdi", OFFSET_RDI, 8),
next_reg("rbp", OFFSET_RBP, 8),
next_reg("rsp", OFFSET_RSP, 8),
next_reg("r8", OFFSET_R8, 8),
next_reg("r9", OFFSET_R9, 8),
next_reg("r10", OFFSET_R10, 8),
next_reg("r11", OFFSET_R11, 8),
next_reg("r12", OFFSET_R12, 8),
next_reg("r13", OFFSET_R13, 8),
next_reg("r14", OFFSET_R14, 8),
next_reg("r15", OFFSET_R15, 8),
next_reg("rip", OFFSET_RIP, 8),
next_reg("eflags", OFFSET_EFLAGS, 4),
next_reg("cs", OFFSET_SEG_CS, 2),
next_reg("ss", OFFSET_SEG_SS, 2),
next_reg("ds", OFFSET_SEG_DS, 2),
next_reg("es", OFFSET_SEG_ES, 2),
next_reg("fs", OFFSET_SEG_FS, 2),
next_reg("gs", OFFSET_SEG_GS, 2),
next_reg("cr0", OFFSET_CR0, 8),
next_reg("cr2", OFFSET_CR2, 8),
next_reg("cr3", OFFSET_CR3, 8),
next_reg("cr4", OFFSET_CR4, 8),
next_reg("cr8", OFFSET_CR8, 8),
];
RegisterMap::from_registers(registers)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn offsets_are_monotonic_in_the_gpr_block() {
let gprs = [
OFFSET_RAX, OFFSET_RCX, OFFSET_RDX, OFFSET_RBX, OFFSET_RSP, OFFSET_RBP, OFFSET_RSI,
OFFSET_RDI, OFFSET_R8, OFFSET_R9, OFFSET_R10, OFFSET_R11, OFFSET_R12, OFFSET_R13,
OFFSET_R14, OFFSET_R15, OFFSET_RIP,
];
for window in gprs.windows(2) {
assert_eq!(
window[1] - window[0],
8,
"non-contiguous GPRs near {:#x}",
window[0]
);
}
}
#[test]
fn register_map_reads_known_offsets() {
let map = build_register_map();
let mut buf = vec![0u8; CONTEXT_SIZE];
let want_rip: u64 = 0xfffff80000123456;
buf[OFFSET_RIP..OFFSET_RIP + 8].copy_from_slice(&want_rip.to_le_bytes());
assert_eq!(map.read_u64("rip", &buf).unwrap(), want_rip);
let want_rsp: u64 = 0xdeadbeef_cafebabe;
buf[OFFSET_RSP..OFFSET_RSP + 8].copy_from_slice(&want_rsp.to_le_bytes());
assert_eq!(map.read_u64("rsp", &buf).unwrap(), want_rsp);
let want_cr3: u64 = 0x1234_5000;
let mut extended = vec![0u8; REGISTER_BUFFER_SIZE];
extended[OFFSET_CR3..OFFSET_CR3 + 8].copy_from_slice(&want_cr3.to_le_bytes());
assert_eq!(map.read_u64("cr3", &extended).unwrap(), want_cr3);
}
#[test]
fn register_map_round_trips_writes() {
let map = build_register_map();
let mut buf = vec![0u8; CONTEXT_SIZE];
map.write_u64("rip", &mut buf, 0x1234_5678_9abc_def0)
.unwrap();
assert_eq!(
&buf[OFFSET_RIP..OFFSET_RIP + 8],
&0x1234_5678_9abc_def0u64.to_le_bytes()
);
buf[OFFSET_EFLAGS + 4] = 0xff;
map.write_u64("eflags", &mut buf, 0x202).unwrap();
assert_eq!(
&buf[OFFSET_EFLAGS..OFFSET_EFLAGS + 4],
&0x202u32.to_le_bytes()
);
assert_eq!(buf[OFFSET_EFLAGS + 4], 0xff, "wrote past register width");
}
}