use std::io::Write as _;
use std::path::PathBuf;
use std::sync::Once;
static INIT: Once = Once::new();
pub fn setup() {
INIT.call_once(|| {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("error"))
.format(|buf, record| writeln!(buf, "{}", record.args()))
.init();
});
}
pub fn test_data_path(rel: &str) -> String {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../test")
.join(rel)
.to_string_lossy()
.into_owned()
}
pub fn win32_maps_folder() -> String {
let mut s = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../maps/windows/x86")
.to_string_lossy()
.into_owned();
if !s.ends_with('/') {
s.push('/');
}
s
}
pub fn set_winver_maps(emu: &mut crate::emu::Emu, version: &str) -> bool {
if let Err(e) = emu.set_maps_from_winver(version) {
eprintln!("skipping: --winver {} unavailable ({})", version, e);
return false;
}
let nls = std::path::Path::new(&emu.cfg.maps_folder).join("locale.nls");
if !nls.is_file() {
eprintln!(
"skipping: --winver {} has no NLS tables (seed them once from --iso)",
version
);
return false;
}
true
}
pub fn win64_maps_folder() -> String {
let mut s = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("../../maps/windows/x86_64")
.to_string_lossy()
.into_owned();
if !s.ends_with('/') {
s.push('/');
}
s
}
pub fn critical_values(bits: u32) -> Vec<u64> {
let max = match bits {
8 => u8::MAX as u64,
16 => u16::MAX as u64,
32 => u32::MAX as u64,
64 => u64::MAX,
_ => panic!("Unsupported size"),
};
let sign_bit = 1u64 << (bits - 1);
vec![
0,
1,
max,
sign_bit,
sign_bit - 1,
sign_bit + 1,
0x55, 0xAA, 0xFFFFFFFFFFFFFFFFu64 >> (64 - bits), ]
}
pub fn shift_counts(bits: u32) -> Vec<u64> {
vec![
0,
1,
bits as u64 - 1,
bits as u64,
bits as u64 + 1,
63,
64,
127,
]
}
use crate::emu::Emu;
use crate::maps::mem64::Permission;
fn ensure_stack(emu: &mut Emu) {
let sp = if emu.cfg.arch.is_64bits() {
emu.regs().rsp
} else {
emu.regs().get_esp()
};
if emu.maps.is_mapped(sp) && emu.maps.is_mapped(sp.wrapping_sub(0x1000)) {
return;
}
let sz = 0x40000u64;
let base = emu.maps.alloc(sz).expect("cannot reserve test stack");
emu.maps
.create_map("teststack", base, sz, Permission::READ_WRITE)
.expect("cannot create test stack");
let sp = base + sz / 2;
if emu.cfg.arch.is_64bits() {
emu.regs_mut().rsp = sp;
} else {
emu.regs_mut().set_esp(sp);
}
}
pub fn call_winapi64(emu: &mut Emu, func: fn(&mut Emu), args: &[u64]) -> u64 {
ensure_stack(emu);
let reg_setters: [fn(&mut Emu, u64); 4] = [
|e, v| e.regs_mut().rcx = v,
|e, v| e.regs_mut().rdx = v,
|e, v| e.regs_mut().r8 = v,
|e, v| e.regs_mut().r9 = v,
];
for (i, &a) in args.iter().take(4).enumerate() {
reg_setters[i](emu, a);
}
let rsp = emu.regs().rsp;
for (i, &a) in args.iter().enumerate().skip(4) {
let slot = rsp + 0x20 + ((i - 4) as u64) * 8;
emu.maps.write_qword(slot, a);
}
func(emu);
emu.regs().rax
}
pub fn call_winapi32(emu: &mut Emu, func: fn(&mut Emu), args: &[u32]) -> u32 {
ensure_stack(emu);
for &a in args.iter().rev() {
emu.stack_push32(a);
}
func(emu);
emu.regs().get_eax() as u32
}