bindings: add Rust
This commit is contained in:
146
bindings/rust/src/arm.rs
Normal file
146
bindings/rust/src/arm.rs
Normal file
@ -0,0 +1,146 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||
pub enum RegisterARM {
|
||||
// ARM registers
|
||||
INVALID = 0,
|
||||
APSR = 1,
|
||||
APSR_NZCV = 2,
|
||||
CPSR = 3,
|
||||
FPEXC = 4,
|
||||
FPINST = 5,
|
||||
FPSCR = 6,
|
||||
FPSCR_NZCV = 7,
|
||||
FPSID = 8,
|
||||
ITSTATE = 9,
|
||||
LR = 10,
|
||||
PC = 11,
|
||||
SP = 12,
|
||||
SPSR = 13,
|
||||
D0 = 14,
|
||||
D1 = 15,
|
||||
D2 = 16,
|
||||
D3 = 17,
|
||||
D4 = 18,
|
||||
D5 = 19,
|
||||
D6 = 20,
|
||||
D7 = 21,
|
||||
D8 = 22,
|
||||
D9 = 23,
|
||||
D10 = 24,
|
||||
D11 = 25,
|
||||
D12 = 26,
|
||||
D13 = 27,
|
||||
D14 = 28,
|
||||
D15 = 29,
|
||||
D16 = 30,
|
||||
D17 = 31,
|
||||
D18 = 32,
|
||||
D19 = 33,
|
||||
D20 = 34,
|
||||
D21 = 35,
|
||||
D22 = 36,
|
||||
D23 = 37,
|
||||
D24 = 38,
|
||||
D25 = 39,
|
||||
D26 = 40,
|
||||
D27 = 41,
|
||||
D28 = 42,
|
||||
D29 = 43,
|
||||
D30 = 44,
|
||||
D31 = 45,
|
||||
FPINST2 = 46,
|
||||
MVFR0 = 47,
|
||||
MVFR1 = 48,
|
||||
MVFR2 = 49,
|
||||
Q0 = 50,
|
||||
Q1 = 51,
|
||||
Q2 = 52,
|
||||
Q3 = 53,
|
||||
Q4 = 54,
|
||||
Q5 = 55,
|
||||
Q6 = 56,
|
||||
Q7 = 57,
|
||||
Q8 = 58,
|
||||
Q9 = 59,
|
||||
Q10 = 60,
|
||||
Q11 = 61,
|
||||
Q12 = 62,
|
||||
Q13 = 63,
|
||||
Q14 = 64,
|
||||
Q15 = 65,
|
||||
R0 = 66,
|
||||
R1 = 67,
|
||||
R2 = 68,
|
||||
R3 = 69,
|
||||
R4 = 70,
|
||||
R5 = 71,
|
||||
R6 = 72,
|
||||
R7 = 73,
|
||||
R8 = 74,
|
||||
R9 = 75,
|
||||
R10 = 76,
|
||||
R11 = 77,
|
||||
R12 = 78,
|
||||
S0 = 79,
|
||||
S1 = 80,
|
||||
S2 = 81,
|
||||
S3 = 82,
|
||||
S4 = 83,
|
||||
S5 = 84,
|
||||
S6 = 85,
|
||||
S7 = 86,
|
||||
S8 = 87,
|
||||
S9 = 88,
|
||||
S10 = 89,
|
||||
S11 = 90,
|
||||
S12 = 91,
|
||||
S13 = 92,
|
||||
S14 = 93,
|
||||
S15 = 94,
|
||||
S16 = 95,
|
||||
S17 = 96,
|
||||
S18 = 97,
|
||||
S19 = 98,
|
||||
S20 = 99,
|
||||
S21 = 100,
|
||||
S22 = 101,
|
||||
S23 = 102,
|
||||
S24 = 103,
|
||||
S25 = 104,
|
||||
S26 = 105,
|
||||
S27 = 106,
|
||||
S28 = 107,
|
||||
S29 = 108,
|
||||
S30 = 109,
|
||||
S31 = 110,
|
||||
C1_C0_2 = 111,
|
||||
C13_C0_2 = 112,
|
||||
C13_C0_3 = 113,
|
||||
IPSR = 114,
|
||||
MSP = 115,
|
||||
PSP = 116,
|
||||
CONTROL = 117,
|
||||
XPSR = 118,
|
||||
ENDING = 119,
|
||||
// alias registers
|
||||
// (assoc) R13 = 12,
|
||||
// (assoc) R14 = 10,
|
||||
// (assoc) R15 = 11,
|
||||
// (assoc) SB = 75,
|
||||
// (assoc) SL = 76,
|
||||
// (assoc) FP = 77,
|
||||
// (assoc) IP = 78,
|
||||
}
|
||||
|
||||
impl RegisterARM {
|
||||
pub const R13: RegisterARM = RegisterARM::SP;
|
||||
pub const R14: RegisterARM = RegisterARM::LR;
|
||||
pub const R15: RegisterARM = RegisterARM::PC;
|
||||
pub const SB: RegisterARM = RegisterARM::R9;
|
||||
pub const SL: RegisterARM = RegisterARM::R10;
|
||||
pub const FP: RegisterARM = RegisterARM::R11;
|
||||
pub const IP: RegisterARM = RegisterARM::R12;
|
||||
}
|
321
bindings/rust/src/arm64.rs
Normal file
321
bindings/rust/src/arm64.rs
Normal file
@ -0,0 +1,321 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
// ARM64 registers
|
||||
#[repr(C)]
|
||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||
pub enum RegisterARM64 {
|
||||
INVALID = 0,
|
||||
X29 = 1,
|
||||
X30 = 2,
|
||||
NZCV = 3,
|
||||
SP = 4,
|
||||
WSP = 5,
|
||||
WZR = 6,
|
||||
XZR = 7,
|
||||
B0 = 8,
|
||||
B1 = 9,
|
||||
B2 = 10,
|
||||
B3 = 11,
|
||||
B4 = 12,
|
||||
B5 = 13,
|
||||
B6 = 14,
|
||||
B7 = 15,
|
||||
B8 = 16,
|
||||
B9 = 17,
|
||||
B10 = 18,
|
||||
B11 = 19,
|
||||
B12 = 20,
|
||||
B13 = 21,
|
||||
B14 = 22,
|
||||
B15 = 23,
|
||||
B16 = 24,
|
||||
B17 = 25,
|
||||
B18 = 26,
|
||||
B19 = 27,
|
||||
B20 = 28,
|
||||
B21 = 29,
|
||||
B22 = 30,
|
||||
B23 = 31,
|
||||
B24 = 32,
|
||||
B25 = 33,
|
||||
B26 = 34,
|
||||
B27 = 35,
|
||||
B28 = 36,
|
||||
B29 = 37,
|
||||
B30 = 38,
|
||||
B31 = 39,
|
||||
D0 = 40,
|
||||
D1 = 41,
|
||||
D2 = 42,
|
||||
D3 = 43,
|
||||
D4 = 44,
|
||||
D5 = 45,
|
||||
D6 = 46,
|
||||
D7 = 47,
|
||||
D8 = 48,
|
||||
D9 = 49,
|
||||
D10 = 50,
|
||||
D11 = 51,
|
||||
D12 = 52,
|
||||
D13 = 53,
|
||||
D14 = 54,
|
||||
D15 = 55,
|
||||
D16 = 56,
|
||||
D17 = 57,
|
||||
D18 = 58,
|
||||
D19 = 59,
|
||||
D20 = 60,
|
||||
D21 = 61,
|
||||
D22 = 62,
|
||||
D23 = 63,
|
||||
D24 = 64,
|
||||
D25 = 65,
|
||||
D26 = 66,
|
||||
D27 = 67,
|
||||
D28 = 68,
|
||||
D29 = 69,
|
||||
D30 = 70,
|
||||
D31 = 71,
|
||||
H0 = 72,
|
||||
H1 = 73,
|
||||
H2 = 74,
|
||||
H3 = 75,
|
||||
H4 = 76,
|
||||
H5 = 77,
|
||||
H6 = 78,
|
||||
H7 = 79,
|
||||
H8 = 80,
|
||||
H9 = 81,
|
||||
H10 = 82,
|
||||
H11 = 83,
|
||||
H12 = 84,
|
||||
H13 = 85,
|
||||
H14 = 86,
|
||||
H15 = 87,
|
||||
H16 = 88,
|
||||
H17 = 89,
|
||||
H18 = 90,
|
||||
H19 = 91,
|
||||
H20 = 92,
|
||||
H21 = 93,
|
||||
H22 = 94,
|
||||
H23 = 95,
|
||||
H24 = 96,
|
||||
H25 = 97,
|
||||
H26 = 98,
|
||||
H27 = 99,
|
||||
H28 = 100,
|
||||
H29 = 101,
|
||||
H30 = 102,
|
||||
H31 = 103,
|
||||
Q0 = 104,
|
||||
Q1 = 105,
|
||||
Q2 = 106,
|
||||
Q3 = 107,
|
||||
Q4 = 108,
|
||||
Q5 = 109,
|
||||
Q6 = 110,
|
||||
Q7 = 111,
|
||||
Q8 = 112,
|
||||
Q9 = 113,
|
||||
Q10 = 114,
|
||||
Q11 = 115,
|
||||
Q12 = 116,
|
||||
Q13 = 117,
|
||||
Q14 = 118,
|
||||
Q15 = 119,
|
||||
Q16 = 120,
|
||||
Q17 = 121,
|
||||
Q18 = 122,
|
||||
Q19 = 123,
|
||||
Q20 = 124,
|
||||
Q21 = 125,
|
||||
Q22 = 126,
|
||||
Q23 = 127,
|
||||
Q24 = 128,
|
||||
Q25 = 129,
|
||||
Q26 = 130,
|
||||
Q27 = 131,
|
||||
Q28 = 132,
|
||||
Q29 = 133,
|
||||
Q30 = 134,
|
||||
Q31 = 135,
|
||||
S0 = 136,
|
||||
S1 = 137,
|
||||
S2 = 138,
|
||||
S3 = 139,
|
||||
S4 = 140,
|
||||
S5 = 141,
|
||||
S6 = 142,
|
||||
S7 = 143,
|
||||
S8 = 144,
|
||||
S9 = 145,
|
||||
S10 = 146,
|
||||
S11 = 147,
|
||||
S12 = 148,
|
||||
S13 = 149,
|
||||
S14 = 150,
|
||||
S15 = 151,
|
||||
S16 = 152,
|
||||
S17 = 153,
|
||||
S18 = 154,
|
||||
S19 = 155,
|
||||
S20 = 156,
|
||||
S21 = 157,
|
||||
S22 = 158,
|
||||
S23 = 159,
|
||||
S24 = 160,
|
||||
S25 = 161,
|
||||
S26 = 162,
|
||||
S27 = 163,
|
||||
S28 = 164,
|
||||
S29 = 165,
|
||||
S30 = 166,
|
||||
S31 = 167,
|
||||
W0 = 168,
|
||||
W1 = 169,
|
||||
W2 = 170,
|
||||
W3 = 171,
|
||||
W4 = 172,
|
||||
W5 = 173,
|
||||
W6 = 174,
|
||||
W7 = 175,
|
||||
W8 = 176,
|
||||
W9 = 177,
|
||||
W10 = 178,
|
||||
W11 = 179,
|
||||
W12 = 180,
|
||||
W13 = 181,
|
||||
W14 = 182,
|
||||
W15 = 183,
|
||||
W16 = 184,
|
||||
W17 = 185,
|
||||
W18 = 186,
|
||||
W19 = 187,
|
||||
W20 = 188,
|
||||
W21 = 189,
|
||||
W22 = 190,
|
||||
W23 = 191,
|
||||
W24 = 192,
|
||||
W25 = 193,
|
||||
W26 = 194,
|
||||
W27 = 195,
|
||||
W28 = 196,
|
||||
W29 = 197,
|
||||
W30 = 198,
|
||||
X0 = 199,
|
||||
X1 = 200,
|
||||
X2 = 201,
|
||||
X3 = 202,
|
||||
X4 = 203,
|
||||
X5 = 204,
|
||||
X6 = 205,
|
||||
X7 = 206,
|
||||
X8 = 207,
|
||||
X9 = 208,
|
||||
X10 = 209,
|
||||
X11 = 210,
|
||||
X12 = 211,
|
||||
X13 = 212,
|
||||
X14 = 213,
|
||||
X15 = 214,
|
||||
X16 = 215,
|
||||
X17 = 216,
|
||||
X18 = 217,
|
||||
X19 = 218,
|
||||
X20 = 219,
|
||||
X21 = 220,
|
||||
X22 = 221,
|
||||
X23 = 222,
|
||||
X24 = 223,
|
||||
X25 = 224,
|
||||
X26 = 225,
|
||||
X27 = 226,
|
||||
X28 = 227,
|
||||
V0 = 228,
|
||||
V1 = 229,
|
||||
V2 = 230,
|
||||
V3 = 231,
|
||||
V4 = 232,
|
||||
V5 = 233,
|
||||
V6 = 234,
|
||||
V7 = 235,
|
||||
V8 = 236,
|
||||
V9 = 237,
|
||||
V10 = 238,
|
||||
V11 = 239,
|
||||
V12 = 240,
|
||||
V13 = 241,
|
||||
V14 = 242,
|
||||
V15 = 243,
|
||||
V16 = 244,
|
||||
V17 = 245,
|
||||
V18 = 246,
|
||||
V19 = 247,
|
||||
V20 = 248,
|
||||
V21 = 249,
|
||||
V22 = 250,
|
||||
V23 = 251,
|
||||
V24 = 252,
|
||||
V25 = 253,
|
||||
V26 = 254,
|
||||
V27 = 255,
|
||||
V28 = 256,
|
||||
V29 = 257,
|
||||
V30 = 258,
|
||||
V31 = 259,
|
||||
|
||||
// pseudo registers
|
||||
PC = 260,
|
||||
CPACR_EL1 = 261,
|
||||
|
||||
// thread registers
|
||||
TPIDR_EL0 = 262,
|
||||
TPIDRRO_EL0 = 263,
|
||||
TPIDR_EL1 = 264,
|
||||
PSTATE = 265,
|
||||
|
||||
// exception link registers
|
||||
ELR_EL0 = 266,
|
||||
ELR_EL1 = 267,
|
||||
ELR_EL2 = 268,
|
||||
ELR_EL3 = 269,
|
||||
|
||||
// stack pointers registers
|
||||
SP_EL0 = 270,
|
||||
SP_EL1 = 271,
|
||||
SP_EL2 = 272,
|
||||
SP_EL3 = 273,
|
||||
|
||||
// other CP15 registers
|
||||
TTBR0_EL1 = 274,
|
||||
TTBR1_EL1 = 275,
|
||||
ESR_EL0 = 276,
|
||||
ESR_EL1 = 277,
|
||||
ESR_EL2 = 278,
|
||||
ESR_EL3 = 279,
|
||||
FAR_EL0 = 280,
|
||||
FAR_EL1 = 281,
|
||||
FAR_EL2 = 282,
|
||||
FAR_EL3 = 283,
|
||||
PAR_EL1 = 284,
|
||||
MAIR_EL1 = 285,
|
||||
VBAR_EL0 = 286,
|
||||
VBAR_EL1 = 287,
|
||||
VBAR_EL2 = 288,
|
||||
VBAR_EL3 = 289,
|
||||
ENDING = 290,
|
||||
|
||||
// alias registers
|
||||
// (assoc) IP0 = 215,
|
||||
// (assoc) IP1 = 216,
|
||||
// (assoc) FP = 1,
|
||||
// (assoc) LR = 2,
|
||||
}
|
||||
|
||||
impl RegisterARM64 {
|
||||
pub const IP0: RegisterARM64 = RegisterARM64::X16;
|
||||
pub const IP1: RegisterARM64 = RegisterARM64::X17;
|
||||
pub const FP: RegisterARM64 = RegisterARM64::X29;
|
||||
pub const LR: RegisterARM64 = RegisterARM64::X30;
|
||||
}
|
230
bindings/rust/src/ffi.rs
Normal file
230
bindings/rust/src/ffi.rs
Normal file
@ -0,0 +1,230 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
use super::unicorn_const::*;
|
||||
use libc::{c_char, c_int};
|
||||
use std::ffi::c_void;
|
||||
use std::pin::Pin;
|
||||
|
||||
pub type uc_handle = *mut c_void;
|
||||
pub type uc_hook = *mut c_void;
|
||||
pub type uc_context = libc::size_t;
|
||||
|
||||
extern "C" {
|
||||
pub fn uc_version(major: *mut u32, minor: *mut u32) -> u32;
|
||||
pub fn uc_arch_supported(arch: Arch) -> bool;
|
||||
pub fn uc_open(arch: Arch, mode: Mode, engine: *mut uc_handle) -> uc_error;
|
||||
pub fn uc_close(engine: uc_handle) -> uc_error;
|
||||
pub fn uc_context_free(mem: uc_context) -> uc_error;
|
||||
pub fn uc_errno(engine: uc_handle) -> uc_error;
|
||||
pub fn uc_strerror(error_code: uc_error) -> *const c_char;
|
||||
pub fn uc_reg_write(engine: uc_handle, regid: c_int, value: *const c_void) -> uc_error;
|
||||
pub fn uc_reg_read(engine: uc_handle, regid: c_int, value: *mut c_void) -> uc_error;
|
||||
pub fn uc_mem_write(
|
||||
engine: uc_handle,
|
||||
address: u64,
|
||||
bytes: *const u8,
|
||||
size: libc::size_t,
|
||||
) -> uc_error;
|
||||
pub fn uc_mem_read(
|
||||
engine: uc_handle,
|
||||
address: u64,
|
||||
bytes: *mut u8,
|
||||
size: libc::size_t,
|
||||
) -> uc_error;
|
||||
pub fn uc_mem_map(engine: uc_handle, address: u64, size: libc::size_t, perms: u32) -> uc_error;
|
||||
pub fn uc_mem_map_ptr(
|
||||
engine: uc_handle,
|
||||
address: u64,
|
||||
size: libc::size_t,
|
||||
perms: u32,
|
||||
ptr: *mut c_void,
|
||||
) -> uc_error;
|
||||
pub fn uc_mem_unmap(engine: uc_handle, address: u64, size: libc::size_t) -> uc_error;
|
||||
pub fn uc_mem_protect(
|
||||
engine: uc_handle,
|
||||
address: u64,
|
||||
size: libc::size_t,
|
||||
perms: u32,
|
||||
) -> uc_error;
|
||||
pub fn uc_mem_regions(
|
||||
engine: uc_handle,
|
||||
regions: *const *const MemRegion,
|
||||
count: *mut u32,
|
||||
) -> uc_error;
|
||||
pub fn uc_emu_start(
|
||||
engine: uc_handle,
|
||||
begin: u64,
|
||||
until: u64,
|
||||
timeout: u64,
|
||||
count: libc::size_t,
|
||||
) -> uc_error;
|
||||
pub fn uc_emu_stop(engine: uc_handle) -> uc_error;
|
||||
pub fn uc_hook_add(
|
||||
engine: uc_handle,
|
||||
hook: *mut uc_hook,
|
||||
hook_type: HookType,
|
||||
callback: *mut c_void,
|
||||
user_data: *mut c_void,
|
||||
begin: u64,
|
||||
end: u64,
|
||||
...
|
||||
) -> uc_error;
|
||||
pub fn uc_hook_del(engine: uc_handle, hook: uc_hook) -> uc_error;
|
||||
pub fn uc_query(engine: uc_handle, query_type: Query, result: *mut libc::size_t) -> uc_error;
|
||||
pub fn uc_context_alloc(engine: uc_handle, context: *mut uc_context) -> uc_error;
|
||||
pub fn uc_context_save(engine: uc_handle, context: uc_context) -> uc_error;
|
||||
pub fn uc_context_restore(engine: uc_handle, context: uc_context) -> uc_error;
|
||||
}
|
||||
|
||||
pub struct CodeHook {
|
||||
pub unicorn: *mut crate::UnicornInner,
|
||||
pub callback: Box<dyn FnMut(crate::UnicornHandle, u64, u32)>,
|
||||
}
|
||||
|
||||
pub struct BlockHook {
|
||||
pub unicorn: *mut crate::UnicornInner,
|
||||
pub callback: Box<dyn FnMut(crate::UnicornHandle, u64, u32)>,
|
||||
}
|
||||
|
||||
pub struct MemHook {
|
||||
pub unicorn: *mut crate::UnicornInner,
|
||||
pub callback: Box<dyn FnMut(crate::UnicornHandle, MemType, u64, usize, i64)>,
|
||||
}
|
||||
|
||||
pub struct InterruptHook {
|
||||
pub unicorn: *mut crate::UnicornInner,
|
||||
pub callback: Box<dyn FnMut(crate::UnicornHandle, u32)>,
|
||||
}
|
||||
|
||||
pub struct InstructionInHook {
|
||||
pub unicorn: *mut crate::UnicornInner,
|
||||
pub callback: Box<dyn FnMut(crate::UnicornHandle, u32, usize)>,
|
||||
}
|
||||
|
||||
pub struct InstructionOutHook {
|
||||
pub unicorn: *mut crate::UnicornInner,
|
||||
pub callback: Box<dyn FnMut(crate::UnicornHandle, u32, usize, u32)>,
|
||||
}
|
||||
|
||||
pub struct InstructionSysHook {
|
||||
pub unicorn: *mut crate::UnicornInner,
|
||||
pub callback: Box<dyn FnMut(crate::UnicornHandle)>,
|
||||
}
|
||||
|
||||
pub extern "C" fn code_hook_proxy(
|
||||
uc: uc_handle,
|
||||
address: u64,
|
||||
size: u32,
|
||||
user_data: *mut CodeHook,
|
||||
) {
|
||||
let unicorn = unsafe { &mut *(*user_data).unicorn };
|
||||
let callback = &mut unsafe { &mut *(*user_data).callback };
|
||||
assert_eq!(uc, unicorn.uc);
|
||||
callback(
|
||||
crate::UnicornHandle {
|
||||
inner: unsafe { Pin::new_unchecked(unicorn) },
|
||||
},
|
||||
address,
|
||||
size,
|
||||
);
|
||||
}
|
||||
|
||||
pub extern "C" fn block_hook_proxy(
|
||||
uc: uc_handle,
|
||||
address: u64,
|
||||
size: u32,
|
||||
user_data: *mut BlockHook,
|
||||
) {
|
||||
let unicorn = unsafe { &mut *(*user_data).unicorn };
|
||||
let callback = &mut unsafe { &mut *(*user_data).callback };
|
||||
assert_eq!(uc, unicorn.uc);
|
||||
callback(
|
||||
crate::UnicornHandle {
|
||||
inner: unsafe { Pin::new_unchecked(unicorn) },
|
||||
},
|
||||
address,
|
||||
size,
|
||||
);
|
||||
}
|
||||
|
||||
pub extern "C" fn mem_hook_proxy(
|
||||
uc: uc_handle,
|
||||
mem_type: MemType,
|
||||
address: u64,
|
||||
size: u32,
|
||||
value: i64,
|
||||
user_data: *mut MemHook,
|
||||
) {
|
||||
let unicorn = unsafe { &mut *(*user_data).unicorn };
|
||||
let callback = &mut unsafe { &mut *(*user_data).callback };
|
||||
assert_eq!(uc, unicorn.uc);
|
||||
callback(
|
||||
crate::UnicornHandle {
|
||||
inner: unsafe { Pin::new_unchecked(unicorn) },
|
||||
},
|
||||
mem_type,
|
||||
address,
|
||||
size as usize,
|
||||
value,
|
||||
);
|
||||
}
|
||||
|
||||
pub extern "C" fn intr_hook_proxy(uc: uc_handle, value: u32, user_data: *mut InterruptHook) {
|
||||
let unicorn = unsafe { &mut *(*user_data).unicorn };
|
||||
let callback = &mut unsafe { &mut *(*user_data).callback };
|
||||
assert_eq!(uc, unicorn.uc);
|
||||
callback(
|
||||
crate::UnicornHandle {
|
||||
inner: unsafe { Pin::new_unchecked(unicorn) },
|
||||
},
|
||||
value,
|
||||
);
|
||||
}
|
||||
|
||||
pub extern "C" fn insn_in_hook_proxy(
|
||||
uc: uc_handle,
|
||||
port: u32,
|
||||
size: usize,
|
||||
user_data: *mut InstructionInHook,
|
||||
) {
|
||||
let unicorn = unsafe { &mut *(*user_data).unicorn };
|
||||
let callback = &mut unsafe { &mut *(*user_data).callback };
|
||||
assert_eq!(uc, unicorn.uc);
|
||||
callback(
|
||||
crate::UnicornHandle {
|
||||
inner: unsafe { Pin::new_unchecked(unicorn) },
|
||||
},
|
||||
port,
|
||||
size,
|
||||
);
|
||||
}
|
||||
|
||||
pub extern "C" fn insn_out_hook_proxy(
|
||||
uc: uc_handle,
|
||||
port: u32,
|
||||
size: usize,
|
||||
value: u32,
|
||||
user_data: *mut InstructionOutHook,
|
||||
) {
|
||||
let unicorn = unsafe { &mut *(*user_data).unicorn };
|
||||
let callback = &mut unsafe { &mut *(*user_data).callback };
|
||||
assert_eq!(uc, unicorn.uc);
|
||||
callback(
|
||||
crate::UnicornHandle {
|
||||
inner: unsafe { Pin::new_unchecked(unicorn) },
|
||||
},
|
||||
port,
|
||||
size,
|
||||
value,
|
||||
);
|
||||
}
|
||||
|
||||
pub extern "C" fn insn_sys_hook_proxy(uc: uc_handle, user_data: *mut InstructionSysHook) {
|
||||
let unicorn = unsafe { &mut *(*user_data).unicorn };
|
||||
let callback = &mut unsafe { &mut *(*user_data).callback };
|
||||
assert_eq!(uc, unicorn.uc);
|
||||
callback(crate::UnicornHandle {
|
||||
inner: unsafe { Pin::new_unchecked(unicorn) },
|
||||
});
|
||||
}
|
784
bindings/rust/src/lib.rs
Normal file
784
bindings/rust/src/lib.rs
Normal file
@ -0,0 +1,784 @@
|
||||
//! Bindings for the Unicorn emulator.
|
||||
//!
|
||||
//!
|
||||
//!
|
||||
//! # Example use
|
||||
//!
|
||||
//! ```rust
|
||||
//!
|
||||
//! use unicorn::RegisterARM;
|
||||
//! use unicorn::unicorn_const::{Arch, Mode, Permission, SECOND_SCALE};
|
||||
//!
|
||||
//! fn main() {
|
||||
//! let arm_code32: Vec<u8> = vec![0x17, 0x00, 0x40, 0xe2]; // sub r0, #23
|
||||
//!
|
||||
//! let mut unicorn = unicorn::Unicorn::new(Arch::ARM, Mode::LITTLE_ENDIAN).expect("failed to initialize Unicorn instance");
|
||||
//! let mut emu = unicorn.borrow();
|
||||
//! emu.mem_map(0x1000, 0x4000, Permission::ALL).expect("failed to map code page");
|
||||
//! emu.mem_write(0x1000, &arm_code32).expect("failed to write instructions");
|
||||
//!
|
||||
//! emu.reg_write(RegisterARM::R0 as i32, 123).expect("failed write R0");
|
||||
//! emu.reg_write(RegisterARM::R5 as i32, 1337).expect("failed write R5");
|
||||
//!
|
||||
//! let _ = emu.emu_start(0x1000, (0x1000 + arm_code32.len()) as u64, 10 * SECOND_SCALE, 1000);
|
||||
//! assert_eq!(emu.reg_read(RegisterARM::R0 as i32), Ok(100));
|
||||
//! assert_eq!(emu.reg_read(RegisterARM::R5 as i32), Ok(1337));
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
|
||||
mod ffi;
|
||||
pub mod unicorn_const;
|
||||
|
||||
mod arm;
|
||||
mod arm64;
|
||||
mod m68k;
|
||||
mod mips;
|
||||
mod ppc;
|
||||
mod sparc;
|
||||
mod x86;
|
||||
pub use crate::{arm::*, arm64::*, m68k::*, mips::*, ppc::*, sparc::*, x86::*};
|
||||
|
||||
use ffi::uc_handle;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::c_void;
|
||||
use std::marker::PhantomPinned;
|
||||
use std::pin::Pin;
|
||||
use unicorn_const::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Context {
|
||||
context: ffi::uc_context,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn new() -> Self {
|
||||
Context { context: 0 }
|
||||
}
|
||||
pub fn is_initialized(&self) -> bool {
|
||||
self.context != 0
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Context {
|
||||
fn drop(&mut self) {
|
||||
unsafe { ffi::uc_context_free(self.context) };
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// A Unicorn emulator instance.
|
||||
pub struct Unicorn {
|
||||
inner: Pin<Box<UnicornInner>>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
/// Handle used to safely access exposed functions and data of a Unicorn instance.
|
||||
pub struct UnicornHandle<'a> {
|
||||
inner: Pin<&'a mut UnicornInner>,
|
||||
}
|
||||
|
||||
/// Internal Management struct
|
||||
pub struct UnicornInner {
|
||||
pub uc: uc_handle,
|
||||
pub arch: Arch,
|
||||
pub code_hooks: HashMap<*mut libc::c_void, Box<ffi::CodeHook>>,
|
||||
pub block_hooks: HashMap<*mut libc::c_void, Box<ffi::BlockHook>>,
|
||||
pub mem_hooks: HashMap<*mut libc::c_void, Box<ffi::MemHook>>,
|
||||
pub intr_hooks: HashMap<*mut libc::c_void, Box<ffi::InterruptHook>>,
|
||||
pub insn_in_hooks: HashMap<*mut libc::c_void, Box<ffi::InstructionInHook>>,
|
||||
pub insn_out_hooks: HashMap<*mut libc::c_void, Box<ffi::InstructionOutHook>>,
|
||||
pub insn_sys_hooks: HashMap<*mut libc::c_void, Box<ffi::InstructionSysHook>>,
|
||||
_pin: PhantomPinned,
|
||||
}
|
||||
|
||||
impl Unicorn {
|
||||
/// Create a new instance of the unicorn engine for the specified architecture
|
||||
/// and hardware mode.
|
||||
pub fn new(arch: Arch, mode: Mode) -> Result<Unicorn, uc_error> {
|
||||
let mut handle = std::ptr::null_mut();
|
||||
let err = unsafe { ffi::uc_open(arch, mode, &mut handle) };
|
||||
if err == uc_error::OK {
|
||||
Ok(Unicorn {
|
||||
inner: Box::pin(UnicornInner {
|
||||
uc: handle,
|
||||
arch: arch,
|
||||
code_hooks: HashMap::new(),
|
||||
block_hooks: HashMap::new(),
|
||||
mem_hooks: HashMap::new(),
|
||||
intr_hooks: HashMap::new(),
|
||||
insn_in_hooks: HashMap::new(),
|
||||
insn_out_hooks: HashMap::new(),
|
||||
insn_sys_hooks: HashMap::new(),
|
||||
_pin: std::marker::PhantomPinned,
|
||||
}),
|
||||
})
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn borrow<'a>(&'a mut self) -> UnicornHandle<'a> {
|
||||
UnicornHandle {
|
||||
inner: self.inner.as_mut(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Unicorn {
|
||||
fn drop(&mut self) {
|
||||
unsafe { ffi::uc_close(self.inner.uc) };
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for UnicornInner {
|
||||
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
write!(formatter, "Unicorn {{ uc: {:p} }}", self.uc)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> UnicornHandle<'a> {
|
||||
|
||||
/// Return the architecture of the current emulator.
|
||||
pub fn get_arch(&self) -> Arch {
|
||||
self.inner.arch
|
||||
}
|
||||
|
||||
/// Returns a vector with the memory regions that are mapped in the emulator.
|
||||
pub fn mem_regions(&self) -> Result<Vec<MemRegion>, uc_error> {
|
||||
let mut nb_regions: u32 = 0;
|
||||
let mut p_regions: *const MemRegion = std::ptr::null_mut();
|
||||
let err = unsafe { ffi::uc_mem_regions(self.inner.uc, &mut p_regions, &mut nb_regions) };
|
||||
if err == uc_error::OK {
|
||||
let mut regions = Vec::new();
|
||||
for i in 0..nb_regions {
|
||||
regions.push(unsafe { std::mem::transmute_copy(&*p_regions.offset(i as isize)) });
|
||||
}
|
||||
unsafe { libc::free(p_regions as _) };
|
||||
Ok(regions)
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a range of bytes from memory at the specified address.
|
||||
pub fn mem_read(&self, address: u64, buf: &mut [u8]) -> Result<(), uc_error> {
|
||||
let err = unsafe { ffi::uc_mem_read(self.inner.uc, address, buf.as_mut_ptr(), buf.len()) };
|
||||
if err == uc_error::OK {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Return a range of bytes from memory at the specified address as vector.
|
||||
pub fn mem_read_as_vec(&self, address: u64, size: usize) -> Result<Vec<u8>, uc_error> {
|
||||
let mut buf = vec![0; size];
|
||||
let err = unsafe { ffi::uc_mem_read(self.inner.uc, address, buf.as_mut_ptr(), size) };
|
||||
if err == uc_error::OK {
|
||||
Ok(buf)
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mem_write(&mut self, address: u64, bytes: &[u8]) -> Result<(), uc_error> {
|
||||
let err = unsafe { ffi::uc_mem_write(self.inner.uc, address, bytes.as_ptr(), bytes.len()) };
|
||||
if err == uc_error::OK {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Map an existing memory region in the emulator at the specified address.
|
||||
///
|
||||
/// This function is marked unsafe because it is the responsibility of the caller to
|
||||
/// ensure that `size` matches the size of the passed buffer, an invalid `size` value will
|
||||
/// likely cause a crash in unicorn.
|
||||
///
|
||||
/// `address` must be aligned to 4kb or this will return `Error::ARG`.
|
||||
///
|
||||
/// `size` must be a multiple of 4kb or this will return `Error::ARG`.
|
||||
///
|
||||
/// `ptr` is a pointer to the provided memory region that will be used by the emulator.
|
||||
pub fn mem_map_ptr(
|
||||
&mut self,
|
||||
address: u64,
|
||||
size: usize,
|
||||
perms: Permission,
|
||||
ptr: *mut c_void,
|
||||
) -> Result<(), uc_error> {
|
||||
let err = unsafe { ffi::uc_mem_map_ptr(self.inner.uc, address, size, perms.bits(), ptr) };
|
||||
if err == uc_error::OK {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Map a memory region in the emulator at the specified address.
|
||||
///
|
||||
/// `address` must be aligned to 4kb or this will return `Error::ARG`.
|
||||
/// `size` must be a multiple of 4kb or this will return `Error::ARG`.
|
||||
pub fn mem_map(
|
||||
&mut self,
|
||||
address: u64,
|
||||
size: libc::size_t,
|
||||
perms: Permission,
|
||||
) -> Result<(), uc_error> {
|
||||
let err = unsafe { ffi::uc_mem_map(self.inner.uc, address, size, perms.bits()) };
|
||||
if err == uc_error::OK {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Unmap a memory region.
|
||||
///
|
||||
/// `address` must be aligned to 4kb or this will return `Error::ARG`.
|
||||
/// `size` must be a multiple of 4kb or this will return `Error::ARG`.
|
||||
pub fn mem_unmap(&mut self, address: u64, size: libc::size_t) -> Result<(), uc_error> {
|
||||
let err = unsafe { ffi::uc_mem_unmap(self.inner.uc, address, size) };
|
||||
if err == uc_error::OK {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the memory permissions for an existing memory region.
|
||||
///
|
||||
/// `address` must be aligned to 4kb or this will return `Error::ARG`.
|
||||
/// `size` must be a multiple of 4kb or this will return `Error::ARG`.
|
||||
pub fn mem_protect(
|
||||
&mut self,
|
||||
address: u64,
|
||||
size: libc::size_t,
|
||||
perms: Permission,
|
||||
) -> Result<(), uc_error> {
|
||||
let err = unsafe { ffi::uc_mem_protect(self.inner.uc, address, size, perms.bits()) };
|
||||
if err == uc_error::OK {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Write an unsigned value from a register.
|
||||
pub fn reg_write<T: Into<i32>>(&mut self, regid: T, value: u64) -> Result<(), uc_error> {
|
||||
let err =
|
||||
unsafe { ffi::uc_reg_write(self.inner.uc, regid.into(), &value as *const _ as _) };
|
||||
if err == uc_error::OK {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Write variable sized values into registers.
|
||||
///
|
||||
/// The user has to make sure that the buffer length matches the register size.
|
||||
/// This adds support for registers >64 bit (GDTR/IDTR, XMM, YMM, ZMM (x86); Q, V (arm64)).
|
||||
pub fn reg_write_long<T: Into<i32>>(&self, regid: T, value: Box<[u8]>) -> Result<(), uc_error> {
|
||||
let err = unsafe { ffi::uc_reg_write(self.inner.uc, regid.into(), value.as_ptr() as _) };
|
||||
if err == uc_error::OK {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Read an unsigned value from a register.
|
||||
///
|
||||
/// Not to be used with registers larger than 64 bit.
|
||||
pub fn reg_read<T: Into<i32>>(&self, regid: T) -> Result<u64, uc_error> {
|
||||
let mut value: u64 = 0;
|
||||
let err =
|
||||
unsafe { ffi::uc_reg_read(self.inner.uc, regid.into(), &mut value as *mut u64 as _) };
|
||||
if err == uc_error::OK {
|
||||
Ok(value)
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Read 128, 256 or 512 bit register value into heap allocated byte array.
|
||||
///
|
||||
/// This adds safe support for registers >64 bit (GDTR/IDTR, XMM, YMM, ZMM (x86); Q, V (arm64)).
|
||||
pub fn reg_read_long<T: Into<i32>>(&self, regid: T) -> Result<Box<[u8]>, uc_error> {
|
||||
let err: uc_error;
|
||||
let boxed: Box<[u8]>;
|
||||
let mut value: Vec<u8>;
|
||||
let curr_reg_id = regid.into();
|
||||
let curr_arch = self.get_arch();
|
||||
|
||||
if curr_arch == Arch::X86 {
|
||||
if curr_reg_id >= x86::RegisterX86::XMM0 as i32
|
||||
&& curr_reg_id <= x86::RegisterX86::XMM31 as i32
|
||||
{
|
||||
value = vec![0; 16];
|
||||
} else if curr_reg_id >= x86::RegisterX86::YMM0 as i32
|
||||
&& curr_reg_id <= x86::RegisterX86::YMM31 as i32
|
||||
{
|
||||
value = vec![0; 32];
|
||||
} else if curr_reg_id >= x86::RegisterX86::ZMM0 as i32
|
||||
&& curr_reg_id <= x86::RegisterX86::ZMM31 as i32
|
||||
{
|
||||
value = vec![0; 64];
|
||||
} else if curr_reg_id == x86::RegisterX86::GDTR as i32
|
||||
|| curr_reg_id == x86::RegisterX86::IDTR as i32
|
||||
{
|
||||
value = vec![0; 10]; // 64 bit base address in IA-32e mode
|
||||
} else {
|
||||
return Err(uc_error::ARG);
|
||||
}
|
||||
} else if curr_arch == Arch::ARM64 {
|
||||
if (curr_reg_id >= arm64::RegisterARM64::Q0 as i32
|
||||
&& curr_reg_id <= arm64::RegisterARM64::Q31 as i32)
|
||||
|| (curr_reg_id >= arm64::RegisterARM64::V0 as i32
|
||||
&& curr_reg_id <= arm64::RegisterARM64::V31 as i32)
|
||||
{
|
||||
value = vec![0; 16];
|
||||
} else {
|
||||
return Err(uc_error::ARG);
|
||||
}
|
||||
} else {
|
||||
return Err(uc_error::ARCH);
|
||||
}
|
||||
|
||||
err = unsafe { ffi::uc_reg_read(self.inner.uc, curr_reg_id, value.as_mut_ptr() as _) };
|
||||
|
||||
if err == uc_error::OK {
|
||||
boxed = value.into_boxed_slice();
|
||||
Ok(boxed)
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Read a signed 32-bit value from a register.
|
||||
pub fn reg_read_i32<T: Into<i32>>(&self, regid: T) -> Result<i32, uc_error> {
|
||||
let mut value: i32 = 0;
|
||||
let err =
|
||||
unsafe { ffi::uc_reg_read(self.inner.uc, regid.into(), &mut value as *mut i32 as _) };
|
||||
if err == uc_error::OK {
|
||||
Ok(value)
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a code hook.
|
||||
pub fn add_code_hook<F: 'static>(
|
||||
&mut self,
|
||||
begin: u64,
|
||||
end: u64,
|
||||
callback: F,
|
||||
) -> Result<ffi::uc_hook, uc_error>
|
||||
where
|
||||
F: FnMut(UnicornHandle, u64, u32),
|
||||
{
|
||||
let mut hook_ptr = std::ptr::null_mut();
|
||||
let mut user_data = Box::new(ffi::CodeHook {
|
||||
unicorn: unsafe { self.inner.as_mut().get_unchecked_mut() } as _,
|
||||
callback: Box::new(callback),
|
||||
});
|
||||
|
||||
let err = unsafe {
|
||||
ffi::uc_hook_add(
|
||||
self.inner.uc,
|
||||
&mut hook_ptr,
|
||||
HookType::CODE,
|
||||
ffi::code_hook_proxy as _,
|
||||
user_data.as_mut() as *mut _ as _,
|
||||
begin,
|
||||
end,
|
||||
)
|
||||
};
|
||||
if err == uc_error::OK {
|
||||
unsafe { self.inner.as_mut().get_unchecked_mut() }
|
||||
.code_hooks
|
||||
.insert(hook_ptr, user_data);
|
||||
Ok(hook_ptr)
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a block hook.
|
||||
pub fn add_block_hook<F: 'static>(&mut self, callback: F) -> Result<ffi::uc_hook, uc_error>
|
||||
where
|
||||
F: FnMut(UnicornHandle, u64, u32),
|
||||
{
|
||||
let mut hook_ptr = std::ptr::null_mut();
|
||||
let mut user_data = Box::new(ffi::BlockHook {
|
||||
unicorn: unsafe { self.inner.as_mut().get_unchecked_mut() } as _,
|
||||
callback: Box::new(callback),
|
||||
});
|
||||
|
||||
let err = unsafe {
|
||||
ffi::uc_hook_add(
|
||||
self.inner.uc,
|
||||
&mut hook_ptr,
|
||||
HookType::BLOCK,
|
||||
ffi::block_hook_proxy as _,
|
||||
user_data.as_mut() as *mut _ as _,
|
||||
1,
|
||||
0,
|
||||
)
|
||||
};
|
||||
if err == uc_error::OK {
|
||||
unsafe { self.inner.as_mut().get_unchecked_mut() }
|
||||
.block_hooks
|
||||
.insert(hook_ptr, user_data);
|
||||
Ok(hook_ptr)
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a memory hook.
|
||||
pub fn add_mem_hook<F: 'static>(
|
||||
&mut self,
|
||||
hook_type: HookType,
|
||||
begin: u64,
|
||||
end: u64,
|
||||
callback: F,
|
||||
) -> Result<ffi::uc_hook, uc_error>
|
||||
where
|
||||
F: FnMut(UnicornHandle, MemType, u64, usize, i64),
|
||||
{
|
||||
if !(HookType::MEM_ALL | HookType::MEM_READ_AFTER).contains(hook_type) {
|
||||
return Err(uc_error::ARG);
|
||||
}
|
||||
|
||||
let mut hook_ptr = std::ptr::null_mut();
|
||||
let mut user_data = Box::new(ffi::MemHook {
|
||||
unicorn: unsafe { self.inner.as_mut().get_unchecked_mut() } as _,
|
||||
callback: Box::new(callback),
|
||||
});
|
||||
|
||||
let err = unsafe {
|
||||
ffi::uc_hook_add(
|
||||
self.inner.uc,
|
||||
&mut hook_ptr,
|
||||
hook_type,
|
||||
ffi::mem_hook_proxy as _,
|
||||
user_data.as_mut() as *mut _ as _,
|
||||
begin,
|
||||
end,
|
||||
)
|
||||
};
|
||||
if err == uc_error::OK {
|
||||
unsafe { self.inner.as_mut().get_unchecked_mut() }
|
||||
.mem_hooks
|
||||
.insert(hook_ptr, user_data);
|
||||
Ok(hook_ptr)
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Add an interrupt hook.
|
||||
pub fn add_intr_hook<F: 'static>(&mut self, callback: F) -> Result<ffi::uc_hook, uc_error>
|
||||
where
|
||||
F: FnMut(UnicornHandle, u32),
|
||||
{
|
||||
let mut hook_ptr = std::ptr::null_mut();
|
||||
let mut user_data = Box::new(ffi::InterruptHook {
|
||||
unicorn: unsafe { self.inner.as_mut().get_unchecked_mut() } as _,
|
||||
callback: Box::new(callback),
|
||||
});
|
||||
|
||||
let err = unsafe {
|
||||
ffi::uc_hook_add(
|
||||
self.inner.uc,
|
||||
&mut hook_ptr,
|
||||
HookType::INTR,
|
||||
ffi::intr_hook_proxy as _,
|
||||
user_data.as_mut() as *mut _ as _,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
};
|
||||
if err == uc_error::OK {
|
||||
unsafe { self.inner.as_mut().get_unchecked_mut() }
|
||||
.intr_hooks
|
||||
.insert(hook_ptr, user_data);
|
||||
Ok(hook_ptr)
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Add hook for x86 IN instruction.
|
||||
pub fn add_insn_in_hook<F: 'static>(&mut self, callback: F) -> Result<ffi::uc_hook, uc_error>
|
||||
where
|
||||
F: FnMut(UnicornHandle, u32, usize),
|
||||
{
|
||||
let mut hook_ptr = std::ptr::null_mut();
|
||||
let mut user_data = Box::new(ffi::InstructionInHook {
|
||||
unicorn: unsafe { self.inner.as_mut().get_unchecked_mut() } as _,
|
||||
callback: Box::new(callback),
|
||||
});
|
||||
|
||||
let err = unsafe {
|
||||
ffi::uc_hook_add(
|
||||
self.inner.uc,
|
||||
&mut hook_ptr,
|
||||
HookType::INSN,
|
||||
ffi::insn_in_hook_proxy as _,
|
||||
user_data.as_mut() as *mut _ as _,
|
||||
0,
|
||||
0,
|
||||
x86::InsnX86::IN,
|
||||
)
|
||||
};
|
||||
if err == uc_error::OK {
|
||||
unsafe { self.inner.as_mut().get_unchecked_mut() }
|
||||
.insn_in_hooks
|
||||
.insert(hook_ptr, user_data);
|
||||
Ok(hook_ptr)
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Add hook for x86 OUT instruction.
|
||||
pub fn add_insn_out_hook<F: 'static>(&mut self, callback: F) -> Result<ffi::uc_hook, uc_error>
|
||||
where
|
||||
F: FnMut(UnicornHandle, u32, usize, u32),
|
||||
{
|
||||
let mut hook_ptr = std::ptr::null_mut();
|
||||
let mut user_data = Box::new(ffi::InstructionOutHook {
|
||||
unicorn: unsafe { self.inner.as_mut().get_unchecked_mut() } as _,
|
||||
callback: Box::new(callback),
|
||||
});
|
||||
|
||||
let err = unsafe {
|
||||
ffi::uc_hook_add(
|
||||
self.inner.uc,
|
||||
&mut hook_ptr,
|
||||
HookType::INSN,
|
||||
ffi::insn_out_hook_proxy as _,
|
||||
user_data.as_mut() as *mut _ as _,
|
||||
0,
|
||||
0,
|
||||
x86::InsnX86::OUT,
|
||||
)
|
||||
};
|
||||
if err == uc_error::OK {
|
||||
unsafe { self.inner.as_mut().get_unchecked_mut() }
|
||||
.insn_out_hooks
|
||||
.insert(hook_ptr, user_data);
|
||||
Ok(hook_ptr)
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Add hook for x86 SYSCALL or SYSENTER.
|
||||
pub fn add_insn_sys_hook<F: 'static>(
|
||||
&mut self,
|
||||
insn_type: x86::InsnSysX86,
|
||||
begin: u64,
|
||||
end: u64,
|
||||
callback: F,
|
||||
) -> Result<ffi::uc_hook, uc_error>
|
||||
where
|
||||
F: FnMut(UnicornHandle),
|
||||
{
|
||||
let mut hook_ptr = std::ptr::null_mut();
|
||||
let mut user_data = Box::new(ffi::InstructionSysHook {
|
||||
unicorn: unsafe { self.inner.as_mut().get_unchecked_mut() } as _,
|
||||
callback: Box::new(callback),
|
||||
});
|
||||
|
||||
let err = unsafe {
|
||||
ffi::uc_hook_add(
|
||||
self.inner.uc,
|
||||
&mut hook_ptr,
|
||||
HookType::INSN,
|
||||
ffi::insn_sys_hook_proxy as _,
|
||||
user_data.as_mut() as *mut _ as _,
|
||||
begin,
|
||||
end,
|
||||
insn_type,
|
||||
)
|
||||
};
|
||||
if err == uc_error::OK {
|
||||
unsafe { self.inner.as_mut().get_unchecked_mut() }
|
||||
.insn_sys_hooks
|
||||
.insert(hook_ptr, user_data);
|
||||
Ok(hook_ptr)
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove a hook.
|
||||
///
|
||||
/// `hook` is the value returned by `add_*_hook` functions.
|
||||
pub fn remove_hook(&mut self, hook: ffi::uc_hook) -> Result<(), uc_error> {
|
||||
let handle = unsafe { self.inner.as_mut().get_unchecked_mut() };
|
||||
let err: uc_error;
|
||||
let mut in_one_hashmap = false;
|
||||
|
||||
if handle.code_hooks.contains_key(&hook) {
|
||||
in_one_hashmap = true;
|
||||
handle.code_hooks.remove(&hook);
|
||||
}
|
||||
|
||||
if handle.mem_hooks.contains_key(&hook) {
|
||||
in_one_hashmap = true;
|
||||
handle.mem_hooks.remove(&hook);
|
||||
}
|
||||
|
||||
if handle.block_hooks.contains_key(&hook) {
|
||||
in_one_hashmap = true;
|
||||
handle.block_hooks.remove(&hook);
|
||||
}
|
||||
|
||||
if handle.intr_hooks.contains_key(&hook) {
|
||||
in_one_hashmap = true;
|
||||
handle.intr_hooks.remove(&hook);
|
||||
}
|
||||
|
||||
if handle.insn_in_hooks.contains_key(&hook) {
|
||||
in_one_hashmap = true;
|
||||
handle.insn_in_hooks.remove(&hook);
|
||||
}
|
||||
|
||||
if handle.insn_out_hooks.contains_key(&hook) {
|
||||
in_one_hashmap = true;
|
||||
handle.insn_out_hooks.remove(&hook);
|
||||
}
|
||||
|
||||
if handle.insn_sys_hooks.contains_key(&hook) {
|
||||
in_one_hashmap = true;
|
||||
handle.insn_sys_hooks.remove(&hook);
|
||||
}
|
||||
|
||||
if in_one_hashmap {
|
||||
err = unsafe { ffi::uc_hook_del(handle.uc, hook) };
|
||||
} else {
|
||||
err = uc_error::HOOK;
|
||||
}
|
||||
|
||||
if err == uc_error::OK {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Allocate and return an empty Unicorn context.
|
||||
///
|
||||
/// To be populated via context_save.
|
||||
pub fn context_alloc(&self) -> Result<Context, uc_error> {
|
||||
let mut empty_context: ffi::uc_context = Default::default();
|
||||
let err = unsafe { ffi::uc_context_alloc(self.inner.uc, &mut empty_context) };
|
||||
if err == uc_error::OK {
|
||||
Ok(Context {
|
||||
context: empty_context,
|
||||
})
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Save current Unicorn context to previously allocated Context struct.
|
||||
pub fn context_save(&self, context: &mut Context) -> Result<(), uc_error> {
|
||||
let err = unsafe { ffi::uc_context_save(self.inner.uc, context.context) };
|
||||
if err == uc_error::OK {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Allocate and return a Context struct initialized with the current CPU context.
|
||||
///
|
||||
/// This can be used for fast rollbacks with context_restore.
|
||||
/// In case of many non-concurrent context saves, use context_alloc and *_save
|
||||
/// individually to avoid unnecessary allocations.
|
||||
pub fn context_init(&self) -> Result<Context, uc_error> {
|
||||
let mut new_context: ffi::uc_context = Default::default();
|
||||
let err = unsafe { ffi::uc_context_alloc(self.inner.uc, &mut new_context) };
|
||||
if err != uc_error::OK {
|
||||
return Err(err);
|
||||
}
|
||||
let err = unsafe { ffi::uc_context_save(self.inner.uc, new_context) };
|
||||
if err == uc_error::OK {
|
||||
Ok(Context {
|
||||
context: new_context,
|
||||
})
|
||||
} else {
|
||||
unsafe { ffi::uc_context_free(new_context) };
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Restore a previously saved Unicorn context.
|
||||
///
|
||||
/// Perform a quick rollback of the CPU context, including registers and some
|
||||
/// internal metadata. Contexts may not be shared across engine instances with
|
||||
/// differing arches or modes. Memory has to be restored manually, if needed.
|
||||
pub fn context_restore(&self, context: &Context) -> Result<(), uc_error> {
|
||||
let err = unsafe { ffi::uc_context_restore(self.inner.uc, context.context) };
|
||||
if err == uc_error::OK {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Emulate machine code for a specified duration.
|
||||
///
|
||||
/// `begin` is the address where to start the emulation. The emulation stops if `until`
|
||||
/// is hit. `timeout` specifies a duration in microseconds after which the emulation is
|
||||
/// stopped (infinite execution if set to 0). `count` is the maximum number of instructions
|
||||
/// to emulate (emulate all the available instructions if set to 0).
|
||||
pub fn emu_start(
|
||||
&mut self,
|
||||
begin: u64,
|
||||
until: u64,
|
||||
timeout: u64,
|
||||
count: usize,
|
||||
) -> Result<(), uc_error> {
|
||||
let err = unsafe { ffi::uc_emu_start(self.inner.uc, begin, until, timeout, count as _) };
|
||||
if err == uc_error::OK {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Stop the emulation.
|
||||
///
|
||||
/// This is usually called from callback function in hooks.
|
||||
/// NOTE: For now, this will stop the execution only after the current block.
|
||||
pub fn emu_stop(&mut self) -> Result<(), uc_error> {
|
||||
let err = unsafe { ffi::uc_emu_stop(self.inner.uc) };
|
||||
if err == uc_error::OK {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Query the internal status of the engine.
|
||||
///
|
||||
/// supported: MODE, PAGE_SIZE, ARCH
|
||||
pub fn query(&self, query: Query) -> Result<usize, uc_error> {
|
||||
let mut result: libc::size_t = Default::default();
|
||||
let err = unsafe { ffi::uc_query(self.inner.uc, query, &mut result) };
|
||||
if err == uc_error::OK {
|
||||
Ok(result)
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
}
|
24
bindings/rust/src/m68k.rs
Normal file
24
bindings/rust/src/m68k.rs
Normal file
@ -0,0 +1,24 @@
|
||||
// M68K registers
|
||||
#[repr(C)]
|
||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||
pub enum RegisterM68K {
|
||||
INVALID = 0,
|
||||
A0,
|
||||
A1,
|
||||
A2,
|
||||
A3,
|
||||
A4,
|
||||
A5,
|
||||
A6,
|
||||
A7,
|
||||
D0,
|
||||
D1,
|
||||
D2,
|
||||
D3,
|
||||
D4,
|
||||
D5,
|
||||
D6,
|
||||
D7,
|
||||
SR,
|
||||
PC,
|
||||
}
|
246
bindings/rust/src/mips.rs
Normal file
246
bindings/rust/src/mips.rs
Normal file
@ -0,0 +1,246 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
// MIPS registers
|
||||
#[repr(C)]
|
||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||
pub enum RegisterMIPS {
|
||||
INVALID = 0,
|
||||
|
||||
// General purpose registers
|
||||
PC = 1,
|
||||
GPR0 = 2,
|
||||
GPR1 = 3,
|
||||
GPR2 = 4,
|
||||
GPR3 = 5,
|
||||
GPR4 = 6,
|
||||
GPR5 = 7,
|
||||
GPR6 = 8,
|
||||
GPR7 = 9,
|
||||
GPR8 = 10,
|
||||
GPR9 = 11,
|
||||
GPR10 = 12,
|
||||
GPR11 = 13,
|
||||
GPR12 = 14,
|
||||
GPR13 = 15,
|
||||
GPR14 = 16,
|
||||
GPR15 = 17,
|
||||
GPR16 = 18,
|
||||
GPR17 = 19,
|
||||
GPR18 = 20,
|
||||
GPR19 = 21,
|
||||
GPR20 = 22,
|
||||
GPR21 = 23,
|
||||
GPR22 = 24,
|
||||
GPR23 = 25,
|
||||
GPR24 = 26,
|
||||
GPR25 = 27,
|
||||
GPR26 = 28,
|
||||
GPR27 = 29,
|
||||
GPR28 = 30,
|
||||
GPR29 = 31,
|
||||
GPR30 = 32,
|
||||
GPR31 = 33,
|
||||
|
||||
// DSP registers
|
||||
DSPCCOND = 34,
|
||||
DSPCARRY = 35,
|
||||
DSPEFI = 36,
|
||||
DSPOUTFLAG = 37,
|
||||
DSPOUTFLAG16_19 = 38,
|
||||
DSPOUTFLAG20 = 39,
|
||||
DSPOUTFLAG21 = 40,
|
||||
DSPOUTFLAG22 = 41,
|
||||
DSPOUTFLAG23 = 42,
|
||||
DSPPOS = 43,
|
||||
DSPSCOUNT = 44,
|
||||
|
||||
// ACC registers
|
||||
AC0 = 45,
|
||||
AC1 = 46,
|
||||
AC2 = 47,
|
||||
AC3 = 48,
|
||||
|
||||
// COP registers
|
||||
CC0 = 49,
|
||||
CC1 = 50,
|
||||
CC2 = 51,
|
||||
CC3 = 52,
|
||||
CC4 = 53,
|
||||
CC5 = 54,
|
||||
CC6 = 55,
|
||||
CC7 = 56,
|
||||
|
||||
// FPU registers
|
||||
F0 = 57,
|
||||
F1 = 58,
|
||||
F2 = 59,
|
||||
F3 = 60,
|
||||
F4 = 61,
|
||||
F5 = 62,
|
||||
F6 = 63,
|
||||
F7 = 64,
|
||||
F8 = 65,
|
||||
F9 = 66,
|
||||
F10 = 67,
|
||||
F11 = 68,
|
||||
F12 = 69,
|
||||
F13 = 70,
|
||||
F14 = 71,
|
||||
F15 = 72,
|
||||
F16 = 73,
|
||||
F17 = 74,
|
||||
F18 = 75,
|
||||
F19 = 76,
|
||||
F20 = 77,
|
||||
F21 = 78,
|
||||
F22 = 79,
|
||||
F23 = 80,
|
||||
F24 = 81,
|
||||
F25 = 82,
|
||||
F26 = 83,
|
||||
F27 = 84,
|
||||
F28 = 85,
|
||||
F29 = 86,
|
||||
F30 = 87,
|
||||
F31 = 88,
|
||||
FCC0 = 89,
|
||||
FCC1 = 90,
|
||||
FCC2 = 91,
|
||||
FCC3 = 92,
|
||||
FCC4 = 93,
|
||||
FCC5 = 94,
|
||||
FCC6 = 95,
|
||||
FCC7 = 96,
|
||||
|
||||
// AFPR128
|
||||
W0 = 97,
|
||||
W1 = 98,
|
||||
W2 = 99,
|
||||
W3 = 100,
|
||||
W4 = 101,
|
||||
W5 = 102,
|
||||
W6 = 103,
|
||||
W7 = 104,
|
||||
W8 = 105,
|
||||
W9 = 106,
|
||||
W10 = 107,
|
||||
W11 = 108,
|
||||
W12 = 109,
|
||||
W13 = 110,
|
||||
W14 = 111,
|
||||
W15 = 112,
|
||||
W16 = 113,
|
||||
W17 = 114,
|
||||
W18 = 115,
|
||||
W19 = 116,
|
||||
W20 = 117,
|
||||
W21 = 118,
|
||||
W22 = 119,
|
||||
W23 = 120,
|
||||
W24 = 121,
|
||||
W25 = 122,
|
||||
W26 = 123,
|
||||
W27 = 124,
|
||||
W28 = 125,
|
||||
W29 = 126,
|
||||
W30 = 127,
|
||||
W31 = 128,
|
||||
HI = 129,
|
||||
LO = 130,
|
||||
P0 = 131,
|
||||
P1 = 132,
|
||||
P2 = 133,
|
||||
MPL0 = 134,
|
||||
MPL1 = 135,
|
||||
MPL2 = 136,
|
||||
CP0_CONFIG3 = 137,
|
||||
CP0_USERLOCAL = 138,
|
||||
ENDING = 139,
|
||||
|
||||
// alias registers
|
||||
// (assoc) ZERO = 2,
|
||||
// (assoc) AT = 3,
|
||||
// (assoc) V0 = 4,
|
||||
// (assoc) V1 = 5,
|
||||
// (assoc) A0 = 6,
|
||||
// (assoc) A1 = 7,
|
||||
// (assoc) A2 = 8,
|
||||
// (assoc) A3 = 9,
|
||||
// (assoc) T0 = 10,
|
||||
// (assoc) T1 = 11,
|
||||
// (assoc) T2 = 12,
|
||||
// (assoc) T3 = 13,
|
||||
// (assoc) T4 = 14,
|
||||
// (assoc) T5 = 15,
|
||||
// (assoc) T6 = 16,
|
||||
// (assoc) T7 = 17,
|
||||
// (assoc) S0 = 18,
|
||||
// (assoc) S1 = 19,
|
||||
// (assoc) S2 = 20,
|
||||
// (assoc) S3 = 21,
|
||||
// (assoc) S4 = 22,
|
||||
// (assoc) S5 = 23,
|
||||
// (assoc) S6 = 24,
|
||||
// (assoc) S7 = 25,
|
||||
// (assoc) T8 = 26,
|
||||
// (assoc) T9 = 27,
|
||||
// (assoc) K0 = 28,
|
||||
// (assoc) K1 = 29,
|
||||
// (assoc) GP = 30,
|
||||
// (assoc) SP = 31,
|
||||
// (assoc) FP = 32,
|
||||
// (assoc) S8 = 32,
|
||||
// (assoc) RA = 33,
|
||||
// (assoc) HI0 = 45,
|
||||
// (assoc) HI1 = 46,
|
||||
// (assoc) HI2 = 47,
|
||||
// (assoc) HI3 = 48,
|
||||
// (assoc) LO0 = 45,
|
||||
// (assoc) LO1 = 46,
|
||||
// (assoc) LO2 = 47,
|
||||
// (assoc) LO3 = 48,
|
||||
}
|
||||
|
||||
impl RegisterMIPS {
|
||||
pub const ZERO: RegisterMIPS = RegisterMIPS::GPR0;
|
||||
pub const AT: RegisterMIPS = RegisterMIPS::GPR1;
|
||||
pub const V0: RegisterMIPS = RegisterMIPS::GPR2;
|
||||
pub const V1: RegisterMIPS = RegisterMIPS::GPR3;
|
||||
pub const A0: RegisterMIPS = RegisterMIPS::GPR4;
|
||||
pub const A1: RegisterMIPS = RegisterMIPS::GPR5;
|
||||
pub const A2: RegisterMIPS = RegisterMIPS::GPR6;
|
||||
pub const A3: RegisterMIPS = RegisterMIPS::GPR7;
|
||||
pub const T0: RegisterMIPS = RegisterMIPS::GPR8;
|
||||
pub const T1: RegisterMIPS = RegisterMIPS::GPR9;
|
||||
pub const T2: RegisterMIPS = RegisterMIPS::GPR10;
|
||||
pub const T3: RegisterMIPS = RegisterMIPS::GPR11;
|
||||
pub const T4: RegisterMIPS = RegisterMIPS::GPR12;
|
||||
pub const T5: RegisterMIPS = RegisterMIPS::GPR13;
|
||||
pub const T6: RegisterMIPS = RegisterMIPS::GPR14;
|
||||
pub const T7: RegisterMIPS = RegisterMIPS::GPR15;
|
||||
pub const S0: RegisterMIPS = RegisterMIPS::GPR16;
|
||||
pub const S1: RegisterMIPS = RegisterMIPS::GPR17;
|
||||
pub const S2: RegisterMIPS = RegisterMIPS::GPR18;
|
||||
pub const S3: RegisterMIPS = RegisterMIPS::GPR19;
|
||||
pub const S4: RegisterMIPS = RegisterMIPS::GPR20;
|
||||
pub const S5: RegisterMIPS = RegisterMIPS::GPR21;
|
||||
pub const S6: RegisterMIPS = RegisterMIPS::GPR22;
|
||||
pub const S7: RegisterMIPS = RegisterMIPS::GPR23;
|
||||
pub const T8: RegisterMIPS = RegisterMIPS::GPR24;
|
||||
pub const T9: RegisterMIPS = RegisterMIPS::GPR25;
|
||||
pub const K0: RegisterMIPS = RegisterMIPS::GPR26;
|
||||
pub const K1: RegisterMIPS = RegisterMIPS::GPR27;
|
||||
pub const GP: RegisterMIPS = RegisterMIPS::GPR28;
|
||||
pub const SP: RegisterMIPS = RegisterMIPS::GPR29;
|
||||
pub const FP: RegisterMIPS = RegisterMIPS::GPR30;
|
||||
pub const S8: RegisterMIPS = RegisterMIPS::GPR30;
|
||||
pub const RA: RegisterMIPS = RegisterMIPS::GPR31;
|
||||
pub const HI0: RegisterMIPS = RegisterMIPS::AC0;
|
||||
pub const HI1: RegisterMIPS = RegisterMIPS::AC1;
|
||||
pub const HI2: RegisterMIPS = RegisterMIPS::AC2;
|
||||
pub const HI3: RegisterMIPS = RegisterMIPS::AC3;
|
||||
pub const LO0: RegisterMIPS = RegisterMIPS::AC0;
|
||||
pub const LO1: RegisterMIPS = RegisterMIPS::AC1;
|
||||
pub const LO2: RegisterMIPS = RegisterMIPS::AC2;
|
||||
pub const LO3: RegisterMIPS = RegisterMIPS::AC3;
|
||||
}
|
42
bindings/rust/src/ppc.rs
Normal file
42
bindings/rust/src/ppc.rs
Normal file
@ -0,0 +1,42 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT
|
||||
|
||||
// PowerPC registers
|
||||
#[repr(C)]
|
||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||
pub enum RegisterPPC {
|
||||
INVALID = 0,
|
||||
PC = 1,
|
||||
GPR0 = 2,
|
||||
GPR1 = 3,
|
||||
GPR2 = 4,
|
||||
GPR3 = 5,
|
||||
GPR4 = 6,
|
||||
GPR5 = 7,
|
||||
GPR6 = 8,
|
||||
GPR7 = 9,
|
||||
GPR8 = 10,
|
||||
GPR9 = 11,
|
||||
GPR10 = 12,
|
||||
GPR11 = 13,
|
||||
GPR12 = 14,
|
||||
GPR13 = 15,
|
||||
GPR14 = 16,
|
||||
GPR15 = 17,
|
||||
GPR16 = 18,
|
||||
GPR17 = 19,
|
||||
GPR18 = 20,
|
||||
GPR19 = 21,
|
||||
GPR20 = 22,
|
||||
GPR21 = 23,
|
||||
GPR22 = 24,
|
||||
GPR23 = 25,
|
||||
GPR24 = 26,
|
||||
GPR25 = 27,
|
||||
GPR26 = 28,
|
||||
GPR27 = 29,
|
||||
GPR28 = 30,
|
||||
GPR29 = 31,
|
||||
GPR30 = 32,
|
||||
GPR31 = 33,
|
||||
}
|
94
bindings/rust/src/sparc.rs
Normal file
94
bindings/rust/src/sparc.rs
Normal file
@ -0,0 +1,94 @@
|
||||
// SPARC registers
|
||||
#[repr(C)]
|
||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||
pub enum RegisterSPARC {
|
||||
INVALID = 0,
|
||||
F0 = 1,
|
||||
F1 = 2,
|
||||
F2 = 3,
|
||||
F3 = 4,
|
||||
F4 = 5,
|
||||
F5 = 6,
|
||||
F6 = 7,
|
||||
F7 = 8,
|
||||
F8 = 9,
|
||||
F9 = 10,
|
||||
F10 = 11,
|
||||
F11 = 12,
|
||||
F12 = 13,
|
||||
F13 = 14,
|
||||
F14 = 15,
|
||||
F15 = 16,
|
||||
F16 = 17,
|
||||
F17 = 18,
|
||||
F18 = 19,
|
||||
F19 = 20,
|
||||
F20 = 21,
|
||||
F21 = 22,
|
||||
F22 = 23,
|
||||
F23 = 24,
|
||||
F24 = 25,
|
||||
F25 = 26,
|
||||
F26 = 27,
|
||||
F27 = 28,
|
||||
F28 = 29,
|
||||
F29 = 30,
|
||||
F30 = 31,
|
||||
F31 = 32,
|
||||
F32 = 33,
|
||||
F34 = 34,
|
||||
F36 = 35,
|
||||
F38 = 36,
|
||||
F40 = 37,
|
||||
F42 = 38,
|
||||
F44 = 39,
|
||||
F46 = 40,
|
||||
F48 = 41,
|
||||
F50 = 42,
|
||||
F52 = 43,
|
||||
F54 = 44,
|
||||
F56 = 45,
|
||||
F58 = 46,
|
||||
F60 = 47,
|
||||
F62 = 48,
|
||||
FCC0 = 49,
|
||||
FCC1 = 50,
|
||||
FCC2 = 51,
|
||||
FCC3 = 52,
|
||||
G0 = 53,
|
||||
G1 = 54,
|
||||
G2 = 55,
|
||||
G3 = 56,
|
||||
G4 = 57,
|
||||
G5 = 58,
|
||||
G6 = 59,
|
||||
G7 = 60,
|
||||
I0 = 61,
|
||||
I1 = 62,
|
||||
I2 = 63,
|
||||
I3 = 64,
|
||||
I4 = 65,
|
||||
I5 = 66,
|
||||
FP = 67,
|
||||
I7 = 68,
|
||||
ICC = 69,
|
||||
L0 = 70,
|
||||
L1 = 71,
|
||||
L2 = 72,
|
||||
L3 = 73,
|
||||
L4 = 74,
|
||||
L5 = 75,
|
||||
L6 = 76,
|
||||
L7 = 77,
|
||||
O0 = 78,
|
||||
O1 = 79,
|
||||
O2 = 80,
|
||||
O3 = 81,
|
||||
O4 = 82,
|
||||
O5 = 83,
|
||||
SP = 84,
|
||||
O7 = 85,
|
||||
Y = 86,
|
||||
XCC = 87,
|
||||
PC = 88,
|
||||
}
|
158
bindings/rust/src/unicorn_const.rs
Normal file
158
bindings/rust/src/unicorn_const.rs
Normal file
@ -0,0 +1,158 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
use bitflags::bitflags;
|
||||
|
||||
pub const API_MAJOR: u64 = 1;
|
||||
pub const API_MINOR: u64 = 0;
|
||||
pub const VERSION_MAJOR: u64 = 1;
|
||||
pub const VERSION_MINOR: u64 = 0;
|
||||
pub const VERSION_EXTRA: u64 = 2;
|
||||
pub const SECOND_SCALE: u64 = 1_000_000;
|
||||
pub const MILISECOND_SCALE: u64 = 1_000;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||
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,
|
||||
}
|
||||
|
||||
#[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,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[repr(C)]
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||
pub enum Query {
|
||||
MODE = 1,
|
||||
PAGE_SIZE = 2,
|
||||
ARCH = 3,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[repr(C)]
|
||||
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,
|
||||
MAX = 8,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[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 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;
|
||||
}
|
||||
}
|
281
bindings/rust/src/x86.rs
Normal file
281
bindings/rust/src/x86.rs
Normal file
@ -0,0 +1,281 @@
|
||||
// X86 registers
|
||||
#[repr(C)]
|
||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||
pub enum RegisterX86 {
|
||||
INVALID = 0,
|
||||
AH,
|
||||
AL,
|
||||
AX,
|
||||
BH,
|
||||
BL,
|
||||
BP,
|
||||
BPL,
|
||||
BX,
|
||||
CH,
|
||||
CL,
|
||||
CS,
|
||||
CX,
|
||||
DH,
|
||||
DI,
|
||||
DIL,
|
||||
DL,
|
||||
DS,
|
||||
DX,
|
||||
EAX,
|
||||
EBP,
|
||||
EBX,
|
||||
ECX,
|
||||
EDI,
|
||||
EDX,
|
||||
EFLAGS,
|
||||
EIP,
|
||||
EIZ,
|
||||
ES,
|
||||
ESI,
|
||||
ESP,
|
||||
FPSW,
|
||||
FS,
|
||||
GS,
|
||||
IP,
|
||||
RAX,
|
||||
RBP,
|
||||
RBX,
|
||||
RCX,
|
||||
RDI,
|
||||
RDX,
|
||||
RIP,
|
||||
RIZ,
|
||||
RSI,
|
||||
RSP,
|
||||
SI,
|
||||
SIL,
|
||||
SP,
|
||||
SPL,
|
||||
SS,
|
||||
CR0,
|
||||
CR1,
|
||||
CR2,
|
||||
CR3,
|
||||
CR4,
|
||||
CR5,
|
||||
CR6,
|
||||
CR7,
|
||||
CR8,
|
||||
CR9,
|
||||
CR10,
|
||||
CR11,
|
||||
CR12,
|
||||
CR13,
|
||||
CR14,
|
||||
CR15,
|
||||
DR0,
|
||||
DR1,
|
||||
DR2,
|
||||
DR3,
|
||||
DR4,
|
||||
DR5,
|
||||
DR6,
|
||||
DR7,
|
||||
DR8,
|
||||
DR9,
|
||||
DR10,
|
||||
DR11,
|
||||
DR12,
|
||||
DR13,
|
||||
DR14,
|
||||
DR15,
|
||||
FP0,
|
||||
FP1,
|
||||
FP2,
|
||||
FP3,
|
||||
FP4,
|
||||
FP5,
|
||||
FP6,
|
||||
FP7,
|
||||
K0,
|
||||
K1,
|
||||
K2,
|
||||
K3,
|
||||
K4,
|
||||
K5,
|
||||
K6,
|
||||
K7,
|
||||
MM0,
|
||||
MM1,
|
||||
MM2,
|
||||
MM3,
|
||||
MM4,
|
||||
MM5,
|
||||
MM6,
|
||||
MM7,
|
||||
R8,
|
||||
R9,
|
||||
R10,
|
||||
R11,
|
||||
R12,
|
||||
R13,
|
||||
R14,
|
||||
R15,
|
||||
ST0,
|
||||
ST1,
|
||||
ST2,
|
||||
ST3,
|
||||
ST4,
|
||||
ST5,
|
||||
ST6,
|
||||
ST7,
|
||||
XMM0,
|
||||
XMM1,
|
||||
XMM2,
|
||||
XMM3,
|
||||
XMM4,
|
||||
XMM5,
|
||||
XMM6,
|
||||
XMM7,
|
||||
XMM8,
|
||||
XMM9,
|
||||
XMM10,
|
||||
XMM11,
|
||||
XMM12,
|
||||
XMM13,
|
||||
XMM14,
|
||||
XMM15,
|
||||
XMM16,
|
||||
XMM17,
|
||||
XMM18,
|
||||
XMM19,
|
||||
XMM20,
|
||||
XMM21,
|
||||
XMM22,
|
||||
XMM23,
|
||||
XMM24,
|
||||
XMM25,
|
||||
XMM26,
|
||||
XMM27,
|
||||
XMM28,
|
||||
XMM29,
|
||||
XMM30,
|
||||
XMM31,
|
||||
YMM0,
|
||||
YMM1,
|
||||
YMM2,
|
||||
YMM3,
|
||||
YMM4,
|
||||
YMM5,
|
||||
YMM6,
|
||||
YMM7,
|
||||
YMM8,
|
||||
YMM9,
|
||||
YMM10,
|
||||
YMM11,
|
||||
YMM12,
|
||||
YMM13,
|
||||
YMM14,
|
||||
YMM15,
|
||||
YMM16,
|
||||
YMM17,
|
||||
YMM18,
|
||||
YMM19,
|
||||
YMM20,
|
||||
YMM21,
|
||||
YMM22,
|
||||
YMM23,
|
||||
YMM24,
|
||||
YMM25,
|
||||
YMM26,
|
||||
YMM27,
|
||||
YMM28,
|
||||
YMM29,
|
||||
YMM30,
|
||||
YMM31,
|
||||
ZMM0,
|
||||
ZMM1,
|
||||
ZMM2,
|
||||
ZMM3,
|
||||
ZMM4,
|
||||
ZMM5,
|
||||
ZMM6,
|
||||
ZMM7,
|
||||
ZMM8,
|
||||
ZMM9,
|
||||
ZMM10,
|
||||
ZMM11,
|
||||
ZMM12,
|
||||
ZMM13,
|
||||
ZMM14,
|
||||
ZMM15,
|
||||
ZMM16,
|
||||
ZMM17,
|
||||
ZMM18,
|
||||
ZMM19,
|
||||
ZMM20,
|
||||
ZMM21,
|
||||
ZMM22,
|
||||
ZMM23,
|
||||
ZMM24,
|
||||
ZMM25,
|
||||
ZMM26,
|
||||
ZMM27,
|
||||
ZMM28,
|
||||
ZMM29,
|
||||
ZMM30,
|
||||
ZMM31,
|
||||
R8B,
|
||||
R9B,
|
||||
R10B,
|
||||
R11B,
|
||||
R12B,
|
||||
R13B,
|
||||
R14B,
|
||||
R15B,
|
||||
R8D,
|
||||
R9D,
|
||||
R10D,
|
||||
R11D,
|
||||
R12D,
|
||||
R13D,
|
||||
R14D,
|
||||
R15D,
|
||||
R8W,
|
||||
R9W,
|
||||
R10W,
|
||||
R11W,
|
||||
R12W,
|
||||
R13W,
|
||||
R14W,
|
||||
R15W,
|
||||
IDTR,
|
||||
GDTR,
|
||||
LDTR,
|
||||
TR,
|
||||
FPCW,
|
||||
FPTAG,
|
||||
MSR,
|
||||
MXCSR,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||
pub enum InsnX86 {
|
||||
IN = 218,
|
||||
OUT = 500,
|
||||
SYSCALL = 699,
|
||||
SYSENTER = 700,
|
||||
RET = 151,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||
pub enum InsnSysX86 {
|
||||
SYSCALL = InsnX86::SYSCALL as isize,
|
||||
SYSENTER = InsnX86::SYSENTER as isize,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||
pub struct X86Mmr {
|
||||
pub selector: u64,
|
||||
pub base: u64,
|
||||
pub limit: u32,
|
||||
pub flags: u32,
|
||||
}
|
Reference in New Issue
Block a user