mod common;
use std::path::PathBuf;
use ud_emulator::{Sandbox, DLL_PROCESS_ATTACH};
fn workspace_root() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.ancestors()
.find(|p| p.join("Cargo.toml").is_file() && p.join("crates").is_dir())
.map(std::path::Path::to_path_buf)
.unwrap()
}
fn fourcc(s: &str) -> u32 {
let mut b = [b' '; 4];
for (i, c) in s.bytes().take(4).enumerate() {
b[i] = c;
}
u32::from_le_bytes(b)
}
const ICMODE_DECOMPRESS: u32 = 1;
fn trace_codec(name: &str, base_url: &str, fcc: &str) {
let bytes = match common::fetch_or_load(base_url, name) {
Ok(b) => b,
Err(e) => {
eprintln!("skip {name}: {e}");
return;
}
};
let mut sb = Sandbox::new();
sb.host.trace_stubs = true;
sb.host.instruction_budget = Some(50_000_000);
sb.cpu.trace_ring_cap = 32;
let img = sb.load(name, &bytes).expect("load");
sb.call_dll_main(&img, DLL_PROCESS_ATTACH).expect("DllMain");
sb.install_codec(&img).expect("install_codec");
println!(
"=== {name} DllMain ({} calls) ===",
sb.host.stub_calls.len()
);
for (i, c) in sb.host.stub_calls.iter().enumerate() {
let args: Vec<String> = c.args.iter().map(|a| format!("{a:#x}")).collect();
println!(
" {i:3}: {}!{}({}) -> {:#x} @ {:#010x}",
c.dll,
c.name,
args.join(", "),
c.ret,
c.call_site_eip,
);
}
let dllmain_calls = sb.host.stub_calls.len();
sb.host.stub_calls.clear();
let fcc_type = fourcc("VIDC");
let fcc_handler = fourcc(fcc);
let result = sb.ic_open(fcc_type, fcc_handler, ICMODE_DECOMPRESS);
println!(
"ICOpen(VIDC, {fcc}, DECOMPRESS) -> {:?}",
result.as_ref().map(|h| format!("HIC {h}")),
);
if result.is_err() {
println!("Last 32 instruction EIPs before trap:");
for eip in &sb.cpu.trace_ring {
println!(" {eip:#010x}");
}
}
println!("DRV_OPEN-phase calls (DllMain pre-cleared, was {dllmain_calls}):");
for (i, c) in sb.host.stub_calls.iter().enumerate() {
let args: Vec<String> = c.args.iter().map(|a| format!("{a:#x}")).collect();
println!(
" {i:3}: {}!{}({}) -> {:#x} @ {:#010x}",
c.dll,
c.name,
args.join(", "),
c.ret,
c.call_site_eip,
);
}
println!();
}
#[test]
#[ignore = "diagnostic helper; downloads codecs; run on demand"]
fn lagarith_icopen_trace() {
let _ = workspace_root();
trace_codec(
"lagarith-i386.dll",
"https://samples.oxideav.org/codecs/windows/lagarith",
"LAGS",
);
}
#[test]
#[ignore = "diagnostic helper; downloads codecs; run on demand"]
fn magicyuv_icopen_trace() {
let _ = workspace_root();
trace_codec(
"magicyuv-i386.dll",
"https://samples.oxideav.org/codecs/windows/magicyuv",
"M8RG",
);
}