summaryrefslogtreecommitdiff
path: root/rust
diff options
context:
space:
mode:
authorRubens Brandao <git@rubens.io>2023-11-18 15:58:33 -0300
committerKyle Martin <krm504@nyu.edu>2023-11-21 15:18:50 -0500
commit8c9cdd38c3302280087c9e6d94f7f57083885edd (patch)
tree8bccf380b4470e0de8ac11c23b164e0acf6ffbb0 /rust
parentb040fcfce48db861600eeb122cd0e2ff802fac96 (diff)
add mlil to rust
Diffstat (limited to 'rust')
-rw-r--r--rust/Cargo.lock14
-rw-r--r--rust/Cargo.toml2
-rw-r--r--rust/examples/mlil_lifter/Cargo.lock355
-rw-r--r--rust/examples/mlil_lifter/Cargo.toml16
-rw-r--r--rust/examples/mlil_lifter/build.rs68
-rw-r--r--rust/examples/mlil_lifter/src/main.rs52
-rw-r--r--rust/examples/mlil_visitor/Cargo.lock355
-rw-r--r--rust/examples/mlil_visitor/Cargo.toml16
-rw-r--r--rust/examples/mlil_visitor/build.rs68
-rw-r--r--rust/examples/mlil_visitor/src/main.rs267
-rw-r--r--rust/src/function.rs23
-rw-r--r--rust/src/interaction.rs2
-rw-r--r--rust/src/lib.rs1
-rw-r--r--rust/src/mlil/block.rs63
-rw-r--r--rust/src/mlil/function.rs116
-rw-r--r--rust/src/mlil/instruction.rs812
-rw-r--r--rust/src/mlil/lift.rs139
-rw-r--r--rust/src/mlil/mod.rs10
-rw-r--r--rust/src/mlil/operation.rs2170
-rw-r--r--rust/src/types.rs16
20 files changed, 4562 insertions, 3 deletions
diff --git a/rust/Cargo.lock b/rust/Cargo.lock
index fb490c25..42f4ed81 100644
--- a/rust/Cargo.lock
+++ b/rust/Cargo.lock
@@ -652,6 +652,20 @@ dependencies = [
]
[[package]]
+name = "mlil_lifter"
+version = "0.1.0"
+dependencies = [
+ "binaryninja",
+]
+
+[[package]]
+name = "mlil_visitor"
+version = "0.1.0"
+dependencies = [
+ "binaryninja",
+]
+
+[[package]]
name = "nom"
version = "7.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/rust/Cargo.toml b/rust/Cargo.toml
index 5bd61635..9ab2413a 100644
--- a/rust/Cargo.toml
+++ b/rust/Cargo.toml
@@ -24,5 +24,7 @@ members = [
"examples/dwarf/shared",
"examples/flowgraph",
"examples/minidump",
+ "examples/mlil_visitor",
+ "examples/mlil_lifter",
"examples/template"
]
diff --git a/rust/examples/mlil_lifter/Cargo.lock b/rust/examples/mlil_lifter/Cargo.lock
new file mode 100644
index 00000000..57f01d55
--- /dev/null
+++ b/rust/examples/mlil_lifter/Cargo.lock
@@ -0,0 +1,355 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "aho-corasick"
+version = "0.7.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "ansi_term"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "binaryninja"
+version = "0.1.0"
+source = "git+https://github.com/Vector35/binaryninja-api.git?branch=dev#83d7a7800ac4a970d618ad125cdbb18e3b29b53e"
+dependencies = [
+ "binaryninjacore-sys",
+ "libc",
+ "log",
+]
+
+[[package]]
+name = "binaryninjacore-sys"
+version = "0.1.0"
+source = "git+https://github.com/Vector35/binaryninja-api.git?branch=dev#83d7a7800ac4a970d618ad125cdbb18e3b29b53e"
+dependencies = [
+ "bindgen",
+]
+
+[[package]]
+name = "bindgen"
+version = "0.58.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f8523b410d7187a43085e7e064416ea32ded16bd0a4e6fc025e21616d01258f"
+dependencies = [
+ "bitflags",
+ "cexpr",
+ "clang-sys",
+ "clap",
+ "env_logger",
+ "lazy_static",
+ "lazycell",
+ "log",
+ "peeking_take_while",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "rustc-hash",
+ "shlex",
+ "which",
+]
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "cexpr"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27"
+dependencies = [
+ "nom",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "clang-sys"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa66045b9cb23c2e9c1520732030608b02ee07e5cfaa5a521ec15ded7fa24c90"
+dependencies = [
+ "glob",
+ "libc",
+ "libloading",
+]
+
+[[package]]
+name = "clap"
+version = "2.34.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
+dependencies = [
+ "ansi_term",
+ "atty",
+ "bitflags",
+ "strsim",
+ "textwrap",
+ "unicode-width",
+ "vec_map",
+]
+
+[[package]]
+name = "env_logger"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3"
+dependencies = [
+ "atty",
+ "humantime",
+ "log",
+ "regex",
+ "termcolor",
+]
+
+[[package]]
+name = "glob"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "humantime"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "lazycell"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
+
+[[package]]
+name = "libc"
+version = "0.2.117"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e74d72e0f9b65b5b4ca49a346af3976df0f9c61d550727f349ecd559f251a26c"
+
+[[package]]
+name = "libloading"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
+dependencies = [
+ "cfg-if",
+ "winapi",
+]
+
+[[package]]
+name = "log"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "memchr"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+
+[[package]]
+name = "nom"
+version = "5.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
+dependencies = [
+ "memchr",
+ "version_check",
+]
+
+[[package]]
+name = "peeking_take_while"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "regex"
+version = "1.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
+
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
+[[package]]
+name = "shlex"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
+
+[[package]]
+name = "strsim"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
+
+[[package]]
+name = "template"
+version = "0.1.0"
+dependencies = [
+ "binaryninja",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
+dependencies = [
+ "unicode-width",
+]
+
+[[package]]
+name = "unicode-width"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
+
+[[package]]
+name = "vec_map"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
+
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
+[[package]]
+name = "which"
+version = "3.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/rust/examples/mlil_lifter/Cargo.toml b/rust/examples/mlil_lifter/Cargo.toml
new file mode 100644
index 00000000..4ea158fc
--- /dev/null
+++ b/rust/examples/mlil_lifter/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+name = "mlil_lifter"
+version = "0.1.0"
+edition = "2021"
+
+# Uncomment this if you're writing a plugin (plugins are shared objects loaded by the core):
+# [lib]
+# crate-type = ["cdylib"]
+
+# You can point at the BinaryNinja dependency in one of two ways, via path:
+[dependencies]
+binaryninja = {path="../../"}
+
+# Or directly at the git repo:
+# [dependencies]
+# binaryninja = {git = "https://github.com/Vector35/binaryninja-api.git", branch = "dev"}
diff --git a/rust/examples/mlil_lifter/build.rs b/rust/examples/mlil_lifter/build.rs
new file mode 100644
index 00000000..5ba9bcde
--- /dev/null
+++ b/rust/examples/mlil_lifter/build.rs
@@ -0,0 +1,68 @@
+use std::env;
+use std::fs::File;
+use std::io::BufReader;
+use std::path::PathBuf;
+
+#[cfg(target_os = "macos")]
+static LASTRUN_PATH: (&str, &str) = ("HOME", "Library/Application Support/Binary Ninja/lastrun");
+
+#[cfg(target_os = "linux")]
+static LASTRUN_PATH: (&str, &str) = ("HOME", ".binaryninja/lastrun");
+
+#[cfg(windows)]
+static LASTRUN_PATH: (&str, &str) = ("APPDATA", "Binary Ninja\\lastrun");
+
+// Check last run location for path to BinaryNinja; Otherwise check the default install locations
+fn link_path() -> PathBuf {
+ use std::io::prelude::*;
+
+ let home = PathBuf::from(env::var(LASTRUN_PATH.0).unwrap());
+ let lastrun = PathBuf::from(&home).join(LASTRUN_PATH.1);
+
+ File::open(lastrun)
+ .and_then(|f| {
+ let mut binja_path = String::new();
+ let mut reader = BufReader::new(f);
+
+ reader.read_line(&mut binja_path)?;
+ Ok(PathBuf::from(binja_path.trim()))
+ })
+ .unwrap_or_else(|_| {
+ #[cfg(target_os = "macos")]
+ return PathBuf::from("/Applications/Binary Ninja.app/Contents/MacOS");
+
+ #[cfg(target_os = "linux")]
+ return home.join("binaryninja");
+
+ #[cfg(windows)]
+ return PathBuf::from(env::var("PROGRAMFILES").unwrap())
+ .join("Vector35\\BinaryNinja\\");
+ })
+}
+
+fn main() {
+ // Use BINARYNINJADIR first for custom BN builds/configurations (BN devs/build server), fallback on defaults
+ let install_path = env::var("BINARYNINJADIR")
+ .map(PathBuf::from)
+ .unwrap_or_else(|_| link_path());
+
+ #[cfg(target_os = "linux")]
+ println!(
+ "cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-l:libbinaryninjacore.so.1",
+ install_path.to_str().unwrap(),
+ install_path.to_str().unwrap(),
+ );
+
+ #[cfg(target_os = "macos")]
+ println!(
+ "cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-lbinaryninjacore",
+ install_path.to_str().unwrap(),
+ install_path.to_str().unwrap(),
+ );
+
+ #[cfg(target_os = "windows")]
+ {
+ println!("cargo:rustc-link-lib=binaryninjacore");
+ println!("cargo:rustc-link-search={}", install_path.to_str().unwrap());
+ }
+}
diff --git a/rust/examples/mlil_lifter/src/main.rs b/rust/examples/mlil_lifter/src/main.rs
new file mode 100644
index 00000000..3ba25630
--- /dev/null
+++ b/rust/examples/mlil_lifter/src/main.rs
@@ -0,0 +1,52 @@
+use std::env;
+
+use binaryninja::binaryview::BinaryViewExt;
+
+// Standalone executables need to provide a main function for rustc
+// Plugins should refer to `binaryninja::command::*` for the various registration callbacks.
+fn main() {
+ let mut args = env::args();
+ let _ = args.next().unwrap();
+ let Some(filename) = args.next() else {
+ panic!("Expected input filename\n");
+ };
+
+ // This loads all the core architecture, platform, etc plugins
+ // Standalone executables probably need to call this, but plugins do not
+ println!("Loading plugins...");
+ binaryninja::headless::init();
+
+ // Your code here...
+ println!("Loading binary...");
+ let bv = binaryninja::load(filename).expect("Couldn't open binary file");
+
+ // Go through all functions in the binary
+ for func in bv.functions().iter() {
+ let sym = func.symbol();
+ println!("Function {}:", sym.full_name());
+
+ let Ok(il) = func.medium_level_il() else {
+ println!(" Does not have MLIL\n");
+ continue;
+ };
+ // Get the SSA form for this function
+ let il = il.ssa_form();
+
+ // Loop through all blocks in the function
+ for block in il.basic_blocks().iter() {
+ // Loop though each instruction in the block
+ for instr in block.iter() {
+ // Uplift the instruction into a native rust format
+ let lifted = instr.lift();
+ let address = instr.address();
+
+ // print the lifted instruction
+ println!("{address:08x}: {lifted:x?}");
+ }
+ }
+ println!();
+ }
+
+ // Important! Standalone executables need to call shutdown or they will hang forever
+ binaryninja::headless::shutdown();
+}
diff --git a/rust/examples/mlil_visitor/Cargo.lock b/rust/examples/mlil_visitor/Cargo.lock
new file mode 100644
index 00000000..57f01d55
--- /dev/null
+++ b/rust/examples/mlil_visitor/Cargo.lock
@@ -0,0 +1,355 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "aho-corasick"
+version = "0.7.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "ansi_term"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "binaryninja"
+version = "0.1.0"
+source = "git+https://github.com/Vector35/binaryninja-api.git?branch=dev#83d7a7800ac4a970d618ad125cdbb18e3b29b53e"
+dependencies = [
+ "binaryninjacore-sys",
+ "libc",
+ "log",
+]
+
+[[package]]
+name = "binaryninjacore-sys"
+version = "0.1.0"
+source = "git+https://github.com/Vector35/binaryninja-api.git?branch=dev#83d7a7800ac4a970d618ad125cdbb18e3b29b53e"
+dependencies = [
+ "bindgen",
+]
+
+[[package]]
+name = "bindgen"
+version = "0.58.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f8523b410d7187a43085e7e064416ea32ded16bd0a4e6fc025e21616d01258f"
+dependencies = [
+ "bitflags",
+ "cexpr",
+ "clang-sys",
+ "clap",
+ "env_logger",
+ "lazy_static",
+ "lazycell",
+ "log",
+ "peeking_take_while",
+ "proc-macro2",
+ "quote",
+ "regex",
+ "rustc-hash",
+ "shlex",
+ "which",
+]
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "cexpr"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27"
+dependencies = [
+ "nom",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "clang-sys"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa66045b9cb23c2e9c1520732030608b02ee07e5cfaa5a521ec15ded7fa24c90"
+dependencies = [
+ "glob",
+ "libc",
+ "libloading",
+]
+
+[[package]]
+name = "clap"
+version = "2.34.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
+dependencies = [
+ "ansi_term",
+ "atty",
+ "bitflags",
+ "strsim",
+ "textwrap",
+ "unicode-width",
+ "vec_map",
+]
+
+[[package]]
+name = "env_logger"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3"
+dependencies = [
+ "atty",
+ "humantime",
+ "log",
+ "regex",
+ "termcolor",
+]
+
+[[package]]
+name = "glob"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "humantime"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "lazycell"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
+
+[[package]]
+name = "libc"
+version = "0.2.117"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e74d72e0f9b65b5b4ca49a346af3976df0f9c61d550727f349ecd559f251a26c"
+
+[[package]]
+name = "libloading"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
+dependencies = [
+ "cfg-if",
+ "winapi",
+]
+
+[[package]]
+name = "log"
+version = "0.4.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "memchr"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+
+[[package]]
+name = "nom"
+version = "5.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
+dependencies = [
+ "memchr",
+ "version_check",
+]
+
+[[package]]
+name = "peeking_take_while"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029"
+dependencies = [
+ "unicode-xid",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "regex"
+version = "1.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
+
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
+[[package]]
+name = "shlex"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
+
+[[package]]
+name = "strsim"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
+
+[[package]]
+name = "template"
+version = "0.1.0"
+dependencies = [
+ "binaryninja",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
+dependencies = [
+ "unicode-width",
+]
+
+[[package]]
+name = "unicode-width"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
+
+[[package]]
+name = "unicode-xid"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
+
+[[package]]
+name = "vec_map"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
+
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
+[[package]]
+name = "which"
+version = "3.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/rust/examples/mlil_visitor/Cargo.toml b/rust/examples/mlil_visitor/Cargo.toml
new file mode 100644
index 00000000..76ca1222
--- /dev/null
+++ b/rust/examples/mlil_visitor/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+name = "mlil_visitor"
+version = "0.1.0"
+edition = "2021"
+
+# Uncomment this if you're writing a plugin (plugins are shared objects loaded by the core):
+# [lib]
+# crate-type = ["cdylib"]
+
+# You can point at the BinaryNinja dependency in one of two ways, via path:
+[dependencies]
+binaryninja = {path="../../"}
+
+# Or directly at the git repo:
+# [dependencies]
+# binaryninja = {git = "https://github.com/Vector35/binaryninja-api.git", branch = "dev"}
diff --git a/rust/examples/mlil_visitor/build.rs b/rust/examples/mlil_visitor/build.rs
new file mode 100644
index 00000000..5ba9bcde
--- /dev/null
+++ b/rust/examples/mlil_visitor/build.rs
@@ -0,0 +1,68 @@
+use std::env;
+use std::fs::File;
+use std::io::BufReader;
+use std::path::PathBuf;
+
+#[cfg(target_os = "macos")]
+static LASTRUN_PATH: (&str, &str) = ("HOME", "Library/Application Support/Binary Ninja/lastrun");
+
+#[cfg(target_os = "linux")]
+static LASTRUN_PATH: (&str, &str) = ("HOME", ".binaryninja/lastrun");
+
+#[cfg(windows)]
+static LASTRUN_PATH: (&str, &str) = ("APPDATA", "Binary Ninja\\lastrun");
+
+// Check last run location for path to BinaryNinja; Otherwise check the default install locations
+fn link_path() -> PathBuf {
+ use std::io::prelude::*;
+
+ let home = PathBuf::from(env::var(LASTRUN_PATH.0).unwrap());
+ let lastrun = PathBuf::from(&home).join(LASTRUN_PATH.1);
+
+ File::open(lastrun)
+ .and_then(|f| {
+ let mut binja_path = String::new();
+ let mut reader = BufReader::new(f);
+
+ reader.read_line(&mut binja_path)?;
+ Ok(PathBuf::from(binja_path.trim()))
+ })
+ .unwrap_or_else(|_| {
+ #[cfg(target_os = "macos")]
+ return PathBuf::from("/Applications/Binary Ninja.app/Contents/MacOS");
+
+ #[cfg(target_os = "linux")]
+ return home.join("binaryninja");
+
+ #[cfg(windows)]
+ return PathBuf::from(env::var("PROGRAMFILES").unwrap())
+ .join("Vector35\\BinaryNinja\\");
+ })
+}
+
+fn main() {
+ // Use BINARYNINJADIR first for custom BN builds/configurations (BN devs/build server), fallback on defaults
+ let install_path = env::var("BINARYNINJADIR")
+ .map(PathBuf::from)
+ .unwrap_or_else(|_| link_path());
+
+ #[cfg(target_os = "linux")]
+ println!(
+ "cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-l:libbinaryninjacore.so.1",
+ install_path.to_str().unwrap(),
+ install_path.to_str().unwrap(),
+ );
+
+ #[cfg(target_os = "macos")]
+ println!(
+ "cargo:rustc-link-arg=-Wl,-rpath,{},-L{},-lbinaryninjacore",
+ install_path.to_str().unwrap(),
+ install_path.to_str().unwrap(),
+ );
+
+ #[cfg(target_os = "windows")]
+ {
+ println!("cargo:rustc-link-lib=binaryninjacore");
+ println!("cargo:rustc-link-search={}", install_path.to_str().unwrap());
+ }
+}
diff --git a/rust/examples/mlil_visitor/src/main.rs b/rust/examples/mlil_visitor/src/main.rs
new file mode 100644
index 00000000..3f75708c
--- /dev/null
+++ b/rust/examples/mlil_visitor/src/main.rs
@@ -0,0 +1,267 @@
+use std::env;
+
+use binaryninja::binaryview::BinaryViewExt;
+use binaryninja::mlil::operation::MediumLevelILOperand;
+use binaryninja::mlil::{MediumLevelILFunction, MediumLevelILInstruction, MediumLevelILOperation};
+use binaryninja::types::Variable;
+
+fn print_indent(indent: usize) {
+ print!("{:<indent$}", "")
+}
+
+fn print_operation(operation: &MediumLevelILOperation) {
+ use MediumLevelILOperation::*;
+ match operation {
+ Nop(_) => print!("Nop"),
+ Noret(_) => print!("Noret"),
+ Bp(_) => print!("Bp"),
+ Undef(_) => print!("Undef"),
+ Unimpl(_) => print!("Unimpl"),
+ If(_) => print!("If"),
+ FloatConst(_) => print!("FloatConst"),
+ Const(_) => print!("Const"),
+ ConstPtr(_) => print!("ConstPtr"),
+ Import(_) => print!("Import"),
+ ExternPtr(_) => print!("ExternPtr"),
+ ConstData(_) => print!("ConstData"),
+ Jump(_) => print!("Jump"),
+ RetHint(_) => print!("RetHint"),
+ StoreSsa(_) => print!("StoreSsa"),
+ StoreStructSsa(_) => print!("StoreStructSsa"),
+ StoreStruct(_) => print!("StoreStruct"),
+ Store(_) => print!("Store"),
+ JumpTo(_) => print!("JumpTo"),
+ Goto(_) => print!("Goto"),
+ FreeVarSlot(_) => print!("FreeVarSlot"),
+ SetVarField(_) => print!("SetVarField"),
+ SetVar(_) => print!("SetVar"),
+ FreeVarSlotSsa(_) => print!("FreeVarSlotSsa"),
+ SetVarSsaField(_) => print!("SetVarSsaField"),
+ SetVarAliasedField(_) => print!("SetVarAliasedField"),
+ SetVarAliased(_) => print!("SetVarAliased"),
+ SetVarSsa(_) => print!("SetVarSsa"),
+ VarPhi(_) => print!("VarPhi"),
+ MemPhi(_) => print!("MemPhi"),
+ VarSplit(_) => print!("VarSplit"),
+ SetVarSplit(_) => print!("SetVarSplit"),
+ VarSplitSsa(_) => print!("VarSplitSsa"),
+ SetVarSplitSsa(_) => print!("SetVarSplitSsa"),
+ Add(_) => print!("Add"),
+ Sub(_) => print!("Sub"),
+ And(_) => print!("And"),
+ Or(_) => print!("Or"),
+ Xor(_) => print!("Xor"),
+ Lsl(_) => print!("Lsl"),
+ Lsr(_) => print!("Lsr"),
+ Asr(_) => print!("Asr"),
+ Rol(_) => print!("Rol"),
+ Ror(_) => print!("Ror"),
+ Mul(_) => print!("Mul"),
+ MuluDp(_) => print!("MuluDp"),
+ MulsDp(_) => print!("MulsDp"),
+ Divu(_) => print!("Divu"),
+ DivuDp(_) => print!("DivuDp"),
+ Divs(_) => print!("Divs"),
+ DivsDp(_) => print!("DivsDp"),
+ Modu(_) => print!("Modu"),
+ ModuDp(_) => print!("ModuDp"),
+ Mods(_) => print!("Mods"),
+ ModsDp(_) => print!("ModsDp"),
+ CmpE(_) => print!("CmpE"),
+ CmpNe(_) => print!("CmpNe"),
+ CmpSlt(_) => print!("CmpSlt"),
+ CmpUlt(_) => print!("CmpUlt"),
+ CmpSle(_) => print!("CmpSle"),
+ CmpUle(_) => print!("CmpUle"),
+ CmpSge(_) => print!("CmpSge"),
+ CmpUge(_) => print!("CmpUge"),
+ CmpSgt(_) => print!("CmpSgt"),
+ CmpUgt(_) => print!("CmpUgt"),
+ TestBit(_) => print!("TestBit"),
+ AddOverflow(_) => print!("AddOverflow"),
+ FcmpE(_) => print!("FcmpE"),
+ FcmpNe(_) => print!("FcmpNe"),
+ FcmpLt(_) => print!("FcmpLt"),
+ FcmpLe(_) => print!("FcmpLe"),
+ FcmpGe(_) => print!("FcmpGe"),
+ FcmpGt(_) => print!("FcmpGt"),
+ FcmpO(_) => print!("FcmpO"),
+ FcmpUo(_) => print!("FcmpUo"),
+ Fadd(_) => print!("Fadd"),
+ Fsub(_) => print!("Fsub"),
+ Fmul(_) => print!("Fmul"),
+ Fdiv(_) => print!("Fdiv"),
+ Adc(_) => print!("Adc"),
+ Sbb(_) => print!("Sbb"),
+ Rlc(_) => print!("Rlc"),
+ Rrc(_) => print!("Rrc"),
+ Call(_) => print!("Call"),
+ Tailcall(_) => print!("Tailcall"),
+ Syscall(_) => print!("Syscall"),
+ Intrinsic(_) => print!("Intrinsic"),
+ IntrinsicSsa(_) => print!("IntrinsicSsa"),
+ CallSsa(_) => print!("CallSsa"),
+ TailcallSsa(_) => print!("TailcallSsa"),
+ CallUntypedSsa(_) => print!("CallUntypedSsa"),
+ TailcallUntypedSsa(_) => print!("TailcallUntypedSsa"),
+ SyscallSsa(_) => print!("SyscallSsa"),
+ SyscallUntypedSsa(_) => print!("SyscallUntypedSsa"),
+ CallUntyped(_) => print!("CallUntyped"),
+ TailcallUntyped(_) => print!("TailcallUntyped"),
+ SyscallUntyped(_) => print!("SyscallUntyped"),
+ Neg(_) => print!("Neg"),
+ Not(_) => print!("Not"),
+ Sx(_) => print!("Sx"),
+ Zx(_) => print!("Zx"),
+ LowPart(_) => print!("LowPart"),
+ BoolToInt(_) => print!("BoolToInt"),
+ UnimplMem(_) => print!("UnimplMem"),
+ Fsqrt(_) => print!("Fsqrt"),
+ Fneg(_) => print!("Fneg"),
+ Fabs(_) => print!("Fabs"),
+ FloatToInt(_) => print!("FloatToInt"),
+ IntToFloat(_) => print!("IntToFloat"),
+ FloatConv(_) => print!("FloatConv"),
+ RoundToInt(_) => print!("RoundToInt"),
+ Floor(_) => print!("Floor"),
+ Ceil(_) => print!("Ceil"),
+ Ftrunc(_) => print!("Ftrunc"),
+ Load(_) => print!("Load"),
+ LoadStruct(_) => print!("LoadStruct"),
+ LoadStructSsa(_) => print!("LoadStructSsa"),
+ LoadSsa(_) => print!("LoadSsa"),
+ Ret(_) => print!("Ret"),
+ Var(_) => print!("Var"),
+ AddressOf(_) => print!("AddressOf"),
+ VarField(_) => print!("VarField"),
+ AddressOfField(_) => print!("AddressOfField"),
+ VarSsa(_) => print!("VarSsa"),
+ VarAliased(_) => print!("VarAliased"),
+ VarSsaField(_) => print!("VarSsaField"),
+ VarAliasedField(_) => print!("VarAliasedField"),
+ Trap(_) => print!("Trap"),
+ }
+}
+
+fn print_variable(func: &MediumLevelILFunction, var: &Variable) {
+ print!("{}", func.get_function().get_variable_name(var));
+}
+
+fn print_il_expr(instr: &MediumLevelILInstruction, mut indent: usize) {
+ print_indent(indent);
+ print_operation(instr.operation());
+ println!("");
+
+ indent += 1;
+
+ use MediumLevelILOperand::*;
+ for (_name, operand) in instr.operands() {
+ match operand {
+ Int(int) => {
+ print_indent(indent);
+ println!("int 0x{:x}", int);
+ }
+ Float(float) => {
+ print_indent(indent);
+ println!("int {:e}", float);
+ }
+ Expr(expr) => print_il_expr(&expr, indent),
+ Var(var) => {
+ print_indent(indent);
+ print!("var ");
+ print_variable(instr.function(), &var);
+ println!();
+ }
+ VarSsa(var) => {
+ print_indent(indent);
+ print!("ssa var ");
+ print_variable(instr.function(), &var.variable);
+ println!("#{}", var.version);
+ }
+ IntList(list) => {
+ print_indent(indent);
+ print!("index list ");
+ for i in list {
+ print!("{i} ");
+ }
+ println!();
+ }
+ VarList(list) => {
+ print_indent(indent);
+ print!("var list ");
+ for i in list {
+ print_variable(instr.function(), &i);
+ print!(" ");
+ }
+ println!();
+ }
+ VarSsaList(list) => {
+ print_indent(indent);
+ print!("ssa var list ");
+ for i in list {
+ print_variable(instr.function(), &i.variable);
+ print!("#{} ", i.version);
+ }
+ println!();
+ }
+ ExprList(list) => {
+ print_indent(indent);
+ println!("expr list");
+ for i in list {
+ print_il_expr(&i, indent + 1);
+ }
+ }
+ TargetMap(list) => {
+ print_indent(indent);
+ print!("target map ");
+ for (i, f) in list {
+ print!("({i}, {f}) ");
+ }
+ println!();
+ }
+ }
+ }
+}
+
+// Standalone executables need to provide a main function for rustc
+// Plugins should refer to `binaryninja::command::*` for the various registration callbacks.
+fn main() {
+ let mut args = env::args();
+ let _ = args.next().unwrap();
+ let Some(filename) = args.next() else {
+ panic!("Expected input filename\n");
+ };
+
+ // This loads all the core architecture, platform, etc plugins
+ // Standalone executables probably need to call this, but plugins do not
+ println!("Loading plugins...");
+ binaryninja::headless::init();
+
+ // Your code here...
+ println!("Loading binary...");
+ let bv = binaryninja::load(filename).expect("Couldn't open binary file");
+
+ // Go through all functions in the binary
+ for func in bv.functions().iter() {
+ let sym = func.symbol();
+ println!("Function {}:", sym.full_name());
+
+ let Ok(il) = func.medium_level_il() else {
+ println!(" Does not have MLIL\n");
+ continue;
+ };
+
+ // Loop through all blocks in the function
+ for block in il.basic_blocks().iter() {
+ // Loop though each instruction in the block
+ for instr in block.iter() {
+ // Generically parse the IL tree and display the parts
+ print_il_expr(&instr, 2);
+ }
+ }
+ println!();
+ }
+
+ // Important! Standalone executables need to call shutdown or they will hang forever
+ binaryninja::headless::shutdown();
+}
diff --git a/rust/src/function.rs b/rust/src/function.rs
index ab504bb7..0a01f337 100644
--- a/rust/src/function.rs
+++ b/rust/src/function.rs
@@ -16,11 +16,12 @@ use binaryninjacore_sys::*;
use crate::rc::*;
use crate::string::*;
+use crate::types::Variable;
use crate::{
architecture::CoreArchitecture,
basicblock::{BasicBlock, BlockContext},
binaryview::{BinaryView, BinaryViewExt},
- llil,
+ llil, mlil,
platform::Platform,
symbol::Symbol,
types::{Conf, NamedTypedVariable, Type},
@@ -216,6 +217,26 @@ impl Function {
}
}
+ pub fn get_variable_name(&self, var: &Variable) -> BnString {
+ unsafe {
+ let raw_var = var.raw();
+ let raw_name = BNGetVariableName(self.handle, &raw_var);
+ BnString::from_raw(raw_name)
+ }
+ }
+
+ pub fn medium_level_il(&self) -> Result<Ref<mlil::MediumLevelILFunction>, ()> {
+ unsafe {
+ let mlil = BNGetFunctionMediumLevelIL(self.handle);
+
+ if mlil.is_null() {
+ return Err(());
+ }
+
+ Ok(Ref::new(mlil::MediumLevelILFunction::from_raw(mlil)))
+ }
+ }
+
pub fn low_level_il(&self) -> Result<Ref<llil::RegularFunction<CoreArchitecture>>, ()> {
unsafe {
let llil = BNGetFunctionLowLevelIL(self.handle);
diff --git a/rust/src/interaction.rs b/rust/src/interaction.rs
index f558a9ea..13785369 100644
--- a/rust/src/interaction.rs
+++ b/rust/src/interaction.rs
@@ -16,7 +16,7 @@
use binaryninjacore_sys::*;
-use std::os::raw::{c_void, c_char};
+use std::os::raw::{c_char, c_void};
use std::path::PathBuf;
use crate::binaryview::BinaryView;
diff --git a/rust/src/lib.rs b/rust/src/lib.rs
index 352ecef9..3eff5ea1 100644
--- a/rust/src/lib.rs
+++ b/rust/src/lib.rs
@@ -153,6 +153,7 @@ pub mod linearview;
pub mod llil;
pub mod logger;
pub mod metadata;
+pub mod mlil;
pub mod platform;
pub mod rc;
pub mod references;
diff --git a/rust/src/mlil/block.rs b/rust/src/mlil/block.rs
new file mode 100644
index 00000000..734d6512
--- /dev/null
+++ b/rust/src/mlil/block.rs
@@ -0,0 +1,63 @@
+use std::ops::Range;
+
+use binaryninjacore_sys::BNGetMediumLevelILIndexForInstruction;
+
+use crate::basicblock::{BasicBlock, BlockContext};
+use crate::rc::Ref;
+
+use super::{MediumLevelILFunction, MediumLevelILInstruction};
+
+pub struct MediumLevelILBlockIter {
+ function: Ref<MediumLevelILFunction>,
+ range: Range<u64>,
+}
+
+impl Iterator for MediumLevelILBlockIter {
+ type Item = MediumLevelILInstruction;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.range
+ .next()
+ .map(|i| unsafe {
+ BNGetMediumLevelILIndexForInstruction(self.function.handle, i as usize)
+ })
+ .map(|i| MediumLevelILInstruction::new(&self.function, i))
+ }
+}
+
+pub struct MediumLevelILBlock {
+ pub(crate) function: Ref<MediumLevelILFunction>,
+}
+
+impl core::fmt::Debug for MediumLevelILBlock {
+ fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+ write!(f, "mlil_bb {:?}", self.function)
+ }
+}
+
+impl BlockContext for MediumLevelILBlock {
+ type Iter = MediumLevelILBlockIter;
+ type Instruction = MediumLevelILInstruction;
+
+ fn start(&self, block: &BasicBlock<Self>) -> MediumLevelILInstruction {
+ let expr_idx = unsafe {
+ BNGetMediumLevelILIndexForInstruction(self.function.handle, block.raw_start() as usize)
+ };
+ MediumLevelILInstruction::new(&self.function, expr_idx)
+ }
+
+ fn iter(&self, block: &BasicBlock<Self>) -> MediumLevelILBlockIter {
+ MediumLevelILBlockIter {
+ function: self.function.to_owned(),
+ range: block.raw_start()..block.raw_end(),
+ }
+ }
+}
+
+impl Clone for MediumLevelILBlock {
+ fn clone(&self) -> Self {
+ MediumLevelILBlock {
+ function: self.function.to_owned(),
+ }
+ }
+}
diff --git a/rust/src/mlil/function.rs b/rust/src/mlil/function.rs
new file mode 100644
index 00000000..63c63a34
--- /dev/null
+++ b/rust/src/mlil/function.rs
@@ -0,0 +1,116 @@
+use core::hash::{Hash, Hasher};
+
+use binaryninjacore_sys::BNFreeMediumLevelILFunction;
+use binaryninjacore_sys::BNGetMediumLevelILBasicBlockList;
+use binaryninjacore_sys::BNGetMediumLevelILInstructionCount;
+use binaryninjacore_sys::BNGetMediumLevelILOwnerFunction;
+use binaryninjacore_sys::BNGetMediumLevelILSSAForm;
+use binaryninjacore_sys::BNMediumLevelILFunction;
+use binaryninjacore_sys::BNMediumLevelILGetInstructionStart;
+use binaryninjacore_sys::BNNewMediumLevelILFunctionReference;
+
+use crate::basicblock::BasicBlock;
+use crate::function::Function;
+use crate::function::Location;
+use crate::rc::{Array, Ref, RefCountable};
+
+use super::{MediumLevelILBlock, MediumLevelILInstruction};
+
+pub struct MediumLevelILFunction {
+ pub(crate) handle: *mut BNMediumLevelILFunction,
+}
+
+unsafe impl Send for MediumLevelILFunction {}
+unsafe impl Sync for MediumLevelILFunction {}
+
+impl Eq for MediumLevelILFunction {}
+impl PartialEq for MediumLevelILFunction {
+ fn eq(&self, rhs: &Self) -> bool {
+ self.handle == rhs.handle
+ }
+}
+
+impl Hash for MediumLevelILFunction {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.handle.hash(state);
+ }
+}
+
+impl MediumLevelILFunction {
+ pub(crate) unsafe fn from_raw(handle: *mut BNMediumLevelILFunction) -> Self {
+ debug_assert!(!handle.is_null());
+
+ Self { handle }
+ }
+
+ pub fn instruction_at<L: Into<Location>>(&self, loc: L) -> Option<MediumLevelILInstruction> {
+ let loc: Location = loc.into();
+ let arch_handle = loc.arch.unwrap();
+
+ let expr_idx =
+ unsafe { BNMediumLevelILGetInstructionStart(self.handle, arch_handle.0, loc.addr) };
+
+ if expr_idx >= self.instruction_count() {
+ None
+ } else {
+ Some(MediumLevelILInstruction::new(self, expr_idx))
+ }
+ }
+
+ pub fn instruction_from_idx(&self, expr_idx: usize) -> MediumLevelILInstruction {
+ MediumLevelILInstruction::new(self, expr_idx)
+ }
+
+ pub fn instruction_count(&self) -> usize {
+ unsafe { BNGetMediumLevelILInstructionCount(self.handle) }
+ }
+
+ pub fn ssa_form(&self) -> MediumLevelILFunction {
+ let ssa = unsafe { BNGetMediumLevelILSSAForm(self.handle) };
+ assert!(!ssa.is_null());
+ MediumLevelILFunction { handle: ssa }
+ }
+
+ pub fn get_function(&self) -> Ref<Function> {
+ unsafe {
+ let func = BNGetMediumLevelILOwnerFunction(self.handle);
+ Function::from_raw(func)
+ }
+ }
+
+ pub fn basic_blocks(&self) -> Array<BasicBlock<MediumLevelILBlock>> {
+ let mut count = 0;
+ let blocks = unsafe { BNGetMediumLevelILBasicBlockList(self.handle, &mut count) };
+ let context = MediumLevelILBlock {
+ function: self.to_owned(),
+ };
+
+ unsafe { Array::new(blocks, count, context) }
+ }
+}
+
+impl ToOwned for MediumLevelILFunction {
+ type Owned = Ref<Self>;
+
+ fn to_owned(&self) -> Self::Owned {
+ unsafe { RefCountable::inc_ref(self) }
+ }
+}
+
+unsafe impl RefCountable for MediumLevelILFunction {
+ unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
+ Ref::new(Self {
+ handle: BNNewMediumLevelILFunctionReference(handle.handle),
+ })
+ }
+
+ unsafe fn dec_ref(handle: &Self) {
+ BNFreeMediumLevelILFunction(handle.handle);
+ }
+}
+
+impl core::fmt::Debug for MediumLevelILFunction {
+ fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+ write!(f, "<mlil func handle {:p}>", self.handle)
+ }
+}
diff --git a/rust/src/mlil/instruction.rs b/rust/src/mlil/instruction.rs
new file mode 100644
index 00000000..5e237128
--- /dev/null
+++ b/rust/src/mlil/instruction.rs
@@ -0,0 +1,812 @@
+use binaryninjacore_sys::BNGetMediumLevelILByIndex;
+use binaryninjacore_sys::BNMediumLevelILOperation;
+
+use crate::mlil::MediumLevelILLiftedOperation;
+use crate::rc::Ref;
+
+use super::operation::*;
+use super::{MediumLevelILFunction, MediumLevelILLiftedInstruction};
+
+#[derive(Clone)]
+pub struct MediumLevelILInstruction {
+ pub(crate) function: Ref<MediumLevelILFunction>,
+ pub(crate) address: u64,
+ pub(crate) operation: MediumLevelILOperation,
+}
+
+#[derive(Copy, Clone)]
+pub enum MediumLevelILOperation {
+ Nop(NoArgs),
+ Noret(NoArgs),
+ Bp(NoArgs),
+ Undef(NoArgs),
+ Unimpl(NoArgs),
+ If(MediumLevelILOperationIf),
+ FloatConst(FloatConst),
+ Const(Constant),
+ ConstPtr(Constant),
+ Import(Constant),
+ ExternPtr(ExternPtr),
+ ConstData(ConstData),
+ Jump(Jump),
+ RetHint(Jump),
+ StoreSsa(StoreSsa),
+ StoreStructSsa(StoreStructSsa),
+ StoreStruct(StoreStruct),
+ Store(Store),
+ JumpTo(JumpTo),
+ Goto(Goto),
+ FreeVarSlot(FreeVarSlot),
+ SetVarField(SetVarField),
+ SetVar(SetVar),
+ FreeVarSlotSsa(FreeVarSlotSsa),
+ SetVarSsaField(SetVarSsaField),
+ SetVarAliasedField(SetVarSsaField),
+ SetVarAliased(SetVarAliased),
+ SetVarSsa(SetVarSsa),
+ VarPhi(VarPhi),
+ MemPhi(MemPhi),
+ VarSplit(VarSplit),
+ SetVarSplit(SetVarSplit),
+ VarSplitSsa(VarSplitSsa),
+ SetVarSplitSsa(SetVarSplitSsa),
+ Add(BinaryOp),
+ Sub(BinaryOp),
+ And(BinaryOp),
+ Or(BinaryOp),
+ Xor(BinaryOp),
+ Lsl(BinaryOp),
+ Lsr(BinaryOp),
+ Asr(BinaryOp),
+ Rol(BinaryOp),
+ Ror(BinaryOp),
+ Mul(BinaryOp),
+ MuluDp(BinaryOp),
+ MulsDp(BinaryOp),
+ Divu(BinaryOp),
+ DivuDp(BinaryOp),
+ Divs(BinaryOp),
+ DivsDp(BinaryOp),
+ Modu(BinaryOp),
+ ModuDp(BinaryOp),
+ Mods(BinaryOp),
+ ModsDp(BinaryOp),
+ CmpE(BinaryOp),
+ CmpNe(BinaryOp),
+ CmpSlt(BinaryOp),
+ CmpUlt(BinaryOp),
+ CmpSle(BinaryOp),
+ CmpUle(BinaryOp),
+ CmpSge(BinaryOp),
+ CmpUge(BinaryOp),
+ CmpSgt(BinaryOp),
+ CmpUgt(BinaryOp),
+ TestBit(BinaryOp),
+ AddOverflow(BinaryOp),
+ FcmpE(BinaryOp),
+ FcmpNe(BinaryOp),
+ FcmpLt(BinaryOp),
+ FcmpLe(BinaryOp),
+ FcmpGe(BinaryOp),
+ FcmpGt(BinaryOp),
+ FcmpO(BinaryOp),
+ FcmpUo(BinaryOp),
+ Fadd(BinaryOp),
+ Fsub(BinaryOp),
+ Fmul(BinaryOp),
+ Fdiv(BinaryOp),
+ Adc(BinaryOpCarry),
+ Sbb(BinaryOpCarry),
+ Rlc(BinaryOpCarry),
+ Rrc(BinaryOpCarry),
+ Call(Call),
+ Tailcall(Call),
+ Syscall(Syscall),
+ Intrinsic(Intrinsic),
+ IntrinsicSsa(IntrinsicSsa),
+ CallSsa(CallSsa),
+ TailcallSsa(CallSsa),
+ CallUntypedSsa(CallUntypedSsa),
+ TailcallUntypedSsa(CallUntypedSsa),
+ SyscallSsa(SyscallSsa),
+ SyscallUntypedSsa(SyscallUntypedSsa),
+ CallUntyped(CallUntyped),
+ TailcallUntyped(CallUntyped),
+ SyscallUntyped(SyscallUntyped),
+ Neg(UnaryOp),
+ Not(UnaryOp),
+ Sx(UnaryOp),
+ Zx(UnaryOp),
+ LowPart(UnaryOp),
+ BoolToInt(UnaryOp),
+ UnimplMem(UnaryOp),
+ Fsqrt(UnaryOp),
+ Fneg(UnaryOp),
+ Fabs(UnaryOp),
+ FloatToInt(UnaryOp),
+ IntToFloat(UnaryOp),
+ FloatConv(UnaryOp),
+ RoundToInt(UnaryOp),
+ Floor(UnaryOp),
+ Ceil(UnaryOp),
+ Ftrunc(UnaryOp),
+ Load(UnaryOp),
+ LoadStruct(LoadStruct),
+ LoadStructSsa(LoadStructSsa),
+ LoadSsa(LoadSsa),
+ Ret(Ret),
+ Var(Var),
+ AddressOf(Var),
+ VarField(Field),
+ AddressOfField(Field),
+ VarSsa(VarSsa),
+ VarAliased(VarSsa),
+ VarSsaField(VarSsaField),
+ VarAliasedField(VarSsaField),
+ Trap(Trap),
+}
+
+impl core::fmt::Debug for MediumLevelILInstruction {
+ fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
+ write!(
+ f,
+ "<{} at 0x{:08}>",
+ core::any::type_name::<Self>(),
+ self.address,
+ )
+ }
+}
+
+impl MediumLevelILInstruction {
+ pub(crate) fn new(function: &MediumLevelILFunction, idx: usize) -> Self {
+ let op = unsafe { BNGetMediumLevelILByIndex(function.handle, idx) };
+ use BNMediumLevelILOperation::*;
+ use MediumLevelILOperation as Op;
+ let info = match op.operation {
+ MLIL_NOP => Op::Nop(NoArgs::default()),
+ MLIL_NORET => Op::Noret(NoArgs::default()),
+ MLIL_BP => Op::Bp(NoArgs::default()),
+ MLIL_UNDEF => Op::Undef(NoArgs::default()),
+ MLIL_UNIMPL => Op::Unimpl(NoArgs::default()),
+ MLIL_IF => Op::If(MediumLevelILOperationIf::new(
+ op.operands[0] as usize,
+ op.operands[1],
+ op.operands[2],
+ )),
+ MLIL_FLOAT_CONST => Op::FloatConst(FloatConst::new(op.operands[0], op.size)),
+ MLIL_CONST => Op::Const(Constant::new(op.operands[0])),
+ MLIL_CONST_PTR => Op::ConstPtr(Constant::new(op.operands[0])),
+ MLIL_IMPORT => Op::Import(Constant::new(op.operands[0])),
+ MLIL_EXTERN_PTR => Op::ExternPtr(ExternPtr::new(op.operands[0], op.operands[1])),
+ MLIL_CONST_DATA => Op::ConstData(ConstData::new((op.operands[0], op.operands[1]))),
+ MLIL_JUMP => Op::Jump(Jump::new(op.operands[0] as usize)),
+ MLIL_RET_HINT => Op::RetHint(Jump::new(op.operands[0] as usize)),
+ MLIL_STORE_SSA => Op::StoreSsa(StoreSsa::new(
+ op.operands[0] as usize,
+ op.operands[1],
+ op.operands[2],
+ op.operands[3] as usize,
+ )),
+ MLIL_STORE_STRUCT_SSA => Op::StoreStructSsa(StoreStructSsa::new(
+ op.operands[0] as usize,
+ op.operands[1],
+ op.operands[2],
+ op.operands[3],
+ op.operands[4] as usize,
+ )),
+ MLIL_STORE_STRUCT => Op::StoreStruct(StoreStruct::new(
+ op.operands[0] as usize,
+ op.operands[1],
+ op.operands[2] as usize,
+ )),
+ MLIL_STORE => Op::Store(Store::new(op.operands[0] as usize, op.operands[1] as usize)),
+ MLIL_JUMP_TO => Op::JumpTo(JumpTo::new(
+ op.operands[0] as usize,
+ (op.operands[1] as usize, op.operands[2] as usize),
+ )),
+ MLIL_GOTO => Op::Goto(Goto::new(op.operands[0])),
+ MLIL_FREE_VAR_SLOT => Op::FreeVarSlot(FreeVarSlot::new(op.operands[0])),
+ MLIL_SET_VAR_FIELD => Op::SetVarField(SetVarField::new(
+ op.operands[0],
+ op.operands[1],
+ op.operands[2] as usize,
+ )),
+ MLIL_SET_VAR => Op::SetVar(SetVar::new(op.operands[0], op.operands[1] as usize)),
+ MLIL_FREE_VAR_SLOT_SSA => Op::FreeVarSlotSsa(FreeVarSlotSsa::new(
+ (op.operands[0], op.operands[1] as usize),
+ (op.operands[0], op.operands[2] as usize),
+ )),
+ MLIL_SET_VAR_SSA_FIELD => Op::SetVarSsaField(SetVarSsaField::new(
+ (op.operands[0], op.operands[1] as usize),
+ (op.operands[0], op.operands[2] as usize),
+ op.operands[3],
+ op.operands[4] as usize,
+ )),
+ MLIL_SET_VAR_ALIASED_FIELD => Op::SetVarAliasedField(SetVarSsaField::new(
+ (op.operands[0], op.operands[1] as usize),
+ (op.operands[0], op.operands[2] as usize),
+ op.operands[3],
+ op.operands[4] as usize,
+ )),
+ MLIL_SET_VAR_ALIASED => Op::SetVarAliased(SetVarAliased::new(
+ (op.operands[0], op.operands[1] as usize),
+ (op.operands[0], op.operands[2] as usize),
+ op.operands[3] as usize,
+ )),
+ MLIL_SET_VAR_SSA => Op::SetVarSsa(SetVarSsa::new(
+ (op.operands[0], op.operands[1] as usize),
+ op.operands[2] as usize,
+ )),
+ MLIL_VAR_PHI => Op::VarPhi(VarPhi::new(
+ (op.operands[0], op.operands[1] as usize),
+ (op.operands[2] as usize, op.operands[3] as usize),
+ )),
+ MLIL_MEM_PHI => Op::MemPhi(MemPhi::new(
+ op.operands[0],
+ (op.operands[1] as usize, op.operands[2] as usize),
+ )),
+ MLIL_VAR_SPLIT => Op::VarSplit(VarSplit::new(op.operands[0], op.operands[1])),
+ MLIL_SET_VAR_SPLIT => Op::SetVarSplit(SetVarSplit::new(
+ op.operands[0],
+ op.operands[1],
+ op.operands[2] as usize,
+ )),
+ MLIL_VAR_SPLIT_SSA => Op::VarSplitSsa(VarSplitSsa::new(
+ (op.operands[0], op.operands[1] as usize),
+ (op.operands[2], op.operands[3] as usize),
+ )),
+ MLIL_SET_VAR_SPLIT_SSA => Op::SetVarSplitSsa(SetVarSplitSsa::new(
+ (op.operands[0], op.operands[1] as usize),
+ (op.operands[2], op.operands[3] as usize),
+ op.operands[4] as usize,
+ )),
+ MLIL_ADD => Op::Add(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_SUB => Op::Sub(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_AND => Op::And(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_OR => Op::Or(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_XOR => Op::Xor(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_LSL => Op::Lsl(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_LSR => Op::Lsr(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_ASR => Op::Asr(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_ROL => Op::Rol(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_ROR => Op::Ror(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_MUL => Op::Mul(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_MULU_DP => Op::MuluDp(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_MULS_DP => Op::MulsDp(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_DIVU => Op::Divu(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_DIVU_DP => Op::DivuDp(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_DIVS => Op::Divs(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_DIVS_DP => Op::DivsDp(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_MODU => Op::Modu(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_MODU_DP => Op::ModuDp(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_MODS => Op::Mods(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_MODS_DP => Op::ModsDp(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_CMP_E => Op::CmpE(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_CMP_NE => Op::CmpNe(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_CMP_SLT => Op::CmpSlt(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_CMP_ULT => Op::CmpUlt(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_CMP_SLE => Op::CmpSle(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_CMP_ULE => Op::CmpUle(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_CMP_SGE => Op::CmpSge(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_CMP_UGE => Op::CmpUge(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_CMP_SGT => Op::CmpSgt(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_CMP_UGT => Op::CmpUgt(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_TEST_BIT => Op::TestBit(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_ADD_OVERFLOW => Op::AddOverflow(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_FCMP_E => Op::FcmpE(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_FCMP_NE => Op::FcmpNe(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_FCMP_LT => Op::FcmpLt(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_FCMP_LE => Op::FcmpLe(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_FCMP_GE => Op::FcmpGe(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_FCMP_GT => Op::FcmpGt(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_FCMP_O => Op::FcmpO(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_FCMP_UO => Op::FcmpUo(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_FADD => Op::Fadd(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_FSUB => Op::Fsub(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_FMUL => Op::Fmul(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_FDIV => Op::Fdiv(BinaryOp::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ )),
+ MLIL_ADC => Op::Adc(BinaryOpCarry::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ op.operands[2] as usize,
+ )),
+ MLIL_SBB => Op::Sbb(BinaryOpCarry::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ op.operands[2] as usize,
+ )),
+ MLIL_RLC => Op::Rlc(BinaryOpCarry::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ op.operands[2] as usize,
+ )),
+ MLIL_RRC => Op::Rrc(BinaryOpCarry::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ op.operands[2] as usize,
+ )),
+ MLIL_CALL => Op::Call(Call::new(
+ (op.operands[0] as usize, op.operands[1] as usize),
+ op.operands[2] as usize,
+ (op.operands[3] as usize, op.operands[4] as usize),
+ )),
+ MLIL_TAILCALL => Op::Tailcall(Call::new(
+ (op.operands[0] as usize, op.operands[1] as usize),
+ op.operands[2] as usize,
+ (op.operands[3] as usize, op.operands[4] as usize),
+ )),
+ MLIL_SYSCALL => Op::Syscall(Syscall::new(
+ (op.operands[0] as usize, op.operands[1] as usize),
+ (op.operands[2] as usize, op.operands[3] as usize),
+ )),
+ MLIL_INTRINSIC => Op::Intrinsic(Intrinsic::new(
+ (op.operands[0] as usize, op.operands[1] as usize),
+ op.operands[2] as usize,
+ (op.operands[3] as usize, op.operands[4] as usize),
+ )),
+ MLIL_INTRINSIC_SSA => Op::IntrinsicSsa(IntrinsicSsa::new(
+ (op.operands[0] as usize, op.operands[1] as usize),
+ op.operands[2] as usize,
+ (op.operands[3] as usize, op.operands[4] as usize),
+ )),
+ MLIL_CALL_SSA => Op::CallSsa(CallSsa::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ (op.operands[2] as usize, op.operands[3] as usize),
+ op.operands[4],
+ )),
+ MLIL_TAILCALL_SSA => Op::TailcallSsa(CallSsa::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ (op.operands[2] as usize, op.operands[3] as usize),
+ op.operands[4],
+ )),
+ MLIL_CALL_UNTYPED_SSA => Op::CallUntypedSsa(CallUntypedSsa::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ op.operands[2] as usize,
+ op.operands[3] as usize,
+ )),
+ MLIL_TAILCALL_UNTYPED_SSA => Op::TailcallUntypedSsa(CallUntypedSsa::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ op.operands[2] as usize,
+ op.operands[3] as usize,
+ )),
+ MLIL_SYSCALL_SSA => Op::SyscallSsa(SyscallSsa::new(
+ op.operands[0] as usize,
+ (op.operands[1] as usize, op.operands[2] as usize),
+ op.operands[3],
+ )),
+ MLIL_SYSCALL_UNTYPED_SSA => Op::SyscallUntypedSsa(SyscallUntypedSsa::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ op.operands[2] as usize,
+ )),
+ MLIL_CALL_UNTYPED => Op::CallUntyped(CallUntyped::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ op.operands[2] as usize,
+ op.operands[3] as usize,
+ )),
+ MLIL_TAILCALL_UNTYPED => Op::TailcallUntyped(CallUntyped::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ op.operands[2] as usize,
+ op.operands[3] as usize,
+ )),
+ MLIL_SYSCALL_UNTYPED => Op::SyscallUntyped(SyscallUntyped::new(
+ op.operands[0] as usize,
+ op.operands[1] as usize,
+ op.operands[2] as usize,
+ )),
+ MLIL_NEG => Op::Neg(UnaryOp::new(op.operands[0] as usize)),
+ MLIL_NOT => Op::Not(UnaryOp::new(op.operands[0] as usize)),
+ MLIL_SX => Op::Sx(UnaryOp::new(op.operands[0] as usize)),
+ MLIL_ZX => Op::Zx(UnaryOp::new(op.operands[0] as usize)),
+ MLIL_LOW_PART => Op::LowPart(UnaryOp::new(op.operands[0] as usize)),
+ MLIL_BOOL_TO_INT => Op::BoolToInt(UnaryOp::new(op.operands[0] as usize)),
+ MLIL_UNIMPL_MEM => Op::UnimplMem(UnaryOp::new(op.operands[0] as usize)),
+ MLIL_FSQRT => Op::Fsqrt(UnaryOp::new(op.operands[0] as usize)),
+ MLIL_FNEG => Op::Fneg(UnaryOp::new(op.operands[0] as usize)),
+ MLIL_FABS => Op::Fabs(UnaryOp::new(op.operands[0] as usize)),
+ MLIL_FLOAT_TO_INT => Op::FloatToInt(UnaryOp::new(op.operands[0] as usize)),
+ MLIL_INT_TO_FLOAT => Op::IntToFloat(UnaryOp::new(op.operands[0] as usize)),
+ MLIL_FLOAT_CONV => Op::FloatConv(UnaryOp::new(op.operands[0] as usize)),
+ MLIL_ROUND_TO_INT => Op::RoundToInt(UnaryOp::new(op.operands[0] as usize)),
+ MLIL_FLOOR => Op::Floor(UnaryOp::new(op.operands[0] as usize)),
+ MLIL_CEIL => Op::Ceil(UnaryOp::new(op.operands[0] as usize)),
+ MLIL_FTRUNC => Op::Ftrunc(UnaryOp::new(op.operands[0] as usize)),
+ MLIL_LOAD => Op::Load(UnaryOp::new(op.operands[0] as usize)),
+ MLIL_LOAD_STRUCT => {
+ Op::LoadStruct(LoadStruct::new(op.operands[0] as usize, op.operands[1]))
+ }
+ MLIL_LOAD_STRUCT_SSA => Op::LoadStructSsa(LoadStructSsa::new(
+ op.operands[0] as usize,
+ op.operands[1],
+ op.operands[2],
+ )),
+ MLIL_LOAD_SSA => Op::LoadSsa(LoadSsa::new(op.operands[0] as usize, op.operands[1])),
+ MLIL_RET => Op::Ret(Ret::new((op.operands[0] as usize, op.operands[1] as usize))),
+ MLIL_VAR => Op::Var(Var::new(op.operands[0])),
+ MLIL_ADDRESS_OF => Op::AddressOf(Var::new(op.operands[0])),
+ MLIL_VAR_FIELD => Op::VarField(Field::new(op.operands[0], op.operands[1])),
+ MLIL_ADDRESS_OF_FIELD => Op::AddressOfField(Field::new(op.operands[0], op.operands[1])),
+ MLIL_VAR_SSA => Op::VarSsa(VarSsa::new((op.operands[0], op.operands[1] as usize))),
+ MLIL_VAR_ALIASED => {
+ Op::VarAliased(VarSsa::new((op.operands[0], op.operands[1] as usize)))
+ }
+ MLIL_VAR_SSA_FIELD => Op::VarSsaField(VarSsaField::new(
+ (op.operands[0], op.operands[1] as usize),
+ op.operands[2],
+ )),
+ MLIL_VAR_ALIASED_FIELD => Op::VarAliasedField(VarSsaField::new(
+ (op.operands[0], op.operands[1] as usize),
+ op.operands[2],
+ )),
+ MLIL_TRAP => Op::Trap(Trap::new(op.operands[0])),
+ // translated directly into a list for Expression or Variables
+ MLIL_CALL_OUTPUT | MLIL_CALL_PARAM | MLIL_CALL_PARAM_SSA | MLIL_CALL_OUTPUT_SSA => {
+ unreachable!()
+ }
+ };
+ Self {
+ function: function.to_owned(),
+ address: op.address,
+ operation: info,
+ }
+ }
+
+ pub fn function(&self) -> &MediumLevelILFunction {
+ &self.function
+ }
+
+ pub fn address(&self) -> u64 {
+ self.address
+ }
+
+ pub fn operation(&self) -> &MediumLevelILOperation {
+ &self.operation
+ }
+
+ pub fn lift(&self) -> MediumLevelILLiftedInstruction {
+ use MediumLevelILLiftedOperation as Lifted;
+ use MediumLevelILOperation::*;
+
+ let operation = match self.operation {
+ Nop(op) => Lifted::Nop(op),
+ Noret(op) => Lifted::Noret(op),
+ Bp(op) => Lifted::Bp(op),
+ Undef(op) => Lifted::Undef(op),
+ Unimpl(op) => Lifted::Unimpl(op),
+ If(op) => Lifted::If(op.lift(&self.function)),
+ FloatConst(op) => Lifted::FloatConst(op),
+ Const(op) => Lifted::Const(op),
+ ConstPtr(op) => Lifted::ConstPtr(op),
+ Import(op) => Lifted::Import(op),
+ ExternPtr(op) => Lifted::ExternPtr(op),
+ ConstData(op) => Lifted::ConstData(op.lift(&self.function)),
+ Jump(op) => Lifted::Jump(op.lift(&self.function)),
+ RetHint(op) => Lifted::RetHint(op.lift(&self.function)),
+ StoreSsa(op) => Lifted::StoreSsa(op.lift(&self.function)),
+ StoreStructSsa(op) => Lifted::StoreStructSsa(op.lift(&self.function)),
+ StoreStruct(op) => Lifted::StoreStruct(op.lift(&self.function)),
+ Store(op) => Lifted::Store(op.lift(&self.function)),
+ JumpTo(op) => Lifted::JumpTo(op.lift(&self.function)),
+ Goto(op) => Lifted::Goto(op),
+ FreeVarSlot(op) => Lifted::FreeVarSlot(op),
+ SetVarField(op) => Lifted::SetVarField(op.lift(&self.function)),
+ SetVar(op) => Lifted::SetVar(op.lift(&self.function)),
+ FreeVarSlotSsa(op) => Lifted::FreeVarSlotSsa(op.lift()),
+ SetVarSsaField(op) => Lifted::SetVarSsaField(op.lift(&self.function)),
+ SetVarAliasedField(op) => Lifted::SetVarAliasedField(op.lift(&self.function)),
+ SetVarAliased(op) => Lifted::SetVarAliased(op.lift(&self.function)),
+ SetVarSsa(op) => Lifted::SetVarSsa(op.lift(&self.function)),
+ VarPhi(op) => Lifted::VarPhi(op.lift(&self.function)),
+ MemPhi(op) => Lifted::MemPhi(op.lift(&self.function)),
+ VarSplit(op) => Lifted::VarSplit(op.lift()),
+ SetVarSplit(op) => Lifted::SetVarSplit(op.lift(&self.function)),
+ VarSplitSsa(op) => Lifted::VarSplitSsa(op.lift()),
+ SetVarSplitSsa(op) => Lifted::SetVarSplitSsa(op.lift(&self.function)),
+ Add(op) => Lifted::Add(op.lift(&self.function)),
+ Sub(op) => Lifted::Sub(op.lift(&self.function)),
+ And(op) => Lifted::And(op.lift(&self.function)),
+ Or(op) => Lifted::Or(op.lift(&self.function)),
+ Xor(op) => Lifted::Xor(op.lift(&self.function)),
+ Lsl(op) => Lifted::Lsl(op.lift(&self.function)),
+ Lsr(op) => Lifted::Lsr(op.lift(&self.function)),
+ Asr(op) => Lifted::Asr(op.lift(&self.function)),
+ Rol(op) => Lifted::Rol(op.lift(&self.function)),
+ Ror(op) => Lifted::Ror(op.lift(&self.function)),
+ Mul(op) => Lifted::Mul(op.lift(&self.function)),
+ MuluDp(op) => Lifted::MuluDp(op.lift(&self.function)),
+ MulsDp(op) => Lifted::MulsDp(op.lift(&self.function)),
+ Divu(op) => Lifted::Divu(op.lift(&self.function)),
+ DivuDp(op) => Lifted::DivuDp(op.lift(&self.function)),
+ Divs(op) => Lifted::Divs(op.lift(&self.function)),
+ DivsDp(op) => Lifted::DivsDp(op.lift(&self.function)),
+ Modu(op) => Lifted::Modu(op.lift(&self.function)),
+ ModuDp(op) => Lifted::ModuDp(op.lift(&self.function)),
+ Mods(op) => Lifted::Mods(op.lift(&self.function)),
+ ModsDp(op) => Lifted::ModsDp(op.lift(&self.function)),
+ CmpE(op) => Lifted::CmpE(op.lift(&self.function)),
+ CmpNe(op) => Lifted::CmpNe(op.lift(&self.function)),
+ CmpSlt(op) => Lifted::CmpSlt(op.lift(&self.function)),
+ CmpUlt(op) => Lifted::CmpUlt(op.lift(&self.function)),
+ CmpSle(op) => Lifted::CmpSle(op.lift(&self.function)),
+ CmpUle(op) => Lifted::CmpUle(op.lift(&self.function)),
+ CmpSge(op) => Lifted::CmpSge(op.lift(&self.function)),
+ CmpUge(op) => Lifted::CmpUge(op.lift(&self.function)),
+ CmpSgt(op) => Lifted::CmpSgt(op.lift(&self.function)),
+ CmpUgt(op) => Lifted::CmpUgt(op.lift(&self.function)),
+ TestBit(op) => Lifted::TestBit(op.lift(&self.function)),
+ AddOverflow(op) => Lifted::AddOverflow(op.lift(&self.function)),
+ FcmpE(op) => Lifted::FcmpE(op.lift(&self.function)),
+ FcmpNe(op) => Lifted::FcmpNe(op.lift(&self.function)),
+ FcmpLt(op) => Lifted::FcmpLt(op.lift(&self.function)),
+ FcmpLe(op) => Lifted::FcmpLe(op.lift(&self.function)),
+ FcmpGe(op) => Lifted::FcmpGe(op.lift(&self.function)),
+ FcmpGt(op) => Lifted::FcmpGt(op.lift(&self.function)),
+ FcmpO(op) => Lifted::FcmpO(op.lift(&self.function)),
+ FcmpUo(op) => Lifted::FcmpUo(op.lift(&self.function)),
+ Fadd(op) => Lifted::Fadd(op.lift(&self.function)),
+ Fsub(op) => Lifted::Fsub(op.lift(&self.function)),
+ Fmul(op) => Lifted::Fmul(op.lift(&self.function)),
+ Fdiv(op) => Lifted::Fdiv(op.lift(&self.function)),
+ Adc(op) => Lifted::Adc(op.lift(&self.function)),
+ Sbb(op) => Lifted::Sbb(op.lift(&self.function)),
+ Rlc(op) => Lifted::Rlc(op.lift(&self.function)),
+ Rrc(op) => Lifted::Rrc(op.lift(&self.function)),
+ Call(op) => Lifted::Call(op.lift(&self.function)),
+ Tailcall(op) => Lifted::Tailcall(op.lift(&self.function)),
+ Intrinsic(op) => Lifted::Intrinsic(op.lift(&self.function)),
+ Syscall(op) => Lifted::Syscall(op.lift(&self.function)),
+ IntrinsicSsa(op) => Lifted::IntrinsicSsa(op.lift(&self.function)),
+ CallSsa(op) => Lifted::CallSsa(op.lift(&self.function)),
+ TailcallSsa(op) => Lifted::TailcallSsa(op.lift(&self.function)),
+ CallUntypedSsa(op) => Lifted::CallUntypedSsa(op.lift(&self.function)),
+ TailcallUntypedSsa(op) => Lifted::TailcallUntypedSsa(op.lift(&self.function)),
+ SyscallSsa(op) => Lifted::SyscallSsa(op.lift(&self.function)),
+ SyscallUntypedSsa(op) => Lifted::SyscallUntypedSsa(op.lift(&self.function)),
+ CallUntyped(op) => Lifted::CallUntyped(op.lift(&self.function)),
+ TailcallUntyped(op) => Lifted::TailcallUntyped(op.lift(&self.function)),
+ SyscallUntyped(op) => Lifted::SyscallUntyped(op.lift(&self.function)),
+ Neg(op) => Lifted::Neg(op.lift(&self.function)),
+ Not(op) => Lifted::Not(op.lift(&self.function)),
+ Sx(op) => Lifted::Sx(op.lift(&self.function)),
+ Zx(op) => Lifted::Zx(op.lift(&self.function)),
+ LowPart(op) => Lifted::LowPart(op.lift(&self.function)),
+ BoolToInt(op) => Lifted::BoolToInt(op.lift(&self.function)),
+ UnimplMem(op) => Lifted::UnimplMem(op.lift(&self.function)),
+ Fsqrt(op) => Lifted::Fsqrt(op.lift(&self.function)),
+ Fneg(op) => Lifted::Fneg(op.lift(&self.function)),
+ Fabs(op) => Lifted::Fabs(op.lift(&self.function)),
+ FloatToInt(op) => Lifted::FloatToInt(op.lift(&self.function)),
+ IntToFloat(op) => Lifted::IntToFloat(op.lift(&self.function)),
+ FloatConv(op) => Lifted::FloatConv(op.lift(&self.function)),
+ RoundToInt(op) => Lifted::RoundToInt(op.lift(&self.function)),
+ Floor(op) => Lifted::Floor(op.lift(&self.function)),
+ Ceil(op) => Lifted::Ceil(op.lift(&self.function)),
+ Ftrunc(op) => Lifted::Ftrunc(op.lift(&self.function)),
+ Load(op) => Lifted::Load(op.lift(&self.function)),
+ LoadStruct(op) => Lifted::LoadStruct(op.lift(&self.function)),
+ LoadStructSsa(op) => Lifted::LoadStructSsa(op.lift(&self.function)),
+ LoadSsa(op) => Lifted::LoadSsa(op.lift(&self.function)),
+ Ret(op) => Lifted::Ret(op.lift(&self.function)),
+ Var(op) => Lifted::Var(op),
+ AddressOf(op) => Lifted::AddressOf(op),
+ VarField(op) => Lifted::VarField(op),
+ AddressOfField(op) => Lifted::AddressOfField(op),
+ VarSsa(op) => Lifted::VarSsa(op),
+ VarAliased(op) => Lifted::VarAliased(op),
+ VarSsaField(op) => Lifted::VarSsaField(op),
+ VarAliasedField(op) => Lifted::VarAliasedField(op),
+ Trap(op) => Lifted::Trap(op),
+ };
+ MediumLevelILLiftedInstruction {
+ address: self.address,
+ operation,
+ }
+ }
+
+ pub fn operands(&self) -> Box<dyn Iterator<Item = (&'static str, MediumLevelILOperand)>> {
+ use MediumLevelILOperation::*;
+ match &self.operation {
+ Nop(_op) | Noret(_op) | Bp(_op) | Undef(_op) | Unimpl(_op) => Box::new([].into_iter()),
+ If(op) => Box::new(op.operands(&self.function)),
+ FloatConst(op) => Box::new(op.operands()),
+ Const(op) | ConstPtr(op) | Import(op) => Box::new(op.operands()),
+ ExternPtr(op) => Box::new(op.operands(&self.function)),
+ ConstData(op) => Box::new(op.operands(&self.function)),
+ Jump(op) | RetHint(op) => Box::new(op.operands(&self.function)),
+ StoreSsa(op) => Box::new(op.operands(&self.function)),
+ StoreStructSsa(op) => Box::new(op.operands(&self.function)),
+ StoreStruct(op) => Box::new(op.operands(&self.function)),
+ Store(op) => Box::new(op.operands(&self.function)),
+ JumpTo(op) => Box::new(op.operands(&self.function)),
+ Goto(op) => Box::new(op.operands()),
+ FreeVarSlot(op) => Box::new(op.operands()),
+ SetVarField(op) => Box::new(op.operands(&self.function)),
+ SetVar(op) => Box::new(op.operands(&self.function)),
+ FreeVarSlotSsa(op) => Box::new(op.operands()),
+ SetVarSsaField(op) | SetVarAliasedField(op) => Box::new(op.operands(&self.function)),
+ SetVarAliased(op) => Box::new(op.operands(&self.function)),
+ SetVarSsa(op) => Box::new(op.operands(&self.function)),
+ VarPhi(op) => Box::new(op.operands(&self.function)),
+ MemPhi(op) => Box::new(op.operands(&self.function)),
+ VarSplit(op) => Box::new(op.operands()),
+ SetVarSplit(op) => Box::new(op.operands(&self.function)),
+ VarSplitSsa(op) => Box::new(op.operands()),
+ SetVarSplitSsa(op) => Box::new(op.operands(&self.function)),
+ Add(op) | Sub(op) | And(op) | Or(op) | Xor(op) | Lsl(op) | Lsr(op) | Asr(op)
+ | Rol(op) | Ror(op) | Mul(op) | MuluDp(op) | MulsDp(op) | Divu(op) | DivuDp(op)
+ | Divs(op) | DivsDp(op) | Modu(op) | ModuDp(op) | Mods(op) | ModsDp(op) | CmpE(op)
+ | CmpNe(op) | CmpSlt(op) | CmpUlt(op) | CmpSle(op) | CmpUle(op) | CmpSge(op)
+ | CmpUge(op) | CmpSgt(op) | CmpUgt(op) | TestBit(op) | AddOverflow(op) | FcmpE(op)
+ | FcmpNe(op) | FcmpLt(op) | FcmpLe(op) | FcmpGe(op) | FcmpGt(op) | FcmpO(op)
+ | FcmpUo(op) | Fadd(op) | Fsub(op) | Fmul(op) | Fdiv(op) => {
+ Box::new(op.operands(&self.function))
+ }
+ Adc(op) | Sbb(op) | Rlc(op) | Rrc(op) => Box::new(op.operands(&self.function)),
+ Call(op) | Tailcall(op) => Box::new(op.operands(&self.function)),
+ Syscall(op) => Box::new(op.operands(&self.function)),
+ Intrinsic(op) => Box::new(op.operands(&self.function)),
+ IntrinsicSsa(op) => Box::new(op.operands(&self.function)),
+ CallSsa(op) | TailcallSsa(op) => Box::new(op.operands(&self.function)),
+ CallUntypedSsa(op) | TailcallUntypedSsa(op) => Box::new(op.operands(&self.function)),
+ SyscallSsa(op) => Box::new(op.operands(&self.function)),
+ SyscallUntypedSsa(op) => Box::new(op.operands(&self.function)),
+ CallUntyped(op) | TailcallUntyped(op) => Box::new(op.operands(&self.function)),
+ SyscallUntyped(op) => Box::new(op.operands(&self.function)),
+ Neg(op) | Not(op) | Sx(op) | Zx(op) | LowPart(op) | BoolToInt(op) | UnimplMem(op)
+ | Fsqrt(op) | Fneg(op) | Fabs(op) | FloatToInt(op) | IntToFloat(op) | FloatConv(op)
+ | RoundToInt(op) | Floor(op) | Ceil(op) | Ftrunc(op) | Load(op) => {
+ Box::new(op.operands(&self.function))
+ }
+ LoadStruct(op) => Box::new(op.operands(&self.function)),
+ LoadStructSsa(op) => Box::new(op.operands(&self.function)),
+ LoadSsa(op) => Box::new(op.operands(&self.function)),
+ Ret(op) => Box::new(op.operands(&self.function)),
+ Var(op) | AddressOf(op) => Box::new(op.operands()),
+ VarField(op) | AddressOfField(op) => Box::new(op.operands()),
+ VarSsa(op) | VarAliased(op) => Box::new(op.operands()),
+ VarSsaField(op) | VarAliasedField(op) => Box::new(op.operands()),
+ Trap(op) => Box::new(op.operands()),
+ }
+ }
+}
diff --git a/rust/src/mlil/lift.rs b/rust/src/mlil/lift.rs
new file mode 100644
index 00000000..68a7884e
--- /dev/null
+++ b/rust/src/mlil/lift.rs
@@ -0,0 +1,139 @@
+use super::operation::*;
+
+#[derive(Clone, Debug, PartialEq)]
+pub struct MediumLevelILLiftedInstruction {
+ pub address: u64,
+ pub operation: MediumLevelILLiftedOperation,
+}
+
+#[derive(Clone, Debug, PartialEq)]
+pub enum MediumLevelILLiftedOperation {
+ Nop(NoArgs),
+ Noret(NoArgs),
+ Bp(NoArgs),
+ Undef(NoArgs),
+ Unimpl(NoArgs),
+ If(LiftedIf),
+ FloatConst(FloatConst),
+ Const(Constant),
+ ConstPtr(Constant),
+ Import(Constant),
+ ExternPtr(ExternPtr),
+ ConstData(ConstantData),
+ Jump(LiftedJump),
+ RetHint(LiftedJump),
+ StoreSsa(LiftedStoreSsa),
+ StoreStructSsa(LiftedStoreStructSsa),
+ StoreStruct(LiftedStoreStruct),
+ Store(LiftedStore),
+ JumpTo(LiftedJumpTo),
+ Goto(Goto),
+ FreeVarSlot(FreeVarSlot),
+ SetVarField(LiftedSetVarField),
+ SetVar(LiftedSetVar),
+ FreeVarSlotSsa(FreeVarSlotSsa),
+ SetVarSsaField(LiftedSetVarSsaField),
+ SetVarAliasedField(LiftedSetVarSsaField),
+ SetVarAliased(LiftedSetVarAliased),
+ SetVarSsa(LiftedSetVarSsa),
+ VarPhi(LiftedVarPhi),
+ MemPhi(LiftedMemPhi),
+ VarSplit(VarSplit),
+ SetVarSplit(LiftedSetVarSplit),
+ VarSplitSsa(VarSplitSsa),
+ SetVarSplitSsa(LiftedSetVarSplitSsa),
+ Add(LiftedBinaryOp),
+ Sub(LiftedBinaryOp),
+ And(LiftedBinaryOp),
+ Or(LiftedBinaryOp),
+ Xor(LiftedBinaryOp),
+ Lsl(LiftedBinaryOp),
+ Lsr(LiftedBinaryOp),
+ Asr(LiftedBinaryOp),
+ Rol(LiftedBinaryOp),
+ Ror(LiftedBinaryOp),
+ Mul(LiftedBinaryOp),
+ MuluDp(LiftedBinaryOp),
+ MulsDp(LiftedBinaryOp),
+ Divu(LiftedBinaryOp),
+ DivuDp(LiftedBinaryOp),
+ Divs(LiftedBinaryOp),
+ DivsDp(LiftedBinaryOp),
+ Modu(LiftedBinaryOp),
+ ModuDp(LiftedBinaryOp),
+ Mods(LiftedBinaryOp),
+ ModsDp(LiftedBinaryOp),
+ CmpE(LiftedBinaryOp),
+ CmpNe(LiftedBinaryOp),
+ CmpSlt(LiftedBinaryOp),
+ CmpUlt(LiftedBinaryOp),
+ CmpSle(LiftedBinaryOp),
+ CmpUle(LiftedBinaryOp),
+ CmpSge(LiftedBinaryOp),
+ CmpUge(LiftedBinaryOp),
+ CmpSgt(LiftedBinaryOp),
+ CmpUgt(LiftedBinaryOp),
+ TestBit(LiftedBinaryOp),
+ AddOverflow(LiftedBinaryOp),
+ FcmpE(LiftedBinaryOp),
+ FcmpNe(LiftedBinaryOp),
+ FcmpLt(LiftedBinaryOp),
+ FcmpLe(LiftedBinaryOp),
+ FcmpGe(LiftedBinaryOp),
+ FcmpGt(LiftedBinaryOp),
+ FcmpO(LiftedBinaryOp),
+ FcmpUo(LiftedBinaryOp),
+ Fadd(LiftedBinaryOp),
+ Fsub(LiftedBinaryOp),
+ Fmul(LiftedBinaryOp),
+ Fdiv(LiftedBinaryOp),
+ Adc(LiftedBinaryOpCarry),
+ Sbb(LiftedBinaryOpCarry),
+ Rlc(LiftedBinaryOpCarry),
+ Rrc(LiftedBinaryOpCarry),
+ Call(LiftedCall),
+ Tailcall(LiftedCall),
+ Intrinsic(LiftedInnerCall),
+ Syscall(LiftedInnerCall),
+ IntrinsicSsa(LiftedIntrinsicSsa),
+ CallSsa(LiftedCallSsa),
+ TailcallSsa(LiftedCallSsa),
+ CallUntypedSsa(LiftedCallUntypedSsa),
+ TailcallUntypedSsa(LiftedCallUntypedSsa),
+ SyscallSsa(LiftedSyscallSsa),
+ SyscallUntypedSsa(LiftedSyscallUntypedSsa),
+ CallUntyped(LiftedCallUntyped),
+ TailcallUntyped(LiftedCallUntyped),
+ SyscallUntyped(LiftedSyscallUntyped),
+ Neg(LiftedUnaryOp),
+ Not(LiftedUnaryOp),
+ Sx(LiftedUnaryOp),
+ Zx(LiftedUnaryOp),
+ LowPart(LiftedUnaryOp),
+ BoolToInt(LiftedUnaryOp),
+ UnimplMem(LiftedUnaryOp),
+ Fsqrt(LiftedUnaryOp),
+ Fneg(LiftedUnaryOp),
+ Fabs(LiftedUnaryOp),
+ FloatToInt(LiftedUnaryOp),
+ IntToFloat(LiftedUnaryOp),
+ FloatConv(LiftedUnaryOp),
+ RoundToInt(LiftedUnaryOp),
+ Floor(LiftedUnaryOp),
+ Ceil(LiftedUnaryOp),
+ Ftrunc(LiftedUnaryOp),
+ Load(LiftedUnaryOp),
+ LoadStruct(LiftedLoadStruct),
+ LoadStructSsa(LiftedLoadStructSsa),
+ LoadSsa(LiftedLoadSsa),
+ Ret(LiftedRet),
+ Var(Var),
+ AddressOf(Var),
+ VarField(Field),
+ AddressOfField(Field),
+ VarSsa(VarSsa),
+ VarAliased(VarSsa),
+ VarSsaField(VarSsaField),
+ VarAliasedField(VarSsaField),
+ Trap(Trap),
+}
diff --git a/rust/src/mlil/mod.rs b/rust/src/mlil/mod.rs
new file mode 100644
index 00000000..8a9103ac
--- /dev/null
+++ b/rust/src/mlil/mod.rs
@@ -0,0 +1,10 @@
+mod block;
+mod function;
+mod instruction;
+mod lift;
+pub mod operation;
+
+pub use self::block::*;
+pub use self::function::*;
+pub use self::instruction::*;
+pub use self::lift::*;
diff --git a/rust/src/mlil/operation.rs b/rust/src/mlil/operation.rs
new file mode 100644
index 00000000..4b234bf1
--- /dev/null
+++ b/rust/src/mlil/operation.rs
@@ -0,0 +1,2170 @@
+use std::collections::HashMap;
+
+use binaryninjacore_sys::BNFromVariableIdentifier;
+use binaryninjacore_sys::BNGetMediumLevelILByIndex;
+use binaryninjacore_sys::BNMediumLevelILInstruction;
+use binaryninjacore_sys::BNMediumLevelILOperation;
+
+use crate::rc::Ref;
+use crate::types::{SSAVariable, Variable};
+
+use super::{MediumLevelILFunction, MediumLevelILInstruction, MediumLevelILLiftedInstruction};
+
+pub enum MediumLevelILOperand {
+ //TODO
+ //ConstantData(!),
+ //TODO
+ //Intrinsic(!),
+ Expr(MediumLevelILInstruction),
+ ExprList(OperandExprList),
+ Float(f64),
+ Int(u64),
+ IntList(OperandList),
+ TargetMap(OperandDubleList),
+ Var(Variable),
+ VarList(OperandVariableList),
+ VarSsa(SSAVariable),
+ VarSsaList(OperandSSAVariableList),
+}
+
+// Iterator for the get_list, this is better then a inline iterator because
+// this also implement ExactSizeIterator, what a inline iterator does not.
+pub struct OperandList {
+ function: Ref<MediumLevelILFunction>,
+ remaining: usize,
+ next_node_idx: Option<usize>,
+
+ current_node: core::array::IntoIter<u64, 4>,
+}
+impl OperandList {
+ fn new(function: &MediumLevelILFunction, idx: usize, number: usize) -> Self {
+ // alternative to core::array::IntoIter::empty();
+ let mut iter = [0; 4].into_iter();
+ for _ in 0..4 {
+ let _ = iter.next();
+ }
+ Self {
+ function: function.to_owned(),
+ remaining: number,
+ next_node_idx: Some(idx),
+ current_node: iter,
+ }
+ }
+ fn duble(self) -> OperandDubleList {
+ assert_eq!(self.len() % 2, 0);
+ OperandDubleList(self)
+ }
+ fn map_expr(self) -> OperandExprList {
+ OperandExprList(self)
+ }
+ fn map_var(self) -> OperandVariableList {
+ OperandVariableList(self)
+ }
+ fn map_ssa_var(self) -> OperandSSAVariableList {
+ OperandSSAVariableList(self.duble())
+ }
+}
+impl Iterator for OperandList {
+ type Item = u64;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ // if there is an item in this node, return it
+ if let Some(current_node) = self.current_node.next() {
+ return Some(current_node);
+ }
+
+ // no more items to fetch
+ if self.remaining == 0 {
+ return None;
+ }
+
+ // otherwise get the next node
+ let next_idx = self.next_node_idx?;
+ let node = unsafe { BNGetMediumLevelILByIndex(self.function.handle, next_idx) };
+ assert_eq!(node.operation, BNMediumLevelILOperation::MLIL_UNDEF);
+
+ // each node contains at most 4, the last is reserved to next node idx
+ let consume = if self.remaining > 4 {
+ // there are more nodes after this one
+ self.next_node_idx = Some(node.operands[4] as usize);
+ self.remaining -= 4;
+ &node.operands[0..4]
+ } else {
+ // last part of the list, there is no next node
+ self.next_node_idx = None;
+ let nodes = &node.operands[0..self.remaining];
+ self.remaining = 0;
+ nodes
+ };
+ // the iter need to have a space of 4, but we may have less then that,
+ // solution is create a dummy elements at the start and discard it
+ let mut nodes = [0; 4];
+ let dummy_values = 4 - consume.len();
+ nodes[dummy_values..4].copy_from_slice(consume);
+ self.current_node = nodes.into_iter();
+ for _ in 0..dummy_values {
+ let _ = self.current_node.next();
+ }
+
+ self.current_node.next()
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.len(), Some(self.len()))
+ }
+}
+impl ExactSizeIterator for OperandList {
+ fn len(&self) -> usize {
+ self.remaining + self.current_node.len()
+ }
+}
+
+// Iterator similar to OperationList, but returns two elements
+pub struct OperandDubleList(OperandList);
+impl Iterator for OperandDubleList {
+ type Item = (u64, u64);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let first = self.0.next()?;
+ let second = self.0.next().unwrap();
+ Some((first, second))
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.len(), Some(self.len()))
+ }
+}
+impl ExactSizeIterator for OperandDubleList {
+ fn len(&self) -> usize {
+ self.0.len() / 2
+ }
+}
+
+pub struct OperandExprList(OperandList);
+impl Iterator for OperandExprList {
+ type Item = MediumLevelILInstruction;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.0
+ .next()
+ .map(|idx| get_operation(&self.0.function, idx as usize))
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.0.len(), Some(self.0.len()))
+ }
+}
+impl ExactSizeIterator for OperandExprList {
+ fn len(&self) -> usize {
+ self.0.len()
+ }
+}
+
+pub struct OperandVariableList(OperandList);
+impl Iterator for OperandVariableList {
+ type Item = Variable;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.0.next().map(get_var)
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.0.len(), Some(self.0.len()))
+ }
+}
+impl ExactSizeIterator for OperandVariableList {
+ fn len(&self) -> usize {
+ self.0.len()
+ }
+}
+
+pub struct OperandSSAVariableList(OperandDubleList);
+impl Iterator for OperandSSAVariableList {
+ type Item = SSAVariable;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.0.next().map(|(id, version)| {
+ let raw = unsafe { BNFromVariableIdentifier(id) };
+ let var = unsafe { Variable::from_raw(raw) };
+ SSAVariable::new(var, version as usize)
+ })
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (self.len(), Some(self.len()))
+ }
+}
+impl ExactSizeIterator for OperandSSAVariableList {
+ fn len(&self) -> usize {
+ self.0.len()
+ }
+}
+
+fn get_float(value: u64, size: usize) -> f64 {
+ match size {
+ 4 => f32::from_bits(value as u32) as f64,
+ 8 => f64::from_bits(value),
+ // TODO how to handle this value?
+ size => todo!("float size {}", size),
+ }
+}
+
+// TODO implement ConstantData
+fn get_constant_data(
+ _function: &MediumLevelILFunction,
+ _value: u64,
+ _state: u64,
+ _size: usize,
+) -> ! {
+ todo!()
+}
+
+// TODO implement Intrinsic
+fn get_intrinsic(_function: &MediumLevelILFunction, _idx: usize) -> ! {
+ todo!()
+}
+
+fn get_operation(function: &MediumLevelILFunction, idx: usize) -> MediumLevelILInstruction {
+ function.instruction_from_idx(idx)
+}
+
+fn get_raw_operation(function: &MediumLevelILFunction, idx: usize) -> BNMediumLevelILInstruction {
+ unsafe { BNGetMediumLevelILByIndex(function.handle, idx) }
+}
+
+fn get_var(id: u64) -> Variable {
+ unsafe { Variable::from_raw(BNFromVariableIdentifier(id)) }
+}
+
+fn get_var_ssa(id: u64, version: usize) -> SSAVariable {
+ let raw = unsafe { BNFromVariableIdentifier(id) };
+ let var = unsafe { Variable::from_raw(raw) };
+ SSAVariable::new(var, version as usize)
+}
+
+fn get_call_list(
+ function: &MediumLevelILFunction,
+ op_type: BNMediumLevelILOperation,
+ idx: usize,
+) -> OperandVariableList {
+ let op = unsafe { BNGetMediumLevelILByIndex(function.handle, idx) };
+ assert_eq!(op.operation, op_type);
+ OperandList::new(function, op.operands[1] as usize, op.operands[0] as usize).map_var()
+}
+
+fn get_call_output(function: &MediumLevelILFunction, idx: usize) -> OperandVariableList {
+ get_call_list(function, BNMediumLevelILOperation::MLIL_CALL_OUTPUT, idx)
+}
+
+fn get_call_params(function: &MediumLevelILFunction, idx: usize) -> OperandVariableList {
+ get_call_list(function, BNMediumLevelILOperation::MLIL_CALL_PARAM, idx)
+}
+
+fn get_call_list_ssa(
+ function: &MediumLevelILFunction,
+ op_type: BNMediumLevelILOperation,
+ idx: usize,
+) -> OperandSSAVariableList {
+ let op = get_raw_operation(function, idx);
+ assert_eq!(op.operation, op_type);
+ OperandList::new(function, op.operands[2] as usize, op.operands[1] as usize).map_ssa_var()
+}
+
+fn get_call_output_ssa(function: &MediumLevelILFunction, idx: usize) -> OperandSSAVariableList {
+ get_call_list_ssa(
+ function,
+ BNMediumLevelILOperation::MLIL_CALL_OUTPUT_SSA,
+ idx,
+ )
+}
+
+fn get_call_params_ssa(function: &MediumLevelILFunction, idx: usize) -> OperandSSAVariableList {
+ get_call_list_ssa(function, BNMediumLevelILOperation::MLIL_CALL_PARAM_SSA, idx)
+}
+
+// NOP, NORET, BP, UNDEF, UNIMPL
+#[derive(Default, Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct NoArgs {}
+
+// IF
+#[derive(Copy, Clone)]
+pub struct MediumLevelILOperationIf {
+ condition: usize,
+ dest_true: u64,
+ dest_false: u64,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedIf {
+ pub condition: Box<MediumLevelILLiftedInstruction>,
+ pub dest_true: u64,
+ pub dest_false: u64,
+}
+impl MediumLevelILOperationIf {
+ pub fn new(condition: usize, dest_true: u64, dest_false: u64) -> Self {
+ Self {
+ condition,
+ dest_true,
+ dest_false,
+ }
+ }
+ pub fn condition(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.condition)
+ }
+ pub fn dest_true(&self) -> u64 {
+ self.dest_true
+ }
+ pub fn dest_false(&self) -> u64 {
+ self.dest_false
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedIf {
+ LiftedIf {
+ condition: Box::new(self.condition(function).lift()),
+ dest_true: self.dest_true(),
+ dest_false: self.dest_false(),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ use MediumLevelILOperand::*;
+ [
+ ("condition", Expr(self.condition(function))),
+ ("dest_true", Int(self.dest_true())),
+ ("dest_false", Int(self.dest_false())),
+ ]
+ .into_iter()
+ }
+}
+
+// FLOAT_CONST
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub struct FloatConst {
+ pub constant: f64,
+}
+impl FloatConst {
+ pub fn new(constant: u64, size: usize) -> Self {
+ Self {
+ constant: get_float(constant, size),
+ }
+ }
+ pub fn constant(&self) -> f64 {
+ self.constant
+ }
+ pub fn operands(&self) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [("constant", MediumLevelILOperand::Float(self.constant()))].into_iter()
+ }
+}
+
+// CONST, CONST_PTR, IMPORT
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct Constant {
+ pub constant: u64,
+}
+impl Constant {
+ pub fn new(constant: u64) -> Self {
+ Self { constant }
+ }
+ pub fn constant(&self) -> u64 {
+ self.constant
+ }
+ pub fn operands(&self) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [("constant", MediumLevelILOperand::Int(self.constant()))].into_iter()
+ }
+}
+
+// EXTERN_PTR
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct ExternPtr {
+ pub constant: u64,
+ pub offset: u64,
+}
+impl ExternPtr {
+ pub fn new(constant: u64, offset: u64) -> Self {
+ Self { constant, offset }
+ }
+ pub fn constant(&self) -> u64 {
+ self.constant
+ }
+ pub fn offset(&self) -> u64 {
+ self.offset
+ }
+ pub fn operands(
+ &self,
+ _function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [
+ ("constant", MediumLevelILOperand::Int(self.constant())),
+ ("offset", MediumLevelILOperand::Int(self.offset())),
+ ]
+ .into_iter()
+ }
+}
+
+// CONST_DATA
+#[derive(Copy, Clone)]
+pub struct ConstData {
+ constant_data: (u64, u64),
+}
+#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+pub struct ConstantData {
+ //pub constant_data: !,
+}
+impl ConstData {
+ pub fn new(constant_data: (u64, u64)) -> Self {
+ Self { constant_data }
+ }
+ pub fn constant_data(&self, function: &MediumLevelILFunction, size: usize) -> ! {
+ get_constant_data(function, self.constant_data.0, self.constant_data.1, size)
+ }
+ pub fn lift(&self, _function: &MediumLevelILFunction) -> ConstantData {
+ ConstantData {
+ // TODO
+ }
+ }
+ pub fn operands(
+ &self,
+ _function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ // TODO
+ [
+ //("contant_data", MediumLevelILOperand::ConstData(_self.constant_data(function, self.size)))
+ ]
+ .into_iter()
+ }
+}
+
+// JUMP, RET_HINT
+#[derive(Copy, Clone)]
+pub struct Jump {
+ dest: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedJump {
+ pub dest: Box<MediumLevelILLiftedInstruction>,
+}
+impl Jump {
+ pub fn new(dest: usize) -> Self {
+ Self { dest }
+ }
+ pub fn dest(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.dest)
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedJump {
+ LiftedJump {
+ dest: Box::new(self.dest(function).lift()),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [("dest", MediumLevelILOperand::Expr(self.dest(&function)))].into_iter()
+ }
+}
+
+// STORE_SSA
+#[derive(Copy, Clone)]
+pub struct StoreSsa {
+ dest: usize,
+ dest_memory: u64,
+ src_memory: u64,
+ src: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedStoreSsa {
+ pub dest: Box<MediumLevelILLiftedInstruction>,
+ pub dest_memory: u64,
+ pub src_memory: u64,
+ pub src: Box<MediumLevelILLiftedInstruction>,
+}
+impl StoreSsa {
+ pub fn new(dest: usize, dest_memory: u64, src_memory: u64, src: usize) -> Self {
+ Self {
+ dest,
+ dest_memory,
+ src_memory,
+ src,
+ }
+ }
+ pub fn dest(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.dest)
+ }
+ pub fn dest_memory(&self) -> u64 {
+ self.dest_memory
+ }
+ pub fn src_memory(&self) -> u64 {
+ self.src_memory
+ }
+ pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.src)
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedStoreSsa {
+ LiftedStoreSsa {
+ dest: Box::new(self.dest(function).lift()),
+ dest_memory: self.dest_memory(),
+ src_memory: self.src_memory(),
+ src: Box::new(self.src(function).lift()),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [
+ ("dest", MediumLevelILOperand::Expr(self.dest(&function))),
+ ("dest_memory", MediumLevelILOperand::Int(self.dest_memory())),
+ ("src_memory", MediumLevelILOperand::Int(self.src_memory())),
+ ("src", MediumLevelILOperand::Expr(self.src(&function))),
+ ]
+ .into_iter()
+ }
+}
+
+// STORE_STRUCT_SSA
+#[derive(Copy, Clone)]
+pub struct StoreStructSsa {
+ dest: usize,
+ offset: u64,
+ dest_memory: u64,
+ src_memory: u64,
+ src: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedStoreStructSsa {
+ pub dest: Box<MediumLevelILLiftedInstruction>,
+ pub offset: u64,
+ pub dest_memory: u64,
+ pub src_memory: u64,
+ pub src: Box<MediumLevelILLiftedInstruction>,
+}
+impl StoreStructSsa {
+ pub fn new(dest: usize, offset: u64, dest_memory: u64, src_memory: u64, src: usize) -> Self {
+ Self {
+ dest,
+ offset,
+ dest_memory,
+ src_memory,
+ src,
+ }
+ }
+ pub fn dest(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.dest)
+ }
+ pub fn offset(&self) -> u64 {
+ self.offset
+ }
+ pub fn dest_memory(&self) -> u64 {
+ self.dest_memory
+ }
+ pub fn src_memory(&self) -> u64 {
+ self.src_memory
+ }
+ pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.src)
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedStoreStructSsa {
+ LiftedStoreStructSsa {
+ dest: Box::new(self.dest(function).lift()),
+ offset: self.offset(),
+ dest_memory: self.dest_memory(),
+ src_memory: self.src_memory(),
+ src: Box::new(self.src(function).lift()),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [
+ ("dest", MediumLevelILOperand::Expr(self.dest(function))),
+ ("offset", MediumLevelILOperand::Int(self.offset())),
+ ("dest_memory", MediumLevelILOperand::Int(self.dest_memory())),
+ ("src_memory", MediumLevelILOperand::Int(self.src_memory())),
+ ("src", MediumLevelILOperand::Expr(self.src(function))),
+ ]
+ .into_iter()
+ }
+}
+
+// STORE_STRUCT
+#[derive(Copy, Clone)]
+pub struct StoreStruct {
+ dest: usize,
+ offset: u64,
+ src: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedStoreStruct {
+ pub dest: Box<MediumLevelILLiftedInstruction>,
+ pub offset: u64,
+ pub src: Box<MediumLevelILLiftedInstruction>,
+}
+impl StoreStruct {
+ pub fn new(dest: usize, offset: u64, src: usize) -> Self {
+ Self { dest, offset, src }
+ }
+ pub fn dest(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.dest)
+ }
+ pub fn offset(&self) -> u64 {
+ self.offset
+ }
+ pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.src)
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedStoreStruct {
+ LiftedStoreStruct {
+ dest: Box::new(self.dest(function).lift()),
+ offset: self.offset(),
+ src: Box::new(self.src(function).lift()),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [
+ ("dest", MediumLevelILOperand::Expr(self.dest(function))),
+ ("offset", MediumLevelILOperand::Int(self.offset())),
+ ("src", MediumLevelILOperand::Expr(self.src(function))),
+ ]
+ .into_iter()
+ }
+}
+
+// STORE
+#[derive(Copy, Clone)]
+pub struct Store {
+ dest: usize,
+ src: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedStore {
+ pub dest: Box<MediumLevelILLiftedInstruction>,
+ pub src: Box<MediumLevelILLiftedInstruction>,
+}
+impl Store {
+ pub fn new(dest: usize, src: usize) -> Self {
+ Self { dest, src }
+ }
+ pub fn dest(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.dest)
+ }
+ pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.src)
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedStore {
+ LiftedStore {
+ dest: Box::new(self.dest(function).lift()),
+ src: Box::new(self.src(function).lift()),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [
+ ("dest", MediumLevelILOperand::Expr(self.dest(function))),
+ ("src", MediumLevelILOperand::Expr(self.src(function))),
+ ]
+ .into_iter()
+ }
+}
+
+// JUMP_TO
+#[derive(Copy, Clone)]
+pub struct JumpTo {
+ dest: usize,
+ targets: (usize, usize),
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedJumpTo {
+ pub dest: Box<MediumLevelILLiftedInstruction>,
+ pub targets: HashMap<u64, u64>,
+}
+impl JumpTo {
+ pub fn new(dest: usize, targets: (usize, usize)) -> Self {
+ Self { dest, targets }
+ }
+ pub fn dest(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.dest)
+ }
+ pub fn targets(&self, function: &MediumLevelILFunction) -> OperandDubleList {
+ OperandList::new(function, self.targets.1, self.targets.0).duble()
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedJumpTo {
+ LiftedJumpTo {
+ dest: Box::new(self.dest(function).lift()),
+ targets: self.targets(function).collect(),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ use MediumLevelILOperand::*;
+ [
+ ("dest", Expr(self.dest(function))),
+ ("targets", TargetMap(self.targets(function))),
+ ]
+ .into_iter()
+ }
+}
+
+// GOTO
+#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
+pub struct Goto {
+ pub dest: u64,
+}
+impl Goto {
+ pub fn new(dest: u64) -> Self {
+ Self { dest }
+ }
+ pub fn dest(&self) -> u64 {
+ self.dest
+ }
+ pub fn operands(&self) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [("dest", MediumLevelILOperand::Int(self.dest()))].into_iter()
+ }
+}
+
+// FREE_VAR_SLOT
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct FreeVarSlot {
+ pub dest: Variable,
+}
+impl FreeVarSlot {
+ pub fn new(dest: u64) -> Self {
+ Self {
+ dest: get_var(dest),
+ }
+ }
+ pub fn dest(&self) -> Variable {
+ self.dest
+ }
+ pub fn operands(&self) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [("dest", MediumLevelILOperand::Var(self.dest()))].into_iter()
+ }
+}
+
+// SET_VAR_FIELD
+#[derive(Copy, Clone)]
+pub struct SetVarField {
+ dest: u64,
+ offset: u64,
+ src: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedSetVarField {
+ pub dest: Variable,
+ pub offset: u64,
+ pub src: Box<MediumLevelILLiftedInstruction>,
+}
+impl SetVarField {
+ pub fn new(dest: u64, offset: u64, src: usize) -> Self {
+ Self { dest, offset, src }
+ }
+ pub fn dest(&self) -> Variable {
+ get_var(self.dest)
+ }
+ pub fn offset(&self) -> u64 {
+ self.offset
+ }
+ pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.src)
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedSetVarField {
+ LiftedSetVarField {
+ dest: self.dest(),
+ offset: self.offset(),
+ src: Box::new(self.src(function).lift()),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [
+ ("dest", MediumLevelILOperand::Var(self.dest())),
+ ("offset", MediumLevelILOperand::Int(self.offset())),
+ ("src", MediumLevelILOperand::Expr(self.src(function))),
+ ]
+ .into_iter()
+ }
+}
+
+// SET_VAR
+#[derive(Copy, Clone)]
+pub struct SetVar {
+ dest: u64,
+ src: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedSetVar {
+ pub dest: Variable,
+ pub src: Box<MediumLevelILLiftedInstruction>,
+}
+impl SetVar {
+ pub fn new(dest: u64, src: usize) -> Self {
+ Self { dest, src }
+ }
+ pub fn dest(&self) -> Variable {
+ get_var(self.dest)
+ }
+ pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.src)
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedSetVar {
+ LiftedSetVar {
+ dest: self.dest(),
+ src: Box::new(self.src(function).lift()),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [
+ ("dest", MediumLevelILOperand::Var(self.dest())),
+ ("src", MediumLevelILOperand::Expr(self.src(function))),
+ ]
+ .into_iter()
+ }
+}
+
+// FREE_VAR_SLOT_SSA
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct FreeVarSlotSsa {
+ pub dest: SSAVariable,
+ pub prev: SSAVariable,
+}
+impl FreeVarSlotSsa {
+ pub fn new(dest: (u64, usize), prev: (u64, usize)) -> Self {
+ Self {
+ dest: get_var_ssa(dest.0, dest.1),
+ prev: get_var_ssa(prev.0, prev.1),
+ }
+ }
+ pub fn dest(&self) -> SSAVariable {
+ self.dest
+ }
+ pub fn prev(&self) -> SSAVariable {
+ self.prev
+ }
+ pub fn lift(self) -> FreeVarSlotSsa {
+ FreeVarSlotSsa {
+ dest: self.dest(),
+ prev: self.prev(),
+ }
+ }
+ pub fn operands(&self) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [
+ ("dest", MediumLevelILOperand::VarSsa(self.dest())),
+ ("prev", MediumLevelILOperand::VarSsa(self.prev())),
+ ]
+ .into_iter()
+ }
+}
+
+// SET_VAR_SSA_FIELD, SET_VAR_ALIASED_FIELD
+#[derive(Copy, Clone)]
+pub struct SetVarSsaField {
+ dest: (u64, usize),
+ prev: (u64, usize),
+ offset: u64,
+ src: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedSetVarSsaField {
+ pub dest: SSAVariable,
+ pub prev: SSAVariable,
+ pub offset: u64,
+ pub src: Box<MediumLevelILLiftedInstruction>,
+}
+impl SetVarSsaField {
+ pub fn new(dest: (u64, usize), prev: (u64, usize), offset: u64, src: usize) -> Self {
+ Self {
+ dest,
+ prev,
+ offset,
+ src,
+ }
+ }
+ pub fn dest(&self) -> SSAVariable {
+ get_var_ssa(self.dest.0, self.dest.1)
+ }
+ pub fn prev(&self) -> SSAVariable {
+ get_var_ssa(self.prev.0, self.prev.1)
+ }
+ pub fn offset(&self) -> u64 {
+ self.offset
+ }
+ pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.src)
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedSetVarSsaField {
+ LiftedSetVarSsaField {
+ dest: self.dest(),
+ prev: self.prev(),
+ offset: self.offset(),
+ src: Box::new(self.src(function).lift()),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [
+ ("dest", MediumLevelILOperand::VarSsa(self.dest())),
+ ("prev", MediumLevelILOperand::VarSsa(self.prev())),
+ ("offset", MediumLevelILOperand::Int(self.offset())),
+ ("src", MediumLevelILOperand::Expr(self.src(function))),
+ ]
+ .into_iter()
+ }
+}
+
+// SET_VAR_ALIASED
+#[derive(Copy, Clone)]
+pub struct SetVarAliased {
+ dest: (u64, usize),
+ prev: (u64, usize),
+ src: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedSetVarAliased {
+ pub dest: SSAVariable,
+ pub prev: SSAVariable,
+ pub src: Box<MediumLevelILLiftedInstruction>,
+}
+impl SetVarAliased {
+ pub fn new(dest: (u64, usize), prev: (u64, usize), src: usize) -> Self {
+ Self { dest, prev, src }
+ }
+ pub fn dest(&self) -> SSAVariable {
+ get_var_ssa(self.dest.0, self.dest.1)
+ }
+ pub fn prev(&self) -> SSAVariable {
+ get_var_ssa(self.prev.0, self.prev.1)
+ }
+ pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.src)
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedSetVarAliased {
+ LiftedSetVarAliased {
+ dest: self.dest(),
+ prev: self.prev(),
+ src: Box::new(self.src(function).lift()),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [
+ ("dest", MediumLevelILOperand::VarSsa(self.dest())),
+ ("prev", MediumLevelILOperand::VarSsa(self.prev())),
+ ("src", MediumLevelILOperand::Expr(self.src(function))),
+ ]
+ .into_iter()
+ }
+}
+
+// SET_VAR_SSA
+#[derive(Copy, Clone)]
+pub struct SetVarSsa {
+ dest: (u64, usize),
+ src: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedSetVarSsa {
+ pub dest: SSAVariable,
+ pub src: Box<MediumLevelILLiftedInstruction>,
+}
+impl SetVarSsa {
+ pub fn new(dest: (u64, usize), src: usize) -> Self {
+ Self { dest, src }
+ }
+ pub fn dest(&self) -> SSAVariable {
+ get_var_ssa(self.dest.0, self.dest.1)
+ }
+ pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.src)
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedSetVarSsa {
+ LiftedSetVarSsa {
+ dest: self.dest(),
+ src: Box::new(self.src(function).lift()),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [
+ ("dest", MediumLevelILOperand::VarSsa(self.dest())),
+ ("src", MediumLevelILOperand::Expr(self.src(function))),
+ ]
+ .into_iter()
+ }
+}
+
+// VAR_PHI
+#[derive(Copy, Clone)]
+pub struct VarPhi {
+ dest: (u64, usize),
+ src: (usize, usize),
+}
+#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+pub struct LiftedVarPhi {
+ pub dest: SSAVariable,
+ pub src: Vec<SSAVariable>,
+}
+impl VarPhi {
+ pub fn new(dest: (u64, usize), src: (usize, usize)) -> Self {
+ Self { dest, src }
+ }
+ pub fn dest(&self) -> SSAVariable {
+ get_var_ssa(self.dest.0, self.dest.1)
+ }
+ pub fn src(&self, function: &MediumLevelILFunction) -> OperandSSAVariableList {
+ OperandList::new(function, self.src.1, self.src.0).map_ssa_var()
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedVarPhi {
+ LiftedVarPhi {
+ dest: self.dest(),
+ src: self.src(function).collect(),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [
+ ("dest", MediumLevelILOperand::VarSsa(self.dest())),
+ ("src", MediumLevelILOperand::VarSsaList(self.src(function))),
+ ]
+ .into_iter()
+ }
+}
+
+// MEM_PHI
+#[derive(Copy, Clone)]
+pub struct MemPhi {
+ dest_memory: u64,
+ src_memory: (usize, usize),
+}
+#[derive(Clone, Debug, Hash, PartialEq, Eq)]
+pub struct LiftedMemPhi {
+ pub dest_memory: u64,
+ pub src_memory: Vec<u64>,
+}
+impl MemPhi {
+ pub fn new(dest_memory: u64, src_memory: (usize, usize)) -> Self {
+ Self {
+ dest_memory,
+ src_memory,
+ }
+ }
+ pub fn dest_memory(&self) -> u64 {
+ self.dest_memory
+ }
+ pub fn src_memory(&self, function: &MediumLevelILFunction) -> OperandList {
+ OperandList::new(function, self.src_memory.1, self.src_memory.0)
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedMemPhi {
+ LiftedMemPhi {
+ dest_memory: self.dest_memory(),
+ src_memory: self.src_memory(function).collect(),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ use MediumLevelILOperand::*;
+ [
+ ("dest_memory", Int(self.dest_memory())),
+ ("src_memory", IntList(self.src_memory(function))),
+ ]
+ .into_iter()
+ }
+}
+
+// VAR_SPLIT
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct VarSplit {
+ pub high: Variable,
+ pub low: Variable,
+}
+impl VarSplit {
+ pub fn new(high: u64, low: u64) -> Self {
+ Self {
+ high: get_var(high),
+ low: get_var(low),
+ }
+ }
+ pub fn high(&self) -> Variable {
+ self.high
+ }
+ pub fn low(&self) -> Variable {
+ self.low
+ }
+ pub fn lift(self) -> VarSplit {
+ VarSplit {
+ high: self.high(),
+ low: self.low(),
+ }
+ }
+ pub fn operands(&self) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [
+ ("high", MediumLevelILOperand::Var(self.high())),
+ ("low", MediumLevelILOperand::Var(self.low())),
+ ]
+ .into_iter()
+ }
+}
+
+// SET_VAR_SPLIT
+#[derive(Copy, Clone)]
+pub struct SetVarSplit {
+ high: u64,
+ low: u64,
+ src: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedSetVarSplit {
+ pub high: Variable,
+ pub low: Variable,
+ pub src: Box<MediumLevelILLiftedInstruction>,
+}
+impl SetVarSplit {
+ pub fn new(high: u64, low: u64, src: usize) -> Self {
+ Self { high, low, src }
+ }
+ pub fn high(&self) -> Variable {
+ get_var(self.high)
+ }
+ pub fn low(&self) -> Variable {
+ get_var(self.low)
+ }
+ pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.src)
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedSetVarSplit {
+ LiftedSetVarSplit {
+ high: self.high(),
+ low: self.low(),
+ src: Box::new(self.src(function).lift()),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [
+ ("high", MediumLevelILOperand::Var(self.high())),
+ ("low", MediumLevelILOperand::Var(self.low())),
+ ("src", MediumLevelILOperand::Expr(self.src(function))),
+ ]
+ .into_iter()
+ }
+}
+
+// VAR_SPLIT_SSA
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct VarSplitSsa {
+ pub high: SSAVariable,
+ pub low: SSAVariable,
+}
+impl VarSplitSsa {
+ pub fn new(high: (u64, usize), low: (u64, usize)) -> Self {
+ Self {
+ high: get_var_ssa(high.0, high.1),
+ low: get_var_ssa(low.0, low.1),
+ }
+ }
+ pub fn high(&self) -> SSAVariable {
+ self.high
+ }
+ pub fn low(&self) -> SSAVariable {
+ self.low
+ }
+ pub fn lift(self) -> VarSplitSsa {
+ VarSplitSsa {
+ high: self.high(),
+ low: self.low(),
+ }
+ }
+ pub fn operands(&self) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [
+ ("high", MediumLevelILOperand::VarSsa(self.high())),
+ ("low", MediumLevelILOperand::VarSsa(self.low())),
+ ]
+ .into_iter()
+ }
+}
+
+// SET_VAR_SPLIT_SSA
+#[derive(Copy, Clone)]
+pub struct SetVarSplitSsa {
+ high: (u64, usize),
+ low: (u64, usize),
+ src: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedSetVarSplitSsa {
+ pub high: SSAVariable,
+ pub low: SSAVariable,
+ pub src: Box<MediumLevelILLiftedInstruction>,
+}
+impl SetVarSplitSsa {
+ pub fn new(high: (u64, usize), low: (u64, usize), src: usize) -> Self {
+ Self { high, low, src }
+ }
+ pub fn high(&self) -> SSAVariable {
+ get_var_ssa(self.high.0, self.high.1)
+ }
+ pub fn low(&self) -> SSAVariable {
+ get_var_ssa(self.low.0, self.low.1)
+ }
+ pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.src)
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedSetVarSplitSsa {
+ LiftedSetVarSplitSsa {
+ high: self.high(),
+ low: self.low(),
+ src: Box::new(self.src(function).lift()),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [
+ ("high", MediumLevelILOperand::VarSsa(self.high())),
+ ("low", MediumLevelILOperand::VarSsa(self.low())),
+ ("src", MediumLevelILOperand::Expr(self.src(function))),
+ ]
+ .into_iter()
+ }
+}
+
+// ADD, SUB, AND, OR, XOR, LSL, LSR, ASR, ROL, ROR, MUL, MULU_DP, MULS_DP, DIVU, DIVU_DP, DIVS, DIVS_DP, MODU, MODU_DP, MODS, MODS_DP, CMP_E, CMP_NE, CMP_SLT, CMP_ULT, CMP_SLE, CMP_ULE, CMP_SGE, CMP_UGE, CMP_SGT, CMP_UGT, TEST_BIT, ADD_OVERFLOW, FCMP_E, FCMP_NE, FCMP_LT, FCMP_LE, FCMP_GE, FCMP_GT, FCMP_O, FCMP_UO, FADD, FSUB, FMUL, FDIV
+#[derive(Copy, Clone)]
+pub struct BinaryOp {
+ left: usize,
+ right: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedBinaryOp {
+ pub left: Box<MediumLevelILLiftedInstruction>,
+ pub right: Box<MediumLevelILLiftedInstruction>,
+}
+impl BinaryOp {
+ pub fn new(left: usize, right: usize) -> Self {
+ Self { left, right }
+ }
+ pub fn left(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.left)
+ }
+ pub fn right(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.right)
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedBinaryOp {
+ LiftedBinaryOp {
+ left: Box::new(self.left(function).lift()),
+ right: Box::new(self.right(function).lift()),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [
+ ("left", MediumLevelILOperand::Expr(self.left(function))),
+ ("right", MediumLevelILOperand::Expr(self.right(function))),
+ ]
+ .into_iter()
+ }
+}
+
+// ADC, SBB, RLC, RRC
+#[derive(Copy, Clone)]
+pub struct BinaryOpCarry {
+ left: usize,
+ right: usize,
+ carry: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedBinaryOpCarry {
+ pub left: Box<MediumLevelILLiftedInstruction>,
+ pub right: Box<MediumLevelILLiftedInstruction>,
+ pub carry: Box<MediumLevelILLiftedInstruction>,
+}
+impl BinaryOpCarry {
+ pub fn new(left: usize, right: usize, carry: usize) -> Self {
+ Self { left, right, carry }
+ }
+ pub fn left(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.left)
+ }
+ pub fn right(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.right)
+ }
+ pub fn carry(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.carry)
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedBinaryOpCarry {
+ LiftedBinaryOpCarry {
+ left: Box::new(self.left(function).lift()),
+ right: Box::new(self.right(function).lift()),
+ carry: Box::new(self.carry(function).lift()),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [
+ ("left", MediumLevelILOperand::Expr(self.left(function))),
+ ("right", MediumLevelILOperand::Expr(self.right(function))),
+ ("carry", MediumLevelILOperand::Expr(self.carry(function))),
+ ]
+ .into_iter()
+ }
+}
+
+// CALL, TAILCALL
+#[derive(Copy, Clone)]
+pub struct Call {
+ output: (usize, usize),
+ dest: usize,
+ params: (usize, usize),
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedCall {
+ pub output: Vec<Variable>,
+ pub dest: Box<MediumLevelILLiftedInstruction>,
+ pub params: Vec<MediumLevelILLiftedInstruction>,
+}
+impl Call {
+ pub fn new(output: (usize, usize), dest: usize, params: (usize, usize)) -> Self {
+ Self {
+ output,
+ dest,
+ params,
+ }
+ }
+ pub fn output(&self, function: &MediumLevelILFunction) -> OperandVariableList {
+ OperandList::new(function, self.output.1, self.output.0).map_var()
+ }
+ pub fn dest(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.dest)
+ }
+ pub fn params(&self, function: &MediumLevelILFunction) -> OperandExprList {
+ OperandList::new(function, self.params.1, self.params.0).map_expr()
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedCall {
+ LiftedCall {
+ output: self.output(function).collect(),
+ dest: Box::new(self.dest(function).lift()),
+ params: self.params(function).map(|instr| instr.lift()).collect(),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [
+ (
+ "output",
+ MediumLevelILOperand::VarList(self.output(function)),
+ ),
+ ("dest", MediumLevelILOperand::Expr(self.dest(function))),
+ (
+ "params",
+ MediumLevelILOperand::ExprList(self.params(function)),
+ ),
+ ]
+ .into_iter()
+ }
+}
+
+// SYSCALL
+#[derive(Copy, Clone)]
+pub struct Syscall {
+ output: (usize, usize),
+ params: (usize, usize),
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedInnerCall {
+ pub output: Vec<Variable>,
+ pub params: Vec<MediumLevelILLiftedInstruction>,
+}
+impl Syscall {
+ pub fn new(output: (usize, usize), params: (usize, usize)) -> Self {
+ Self { output, params }
+ }
+ pub fn output(&self, function: &MediumLevelILFunction) -> OperandVariableList {
+ OperandList::new(function, self.output.1, self.output.0).map_var()
+ }
+ pub fn params(&self, function: &MediumLevelILFunction) -> OperandExprList {
+ OperandList::new(function, self.params.1, self.params.0).map_expr()
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedInnerCall {
+ LiftedInnerCall {
+ output: self.output(function).collect(),
+ params: self.params(function).map(|instr| instr.lift()).collect(),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ use MediumLevelILOperand::*;
+ [
+ ("output", VarList(self.output(function))),
+ ("params", ExprList(self.params(function))),
+ ]
+ .into_iter()
+ }
+}
+
+// INTRINSIC
+#[derive(Copy, Clone)]
+pub struct Intrinsic {
+ output: (usize, usize),
+ intrinsic: usize,
+ params: (usize, usize),
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct MediumLevelILLiftedIntrinsic {
+ pub output: Vec<Variable>,
+ //pub intrinsic: !,
+ pub params: Vec<MediumLevelILLiftedInstruction>,
+}
+impl Intrinsic {
+ pub fn new(output: (usize, usize), intrinsic: usize, params: (usize, usize)) -> Self {
+ Self {
+ output,
+ intrinsic,
+ params,
+ }
+ }
+ pub fn output(&self, function: &MediumLevelILFunction) -> OperandVariableList {
+ OperandList::new(function, self.output.1, self.output.0).map_var()
+ }
+ pub fn intrinsic(&self, function: &MediumLevelILFunction) -> ! {
+ get_intrinsic(function, self.intrinsic)
+ }
+ pub fn params(&self, function: &MediumLevelILFunction) -> OperandExprList {
+ OperandList::new(function, self.params.1, self.params.0).map_expr()
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedInnerCall {
+ LiftedInnerCall {
+ output: self.output(function).collect(),
+ //intrinsic: get_intrinsic(function, self.intrinsic),
+ params: self.params(function).map(|instr| instr.lift()).collect(),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ use MediumLevelILOperand::*;
+ [
+ ("output", VarList(self.output(function))),
+ //("intrinsic", VarList(self.output(function))),
+ ("params", ExprList(self.params(function))),
+ ]
+ .into_iter()
+ }
+}
+
+// INTRINSIC_SSA
+#[derive(Copy, Clone)]
+pub struct IntrinsicSsa {
+ output: (usize, usize),
+ intrinsic: usize,
+ params: (usize, usize),
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedIntrinsicSsa {
+ pub output: Vec<SSAVariable>,
+ //pub intrinsic: !,
+ pub params: Vec<MediumLevelILLiftedInstruction>,
+}
+impl IntrinsicSsa {
+ pub fn new(output: (usize, usize), intrinsic: usize, params: (usize, usize)) -> Self {
+ Self {
+ output,
+ intrinsic,
+ params,
+ }
+ }
+ pub fn output(&self, function: &MediumLevelILFunction) -> OperandSSAVariableList {
+ OperandList::new(function, self.output.1, self.output.0).map_ssa_var()
+ }
+ pub fn intrinsic(&self, function: &MediumLevelILFunction) -> ! {
+ get_intrinsic(function, self.intrinsic)
+ }
+ pub fn params(&self, function: &MediumLevelILFunction) -> OperandExprList {
+ OperandList::new(function, self.params.1, self.params.0).map_expr()
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedIntrinsicSsa {
+ LiftedIntrinsicSsa {
+ output: self.output(function).collect(),
+ //intrinsic: get_intrinsic(function, self.intrinsic),
+ params: self.params(function).map(|instr| instr.lift()).collect(),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ use MediumLevelILOperand::*;
+ [
+ ("output", VarSsaList(self.output(function))),
+ ("params", ExprList(self.params(function))),
+ ]
+ .into_iter()
+ }
+}
+
+// CALL_SSA, TAILCALL_SSA
+#[derive(Copy, Clone)]
+pub struct CallSsa {
+ output: usize,
+ dest: usize,
+ params: (usize, usize),
+ src_memory: u64,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedCallSsa {
+ pub output: Vec<SSAVariable>,
+ pub dest: Box<MediumLevelILLiftedInstruction>,
+ pub params: Vec<MediumLevelILLiftedInstruction>,
+ pub src_memory: u64,
+}
+impl CallSsa {
+ pub fn new(output: usize, dest: usize, params: (usize, usize), src_memory: u64) -> Self {
+ Self {
+ output,
+ dest,
+ params,
+ src_memory,
+ }
+ }
+ pub fn output(&self, function: &MediumLevelILFunction) -> OperandSSAVariableList {
+ get_call_output_ssa(function, self.output)
+ }
+ pub fn dest(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.dest)
+ }
+ pub fn params(&self, function: &MediumLevelILFunction) -> OperandExprList {
+ OperandList::new(function, self.params.1, self.params.0).map_expr()
+ }
+ pub fn src_memory(&self) -> u64 {
+ self.src_memory
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedCallSsa {
+ LiftedCallSsa {
+ output: self.output(function).collect(),
+ dest: Box::new(self.dest(function).lift()),
+ params: self.params(function).map(|instr| instr.lift()).collect(),
+ src_memory: self.src_memory(),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ use MediumLevelILOperand::*;
+ [
+ ("output", VarSsaList(self.output(function))),
+ ("dest", Expr(self.dest(function))),
+ ("params", ExprList(self.params(function))),
+ ("src_memory", Int(self.src_memory())),
+ ]
+ .into_iter()
+ }
+}
+
+// CALL_UNTYPED_SSA, TAILCALL_UNTYPED_SSA
+#[derive(Copy, Clone)]
+pub struct CallUntypedSsa {
+ output: usize,
+ dest: usize,
+ params: usize,
+ stack: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedCallUntypedSsa {
+ pub output: Vec<SSAVariable>,
+ pub dest: Box<MediumLevelILLiftedInstruction>,
+ pub params: Vec<SSAVariable>,
+ pub stack: Box<MediumLevelILLiftedInstruction>,
+}
+impl CallUntypedSsa {
+ pub fn new(output: usize, dest: usize, params: usize, stack: usize) -> Self {
+ Self {
+ output,
+ dest,
+ params,
+ stack,
+ }
+ }
+ pub fn output(&self, function: &MediumLevelILFunction) -> OperandSSAVariableList {
+ get_call_output_ssa(function, self.output)
+ }
+ pub fn dest(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.dest)
+ }
+ pub fn params(&self, function: &MediumLevelILFunction) -> OperandSSAVariableList {
+ get_call_params_ssa(function, self.params)
+ }
+ pub fn stack(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.stack)
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedCallUntypedSsa {
+ LiftedCallUntypedSsa {
+ output: self.output(function).collect(),
+ dest: Box::new(self.dest(function).lift()),
+ params: self.params(function).collect(),
+ stack: Box::new(self.stack(function).lift()),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ use MediumLevelILOperand::*;
+ [
+ ("output", VarSsaList(self.output(function))),
+ ("dest", Expr(self.dest(function))),
+ ("params", VarSsaList(self.params(function))),
+ ("stack", Expr(self.stack(function))),
+ ]
+ .into_iter()
+ }
+}
+
+// SYSCALL_SSA
+#[derive(Copy, Clone)]
+pub struct SyscallSsa {
+ output: usize,
+ params: (usize, usize),
+ src_memory: u64,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedSyscallSsa {
+ pub output: Vec<SSAVariable>,
+ pub params: Vec<MediumLevelILLiftedInstruction>,
+ pub src_memory: u64,
+}
+impl SyscallSsa {
+ pub fn new(output: usize, params: (usize, usize), src_memory: u64) -> Self {
+ Self {
+ output,
+ params,
+ src_memory,
+ }
+ }
+ pub fn output(&self, function: &MediumLevelILFunction) -> OperandSSAVariableList {
+ get_call_output_ssa(function, self.output)
+ }
+ pub fn params(&self, function: &MediumLevelILFunction) -> OperandExprList {
+ OperandList::new(function, self.params.1, self.params.0).map_expr()
+ }
+ pub fn src_memory(&self) -> u64 {
+ self.src_memory
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedSyscallSsa {
+ LiftedSyscallSsa {
+ output: self.output(function).collect(),
+ params: self.params(function).map(|instr| instr.lift()).collect(),
+ src_memory: self.src_memory(),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ use MediumLevelILOperand::*;
+ [
+ ("output", VarSsaList(self.output(function))),
+ ("params", ExprList(self.params(function))),
+ ("src_memory", MediumLevelILOperand::Int(self.src_memory())),
+ ]
+ .into_iter()
+ }
+}
+
+// SYSCALL_UNTYPED_SSA
+#[derive(Copy, Clone)]
+pub struct SyscallUntypedSsa {
+ output: usize,
+ params: usize,
+ stack: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedSyscallUntypedSsa {
+ pub output: Vec<SSAVariable>,
+ pub params: Vec<SSAVariable>,
+ pub stack: Box<MediumLevelILLiftedInstruction>,
+}
+impl SyscallUntypedSsa {
+ pub fn new(output: usize, params: usize, stack: usize) -> Self {
+ Self {
+ output,
+ params,
+ stack,
+ }
+ }
+ pub fn output(&self, function: &MediumLevelILFunction) -> OperandSSAVariableList {
+ get_call_output_ssa(function, self.output)
+ }
+ pub fn params(&self, function: &MediumLevelILFunction) -> OperandSSAVariableList {
+ get_call_params_ssa(function, self.params)
+ }
+ pub fn stack(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.stack)
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedSyscallUntypedSsa {
+ LiftedSyscallUntypedSsa {
+ output: self.output(function).collect(),
+ params: self.params(function).collect(),
+ stack: Box::new(self.stack(function).lift()),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ use MediumLevelILOperand::*;
+ [
+ ("output", VarSsaList(self.output(function))),
+ ("params", VarSsaList(self.params(function))),
+ ("stack", Expr(self.stack(function))),
+ ]
+ .into_iter()
+ }
+}
+
+// CALL_UNTYPED, TAILCALL_UNTYPED
+#[derive(Copy, Clone)]
+pub struct CallUntyped {
+ output: usize,
+ dest: usize,
+ params: usize,
+ stack: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedCallUntyped {
+ pub output: Vec<Variable>,
+ pub dest: Box<MediumLevelILLiftedInstruction>,
+ pub params: Vec<Variable>,
+ pub stack: Box<MediumLevelILLiftedInstruction>,
+}
+impl CallUntyped {
+ pub fn new(output: usize, dest: usize, params: usize, stack: usize) -> Self {
+ Self {
+ output,
+ dest,
+ params,
+ stack,
+ }
+ }
+ pub fn output(&self, function: &MediumLevelILFunction) -> OperandVariableList {
+ get_call_output(function, self.output)
+ }
+ pub fn dest(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.dest)
+ }
+ pub fn params(&self, function: &MediumLevelILFunction) -> OperandVariableList {
+ get_call_params(function, self.params)
+ }
+ pub fn stack(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.stack)
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedCallUntyped {
+ LiftedCallUntyped {
+ output: self.output(function).collect(),
+ dest: Box::new(self.dest(function).lift()),
+ params: self.params(function).collect(),
+ stack: Box::new(self.stack(function).lift()),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ use MediumLevelILOperand::*;
+ [
+ ("output", VarList(self.output(function))),
+ ("dest", Expr(self.dest(function))),
+ ("params", VarList(self.params(function))),
+ ("stack", Expr(self.stack(function))),
+ ]
+ .into_iter()
+ }
+}
+
+// SYSCALL_UNTYPED
+#[derive(Copy, Clone)]
+pub struct SyscallUntyped {
+ output: usize,
+ params: usize,
+ stack: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedSyscallUntyped {
+ pub output: Vec<Variable>,
+ pub params: Vec<Variable>,
+ pub stack: Box<MediumLevelILLiftedInstruction>,
+}
+impl SyscallUntyped {
+ pub fn new(output: usize, params: usize, stack: usize) -> Self {
+ Self {
+ output,
+ params,
+ stack,
+ }
+ }
+ pub fn output(&self, function: &MediumLevelILFunction) -> OperandVariableList {
+ get_call_output(function, self.output)
+ }
+ pub fn params(&self, function: &MediumLevelILFunction) -> OperandVariableList {
+ get_call_params(function, self.params)
+ }
+ pub fn stack(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.stack)
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedSyscallUntyped {
+ LiftedSyscallUntyped {
+ output: self.output(function).collect(),
+ params: self.params(function).collect(),
+ stack: Box::new(self.stack(function).lift()),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ use MediumLevelILOperand::*;
+ [
+ ("output", VarList(self.output(function))),
+ ("params", VarList(self.params(function))),
+ ("stack", Expr(self.stack(function))),
+ ]
+ .into_iter()
+ }
+}
+
+// NEG, NOT, SX, ZX, LOW_PART, BOOL_TO_INT, UNIMPL_MEM, FSQRT, FNEG, FABS, FLOAT_TO_INT, INT_TO_FLOAT, FLOAT_CONV, ROUND_TO_INT, FLOOR, CEIL, FTRUNC, LOAD
+#[derive(Copy, Clone)]
+pub struct UnaryOp {
+ src: usize,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedUnaryOp {
+ pub src: Box<MediumLevelILLiftedInstruction>,
+}
+impl UnaryOp {
+ pub fn new(src: usize) -> Self {
+ Self { src }
+ }
+ pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.src)
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedUnaryOp {
+ LiftedUnaryOp {
+ src: Box::new(self.src(function).lift()),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [("src", MediumLevelILOperand::Expr(self.src(function)))].into_iter()
+ }
+}
+
+// LOAD_STRUCT
+#[derive(Copy, Clone)]
+pub struct LoadStruct {
+ src: usize,
+ offset: u64,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedLoadStruct {
+ pub src: Box<MediumLevelILLiftedInstruction>,
+ pub offset: u64,
+}
+impl LoadStruct {
+ pub fn new(src: usize, offset: u64) -> Self {
+ Self { src, offset }
+ }
+ pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.src)
+ }
+ pub fn offset(&self) -> u64 {
+ self.offset
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedLoadStruct {
+ LiftedLoadStruct {
+ src: Box::new(self.src(function).lift()),
+ offset: self.offset(),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [
+ ("src", MediumLevelILOperand::Expr(self.src(function))),
+ ("offset", MediumLevelILOperand::Int(self.offset())),
+ ]
+ .into_iter()
+ }
+}
+
+// LOAD_STRUCT_SSA
+#[derive(Copy, Clone)]
+pub struct LoadStructSsa {
+ src: usize,
+ offset: u64,
+ src_memory: u64,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedLoadStructSsa {
+ pub src: Box<MediumLevelILLiftedInstruction>,
+ pub offset: u64,
+ pub src_memory: u64,
+}
+impl LoadStructSsa {
+ pub fn new(src: usize, offset: u64, src_memory: u64) -> Self {
+ Self {
+ src,
+ offset,
+ src_memory,
+ }
+ }
+ pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.src)
+ }
+ pub fn offset(&self) -> u64 {
+ self.offset
+ }
+ pub fn src_memory(&self) -> u64 {
+ self.src_memory
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedLoadStructSsa {
+ LiftedLoadStructSsa {
+ src: Box::new(self.src(function).lift()),
+ offset: self.offset(),
+ src_memory: self.src_memory(),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [
+ ("src", MediumLevelILOperand::Expr(self.src(function))),
+ ("offset", MediumLevelILOperand::Int(self.offset())),
+ ("src_memory", MediumLevelILOperand::Int(self.src_memory())),
+ ]
+ .into_iter()
+ }
+}
+
+// LOAD_SSA
+#[derive(Copy, Clone)]
+pub struct LoadSsa {
+ src: usize,
+ src_memory: u64,
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedLoadSsa {
+ pub src: Box<MediumLevelILLiftedInstruction>,
+ pub src_memory: u64,
+}
+impl LoadSsa {
+ pub fn new(src: usize, src_memory: u64) -> Self {
+ Self { src, src_memory }
+ }
+ pub fn src(&self, function: &MediumLevelILFunction) -> MediumLevelILInstruction {
+ get_operation(function, self.src)
+ }
+ pub fn src_memory(&self) -> u64 {
+ self.src_memory
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedLoadSsa {
+ LiftedLoadSsa {
+ src: Box::new(self.src(function).lift()),
+ src_memory: self.src_memory(),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [
+ ("src", MediumLevelILOperand::Expr(self.src(function))),
+ ("src_memory", MediumLevelILOperand::Int(self.src_memory())),
+ ]
+ .into_iter()
+ }
+}
+
+// RET
+#[derive(Copy, Clone)]
+pub struct Ret {
+ src: (usize, usize),
+}
+#[derive(Clone, Debug, PartialEq)]
+pub struct LiftedRet {
+ pub src: Vec<MediumLevelILLiftedInstruction>,
+}
+impl Ret {
+ pub fn new(src: (usize, usize)) -> Self {
+ Self { src }
+ }
+ pub fn src(&self, function: &MediumLevelILFunction) -> OperandExprList {
+ OperandList::new(function, self.src.1, self.src.0).map_expr()
+ }
+ pub fn lift(&self, function: &MediumLevelILFunction) -> LiftedRet {
+ LiftedRet {
+ src: self.src(function).map(|instr| instr.lift()).collect(),
+ }
+ }
+ pub fn operands(
+ &self,
+ function: &MediumLevelILFunction,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [("src", MediumLevelILOperand::ExprList(self.src(function)))].into_iter()
+ }
+}
+
+// VAR, ADDRESS_OF
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct Var {
+ pub src: Variable,
+}
+impl Var {
+ pub fn new(src: u64) -> Self {
+ Self { src: get_var(src) }
+ }
+ pub fn src(&self) -> Variable {
+ self.src
+ }
+ pub fn operands(
+ &self,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [("src", MediumLevelILOperand::Var(self.src()))].into_iter()
+ }
+}
+
+// VAR_FIELD, ADDRESS_OF_FIELD
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct Field {
+ pub src: Variable,
+ pub offset: u64,
+}
+impl Field {
+ pub fn new(src: u64, offset: u64) -> Self {
+ Self {
+ src: get_var(src),
+ offset,
+ }
+ }
+ pub fn src(&self) -> Variable {
+ self.src
+ }
+ pub fn offset(&self) -> u64 {
+ self.offset
+ }
+ pub fn operands(
+ &self,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [
+ ("src", MediumLevelILOperand::Var(self.src())),
+ ("offset", MediumLevelILOperand::Int(self.offset())),
+ ]
+ .into_iter()
+ }
+}
+
+// VAR_SSA, VAR_ALIASED
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct VarSsa {
+ pub src: SSAVariable,
+}
+impl VarSsa {
+ pub fn new(src: (u64, usize)) -> Self {
+ Self {
+ src: get_var_ssa(src.0, src.1),
+ }
+ }
+ pub fn src(&self) -> SSAVariable {
+ self.src
+ }
+ pub fn operands(
+ &self,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [("src", MediumLevelILOperand::VarSsa(self.src()))].into_iter()
+ }
+}
+
+// VAR_SSA_FIELD, VAR_ALIASED_FIELD
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct VarSsaField {
+ pub src: SSAVariable,
+ pub offset: u64,
+}
+impl VarSsaField {
+ pub fn new(src: (u64, usize), offset: u64) -> Self {
+ Self {
+ src: get_var_ssa(src.0, src.1),
+ offset,
+ }
+ }
+ pub fn src(&self) -> SSAVariable {
+ self.src
+ }
+ pub fn offset(&self) -> u64 {
+ self.offset
+ }
+ pub fn operands(
+ &self,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [
+ ("src", MediumLevelILOperand::VarSsa(self.src())),
+ ("offset", MediumLevelILOperand::Int(self.offset())),
+ ]
+ .into_iter()
+ }
+}
+
+// TRAP
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+pub struct Trap {
+ pub vector: u64,
+}
+impl Trap {
+ pub fn new(vector: u64) -> Self {
+ Self { vector }
+ }
+ pub fn vector(&self) -> u64 {
+ self.vector
+ }
+ pub fn operands(
+ &self,
+ ) -> impl Iterator<Item = (&'static str, MediumLevelILOperand)> {
+ [("vector", MediumLevelILOperand::Int(self.vector()))].into_iter()
+ }
+}
diff --git a/rust/src/types.rs b/rust/src/types.rs
index 5c568142..d86ffc82 100644
--- a/rust/src/types.rs
+++ b/rust/src/types.rs
@@ -29,7 +29,6 @@ use crate::{
};
use lazy_static::lazy_static;
-use std::ptr::null_mut;
use std::{
borrow::Cow,
collections::HashSet,
@@ -1392,6 +1391,21 @@ impl Variable {
}
}
+//////////////
+// SSAVariable
+
+#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq)]
+pub struct SSAVariable {
+ pub variable: Variable,
+ pub version: usize,
+}
+
+impl SSAVariable {
+ pub fn new(variable: Variable, version: usize) -> Self {
+ Self { variable, version }
+ }
+}
+
///////////////
// NamedVariable