Squashed commit of the following:

commit 520c6647c32f02d83083d969d416154aa95e922c
Merge: 6bb29b12 b999f507
Author: mio <mio@lazym.io>
Date:   Sun Apr 13 00:14:23 2025 +0800

    merge dev

commit 6bb29b12f1d9f452365cc9cb5bc2d65ef376af30
Author: mio <mio@lazym.io>
Date:   Sun Apr 13 00:13:12 2025 +0800

    enable test

commit bcb8b363ef12ac295cf4fe4f1645416e5f0ea6ae
Author: mio <mio@lazym.io>
Date:   Sun Apr 13 00:13:06 2025 +0800

    also logging

commit 5972fc156b7379d09582c745d6d597e07555f2f4
Author: mio <mio@lazym.io>
Date:   Sun Apr 13 00:12:58 2025 +0800

    no unlimited translation

commit 7d600feebf9055505918e50d0af8b529a3eba542
Author: mio <mio@lazym.io>
Date:   Sun Apr 13 00:12:47 2025 +0800

    Ignore bindings.rs

commit dde4d50f2c7713156ac3bc284287480e4d92005f
Author: Amaan Qureshi <amaanq12@gmail.com>
Date:   Sun Apr 6 03:26:22 2025 -0400

    alias `uc_mips_reg` to `UC_MIPS_REG`

commit 04234ae01ba7c82d9717eaae64cdda289ce3b832
Author: Amaan Qureshi <amaanq12@gmail.com>
Date:   Sun Apr 6 01:13:00 2025 -0400

    remove bindings.rs

commit edec1300cd7c2d8ef4babbd51f6bcba2e126bdd7
Author: Amaan Qureshi <amaanq12@gmail.com>
Date:   Sat Apr 5 14:29:40 2025 -0400

    address review

commit feb157b28b6c262c5dc3d810ec54de55a25bcd6e
Author: Amaan Qureshi <amaanq12@gmail.com>
Date:   Sat Mar 29 22:40:53 2025 -0400

    ci(rust): rework workflow

    The notable changes are migrating to
    `actions-rust-lang/setup-rust-toolchain` for setting up Rust as it's
    maintained, and using `katyo/publish-crates` for publishing crates in a
    workspace

commit c1c7a8f8ed841b6ec5b4abe57013a1c2c9748c60
Author: Amaan Qureshi <amaanq12@gmail.com>
Date:   Sat Mar 29 22:40:06 2025 -0400

    build(rust): set `rust-version` to 1.85

commit 8df938c9f8b478160213707674157103b0893caf
Author: Amaan Qureshi <amaanq12@gmail.com>
Date:   Sat Mar 29 21:53:21 2025 -0400

    fix(rust): correct unsound pointer cast

    The size of `T` is not guaranteed to be the size of `i32` - all we know
    is that `T` is `Into<i32>`, so we should first copy them over into an
    `i32` array

commit 3059b2583a60aa0cac9278afc945ed87f7ddb65e
Author: Amaan Qureshi <amaanq12@gmail.com>
Date:   Sat Mar 29 20:13:26 2025 -0400

    docs(rust): update readme

commit 7db69a888e58a4bda20083e4e0771d26a327ad13
Author: Amaan Qureshi <amaanq12@gmail.com>
Date:   Sat Mar 29 13:58:30 2025 -0400

    feat(rust): add comprehensive tests

    These tests are copied over from the C tests

commit 78f2207f0e0481aef4de6d5908f8dc699a39a8d5
Author: Amaan Qureshi <amaanq12@gmail.com>
Date:   Sat Mar 29 13:57:27 2025 -0400

    feat(rust): add tcg hook

commit 46e53328531ec3279dadbf18c16b493432227b31
Author: Amaan Qureshi <amaanq12@gmail.com>
Date:   Sat Mar 29 13:56:55 2025 -0400

    feat(rust): add a hook for arm64 sys instructions

commit d1b58ee8282bf1eeeefbf68c87c2cf7c50c90320
Author: Amaan Qureshi <amaanq12@gmail.com>
Date:   Sat Mar 29 13:56:35 2025 -0400

    feat(rust): add the ability to read the arm coprocessor register

