305 lines
7.9 KiB
Rust
305 lines
7.9 KiB
Rust
#![allow(non_camel_case_types)]
|
|
use bitflags::bitflags;
|
|
|
|
pub const API_MAJOR: u64 = 2;
|
|
pub const API_MINOR: u64 = 0;
|
|
pub const VERSION_MAJOR: u64 = 2;
|
|
pub const VERSION_MINOR: u64 = 0;
|
|
pub const VERSION_PATCH: u64 = 0;
|
|
pub const VERSION_EXTRA: u64 = 7;
|
|
pub const SECOND_SCALE: u64 = 1_000_000;
|
|
pub const MILISECOND_SCALE: u64 = 1_000;
|
|
|
|
#[repr(C)]
|
|
#[derive(PartialEq, Debug, Clone, Copy)]
|
|
#[allow(clippy::upper_case_acronyms)]
|
|
pub enum uc_error {
|
|
OK = 0,
|
|
NOMEM = 1,
|
|
ARCH = 2,
|
|
HANDLE = 3,
|
|
MODE = 4,
|
|
VERSION = 5,
|
|
READ_UNMAPPED = 6,
|
|
WRITE_UNMAPPED = 7,
|
|
FETCH_UNMAPPED = 8,
|
|
HOOK = 9,
|
|
INSN_INVALID = 10,
|
|
MAP = 11,
|
|
WRITE_PROT = 12,
|
|
READ_PROT = 13,
|
|
FETCH_PROT = 14,
|
|
ARG = 15,
|
|
READ_UNALIGNED = 16,
|
|
WRITE_UNALIGNED = 17,
|
|
FETCH_UNALIGNED = 18,
|
|
HOOK_EXIST = 19,
|
|
RESOURCE = 20,
|
|
EXCEPTION = 21,
|
|
}
|
|
|
|
impl uc_error {
|
|
/// Calls op if the result is Ok, otherwise returns the Err value of self.
|
|
/// This function can be used for control flow based on Result values.
|
|
pub fn and_then<U, F: FnOnce() -> Result<U, uc_error>>(
|
|
self,
|
|
op: F,
|
|
) -> Result<U, uc_error> {
|
|
if let Self::OK = self {
|
|
op()
|
|
} else {
|
|
Err(self)
|
|
}
|
|
}
|
|
|
|
/// Returns res if the result is Ok, otherwise returns the Err value of self.
|
|
/// Arguments passed to and are eagerly evaluated; if you are passing the result
|
|
/// of a function call, it is recommended to use and_then, which is lazily evaluated.
|
|
pub fn and<U>(
|
|
self,
|
|
res: Result<U, uc_error>,
|
|
) -> Result<U, uc_error> {
|
|
if let Self::OK = self {
|
|
res
|
|
} else {
|
|
Err(self)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<uc_error> for Result<(), uc_error> {
|
|
fn from(value: uc_error) -> Self {
|
|
if let uc_error::OK = value {
|
|
Ok(())
|
|
} else {
|
|
Err(value)
|
|
}
|
|
}
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(PartialEq, Debug, Clone, Copy)]
|
|
pub enum MemType {
|
|
READ = 16,
|
|
WRITE = 17,
|
|
FETCH = 18,
|
|
READ_UNMAPPED = 19,
|
|
WRITE_UNMAPPED = 20,
|
|
FETCH_UNMAPPED = 21,
|
|
WRITE_PROT = 22,
|
|
READ_PROT = 23,
|
|
FETCH_PROT = 24,
|
|
READ_AFTER = 25,
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(PartialEq, Debug, Clone, Copy)]
|
|
pub enum TlbType {
|
|
CPU = 0,
|
|
VIRTUAL = 1,
|
|
}
|
|
|
|
bitflags! {
|
|
#[repr(C)]
|
|
#[derive(Copy, Clone)]
|
|
pub struct HookType: i32 {
|
|
const INTR = 1;
|
|
const INSN = 2;
|
|
const CODE = 4;
|
|
const BLOCK = 8;
|
|
|
|
const MEM_READ_UNMAPPED = 0x10;
|
|
const MEM_WRITE_UNMAPPED = 0x20;
|
|
const MEM_FETCH_UNMAPPED = 0x40;
|
|
const MEM_UNMAPPED = Self::MEM_READ_UNMAPPED.bits() | Self::MEM_WRITE_UNMAPPED.bits() | Self::MEM_FETCH_UNMAPPED.bits();
|
|
|
|
const MEM_READ_PROT = 0x80;
|
|
const MEM_WRITE_PROT = 0x100;
|
|
const MEM_FETCH_PROT = 0x200;
|
|
const MEM_PROT = Self::MEM_READ_PROT.bits() | Self::MEM_WRITE_PROT.bits() | Self::MEM_FETCH_PROT.bits();
|
|
|
|
const MEM_READ = 0x400;
|
|
const MEM_WRITE = 0x800;
|
|
const MEM_FETCH = 0x1000;
|
|
const MEM_VALID = Self::MEM_READ.bits() | Self::MEM_WRITE.bits() | Self::MEM_FETCH.bits();
|
|
|
|
const MEM_READ_AFTER = 0x2000;
|
|
|
|
const INSN_INVALID = 0x4000;
|
|
|
|
const MEM_READ_INVALID = Self::MEM_READ_UNMAPPED.bits() | Self::MEM_READ_PROT.bits();
|
|
const MEM_WRITE_INVALID = Self::MEM_WRITE_UNMAPPED.bits() | Self::MEM_WRITE_PROT.bits();
|
|
const MEM_FETCH_INVALID = Self::MEM_FETCH_UNMAPPED.bits() | Self::MEM_FETCH_PROT.bits();
|
|
const MEM_INVALID = Self::MEM_READ_INVALID.bits() | Self::MEM_WRITE_INVALID.bits() | Self::MEM_FETCH_INVALID.bits();
|
|
|
|
const MEM_ALL = Self::MEM_VALID.bits() | Self::MEM_INVALID.bits();
|
|
|
|
const TLB = (1 << 17);
|
|
}
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(PartialEq, Debug, Clone, Copy)]
|
|
#[allow(clippy::upper_case_acronyms)]
|
|
pub enum Query {
|
|
MODE = 1,
|
|
PAGE_SIZE = 2,
|
|
ARCH = 3,
|
|
TIMEOUT = 4,
|
|
}
|
|
|
|
bitflags! {
|
|
#[repr(C)]
|
|
#[derive(Copy, Clone, Debug)]
|
|
pub struct Permission : u32 {
|
|
const NONE = 0;
|
|
const READ = 1;
|
|
const WRITE = 2;
|
|
const EXEC = 4;
|
|
const ALL = Self::READ.bits() | Self::WRITE.bits() | Self::EXEC.bits();
|
|
}
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Debug, Clone)]
|
|
pub struct MemRegion {
|
|
pub begin: u64,
|
|
pub end: u64,
|
|
pub perms: Permission,
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(PartialEq, Debug, Clone, Copy)]
|
|
pub enum Arch {
|
|
ARM = 1,
|
|
ARM64 = 2,
|
|
MIPS = 3,
|
|
X86 = 4,
|
|
PPC = 5,
|
|
SPARC = 6,
|
|
M68K = 7,
|
|
RISCV = 8,
|
|
S390X = 9,
|
|
TRICORE = 10,
|
|
MAX = 11,
|
|
}
|
|
|
|
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),
|
|
}
|
|
}
|
|
}
|
|
|
|
bitflags! {
|
|
#[derive(Copy, Clone)]
|
|
#[repr(C)]
|
|
pub struct Mode: i32 {
|
|
const LITTLE_ENDIAN = 0;
|
|
const BIG_ENDIAN = 0x4000_0000;
|
|
|
|
const ARM = 0;
|
|
const THUMB = 0x10;
|
|
const MCLASS = 0x20;
|
|
const V8 = 0x40;
|
|
const ARMBE8 = 0x400;
|
|
const ARM926 = 0x80;
|
|
const ARM946 = 0x100;
|
|
const ARM1176 = 0x200;
|
|
const MICRO = Self::THUMB.bits();
|
|
const MIPS3 = Self::MCLASS.bits();
|
|
const MIPS32R6 = Self::V8.bits();
|
|
const MIPS32 = 4;
|
|
const MIPS64 = 8;
|
|
const MODE_16 = 2;
|
|
const MODE_32 = Self::MIPS32.bits();
|
|
const MODE_64 = Self::MIPS64.bits();
|
|
const PPC32 = Self::MIPS32.bits();
|
|
const PPC64 = Self::MIPS64.bits();
|
|
const QPX = Self::THUMB.bits();
|
|
const SPARC32 = Self::MIPS32.bits();
|
|
const SPARC64 = Self::MIPS64.bits();
|
|
const V9 = Self::THUMB.bits();
|
|
const RISCV32 = Self::MIPS32.bits();
|
|
const RISCV64 = Self::MIPS64.bits();
|
|
}
|
|
}
|
|
|
|
// Represent a TranslationBlock.
|
|
#[repr(C)]
|
|
pub struct TranslationBlock {
|
|
pub pc: u64,
|
|
pub icount: u16,
|
|
pub size: u16,
|
|
}
|
|
|
|
macro_rules! UC_CTL_READ {
|
|
($expr:expr) => {
|
|
$expr as u32 | ControlType::UC_CTL_IO_READ as u32
|
|
};
|
|
}
|
|
|
|
macro_rules! UC_CTL_WRITE {
|
|
($expr:expr) => {
|
|
$expr as u32 | ControlType::UC_CTL_IO_WRITE as u32
|
|
};
|
|
}
|
|
|
|
macro_rules! UC_CTL_READ_WRITE {
|
|
($expr:expr) => {
|
|
$expr as u32 | ControlType::UC_CTL_IO_WRITE as u32 | ControlType::UC_CTL_IO_READ as u32
|
|
};
|
|
}
|
|
|
|
#[allow(clippy::upper_case_acronyms)]
|
|
#[repr(u64)]
|
|
pub enum ControlType {
|
|
UC_CTL_UC_MODE = 0,
|
|
UC_CTL_UC_PAGE_SIZE = 1,
|
|
UC_CTL_UC_ARCH = 2,
|
|
UC_CTL_UC_TIMEOUT = 3,
|
|
UC_CTL_UC_USE_EXITS = 4,
|
|
UC_CTL_UC_EXITS_CNT = 5,
|
|
UC_CTL_UC_EXITS = 6,
|
|
UC_CTL_CPU_MODEL = 7,
|
|
UC_CTL_TB_REQUEST_CACHE = 8,
|
|
UC_CTL_TB_REMOVE_CACHE = 9,
|
|
UC_CTL_TB_FLUSH = 10,
|
|
UC_CTL_TLB_FLUSH = 11,
|
|
UC_CTL_TLB_TYPE = 12,
|
|
UC_CTL_TCG_BUFFER_SIZE = 13,
|
|
UC_CTL_CONTEXT_MODE = 14,
|
|
UC_CTL_IO_READ = 1 << 31,
|
|
UC_CTL_IO_WRITE = 1 << 30,
|
|
}
|
|
|
|
bitflags! {
|
|
#[derive(Debug, Copy, Clone)]
|
|
#[repr(C)]
|
|
pub struct ContextMode : u32 {
|
|
const CPU = 1;
|
|
const Memory = 2;
|
|
}
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Debug, Clone, Copy)]
|
|
pub struct TlbEntry {
|
|
pub paddr: u64,
|
|
pub perms: Permission,
|
|
}
|