190 lines
5.4 KiB
Rust
190 lines
5.4 KiB
Rust
unsafe extern "C" {
|
|
// unsafe fn parse_gpr(src: *mut Source, prefix: u8) -> (u64, u64);
|
|
// unsafe fn parse_reg(src: *mut Source) -> (u64, u64);
|
|
|
|
unsafe fn try_parse_reg(_: *const u8) -> (usize, Register);
|
|
unsafe fn try_parse_mem(_: *const u8, _: *mut Operand) -> (usize, *const Operand);
|
|
|
|
#[link_name = "buf"]
|
|
static mut BUF: [u8; 0x100];
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Debug, PartialEq, Eq)]
|
|
struct Register {
|
|
size: u32,
|
|
num: u32,
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Debug, PartialEq, Eq)]
|
|
struct Operand {
|
|
kind: u32,
|
|
size: u32,
|
|
reg: Register,
|
|
index: Register,
|
|
scale: u32,
|
|
disp: i32,
|
|
}
|
|
|
|
impl Register {
|
|
fn new(num: u32, size: u32) -> Self {
|
|
Self {
|
|
num,
|
|
size: size.ilog2(),
|
|
}
|
|
}
|
|
fn invalid() -> Self {
|
|
Self { num: !0, size: !0 }
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use core::mem::MaybeUninit;
|
|
|
|
fn write_to_buf(b: &[u8]) {
|
|
assert!(b.len() <= 0x100, "Buffer overflow");
|
|
unsafe {
|
|
core::ptr::copy_nonoverlapping(b.as_ptr(), (&raw mut BUF).cast(), b.len());
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn parse_mem() {
|
|
let mut op = MaybeUninit::<Operand>::uninit();
|
|
// let (n, _) =
|
|
// unsafe { try_parse_mem(b"qword [rax + rbx * 2 + 0x10]\0".as_ptr(), op.as_mut_ptr()) };
|
|
// assert_eq!(
|
|
// (n, unsafe { op.assume_init_ref() }),
|
|
// (
|
|
// 28,
|
|
// &Operand {
|
|
// kind: 2,
|
|
// size: 3,
|
|
// reg: Register::new(0, 8),
|
|
// index: Register::new(3, 8),
|
|
// scale: 2,
|
|
// disp: 0x10,
|
|
// }
|
|
// )
|
|
// );
|
|
|
|
let (n, _) =
|
|
unsafe { try_parse_mem(b"byte [r12 + r13 * 4 - 0x20]\0".as_ptr(), op.as_mut_ptr()) };
|
|
assert_eq!(
|
|
(n, unsafe { op.assume_init_ref() }),
|
|
(
|
|
27,
|
|
&Operand {
|
|
kind: 2,
|
|
size: 0,
|
|
reg: Register::new(12, 8),
|
|
index: Register::new(13, 8),
|
|
scale: 4,
|
|
disp: -0x20,
|
|
}
|
|
)
|
|
);
|
|
|
|
let (n, _) = unsafe { try_parse_mem(b"word [r8 * 8 + 5]\0".as_ptr(), op.as_mut_ptr()) };
|
|
assert_eq!(
|
|
(n, unsafe { op.assume_init_ref() }),
|
|
(
|
|
17,
|
|
&Operand {
|
|
kind: 2,
|
|
size: 1,
|
|
reg: Register::invalid(),
|
|
index: Register::new(8, 8),
|
|
scale: 8,
|
|
disp: 5,
|
|
}
|
|
)
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn parse_reg() {
|
|
let cases = [
|
|
(&b"rax"[..], (0, 8)),
|
|
(&b"rcx"[..], (1, 8)),
|
|
(&b"rdx"[..], (2, 8)),
|
|
(&b"rbx"[..], (3, 8)),
|
|
(&b"rsp"[..], (4, 8)),
|
|
(&b"rbp"[..], (5, 8)),
|
|
(&b"rsi"[..], (6, 8)),
|
|
(&b"rdi"[..], (7, 8)),
|
|
(&b"r8"[..], (8, 8)),
|
|
(&b"r9"[..], (9, 8)),
|
|
(&b"r10"[..], (10, 8)),
|
|
(&b"r11"[..], (11, 8)),
|
|
(&b"r12"[..], (12, 8)),
|
|
(&b"r13"[..], (13, 8)),
|
|
(&b"r14"[..], (14, 8)),
|
|
(&b"r15"[..], (15, 8)),
|
|
(&b"rip"[..], (!0, 8)),
|
|
(&b"eax"[..], (0, 4)),
|
|
(&b"ecx"[..], (1, 4)),
|
|
(&b"edx"[..], (2, 4)),
|
|
(&b"ebx"[..], (3, 4)),
|
|
(&b"esp"[..], (4, 4)),
|
|
(&b"ebp"[..], (5, 4)),
|
|
(&b"esi"[..], (6, 4)),
|
|
(&b"edi"[..], (7, 4)),
|
|
(&b"r8d"[..], (8, 4)),
|
|
(&b"r9d"[..], (9, 4)),
|
|
(&b"r10d"[..], (10, 4)),
|
|
(&b"r11d"[..], (11, 4)),
|
|
(&b"r12d"[..], (12, 4)),
|
|
(&b"r13d"[..], (13, 4)),
|
|
(&b"r14d"[..], (14, 4)),
|
|
(&b"r15d"[..], (15, 4)),
|
|
(&b"r8w"[..], (8, 2)),
|
|
(&b"r9w"[..], (9, 2)),
|
|
(&b"r10w"[..], (10, 2)),
|
|
(&b"r11w"[..], (11, 2)),
|
|
(&b"r12w"[..], (12, 2)),
|
|
(&b"r13w"[..], (13, 2)),
|
|
(&b"r14w"[..], (14, 2)),
|
|
(&b"r15w"[..], (15, 2)),
|
|
(&b"r8b"[..], (8, 1)),
|
|
(&b"r9b"[..], (9, 1)),
|
|
(&b"r10b"[..], (10, 1)),
|
|
(&b"r11b"[..], (11, 1)),
|
|
(&b"r12b"[..], (12, 1)),
|
|
(&b"r13b"[..], (13, 1)),
|
|
(&b"r14b"[..], (14, 1)),
|
|
(&b"r15b"[..], (15, 1)),
|
|
(&b"ax"[..], (0, 2)),
|
|
(&b"cx"[..], (1, 2)),
|
|
(&b"dx"[..], (2, 2)),
|
|
(&b"bx"[..], (3, 2)),
|
|
(&b"sp"[..], (4, 2)),
|
|
(&b"bp"[..], (5, 2)),
|
|
(&b"si"[..], (6, 2)),
|
|
(&b"di"[..], (7, 2)),
|
|
(&b"al"[..], (0, 1)),
|
|
(&b"cl"[..], (1, 1)),
|
|
(&b"dl"[..], (2, 1)),
|
|
(&b"bl"[..], (3, 1)),
|
|
(&b"spl"[..], (4, 1)),
|
|
(&b"bpl"[..], (5, 1)),
|
|
(&b"sil"[..], (6, 1)),
|
|
(&b"dil"[..], (7, 1)),
|
|
];
|
|
|
|
for (text, (reg, size)) in cases {
|
|
let (n, result) = unsafe { try_parse_reg(text.as_ptr()) };
|
|
assert_eq!(
|
|
result,
|
|
Register::new(reg, size),
|
|
"Failed to parse '{}' n={n}",
|
|
std::str::from_utf8(text).unwrap()
|
|
);
|
|
}
|
|
}
|
|
}
|