commit d304da18b9e6741042b2a70657437be8f39f5c7c
Author: Amaan Qureshi <amaanq12@gmail.com>
Date:   Sat Mar 29 13:55:29 2025 -0400

    feat(rust): add missing `Context` methods

commit 0dd87833081ac9db1feaf5bae8c839a7a2ae4947
Author: Amaan Qureshi <amaanq12@gmail.com>
Date:   Sat Mar 29 13:44:51 2025 -0400

    refactor(rust): remove unnecessary code

    `unicorn-engine-sys` will provide the necessary constants & types

commit da3d2fa7c3ecd3ae8fdb6672b6c5ea23da4570ff
Author: Amaan Qureshi <amaanq12@gmail.com>
Date:   Sat Mar 29 13:43:57 2025 -0400

    feat(rust): add a workspace `Cargo.toml`, and use `unicorn-engine-sys`

commit b27a2a93e4ac43aa2079e936df4dd30a1f8f329a
Author: Amaan Qureshi <amaanq12@gmail.com>
Date:   Sat Mar 29 13:38:06 2025 -0400

    feat(rust): introduce `unicorn-engine-sys` crate

    This crate contains generated Rust bindings to the C library via
    bindgen. It is independent from the main `unicorn-engine` bindings,
    which will leverage this

commit bcec87a3f6e316e328683c303ccfa89e530a6c56
Author: Amaan Qureshi <amaanq12@gmail.com>
Date:   Sat Mar 29 13:31:24 2025 -0400

    test(m68k): actually assert an expectation

    This test did not actually test for anything before

commit bc7e65ca96164496eb2e250b1f296a33a8aa58ee
Author: Amaan Qureshi <amaanq12@gmail.com>
Date:   Sat Mar 29 13:31:09 2025 -0400

    style(test): use bitflag shorthands

commit 0ab4b7fefb3ca17b0b5977d7b204291c5de184ad
Author: Amaan Qureshi <amaanq12@gmail.com>
Date:   Sat Mar 29 13:22:13 2025 -0400

    fix(mips): lowercase enum name `uc_mips_reg`

    This aligns with other architectures

Co-authored-by: Amaan Qureshi <amaanq12@gmail.com>
This commit is contained in:
mio
2025-04-13 00:17:55 +08:00
parent b999f507b9
commit bd5a8c5146
41 changed files with 5033 additions and 4642 deletions

View File

@@ -0,0 +1,55 @@
[package]
name = "unicorn-engine-sys"
version.workspace = true
authors.workspace = true
keywords.workspace = true
categories = [
"api-bindings",
"emulators",
"external-ffi-bindings",
"no-std",
"virtualization",
]
documentation.workspace = true
edition.workspace = true
license.workspace = true
readme = "README.md"
repository.workspace = true
description.workspace = true
links = "unicorn"
[lints]
workspace = true
[build-dependencies]
bindgen = "0.71.1"
cc = { version = "1.2.17" }
cmake = { version = "0.1.54" }
heck = "0.5.0"
pkg-config = { version = "0.3.32" }
[features]
default = ["arch_all"]
dynamic_linkage = []
arch_all = [
"arch_x86",
"arch_arm",
"arch_aarch64",
"arch_riscv",
"arch_mips",
"arch_sparc",
"arch_m68k",
"arch_ppc",
"arch_s390x",
"arch_tricore",
]
arch_x86 = []
arch_arm = []
arch_aarch64 = ["arch_arm"]
arch_riscv = []
arch_mips = []
arch_sparc = []
arch_m68k = []
arch_ppc = []
arch_s390x = []
arch_tricore = []

View File

