#[cfg(test)]
pub mod tests {
use crate::tests::util::local_debug2;
use wdext::{data::RegisterIndex, error::WdErrorKind, *};
mod util;
macro_rules! assert_invalid_reg {
($e:expr) => {
assert_eq!($e.unwrap_err().kind(), WdErrorKind::RegisterNotFound)
};
}
fn assert_read_reg(ctx: &TargetContext, name: &str) {
let reg_view = ctx.register_view();
let idx = reg_view.get_index_by_name(name).unwrap();
let name2 = reg_view.get_name_by_index(idx).unwrap();
assert_eq!(name, name2);
macro_rules! assert_read {
($ty:ty) => {{
let a = reg_view
.read_value::<$ty>(name)
.expect("RegisterSelector::Name failed");
let b = reg_view
.read_value::<$ty>(idx)
.expect("RegisterSelector::Index failed");
assert_eq!(a, b);
}};
}
assert_read!(u8);
assert_read!(i8);
assert_read!(u16);
assert_read!(i16);
assert_read!(u32);
assert_read!(i32);
assert_read!(u64);
assert_read!(i64);
assert_read!(f32);
assert_read!(f64);
assert_read!([u8; 10]);
assert_read!([u8; 8]);
assert_read!([u16; 4]);
assert_read!([u32; 2]);
assert_read!([u64; 1]);
assert_read!([u8; 16]);
assert_read!([u16; 8]);
assert_read!([u32; 4]);
assert_read!([u64; 2]);
assert_read!([f32; 2]);
assert_read!([f64; 1]);
assert_read!([f32; 4]);
assert_read!([f64; 2]);
}
fn assert_write_regs(
ctx: &TargetContext,
name: &str,
width: usize,
is_float: bool,
) {
let reg_view = ctx.register_view();
let idx = reg_view.get_index_by_name(name).unwrap();
macro_rules! assert_write {
($name:expr, $idx:expr, $t:ty, $v1:expr, $v2:expr) => {{
reg_view
.write_value($name, $v1)
.expect("write1 RegisterSelector::Name failed");
let a: $t = reg_view.read_value($idx).expect("read1 failed");
assert_eq!(a, $v1);
reg_view
.write_value($idx, $v2)
.expect("write2 RegisterSelector::Index failed");
let a: $t = reg_view.read_value($idx).expect("read2 failed ");
assert_eq!(a, $v2);
}};
(
$name:expr,
$idx:expr,
$t:ty,
$v1:expr,
$v1_2:expr,
$v2:expr,
$v2_2:expr
) => {{
reg_view
.write_value($name, $v1)
.expect("write1 RegisterSelector::Name failed");
let a: $t = reg_view.read_value($idx).expect("read1 failed");
assert_eq!(a, $v1_2);
reg_view
.write_value($idx, $v2)
.expect("write2 RegisterSelector::Index failed");
let a: $t = reg_view.read_value($idx).expect("read2 failed ");
assert_eq!(a, $v2_2);
}};
}
macro_rules! assert_invalid_write {
($name:expr, $idx:expr, $t:ty, $v1:expr, $v2:expr) => {{
assert_eq!(
reg_view.write_value($name, $v1).unwrap_err().kind(),
WdErrorKind::InvalidArgument
);
let a: $t = reg_view.read_value($idx).expect("read1 failed");
assert_eq!(a, $v2);
assert_eq!(
reg_view.write_value($idx, $v1).unwrap_err().kind(),
WdErrorKind::InvalidArgument
);
let a: $t = reg_view.read_value($idx).expect("read2 failed ");
assert_eq!(a, $v2);
}};
}
#[rustfmt::skip]
{
assert_write!(name, idx, u8, u8::MAX, 0);
assert_write!(name, idx, i8, -1i8, 0);
if width >= 16 {
assert_write!(name, idx, u16, u16::MAX, 0);
assert_write!(name, idx, i16, -1i16, 0);
} else {
assert_invalid_write!(name, idx, u16, u16::MAX, 0);
assert_invalid_write!(name, idx, i16, -1i16, 0);
}
if width >= 32 {
assert_write!(name, idx, u32, u32::MAX, 0);
assert_write!(name, idx, i32, -1i32, 0);
} else {
assert_invalid_write!(name, idx, u32, u32::MAX, 0);
assert_invalid_write!(name, idx, i32, -1i32, 0);
}
if width >= 64 {
assert_write!(name, idx, u64, u64::MAX, 0);
assert_write!(name, idx, i64, -1i64, 0);
{
}
assert_write!(name, idx, [u8; 8], [u8::MAX; 8], [0u8; 8]);
assert_write!(name, idx, [u16; 4], [u16::MAX; 4], [0u16; 4]);
assert_write!(name, idx, [u32; 2], [u32::MAX; 2], [0u32; 2]);
assert_write!(name, idx, [u64; 1], [u64::MAX; 1], [0u64; 1]);
} else {
assert_invalid_write!(name, idx, u64, u64::MAX, 0);
assert_invalid_write!(name, idx, i64, -1i64, 0);
assert_invalid_write!(name, idx, [u8; 8], [u8::MAX; 8], [0u8; 8]);
assert_invalid_write!(name, idx, [u16; 4], [u16::MAX; 4], [0u16; 4]);
assert_invalid_write!(name, idx, [u32; 2], [u32::MAX; 2], [0u32; 2]);
assert_invalid_write!(name, idx, [u64; 1], [u64::MAX; 1], [0u64; 1]);
}
if width >= 128 {
assert_write!(name, idx, [u8; 16], [u8::MAX; 16], [0u8; 16]);
assert_write!(name, idx, [u16; 8], [u16::MAX; 8], [0u16; 8]);
assert_write!(name, idx, [u32; 4], [u32::MAX; 4], [0u32; 4]);
assert_write!(name, idx, [u64; 2], [u64::MAX; 2], [0u64; 2]);
if is_float {
assert_write!(name, idx, [f32; 2], [1.1f32; 2], [0.0f32; 2]);
} else {
assert_write!(name, idx, [f32; 2], [1.1f32; 2], [1.0f32; 2], [0.0f32; 2], [0.0f32; 2]);
}
}
if is_float {
assert_write!(name, idx, f32, 1.1f32, 0.0f32);
assert_write!(name, idx, f64, 1.1f64, 0.0f64);
} else {
assert_write!(name, idx, f32, 1.1f32, 1.0f32, 0.0f32, 0.0f32);
assert_write!(name, idx, f64, 1.1f64, 1.0f64, 0.0f64, 0.0f64);
}
};
}
#[test]
fn test_wd_registers() {
let ctx = local_debug2();
let reg = ctx.registers();
assert_invalid_reg!(reg.get_index_by_name("invalid"));
let invalid_index = RegisterIndex(u32::MAX);
assert_invalid_reg!(reg.get_name_by_index(invalid_index));
assert_invalid_reg!(reg.get_description(invalid_index));
#[cfg(target_arch = "x86_64")]
assert_read_reg(&ctx, "rax");
assert_read_reg(&ctx, "eax");
assert_read_reg(&ctx, "ax");
assert_read_reg(&ctx, "ah");
assert_read_reg(&ctx, "al");
assert_read_reg(&ctx, "xmm0");
#[cfg(target_arch = "x86_64")]
assert_write_regs(&ctx, "rax", 64, false);
#[cfg(target_arch = "x86_64")]
assert_write_regs(&ctx, "eax", 32, false);
assert_write_regs(&ctx, "ax", 16, false);
assert_write_regs(&ctx, "ah", 8, false);
assert_write_regs(&ctx, "al", 8, false);
assert_write_regs(&ctx, "xmm0", 128, true);
}
}