From c8eea0bcb336b5b368081352f01fe004fa7a269c Mon Sep 17 00:00:00 2001 From: mio Date: Sat, 16 Oct 2021 21:21:12 +0200 Subject: [PATCH] Fix build.rs and tests --- bindings/rust/build.rs | 114 ++++++++++++++++++++++++++++----- bindings/rust/tests/unicorn.rs | 14 ++-- 2 files changed, 109 insertions(+), 19 deletions(-) diff --git a/bindings/rust/build.rs b/bindings/rust/build.rs index 7df3e61c..a122faab 100644 --- a/bindings/rust/build.rs +++ b/bindings/rust/build.rs @@ -1,20 +1,104 @@ +use std::result::Result; use std::{env, process::Command}; -use build_helper::rustc::{link_lib, link_search}; - fn main() { - println!("cargo:rerun-if-changed=unicorn"); let out_dir = env::var("OUT_DIR").unwrap(); - let unicorn = "libunicorn.a"; - let _ = Command::new("cp") - .current_dir("../..") - .arg(&unicorn) - .arg(&out_dir) - .status() - .unwrap(); - link_search( - Some(build_helper::SearchKind::Native), - build_helper::out_dir(), - ); - link_lib(Some(build_helper::LibKind::Static), "unicorn"); + let profile = env::var("PROFILE").unwrap(); + let mut version = String::from("dev"); + if let Result::Ok(version_env) = env::var("UNICORN_VERISON") { + version = version_env; + } + + let unicorn_dir = format!("{}/unicorn_git", out_dir); + + Command::new("rm").arg("-rf").arg(&unicorn_dir); + + Command::new("git") + .arg("clone") + .arg("git@github.com:unicorn-engine/unicorn.git") + .arg("-b") + .arg(version) + .arg(&unicorn_dir) + .output() + .expect("Fail to clone Unicorn repository."); + + println!("cargo:rerun-if-changed={}", &unicorn_dir); + + // We don't use TARGET since we can't cross-build. + if env::consts::OS == "windows" { + // Windows + let mut platform = "x64"; + let mut conf = "Release"; + if std::mem::size_of::() == 4 { + platform = "Win32"; + } + if profile == "debug" { + conf = "Debug"; + } + + Command::new("msbuild") + .current_dir(format!("{}/msvc", &unicorn_dir)) + .arg("unicorn.sln") + .arg("-m") + .arg("-p:Platform".to_owned() + platform) + .arg("-p:Configuration".to_owned() + conf) + .output() + .expect("Fail to build unicorn on Win32."); + println!( + "cargo:rustc-link-lib=static={}/msvc/{}/{}/unicorn.lib", + unicorn_dir, platform, conf + ); + } else { + // Most Unix-like systems + let mut cmd = Command::new("cmake"); + cmd.current_dir(&unicorn_dir) + .arg("-B") + .arg("rust_build") + .arg("-DUNICORN_BUILD_SHARED=off"); + + if profile == "debug" { + cmd.arg("-DCMAKE_BUILD_TYPE=Debug"); + } else { + cmd.arg("-DCMAKE_BUILD_TYPE=Release"); + } + + cmd.output() + .expect("Fail to create build directory on *nix."); + + Command::new("make") + .current_dir(format!("{}/rust_build", &unicorn_dir)) + .arg("-j6") + .output() + .expect("Fail to build unicorn on *nix."); + // This is a workaround for Unicorn static link since libunicorn.a is also linked again lib*-softmmu.a. + // Static libs is just a bundle of objects files. The link relation defined in CMakeLists is only + // valid within the cmake project scope and cmake would help link again sub static libs automatically. + // + // Why do I stick to static link? See: https://github.com/rust-lang/cargo/issues/5077 + println!("cargo:rustc-link-lib=unicorn"); + for arch in [ + "x86_64", + "arm", + "armeb", + "aarch64", + "aarch64eb", + "riscv32", + "riscv64", + "mips", + "mipsel", + "mips64", + "mips64el", + "sparc", + "sparc64", + "m68k", + "ppc", + "ppc64", + ] + .iter() + { + println!("cargo:rustc-link-lib={}-softmmu", arch); + } + println!("cargo:rustc-link-lib=unicorn-common"); + println!("cargo:rustc-link-search={}/rust_build", unicorn_dir); + } } diff --git a/bindings/rust/tests/unicorn.rs b/bindings/rust/tests/unicorn.rs index a46cfa89..81c81ad4 100644 --- a/bindings/rust/tests/unicorn.rs +++ b/bindings/rust/tests/unicorn.rs @@ -256,9 +256,15 @@ fn x86_mem_callback() { let callback_mems = mems_cell.clone(); let callback = - move |_: Unicorn<'_>, mem_type: MemType, address: u64, size: usize, value: i64| { + move |uc: Unicorn<'_>, mem_type: MemType, address: u64, size: usize, value: i64| { let mut mems = callback_mems.borrow_mut(); + let mut uc = uc; + mems.push(MemExpectation(mem_type, address, size, value)); + + if mem_type == MemType::READ_UNMAPPED { + uc.mem_map(address, 0x1000, Permission::ALL).unwrap(); + } }; // mov eax, 0xdeadbeef; @@ -285,7 +291,7 @@ fn x86_mem_callback() { 10 * SECOND_SCALE, 0x1000 ), - Err(uc_error::READ_UNMAPPED) + Ok(()) ); assert_eq!(expects, *mems_cell.borrow()); @@ -479,7 +485,7 @@ fn emulate_mips() { fn emulate_ppc() { let ppc_code32 = vec![0x7F, 0x46, 0x1A, 0x14]; // add 26, 6, 3 - let mut unicorn = unicorn::Unicorn::new(Arch::PPC, Mode::PPC32) + let mut unicorn = unicorn::Unicorn::new(Arch::PPC, Mode::PPC32 | Mode::BIG_ENDIAN) .expect("failed to initialize unicorn instance"); let mut emu = unicorn.borrow(); assert_eq!(emu.mem_map(0x1000, 0x4000, Permission::ALL), Ok(())); @@ -631,7 +637,7 @@ fn x86_context_save_and_restore() { fn x86_block_callback() { #[derive(PartialEq, Debug)] struct BlockExpectation(u64, u32); - let expects = vec![BlockExpectation(0x1000, 2), BlockExpectation(0x1000, 2)]; + let expects = vec![BlockExpectation(0x1000, 2)]; let blocks: Vec = Vec::new(); let blocks_cell = Rc::new(RefCell::new(blocks));