@@ -0,0 +1,61 @@
# Unicorn-engine-sys
Low-level Rust bindings for the [Unicorn](http://www.unicorn-engine.org/) emulator. This crate only exposes the C API of Unicorn.
Checkout Unicorn2 source code at [dev branch](https://github.com/unicorn-engine/unicorn/tree/dev).
```rust
use unicorn_engine_sys::{
Arch, Mode, uc_close, uc_emu_start, uc_engine, uc_mem_map, uc_mem_write, uc_open,
uc_reg_read, uc_reg_write,
};
fn main() {
let mut uc_engine: *mut uc_engine = std::ptr::null_mut();
let err = unsafe { uc_open(Arch::ARM, Mode::ARM, &raw mut uc_engine) };
assert_eq!(err, uc_error::OK, "Failed to open Unicorn engine");
let code: [u8; 4] = [0x17, 0x00, 0x40, 0xe2]; // sub r0, #23
let err = unsafe { uc_mem_map(uc_engine, CODE_START, 0x1000, Prot::ALL.0) };
assert_eq!(err, uc_error::OK, "Failed to map memory");
let err = unsafe { uc_mem_write(uc_engine, CODE_START, code.as_ptr().cast(), code.len()) };
assert_eq!(err, uc_error::OK, "Failed to write memory");
let mut r0: u64 = 123;
let err = unsafe { uc_reg_write(uc_engine, RegisterARM::R0 as i32, (&raw mut r0).cast()) };
assert_eq!(err, uc_error::OK, "Failed to write R0");
let mut r5: u64 = 1337;
let err = unsafe { uc_reg_write(uc_engine, RegisterARM::R5 as i32, (&raw mut r5).cast()) };
assert_eq!(err, uc_error::OK, "Failed to write R5");
let err = unsafe { uc_emu_start(uc_engine, CODE_START, CODE_START + code.len() as u64, 0, 0) };
assert_eq!(err, uc_error::OK, "Failed to start emulation");
r0 = 0;
let err = unsafe { uc_reg_read(uc_engine, RegisterARM::R0 as i32, (&raw mut r0).cast()) };
assert_eq!(err, uc_error::OK, "Failed to read R0");
r5 = 0;
let err = unsafe { uc_reg_read(uc_engine, RegisterARM::R5 as i32, (&raw mut r5).cast()) };
assert_eq!(err, uc_error::OK, "Failed to read R5");
assert_eq!(r0, 100);
assert_eq!(r5, 1337);
// Clean up
unsafe { uc_close(uc_engine) };
}
```
Further sample code can be found in [tests](./src/tests).
## Usage
Add this to your `Cargo.toml`:
```
[dependencies]
unicorn-engine-sys = "2.2.0"
```

356
bindings/rust/sys/build.rs Normal file
View File

@@ -0,0 +1,356 @@
use std::{env, path::PathBuf, process::Command};
use bindgen::callbacks::{EnumVariantValue, ParseCallbacks};
use heck::ToUpperCamelCase;
fn ninja_available() -> bool {
Command::new("ninja").arg("--version").spawn().is_ok()
}
fn msvc_cmake_tools_available() -> bool {
Command::new("cmake").arg("--version").spawn().is_ok() && ninja_available()
}
fn get_tool_paths_msvc(compiler: &cc::Tool) -> Option<(PathBuf, PathBuf)> {
// If tools are already available, don't need to find them
if msvc_cmake_tools_available() {
return None;
}
let target = env::var("TARGET").unwrap();
let devenv = cc::windows_registry::find_tool(target.as_str(), "devenv");
let tool_root = devenv.map_or_else(
|| {
// if devenv (i.e. Visual Studio) was not found, assume compiler is
// from standalone Build Tools and look there instead.
let tools_name = std::ffi::OsStr::new("BuildTools");
let compiler_path = compiler.path().to_path_buf();
compiler_path
.iter()
.find(|x| *x == tools_name)
.expect("Failed to find devenv or Build Tools");
compiler_path
.iter()
.take_while(|x| *x != tools_name)
.collect::<PathBuf>()
.join(tools_name)
.join(r"Common7\IDE")
},
|devenv_tool| devenv_tool.path().parent().unwrap().to_path_buf(),
);
let cmake_pkg_dir = tool_root.join(r"CommonExtensions\Microsoft\CMake");
let cmake_path = cmake_pkg_dir.join(r"CMake\bin\cmake.exe");
let ninja_path = cmake_pkg_dir.join(r"Ninja\ninja.exe");
assert!(cmake_path.is_file(), "missing cmake");
assert!(ninja_path.is_file(), "missing ninja");
Some((cmake_path, ninja_path))
}
fn build_with_cmake() {
let current_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap());
let uc_dir = current_dir
.parent()
.unwrap()
.parent()
.unwrap()
.parent()
.unwrap();
let compiler = cc::Build::new().get_compiler();
// Initialize configuration
let mut config = cmake::Config::new(uc_dir);
// Check for tools and set up configuration
let has_ninja = if compiler.is_like_msvc() {
// MSVC-specific setup
if let Some((cmake_path, ninja_path)) = get_tool_paths_msvc(&compiler) {
// Tell Cargo where to find the tools instead of modifying PATH
println!("cargo:rustc-env=CMAKE_PATH={}", cmake_path.display());
println!("cargo:rustc-env=NINJA_PATH={}", ninja_path.display());
// Set cmake path for the cmake crate
config.define("CMAKE_PROGRAM", cmake_path.to_str().unwrap());
}
// MSVC-specific linker flags
println!("cargo:rustc-link-arg=/FORCE:MULTIPLE");
true
} else {
// Non-MSVC setup
ninja_available()
};
// GNU-specific linker flags (but not on macOS)
if compiler.is_like_gnu() && env::consts::OS != "macos" {
println!("cargo:rustc-link-arg=-Wl,-allow-multiple-definition");
}
// Configure build generator
if has_ninja {
config.generator("Ninja");
}
let mut archs = String::new();
if std::env::var("CARGO_FEATURE_ARCH_X86").is_ok() {
archs.push_str("x86;");
}
if std::env::var("CARGO_FEATURE_ARCH_ARM").is_ok() {
archs.push_str("arm;");
}
if std::env::var("CARGO_FEATURE_ARCH_AARCH64").is_ok() {
archs.push_str("aarch64;");
}
if std::env::var("CARGO_FEATURE_ARCH_RISCV").is_ok() {
archs.push_str("riscv;");
}
if std::env::var("CARGO_FEATURE_ARCH_MIPS").is_ok() {
archs.push_str("mips;");
}
if std::env::var("CARGO_FEATURE_ARCH_SPARC").is_ok() {
archs.push_str("sparc;");
}
if std::env::var("CARGO_FEATURE_ARCH_M68K").is_ok() {
archs.push_str("m68k;");
}
if std::env::var("CARGO_FEATURE_ARCH_PPC").is_ok() {
archs.push_str("ppc;");
}
if std::env::var("CARGO_FEATURE_ARCH_S390X").is_ok() {
archs.push_str("s390x;");
}
if std::env::var("CARGO_FEATURE_ARCH_TRICORE").is_ok() {
archs.push_str("tricore;");
}
if !archs.is_empty() {
archs.pop();
}
if config.get_profile() == "Debug" {
config.define("UNICORN_LOGGING", "ON");
}
// need to clear build target and append "build" to the path because
// unicorn's CMakeLists.txt doesn't properly support 'install', so we use
// the build artifacts from the build directory, which cmake crate sets
// to "<out_dir>/build/"
let dst = config
.define("UNICORN_BUILD_TESTS", "OFF")
.define("UNICORN_INSTALL", "OFF")
.define("UNICORN_ARCH", archs)
.no_build_target(true)
.build();
println!(
"cargo:rustc-link-search=native={}",
dst.join("build").display()
);
// Lazymio(@wtdcode): Dynamic link may break. See: https://github.com/rust-lang/cargo/issues/5077
if cfg!(feature = "dynamic_linkage") {
if compiler.is_like_msvc() {
println!("cargo:rustc-link-lib=dylib=unicorn-import");
} else {
println!("cargo:rustc-link-lib=dylib=unicorn");
}
} else {
println!("cargo:rustc-link-lib=static=unicorn");
}
if !compiler.is_like_msvc() {
println!("cargo:rustc-link-lib=pthread");
println!("cargo:rustc-link-lib=m");
}
}
#[derive(Debug)]
struct Renamer;
impl ParseCallbacks for Renamer {
fn item_name(&self, original_item_name: &str) -> Option<String> {
// Special case for error type
if original_item_name == "uc_err" {
return Some(String::from("uc_error"));
}
if original_item_name.contains("_cpu_") {
return original_item_name
.strip_prefix("uc_cpu_")
.map(|suffix| format!("{}CpuModel", suffix.to_upper_camel_case()));
}
if original_item_name.ends_with("_reg") {
return original_item_name
.strip_prefix("uc_")
.and_then(|suffix| suffix.strip_suffix("_reg"))
.map(|suffix| format!("Register{}", suffix.to_uppercase()));
}
if original_item_name.ends_with("_insn") {
return original_item_name
.strip_prefix("uc_")
.and_then(|suffix| suffix.strip_suffix("_insn"))
.map(|suffix| format!("{}Insn", suffix.to_upper_camel_case()));
}
if original_item_name.contains("_mode_") {
return original_item_name
.strip_prefix("uc_mode_")
.map(|suffix| format!("{}Mode", suffix.to_upper_camel_case()));
}
// Map various specific types to more idiomatic Rust names
match original_item_name {
"uc_query_type" => Some(String::from("Query")),
"uc_tlb_type" => Some(String::from("TlbType")),
"uc_mem_type" => Some(String::from("MemType")),
"uc_tb" => Some(String::from("TranslationBlock")),
"uc_arch" => Some(String::from("Arch")),
"uc_mode" => Some(String::from("Mode")),
"uc_mem_region" => Some(String::from("MemRegion")),
"uc_prot" => Some(String::from("Prot")),
"uc_hook_type" => Some(String::from("HookType")),
"uc_tlb_entry" => Some(String::from("TlbEntry")),
"uc_control_type" => Some(String::from("ControlType")),
"uc_context_content" => Some(String::from("ContextMode")),
"uc_tcg_op_code" => Some(String::from("TcgOpCode")),
"uc_tcg_op_flag" => Some(String::from("TcgOpFlag")),
_ => None,
}
}
fn enum_variant_name(
&self,
enum_name: Option<&str>,
original_variant_name: &str,
_variant_value: EnumVariantValue,
) -> Option<String> {
if let Some(enum_name) = enum_name {
if enum_name.starts_with("enum uc_") {
// Prefix to strip from enum variant names
let prefix = match enum_name.strip_prefix("enum uc_").unwrap() {
"query_type" => "UC_QUERY",
"tlb_type" => "UC_TLB",
"control_type" => "UC_CTL",
"context_content" => "UC_CTL_CONTEXT",
"err" => "UC_ERR",
"mem_type" | "mem_region" => "UC_MEM",
"arch" => "UC_ARCH",
"mode" => "UC_MODE",
"prot" => "UC_PROT",
"hook_type" => "UC_HOOK",
"x86_insn" => "UC_X86_INS",
"tcg_op_code" => "UC_TCG_OP",
"tcg_op_flag" => "UC_TCG_OP_FLAG",
other => format!("UC_{}", other.to_uppercase()).leak(),
}
.to_string()
+ "_";
// Strip prefix
let mut fixed = original_variant_name
.strip_prefix(&prefix)
.map(str::to_uppercase);
// Special handling for numeric register names in PPC and MIPS
if (enum_name == "enum uc_ppc_reg" || enum_name == "enum uc_mips_reg")
&& fixed.as_ref().is_some_and(|s| s.parse::<u32>().is_ok())
{
fixed = fixed.map(|s| format!("R{s}"));
}
// Special handling for CPU variants that start with a number
if enum_name.contains("cpu")
&& fixed
.as_ref()
.is_some_and(|s| s.chars().next().unwrap().is_ascii_digit())
{
fixed = fixed.map(|s| format!("Model_{s}"));
}
// Special handling for mode values
if enum_name == "enum uc_mode" {
fixed = fixed.map(|s| match s.as_str() {
"16" | "32" | "64" => format!("MODE_{s}"),
_ => s,
});
}
return fixed;
}
}
None
}
}
fn generate_bindings() {
const HEADER_PATH: &str = concat!(
env!("CARGO_MANIFEST_DIR"),
"/../../../include/unicorn/unicorn.h"
);
println!("cargo:rerun-if-changed={HEADER_PATH}");
let bitflag_enums = [
"uc_hook_type",
"uc_tcg_op_flag",
"uc_prot",
"uc_mode",
"uc_context_content",
"uc_control_type",
];
let bindings = bindgen::Builder::default()
.header(HEADER_PATH)
.layout_tests(false)
.allowlist_type("^uc.*")
.allowlist_function("^uc_.*")
.allowlist_var("^uc.*")
.rustified_enum("^uc.*")
.prepend_enum_name(false)
.parse_callbacks(Box::new(Renamer))
.bitfield_enum(bitflag_enums.join("|"))
.derive_ord(true)
.derive_eq(true)
.use_core()
.generate()
.expect("Failed to generate bindings");
let bindings_rs = "src/bindings.rs";
bindings
.write_to_file(bindings_rs)
.unwrap_or_else(|_| panic!("Failed to write bindings into path: {bindings_rs:?}"));
}
fn main() {
generate_bindings();
match pkg_config::Config::new()
.atleast_version("2")
.cargo_metadata(false)
.probe("unicorn")
{
Ok(lib) => {
for dir in lib.link_paths {
println!("cargo:rustc-link-search=native={}", dir.to_str().unwrap());
}
if cfg!(feature = "dynamic_linkage") {
if cc::Build::new().get_compiler().is_like_msvc() {
println!("cargo:rustc-link-lib=dylib=unicorn-import");
} else {
println!("cargo:rustc-link-lib=dylib=unicorn");
}
} else {
println!("cargo:rustc-link-arg=-Wl,-allow-multiple-definition");
println!("cargo:rustc-link-lib=static=unicorn");
println!("cargo:rustc-link-lib=pthread");
println!("cargo:rustc-link-lib=m");
}
}
Err(_) => {
build_with_cmake();
}
}
}

View File

@@ -0,0 +1,342 @@
#![allow(non_camel_case_types)]
mod bindings;
pub use bindings::*;
impl uc_error {
/// Calls `op` if the result is Ok, otherwise returns the [`Err`] value of `self`.
pub fn and_then<U, F: FnOnce() -> Result<U, Self>>(self, op: F) -> Result<U, Self> {
if self == Self::OK { op() } else { Err(self) }
}
/// Returns `res` if the result is Ok, otherwise returns the [`Err`] value of `self`.
/// Arguments passed to this are eagerly evaluated; if you are passing the result
/// of a function call, it is recommended to use [`uc_error::and_then`] instead, as it's lazily
/// evaluated.
pub fn and<U>(self, res: Result<U, Self>) -> Result<U, Self> {
if self == Self::OK { res } else { Err(self) }
}
}
impl From<uc_error> for Result<(), uc_error> {
fn from(value: uc_error) -> Self {
if value == uc_error::OK {
Ok(())
} else {
Err(value)
}
}
}
impl TryFrom<usize> for Arch {
type Error = uc_error;
fn try_from(v: usize) -> Result<Self, Self::Error> {
match v {
x if x == Self::ARM as usize => Ok(Self::ARM),
x if x == Self::ARM64 as usize => Ok(Self::ARM64),
x if x == Self::MIPS as usize => Ok(Self::MIPS),
x if x == Self::X86 as usize => Ok(Self::X86),
x if x == Self::PPC as usize => Ok(Self::PPC),
x if x == Self::SPARC as usize => Ok(Self::SPARC),
x if x == Self::M68K as usize => Ok(Self::M68K),
x if x == Self::RISCV as usize => Ok(Self::RISCV),
x if x == Self::S390X as usize => Ok(Self::S390X),
x if x == Self::TRICORE as usize => Ok(Self::TRICORE),
x if x == Self::MAX as usize => Ok(Self::MAX),
_ => Err(uc_error::ARCH),
}
}
}
impl TryFrom<i32> for Mode {
type Error = uc_error;
#[allow(clippy::cognitive_complexity)]
fn try_from(v: i32) -> Result<Self, Self::Error> {
match v {
x if x == Self::LITTLE_ENDIAN.0 as i32 => Ok(Self::LITTLE_ENDIAN),
x if x == Self::BIG_ENDIAN.0 as i32 => Ok(Self::BIG_ENDIAN),
x if x == Self::ARM.0 as i32 => Ok(Self::ARM),
x if x == Self::THUMB.0 as i32 => Ok(Self::THUMB),
x if x == Self::MCLASS.0 as i32 => Ok(Self::MCLASS),
x if x == Self::V8.0 as i32 => Ok(Self::V8),
x if x == Self::ARMBE8.0 as i32 => Ok(Self::ARMBE8),
x if x == Self::ARM926.0 as i32 => Ok(Self::ARM926),
x if x == Self::ARM946.0 as i32 => Ok(Self::ARM946),
x if x == Self::ARM1176.0 as i32 => Ok(Self::ARM1176),
x if x == Self::MICRO.0 as i32 => Ok(Self::MICRO),
x if x == Self::MIPS3.0 as i32 => Ok(Self::MIPS3),
x if x == Self::MIPS32R6.0 as i32 => Ok(Self::MIPS32R6),
x if x == Self::MIPS32.0 as i32 => Ok(Self::MIPS32),
x if x == Self::MIPS64.0 as i32 => Ok(Self::MIPS64),
x if x == Self::MODE_16.0 as i32 => Ok(Self::MODE_16),
x if x == Self::MODE_32.0 as i32 => Ok(Self::MODE_32),
x if x == Self::MODE_64.0 as i32 => Ok(Self::MODE_64),
x if x == Self::PPC32.0 as i32 => Ok(Self::PPC32),
x if x == Self::PPC64.0 as i32 => Ok(Self::PPC64),
x if x == Self::QPX.0 as i32 => Ok(Self::QPX),
x if x == Self::SPARC32.0 as i32 => Ok(Self::SPARC32),
x if x == Self::SPARC64.0 as i32 => Ok(Self::SPARC64),
x if x == Self::V9.0 as i32 => Ok(Self::V9),
x if x == Self::RISCV32.0 as i32 => Ok(Self::RISCV32),
x if x == Self::RISCV64.0 as i32 => Ok(Self::RISCV64),
_ => Err(uc_error::MODE),
}
}
}
impl HookType {
pub const MEM_UNMAPPED: Self =
Self(Self::MEM_READ_UNMAPPED.0 | Self::MEM_WRITE_UNMAPPED.0 | Self::MEM_FETCH_UNMAPPED.0);
pub const MEM_PROT: Self =
Self(Self::MEM_READ_PROT.0 | Self::MEM_WRITE_PROT.0 | Self::MEM_FETCH_PROT.0);
pub const MEM_VALID: Self = Self(Self::MEM_READ.0 | Self::MEM_WRITE.0 | Self::MEM_FETCH.0);
pub const MEM_READ_INVALID: Self = Self(Self::MEM_READ_UNMAPPED.0 | Self::MEM_READ_PROT.0);
pub const MEM_WRITE_INVALID: Self = Self(Self::MEM_WRITE_UNMAPPED.0 | Self::MEM_WRITE_PROT.0);
pub const MEM_FETCH_INVALID: Self = Self(Self::MEM_FETCH_UNMAPPED.0 | Self::MEM_FETCH_PROT.0);
pub const MEM_INVALID: Self =
Self(Self::MEM_READ_INVALID.0 | Self::MEM_WRITE_INVALID.0 | Self::MEM_FETCH_INVALID.0);
pub const MEM_ALL: Self = Self(Self::MEM_VALID.0 | Self::MEM_INVALID.0);
}
impl ControlType {
pub const IO_READ: Self = Self(1 << 31);
pub const IO_WRITE: Self = Self(1 << 30);
}
impl From<M68kCpuModel> for i32 {
fn from(value: M68kCpuModel) -> Self {
value as Self
}
}
impl From<&M68kCpuModel> for i32 {
fn from(value: &M68kCpuModel) -> Self {
*value as Self
}
}
impl From<X86CpuModel> for i32 {
fn from(value: X86CpuModel) -> Self {
value as Self
}
}
impl From<&X86CpuModel> for i32 {
fn from(value: &X86CpuModel) -> Self {
*value as Self
}
}
impl From<ArmCpuModel> for i32 {
fn from(value: ArmCpuModel) -> Self {
value as Self
}
}
impl From<&ArmCpuModel> for i32 {
fn from(value: &ArmCpuModel) -> Self {
*value as Self
}
}
impl From<Arm64CpuModel> for i32 {
fn from(value: Arm64CpuModel) -> Self {
value as Self
}
}
impl From<&Arm64CpuModel> for i32 {
fn from(value: &Arm64CpuModel) -> Self {
*value as Self
}
}
impl From<Mips32CpuModel> for i32 {
fn from(value: Mips32CpuModel) -> Self {
value as Self
}
}
impl From<&Mips32CpuModel> for i32 {
fn from(value: &Mips32CpuModel) -> Self {
*value as Self
}
}
impl From<Mips64CpuModel> for i32 {
fn from(value: Mips64CpuModel) -> Self {
value as Self
}
}
impl From<&Mips64CpuModel> for i32 {
fn from(value: &Mips64CpuModel) -> Self {
*value as Self
}
}
impl From<Sparc32CpuModel> for i32 {
fn from(value: Sparc32CpuModel) -> Self {
value as Self
}
}
impl From<&Sparc32CpuModel> for i32 {
fn from(value: &Sparc32CpuModel) -> Self {
*value as Self
}
}
impl From<Sparc64CpuModel> for i32 {
fn from(value: Sparc64CpuModel) -> Self {
value as Self
}
}
impl From<&Sparc64CpuModel> for i32 {
fn from(value: &Sparc64CpuModel) -> Self {
*value as Self
}
}
impl From<PpcCpuModel> for i32 {
fn from(value: PpcCpuModel) -> Self {
value as Self
}
}
impl From<&PpcCpuModel> for i32 {
fn from(value: &PpcCpuModel) -> Self {
*value as Self
}
}
impl From<Ppc64CpuModel> for i32 {
fn from(value: Ppc64CpuModel) -> Self {
value as Self
}
}
impl From<&Ppc64CpuModel> for i32 {
fn from(value: &Ppc64CpuModel) -> Self {
*value as Self
}
}
impl From<Riscv32CpuModel> for i32 {
fn from(value: Riscv32CpuModel) -> Self {
value as Self
}
}
impl From<&Riscv32CpuModel> for i32 {
fn from(value: &Riscv32CpuModel) -> Self {
*value as Self
}
}
impl From<Riscv64CpuModel> for i32 {
fn from(value: Riscv64CpuModel) -> Self {
value as Self
}
}
impl From<&Riscv64CpuModel> for i32 {
fn from(value: &Riscv64CpuModel) -> Self {
*value as Self
}
}
impl From<S390xCpuModel> for i32 {
fn from(value: S390xCpuModel) -> Self {
value as Self
}
}
impl From<&S390xCpuModel> for i32 {
fn from(value: &S390xCpuModel) -> Self {
*value as Self
}
}
impl From<TricoreCpuModel> for i32 {
fn from(value: TricoreCpuModel) -> Self {
value as Self
}
}
impl From<&TricoreCpuModel> for i32 {
fn from(value: &TricoreCpuModel) -> Self {
*value as Self
}
}
impl From<RegisterM68K> for i32 {
fn from(value: RegisterM68K) -> Self {
value as Self
}
}
impl From<RegisterX86> for i32 {
fn from(value: RegisterX86) -> Self {
value as Self
}
}
impl From<RegisterARM> for i32 {
fn from(value: RegisterARM) -> Self {
value as Self
}
}
impl From<RegisterARM64> for i32 {
fn from(value: RegisterARM64) -> Self {
value as Self
}
}
impl From<RegisterMIPS> for i32 {
fn from(value: RegisterMIPS) -> Self {
value as Self
}
}
impl From<RegisterSPARC> for i32 {
fn from(value: RegisterSPARC) -> Self {
value as Self
}
}
impl From<RegisterPPC> for i32 {
fn from(value: RegisterPPC) -> Self {
value as Self
}
}
impl From<RegisterRISCV> for i32 {
fn from(value: RegisterRISCV) -> Self {
value as Self
}
}
impl From<RegisterS390X> for i32 {
fn from(value: RegisterS390X) -> Self {
value as Self
}
}
impl From<RegisterTRICORE> for i32 {
fn from(value: RegisterTRICORE) -> Self {
value as Self
}
}