diff --git a/.github/workflows/Nuget-publishing.yml b/.github/workflows/Nuget-publishing.yml index e82961cd..5a6c5815 100644 --- a/.github/workflows/Nuget-publishing.yml +++ b/.github/workflows/Nuget-publishing.yml @@ -257,6 +257,7 @@ jobs: else export CFLAGS="-m32" LDFLAGS="-m32" LDFLAGS_STATIC="-m32" UNICORN_QEMU_FLAGS="--cpu=i386" sudo dpkg --add-architecture i386 + sudo apt update sudo apt install -q -y lib32ncurses-dev lib32z1-dev lib32gcc-9-dev libc6-dev-i386 gcc-multilib \ libcmocka-dev:i386 libcmocka0:i386 libc6:i386 libgcc-s1:i386 ninja-build fi diff --git a/CREDITS.TXT b/CREDITS.TXT index 11df0628..ee443858 100644 --- a/CREDITS.TXT +++ b/CREDITS.TXT @@ -80,3 +80,4 @@ Stuart Dootson (studoot): MSVC compatibility with PowerPC target support Ziqiao Kong (lazymio): uc_context_free() API and various bug fix & improvement. Sven Almgren (blindmatrix): bug fix Chenxu Wu (kabeor): Documentation +Philipp Takacs: virtual tlb, memory snapshots diff --git a/bindings/python/sample_ctl.py b/bindings/python/sample_ctl.py index a3a170fb..88f773e4 100755 --- a/bindings/python/sample_ctl.py +++ b/bindings/python/sample_ctl.py @@ -56,8 +56,8 @@ def test_uc_ctl_tb_cache(): # Now we clear cache for all TBs. for i in range(8): - uc.ctl_remove_cache(addr + i * 512, addr + 0x1000) - + uc.ctl_remove_cache(addr + i * 512, addr + i * 512 + 1) + evicted = time_emulation(uc, addr, addr + len(code)) print(f">>> Run time: First time {standard}, Cached: {cached}, Cached evicted: {evicted}") @@ -65,7 +65,7 @@ def test_uc_ctl_tb_cache(): def trace_new_edge(uc, cur, prev, data): print(f">>> Getting a new edge from {hex(prev.pc + prev.size - 1)} to {hex(cur.pc)}") -def trace_tcg_sub(uc, address, arg1, arg2, data): +def trace_tcg_sub(uc, address, arg1, arg2, size, data): print(f">>> Get a tcg sub opcode at {hex(address)} with args: {arg1} and {arg2}") def test_uc_ctl_exits(): diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 60f791b5..86a5e1b2 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -182,7 +182,7 @@ __set_lib_prototypes(uclib) # native hook callback signatures HOOK_INTR_CFUNC = ctypes.CFUNCTYPE(None, uc_engine, ctypes.c_uint32, ctypes.c_void_p) -HOOK_CODE_CFUNC = ctypes.CFUNCTYPE(None, uc_engine, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_void_p) +HOOK_CODE_CFUNC = ctypes.CFUNCTYPE(None, uc_engine, ctypes.c_uint64, ctypes.c_uint32, ctypes.c_void_p) HOOK_MEM_INVALID_CFUNC = ctypes.CFUNCTYPE(ctypes.c_bool, uc_engine, ctypes.c_int, ctypes.c_uint64, ctypes.c_int, ctypes.c_int64, ctypes.c_void_p) HOOK_MEM_ACCESS_CFUNC = ctypes.CFUNCTYPE(None, uc_engine, ctypes.c_int, ctypes.c_uint64, ctypes.c_int, ctypes.c_int64, ctypes.c_void_p) HOOK_INSN_INVALID_CFUNC = ctypes.CFUNCTYPE(ctypes.c_bool, uc_engine, ctypes.c_void_p) diff --git a/bindings/rust/src/ffi.rs b/bindings/rust/src/ffi.rs index b1c04f57..fb87c211 100644 --- a/bindings/rust/src/ffi.rs +++ b/bindings/rust/src/ffi.rs @@ -3,7 +3,7 @@ use crate::{Unicorn, UnicornInner}; -use super::unicorn_const::{uc_error, Arch, HookType, MemRegion, MemType, Mode, Query}; +use super::unicorn_const::{uc_error, Arch, HookType, MemRegion, MemType, Mode, Query, TlbEntry}; use alloc::rc::Weak; use core::{cell::UnsafeCell, ffi::c_void}; use libc::{c_char, c_int}; @@ -86,6 +86,7 @@ extern "C" { 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 fn uc_ctl(engine: uc_handle, control: u32, ...) -> uc_error; } pub struct UcHook<'a, D: 'a, F: 'a> { @@ -251,3 +252,25 @@ where debug_assert_eq!(uc, user_data_uc.get_handle()); (user_data.callback)(&mut user_data_uc); } + +pub extern "C" fn tlb_lookup_hook_proxy(uc: uc_handle, vaddr: u64, mem_type: MemType, result: *mut TlbEntry, user_data: *mut UcHook) -> bool +where + F: FnMut(&mut crate::Unicorn, u64, MemType) -> Option, +{ + let user_data = unsafe { &mut *user_data }; + let mut user_data_uc = Unicorn { + inner: user_data.uc.upgrade().unwrap(), + }; + debug_assert_eq!(uc, user_data_uc.get_handle()); + let r = (user_data.callback)(&mut user_data_uc, vaddr, mem_type); + match r { + Some(ref e) => { + unsafe { + let ref_result: &mut TlbEntry = &mut *result; + *ref_result = *e; + } + }, + None => {}, + }; + return r.is_some(); +} diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index cb8497c7..5b4e7d33 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -30,7 +30,9 @@ #[macro_use] extern crate alloc; +extern crate std; +#[macro_use] pub mod unicorn_const; mod arm; @@ -883,6 +885,33 @@ impl<'a, D> Unicorn<'a, D> { } } + pub fn add_tlb_hook(&mut self, begin: u64, end: u64, callback: F) -> Result + where + F: FnMut(&mut crate::Unicorn, u64, MemType) -> Option + 'a, + { + let mut hook_ptr = core::ptr::null_mut(); + let mut user_data = Box::new(ffi::UcHook { + callback, + uc: Rc::downgrade(&self.inner), + }); + let err = unsafe { + ffi::uc_hook_add(self.get_handle(), + &mut hook_ptr, + HookType::TLB, + ffi::tlb_lookup_hook_proxy:: as _, + user_data.as_mut() as *mut _ as _, + begin, + end, + ) + }; + if err == uc_error::OK { + self.inner_mut().hooks.push((hook_ptr, user_data)); + Ok(hook_ptr) + } else { + Err(err) + } + } + /// Remove a hook. /// /// `hook` is the value returned by `add_*_hook` functions. @@ -1051,4 +1080,166 @@ impl<'a, D> Unicorn<'a, D> { }; self.reg_write(reg, value) } + + pub fn ctl_get_mode(&self) -> Result { + let mut result: i32 = Default::default(); + let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_MODE), &mut result) }; + if err == uc_error::OK { + Ok(Mode::from_bits_truncate(result)) + } else { + Err(err) + } + } + + pub fn ctl_get_page_size(&self) -> Result { + let mut result: u32 = Default::default(); + let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_PAGE_SIZE), &mut result) }; + if err == uc_error::OK { + Ok(result) + } else { + Err(err) + } + } + + pub fn ctl_set_page_size(&self, page_size: u32) -> Result<(), uc_error> { + let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_UC_PAGE_SIZE), page_size) }; + if err == uc_error::OK { + Ok(()) + } else { + Err(err) + } + } + + pub fn ctl_get_arch(&self) -> Result { + let mut result: i32 = Default::default(); + let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_ARCH), &mut result) }; + if err == uc_error::OK { + Arch::try_from(result as usize) + } else { + Err(err) + } + } + + pub fn ctl_get_timeout(&self) -> Result { + let mut result: u64 = Default::default(); + let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_TIMEOUT), &mut result) }; + if err == uc_error::OK { + Ok(result) + } else { + Err(err) + } + } + + pub fn ctl_exits_enable(&self) -> Result<(), uc_error> { + let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_UC_USE_EXITS), 1) }; + if err == uc_error::OK { + Ok(()) + } else { + Err(err) + } + } + + pub fn ctl_exits_disable(&self) -> Result<(), uc_error> { + let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_UC_USE_EXITS), 0) }; + if err == uc_error::OK { + Ok(()) + } else { + Err(err) + } + } + + pub fn ctl_get_exits_count(&self) -> Result { + let mut result: libc::size_t = Default::default(); + let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_EXITS_CNT), &mut result) }; + if err == uc_error::OK { + Ok(result) + } else { + Err(err) + } + } + + pub fn ctl_get_exits(&self) -> Result, uc_error> { + let exits_count: libc::size_t = self.ctl_get_exits_count()?; + let mut exits: Vec = Vec::with_capacity(exits_count); + let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_EXITS), exits.as_mut_ptr(), exits_count) }; + if err == uc_error::OK { + unsafe { exits.set_len(exits_count); } + Ok(exits) + } else { + Err(err) + } + } + + pub fn ctl_set_exits(&self, exits: &[u64]) -> Result<(), uc_error> { + let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_UC_EXITS), exits.as_ptr(), exits.len() as libc::size_t) }; + if err == uc_error::OK { + Ok(()) + } else { + Err(err) + } + } + + pub fn ctl_get_cpu_model(&self) -> Result { + let mut result: i32 = Default::default(); + let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_CPU_MODEL), &mut result) }; + if err == uc_error::OK { + Ok(result) + } else { + Err(err) + } + } + + pub fn ctl_set_cpu_model(&self, cpu_model: i32) -> Result<(), uc_error> { + let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_CPU_MODEL), cpu_model) }; + if err == uc_error::OK { + Ok(()) + } else { + Err(err) + } + } + + pub fn ctl_remove_cache(&self, address: u64, end: u64) -> Result<(), uc_error> { + let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_TB_REMOVE_CACHE), address, end) }; + if err == uc_error::OK { + Ok(()) + } else { + Err(err) + } + } + + pub fn ctl_request_cache(&self, address: u64, tb: &mut TranslationBlock) -> Result<(), uc_error> { + let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ_WRITE!(ControlType::UC_CTL_TB_REQUEST_CACHE), address, tb) }; + if err == uc_error::OK { + Ok(()) + } else { + Err(err) + } + } + + pub fn ctl_flush_tb(&self) -> Result<(), uc_error> { + let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_TB_FLUSH)) }; + if err == uc_error::OK { + Ok(()) + } else { + Err(err) + } + } + + pub fn ctl_flush_tlb(&self) -> Result<(), uc_error> { + let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_TLB_FLUSH)) }; + if err == uc_error::OK { + Ok(()) + } else { + Err(err) + } + } + + pub fn ctl_tlb_type(&self, t: TlbType) -> Result<(), uc_error> { + let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_TLB_TYPE), t as i32) }; + if err == uc_error::OK { + Ok(()) + } else { + Err(err) + } + } } diff --git a/bindings/rust/src/unicorn_const.rs b/bindings/rust/src/unicorn_const.rs index 7e8185d2..2ef7622e 100644 --- a/bindings/rust/src/unicorn_const.rs +++ b/bindings/rust/src/unicorn_const.rs @@ -53,6 +53,13 @@ pub enum MemType { READ_AFTER = 25, } +#[repr(C)] +#[derive(PartialEq, Debug, Clone, Copy)] +pub enum TlbType { + CPU = 0, + VIRTUAL = 1, +} + bitflags! { #[repr(C)] pub struct HookType: i32 { @@ -86,6 +93,8 @@ bitflags! { 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); } } @@ -187,3 +196,55 @@ bitflags! { 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)] +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_IO_READ = 1<<31, + UC_CTL_IO_WRITE = 1<<30, +} + +#[repr(C)] +#[derive(Debug, Clone, Copy)] +pub struct TlbEntry { + pub paddr: u64, + pub perms: Permission, +} diff --git a/include/qemu.h b/include/qemu.h index 337f4f8f..8705a1a6 100644 --- a/include/qemu.h +++ b/include/qemu.h @@ -41,6 +41,7 @@ typedef struct { // This struct is originally from qemu/include/exec/ramlist.h typedef struct RAMList { + bool freed; RAMBlock *mru_block; QLIST_HEAD(, RAMBlock) blocks; } RAMList; diff --git a/include/uc_priv.h b/include/uc_priv.h index 5b2bfed0..a9dca9fb 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -62,19 +62,14 @@ typedef struct _mmio_cbs { typedef uc_err (*query_t)(struct uc_struct *uc, uc_query_type type, size_t *result); -// return 0 on success, -1 on failure -typedef int (*reg_read_t)(struct uc_struct *uc, unsigned int *regs, void **vals, - int count); -typedef int (*reg_write_t)(struct uc_struct *uc, unsigned int *regs, - void *const *vals, int count); +typedef uc_err (*reg_read_t)(void *env, int mode, unsigned int regid, + void *value, size_t *size); +typedef uc_err (*reg_write_t)(void *env, int mode, unsigned int regid, + const void *value, size_t *size, int *setpc); -typedef int (*context_reg_read_t)(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); -typedef int (*context_reg_write_t)(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); typedef struct { - context_reg_read_t context_reg_read; - context_reg_write_t context_reg_write; + reg_read_t read; + reg_write_t write; } context_reg_rw_t; typedef void (*reg_reset_t)(struct uc_struct *uc); @@ -85,12 +80,16 @@ typedef bool (*uc_write_mem_t)(AddressSpace *as, hwaddr addr, typedef bool (*uc_read_mem_t)(AddressSpace *as, hwaddr addr, uint8_t *buf, int len); +typedef MemoryRegion* (*uc_mem_cow_t)(struct uc_struct *uc, + MemoryRegion *current, hwaddr begin, + size_t size); + typedef void (*uc_args_void_t)(void *); typedef void (*uc_args_uc_t)(struct uc_struct *); typedef void (*uc_args_int_uc_t)(struct uc_struct *); -typedef void (*uc_args_uc_long_t)(struct uc_struct *, unsigned long); +typedef void (*uc_args_uc_long_t)(struct uc_struct *, uint32_t); typedef void (*uc_args_uc_u64_t)(struct uc_struct *, uint64_t addr); @@ -105,6 +104,10 @@ typedef MemoryRegion *(*uc_args_uc_ram_size_ptr_t)(struct uc_struct *, typedef void (*uc_mem_unmap_t)(struct uc_struct *, MemoryRegion *mr); +typedef MemoryRegion *(*uc_memory_mapping_t)(struct uc_struct *, hwaddr addr); + +typedef void (*uc_memory_filter_t)(MemoryRegion *, int32_t); + typedef void (*uc_readonly_mem_t)(MemoryRegion *mr, bool readonly); typedef int (*uc_cpus_init)(struct uc_struct *, const char *); @@ -270,6 +273,7 @@ struct uc_struct { uc_write_mem_t write_mem; uc_read_mem_t read_mem; + uc_mem_cow_t memory_cow; uc_args_void_t release; // release resource when uc_close() uc_args_uc_u64_t set_pc; // set PC for tracecode uc_get_pc_t get_pc; @@ -282,7 +286,11 @@ struct uc_struct { uc_args_uc_long_t tcg_exec_init; uc_args_uc_ram_size_t memory_map; uc_args_uc_ram_size_ptr_t memory_map_ptr; + uc_memory_mapping_t memory_mapping; + uc_memory_filter_t memory_filter_subregions; uc_mem_unmap_t memory_unmap; + uc_mem_unmap_t memory_moveout; + uc_mem_unmap_t memory_movein; uc_readonly_mem_t readonly_mem; uc_cpus_init cpus_init; uc_target_page_init target_page; @@ -383,6 +391,7 @@ struct uc_struct { uint64_t qemu_real_host_page_size; int qemu_icache_linesize; /* ARCH_REGS_STORAGE_SIZE */ + uc_context_content context_content; int cpu_context_size; uint64_t next_pc; // save next PC for some special cases bool hook_insert; // insert new hook at begin of the hook list (append by @@ -399,6 +408,14 @@ struct uc_struct { struct TranslationBlock *last_tb; // The real last tb we executed. FlatView *empty_view; // Static function variable moved from flatviews_init + + uint32_t tcg_buffer_size; // The buffer size we are going to use +#ifdef WIN32 + PVOID seh_handle; + void *seh_closure; +#endif + GArray *unmapped_regions; + int32_t snapshot_level; }; // Metadata stub for the variable-size cpu context used with uc_context_*() @@ -406,12 +423,10 @@ struct uc_context { size_t context_size; // size of the real internal context structure uc_mode mode; // the mode of this context uc_arch arch; // the arch of this context + int snapshot_level; // the memory snapshot level to restore char data[0]; // context }; -// check if this address is mapped in (via uc_mem_map()) -MemoryRegion *find_memory_region(struct uc_struct *uc, uint64_t address); - // We have to support 32bit system so we can't hold uint64_t on void* static inline void uc_add_exit(uc_engine *uc, uint64_t addr) { diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index ed016dc0..85a1ade8 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -192,6 +192,7 @@ typedef enum uc_err { UC_ERR_HOOK_EXIST, // hook for this event already existed UC_ERR_RESOURCE, // Insufficient resource: uc_emu_start() UC_ERR_EXCEPTION, // Unhandled CPU exception + UC_ERR_OVERFLOW, // Provided buffer is not large enough: uc_reg_*2() } uc_err; /* @@ -245,20 +246,34 @@ typedef void (*uc_cb_insn_out_t)(uc_engine *uc, uint32_t port, int size, uint32_t value, void *user_data); typedef struct uc_tlb_entry uc_tlb_entry; -typedef enum uc_mem_type uc_mem_type; +// All type of memory accesses for UC_HOOK_MEM_* +typedef enum uc_mem_type { + UC_MEM_READ = 16, // Memory is read from + UC_MEM_WRITE, // Memory is written to + UC_MEM_FETCH, // Memory is fetched + UC_MEM_READ_UNMAPPED, // Unmapped memory is read from + UC_MEM_WRITE_UNMAPPED, // Unmapped memory is written to + UC_MEM_FETCH_UNMAPPED, // Unmapped memory is fetched + UC_MEM_WRITE_PROT, // Write to write protected, but mapped, memory + UC_MEM_READ_PROT, // Read from read protected, but mapped, memory + UC_MEM_FETCH_PROT, // Fetch from non-executable, but mapped, memory + UC_MEM_READ_AFTER, // Memory is read from (successful access) +} uc_mem_type; /* Callback function for tlb lookups @vaddr: virtuall address for lookup @rw: the access mode - @result: result entry, contains physical address (paddr) and permitted access type (perms) for the entry + @result: result entry, contains physical address (paddr) and permitted access + type (perms) for the entry @return: return true if the entry was found. If a callback is present but no one returns true a pagefault is generated. */ -typedef bool (*uc_cb_tlbevent_t)(uc_engine *uc, uint64_t vaddr, uc_mem_type type, - uc_tlb_entry *result, void *user_data); +typedef bool (*uc_cb_tlbevent_t)(uc_engine *uc, uint64_t vaddr, + uc_mem_type type, uc_tlb_entry *result, + void *user_data); // Represent a TranslationBlock. typedef struct uc_tb { @@ -310,20 +325,6 @@ typedef void (*uc_cb_mmio_write_t)(uc_engine *uc, uint64_t offset, unsigned size, uint64_t value, void *user_data); -// All type of memory accesses for UC_HOOK_MEM_* -enum uc_mem_type { - UC_MEM_READ = 16, // Memory is read from - UC_MEM_WRITE, // Memory is written to - UC_MEM_FETCH, // Memory is fetched - UC_MEM_READ_UNMAPPED, // Unmapped memory is read from - UC_MEM_WRITE_UNMAPPED, // Unmapped memory is written to - UC_MEM_FETCH_UNMAPPED, // Unmapped memory is fetched - UC_MEM_WRITE_PROT, // Write to write protected, but mapped, memory - UC_MEM_READ_PROT, // Read from read protected, but mapped, memory - UC_MEM_FETCH_PROT, // Fetch from non-executable, but mapped, memory - UC_MEM_READ_AFTER, // Memory is read from (successful access) -}; - // These are all op codes we support to hook for UC_HOOK_TCG_OP_CODE. // Be cautious since it may bring much more overhead than UC_HOOK_CODE without // proper flags. @@ -512,11 +513,12 @@ typedef enum uc_query_type { // unicorn tlb type selection typedef enum uc_tlb_type { - // The default unicorn virtuall TLB implementation. + // The default unicorn virtuall TLB implementation. // The tlb implementation of the CPU, best to use for full system emulation. UC_TLB_CPU = 0, // This tlb defaults to virtuall address == physical address - // Also a hook is availible to override the tlb entries (see uc_cb_tlbevent_t). + // Also a hook is availible to override the tlb entries (see + // uc_cb_tlbevent_t). UC_TLB_VIRTUAL } uc_tlb_type; @@ -573,8 +575,15 @@ typedef enum uc_control_type { // Change the tlb implementation // see uc_tlb_type for current implemented types // Write: @args = (int) - UC_CTL_TLB_TYPE - + UC_CTL_TLB_TYPE, + // Change the tcg translation buffer size, note that + // unicorn may adjust this value. + // Write: @args = (uint32_t) + // Read: @args = (uint32_t*) + UC_CTL_TCG_BUFFER_SIZE, + // controle if context_save/restore should work with snapshots + // Write: @args = (int) + UC_CTL_CONTEXT_MODE, } uc_control_type; /* @@ -650,7 +659,14 @@ See sample_ctl.c for a detailed example. uc_ctl(uc, UC_CTL_READ_WRITE(UC_CTL_TB_REQUEST_CACHE, 2), (address), (tb)) #define uc_ctl_flush_tb(uc) uc_ctl(uc, UC_CTL_WRITE(UC_CTL_TB_FLUSH, 0)) #define uc_ctl_flush_tlb(uc) uc_ctl(uc, UC_CTL_WRITE(UC_CTL_TLB_FLUSH, 0)) -#define uc_ctl_tlb_mode(uc, mode) uc_ctl(uc, UC_CTL_WRITE(UC_CTL_TLB_TYPE, 1), (mode)) +#define uc_ctl_tlb_mode(uc, mode) \ + uc_ctl(uc, UC_CTL_WRITE(UC_CTL_TLB_TYPE, 1), (mode)) +#define uc_ctl_get_tcg_buffer_size(uc, size) \ + uc_ctl(uc, UC_CTL_READ(UC_CTL_TCG_BUFFER_SIZE, 1), (size)) +#define uc_ctl_set_tcg_buffer_size(uc, size) \ + uc_ctl(uc, UC_CTL_WRITE(UC_CTL_TCG_BUFFER_SIZE, 1), (size)) +#define uc_ctl_context_mode(uc, mode) uc_ctl(uc, UC_CTL_WRITE(UC_CTL_CONTEXT_MODE, 1), (mode)) + // Opaque storage for CPU context, used with uc_context_*() struct uc_context; typedef struct uc_context uc_context; @@ -768,10 +784,9 @@ const char *uc_strerror(uc_err code); @uc: handle returned by uc_open() @regid: register ID that is to be modified. - @value: pointer to the value that will set to register @regid + @value: pointer to the value that will be written to register @regid - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). + @return UC_ERR_OK on success; UC_ERR_ARG if register number or value is invalid */ UNICORN_EXPORT uc_err uc_reg_write(uc_engine *uc, int regid, const void *value); @@ -783,22 +798,49 @@ uc_err uc_reg_write(uc_engine *uc, int regid, const void *value); @regid: register ID that is to be retrieved. @value: pointer to a variable storing the register value. - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). + @return UC_ERR_OK on success; UC_ERR_ARG if register number or value is invalid */ UNICORN_EXPORT uc_err uc_reg_read(uc_engine *uc, int regid, void *value); +/* + Write to register. + + @uc: handle returned by uc_open() + @regid: register ID that is to be modified. + @value: pointer to the value that will be written to register @regid + @size: size of value being written; on return, size of value written + + @return UC_ERR_OK on success; UC_ERR_ARG if register number or value is + invalid; UC_ERR_OVERFLOW if value is not large enough for the register. +*/ +UNICORN_EXPORT +uc_err uc_reg_write2(uc_engine *uc, int regid, const void *value, size_t *size); + +/* + Read register value. + + @uc: handle returned by uc_open() + @regid: register ID that is to be retrieved. + @value: pointer to a variable storing the register value. + @size: size of value buffer; on return, size of value read + + @return UC_ERR_OK on success; UC_ERR_ARG if register number or value is + invalid; UC_ERR_OVERFLOW if value is not large enough to hold the register. +*/ +UNICORN_EXPORT +uc_err uc_reg_read2(uc_engine *uc, int regid, void *value, size_t *size); + /* Write multiple register values. @uc: handle returned by uc_open() - @rges: array of register IDs to store - @value: pointer to array of register values + @regs: array of register IDs to store + @vals: array of pointers to register values @count: length of both *regs and *vals - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). + @return UC_ERR_OK on success; UC_ERR_ARG if some register number or value is + invalid */ UNICORN_EXPORT uc_err uc_reg_write_batch(uc_engine *uc, int *regs, void *const *vals, @@ -808,16 +850,51 @@ uc_err uc_reg_write_batch(uc_engine *uc, int *regs, void *const *vals, Read multiple register values. @uc: handle returned by uc_open() - @rges: array of register IDs to retrieve - @value: pointer to array of values to hold registers + @regs: array of register IDs to retrieve + @vals: array of pointers to register values @count: length of both *regs and *vals - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). + @return UC_ERR_OK on success; UC_ERR_ARG if some register number or value is + invalid */ UNICORN_EXPORT uc_err uc_reg_read_batch(uc_engine *uc, int *regs, void **vals, int count); +/* + Write multiple register values. + + @uc: handle returned by uc_open() + @regs: array of register IDs to store + @value: array of pointers to register values + @sizes: array of sizes of each value; on return, sizes of each stored register + @count: length of *regs, *vals and *sizes + + @return UC_ERR_OK on success; UC_ERR_ARG if some register number or value is + invalid; UC_ERR_OVERFLOW if some value is not large enough for the + corresponding register. +*/ +UNICORN_EXPORT +uc_err uc_reg_write_batch2(uc_engine *uc, int *regs, const void *const *vals, + size_t *sizes, int count); + +/* + Read multiple register values. + + @uc: handle returned by uc_open() + @regs: array of register IDs to retrieve + @value: pointer to array of values to hold registers + @sizes: array of sizes of each value; on return, sizes of each retrieved + register + @count: length of *regs, *vals and *sizes + + @return UC_ERR_OK on success; UC_ERR_ARG if some register number or value is + invalid; UC_ERR_OVERFLOW if some value is not large enough to hold the + corresponding register. +*/ +UNICORN_EXPORT +uc_err uc_reg_read_batch2(uc_engine *uc, int *regs, void *const *vals, + size_t *sizes, int count); + /* Write to a range of bytes in memory. @@ -942,6 +1019,11 @@ struct uc_tlb_entry { uc_prot perms; }; +typedef enum uc_context_content { + UC_CTL_CONTEXT_CPU = 1, + UC_CTL_CONTEXT_MEMORY = 2, +} uc_context_content; + /* Map memory in for emulation. This API adds a memory region that can be used by emulation. @@ -1120,10 +1202,9 @@ uc_err uc_context_save(uc_engine *uc, uc_context *context); @ctx: handle returned by uc_context_alloc() @regid: register ID that is to be modified. - @value: pointer to the value that will set to register @regid + @value: pointer to the value that will be written to register @regid - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). + @return UC_ERR_OK on success; UC_ERR_ARG if register number or value is invalid */ UNICORN_EXPORT uc_err uc_context_reg_write(uc_context *ctx, int regid, const void *value); @@ -1135,12 +1216,41 @@ uc_err uc_context_reg_write(uc_context *ctx, int regid, const void *value); @regid: register ID that is to be retrieved. @value: pointer to a variable storing the register value. - @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum - for detailed error). + @return UC_ERR_OK on success; UC_ERR_ARG if register number or value is invalid */ UNICORN_EXPORT uc_err uc_context_reg_read(uc_context *ctx, int regid, void *value); +/* + Write value to a register of a context. + + @ctx: handle returned by uc_context_alloc() + @regid: register ID that is to be modified. + @value: pointer to the value that will be written to register @regid + @size: size of value being written; on return, size of value written + + @return UC_ERR_OK on success; UC_ERR_ARG if register number or value is + invalid; UC_ERR_OVERFLOW if value is not large enough for the register. +*/ +UNICORN_EXPORT +uc_err uc_context_reg_write2(uc_context *ctx, int regid, const void *value, + size_t *size); + +/* + Read register value from a context. + + @ctx: handle returned by uc_context_alloc() + @regid: register ID that is to be retrieved. + @value: pointer to a variable storing the register value. + @size: size of value buffer; on return, size of value read + + @return UC_ERR_OK on success; UC_ERR_ARG if register number or value is + invalid; UC_ERR_OVERFLOW if value is not large enough to hold the register. +*/ +UNICORN_EXPORT +uc_err uc_context_reg_read2(uc_context *ctx, int regid, void *value, + size_t *size); + /* Write multiple register values to registers of a context. @@ -1171,6 +1281,42 @@ UNICORN_EXPORT uc_err uc_context_reg_read_batch(uc_context *ctx, int *regs, void **vals, int count); +/* + Write multiple register values to registers of a context. + + @ctx: handle returned by uc_context_alloc() + @regs: array of register IDs to store + @value: array of pointers to register values + @sizes: array of sizes of each value; on return, sizes of each stored register + @count: length of *regs, *vals and *sizes + + @return UC_ERR_OK on success; UC_ERR_ARG if some register number or value is + invalid; UC_ERR_OVERFLOW if some value is not large enough for the + corresponding register. +*/ +UNICORN_EXPORT +uc_err uc_context_reg_write_batch2(uc_context *ctx, int *regs, + const void *const *vals, size_t *sizes, + int count); + +/* + Read multiple register values from a context. + + @ctx: handle returned by uc_context_alloc() + @regs: array of register IDs to retrieve + @value: pointer to array of values to hold registers + @sizes: array of sizes of each value; on return, sizes of each retrieved + register + @count: length of *regs, *vals and *sizes + + @return UC_ERR_OK on success; UC_ERR_ARG if some register number or value is + invalid; UC_ERR_OVERFLOW if some value is not large enough to hold the + corresponding register. +*/ +UNICORN_EXPORT +uc_err uc_context_reg_read_batch2(uc_context *ctx, int *regs, void *const *vals, + size_t *sizes, int count); + /* Restore the current CPU context from a saved copy. This API should be used to roll the CPU context back to a previous diff --git a/msvc/config-host.h b/msvc/config-host.h index a5e1e190..943d8593 100644 --- a/msvc/config-host.h +++ b/msvc/config-host.h @@ -7,10 +7,3 @@ #define CONFIG_CMPXCHG128 1 // #define CONFIG_ATOMIC64 1 #define CONFIG_PLUGIN 1 - -// QEMU by default allocates (and commits) 1GB memory on Windows, and multiple Unicorn instances will result in OOM error easily. -// Unfortunately, Windows doesn't have a similar demand paging feature like mmap(), therefore a workaround is to use tcg regions mechanism. -// Note most Unicorn hacks (and even QEMU!) relies on the assumption that the translation memory won't run out and thus it might result -// in some unexpected errors. If that is case, define WIN32_QEMU_ALLOC_BUFFER to align with QEMU and Unicorn <= 2.0.1 behavior. -// -// #define WIN32_QEMU_ALLOC_BUFFER \ No newline at end of file diff --git a/qemu/aarch64.h b/qemu/aarch64.h index c678501b..106ffd2f 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -5,6 +5,9 @@ #define UNICORN_ARCH_POSTFIX _aarch64 #endif #define unicorn_fill_tlb unicorn_fill_tlb_aarch64 +#define reg_read reg_read_aarch64 +#define reg_write reg_write_aarch64 +#define uc_init uc_init_aarch64 #define uc_add_inline_hook uc_add_inline_hook_aarch64 #define uc_del_inline_hook uc_del_inline_hook_aarch64 #define tb_invalidate_phys_range tb_invalidate_phys_range_aarch64 @@ -120,7 +123,10 @@ #define memory_map memory_map_aarch64 #define memory_map_io memory_map_io_aarch64 #define memory_map_ptr memory_map_ptr_aarch64 +#define memory_cow memory_cow_aarch64 #define memory_unmap memory_unmap_aarch64 +#define memory_moveout memory_moveout_aarch64 +#define memory_movein memory_movein_aarch64 #define memory_free memory_free_aarch64 #define flatview_unref flatview_unref_aarch64 #define address_space_get_flatview address_space_get_flatview_aarch64 @@ -139,7 +145,9 @@ #define memory_region_get_ram_addr memory_region_get_ram_addr_aarch64 #define memory_region_add_subregion memory_region_add_subregion_aarch64 #define memory_region_del_subregion memory_region_del_subregion_aarch64 +#define memory_region_add_subregion_overlap memory_region_add_subregion_overlap_aarch64 #define memory_region_find memory_region_find_aarch64 +#define memory_region_filter_subregions memory_region_filter_subregions_aarch64 #define memory_listener_register memory_listener_register_aarch64 #define memory_listener_unregister memory_listener_unregister_aarch64 #define address_space_remove_listeners address_space_remove_listeners_aarch64 @@ -147,6 +155,7 @@ #define address_space_destroy address_space_destroy_aarch64 #define memory_region_init_ram memory_region_init_ram_aarch64 #define memory_mapping_list_add_merge_sorted memory_mapping_list_add_merge_sorted_aarch64 +#define find_memory_mapping find_memory_mapping_aarch64 #define exec_inline_op exec_inline_op_aarch64 #define floatx80_default_nan floatx80_default_nan_aarch64 #define float_raise float_raise_aarch64 @@ -2959,9 +2968,6 @@ #define helper_frint32_d helper_frint32_d_aarch64 #define helper_frint64_d helper_frint64_d_aarch64 #define helper_check_hcr_el2_trap helper_check_hcr_el2_trap_aarch64 -#define arm64_reg_reset arm64_reg_reset_aarch64 -#define arm64_reg_read arm64_reg_read_aarch64 -#define arm64_reg_write arm64_reg_write_aarch64 #define mla_op mla_op_aarch64 #define mls_op mls_op_aarch64 #define sshl_op sshl_op_aarch64 diff --git a/qemu/accel/tcg/cputlb.c b/qemu/accel/tcg/cputlb.c index 659faf3f..c120d27b 100644 --- a/qemu/accel/tcg/cputlb.c +++ b/qemu/accel/tcg/cputlb.c @@ -1460,7 +1460,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, } paddr = entry->paddr | (addr & ~TARGET_PAGE_MASK); - mr = find_memory_region(uc, paddr); + mr = uc->memory_mapping(uc, paddr); // memory might be still unmapped while reading or fetching if (mr == NULL) { @@ -1517,24 +1517,28 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, tlb_addr &= ~TLB_INVALID_MASK; } paddr = entry->paddr | (addr & ~TARGET_PAGE_MASK); - mr = find_memory_region(uc, paddr); + mr = uc->memory_mapping(uc, paddr); if (mr == NULL) { uc->invalid_error = UC_ERR_MAP; - cpu_exit(uc->cpu); - // XXX(@lazymio): We have to exit early so that the target register won't be overwritten - // because qemu might generate tcg code like: - // qemu_ld_i64 x0,x1,leq,8 sync: 0 dead: 0 1 - // where we don't have a change to recover x0 value - cpu_loop_exit(uc->cpu); + if (uc->nested_level > 0 && !uc->cpu->stopped) { + cpu_exit(uc->cpu); + // XXX(@lazymio): We have to exit early so that the target register won't be overwritten + // because qemu might generate tcg code like: + // qemu_ld_i64 x0,x1,leq,8 sync: 0 dead: 0 1 + // where we don't have a change to recover x0 value + cpu_loop_exit(uc->cpu); + } return 0; } } else { uc->invalid_addr = paddr; uc->invalid_error = error_code; // printf("***** Invalid fetch (unmapped memory) at " TARGET_FMT_lx "\n", addr); - cpu_exit(uc->cpu); - // See comments above - cpu_loop_exit(uc->cpu); + if (uc->nested_level > 0 && !uc->cpu->stopped) { + cpu_exit(uc->cpu); + // See comments above + cpu_loop_exit(uc->cpu); + } return 0; } } @@ -1588,9 +1592,11 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uc->invalid_addr = paddr; uc->invalid_error = UC_ERR_READ_PROT; // printf("***** Invalid memory read (non-readable) at " TARGET_FMT_lx "\n", addr); - cpu_exit(uc->cpu); - // See comments above - cpu_loop_exit(uc->cpu); + if (uc->nested_level > 0 && !uc->cpu->stopped) { + cpu_exit(uc->cpu); + // See comments above + cpu_loop_exit(uc->cpu); + } return 0; } } @@ -1618,9 +1624,11 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uc->invalid_addr = paddr; uc->invalid_error = UC_ERR_FETCH_PROT; // printf("***** Invalid fetch (non-executable) at " TARGET_FMT_lx "\n", addr); - cpu_exit(uc->cpu); - // See comments above - cpu_loop_exit(uc->cpu); + if (uc->nested_level > 0 && !uc->cpu->stopped) { + cpu_exit(uc->cpu); + // See comments above + cpu_loop_exit(uc->cpu); + } return 0; } } @@ -2045,7 +2053,7 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, // Load the latest memory mapping. paddr = entry->paddr | (addr & ~TARGET_PAGE_MASK); - mr = find_memory_region(uc, paddr); + mr = uc->memory_mapping(uc, paddr); if (!uc->size_recur_mem) { // disabling write callback if in recursive call // Unicorn: callback on memory write @@ -2099,7 +2107,7 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, tlb_addr = tlb_addr_write(entry) & ~TLB_INVALID_MASK; } paddr = entry->paddr | (addr & ~TARGET_PAGE_MASK); - mr = find_memory_region(uc, paddr); + mr = uc->memory_mapping(uc, paddr); if (mr == NULL) { uc->invalid_error = UC_ERR_MAP; cpu_exit(uc->cpu); @@ -2117,7 +2125,7 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, continue; if (!HOOK_BOUND_CHECK(hook, paddr)) continue; - if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_WRITE_PROT, addr, size, val, hook->user_data))) + if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_WRITE_PROT, paddr, size, val, hook->user_data))) break; // the last callback may already asked to stop emulation @@ -2139,7 +2147,7 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, } uc->invalid_error = UC_ERR_OK; } else { - uc->invalid_addr = addr; + uc->invalid_addr = paddr; uc->invalid_error = UC_ERR_WRITE_PROT; // printf("***** Invalid memory write (ro) at " TARGET_FMT_lx "\n", addr); cpu_exit(uc->cpu); @@ -2147,6 +2155,22 @@ store_helper(CPUArchState *env, target_ulong addr, uint64_t val, } } + if (uc->snapshot_level && mr->ram && mr->priority < uc->snapshot_level) { + mr = memory_cow(uc, mr, addr & TARGET_PAGE_MASK, TARGET_PAGE_SIZE); + if (!mr) { + uc->invalid_addr = paddr; + uc->invalid_error = UC_ERR_NOMEM; + cpu_exit(uc->cpu); + return; + } + /* refill tlb after CoW */ + tlb_fill(env_cpu(env), paddr, size, MMU_DATA_STORE, + mmu_idx, retaddr); + index = tlb_index(env, mmu_idx, addr); + entry = tlb_entry(env, mmu_idx, addr); + tlb_addr = tlb_addr_write(entry); + } + /* Handle anything that isn't just a straight memory access. */ if (unlikely(tlb_addr & ~TARGET_PAGE_MASK)) { CPUIOTLBEntry *iotlbentry; diff --git a/qemu/accel/tcg/translate-all.c b/qemu/accel/tcg/translate-all.c index 56ddb35e..e476c89e 100644 --- a/qemu/accel/tcg/translate-all.c +++ b/qemu/accel/tcg/translate-all.c @@ -869,35 +869,145 @@ static inline void *alloc_code_gen_buffer(struct uc_struct *uc) return buf; } #elif defined(_WIN32) -#ifdef WIN32_QEMU_ALLOC_BUFFER -static inline void *alloc_code_gen_buffer(struct uc_struct *uc) -{ - TCGContext *tcg_ctx = uc->tcg_ctx; - size_t size = tcg_ctx->code_gen_buffer_size; - return VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, - PAGE_EXECUTE_READWRITE); -} +#define COMMIT_COUNT (1024) // Commit 4MB per exception +#define CLOSURE_SIZE (4096) + +#ifdef _WIN64 +static LONG code_gen_buffer_handler(PEXCEPTION_POINTERS ptr, struct uc_struct *uc) #else +/* +The first two DWORD or smaller arguments that are found in the argument list +from left to right are passed in ECX and EDX registers; all other arguments +are passed on the stack from right to left. +*/ +static LONG __fastcall code_gen_buffer_handler(PEXCEPTION_POINTERS ptr, struct uc_struct* uc) +#endif +{ + PEXCEPTION_RECORD record = ptr->ExceptionRecord; + if (record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { + uint8_t* base = (uint8_t*)(record->ExceptionInformation[1]); + uint8_t* left = uc->tcg_ctx->initial_buffer; + uint8_t* right = left + uc->tcg_ctx->initial_buffer_size; + if (left && base >= left && base < right) { + // It's our region + uint8_t* base_end = base + COMMIT_COUNT * 4096; + uint32_t size = COMMIT_COUNT * 4096; + if (base_end >= right) { + size = base_end - base; + // whoops, we are almost run out of memory! Commit all instead + } + if (VirtualAlloc(base, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE)) { + return EXCEPTION_CONTINUE_EXECUTION; + } else { + return EXCEPTION_CONTINUE_SEARCH; + } + } + } + return EXCEPTION_CONTINUE_SEARCH; +} + +static inline void may_remove_handler(struct uc_struct *uc) { + if (uc->seh_closure) { + if (uc->seh_handle) { + RemoveVectoredExceptionHandler(uc->seh_handle); + } + VirtualFree(uc->seh_closure, 0, MEM_RELEASE); + } +} + static inline void *alloc_code_gen_buffer(struct uc_struct *uc) { TCGContext *tcg_ctx = uc->tcg_ctx; size_t size = tcg_ctx->code_gen_buffer_size; + uint8_t *closure, *data; + uint8_t *ptr; + void* handler = code_gen_buffer_handler; - void* ptr = VirtualAlloc(NULL, size, MEM_RESERVE, - PAGE_EXECUTE_READWRITE); + may_remove_handler(uc); - // for prolog init - VirtualAlloc(ptr, - uc->qemu_real_host_page_size * UC_TCG_REGION_PAGES_COUNT, - MEM_COMMIT, - PAGE_EXECUTE_READWRITE); - return ptr; -} + // Naive trampoline implementation + closure = VirtualAlloc(NULL, CLOSURE_SIZE, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE); + if (!closure) { + return NULL; + } + uc->seh_closure = closure; + data = closure + CLOSURE_SIZE /2; + +#ifdef _WIN64 + ptr = closure; + *ptr = 0x48; // REX.w + ptr += 1; + *ptr = 0xb8; // mov rax + ptr += 1; + memcpy(ptr, &data, 8); // mov rax, &data + ptr += 8; + // ; rax = &data + // mov [rax], rdx ; save rdx + // mov rdx, [rax+0x8] ; move uc pointer to 2nd arg + // sub rsp, 0x10; reserve 2 slots as ms fastcall requires + // call [rax + 0x10] ; go to handler + const char tramp[] = "\x48\x89\x10\x48\x8b\x50\x08\x48\x83\xec\x10\xff\x50\x10"; + memcpy(ptr, (void*)tramp, sizeof(tramp) - 1); // Note last zero! + ptr += sizeof(tramp) - 1; + *ptr = 0x48; // REX.w + ptr += 1; + *ptr = 0xba; // mov rdx + ptr += 1; + memcpy(ptr, &data, 8); // mov rdx, &data + ptr += 8; + // ; rdx = &data + // add rsp, 0x10 ; clean stack + // mov rdx, [rdx] ; restore rdx + // ret + const char tramp2[] = "\x48\x83\xc4\x10\x48\x8b\x12\xc3"; + memcpy(ptr, (void*)tramp2, sizeof(tramp2) - 1); + + memcpy(data + 0x8, (void*)&uc, 8); + memcpy(data + 0x10, (void*)&handler, 8); +#else + ptr = closure; + *ptr = 0xb8; // mov eax + ptr += 1; + memcpy(ptr, (void*)&data, 4); // mov eax, &data + ptr += 4; + // ; eax = &data + // mov [eax], edx; save edx + // mov [eax+0x4], ecx; save ecx + // mov ecx, [esp+4]; get ptr to exception because of cdecl + // mov edx, [eax+0x8]; get ptr to uc + // call [eax + 0xC]; get ptr to our handler, it's fastcall so we don't clean stac + const char tramp[] = "\x89\x10\x89\x48\x04\x8b\x4c\x24\x04\x8b\x50\x08\xff\x50\x0c"; + memcpy(ptr, (void*)tramp, sizeof(tramp) - 1); + ptr += sizeof(tramp) - 1; + *ptr = 0xb9; // mov ecx + ptr += 1; + memcpy(ptr, (void*)&data, 4); // mov ecx, &data + ptr += 4; + + // mov edx, [ecx] ; restore edx + // mov ecx, [ecx+4] ; restore ecx + // ret + const char tramp2[] = "\x8b\x11\x8b\x49\x04\xc3"; + memcpy(ptr, (void*)tramp2, sizeof(tramp2) - 1); + + memcpy(data + 0x8, (void*)&uc, 4); + memcpy(data + 0xC, (void*)&handler, 4); #endif + + uc->seh_handle = AddVectoredExceptionHandler(0, (PVECTORED_EXCEPTION_HANDLER)closure); + if (!uc->seh_handle) { + VirtualFree(uc->seh_closure, 0, MEM_RELEASE); + uc->seh_closure = NULL; + return NULL; + } + + return VirtualAlloc(NULL, size, MEM_RESERVE, PAGE_EXECUTE_READWRITE); +} void free_code_gen_buffer(struct uc_struct *uc) { TCGContext *tcg_ctx = uc->tcg_ctx; if (tcg_ctx->initial_buffer) { + may_remove_handler(uc); VirtualFree(tcg_ctx->initial_buffer, 0, MEM_RELEASE); } } @@ -975,6 +1085,7 @@ static inline void code_gen_alloc(struct uc_struct *uc, size_t tb_size) tcg_ctx->code_gen_buffer = alloc_code_gen_buffer(uc); tcg_ctx->initial_buffer = tcg_ctx->code_gen_buffer; tcg_ctx->initial_buffer_size = tcg_ctx->code_gen_buffer_size; + uc->tcg_buffer_size = tcg_ctx->initial_buffer_size; if (tcg_ctx->code_gen_buffer == NULL) { fprintf(stderr, "Could not allocate dynamic translator buffer\n"); exit(1); @@ -1018,11 +1129,13 @@ static void uc_invalidate_tb(struct uc_struct *uc, uint64_t start_addr, size_t l return; } - // GPA to GVA + // GPA to ram addr + // https://raw.githubusercontent.com/android/platform_external_qemu/master/docs/QEMU-MEMORY-MANAGEMENT.TXT // start_addr : GPA - // addr: GVA + // start (returned): ram addr // (GPA -> HVA via memory_region_get_ram_addr(mr) + GPA + block->host, - // HVA->HPA via host mmu) + // GVA -> GPA via tlb & softmmu + // HVA -> HPA via host mmu) start = get_page_addr_code(uc->cpu->env_ptr, start_addr) & (target_ulong)(-1); uc->nested_level--; @@ -1097,7 +1210,7 @@ static uc_err uc_gen_tb(struct uc_struct *uc, uint64_t addr, uc_tb *out_tb) /* Must be called before using the QEMU cpus. 'tb_size' is the size (in bytes) allocated to the translation buffer. Zero means default size. */ -void tcg_exec_init(struct uc_struct *uc, unsigned long tb_size) +void tcg_exec_init(struct uc_struct *uc, uint32_t tb_size) { /* remove tcg object. init here. */ /* tcg class init: tcg-all.c:tcg_accel_class_init(), skip all. */ diff --git a/qemu/arm.h b/qemu/arm.h index 13e8ffee..42ad9c51 100644 --- a/qemu/arm.h +++ b/qemu/arm.h @@ -5,6 +5,9 @@ #define UNICORN_ARCH_POSTFIX _arm #endif #define unicorn_fill_tlb unicorn_fill_tlb_arm +#define reg_read reg_read_arm +#define reg_write reg_write_arm +#define uc_init uc_init_arm #define uc_add_inline_hook uc_add_inline_hook_arm #define uc_del_inline_hook uc_del_inline_hook_arm #define tb_invalidate_phys_range tb_invalidate_phys_range_arm @@ -120,7 +123,10 @@ #define memory_map memory_map_arm #define memory_map_io memory_map_io_arm #define memory_map_ptr memory_map_ptr_arm +#define memory_cow memory_cow_arm #define memory_unmap memory_unmap_arm +#define memory_moveout memory_moveout_arm +#define memory_movein memory_movein_arm #define memory_free memory_free_arm #define flatview_unref flatview_unref_arm #define address_space_get_flatview address_space_get_flatview_arm @@ -139,7 +145,9 @@ #define memory_region_get_ram_addr memory_region_get_ram_addr_arm #define memory_region_add_subregion memory_region_add_subregion_arm #define memory_region_del_subregion memory_region_del_subregion_arm +#define memory_region_add_subregion_overlap memory_region_add_subregion_overlap_arm #define memory_region_find memory_region_find_arm +#define memory_region_filter_subregions memory_region_filter_subregions_arm #define memory_listener_register memory_listener_register_arm #define memory_listener_unregister memory_listener_unregister_arm #define address_space_remove_listeners address_space_remove_listeners_arm @@ -147,6 +155,7 @@ #define address_space_destroy address_space_destroy_arm #define memory_region_init_ram memory_region_init_ram_arm #define memory_mapping_list_add_merge_sorted memory_mapping_list_add_merge_sorted_arm +#define find_memory_mapping find_memory_mapping_arm #define exec_inline_op exec_inline_op_arm #define floatx80_default_nan floatx80_default_nan_arm #define float_raise float_raise_arm @@ -1970,9 +1979,6 @@ #define helper_frint32_d helper_frint32_d_arm #define helper_frint64_d helper_frint64_d_arm #define helper_check_hcr_el2_trap helper_check_hcr_el2_trap_arm -#define arm_reg_reset arm_reg_reset_arm -#define arm_reg_read arm_reg_read_arm -#define arm_reg_write arm_reg_write_arm #define mla_op mla_op_arm #define mls_op mls_op_arm #define sshl_op sshl_op_arm diff --git a/qemu/exec.c b/qemu/exec.c index 2a664788..af77e5de 100644 --- a/qemu/exec.c +++ b/qemu/exec.c @@ -955,6 +955,21 @@ void flatview_add_to_dispatch(struct uc_struct *uc, FlatView *fv, MemoryRegionSe register_subpage(uc, fv, &remain); } +static ram_addr_t find_ram_offset_last(struct uc_struct *uc, ram_addr_t size) +{ + RAMBlock *block; + ram_addr_t result = 0; + + RAMBLOCK_FOREACH(block) { + result = MAX(block->offset + block->max_length, result); + } + + if (result + size > RAM_ADDR_MAX) { + abort(); + } + return result; +} + /* Allocate space within the ram_addr_t space that governs the * dirty bitmaps. * Called with the ramlist lock held. @@ -970,6 +985,10 @@ static ram_addr_t find_ram_offset(struct uc_struct *uc, ram_addr_t size) return 0; } + if (!uc->ram_list.freed) { + return find_ram_offset_last(uc, size); + } + RAMBLOCK_FOREACH(block) { ram_addr_t candidate, next = RAM_ADDR_MAX; @@ -1145,6 +1164,7 @@ void qemu_ram_free(struct uc_struct *uc, RAMBlock *block) QLIST_REMOVE_RCU(block, next); uc->ram_list.mru_block = NULL; + uc->ram_list.freed = true; /* Write list before version */ //smp_wmb(); // call_rcu(block, reclaim_ramblock, rcu); diff --git a/qemu/include/exec/memory.h b/qemu/include/exec/memory.h index a4b36e53..8a8d13c3 100644 --- a/qemu/include/exec/memory.h +++ b/qemu/include/exec/memory.h @@ -687,6 +687,35 @@ void memory_region_add_subregion(MemoryRegion *mr, hwaddr offset, MemoryRegion *subregion); +/** + * memory_region_add_subregion_overlap: Add a subregion to a container + * with overlap. + * + * Adds a subregion at @offset. The subregion may overlap with other + * subregions. Conflicts are resolved by having a higher @priority hide a + * lower @priority. Subregions without priority are taken as @priority 0. + * A region may only be added once as a subregion (unless removed with + * memory_region_del_subregion()); use memory_region_init_alias() if you + * want a region to be a subregion in multiple locations. + * + * @mr: the region to contain the new subregion; must be a container + * initialized with memory_region_init(). + * @offset: the offset relative to @mr where @subregion is added. + * @subregion: the subregion to be added. + * @priority: used for resolving overlaps; highest priority wins. + */ +void memory_region_add_subregion_overlap(MemoryRegion *mr, + hwaddr offset, + MemoryRegion *subregion, + int priority); + +/** + * memory_region_filter_subregions: filter subregios by priority. + * + * remove all subregions beginning by a specified subregion + */ +void memory_region_filter_subregions(MemoryRegion *mr, int32_t level); + /** * memory_region_get_ram_addr: Get the ram address associated with a memory * region @@ -1186,7 +1215,10 @@ MemoryRegion *memory_map(struct uc_struct *uc, hwaddr begin, size_t size, uint32 MemoryRegion *memory_map_ptr(struct uc_struct *uc, hwaddr begin, size_t size, uint32_t perms, void *ptr); MemoryRegion *memory_map_io(struct uc_struct *uc, ram_addr_t begin, size_t size, uc_cb_mmio_read_t read_cb, uc_cb_mmio_write_t write_cb, void *user_data_read, void *user_data_write); +MemoryRegion *memory_cow(struct uc_struct *uc, MemoryRegion *parrent, hwaddr begin, size_t size); void memory_unmap(struct uc_struct *uc, MemoryRegion *mr); +void memory_moveout(struct uc_struct *uc, MemoryRegion *mr); +void memory_movein(struct uc_struct *uc, MemoryRegion *mr); int memory_free(struct uc_struct *uc); #endif diff --git a/qemu/include/sysemu/os-win32.h b/qemu/include/sysemu/os-win32.h index 44e37d7e..d77d0fba 100644 --- a/qemu/include/sysemu/os-win32.h +++ b/qemu/include/sysemu/os-win32.h @@ -28,6 +28,7 @@ #include #include +#include // For vectorized handler #include #if defined(_WIN64) diff --git a/qemu/include/sysemu/tcg.h b/qemu/include/sysemu/tcg.h index ea267831..2aa7296f 100644 --- a/qemu/include/sysemu/tcg.h +++ b/qemu/include/sysemu/tcg.h @@ -9,11 +9,11 @@ #define SYSEMU_TCG_H #include - +#include //#include "uc_priv.h" struct uc_struct; -void tcg_exec_init(struct uc_struct *uc, unsigned long tb_size); +void tcg_exec_init(struct uc_struct *uc, uint32_t tb_size); #endif diff --git a/qemu/include/tcg/tcg.h b/qemu/include/tcg/tcg.h index 1134c75c..f3643fe3 100644 --- a/qemu/include/tcg/tcg.h +++ b/qemu/include/tcg/tcg.h @@ -35,11 +35,6 @@ #include "tcg-apple-jit.h" #include "qemu/int128.h" -// Unicorn: Default region size for win32 -#if defined(_WIN32) && !defined(WIN32_QEMU_ALLOC_BUFFER) -#define UC_TCG_REGION_PAGES_COUNT (128) // Note less pages may cause unexpected and subtle errors. -#endif - /* XXX: make safe guess about sizes */ #define MAX_OP_PER_INSTR 266 diff --git a/qemu/m68k.h b/qemu/m68k.h index 23f5d93a..a743b019 100644 --- a/qemu/m68k.h +++ b/qemu/m68k.h @@ -5,6 +5,9 @@ #define UNICORN_ARCH_POSTFIX _m68k #endif #define unicorn_fill_tlb unicorn_fill_tlb_m68k +#define reg_read reg_read_m68k +#define reg_write reg_write_m68k +#define uc_init uc_init_m68k #define uc_add_inline_hook uc_add_inline_hook_m68k #define uc_del_inline_hook uc_del_inline_hook_m68k #define tb_invalidate_phys_range tb_invalidate_phys_range_m68k @@ -120,7 +123,10 @@ #define memory_map memory_map_m68k #define memory_map_io memory_map_io_m68k #define memory_map_ptr memory_map_ptr_m68k +#define memory_cow memory_cow_m68k #define memory_unmap memory_unmap_m68k +#define memory_moveout memory_moveout_m68k +#define memory_movein memory_movein_m68k #define memory_free memory_free_m68k #define flatview_unref flatview_unref_m68k #define address_space_get_flatview address_space_get_flatview_m68k @@ -139,7 +145,9 @@ #define memory_region_get_ram_addr memory_region_get_ram_addr_m68k #define memory_region_add_subregion memory_region_add_subregion_m68k #define memory_region_del_subregion memory_region_del_subregion_m68k +#define memory_region_add_subregion_overlap memory_region_add_subregion_overlap_m68k #define memory_region_find memory_region_find_m68k +#define memory_region_filter_subregions memory_region_filter_subregions_m68k #define memory_listener_register memory_listener_register_m68k #define memory_listener_unregister memory_listener_unregister_m68k #define address_space_remove_listeners address_space_remove_listeners_m68k @@ -147,6 +155,7 @@ #define address_space_destroy address_space_destroy_m68k #define memory_region_init_ram memory_region_init_ram_m68k #define memory_mapping_list_add_merge_sorted memory_mapping_list_add_merge_sorted_m68k +#define find_memory_mapping find_memory_mapping_m68k #define exec_inline_op exec_inline_op_m68k #define floatx80_default_nan floatx80_default_nan_m68k #define float_raise float_raise_m68k @@ -1433,7 +1442,4 @@ #define register_m68k_insns register_m68k_insns_m68k #define gen_intermediate_code gen_intermediate_code_m68k #define restore_state_to_opc restore_state_to_opc_m68k -#define m68k_reg_reset m68k_reg_reset_m68k -#define m68k_reg_read m68k_reg_read_m68k -#define m68k_reg_write m68k_reg_write_m68k #endif diff --git a/qemu/mips.h b/qemu/mips.h index 8aaa4de4..af08a938 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -5,6 +5,9 @@ #define UNICORN_ARCH_POSTFIX _mips #endif #define unicorn_fill_tlb unicorn_fill_tlb_mips +#define reg_read reg_read_mips +#define reg_write reg_write_mips +#define uc_init uc_init_mips #define uc_add_inline_hook uc_add_inline_hook_mips #define uc_del_inline_hook uc_del_inline_hook_mips #define tb_invalidate_phys_range tb_invalidate_phys_range_mips @@ -120,7 +123,10 @@ #define memory_map memory_map_mips #define memory_map_io memory_map_io_mips #define memory_map_ptr memory_map_ptr_mips +#define memory_cow memory_cow_mips #define memory_unmap memory_unmap_mips +#define memory_moveout memory_moveout_mips +#define memory_movein memory_movein_mips #define memory_free memory_free_mips #define flatview_unref flatview_unref_mips #define address_space_get_flatview address_space_get_flatview_mips @@ -139,7 +145,9 @@ #define memory_region_get_ram_addr memory_region_get_ram_addr_mips #define memory_region_add_subregion memory_region_add_subregion_mips #define memory_region_del_subregion memory_region_del_subregion_mips +#define memory_region_add_subregion_overlap memory_region_add_subregion_overlap_mips #define memory_region_find memory_region_find_mips +#define memory_region_filter_subregions memory_region_filter_subregions_mips #define memory_listener_register memory_listener_register_mips #define memory_listener_unregister memory_listener_unregister_mips #define address_space_remove_listeners address_space_remove_listeners_mips @@ -147,6 +155,7 @@ #define address_space_destroy address_space_destroy_mips #define memory_region_init_ram memory_region_init_ram_mips #define memory_mapping_list_add_merge_sorted memory_mapping_list_add_merge_sorted_mips +#define find_memory_mapping find_memory_mapping_mips #define exec_inline_op exec_inline_op_mips #define floatx80_default_nan floatx80_default_nan_mips #define float_raise float_raise_mips @@ -2385,9 +2394,6 @@ #define cpu_mips_realize_env cpu_mips_realize_env_mips #define cpu_state_reset cpu_state_reset_mips #define restore_state_to_opc restore_state_to_opc_mips -#define mips_reg_reset mips_reg_reset_mips -#define mips_reg_read mips_reg_read_mips -#define mips_reg_write mips_reg_write_mips #define ieee_rm ieee_rm_mips #define mips_defs mips_defs_mips #define mips_defs_number mips_defs_number_mips diff --git a/qemu/mips64.h b/qemu/mips64.h index 30f6b0ac..0b46bae1 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -5,6 +5,9 @@ #define UNICORN_ARCH_POSTFIX _mips64 #endif #define unicorn_fill_tlb unicorn_fill_tlb_mips64 +#define reg_read reg_read_mips64 +#define reg_write reg_write_mips64 +#define uc_init uc_init_mips64 #define uc_add_inline_hook uc_add_inline_hook_mips64 #define uc_del_inline_hook uc_del_inline_hook_mips64 #define tb_invalidate_phys_range tb_invalidate_phys_range_mips64 @@ -120,7 +123,10 @@ #define memory_map memory_map_mips64 #define memory_map_io memory_map_io_mips64 #define memory_map_ptr memory_map_ptr_mips64 +#define memory_cow memory_cow_mips64 #define memory_unmap memory_unmap_mips64 +#define memory_moveout memory_moveout_mips64 +#define memory_movein memory_movein_mips64 #define memory_free memory_free_mips64 #define flatview_unref flatview_unref_mips64 #define address_space_get_flatview address_space_get_flatview_mips64 @@ -139,7 +145,9 @@ #define memory_region_get_ram_addr memory_region_get_ram_addr_mips64 #define memory_region_add_subregion memory_region_add_subregion_mips64 #define memory_region_del_subregion memory_region_del_subregion_mips64 +#define memory_region_add_subregion_overlap memory_region_add_subregion_overlap_mips64 #define memory_region_find memory_region_find_mips64 +#define memory_region_filter_subregions memory_region_filter_subregions_mips64 #define memory_listener_register memory_listener_register_mips64 #define memory_listener_unregister memory_listener_unregister_mips64 #define address_space_remove_listeners address_space_remove_listeners_mips64 @@ -147,6 +155,7 @@ #define address_space_destroy address_space_destroy_mips64 #define memory_region_init_ram memory_region_init_ram_mips64 #define memory_mapping_list_add_merge_sorted memory_mapping_list_add_merge_sorted_mips64 +#define find_memory_mapping find_memory_mapping_mips64 #define exec_inline_op exec_inline_op_mips64 #define floatx80_default_nan floatx80_default_nan_mips64 #define float_raise float_raise_mips64 @@ -2385,9 +2394,6 @@ #define cpu_mips_realize_env cpu_mips_realize_env_mips64 #define cpu_state_reset cpu_state_reset_mips64 #define restore_state_to_opc restore_state_to_opc_mips64 -#define mips_reg_reset mips_reg_reset_mips64 -#define mips_reg_read mips_reg_read_mips64 -#define mips_reg_write mips_reg_write_mips64 #define ieee_rm ieee_rm_mips64 #define mips_defs mips_defs_mips64 #define mips_defs_number mips_defs_number_mips64 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index 115aa427..dd28ff03 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -5,6 +5,9 @@ #define UNICORN_ARCH_POSTFIX _mips64el #endif #define unicorn_fill_tlb unicorn_fill_tlb_mips64el +#define reg_read reg_read_mips64el +#define reg_write reg_write_mips64el +#define uc_init uc_init_mips64el #define uc_add_inline_hook uc_add_inline_hook_mips64el #define uc_del_inline_hook uc_del_inline_hook_mips64el #define tb_invalidate_phys_range tb_invalidate_phys_range_mips64el @@ -120,7 +123,10 @@ #define memory_map memory_map_mips64el #define memory_map_io memory_map_io_mips64el #define memory_map_ptr memory_map_ptr_mips64el +#define memory_cow memory_cow_mips64el #define memory_unmap memory_unmap_mips64el +#define memory_moveout memory_moveout_mips64el +#define memory_movein memory_movein_mips64el #define memory_free memory_free_mips64el #define flatview_unref flatview_unref_mips64el #define address_space_get_flatview address_space_get_flatview_mips64el @@ -139,7 +145,9 @@ #define memory_region_get_ram_addr memory_region_get_ram_addr_mips64el #define memory_region_add_subregion memory_region_add_subregion_mips64el #define memory_region_del_subregion memory_region_del_subregion_mips64el +#define memory_region_add_subregion_overlap memory_region_add_subregion_overlap_mips64el #define memory_region_find memory_region_find_mips64el +#define memory_region_filter_subregions memory_region_filter_subregions_mips64el #define memory_listener_register memory_listener_register_mips64el #define memory_listener_unregister memory_listener_unregister_mips64el #define address_space_remove_listeners address_space_remove_listeners_mips64el @@ -147,6 +155,7 @@ #define address_space_destroy address_space_destroy_mips64el #define memory_region_init_ram memory_region_init_ram_mips64el #define memory_mapping_list_add_merge_sorted memory_mapping_list_add_merge_sorted_mips64el +#define find_memory_mapping find_memory_mapping_mips64el #define exec_inline_op exec_inline_op_mips64el #define floatx80_default_nan floatx80_default_nan_mips64el #define float_raise float_raise_mips64el @@ -2385,9 +2394,6 @@ #define cpu_mips_realize_env cpu_mips_realize_env_mips64el #define cpu_state_reset cpu_state_reset_mips64el #define restore_state_to_opc restore_state_to_opc_mips64el -#define mips_reg_reset mips_reg_reset_mips64el -#define mips_reg_read mips_reg_read_mips64el -#define mips_reg_write mips_reg_write_mips64el #define ieee_rm ieee_rm_mips64el #define mips_defs mips_defs_mips64el #define mips_defs_number mips_defs_number_mips64el diff --git a/qemu/mipsel.h b/qemu/mipsel.h index 552c968e..864857c8 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -5,6 +5,9 @@ #define UNICORN_ARCH_POSTFIX _mipsel #endif #define unicorn_fill_tlb unicorn_fill_tlb_mipsel +#define reg_read reg_read_mipsel +#define reg_write reg_write_mipsel +#define uc_init uc_init_mipsel #define uc_add_inline_hook uc_add_inline_hook_mipsel #define uc_del_inline_hook uc_del_inline_hook_mipsel #define tb_invalidate_phys_range tb_invalidate_phys_range_mipsel @@ -120,7 +123,10 @@ #define memory_map memory_map_mipsel #define memory_map_io memory_map_io_mipsel #define memory_map_ptr memory_map_ptr_mipsel +#define memory_cow memory_cow_mipsel #define memory_unmap memory_unmap_mipsel +#define memory_moveout memory_moveout_mipsel +#define memory_movein memory_movein_mipsel #define memory_free memory_free_mipsel #define flatview_unref flatview_unref_mipsel #define address_space_get_flatview address_space_get_flatview_mipsel @@ -139,7 +145,9 @@ #define memory_region_get_ram_addr memory_region_get_ram_addr_mipsel #define memory_region_add_subregion memory_region_add_subregion_mipsel #define memory_region_del_subregion memory_region_del_subregion_mipsel +#define memory_region_add_subregion_overlap memory_region_add_subregion_overlap_mipsel #define memory_region_find memory_region_find_mipsel +#define memory_region_filter_subregions memory_region_filter_subregions_mipsel #define memory_listener_register memory_listener_register_mipsel #define memory_listener_unregister memory_listener_unregister_mipsel #define address_space_remove_listeners address_space_remove_listeners_mipsel @@ -147,6 +155,7 @@ #define address_space_destroy address_space_destroy_mipsel #define memory_region_init_ram memory_region_init_ram_mipsel #define memory_mapping_list_add_merge_sorted memory_mapping_list_add_merge_sorted_mipsel +#define find_memory_mapping find_memory_mapping_mipsel #define exec_inline_op exec_inline_op_mipsel #define floatx80_default_nan floatx80_default_nan_mipsel #define float_raise float_raise_mipsel @@ -2385,9 +2394,6 @@ #define cpu_mips_realize_env cpu_mips_realize_env_mipsel #define cpu_state_reset cpu_state_reset_mipsel #define restore_state_to_opc restore_state_to_opc_mipsel -#define mips_reg_reset mips_reg_reset_mipsel -#define mips_reg_read mips_reg_read_mipsel -#define mips_reg_write mips_reg_write_mipsel #define ieee_rm ieee_rm_mipsel #define mips_defs mips_defs_mipsel #define mips_defs_number mips_defs_number_mipsel diff --git a/qemu/ppc.h b/qemu/ppc.h index 67e3c4b9..710231b8 100644 --- a/qemu/ppc.h +++ b/qemu/ppc.h @@ -5,6 +5,9 @@ #define UNICORN_ARCH_POSTFIX _ppc #endif #define unicorn_fill_tlb unicorn_fill_tlb_ppc +#define reg_read reg_read_ppc +#define reg_write reg_write_ppc +#define uc_init uc_init_ppc #define uc_add_inline_hook uc_add_inline_hook_ppc #define uc_del_inline_hook uc_del_inline_hook_ppc #define tb_invalidate_phys_range tb_invalidate_phys_range_ppc @@ -120,7 +123,10 @@ #define memory_map memory_map_ppc #define memory_map_io memory_map_io_ppc #define memory_map_ptr memory_map_ptr_ppc +#define memory_cow memory_cow_ppc #define memory_unmap memory_unmap_ppc +#define memory_moveout memory_moveout_ppc +#define memory_movein memory_movein_ppc #define memory_free memory_free_ppc #define flatview_unref flatview_unref_ppc #define address_space_get_flatview address_space_get_flatview_ppc @@ -139,7 +145,9 @@ #define memory_region_get_ram_addr memory_region_get_ram_addr_ppc #define memory_region_add_subregion memory_region_add_subregion_ppc #define memory_region_del_subregion memory_region_del_subregion_ppc +#define memory_region_add_subregion_overlap memory_region_add_subregion_overlap_ppc #define memory_region_find memory_region_find_ppc +#define memory_region_filter_subregions memory_region_filter_subregions_ppc #define memory_listener_register memory_listener_register_ppc #define memory_listener_unregister memory_listener_unregister_ppc #define address_space_remove_listeners address_space_remove_listeners_ppc @@ -147,6 +155,7 @@ #define address_space_destroy address_space_destroy_ppc #define memory_region_init_ram memory_region_init_ram_ppc #define memory_mapping_list_add_merge_sorted memory_mapping_list_add_merge_sorted_ppc +#define find_memory_mapping find_memory_mapping_ppc #define exec_inline_op exec_inline_op_ppc #define floatx80_default_nan floatx80_default_nan_ppc #define float_raise float_raise_ppc @@ -1280,9 +1289,6 @@ #define gen_helper_cpsr_write gen_helper_cpsr_write_ppc #define ppc_cpu_unrealize ppc_cpu_unrealize_ppc #define ppc_cpu_instance_finalize ppc_cpu_instance_finalize_ppc -#define ppc_reg_reset ppc_reg_reset_ppc -#define ppc_reg_read ppc_reg_read_ppc -#define ppc_reg_write ppc_reg_write_ppc #define ppc_cpu_do_interrupt ppc_cpu_do_interrupt_ppc #define ppc_cpu_do_system_reset ppc_cpu_do_system_reset_ppc #define ppc_cpu_do_fwnmi_machine_check ppc_cpu_do_fwnmi_machine_check_ppc diff --git a/qemu/ppc64.h b/qemu/ppc64.h index 36ffbc64..41a4a3e3 100644 --- a/qemu/ppc64.h +++ b/qemu/ppc64.h @@ -5,6 +5,9 @@ #define UNICORN_ARCH_POSTFIX _ppc64 #endif #define unicorn_fill_tlb unicorn_fill_tlb_ppc64 +#define reg_read reg_read_ppc64 +#define reg_write reg_write_ppc64 +#define uc_init uc_init_ppc64 #define uc_add_inline_hook uc_add_inline_hook_ppc64 #define uc_del_inline_hook uc_del_inline_hook_ppc64 #define tb_invalidate_phys_range tb_invalidate_phys_range_ppc64 @@ -120,7 +123,10 @@ #define memory_map memory_map_ppc64 #define memory_map_io memory_map_io_ppc64 #define memory_map_ptr memory_map_ptr_ppc64 +#define memory_cow memory_cow_ppc64 #define memory_unmap memory_unmap_ppc64 +#define memory_moveout memory_moveout_ppc64 +#define memory_movein memory_movein_ppc64 #define memory_free memory_free_ppc64 #define flatview_unref flatview_unref_ppc64 #define address_space_get_flatview address_space_get_flatview_ppc64 @@ -139,7 +145,9 @@ #define memory_region_get_ram_addr memory_region_get_ram_addr_ppc64 #define memory_region_add_subregion memory_region_add_subregion_ppc64 #define memory_region_del_subregion memory_region_del_subregion_ppc64 +#define memory_region_add_subregion_overlap memory_region_add_subregion_overlap_ppc64 #define memory_region_find memory_region_find_ppc64 +#define memory_region_filter_subregions memory_region_filter_subregions_ppc64 #define memory_listener_register memory_listener_register_ppc64 #define memory_listener_unregister memory_listener_unregister_ppc64 #define address_space_remove_listeners address_space_remove_listeners_ppc64 @@ -147,6 +155,7 @@ #define address_space_destroy address_space_destroy_ppc64 #define memory_region_init_ram memory_region_init_ram_ppc64 #define memory_mapping_list_add_merge_sorted memory_mapping_list_add_merge_sorted_ppc64 +#define find_memory_mapping find_memory_mapping_ppc64 #define exec_inline_op exec_inline_op_ppc64 #define floatx80_default_nan floatx80_default_nan_ppc64 #define float_raise float_raise_ppc64 @@ -1280,9 +1289,6 @@ #define gen_helper_cpsr_write gen_helper_cpsr_write_ppc64 #define ppc_cpu_unrealize ppc_cpu_unrealize_ppc64 #define ppc_cpu_instance_finalize ppc_cpu_instance_finalize_ppc64 -#define ppc_reg_reset ppc_reg_reset_ppc64 -#define ppc_reg_read ppc_reg_read_ppc64 -#define ppc_reg_write ppc_reg_write_ppc64 #define ppc_cpu_do_interrupt ppc_cpu_do_interrupt_ppc64 #define ppc_cpu_do_system_reset ppc_cpu_do_system_reset_ppc64 #define ppc_cpu_do_fwnmi_machine_check ppc_cpu_do_fwnmi_machine_check_ppc64 diff --git a/qemu/riscv32.h b/qemu/riscv32.h index 94a8fc02..e4e24f52 100644 --- a/qemu/riscv32.h +++ b/qemu/riscv32.h @@ -5,6 +5,9 @@ #define UNICORN_ARCH_POSTFIX _riscv32 #endif #define unicorn_fill_tlb unicorn_fill_tlb_riscv32 +#define reg_read reg_read_riscv32 +#define reg_write reg_write_riscv32 +#define uc_init uc_init_riscv32 #define uc_add_inline_hook uc_add_inline_hook_riscv32 #define uc_del_inline_hook uc_del_inline_hook_riscv32 #define tb_invalidate_phys_range tb_invalidate_phys_range_riscv32 @@ -120,7 +123,10 @@ #define memory_map memory_map_riscv32 #define memory_map_io memory_map_io_riscv32 #define memory_map_ptr memory_map_ptr_riscv32 +#define memory_cow memory_cow_riscv32 #define memory_unmap memory_unmap_riscv32 +#define memory_moveout memory_moveout_riscv32 +#define memory_movein memory_movein_riscv32 #define memory_free memory_free_riscv32 #define flatview_unref flatview_unref_riscv32 #define address_space_get_flatview address_space_get_flatview_riscv32 @@ -139,7 +145,9 @@ #define memory_region_get_ram_addr memory_region_get_ram_addr_riscv32 #define memory_region_add_subregion memory_region_add_subregion_riscv32 #define memory_region_del_subregion memory_region_del_subregion_riscv32 +#define memory_region_add_subregion_overlap memory_region_add_subregion_overlap_riscv32 #define memory_region_find memory_region_find_riscv32 +#define memory_region_filter_subregions memory_region_filter_subregions_riscv32 #define memory_listener_register memory_listener_register_riscv32 #define memory_listener_unregister memory_listener_unregister_riscv32 #define address_space_remove_listeners address_space_remove_listeners_riscv32 @@ -147,6 +155,7 @@ #define address_space_destroy address_space_destroy_riscv32 #define memory_region_init_ram memory_region_init_ram_riscv32 #define memory_mapping_list_add_merge_sorted memory_mapping_list_add_merge_sorted_riscv32 +#define find_memory_mapping find_memory_mapping_riscv32 #define exec_inline_op exec_inline_op_riscv32 #define floatx80_default_nan floatx80_default_nan_riscv32 #define float_raise float_raise_riscv32 @@ -1361,9 +1370,6 @@ #define riscv_translate_init riscv_translate_init_riscv32 #define restore_state_to_opc restore_state_to_opc_riscv32 #define cpu_riscv_init cpu_riscv_init_riscv32 -#define riscv_reg_reset riscv_reg_reset_riscv32 -#define riscv_reg_read riscv_reg_read_riscv32 -#define riscv_reg_write riscv_reg_write_riscv32 #define helper_fcvt_l_s helper_fcvt_l_s_riscv32 #define helper_fcvt_lu_s helper_fcvt_lu_s_riscv32 #define helper_fcvt_s_l helper_fcvt_s_l_riscv32 diff --git a/qemu/riscv64.h b/qemu/riscv64.h index bfc0bff4..95a4b6ed 100644 --- a/qemu/riscv64.h +++ b/qemu/riscv64.h @@ -5,6 +5,9 @@ #define UNICORN_ARCH_POSTFIX _riscv64 #endif #define unicorn_fill_tlb unicorn_fill_tlb_riscv64 +#define reg_read reg_read_riscv64 +#define reg_write reg_write_riscv64 +#define uc_init uc_init_riscv64 #define uc_add_inline_hook uc_add_inline_hook_riscv64 #define uc_del_inline_hook uc_del_inline_hook_riscv64 #define tb_invalidate_phys_range tb_invalidate_phys_range_riscv64 @@ -120,7 +123,10 @@ #define memory_map memory_map_riscv64 #define memory_map_io memory_map_io_riscv64 #define memory_map_ptr memory_map_ptr_riscv64 +#define memory_cow memory_cow_riscv64 #define memory_unmap memory_unmap_riscv64 +#define memory_moveout memory_moveout_riscv64 +#define memory_movein memory_movein_riscv64 #define memory_free memory_free_riscv64 #define flatview_unref flatview_unref_riscv64 #define address_space_get_flatview address_space_get_flatview_riscv64 @@ -139,7 +145,9 @@ #define memory_region_get_ram_addr memory_region_get_ram_addr_riscv64 #define memory_region_add_subregion memory_region_add_subregion_riscv64 #define memory_region_del_subregion memory_region_del_subregion_riscv64 +#define memory_region_add_subregion_overlap memory_region_add_subregion_overlap_riscv64 #define memory_region_find memory_region_find_riscv64 +#define memory_region_filter_subregions memory_region_filter_subregions_riscv64 #define memory_listener_register memory_listener_register_riscv64 #define memory_listener_unregister memory_listener_unregister_riscv64 #define address_space_remove_listeners address_space_remove_listeners_riscv64 @@ -147,6 +155,7 @@ #define address_space_destroy address_space_destroy_riscv64 #define memory_region_init_ram memory_region_init_ram_riscv64 #define memory_mapping_list_add_merge_sorted memory_mapping_list_add_merge_sorted_riscv64 +#define find_memory_mapping find_memory_mapping_riscv64 #define exec_inline_op exec_inline_op_riscv64 #define floatx80_default_nan floatx80_default_nan_riscv64 #define float_raise float_raise_riscv64 @@ -1361,9 +1370,6 @@ #define riscv_translate_init riscv_translate_init_riscv64 #define restore_state_to_opc restore_state_to_opc_riscv64 #define cpu_riscv_init cpu_riscv_init_riscv64 -#define riscv_reg_reset riscv_reg_reset_riscv64 -#define riscv_reg_read riscv_reg_read_riscv64 -#define riscv_reg_write riscv_reg_write_riscv64 #define helper_fcvt_l_s helper_fcvt_l_s_riscv64 #define helper_fcvt_lu_s helper_fcvt_lu_s_riscv64 #define helper_fcvt_s_l helper_fcvt_s_l_riscv64 diff --git a/qemu/s390x.h b/qemu/s390x.h index b4295cbc..97e8ecd7 100644 --- a/qemu/s390x.h +++ b/qemu/s390x.h @@ -5,6 +5,9 @@ #define UNICORN_ARCH_POSTFIX _s390x #endif #define unicorn_fill_tlb unicorn_fill_tlb_s390x +#define reg_read reg_read_s390x +#define reg_write reg_write_s390x +#define uc_init uc_init_s390x #define uc_add_inline_hook uc_add_inline_hook_s390x #define uc_del_inline_hook uc_del_inline_hook_s390x #define tb_invalidate_phys_range tb_invalidate_phys_range_s390x @@ -120,7 +123,10 @@ #define memory_map memory_map_s390x #define memory_map_io memory_map_io_s390x #define memory_map_ptr memory_map_ptr_s390x +#define memory_cow memory_cow_s390x #define memory_unmap memory_unmap_s390x +#define memory_moveout memory_moveout_s390x +#define memory_movein memory_movein_s390x #define memory_free memory_free_s390x #define flatview_unref flatview_unref_s390x #define address_space_get_flatview address_space_get_flatview_s390x @@ -139,7 +145,9 @@ #define memory_region_get_ram_addr memory_region_get_ram_addr_s390x #define memory_region_add_subregion memory_region_add_subregion_s390x #define memory_region_del_subregion memory_region_del_subregion_s390x +#define memory_region_add_subregion_overlap memory_region_add_subregion_overlap_s390x #define memory_region_find memory_region_find_s390x +#define memory_region_filter_subregions memory_region_filter_subregions_s390x #define memory_listener_register memory_listener_register_s390x #define memory_listener_unregister memory_listener_unregister_s390x #define address_space_remove_listeners address_space_remove_listeners_s390x @@ -147,6 +155,7 @@ #define address_space_destroy address_space_destroy_s390x #define memory_region_init_ram memory_region_init_ram_s390x #define memory_mapping_list_add_merge_sorted memory_mapping_list_add_merge_sorted_s390x +#define find_memory_mapping find_memory_mapping_s390x #define exec_inline_op exec_inline_op_s390x #define floatx80_default_nan floatx80_default_nan_s390x #define float_raise float_raise_s390x diff --git a/qemu/softmmu/memory.c b/qemu/softmmu/memory.c index c58bd79f..2c52539c 100644 --- a/qemu/softmmu/memory.c +++ b/qemu/softmmu/memory.c @@ -26,6 +26,9 @@ //#define DEBUG_UNASSIGNED +void memory_region_transaction_begin(void); +void memory_region_transaction_commit(MemoryRegion *mr); + typedef struct AddrRange AddrRange; /* @@ -49,7 +52,7 @@ MemoryRegion *memory_map(struct uc_struct *uc, hwaddr begin, size_t size, uint32 return NULL; } - memory_region_add_subregion(uc->system_memory, begin, ram); + memory_region_add_subregion_overlap(uc->system_memory, begin, ram, uc->snapshot_level); if (uc->cpu) { tlb_flush(uc->cpu); @@ -79,6 +82,48 @@ MemoryRegion *memory_map_ptr(struct uc_struct *uc, hwaddr begin, size_t size, ui return ram; } +static void make_contained(struct uc_struct *uc, MemoryRegion *current) +{ + hwaddr addr = current->addr; + MemoryRegion *container = g_new(MemoryRegion, 1); + memory_region_init(uc, container, int128_get64(current->size)); + memory_region_del_subregion(uc->system_memory, current); + memory_region_add_subregion_overlap(container, 0, current, current->priority); + memory_region_add_subregion(uc->system_memory, addr, container); +} + +MemoryRegion *memory_cow(struct uc_struct *uc, MemoryRegion *current, hwaddr begin, size_t size) +{ + hwaddr offset; + hwaddr current_offset; + MemoryRegion *ram = g_new(MemoryRegion, 1); + + if (current->container == uc->system_memory) { + make_contained(uc, current); + } + offset = begin - current->container->addr;; + current_offset = offset - current->addr; + + memory_region_init_ram(uc, ram, size, current->perms); + if (ram->addr == -1 || !ram->ram_block) { + g_free(ram); + return NULL; + } + memory_region_transaction_begin(); + + memcpy(ramblock_ptr(ram->ram_block, 0), ramblock_ptr(current->ram_block, current_offset), size); + memory_region_add_subregion_overlap(current->container, offset, ram, uc->snapshot_level); + + if (uc->cpu) { + tlb_flush(uc->cpu); + } + + uc->memory_region_update_pending = true; + memory_region_transaction_commit(ram); + + return ram; +} + static uint64_t mmio_read_wrapper(struct uc_struct *uc, void *opaque, hwaddr addr, unsigned size) { mmio_cbs* cbs = (mmio_cbs*)opaque; @@ -148,44 +193,111 @@ MemoryRegion *memory_map_io(struct uc_struct *uc, ram_addr_t begin, size_t size, return mmio; } -void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) +void memory_region_filter_subregions(MemoryRegion *mr, int32_t level) { - int i; - hwaddr addr; - - // Make sure all pages associated with the MemoryRegion are flushed - // Only need to do this if we are in a running state - if (uc->cpu) { - for (addr = mr->addr; addr < mr->end; addr += uc->target_page_size) { - tlb_flush_page(uc->cpu, addr); + MemoryRegion *subregion, *subregion_next; + memory_region_transaction_begin(); + QTAILQ_FOREACH_SAFE(subregion, &mr->subregions, subregions_link, subregion_next) { + if (subregion->priority >= level) { + memory_region_del_subregion(mr, subregion); + subregion->destructor(subregion); + g_free(subregion); + mr->uc->memory_region_update_pending = true; } } - memory_region_del_subregion(uc->system_memory, mr); + memory_region_transaction_commit(mr); +} +static void memory_region_remove_mapped_block(struct uc_struct *uc, MemoryRegion *mr, bool free) +{ + size_t i; for (i = 0; i < uc->mapped_block_count; i++) { if (uc->mapped_blocks[i] == mr) { uc->mapped_block_count--; //shift remainder of array down over deleted pointer memmove(&uc->mapped_blocks[i], &uc->mapped_blocks[i + 1], sizeof(MemoryRegion*) * (uc->mapped_block_count - i)); - mr->destructor(mr); - g_free(mr); + if (free) { + mr->destructor(mr); + g_free(mr); + } break; } } } +void memory_moveout(struct uc_struct *uc, MemoryRegion *mr) +{ + hwaddr addr; + /* A bit dirty, but it works. + * The first subregion will be the one with the smalest priority. + * In case of CoW this will always be the region which is mapped initial and later be moved in the subregion of the container. + * The initial subregion is the one stored in mapped_blocks + * Because CoW is done after the snapshot level is increased there is only on subregion with + */ + memory_region_transaction_begin(); + MemoryRegion *mr_block = QTAILQ_FIRST(&mr->subregions); + + if (!mr_block) { + mr_block = mr; + } + + if (uc->cpu) { + // We also need to remove all tb cache + uc->uc_invalidate_tb(uc, mr->addr, int128_get64(mr->size)); + + // Make sure all pages associated with the MemoryRegion are flushed + // Only need to do this if we are in a running state + for (addr = mr->addr; (int64_t)(mr->end - addr) > 0; addr += uc->target_page_size) { + tlb_flush_page(uc->cpu, addr); + } + } + + memory_region_del_subregion(uc->system_memory, mr); + g_array_append_val(uc->unmapped_regions, mr); + memory_region_remove_mapped_block(uc, mr_block, false); + uc->memory_region_update_pending = true; + memory_region_transaction_commit(uc->system_memory); + /* dirty hack to save the snapshot level */ + mr->container = (void *)(intptr_t)uc->snapshot_level; +} + +void memory_movein(struct uc_struct *uc, MemoryRegion *mr) +{ + memory_region_transaction_begin(); + memory_region_add_subregion_overlap(uc->system_memory, mr->addr, mr, mr->priority); + uc->memory_region_update_pending = true; + memory_region_transaction_commit(uc->system_memory); +} + +void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) +{ + hwaddr addr; + + if (uc->cpu) { + // We also need to remove all tb cache + uc->uc_invalidate_tb(uc, mr->addr, int128_get64(mr->size)); + + // Make sure all pages associated with the MemoryRegion are flushed + // Only need to do this if we are in a running state + for (addr = mr->addr; (int64_t)(mr->end - addr) > 0; addr += uc->target_page_size) { + tlb_flush_page(uc->cpu, addr); + } + } + memory_region_del_subregion(uc->system_memory, mr); + memory_region_remove_mapped_block(uc, mr, true); +} + int memory_free(struct uc_struct *uc) { - MemoryRegion *mr; - int i; + MemoryRegion *subregion, *subregion_next; + MemoryRegion *mr = uc->system_memory; - for (i = 0; i < uc->mapped_block_count; i++) { - mr = uc->mapped_blocks[i]; - mr->enabled = false; - memory_region_del_subregion(uc->system_memory, mr); - mr->destructor(mr); + QTAILQ_FOREACH_SAFE(subregion, &mr->subregions, subregions_link, subregion_next) { + subregion->enabled = false; + memory_region_del_subregion(uc->system_memory, subregion); + subregion->destructor(subregion); /* destroy subregion */ - g_free(mr); + g_free(subregion); } return 0; @@ -883,6 +995,7 @@ static void memory_region_destructor_none(MemoryRegion *mr) static void memory_region_destructor_ram(MemoryRegion *mr) { + memory_region_filter_subregions(mr, 0); qemu_ram_free(mr->uc, mr->ram_block); } @@ -1113,8 +1226,10 @@ static void memory_region_update_container_subregions(MemoryRegion *subregion) memory_region_transaction_begin(); QTAILQ_FOREACH(other, &mr->subregions, subregions_link) { - QTAILQ_INSERT_BEFORE(other, subregion, subregions_link); - goto done; + if (subregion->priority >= other->priority) { + QTAILQ_INSERT_BEFORE(other, subregion, subregions_link); + goto done; + } } QTAILQ_INSERT_TAIL(&mr->subregions, subregion, subregions_link); @@ -1138,6 +1253,16 @@ void memory_region_add_subregion(MemoryRegion *mr, hwaddr offset, MemoryRegion *subregion) { + subregion->priority = 0; + memory_region_add_subregion_common(mr, offset, subregion); +} + +void memory_region_add_subregion_overlap(MemoryRegion *mr, + hwaddr offset, + MemoryRegion *subregion, + int priority) +{ + subregion->priority = priority; memory_region_add_subregion_common(mr, offset, subregion); } diff --git a/qemu/softmmu/vl.c b/qemu/softmmu/vl.c index 6860afd9..7802a2d5 100644 --- a/qemu/softmmu/vl.c +++ b/qemu/softmmu/vl.c @@ -50,7 +50,7 @@ int machine_initialize(struct uc_struct *uc) uc->target_page(uc); /* Init tcg. use DEFAULT_CODE_GEN_BUFFER_SIZE. */ - uc->tcg_exec_init(uc, 0); + uc->tcg_exec_init(uc, uc->tcg_buffer_size); /* Init cpu. use default cpu_model. */ return uc->cpus_init(uc, NULL); diff --git a/qemu/sparc.h b/qemu/sparc.h index 7083a74f..51d623da 100644 --- a/qemu/sparc.h +++ b/qemu/sparc.h @@ -5,6 +5,9 @@ #define UNICORN_ARCH_POSTFIX _sparc #endif #define unicorn_fill_tlb unicorn_fill_tlb_sparc +#define reg_read reg_read_sparc +#define reg_write reg_write_sparc +#define uc_init uc_init_sparc #define uc_add_inline_hook uc_add_inline_hook_sparc #define uc_del_inline_hook uc_del_inline_hook_sparc #define tb_invalidate_phys_range tb_invalidate_phys_range_sparc @@ -120,7 +123,10 @@ #define memory_map memory_map_sparc #define memory_map_io memory_map_io_sparc #define memory_map_ptr memory_map_ptr_sparc +#define memory_cow memory_cow_sparc #define memory_unmap memory_unmap_sparc +#define memory_moveout memory_moveout_sparc +#define memory_movein memory_movein_sparc #define memory_free memory_free_sparc #define flatview_unref flatview_unref_sparc #define address_space_get_flatview address_space_get_flatview_sparc @@ -139,7 +145,9 @@ #define memory_region_get_ram_addr memory_region_get_ram_addr_sparc #define memory_region_add_subregion memory_region_add_subregion_sparc #define memory_region_del_subregion memory_region_del_subregion_sparc +#define memory_region_add_subregion_overlap memory_region_add_subregion_overlap_sparc #define memory_region_find memory_region_find_sparc +#define memory_region_filter_subregions memory_region_filter_subregions_sparc #define memory_listener_register memory_listener_register_sparc #define memory_listener_unregister memory_listener_unregister_sparc #define address_space_remove_listeners address_space_remove_listeners_sparc @@ -147,6 +155,7 @@ #define address_space_destroy address_space_destroy_sparc #define memory_region_init_ram memory_region_init_ram_sparc #define memory_mapping_list_add_merge_sorted memory_mapping_list_add_merge_sorted_sparc +#define find_memory_mapping find_memory_mapping_sparc #define exec_inline_op exec_inline_op_sparc #define floatx80_default_nan floatx80_default_nan_sparc #define float_raise float_raise_sparc @@ -1415,7 +1424,4 @@ #define helper_wrpil helper_wrpil_sparc #define helper_done helper_done_sparc #define helper_retry helper_retry_sparc -#define sparc_reg_reset sparc_reg_reset_sparc -#define sparc_reg_read sparc_reg_read_sparc -#define sparc_reg_write sparc_reg_write_sparc #endif diff --git a/qemu/sparc64.h b/qemu/sparc64.h index e70362dc..5779f315 100644 --- a/qemu/sparc64.h +++ b/qemu/sparc64.h @@ -5,6 +5,9 @@ #define UNICORN_ARCH_POSTFIX _sparc64 #endif #define unicorn_fill_tlb unicorn_fill_tlb_sparc64 +#define reg_read reg_read_sparc64 +#define reg_write reg_write_sparc64 +#define uc_init uc_init_sparc64 #define uc_add_inline_hook uc_add_inline_hook_sparc64 #define uc_del_inline_hook uc_del_inline_hook_sparc64 #define tb_invalidate_phys_range tb_invalidate_phys_range_sparc64 @@ -120,7 +123,10 @@ #define memory_map memory_map_sparc64 #define memory_map_io memory_map_io_sparc64 #define memory_map_ptr memory_map_ptr_sparc64 +#define memory_cow memory_cow_sparc64 #define memory_unmap memory_unmap_sparc64 +#define memory_moveout memory_moveout_sparc64 +#define memory_movein memory_movein_sparc64 #define memory_free memory_free_sparc64 #define flatview_unref flatview_unref_sparc64 #define address_space_get_flatview address_space_get_flatview_sparc64 @@ -139,7 +145,9 @@ #define memory_region_get_ram_addr memory_region_get_ram_addr_sparc64 #define memory_region_add_subregion memory_region_add_subregion_sparc64 #define memory_region_del_subregion memory_region_del_subregion_sparc64 +#define memory_region_add_subregion_overlap memory_region_add_subregion_overlap_sparc64 #define memory_region_find memory_region_find_sparc64 +#define memory_region_filter_subregions memory_region_filter_subregions_sparc64 #define memory_listener_register memory_listener_register_sparc64 #define memory_listener_unregister memory_listener_unregister_sparc64 #define address_space_remove_listeners address_space_remove_listeners_sparc64 @@ -147,6 +155,7 @@ #define address_space_destroy address_space_destroy_sparc64 #define memory_region_init_ram memory_region_init_ram_sparc64 #define memory_mapping_list_add_merge_sorted memory_mapping_list_add_merge_sorted_sparc64 +#define find_memory_mapping find_memory_mapping_sparc64 #define exec_inline_op exec_inline_op_sparc64 #define floatx80_default_nan floatx80_default_nan_sparc64 #define float_raise float_raise_sparc64 @@ -1415,7 +1424,4 @@ #define helper_wrpil helper_wrpil_sparc64 #define helper_done helper_done_sparc64 #define helper_retry helper_retry_sparc64 -#define sparc_reg_reset sparc_reg_reset_sparc64 -#define sparc_reg_read sparc_reg_read_sparc64 -#define sparc_reg_write sparc_reg_write_sparc64 #endif diff --git a/qemu/target/arm/unicorn.h b/qemu/target/arm/unicorn.h index df0b20a0..9327f04f 100644 --- a/qemu/target/arm/unicorn.h +++ b/qemu/target/arm/unicorn.h @@ -5,28 +5,15 @@ #define UC_QEMU_TARGET_ARM_H // functions to read & write registers -int arm_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count); -int arm_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, - int count); -int arm64_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count); -int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, - int count); +uc_err reg_read_arm(void *env, int mode, unsigned int regid, void *value, + size_t *size); +uc_err reg_read_aarch64(void *env, int mode, unsigned int regid, void *value, + size_t *size); +uc_err reg_write_arm(void *env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc); +uc_err reg_write_aarch64(void *env, int mode, unsigned int regid, + const void *value, size_t *size, int *setpc); -int arm_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); -int arm_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); -int arm64_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); -int arm64_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); - -void arm_reg_reset(struct uc_struct *uc); -void arm64_reg_reset(struct uc_struct *uc); - -void arm_uc_init(struct uc_struct *uc); - -void arm64_uc_init(struct uc_struct *uc); +void uc_init_arm(struct uc_struct *uc); +void uc_init_aarch64(struct uc_struct *uc); #endif diff --git a/qemu/target/arm/unicorn_aarch64.c b/qemu/target/arm/unicorn_aarch64.c index fa40330f..c2463957 100644 --- a/qemu/target/arm/unicorn_aarch64.c +++ b/qemu/target/arm/unicorn_aarch64.c @@ -88,7 +88,7 @@ static void arm64_release(void *ctx) g_hash_table_destroy(cpu->cp_regs); } -void arm64_reg_reset(struct uc_struct *uc) +static void reg_reset(struct uc_struct *uc) { CPUArchState *env = uc->cpu->env_ptr; memset(env->xregs, 0, sizeof(env->xregs)); @@ -138,97 +138,129 @@ static uc_err write_cp_reg(CPUARMState *env, uc_arm64_cp_reg *cp) return UC_ERR_OK; } -static uc_err reg_read(CPUARMState *env, unsigned int regid, void *value) +DEFAULT_VISIBILITY +uc_err reg_read(void *_env, int mode, unsigned int regid, void *value, + size_t *size) { - uc_err ret = UC_ERR_OK; + CPUARMState *env = _env; + uc_err ret = UC_ERR_ARG; if (regid >= UC_ARM64_REG_V0 && regid <= UC_ARM64_REG_V31) { regid += UC_ARM64_REG_Q0 - UC_ARM64_REG_V0; } if (regid >= UC_ARM64_REG_X0 && regid <= UC_ARM64_REG_X28) { - *(int64_t *)value = env->xregs[regid - UC_ARM64_REG_X0]; + CHECK_REG_TYPE(uint64_t); + *(uint64_t *)value = env->xregs[regid - UC_ARM64_REG_X0]; } else if (regid >= UC_ARM64_REG_W0 && regid <= UC_ARM64_REG_W30) { - *(int32_t *)value = READ_DWORD(env->xregs[regid - UC_ARM64_REG_W0]); + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = READ_DWORD(env->xregs[regid - UC_ARM64_REG_W0]); } else if (regid >= UC_ARM64_REG_Q0 && regid <= UC_ARM64_REG_Q31) { // FIXME + CHECK_REG_TYPE(float64[2]); float64 *dst = (float64 *)value; uint32_t reg_index = regid - UC_ARM64_REG_Q0; dst[0] = env->vfp.zregs[reg_index].d[0]; dst[1] = env->vfp.zregs[reg_index].d[1]; } else if (regid >= UC_ARM64_REG_D0 && regid <= UC_ARM64_REG_D31) { + CHECK_REG_TYPE(float64); *(float64 *)value = env->vfp.zregs[regid - UC_ARM64_REG_D0].d[0]; } else if (regid >= UC_ARM64_REG_S0 && regid <= UC_ARM64_REG_S31) { + CHECK_REG_TYPE(int32_t); *(int32_t *)value = READ_DWORD(env->vfp.zregs[regid - UC_ARM64_REG_S0].d[0]); } else if (regid >= UC_ARM64_REG_H0 && regid <= UC_ARM64_REG_H31) { + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->vfp.zregs[regid - UC_ARM64_REG_H0].d[0]); } else if (regid >= UC_ARM64_REG_B0 && regid <= UC_ARM64_REG_B31) { + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_L(env->vfp.zregs[regid - UC_ARM64_REG_B0].d[0]); } else if (regid >= UC_ARM64_REG_ELR_EL0 && regid <= UC_ARM64_REG_ELR_EL3) { + CHECK_REG_TYPE(uint64_t); *(uint64_t *)value = env->elr_el[regid - UC_ARM64_REG_ELR_EL0]; } else if (regid >= UC_ARM64_REG_SP_EL0 && regid <= UC_ARM64_REG_SP_EL3) { + CHECK_REG_TYPE(uint64_t); *(uint64_t *)value = env->sp_el[regid - UC_ARM64_REG_SP_EL0]; } else if (regid >= UC_ARM64_REG_ESR_EL0 && regid <= UC_ARM64_REG_ESR_EL3) { + CHECK_REG_TYPE(uint64_t); *(uint64_t *)value = env->cp15.esr_el[regid - UC_ARM64_REG_ESR_EL0]; } else if (regid >= UC_ARM64_REG_FAR_EL0 && regid <= UC_ARM64_REG_FAR_EL3) { + CHECK_REG_TYPE(uint64_t); *(uint64_t *)value = env->cp15.far_el[regid - UC_ARM64_REG_FAR_EL0]; } else if (regid >= UC_ARM64_REG_VBAR_EL0 && regid <= UC_ARM64_REG_VBAR_EL3) { + CHECK_REG_TYPE(uint64_t); *(uint64_t *)value = env->cp15.vbar_el[regid - UC_ARM64_REG_VBAR_EL0]; } else { switch (regid) { default: break; case UC_ARM64_REG_CPACR_EL1: + CHECK_REG_TYPE(uint32_t); *(uint32_t *)value = env->cp15.cpacr_el1; break; case UC_ARM64_REG_TPIDR_EL0: - *(int64_t *)value = env->cp15.tpidr_el[0]; + CHECK_REG_TYPE(uint64_t); + *(uint64_t *)value = env->cp15.tpidr_el[0]; break; case UC_ARM64_REG_TPIDRRO_EL0: - *(int64_t *)value = env->cp15.tpidrro_el[0]; + CHECK_REG_TYPE(uint64_t); + *(uint64_t *)value = env->cp15.tpidrro_el[0]; break; case UC_ARM64_REG_TPIDR_EL1: - *(int64_t *)value = env->cp15.tpidr_el[1]; + CHECK_REG_TYPE(uint64_t); + *(uint64_t *)value = env->cp15.tpidr_el[1]; break; case UC_ARM64_REG_X29: - *(int64_t *)value = env->xregs[29]; + CHECK_REG_TYPE(uint64_t); + *(uint64_t *)value = env->xregs[29]; break; case UC_ARM64_REG_X30: - *(int64_t *)value = env->xregs[30]; + CHECK_REG_TYPE(uint64_t); + *(uint64_t *)value = env->xregs[30]; break; case UC_ARM64_REG_PC: + CHECK_REG_TYPE(uint64_t); *(uint64_t *)value = env->pc; break; case UC_ARM64_REG_SP: - *(int64_t *)value = env->xregs[31]; + CHECK_REG_TYPE(uint64_t); + *(uint64_t *)value = env->xregs[31]; break; case UC_ARM64_REG_NZCV: - *(int32_t *)value = cpsr_read(env) & CPSR_NZCV; + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = cpsr_read(env) & CPSR_NZCV; break; case UC_ARM64_REG_PSTATE: + CHECK_REG_TYPE(uint32_t); *(uint32_t *)value = pstate_read(env); break; case UC_ARM64_REG_TTBR0_EL1: + CHECK_REG_TYPE(uint64_t); *(uint64_t *)value = env->cp15.ttbr0_el[1]; break; case UC_ARM64_REG_TTBR1_EL1: + CHECK_REG_TYPE(uint64_t); *(uint64_t *)value = env->cp15.ttbr1_el[1]; break; case UC_ARM64_REG_PAR_EL1: + CHECK_REG_TYPE(uint64_t); *(uint64_t *)value = env->cp15.par_el[1]; break; case UC_ARM64_REG_MAIR_EL1: + CHECK_REG_TYPE(uint64_t); *(uint64_t *)value = env->cp15.mair_el[1]; break; case UC_ARM64_REG_CP_REG: + CHECK_REG_TYPE(uc_arm64_cp_reg); ret = read_cp_reg(env, (uc_arm64_cp_reg *)value); break; case UC_ARM64_REG_FPCR: + CHECK_REG_TYPE(uint32_t); *(uint32_t *)value = vfp_get_fpcr(env); break; case UC_ARM64_REG_FPSR: + CHECK_REG_TYPE(uint32_t); *(uint32_t *)value = vfp_get_fpsr(env); break; } @@ -237,97 +269,131 @@ static uc_err reg_read(CPUARMState *env, unsigned int regid, void *value) return ret; } -static uc_err reg_write(CPUARMState *env, unsigned int regid, const void *value) +DEFAULT_VISIBILITY +uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc) { - uc_err ret = UC_ERR_OK; + CPUARMState *env = _env; + uc_err ret = UC_ERR_ARG; if (regid >= UC_ARM64_REG_V0 && regid <= UC_ARM64_REG_V31) { regid += UC_ARM64_REG_Q0 - UC_ARM64_REG_V0; } if (regid >= UC_ARM64_REG_X0 && regid <= UC_ARM64_REG_X28) { + CHECK_REG_TYPE(uint64_t); env->xregs[regid - UC_ARM64_REG_X0] = *(uint64_t *)value; } else if (regid >= UC_ARM64_REG_W0 && regid <= UC_ARM64_REG_W30) { + CHECK_REG_TYPE(uint32_t); WRITE_DWORD(env->xregs[regid - UC_ARM64_REG_W0], *(uint32_t *)value); } else if (regid >= UC_ARM64_REG_Q0 && regid <= UC_ARM64_REG_Q31) { + CHECK_REG_TYPE(float64[2]); float64 *src = (float64 *)value; uint32_t reg_index = regid - UC_ARM64_REG_Q0; env->vfp.zregs[reg_index].d[0] = src[0]; env->vfp.zregs[reg_index].d[1] = src[1]; } else if (regid >= UC_ARM64_REG_D0 && regid <= UC_ARM64_REG_D31) { + CHECK_REG_TYPE(float64); env->vfp.zregs[regid - UC_ARM64_REG_D0].d[0] = *(float64 *)value; } else if (regid >= UC_ARM64_REG_S0 && regid <= UC_ARM64_REG_S31) { + CHECK_REG_TYPE(int32_t); WRITE_DWORD(env->vfp.zregs[regid - UC_ARM64_REG_S0].d[0], *(int32_t *)value); } else if (regid >= UC_ARM64_REG_H0 && regid <= UC_ARM64_REG_H31) { + CHECK_REG_TYPE(int16_t); WRITE_WORD(env->vfp.zregs[regid - UC_ARM64_REG_H0].d[0], *(int16_t *)value); } else if (regid >= UC_ARM64_REG_B0 && regid <= UC_ARM64_REG_B31) { + CHECK_REG_TYPE(int8_t); WRITE_BYTE_L(env->vfp.zregs[regid - UC_ARM64_REG_B0].d[0], *(int8_t *)value); } else if (regid >= UC_ARM64_REG_ELR_EL0 && regid <= UC_ARM64_REG_ELR_EL3) { + CHECK_REG_TYPE(uint64_t); env->elr_el[regid - UC_ARM64_REG_ELR_EL0] = *(uint64_t *)value; } else if (regid >= UC_ARM64_REG_SP_EL0 && regid <= UC_ARM64_REG_SP_EL3) { + CHECK_REG_TYPE(uint64_t); env->sp_el[regid - UC_ARM64_REG_SP_EL0] = *(uint64_t *)value; } else if (regid >= UC_ARM64_REG_ESR_EL0 && regid <= UC_ARM64_REG_ESR_EL3) { + CHECK_REG_TYPE(uint64_t); env->cp15.esr_el[regid - UC_ARM64_REG_ESR_EL0] = *(uint64_t *)value; } else if (regid >= UC_ARM64_REG_FAR_EL0 && regid <= UC_ARM64_REG_FAR_EL3) { + CHECK_REG_TYPE(uint64_t); env->cp15.far_el[regid - UC_ARM64_REG_FAR_EL0] = *(uint64_t *)value; } else if (regid >= UC_ARM64_REG_VBAR_EL0 && regid <= UC_ARM64_REG_VBAR_EL3) { + CHECK_REG_TYPE(uint64_t); env->cp15.vbar_el[regid - UC_ARM64_REG_VBAR_EL0] = *(uint64_t *)value; } else { switch (regid) { default: break; case UC_ARM64_REG_CPACR_EL1: + CHECK_REG_TYPE(uint32_t); env->cp15.cpacr_el1 = *(uint32_t *)value; break; case UC_ARM64_REG_TPIDR_EL0: + CHECK_REG_TYPE(uint64_t); env->cp15.tpidr_el[0] = *(uint64_t *)value; break; case UC_ARM64_REG_TPIDRRO_EL0: + CHECK_REG_TYPE(uint64_t); env->cp15.tpidrro_el[0] = *(uint64_t *)value; break; case UC_ARM64_REG_TPIDR_EL1: + CHECK_REG_TYPE(uint64_t); env->cp15.tpidr_el[1] = *(uint64_t *)value; break; case UC_ARM64_REG_X29: + CHECK_REG_TYPE(uint64_t); env->xregs[29] = *(uint64_t *)value; break; case UC_ARM64_REG_X30: + CHECK_REG_TYPE(uint64_t); env->xregs[30] = *(uint64_t *)value; break; case UC_ARM64_REG_PC: + CHECK_REG_TYPE(uint64_t); env->pc = *(uint64_t *)value; + *setpc = 1; break; case UC_ARM64_REG_SP: + CHECK_REG_TYPE(uint64_t); env->xregs[31] = *(uint64_t *)value; break; case UC_ARM64_REG_NZCV: + CHECK_REG_TYPE(uint32_t); cpsr_write(env, *(uint32_t *)value, CPSR_NZCV, CPSRWriteRaw); break; case UC_ARM64_REG_PSTATE: + CHECK_REG_TYPE(uint32_t); pstate_write(env, *(uint32_t *)value); break; case UC_ARM64_REG_TTBR0_EL1: + CHECK_REG_TYPE(uint64_t); env->cp15.ttbr0_el[1] = *(uint64_t *)value; break; case UC_ARM64_REG_TTBR1_EL1: + CHECK_REG_TYPE(uint64_t); env->cp15.ttbr1_el[1] = *(uint64_t *)value; break; case UC_ARM64_REG_PAR_EL1: + CHECK_REG_TYPE(uint64_t); env->cp15.par_el[1] = *(uint64_t *)value; break; case UC_ARM64_REG_MAIR_EL1: + CHECK_REG_TYPE(uint64_t); env->cp15.mair_el[1] = *(uint64_t *)value; break; case UC_ARM64_REG_CP_REG: + CHECK_REG_TYPE(uc_arm64_cp_reg); ret = write_cp_reg(env, (uc_arm64_cp_reg *)value); + arm_rebuild_hflags(env); break; case UC_ARM64_REG_FPCR: + CHECK_REG_TYPE(uint32_t); vfp_set_fpcr(env, *(uint32_t *)value); break; case UC_ARM64_REG_FPSR: + CHECK_REG_TYPE(uint32_t); vfp_set_fpsr(env, *(uint32_t *)value); break; } @@ -336,99 +402,6 @@ static uc_err reg_write(CPUARMState *env, unsigned int regid, const void *value) return ret; } -int arm64_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count) -{ - CPUARMState *env = &(ARM_CPU(uc->cpu)->env); - int i; - uc_err err; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - err = reg_read(env, regid, value); - if (err) { - return err; - } - } - - return UC_ERR_OK; -} - -int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, - int count) -{ - CPUARMState *env = &(ARM_CPU(uc->cpu)->env); - int i; - uc_err err; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - err = reg_write(env, regid, value); - if (err) { - return err; - } - if (regid == UC_ARM64_REG_PC) { - // force to quit execution and flush TB - uc->quit_request = true; - break_translation_loop(uc); - } - } - - return UC_ERR_OK; -} - -DEFAULT_VISIBILITY -#ifdef TARGET_WORDS_BIGENDIAN -int arm64eb_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) -#else -int arm64_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) -#endif -{ - CPUARMState *env = (CPUARMState *)ctx->data; - int i; - uc_err err; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - err = reg_read(env, regid, value); - if (err) { - return err; - } - } - - return 0; -} - -DEFAULT_VISIBILITY -#ifdef TARGET_WORDS_BIGENDIAN -int arm64eb_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) -#else -int arm64_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) -#endif -{ - CPUARMState *env = (CPUARMState *)ctx->data; - int i; - uc_err err; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - err = reg_write(env, regid, value); - if (err) { - return err; - } - } - - return 0; -} - static int arm64_cpus_init(struct uc_struct *uc, const char *cpu_model) { ARMCPU *cpu; @@ -442,11 +415,11 @@ static int arm64_cpus_init(struct uc_struct *uc, const char *cpu_model) } DEFAULT_VISIBILITY -void arm64_uc_init(struct uc_struct *uc) +void uc_init(struct uc_struct *uc) { - uc->reg_read = arm64_reg_read; - uc->reg_write = arm64_reg_write; - uc->reg_reset = arm64_reg_reset; + uc->reg_read = reg_read; + uc->reg_write = reg_write; + uc->reg_reset = reg_reset; uc->set_pc = arm64_set_pc; uc->get_pc = arm64_get_pc; uc->release = arm64_release; diff --git a/qemu/target/arm/unicorn_arm.c b/qemu/target/arm/unicorn_arm.c index e706b12b..eda70af5 100644 --- a/qemu/target/arm/unicorn_arm.c +++ b/qemu/target/arm/unicorn_arm.c @@ -91,7 +91,7 @@ static void arm_release(void *ctx) g_hash_table_destroy(cpu->cp_regs); } -void arm_reg_reset(struct uc_struct *uc) +static void reg_reset(struct uc_struct *uc) { CPUArchState *env; (void)uc; @@ -206,20 +206,27 @@ static uc_err write_cp_reg(CPUARMState *env, uc_arm_cp_reg *cp) return UC_ERR_OK; } -static uc_err reg_read(CPUARMState *env, unsigned int regid, void *value) +DEFAULT_VISIBILITY +uc_err reg_read(void *_env, int mode, unsigned int regid, void *value, + size_t *size) { - uc_err ret = UC_ERR_OK; + CPUARMState *env = _env; + uc_err ret = UC_ERR_ARG; if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12) { + CHECK_REG_TYPE(uint32_t); *(uint32_t *)value = env->regs[regid - UC_ARM_REG_R0]; } else if (regid >= UC_ARM_REG_Q0 && regid <= UC_ARM_REG_Q15) { + CHECK_REG_TYPE(uint64_t[2]); uint32_t reg_index = regid - UC_ARM_REG_Q0; *(uint64_t *)value = env->vfp.zregs[reg_index].d[0]; *(((uint64_t *)value) + 1) = env->vfp.zregs[reg_index].d[1]; } else if (regid >= UC_ARM_REG_D0 && regid <= UC_ARM_REG_D31) { + CHECK_REG_TYPE(uint64_t); uint32_t reg_index = regid - UC_ARM_REG_D0; *(uint64_t *)value = env->vfp.zregs[reg_index / 2].d[reg_index & 1]; } else if (regid >= UC_ARM_REG_S0 && regid <= UC_ARM_REG_S31) { + CHECK_REG_TYPE(uint32_t); uint32_t reg_index = regid - UC_ARM_REG_S0; uint64_t reg_value = env->vfp.zregs[reg_index / 4].d[reg_index % 4 / 2]; @@ -232,88 +239,115 @@ static uc_err reg_read(CPUARMState *env, unsigned int regid, void *value) switch (regid) { case UC_ARM_REG_APSR: if (arm_feature(env, ARM_FEATURE_M)) { + CHECK_REG_TYPE(int32_t); *(int32_t *)value = v7m_mrs_xpsr(env, 0); } else { + CHECK_REG_TYPE(int32_t); *(int32_t *)value = cpsr_read(env) & (CPSR_NZCV | CPSR_Q | CPSR_GE); } break; case UC_ARM_REG_APSR_NZCV: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = cpsr_read(env) & CPSR_NZCV; break; case UC_ARM_REG_CPSR: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = cpsr_read(env); break; case UC_ARM_REG_SPSR: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = env->spsr; break; // case UC_ARM_REG_SP: case UC_ARM_REG_R13: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = env->regs[13]; break; // case UC_ARM_REG_LR: case UC_ARM_REG_R14: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = env->regs[14]; break; // case UC_ARM_REG_PC: case UC_ARM_REG_R15: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = env->regs[15]; break; case UC_ARM_REG_C1_C0_2: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = env->cp15.cpacr_el1; break; case UC_ARM_REG_C13_C0_3: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = env->cp15.tpidrro_el[0]; break; case UC_ARM_REG_FPEXC: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = env->vfp.xregs[ARM_VFP_FPEXC]; break; case UC_ARM_REG_FPSCR: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = vfp_get_fpscr(env); break; case UC_ARM_REG_FPSID: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = env->vfp.xregs[ARM_VFP_FPSID]; break; case UC_ARM_REG_IPSR: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = v7m_mrs_xpsr(env, 5); break; case UC_ARM_REG_MSP: + CHECK_REG_TYPE(uint32_t); *(uint32_t *)value = helper_v7m_mrs(env, 8); break; case UC_ARM_REG_PSP: + CHECK_REG_TYPE(uint32_t); *(uint32_t *)value = helper_v7m_mrs(env, 9); break; case UC_ARM_REG_IAPSR: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = v7m_mrs_xpsr(env, 1); break; case UC_ARM_REG_EAPSR: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = v7m_mrs_xpsr(env, 2); break; case UC_ARM_REG_XPSR: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = v7m_mrs_xpsr(env, 3); break; case UC_ARM_REG_EPSR: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = v7m_mrs_xpsr(env, 6); break; case UC_ARM_REG_IEPSR: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = v7m_mrs_xpsr(env, 7); break; case UC_ARM_REG_PRIMASK: + CHECK_REG_TYPE(uint32_t); *(uint32_t *)value = helper_v7m_mrs(env, 16); break; case UC_ARM_REG_BASEPRI: + CHECK_REG_TYPE(uint32_t); *(uint32_t *)value = helper_v7m_mrs(env, 17); break; case UC_ARM_REG_BASEPRI_MAX: + CHECK_REG_TYPE(uint32_t); *(uint32_t *)value = helper_v7m_mrs(env, 18); break; case UC_ARM_REG_FAULTMASK: + CHECK_REG_TYPE(uint32_t); *(uint32_t *)value = helper_v7m_mrs(env, 19); break; case UC_ARM_REG_CONTROL: + CHECK_REG_TYPE(uint32_t); *(uint32_t *)value = helper_v7m_mrs(env, 20); break; case UC_ARM_REG_CP_REG: + CHECK_REG_TYPE(uc_arm_cp_reg); ret = read_cp_reg(env, (uc_arm_cp_reg *)value); break; } @@ -322,20 +356,27 @@ static uc_err reg_read(CPUARMState *env, unsigned int regid, void *value) return ret; } -static uc_err reg_write(CPUARMState *env, unsigned int regid, const void *value) +DEFAULT_VISIBILITY +uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc) { - uc_err ret = UC_ERR_OK; + CPUARMState *env = _env; + uc_err ret = UC_ERR_ARG; if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12) { + CHECK_REG_TYPE(uint32_t); env->regs[regid - UC_ARM_REG_R0] = *(uint32_t *)value; } else if (regid >= UC_ARM_REG_Q0 && regid <= UC_ARM_REG_Q15) { + CHECK_REG_TYPE(uint64_t[2]); uint32_t reg_index = regid - UC_ARM_REG_Q0; env->vfp.zregs[reg_index].d[0] = *(uint64_t *)value; env->vfp.zregs[reg_index].d[1] = *(((uint64_t *)value) + 1); } else if (regid >= UC_ARM_REG_D0 && regid <= UC_ARM_REG_D31) { + CHECK_REG_TYPE(uint64_t); uint32_t reg_index = regid - UC_ARM_REG_D0; env->vfp.zregs[reg_index / 2].d[reg_index & 1] = *(uint64_t *)value; } else if (regid >= UC_ARM_REG_S0 && regid <= UC_ARM_REG_S31) { + CHECK_REG_TYPE(uint32_t); uint32_t reg_index = regid - UC_ARM_REG_S0; uint64_t *p_reg_value = &env->vfp.zregs[reg_index / 4].d[reg_index % 4 / 2]; @@ -350,6 +391,7 @@ static uc_err reg_write(CPUARMState *env, unsigned int regid, const void *value) } else { switch (regid) { case UC_ARM_REG_APSR: + CHECK_REG_TYPE(uint32_t); if (!arm_feature(env, ARM_FEATURE_M)) { cpsr_write(env, *(uint32_t *)value, (CPSR_NZCV | CPSR_Q | CPSR_GE), CPSRWriteByUnicorn); @@ -360,118 +402,153 @@ static uc_err reg_write(CPUARMState *env, unsigned int regid, const void *value) } break; case UC_ARM_REG_APSR_NZCV: + CHECK_REG_TYPE(uint32_t); cpsr_write(env, *(uint32_t *)value, CPSR_NZCV, CPSRWriteByUnicorn); arm_rebuild_hflags(env); break; case UC_ARM_REG_CPSR: + CHECK_REG_TYPE(uint32_t); cpsr_write(env, *(uint32_t *)value, ~0, CPSRWriteByUnicorn); arm_rebuild_hflags(env); break; case UC_ARM_REG_SPSR: + CHECK_REG_TYPE(uint32_t); env->spsr = *(uint32_t *)value; break; // case UC_ARM_REG_SP: case UC_ARM_REG_R13: + CHECK_REG_TYPE(uint32_t); env->regs[13] = *(uint32_t *)value; break; // case UC_ARM_REG_LR: case UC_ARM_REG_R14: + CHECK_REG_TYPE(uint32_t); env->regs[14] = *(uint32_t *)value; break; // case UC_ARM_REG_PC: case UC_ARM_REG_R15: + CHECK_REG_TYPE(uint32_t); env->pc = (*(uint32_t *)value & ~1); env->thumb = (*(uint32_t *)value & 1); env->uc->thumb = (*(uint32_t *)value & 1); env->regs[15] = (*(uint32_t *)value & ~1); + *setpc = 1; break; // case UC_ARM_REG_C1_C0_2: // env->cp15.c1_coproc = *(int32_t *)value; // break; case UC_ARM_REG_C13_C0_3: + CHECK_REG_TYPE(int32_t); env->cp15.tpidrro_el[0] = *(int32_t *)value; break; case UC_ARM_REG_FPEXC: + CHECK_REG_TYPE(int32_t); env->vfp.xregs[ARM_VFP_FPEXC] = *(int32_t *)value; break; case UC_ARM_REG_FPSCR: + CHECK_REG_TYPE(int32_t); vfp_set_fpscr(env, *(int32_t *)value); break; case UC_ARM_REG_FPSID: + CHECK_REG_TYPE(int32_t); env->vfp.xregs[ARM_VFP_FPSID] = *(int32_t *)value; break; case UC_ARM_REG_IPSR: + CHECK_REG_TYPE(uint32_t); v7m_msr_xpsr(env, 0b1000, 5, *(uint32_t *)value); break; case UC_ARM_REG_MSP: + CHECK_REG_TYPE(uint32_t); helper_v7m_msr(env, 8, *(uint32_t *)value); break; case UC_ARM_REG_PSP: + CHECK_REG_TYPE(uint32_t); helper_v7m_msr(env, 9, *(uint32_t *)value); break; case UC_ARM_REG_CONTROL: + CHECK_REG_TYPE(uint32_t); helper_v7m_msr(env, 20, *(uint32_t *)value); break; case UC_ARM_REG_EPSR: + CHECK_REG_TYPE(uint32_t); v7m_msr_xpsr(env, 0b1000, 6, *(uint32_t *)value); break; case UC_ARM_REG_IEPSR: + CHECK_REG_TYPE(uint32_t); v7m_msr_xpsr(env, 0b1000, 7, *(uint32_t *)value); break; case UC_ARM_REG_PRIMASK: + CHECK_REG_TYPE(uint32_t); helper_v7m_msr(env, 16, *(uint32_t *)value); break; case UC_ARM_REG_BASEPRI: + CHECK_REG_TYPE(uint32_t); helper_v7m_msr(env, 17, *(uint32_t *)value); break; case UC_ARM_REG_BASEPRI_MAX: + CHECK_REG_TYPE(uint32_t); helper_v7m_msr(env, 18, *(uint32_t *)value); break; case UC_ARM_REG_FAULTMASK: + CHECK_REG_TYPE(uint32_t); helper_v7m_msr(env, 19, *(uint32_t *)value); break; case UC_ARM_REG_APSR_NZCVQ: + CHECK_REG_TYPE(uint32_t); v7m_msr_xpsr(env, 0b1000, 0, *(uint32_t *)value); break; case UC_ARM_REG_APSR_G: + CHECK_REG_TYPE(uint32_t); v7m_msr_xpsr(env, 0b0100, 0, *(uint32_t *)value); break; case UC_ARM_REG_APSR_NZCVQG: + CHECK_REG_TYPE(uint32_t); v7m_msr_xpsr(env, 0b1100, 0, *(uint32_t *)value); break; case UC_ARM_REG_IAPSR: case UC_ARM_REG_IAPSR_NZCVQ: + CHECK_REG_TYPE(uint32_t); v7m_msr_xpsr(env, 0b1000, 1, *(uint32_t *)value); break; case UC_ARM_REG_IAPSR_G: + CHECK_REG_TYPE(uint32_t); v7m_msr_xpsr(env, 0b0100, 1, *(uint32_t *)value); break; case UC_ARM_REG_IAPSR_NZCVQG: + CHECK_REG_TYPE(uint32_t); v7m_msr_xpsr(env, 0b1100, 1, *(uint32_t *)value); break; case UC_ARM_REG_EAPSR: case UC_ARM_REG_EAPSR_NZCVQ: + CHECK_REG_TYPE(uint32_t); v7m_msr_xpsr(env, 0b1000, 2, *(uint32_t *)value); break; case UC_ARM_REG_EAPSR_G: + CHECK_REG_TYPE(uint32_t); v7m_msr_xpsr(env, 0b0100, 2, *(uint32_t *)value); break; case UC_ARM_REG_EAPSR_NZCVQG: + CHECK_REG_TYPE(uint32_t); v7m_msr_xpsr(env, 0b1100, 2, *(uint32_t *)value); break; case UC_ARM_REG_XPSR: case UC_ARM_REG_XPSR_NZCVQ: + CHECK_REG_TYPE(uint32_t); v7m_msr_xpsr(env, 0b1000, 3, *(uint32_t *)value); break; case UC_ARM_REG_XPSR_G: + CHECK_REG_TYPE(uint32_t); v7m_msr_xpsr(env, 0b0100, 3, *(uint32_t *)value); break; case UC_ARM_REG_XPSR_NZCVQG: + CHECK_REG_TYPE(uint32_t); v7m_msr_xpsr(env, 0b1100, 3, *(uint32_t *)value); break; case UC_ARM_REG_CP_REG: + CHECK_REG_TYPE(uc_arm_cp_reg); ret = write_cp_reg(env, (uc_arm_cp_reg *)value); + arm_rebuild_hflags_arm(env); break; } } @@ -479,89 +556,6 @@ static uc_err reg_write(CPUARMState *env, unsigned int regid, const void *value) return ret; } -int arm_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count) -{ - CPUARMState *env = &(ARM_CPU(uc->cpu)->env); - int i; - uc_err err; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - err = reg_read(env, regid, value); - if (err) { - return err; - } - } - - return 0; -} - -int arm_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, - int count) -{ - CPUArchState *env = &(ARM_CPU(uc->cpu)->env); - int i; - uc_err err; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - err = reg_write(env, regid, value); - if (err) { - return err; - } - if (regid == UC_ARM_REG_R15) { - // force to quit execution and flush TB - uc->quit_request = true; - break_translation_loop(uc); - } - } - - return 0; -} - -DEFAULT_VISIBILITY -int arm_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) -{ - CPUARMState *env = (CPUARMState *)ctx->data; - int i; - uc_err err; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - err = reg_read(env, regid, value); - if (err) { - return err; - } - } - - return 0; -} - -DEFAULT_VISIBILITY -int arm_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) -{ - CPUARMState *env = (CPUARMState *)ctx->data; - int i; - uc_err err; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - err = reg_write(env, regid, value); - if (err) { - return err; - } - } - - return 0; -} - static bool arm_stop_interrupt(struct uc_struct *uc, int intno) { switch (intno) { @@ -760,11 +754,12 @@ static uc_err uc_arm_context_restore(struct uc_struct *uc, uc_context *context) return UC_ERR_OK; } -void arm_uc_init(struct uc_struct *uc) +DEFAULT_VISIBILITY +void uc_init(struct uc_struct *uc) { - uc->reg_read = arm_reg_read; - uc->reg_write = arm_reg_write; - uc->reg_reset = arm_reg_reset; + uc->reg_read = reg_read; + uc->reg_write = reg_write; + uc->reg_reset = reg_reset; uc->set_pc = arm_set_pc; uc->get_pc = arm_get_pc; uc->stop_interrupt = arm_stop_interrupt; diff --git a/qemu/target/i386/translate.c b/qemu/target/i386/translate.c index 2cc88f23..fc06162e 100644 --- a/qemu/target/i386/translate.c +++ b/qemu/target/i386/translate.c @@ -5476,6 +5476,9 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_jr(s, s->T0); break; case 3: /* lcall Ev */ + if (mod == 3) { + goto illegal_op; + } gen_op_ld_v(s, ot, s->T1, s->A0); gen_add_A0_im(s, 1 << ot); gen_op_ld_v(s, MO_16, s->T0, s->A0); @@ -5503,6 +5506,9 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu) gen_jr(s, s->T0); break; case 5: /* ljmp Ev */ + if (mod == 3) { + goto illegal_op; + } gen_op_ld_v(s, ot, s->T1, s->A0); gen_add_A0_im(s, 1 << ot); gen_op_ld_v(s, MO_16, s->T0, s->A0); diff --git a/qemu/target/i386/unicorn.c b/qemu/target/i386/unicorn.c index a7a93628..ceddb55d 100644 --- a/qemu/target/i386/unicorn.c +++ b/qemu/target/i386/unicorn.c @@ -65,7 +65,7 @@ static void x86_release(void *ctx) free(xcc->model); } -void x86_reg_reset(struct uc_struct *uc) +static void reg_reset(struct uc_struct *uc) { CPUArchState *env = uc->cpu->env_ptr; @@ -211,9 +211,13 @@ static int x86_msr_write(CPUX86State *env, uc_x86_msr *msr) return 0; } -static void reg_read(CPUX86State *env, unsigned int regid, void *value, - uc_mode mode) +DEFAULT_VISIBILITY +uc_err reg_read(void *_env, int mode, unsigned int regid, void *value, + size_t *size) { + CPUX86State *env = _env; + uc_err ret = UC_ERR_ARG; + switch (regid) { default: break; @@ -225,22 +229,26 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, case UC_X86_REG_FP5: case UC_X86_REG_FP6: case UC_X86_REG_FP7: { + CHECK_REG_TYPE(char[10]); floatx80 reg = env->fpregs[regid - UC_X86_REG_FP0].d; cpu_get_fp80(value, (uint16_t *)((char *)value + sizeof(uint64_t)), reg); + return ret; } - return; case UC_X86_REG_FPSW: { + CHECK_REG_TYPE(uint16_t); uint16_t fpus = env->fpus; fpus = fpus & ~0x3800; fpus |= (env->fpstt & 0x7) << 11; *(uint16_t *)value = fpus; + return ret; } - return; case UC_X86_REG_FPCW: + CHECK_REG_TYPE(uint16_t); *(uint16_t *)value = env->fpuc; - return; + return ret; case UC_X86_REG_FPTAG: { + CHECK_REG_TYPE(uint16_t); #define EXPD(fp) (fp.l.upper & 0x7fff) #define MANTD(fp) (fp.l.lower) #define MAXEXPD 0x7fff @@ -267,8 +275,8 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, } } *(uint16_t *)value = fptag; + return ret; } - return; case UC_X86_REG_XMM0: case UC_X86_REG_XMM1: case UC_X86_REG_XMM2: @@ -277,11 +285,12 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, case UC_X86_REG_XMM5: case UC_X86_REG_XMM6: case UC_X86_REG_XMM7: { + CHECK_REG_TYPE(float64[2]); float64 *dst = (float64 *)value; ZMMReg *reg = (ZMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0]; dst[0] = reg->ZMM_Q(0); dst[1] = reg->ZMM_Q(1); - return; + return ret; } case UC_X86_REG_ST0: case UC_X86_REG_ST1: @@ -291,9 +300,9 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, case UC_X86_REG_ST5: case UC_X86_REG_ST6: case UC_X86_REG_ST7: { - // value must be big enough to keep 80 bits (10 bytes) + CHECK_REG_TYPE(char[10]); memcpy(value, &FPST(regid - UC_X86_REG_ST0), 10); - return; + return ret; } case UC_X86_REG_YMM0: case UC_X86_REG_YMM1: @@ -311,6 +320,7 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, case UC_X86_REG_YMM13: case UC_X86_REG_YMM14: case UC_X86_REG_YMM15: { + CHECK_REG_TYPE(float64[4]); float64 *dst = (float64 *)value; ZMMReg *lo_reg = (ZMMReg *)&env->xmm_regs[regid - UC_X86_REG_YMM0]; XMMReg *hi_reg = &env->ymmh_regs[regid - UC_X86_REG_YMM0]; @@ -318,24 +328,29 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, dst[1] = lo_reg->ZMM_Q(1); dst[2] = hi_reg->_d[0]; dst[3] = hi_reg->_d[1]; - return; + return ret; } case UC_X86_REG_FIP: + CHECK_REG_TYPE(uint64_t); *(uint64_t *)value = env->fpip; - return; + return ret; case UC_X86_REG_FCS: + CHECK_REG_TYPE(uint16_t); *(uint16_t *)value = env->fpcs; - return; + return ret; case UC_X86_REG_FDP: + CHECK_REG_TYPE(uint64_t); *(uint64_t *)value = env->fpdp; - return; + return ret; case UC_X86_REG_FDS: + CHECK_REG_TYPE(uint16_t); *(uint16_t *)value = env->fpds; - return; + return ret; case UC_X86_REG_FOP: + CHECK_REG_TYPE(uint16_t); *(uint16_t *)value = env->fpop; - return; + return ret; } switch (mode) { @@ -346,23 +361,29 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, default: break; case UC_X86_REG_ES: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = env->segs[R_ES].selector; - return; + return ret; case UC_X86_REG_SS: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = env->segs[R_SS].selector; - return; + return ret; case UC_X86_REG_DS: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = env->segs[R_DS].selector; - return; + return ret; case UC_X86_REG_FS: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = env->segs[R_FS].selector; - return; + return ret; case UC_X86_REG_GS: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = env->segs[R_GS].selector; - return; + return ret; case UC_X86_REG_FS_BASE: + CHECK_REG_TYPE(uint32_t); *(uint32_t *)value = (uint32_t)env->segs[R_FS].base; - return; + return ret; } // fall-thru case UC_MODE_32: @@ -374,6 +395,7 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, case UC_X86_REG_CR2: case UC_X86_REG_CR3: case UC_X86_REG_CR4: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = env->cr[regid - UC_X86_REG_CR0]; break; case UC_X86_REG_DR0: @@ -384,137 +406,179 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, case UC_X86_REG_DR5: case UC_X86_REG_DR6: case UC_X86_REG_DR7: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = env->dr[regid - UC_X86_REG_DR0]; break; case UC_X86_REG_FLAGS: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = cpu_compute_eflags(env); break; case UC_X86_REG_EFLAGS: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = cpu_compute_eflags(env); break; case UC_X86_REG_EAX: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = env->regs[R_EAX]; break; case UC_X86_REG_AX: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->regs[R_EAX]); break; case UC_X86_REG_AH: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_H(env->regs[R_EAX]); break; case UC_X86_REG_AL: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_L(env->regs[R_EAX]); break; case UC_X86_REG_EBX: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = env->regs[R_EBX]; break; case UC_X86_REG_BX: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->regs[R_EBX]); break; case UC_X86_REG_BH: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_H(env->regs[R_EBX]); break; case UC_X86_REG_BL: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_L(env->regs[R_EBX]); break; case UC_X86_REG_ECX: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = env->regs[R_ECX]; break; case UC_X86_REG_CX: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->regs[R_ECX]); break; case UC_X86_REG_CH: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_H(env->regs[R_ECX]); break; case UC_X86_REG_CL: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_L(env->regs[R_ECX]); break; case UC_X86_REG_EDX: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = env->regs[R_EDX]; break; case UC_X86_REG_DX: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->regs[R_EDX]); break; case UC_X86_REG_DH: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_H(env->regs[R_EDX]); break; case UC_X86_REG_DL: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_L(env->regs[R_EDX]); break; case UC_X86_REG_ESP: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = env->regs[R_ESP]; break; case UC_X86_REG_SP: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->regs[R_ESP]); break; case UC_X86_REG_EBP: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = env->regs[R_EBP]; break; case UC_X86_REG_BP: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->regs[R_EBP]); break; case UC_X86_REG_ESI: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = env->regs[R_ESI]; break; case UC_X86_REG_SI: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->regs[R_ESI]); break; case UC_X86_REG_EDI: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = env->regs[R_EDI]; break; case UC_X86_REG_DI: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->regs[R_EDI]); break; case UC_X86_REG_EIP: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = env->eip; break; case UC_X86_REG_IP: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->eip); break; case UC_X86_REG_CS: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = (uint16_t)env->segs[R_CS].selector; break; case UC_X86_REG_DS: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = (uint16_t)env->segs[R_DS].selector; break; case UC_X86_REG_SS: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = (uint16_t)env->segs[R_SS].selector; break; case UC_X86_REG_ES: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = (uint16_t)env->segs[R_ES].selector; break; case UC_X86_REG_FS: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = (uint16_t)env->segs[R_FS].selector; break; case UC_X86_REG_GS: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = (uint16_t)env->segs[R_GS].selector; break; case UC_X86_REG_IDTR: + CHECK_REG_TYPE(uc_x86_mmr); ((uc_x86_mmr *)value)->limit = (uint16_t)env->idt.limit; ((uc_x86_mmr *)value)->base = (uint32_t)env->idt.base; break; case UC_X86_REG_GDTR: + CHECK_REG_TYPE(uc_x86_mmr); ((uc_x86_mmr *)value)->limit = (uint16_t)env->gdt.limit; ((uc_x86_mmr *)value)->base = (uint32_t)env->gdt.base; break; case UC_X86_REG_LDTR: + CHECK_REG_TYPE(uc_x86_mmr); ((uc_x86_mmr *)value)->limit = env->ldt.limit; ((uc_x86_mmr *)value)->base = (uint32_t)env->ldt.base; ((uc_x86_mmr *)value)->selector = (uint16_t)env->ldt.selector; ((uc_x86_mmr *)value)->flags = env->ldt.flags; break; case UC_X86_REG_TR: + CHECK_REG_TYPE(uc_x86_mmr); ((uc_x86_mmr *)value)->limit = env->tr.limit; ((uc_x86_mmr *)value)->base = (uint32_t)env->tr.base; ((uc_x86_mmr *)value)->selector = (uint16_t)env->tr.selector; ((uc_x86_mmr *)value)->flags = env->tr.flags; break; case UC_X86_REG_MSR: + CHECK_REG_TYPE(uc_x86_msr); x86_msr_read(env, (uc_x86_msr *)value); break; case UC_X86_REG_MXCSR: + CHECK_REG_TYPE(uint32_t); *(uint32_t *)value = env->mxcsr; break; case UC_X86_REG_FS_BASE: + CHECK_REG_TYPE(uint32_t); *(uint32_t *)value = (uint32_t)env->segs[R_FS].base; break; } @@ -530,6 +594,7 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, case UC_X86_REG_CR2: case UC_X86_REG_CR3: case UC_X86_REG_CR4: + CHECK_REG_TYPE(int64_t); *(int64_t *)value = env->cr[regid - UC_X86_REG_CR0]; break; case UC_X86_REG_DR0: @@ -540,272 +605,359 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, case UC_X86_REG_DR5: case UC_X86_REG_DR6: case UC_X86_REG_DR7: + CHECK_REG_TYPE(int64_t); *(int64_t *)value = env->dr[regid - UC_X86_REG_DR0]; break; case UC_X86_REG_FLAGS: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = cpu_compute_eflags(env); break; case UC_X86_REG_EFLAGS: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = cpu_compute_eflags(env); break; case UC_X86_REG_RFLAGS: + CHECK_REG_TYPE(int64_t); *(int64_t *)value = cpu_compute_eflags(env); break; case UC_X86_REG_RAX: + CHECK_REG_TYPE(uint64_t); *(uint64_t *)value = env->regs[R_EAX]; break; case UC_X86_REG_EAX: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = READ_DWORD(env->regs[R_EAX]); break; case UC_X86_REG_AX: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->regs[R_EAX]); break; case UC_X86_REG_AH: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_H(env->regs[R_EAX]); break; case UC_X86_REG_AL: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_L(env->regs[R_EAX]); break; case UC_X86_REG_RBX: + CHECK_REG_TYPE(uint64_t); *(uint64_t *)value = env->regs[R_EBX]; break; case UC_X86_REG_EBX: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = READ_DWORD(env->regs[R_EBX]); break; case UC_X86_REG_BX: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->regs[R_EBX]); break; case UC_X86_REG_BH: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_H(env->regs[R_EBX]); break; case UC_X86_REG_BL: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_L(env->regs[R_EBX]); break; case UC_X86_REG_RCX: + CHECK_REG_TYPE(uint64_t); *(uint64_t *)value = env->regs[R_ECX]; break; case UC_X86_REG_ECX: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = READ_DWORD(env->regs[R_ECX]); break; case UC_X86_REG_CX: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->regs[R_ECX]); break; case UC_X86_REG_CH: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_H(env->regs[R_ECX]); break; case UC_X86_REG_CL: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_L(env->regs[R_ECX]); break; case UC_X86_REG_RDX: + CHECK_REG_TYPE(uint64_t); *(uint64_t *)value = env->regs[R_EDX]; break; case UC_X86_REG_EDX: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = READ_DWORD(env->regs[R_EDX]); break; case UC_X86_REG_DX: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->regs[R_EDX]); break; case UC_X86_REG_DH: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_H(env->regs[R_EDX]); break; case UC_X86_REG_DL: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_L(env->regs[R_EDX]); break; case UC_X86_REG_RSP: + CHECK_REG_TYPE(uint64_t); *(uint64_t *)value = env->regs[R_ESP]; break; case UC_X86_REG_ESP: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = READ_DWORD(env->regs[R_ESP]); break; case UC_X86_REG_SP: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->regs[R_ESP]); break; case UC_X86_REG_SPL: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_L(env->regs[R_ESP]); break; case UC_X86_REG_RBP: + CHECK_REG_TYPE(uint64_t); *(uint64_t *)value = env->regs[R_EBP]; break; case UC_X86_REG_EBP: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = READ_DWORD(env->regs[R_EBP]); break; case UC_X86_REG_BP: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->regs[R_EBP]); break; case UC_X86_REG_BPL: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_L(env->regs[R_EBP]); break; case UC_X86_REG_RSI: + CHECK_REG_TYPE(uint64_t); *(uint64_t *)value = env->regs[R_ESI]; break; case UC_X86_REG_ESI: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = READ_DWORD(env->regs[R_ESI]); break; case UC_X86_REG_SI: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->regs[R_ESI]); break; case UC_X86_REG_SIL: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_L(env->regs[R_ESI]); break; case UC_X86_REG_RDI: + CHECK_REG_TYPE(uint64_t); *(uint64_t *)value = env->regs[R_EDI]; break; case UC_X86_REG_EDI: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = READ_DWORD(env->regs[R_EDI]); break; case UC_X86_REG_DI: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->regs[R_EDI]); break; case UC_X86_REG_DIL: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_L(env->regs[R_EDI]); break; case UC_X86_REG_RIP: + CHECK_REG_TYPE(uint64_t); *(uint64_t *)value = env->eip; break; case UC_X86_REG_EIP: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = READ_DWORD(env->eip); break; case UC_X86_REG_IP: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->eip); break; case UC_X86_REG_CS: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = (uint16_t)env->segs[R_CS].selector; break; case UC_X86_REG_DS: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = (uint16_t)env->segs[R_DS].selector; break; case UC_X86_REG_SS: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = (uint16_t)env->segs[R_SS].selector; break; case UC_X86_REG_ES: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = (uint16_t)env->segs[R_ES].selector; break; case UC_X86_REG_FS: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = (uint16_t)env->segs[R_FS].selector; break; case UC_X86_REG_GS: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = (uint16_t)env->segs[R_GS].selector; break; case UC_X86_REG_R8: + CHECK_REG_TYPE(int64_t); *(int64_t *)value = READ_QWORD(env->regs[8]); break; case UC_X86_REG_R8D: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = READ_DWORD(env->regs[8]); break; case UC_X86_REG_R8W: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->regs[8]); break; case UC_X86_REG_R8B: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_L(env->regs[8]); break; case UC_X86_REG_R9: + CHECK_REG_TYPE(int64_t); *(int64_t *)value = READ_QWORD(env->regs[9]); break; case UC_X86_REG_R9D: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = READ_DWORD(env->regs[9]); break; case UC_X86_REG_R9W: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->regs[9]); break; case UC_X86_REG_R9B: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_L(env->regs[9]); break; case UC_X86_REG_R10: + CHECK_REG_TYPE(int64_t); *(int64_t *)value = READ_QWORD(env->regs[10]); break; case UC_X86_REG_R10D: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = READ_DWORD(env->regs[10]); break; case UC_X86_REG_R10W: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->regs[10]); break; case UC_X86_REG_R10B: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_L(env->regs[10]); break; case UC_X86_REG_R11: + CHECK_REG_TYPE(int64_t); *(int64_t *)value = READ_QWORD(env->regs[11]); break; case UC_X86_REG_R11D: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = READ_DWORD(env->regs[11]); break; case UC_X86_REG_R11W: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->regs[11]); break; case UC_X86_REG_R11B: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_L(env->regs[11]); break; case UC_X86_REG_R12: + CHECK_REG_TYPE(int64_t); *(int64_t *)value = READ_QWORD(env->regs[12]); break; case UC_X86_REG_R12D: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = READ_DWORD(env->regs[12]); break; case UC_X86_REG_R12W: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->regs[12]); break; case UC_X86_REG_R12B: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_L(env->regs[12]); break; case UC_X86_REG_R13: + CHECK_REG_TYPE(int64_t); *(int64_t *)value = READ_QWORD(env->regs[13]); break; case UC_X86_REG_R13D: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = READ_DWORD(env->regs[13]); break; case UC_X86_REG_R13W: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->regs[13]); break; case UC_X86_REG_R13B: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_L(env->regs[13]); break; case UC_X86_REG_R14: + CHECK_REG_TYPE(int64_t); *(int64_t *)value = READ_QWORD(env->regs[14]); break; case UC_X86_REG_R14D: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = READ_DWORD(env->regs[14]); break; case UC_X86_REG_R14W: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->regs[14]); break; case UC_X86_REG_R14B: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_L(env->regs[14]); break; case UC_X86_REG_R15: + CHECK_REG_TYPE(int64_t); *(int64_t *)value = READ_QWORD(env->regs[15]); break; case UC_X86_REG_R15D: + CHECK_REG_TYPE(int32_t); *(int32_t *)value = READ_DWORD(env->regs[15]); break; case UC_X86_REG_R15W: + CHECK_REG_TYPE(int16_t); *(int16_t *)value = READ_WORD(env->regs[15]); break; case UC_X86_REG_R15B: + CHECK_REG_TYPE(int8_t); *(int8_t *)value = READ_BYTE_L(env->regs[15]); break; case UC_X86_REG_IDTR: + CHECK_REG_TYPE(uc_x86_mmr); ((uc_x86_mmr *)value)->limit = (uint16_t)env->idt.limit; ((uc_x86_mmr *)value)->base = env->idt.base; break; case UC_X86_REG_GDTR: + CHECK_REG_TYPE(uc_x86_mmr); ((uc_x86_mmr *)value)->limit = (uint16_t)env->gdt.limit; ((uc_x86_mmr *)value)->base = env->gdt.base; break; case UC_X86_REG_LDTR: + CHECK_REG_TYPE(uc_x86_mmr); ((uc_x86_mmr *)value)->limit = env->ldt.limit; ((uc_x86_mmr *)value)->base = env->ldt.base; ((uc_x86_mmr *)value)->selector = (uint16_t)env->ldt.selector; ((uc_x86_mmr *)value)->flags = env->ldt.flags; break; case UC_X86_REG_TR: + CHECK_REG_TYPE(uc_x86_mmr); ((uc_x86_mmr *)value)->limit = env->tr.limit; ((uc_x86_mmr *)value)->base = env->tr.base; ((uc_x86_mmr *)value)->selector = (uint16_t)env->tr.selector; ((uc_x86_mmr *)value)->flags = env->tr.flags; break; case UC_X86_REG_MSR: + CHECK_REG_TYPE(uc_x86_msr); x86_msr_read(env, (uc_x86_msr *)value); break; case UC_X86_REG_MXCSR: + CHECK_REG_TYPE(uint32_t); *(uint32_t *)value = env->mxcsr; break; case UC_X86_REG_XMM8: @@ -816,6 +968,7 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, case UC_X86_REG_XMM13: case UC_X86_REG_XMM14: case UC_X86_REG_XMM15: { + CHECK_REG_TYPE(float64[2]); float64 *dst = (float64 *)value; ZMMReg *reg = (ZMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0]; dst[0] = reg->ZMM_Q(0); @@ -823,9 +976,11 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, break; } case UC_X86_REG_FS_BASE: + CHECK_REG_TYPE(uint64_t); *(uint64_t *)value = (uint64_t)env->segs[R_FS].base; break; case UC_X86_REG_GS_BASE: + CHECK_REG_TYPE(uint64_t); *(uint64_t *)value = (uint64_t)env->segs[R_GS].base; break; } @@ -833,13 +988,15 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, #endif } - return; + return ret; } -static int reg_write(CPUX86State *env, unsigned int regid, const void *value, - uc_mode mode) +DEFAULT_VISIBILITY +uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc) { - int ret; + CPUX86State *env = _env; + uc_err ret = UC_ERR_ARG; switch (regid) { default: @@ -852,21 +1009,25 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, case UC_X86_REG_FP5: case UC_X86_REG_FP6: case UC_X86_REG_FP7: { + CHECK_REG_TYPE(char[10]); uint64_t mant = *(uint64_t *)value; uint16_t upper = *(uint16_t *)((char *)value + sizeof(uint64_t)); env->fpregs[regid - UC_X86_REG_FP0].d = cpu_set_fp80(mant, upper); + return ret; } - return 0; case UC_X86_REG_FPSW: { + CHECK_REG_TYPE(uint16_t); uint16_t fpus = *(uint16_t *)value; env->fpus = fpus & ~0x3800; env->fpstt = (fpus >> 11) & 0x7; + return ret; } - return 0; case UC_X86_REG_FPCW: + CHECK_REG_TYPE(uint16_t); cpu_set_fpuc(env, *(uint16_t *)value); - return 0; + return ret; case UC_X86_REG_FPTAG: { + CHECK_REG_TYPE(uint16_t); int i; uint16_t fptag = *(uint16_t *)value; for (i = 0; i < 8; i++) { @@ -874,8 +1035,8 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, fptag >>= 2; } - return 0; - } break; + return ret; + } case UC_X86_REG_XMM0: case UC_X86_REG_XMM1: case UC_X86_REG_XMM2: @@ -884,11 +1045,12 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, case UC_X86_REG_XMM5: case UC_X86_REG_XMM6: case UC_X86_REG_XMM7: { + CHECK_REG_TYPE(float64[2]); float64 *src = (float64 *)value; ZMMReg *reg = (ZMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0]; reg->ZMM_Q(0) = src[0]; reg->ZMM_Q(1) = src[1]; - return 0; + return ret; } case UC_X86_REG_ST0: case UC_X86_REG_ST1: @@ -898,9 +1060,9 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, case UC_X86_REG_ST5: case UC_X86_REG_ST6: case UC_X86_REG_ST7: { - // value must be big enough to keep 80 bits (10 bytes) + CHECK_REG_TYPE(char[10]); memcpy(&FPST(regid - UC_X86_REG_ST0), value, 10); - return 0; + return ret; } case UC_X86_REG_YMM0: case UC_X86_REG_YMM1: @@ -918,6 +1080,7 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, case UC_X86_REG_YMM13: case UC_X86_REG_YMM14: case UC_X86_REG_YMM15: { + CHECK_REG_TYPE(float64[4]); float64 *src = (float64 *)value; ZMMReg *lo_reg = (ZMMReg *)&env->xmm_regs[regid - UC_X86_REG_YMM0]; XMMReg *hi_reg = &env->ymmh_regs[regid - UC_X86_REG_YMM0]; @@ -927,24 +1090,29 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, // As of qemu 5.0.1, ymmh_regs is nowhere used. hi_reg->_d[0] = src[2]; hi_reg->_d[1] = src[3]; - return 0; + return ret; } case UC_X86_REG_FIP: + CHECK_REG_TYPE(uint64_t); env->fpip = *(uint64_t *)value; - return 0; + return ret; case UC_X86_REG_FCS: + CHECK_REG_TYPE(uint16_t); env->fpcs = *(uint16_t *)value; - return 0; + return ret; case UC_X86_REG_FDP: + CHECK_REG_TYPE(uint64_t); env->fpdp = *(uint64_t *)value; - return 0; + return ret; case UC_X86_REG_FDS: + CHECK_REG_TYPE(uint16_t); env->fpds = *(uint16_t *)value; - return 0; + return ret; case UC_X86_REG_FOP: + CHECK_REG_TYPE(uint16_t); env->fpop = *(uint16_t *)value; - return 0; + return ret; } switch (mode) { @@ -956,20 +1124,25 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, default: break; case UC_X86_REG_ES: + CHECK_REG_TYPE(uint16_t); load_seg_16_helper(env, R_ES, *(uint16_t *)value); - return 0; + return ret; case UC_X86_REG_SS: + CHECK_REG_TYPE(uint16_t); load_seg_16_helper(env, R_SS, *(uint16_t *)value); - return 0; + return ret; case UC_X86_REG_DS: + CHECK_REG_TYPE(uint16_t); load_seg_16_helper(env, R_DS, *(uint16_t *)value); - return 0; + return ret; case UC_X86_REG_FS: + CHECK_REG_TYPE(uint16_t); load_seg_16_helper(env, R_FS, *(uint16_t *)value); - return 0; + return ret; case UC_X86_REG_GS: + CHECK_REG_TYPE(uint16_t); load_seg_16_helper(env, R_GS, *(uint16_t *)value); - return 0; + return ret; } // fall-thru case UC_MODE_32: @@ -977,16 +1150,19 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, default: break; case UC_X86_REG_CR0: + CHECK_REG_TYPE(uint32_t); cpu_x86_update_cr0(env, *(uint32_t *)value); goto write_cr; case UC_X86_REG_CR1: case UC_X86_REG_CR2: case UC_X86_REG_CR3: + CHECK_REG_TYPE(uint32_t); cpu_x86_update_cr3(env, *(uint32_t *)value); goto write_cr; case UC_X86_REG_CR4: + CHECK_REG_TYPE(uint32_t); cpu_x86_update_cr4(env, *(uint32_t *)value); -write_cr: + write_cr: env->cr[regid - UC_X86_REG_CR0] = *(uint32_t *)value; break; case UC_X86_REG_DR0: @@ -997,93 +1173,125 @@ write_cr: case UC_X86_REG_DR5: case UC_X86_REG_DR6: case UC_X86_REG_DR7: + CHECK_REG_TYPE(uint32_t); env->dr[regid - UC_X86_REG_DR0] = *(uint32_t *)value; break; case UC_X86_REG_FLAGS: + CHECK_REG_TYPE(uint16_t); cpu_load_eflags(env, *(uint16_t *)value, -1); break; case UC_X86_REG_EFLAGS: + CHECK_REG_TYPE(uint32_t); cpu_load_eflags(env, *(uint32_t *)value, -1); break; case UC_X86_REG_EAX: + CHECK_REG_TYPE(uint32_t); env->regs[R_EAX] = *(uint32_t *)value; break; case UC_X86_REG_AX: + CHECK_REG_TYPE(uint16_t); WRITE_WORD(env->regs[R_EAX], *(uint16_t *)value); break; case UC_X86_REG_AH: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_H(env->regs[R_EAX], *(uint8_t *)value); break; case UC_X86_REG_AL: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_L(env->regs[R_EAX], *(uint8_t *)value); break; case UC_X86_REG_EBX: + CHECK_REG_TYPE(uint32_t); env->regs[R_EBX] = *(uint32_t *)value; break; case UC_X86_REG_BX: + CHECK_REG_TYPE(uint16_t); WRITE_WORD(env->regs[R_EBX], *(uint16_t *)value); break; case UC_X86_REG_BH: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_H(env->regs[R_EBX], *(uint8_t *)value); break; case UC_X86_REG_BL: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_L(env->regs[R_EBX], *(uint8_t *)value); break; case UC_X86_REG_ECX: + CHECK_REG_TYPE(uint32_t); env->regs[R_ECX] = *(uint32_t *)value; break; case UC_X86_REG_CX: + CHECK_REG_TYPE(uint16_t); WRITE_WORD(env->regs[R_ECX], *(uint16_t *)value); break; case UC_X86_REG_CH: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_H(env->regs[R_ECX], *(uint8_t *)value); break; case UC_X86_REG_CL: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_L(env->regs[R_ECX], *(uint8_t *)value); break; case UC_X86_REG_EDX: + CHECK_REG_TYPE(uint32_t); env->regs[R_EDX] = *(uint32_t *)value; break; case UC_X86_REG_DX: + CHECK_REG_TYPE(uint16_t); WRITE_WORD(env->regs[R_EDX], *(uint16_t *)value); break; case UC_X86_REG_DH: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_H(env->regs[R_EDX], *(uint8_t *)value); break; case UC_X86_REG_DL: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_L(env->regs[R_EDX], *(uint8_t *)value); break; case UC_X86_REG_ESP: + CHECK_REG_TYPE(uint32_t); env->regs[R_ESP] = *(uint32_t *)value; break; case UC_X86_REG_SP: + CHECK_REG_TYPE(uint16_t); WRITE_WORD(env->regs[R_ESP], *(uint16_t *)value); break; case UC_X86_REG_EBP: + CHECK_REG_TYPE(uint32_t); env->regs[R_EBP] = *(uint32_t *)value; break; case UC_X86_REG_BP: + CHECK_REG_TYPE(uint16_t); WRITE_WORD(env->regs[R_EBP], *(uint16_t *)value); break; case UC_X86_REG_ESI: + CHECK_REG_TYPE(uint32_t); env->regs[R_ESI] = *(uint32_t *)value; break; case UC_X86_REG_SI: + CHECK_REG_TYPE(uint16_t); WRITE_WORD(env->regs[R_ESI], *(uint16_t *)value); break; case UC_X86_REG_EDI: + CHECK_REG_TYPE(uint32_t); env->regs[R_EDI] = *(uint32_t *)value; break; case UC_X86_REG_DI: + CHECK_REG_TYPE(uint16_t); WRITE_WORD(env->regs[R_EDI], *(uint16_t *)value); break; case UC_X86_REG_EIP: + CHECK_REG_TYPE(uint32_t); env->eip = *(uint32_t *)value; + *setpc = 1; break; case UC_X86_REG_IP: + CHECK_REG_TYPE(uint16_t); env->eip = *(uint16_t *)value; + *setpc = 1; break; case UC_X86_REG_CS: + CHECK_REG_TYPE(uint16_t); ret = uc_check_cpu_x86_load_seg(env, R_CS, *(uint16_t *)value); if (ret) { return ret; @@ -1091,6 +1299,7 @@ write_cr: cpu_x86_load_seg(env, R_CS, *(uint16_t *)value); break; case UC_X86_REG_DS: + CHECK_REG_TYPE(uint16_t); ret = uc_check_cpu_x86_load_seg(env, R_DS, *(uint16_t *)value); if (ret) { return ret; @@ -1098,6 +1307,7 @@ write_cr: cpu_x86_load_seg(env, R_DS, *(uint16_t *)value); break; case UC_X86_REG_SS: + CHECK_REG_TYPE(uint16_t); ret = uc_check_cpu_x86_load_seg(env, R_SS, *(uint16_t *)value); if (ret) { return ret; @@ -1105,6 +1315,7 @@ write_cr: cpu_x86_load_seg(env, R_SS, *(uint16_t *)value); break; case UC_X86_REG_ES: + CHECK_REG_TYPE(uint16_t); ret = uc_check_cpu_x86_load_seg(env, R_ES, *(uint16_t *)value); if (ret) { return ret; @@ -1112,6 +1323,7 @@ write_cr: cpu_x86_load_seg(env, R_ES, *(uint16_t *)value); break; case UC_X86_REG_FS: + CHECK_REG_TYPE(uint16_t); ret = uc_check_cpu_x86_load_seg(env, R_FS, *(uint16_t *)value); if (ret) { return ret; @@ -1119,6 +1331,7 @@ write_cr: cpu_x86_load_seg(env, R_FS, *(uint16_t *)value); break; case UC_X86_REG_GS: + CHECK_REG_TYPE(uint16_t); ret = uc_check_cpu_x86_load_seg(env, R_GS, *(uint16_t *)value); if (ret) { return ret; @@ -1126,37 +1339,45 @@ write_cr: cpu_x86_load_seg(env, R_GS, *(uint16_t *)value); break; case UC_X86_REG_IDTR: + CHECK_REG_TYPE(uc_x86_mmr); env->idt.limit = (uint16_t)((uc_x86_mmr *)value)->limit; env->idt.base = (uint32_t)((uc_x86_mmr *)value)->base; break; case UC_X86_REG_GDTR: + CHECK_REG_TYPE(uc_x86_mmr); env->gdt.limit = (uint16_t)((uc_x86_mmr *)value)->limit; env->gdt.base = (uint32_t)((uc_x86_mmr *)value)->base; break; case UC_X86_REG_LDTR: + CHECK_REG_TYPE(uc_x86_mmr); env->ldt.limit = ((uc_x86_mmr *)value)->limit; env->ldt.base = (uint32_t)((uc_x86_mmr *)value)->base; env->ldt.selector = (uint16_t)((uc_x86_mmr *)value)->selector; env->ldt.flags = ((uc_x86_mmr *)value)->flags; break; case UC_X86_REG_TR: + CHECK_REG_TYPE(uc_x86_mmr); env->tr.limit = ((uc_x86_mmr *)value)->limit; env->tr.base = (uint32_t)((uc_x86_mmr *)value)->base; env->tr.selector = (uint16_t)((uc_x86_mmr *)value)->selector; env->tr.flags = ((uc_x86_mmr *)value)->flags; break; case UC_X86_REG_MSR: + CHECK_REG_TYPE(uc_x86_msr); x86_msr_write(env, (uc_x86_msr *)value); break; case UC_X86_REG_MXCSR: + CHECK_REG_TYPE(uint32_t); cpu_set_mxcsr(env, *(uint32_t *)value); break; /* // Don't think base registers are a "thing" on x86 case UC_X86_REG_FS_BASE: + CHECK_REG_TYPE(uint32_t); env->segs[R_FS].base = *(uint32_t *)value; continue; case UC_X86_REG_GS_BASE: + CHECK_REG_TYPE(uint32_t); env->segs[R_GS].base = *(uint32_t *)value; continue; */ @@ -1169,16 +1390,19 @@ write_cr: default: break; case UC_X86_REG_CR0: - cpu_x86_update_cr0(env, *(uint32_t *) value); + CHECK_REG_TYPE(uint64_t); + cpu_x86_update_cr0(env, *(uint32_t *)value); goto write_cr64; case UC_X86_REG_CR1: case UC_X86_REG_CR2: case UC_X86_REG_CR3: - cpu_x86_update_cr3(env, *(uint32_t *) value); + CHECK_REG_TYPE(uint64_t); + cpu_x86_update_cr3(env, *(uint32_t *)value); goto write_cr64; case UC_X86_REG_CR4: - cpu_x86_update_cr4(env, *(uint32_t *) value); -write_cr64: + CHECK_REG_TYPE(uint64_t); + cpu_x86_update_cr4(env, *(uint32_t *)value); + write_cr64: env->cr[regid - UC_X86_REG_CR0] = *(uint64_t *)value; break; case UC_X86_REG_DR0: @@ -1189,147 +1413,198 @@ write_cr64: case UC_X86_REG_DR5: case UC_X86_REG_DR6: case UC_X86_REG_DR7: + CHECK_REG_TYPE(uint64_t); env->dr[regid - UC_X86_REG_DR0] = *(uint64_t *)value; break; case UC_X86_REG_FLAGS: + CHECK_REG_TYPE(uint16_t); cpu_load_eflags(env, *(uint16_t *)value, -1); break; case UC_X86_REG_EFLAGS: + CHECK_REG_TYPE(uint32_t); cpu_load_eflags(env, *(uint32_t *)value, -1); break; case UC_X86_REG_RFLAGS: + CHECK_REG_TYPE(uint64_t); cpu_load_eflags(env, *(uint64_t *)value, -1); break; case UC_X86_REG_RAX: + CHECK_REG_TYPE(uint64_t); env->regs[R_EAX] = *(uint64_t *)value; break; case UC_X86_REG_EAX: + CHECK_REG_TYPE(uint32_t); WRITE_DWORD(env->regs[R_EAX], *(uint32_t *)value); break; case UC_X86_REG_AX: + CHECK_REG_TYPE(uint16_t); WRITE_WORD(env->regs[R_EAX], *(uint16_t *)value); break; case UC_X86_REG_AH: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_H(env->regs[R_EAX], *(uint8_t *)value); break; case UC_X86_REG_AL: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_L(env->regs[R_EAX], *(uint8_t *)value); break; case UC_X86_REG_RBX: + CHECK_REG_TYPE(uint64_t); env->regs[R_EBX] = *(uint64_t *)value; break; case UC_X86_REG_EBX: + CHECK_REG_TYPE(uint32_t); WRITE_DWORD(env->regs[R_EBX], *(uint32_t *)value); break; case UC_X86_REG_BX: + CHECK_REG_TYPE(uint16_t); WRITE_WORD(env->regs[R_EBX], *(uint16_t *)value); break; case UC_X86_REG_BH: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_H(env->regs[R_EBX], *(uint8_t *)value); break; case UC_X86_REG_BL: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_L(env->regs[R_EBX], *(uint8_t *)value); break; case UC_X86_REG_RCX: + CHECK_REG_TYPE(uint64_t); env->regs[R_ECX] = *(uint64_t *)value; break; case UC_X86_REG_ECX: + CHECK_REG_TYPE(uint32_t); WRITE_DWORD(env->regs[R_ECX], *(uint32_t *)value); break; case UC_X86_REG_CX: + CHECK_REG_TYPE(uint16_t); WRITE_WORD(env->regs[R_ECX], *(uint16_t *)value); break; case UC_X86_REG_CH: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_H(env->regs[R_ECX], *(uint8_t *)value); break; case UC_X86_REG_CL: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_L(env->regs[R_ECX], *(uint8_t *)value); break; case UC_X86_REG_RDX: + CHECK_REG_TYPE(uint64_t); env->regs[R_EDX] = *(uint64_t *)value; break; case UC_X86_REG_EDX: + CHECK_REG_TYPE(uint32_t); WRITE_DWORD(env->regs[R_EDX], *(uint32_t *)value); break; case UC_X86_REG_DX: + CHECK_REG_TYPE(uint16_t); WRITE_WORD(env->regs[R_EDX], *(uint16_t *)value); break; case UC_X86_REG_DH: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_H(env->regs[R_EDX], *(uint8_t *)value); break; case UC_X86_REG_DL: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_L(env->regs[R_EDX], *(uint8_t *)value); break; case UC_X86_REG_RSP: + CHECK_REG_TYPE(uint64_t); env->regs[R_ESP] = *(uint64_t *)value; break; case UC_X86_REG_ESP: + CHECK_REG_TYPE(uint32_t); WRITE_DWORD(env->regs[R_ESP], *(uint32_t *)value); break; case UC_X86_REG_SP: + CHECK_REG_TYPE(uint16_t); WRITE_WORD(env->regs[R_ESP], *(uint16_t *)value); break; case UC_X86_REG_SPL: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_L(env->regs[R_ESP], *(uint8_t *)value); break; case UC_X86_REG_RBP: + CHECK_REG_TYPE(uint64_t); env->regs[R_EBP] = *(uint64_t *)value; break; case UC_X86_REG_EBP: + CHECK_REG_TYPE(uint32_t); WRITE_DWORD(env->regs[R_EBP], *(uint32_t *)value); break; case UC_X86_REG_BP: + CHECK_REG_TYPE(uint16_t); WRITE_WORD(env->regs[R_EBP], *(uint16_t *)value); break; case UC_X86_REG_BPL: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_L(env->regs[R_EBP], *(uint8_t *)value); break; case UC_X86_REG_RSI: + CHECK_REG_TYPE(uint64_t); env->regs[R_ESI] = *(uint64_t *)value; break; case UC_X86_REG_ESI: + CHECK_REG_TYPE(uint32_t); WRITE_DWORD(env->regs[R_ESI], *(uint32_t *)value); break; case UC_X86_REG_SI: + CHECK_REG_TYPE(uint16_t); WRITE_WORD(env->regs[R_ESI], *(uint16_t *)value); break; case UC_X86_REG_SIL: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_L(env->regs[R_ESI], *(uint8_t *)value); break; case UC_X86_REG_RDI: + CHECK_REG_TYPE(uint64_t); env->regs[R_EDI] = *(uint64_t *)value; break; case UC_X86_REG_EDI: + CHECK_REG_TYPE(uint32_t); WRITE_DWORD(env->regs[R_EDI], *(uint32_t *)value); break; case UC_X86_REG_DI: + CHECK_REG_TYPE(uint16_t); WRITE_WORD(env->regs[R_EDI], *(uint16_t *)value); break; case UC_X86_REG_DIL: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_L(env->regs[R_EDI], *(uint8_t *)value); break; case UC_X86_REG_RIP: + CHECK_REG_TYPE(uint64_t); env->eip = *(uint64_t *)value; + *setpc = 1; break; case UC_X86_REG_EIP: + CHECK_REG_TYPE(uint32_t); env->eip = *(uint32_t *)value; + *setpc = 1; break; case UC_X86_REG_IP: + CHECK_REG_TYPE(uint16_t); WRITE_WORD(env->eip, *(uint16_t *)value); + *setpc = 1; break; case UC_X86_REG_CS: + CHECK_REG_TYPE(uint16_t); env->segs[R_CS].selector = *(uint16_t *)value; break; case UC_X86_REG_DS: + CHECK_REG_TYPE(uint16_t); env->segs[R_DS].selector = *(uint16_t *)value; break; case UC_X86_REG_SS: + CHECK_REG_TYPE(uint16_t); env->segs[R_SS].selector = *(uint16_t *)value; break; case UC_X86_REG_ES: + CHECK_REG_TYPE(uint16_t); env->segs[R_ES].selector = *(uint16_t *)value; break; case UC_X86_REG_FS: + CHECK_REG_TYPE(uint16_t); ret = uc_check_cpu_x86_load_seg(env, R_FS, *(uint16_t *)value); if (ret) { return ret; @@ -1337,6 +1612,7 @@ write_cr64: cpu_x86_load_seg(env, R_FS, *(uint16_t *)value); break; case UC_X86_REG_GS: + CHECK_REG_TYPE(uint16_t); ret = uc_check_cpu_x86_load_seg(env, R_GS, *(uint16_t *)value); if (ret) { return ret; @@ -1344,125 +1620,163 @@ write_cr64: cpu_x86_load_seg(env, R_GS, *(uint16_t *)value); break; case UC_X86_REG_R8: + CHECK_REG_TYPE(uint64_t); env->regs[8] = *(uint64_t *)value; break; case UC_X86_REG_R8D: + CHECK_REG_TYPE(uint32_t); WRITE_DWORD(env->regs[8], *(uint32_t *)value); break; case UC_X86_REG_R8W: + CHECK_REG_TYPE(uint16_t); WRITE_WORD(env->regs[8], *(uint16_t *)value); break; case UC_X86_REG_R8B: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_L(env->regs[8], *(uint8_t *)value); break; case UC_X86_REG_R9: + CHECK_REG_TYPE(uint64_t); env->regs[9] = *(uint64_t *)value; break; case UC_X86_REG_R9D: + CHECK_REG_TYPE(uint32_t); WRITE_DWORD(env->regs[9], *(uint32_t *)value); break; case UC_X86_REG_R9W: + CHECK_REG_TYPE(uint16_t); WRITE_WORD(env->regs[9], *(uint16_t *)value); break; case UC_X86_REG_R9B: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_L(env->regs[9], *(uint8_t *)value); break; case UC_X86_REG_R10: + CHECK_REG_TYPE(uint64_t); env->regs[10] = *(uint64_t *)value; break; case UC_X86_REG_R10D: + CHECK_REG_TYPE(uint32_t); WRITE_DWORD(env->regs[10], *(uint32_t *)value); break; case UC_X86_REG_R10W: + CHECK_REG_TYPE(uint16_t); WRITE_WORD(env->regs[10], *(uint16_t *)value); break; case UC_X86_REG_R10B: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_L(env->regs[10], *(uint8_t *)value); break; case UC_X86_REG_R11: + CHECK_REG_TYPE(uint64_t); env->regs[11] = *(uint64_t *)value; break; case UC_X86_REG_R11D: + CHECK_REG_TYPE(uint32_t); WRITE_DWORD(env->regs[11], *(uint32_t *)value); break; case UC_X86_REG_R11W: + CHECK_REG_TYPE(uint16_t); WRITE_WORD(env->regs[11], *(uint16_t *)value); break; case UC_X86_REG_R11B: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_L(env->regs[11], *(uint8_t *)value); break; case UC_X86_REG_R12: + CHECK_REG_TYPE(uint64_t); env->regs[12] = *(uint64_t *)value; break; case UC_X86_REG_R12D: + CHECK_REG_TYPE(uint32_t); WRITE_DWORD(env->regs[12], *(uint32_t *)value); break; case UC_X86_REG_R12W: + CHECK_REG_TYPE(uint16_t); WRITE_WORD(env->regs[12], *(uint16_t *)value); break; case UC_X86_REG_R12B: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_L(env->regs[12], *(uint8_t *)value); break; case UC_X86_REG_R13: + CHECK_REG_TYPE(uint64_t); env->regs[13] = *(uint64_t *)value; break; case UC_X86_REG_R13D: + CHECK_REG_TYPE(uint32_t); WRITE_DWORD(env->regs[13], *(uint32_t *)value); break; case UC_X86_REG_R13W: + CHECK_REG_TYPE(uint16_t); WRITE_WORD(env->regs[13], *(uint16_t *)value); break; case UC_X86_REG_R13B: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_L(env->regs[13], *(uint8_t *)value); break; case UC_X86_REG_R14: + CHECK_REG_TYPE(uint64_t); env->regs[14] = *(uint64_t *)value; break; case UC_X86_REG_R14D: + CHECK_REG_TYPE(uint32_t); WRITE_DWORD(env->regs[14], *(uint32_t *)value); break; case UC_X86_REG_R14W: + CHECK_REG_TYPE(uint16_t); WRITE_WORD(env->regs[14], *(uint16_t *)value); break; case UC_X86_REG_R14B: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_L(env->regs[14], *(uint8_t *)value); break; case UC_X86_REG_R15: + CHECK_REG_TYPE(uint64_t); env->regs[15] = *(uint64_t *)value; break; case UC_X86_REG_R15D: + CHECK_REG_TYPE(uint32_t); WRITE_DWORD(env->regs[15], *(uint32_t *)value); break; case UC_X86_REG_R15W: + CHECK_REG_TYPE(uint16_t); WRITE_WORD(env->regs[15], *(uint16_t *)value); break; case UC_X86_REG_R15B: + CHECK_REG_TYPE(uint8_t); WRITE_BYTE_L(env->regs[15], *(uint8_t *)value); break; case UC_X86_REG_IDTR: + CHECK_REG_TYPE(uc_x86_mmr); env->idt.limit = (uint16_t)((uc_x86_mmr *)value)->limit; env->idt.base = ((uc_x86_mmr *)value)->base; break; case UC_X86_REG_GDTR: + CHECK_REG_TYPE(uc_x86_mmr); env->gdt.limit = (uint16_t)((uc_x86_mmr *)value)->limit; env->gdt.base = ((uc_x86_mmr *)value)->base; break; case UC_X86_REG_LDTR: + CHECK_REG_TYPE(uc_x86_mmr); env->ldt.limit = ((uc_x86_mmr *)value)->limit; env->ldt.base = ((uc_x86_mmr *)value)->base; env->ldt.selector = (uint16_t)((uc_x86_mmr *)value)->selector; env->ldt.flags = ((uc_x86_mmr *)value)->flags; break; case UC_X86_REG_TR: + CHECK_REG_TYPE(uc_x86_mmr); env->tr.limit = ((uc_x86_mmr *)value)->limit; env->tr.base = ((uc_x86_mmr *)value)->base; env->tr.selector = (uint16_t)((uc_x86_mmr *)value)->selector; env->tr.flags = ((uc_x86_mmr *)value)->flags; break; case UC_X86_REG_MSR: + CHECK_REG_TYPE(uc_x86_msr); x86_msr_write(env, (uc_x86_msr *)value); break; case UC_X86_REG_MXCSR: + CHECK_REG_TYPE(uint32_t); cpu_set_mxcsr(env, *(uint32_t *)value); break; case UC_X86_REG_XMM8: @@ -1473,6 +1787,7 @@ write_cr64: case UC_X86_REG_XMM13: case UC_X86_REG_XMM14: case UC_X86_REG_XMM15: { + CHECK_REG_TYPE(float64[2]); float64 *src = (float64 *)value; ZMMReg *reg = (ZMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0]; reg->ZMM_Q(0) = src[0]; @@ -1480,9 +1795,11 @@ write_cr64: break; } case UC_X86_REG_FS_BASE: + CHECK_REG_TYPE(uint64_t); env->segs[R_FS].base = *(uint64_t *)value; return 0; case UC_X86_REG_GS_BASE: + CHECK_REG_TYPE(uint64_t); env->segs[R_GS].base = *(uint64_t *)value; return 0; } @@ -1490,107 +1807,7 @@ write_cr64: #endif } - return 0; -} - -int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count) -{ - CPUX86State *env = &(X86_CPU(uc->cpu)->env); - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - reg_read(env, regid, value, uc->mode); - } - - return 0; -} - -int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, - int count) -{ - CPUX86State *env = &(X86_CPU(uc->cpu)->env); - int i; - int ret; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - ret = reg_write(env, regid, value, uc->mode); - if (ret) { - return ret; - } - switch (uc->mode) { - default: - break; - case UC_MODE_32: - switch (regid) { - default: - break; - case UC_X86_REG_EIP: - case UC_X86_REG_IP: - // force to quit execution and flush TB - uc->quit_request = true; - break_translation_loop(uc); - break; - } - -#ifdef TARGET_X86_64 - case UC_MODE_64: - switch (regid) { - default: - break; - case UC_X86_REG_RIP: - case UC_X86_REG_EIP: - case UC_X86_REG_IP: - // force to quit execution and flush TB - uc->quit_request = true; - break_translation_loop(uc); - break; - } -#endif - } - } - - return 0; -} - -DEFAULT_VISIBILITY -int x86_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) -{ - CPUX86State *env = (CPUX86State *)ctx->data; - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - reg_read(env, regid, value, ctx->mode); - } - - return 0; -} - -DEFAULT_VISIBILITY -int x86_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) -{ - CPUX86State *env = (CPUX86State *)ctx->data; - int i; - int ret; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - ret = reg_write(env, regid, value, ctx->mode); - if (ret) { - return ret; - } - } - - return 0; + return ret; } static bool x86_stop_interrupt(struct uc_struct *uc, int intno) @@ -1650,11 +1867,11 @@ static int x86_cpus_init(struct uc_struct *uc, const char *cpu_model) } DEFAULT_VISIBILITY -void x86_uc_init(struct uc_struct *uc) +void uc_init(struct uc_struct *uc) { - uc->reg_read = x86_reg_read; - uc->reg_write = x86_reg_write; - uc->reg_reset = x86_reg_reset; + uc->reg_read = reg_read; + uc->reg_write = reg_write; + uc->reg_reset = reg_reset; uc->release = x86_release; uc->set_pc = x86_set_pc; uc->get_pc = x86_get_pc; diff --git a/qemu/target/i386/unicorn.h b/qemu/target/i386/unicorn.h index 7c456cfb..9927b6c9 100644 --- a/qemu/target/i386/unicorn.h +++ b/qemu/target/i386/unicorn.h @@ -6,16 +6,10 @@ #define UC_QEMU_TARGET_I386_H // functions to read & write registers -int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count); -int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, - int count); -int x86_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); -int x86_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); +uc_err reg_read_x86_64(void *env, int mode, unsigned int regid, void *value, + size_t *size); +uc_err reg_write_x86_64(void *env, int mode, unsigned int regid, + const void *value, size_t *size, int *setpc); -void x86_reg_reset(struct uc_struct *uc); - -void x86_uc_init(struct uc_struct *uc); +void uc_init_x86_64(struct uc_struct *uc); #endif diff --git a/qemu/target/m68k/unicorn.c b/qemu/target/m68k/unicorn.c index d0a091fa..f1efd66e 100644 --- a/qemu/target/m68k/unicorn.c +++ b/qemu/target/m68k/unicorn.c @@ -39,7 +39,7 @@ static void m68k_release(void *ctx) } } -void m68k_reg_reset(struct uc_struct *uc) +static void reg_reset(struct uc_struct *uc) { CPUArchState *env = uc->cpu->env_ptr; @@ -49,111 +49,67 @@ void m68k_reg_reset(struct uc_struct *uc) env->pc = 0; } -static void reg_read(CPUM68KState *env, unsigned int regid, void *value) +DEFAULT_VISIBILITY +uc_err reg_read(void *_env, int mode, unsigned int regid, void *value, + size_t *size) { - if (regid >= UC_M68K_REG_A0 && regid <= UC_M68K_REG_A7) - *(int32_t *)value = env->aregs[regid - UC_M68K_REG_A0]; - else if (regid >= UC_M68K_REG_D0 && regid <= UC_M68K_REG_D7) - *(int32_t *)value = env->dregs[regid - UC_M68K_REG_D0]; - else { + CPUM68KState *env = _env; + uc_err ret = UC_ERR_ARG; + + if (regid >= UC_M68K_REG_A0 && regid <= UC_M68K_REG_A7) { + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->aregs[regid - UC_M68K_REG_A0]; + } else if (regid >= UC_M68K_REG_D0 && regid <= UC_M68K_REG_D7) { + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->dregs[regid - UC_M68K_REG_D0]; + } else { switch (regid) { default: break; case UC_M68K_REG_PC: - *(int32_t *)value = env->pc; + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->pc; break; case UC_M68K_REG_SR: - *(int32_t *)value = env->sr; + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->sr; break; } } + + return ret; } -static void reg_write(CPUM68KState *env, unsigned int regid, const void *value) +DEFAULT_VISIBILITY +uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc) { - if (regid >= UC_M68K_REG_A0 && regid <= UC_M68K_REG_A7) + CPUM68KState *env = _env; + uc_err ret = UC_ERR_ARG; + + if (regid >= UC_M68K_REG_A0 && regid <= UC_M68K_REG_A7) { + CHECK_REG_TYPE(uint32_t); env->aregs[regid - UC_M68K_REG_A0] = *(uint32_t *)value; - else if (regid >= UC_M68K_REG_D0 && regid <= UC_M68K_REG_D7) + } else if (regid >= UC_M68K_REG_D0 && regid <= UC_M68K_REG_D7) { + CHECK_REG_TYPE(uint32_t); env->dregs[regid - UC_M68K_REG_D0] = *(uint32_t *)value; - else { + } else { switch (regid) { default: break; case UC_M68K_REG_PC: + CHECK_REG_TYPE(uint32_t); env->pc = *(uint32_t *)value; + *setpc = 1; break; case UC_M68K_REG_SR: + CHECK_REG_TYPE(uint32_t); cpu_m68k_set_sr(env, *(uint32_t *)value); break; } } -} -int m68k_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count) -{ - CPUM68KState *env = &(M68K_CPU(uc->cpu)->env); - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - reg_read(env, regid, value); - } - - return 0; -} - -int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, - int count) -{ - CPUM68KState *env = &(M68K_CPU(uc->cpu)->env); - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - reg_write(env, regid, value); - if (regid == UC_M68K_REG_PC) { - // force to quit execution and flush TB - uc->quit_request = true; - break_translation_loop(uc); - } - } - - return 0; -} - -DEFAULT_VISIBILITY -int m68k_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) -{ - CPUM68KState *env = (CPUM68KState *)ctx->data; - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - reg_read(env, regid, value); - } - - return 0; -} - -DEFAULT_VISIBILITY -int m68k_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) -{ - CPUM68KState *env = (CPUM68KState *)ctx->data; - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - reg_write(env, regid, value); - } - - return 0; + return ret; } static int m68k_cpus_init(struct uc_struct *uc, const char *cpu_model) @@ -168,12 +124,12 @@ static int m68k_cpus_init(struct uc_struct *uc, const char *cpu_model) } DEFAULT_VISIBILITY -void m68k_uc_init(struct uc_struct *uc) +void uc_init(struct uc_struct *uc) { uc->release = m68k_release; - uc->reg_read = m68k_reg_read; - uc->reg_write = m68k_reg_write; - uc->reg_reset = m68k_reg_reset; + uc->reg_read = reg_read; + uc->reg_write = reg_write; + uc->reg_reset = reg_reset; uc->set_pc = m68k_set_pc; uc->get_pc = m68k_get_pc; uc->cpus_init = m68k_cpus_init; diff --git a/qemu/target/m68k/unicorn.h b/qemu/target/m68k/unicorn.h index ebd5c310..c81ad48e 100644 --- a/qemu/target/m68k/unicorn.h +++ b/qemu/target/m68k/unicorn.h @@ -5,16 +5,10 @@ #define UC_QEMU_TARGET_M68K_H // functions to read & write registers -int m68k_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count); -int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, - int count); -int m68k_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); -int m68k_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); +uc_err reg_read_m68k(void *env, int mode, unsigned int regid, void *value, + size_t *size); +uc_err reg_write_m68k(void *env, int mode, unsigned int regid, + const void *value, size_t *size, int *setpc); -void m68k_reg_reset(struct uc_struct *uc); - -void m68k_uc_init(struct uc_struct *uc); +void uc_init_m68k(struct uc_struct *uc); #endif diff --git a/qemu/target/mips/unicorn.c b/qemu/target/mips/unicorn.c index fb91e9c1..77a7d48d 100644 --- a/qemu/target/mips/unicorn.c +++ b/qemu/target/mips/unicorn.c @@ -49,7 +49,7 @@ static void mips_release(void *ctx) g_free(cpu->env.tlb); } -void mips_reg_reset(struct uc_struct *uc) +static void reg_reset(struct uc_struct *uc) { CPUArchState *env; (void)uc; @@ -59,169 +59,97 @@ void mips_reg_reset(struct uc_struct *uc) env->active_tc.PC = 0; } -static void reg_read(CPUMIPSState *env, unsigned int regid, void *value) +DEFAULT_VISIBILITY +uc_err reg_read(void *_env, int mode, unsigned int regid, void *value, + size_t *size) { - if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31) + CPUMIPSState *env = _env; + uc_err ret = UC_ERR_ARG; + + if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31) { + CHECK_REG_TYPE(mipsreg_t); *(mipsreg_t *)value = env->active_tc.gpr[regid - UC_MIPS_REG_0]; - else { + } else { switch (regid) { default: break; case UC_MIPS_REG_HI: + CHECK_REG_TYPE(mipsreg_t); *(mipsreg_t *)value = env->active_tc.HI[0]; break; case UC_MIPS_REG_LO: + CHECK_REG_TYPE(mipsreg_t); *(mipsreg_t *)value = env->active_tc.LO[0]; break; case UC_MIPS_REG_PC: + CHECK_REG_TYPE(mipsreg_t); *(mipsreg_t *)value = env->active_tc.PC; break; case UC_MIPS_REG_CP0_CONFIG3: + CHECK_REG_TYPE(mipsreg_t); *(mipsreg_t *)value = env->CP0_Config3; break; case UC_MIPS_REG_CP0_STATUS: + CHECK_REG_TYPE(mipsreg_t); *(mipsreg_t *)value = env->CP0_Status; break; case UC_MIPS_REG_CP0_USERLOCAL: + CHECK_REG_TYPE(mipsreg_t); *(mipsreg_t *)value = env->active_tc.CP0_UserLocal; break; } } - return; + return ret; } -static void reg_write(CPUMIPSState *env, unsigned int regid, const void *value) +DEFAULT_VISIBILITY +uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc) { - if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31) + CPUMIPSState *env = _env; + uc_err ret = UC_ERR_ARG; + + if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31) { + CHECK_REG_TYPE(mipsreg_t); env->active_tc.gpr[regid - UC_MIPS_REG_0] = *(mipsreg_t *)value; - else { + } else { switch (regid) { default: break; case UC_MIPS_REG_HI: + CHECK_REG_TYPE(mipsreg_t); env->active_tc.HI[0] = *(mipsreg_t *)value; break; case UC_MIPS_REG_LO: + CHECK_REG_TYPE(mipsreg_t); env->active_tc.LO[0] = *(mipsreg_t *)value; break; case UC_MIPS_REG_PC: + CHECK_REG_TYPE(mipsreg_t); env->active_tc.PC = *(mipsreg_t *)value; + *setpc = 1; break; case UC_MIPS_REG_CP0_CONFIG3: + CHECK_REG_TYPE(mipsreg_t); env->CP0_Config3 = *(mipsreg_t *)value; break; case UC_MIPS_REG_CP0_STATUS: // TODO: ALL CP0 REGS // https://s3-eu-west-1.amazonaws.com/downloads-mips/documents/MD00090-2B-MIPS32PRA-AFP-06.02.pdf // https://s3-eu-west-1.amazonaws.com/downloads-mips/documents/MD00582-2B-microMIPS32-AFP-05.04.pdf + CHECK_REG_TYPE(mipsreg_t); env->CP0_Status = *(mipsreg_t *)value; compute_hflags(env); break; case UC_MIPS_REG_CP0_USERLOCAL: + CHECK_REG_TYPE(mipsreg_t); env->active_tc.CP0_UserLocal = *(mipsreg_t *)value; break; } } - return; -} - -int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count) -{ - CPUMIPSState *env = &(MIPS_CPU(uc->cpu)->env); - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - reg_read(env, regid, value); - } - - return 0; -} - -int mips_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, - int count) -{ - CPUMIPSState *env = &(MIPS_CPU(uc->cpu)->env); - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - reg_write(env, regid, value); - if (regid == UC_MIPS_REG_PC) { - // force to quit execution and flush TB - uc->quit_request = true; - break_translation_loop(uc); - } - } - - return 0; -} - -DEFAULT_VISIBILITY -#ifdef TARGET_MIPS64 -#ifdef TARGET_WORDS_BIGENDIAN -int mips64_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) -#else -int mips64el_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) -#endif -#else // if TARGET_MIPS -#ifdef TARGET_WORDS_BIGENDIAN -int mips_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) -#else -int mipsel_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) -#endif -#endif -{ - CPUMIPSState *env = (CPUMIPSState *)ctx->data; - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - reg_read(env, regid, value); - } - - return 0; -} - -DEFAULT_VISIBILITY -#ifdef TARGET_MIPS64 -#ifdef TARGET_WORDS_BIGENDIAN -int mips64_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) -#else -int mips64el_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) -#endif -#else // if TARGET_MIPS -#ifdef TARGET_WORDS_BIGENDIAN -int mips_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) -#else -int mipsel_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) -#endif -#endif -{ - CPUMIPSState *env = (CPUMIPSState *)ctx->data; - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - reg_write(env, regid, value); - } - - return 0; + return ret; } static int mips_cpus_init(struct uc_struct *uc, const char *cpu_model) @@ -237,23 +165,11 @@ static int mips_cpus_init(struct uc_struct *uc, const char *cpu_model) } DEFAULT_VISIBILITY -#ifdef TARGET_MIPS64 -#ifdef TARGET_WORDS_BIGENDIAN -void mips64_uc_init(struct uc_struct *uc) -#else -void mips64el_uc_init(struct uc_struct *uc) -#endif -#else // if TARGET_MIPS -#ifdef TARGET_WORDS_BIGENDIAN -void mips_uc_init(struct uc_struct *uc) -#else -void mipsel_uc_init(struct uc_struct *uc) -#endif -#endif +void uc_init(struct uc_struct *uc) { - uc->reg_read = mips_reg_read; - uc->reg_write = mips_reg_write; - uc->reg_reset = mips_reg_reset; + uc->reg_read = reg_read; + uc->reg_write = reg_write; + uc->reg_reset = reg_reset; uc->release = mips_release; uc->set_pc = mips_set_pc; uc->get_pc = mips_get_pc; diff --git a/qemu/target/mips/unicorn.h b/qemu/target/mips/unicorn.h index 5a806522..f089e5df 100644 --- a/qemu/target/mips/unicorn.h +++ b/qemu/target/mips/unicorn.h @@ -5,32 +5,26 @@ #define UC_QEMU_TARGET_MIPS_H // functions to read & write registers -int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count); -int mips_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, - int count); +uc_err reg_read_mips(void *env, int mode, unsigned int regid, void *value, + size_t *size); +uc_err reg_read_mipsel(void *env, int mode, unsigned int regid, void *value, + size_t *size); +uc_err reg_read_mips64(void *env, int mode, unsigned int regid, void *value, + size_t *size); +uc_err reg_read_mips64el(void *env, int mode, unsigned int regid, void *value, + size_t *size); -int mips_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); -int mips_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); -int mipsel_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); -int mipsel_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); -int mips64_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); -int mips64_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); -int mips64el_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); -int mips64el_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); +uc_err reg_write_mips(void *env, int mode, unsigned int regid, + const void *value, size_t *size, int *setpc); +uc_err reg_write_mipsel(void *env, int mode, unsigned int regid, + const void *value, size_t *size, int *setpc); +uc_err reg_write_mips64(void *env, int mode, unsigned int regid, + const void *value, size_t *size, int *setpc); +uc_err reg_write_mips64el(void *env, int mode, unsigned int regid, + const void *value, size_t *size, int *setpc); -void mips_reg_reset(struct uc_struct *uc); - -void mips_uc_init(struct uc_struct *uc); -void mipsel_uc_init(struct uc_struct *uc); -void mips64_uc_init(struct uc_struct *uc); -void mips64el_uc_init(struct uc_struct *uc); +void uc_init_mips(struct uc_struct *uc); +void uc_init_mipsel(struct uc_struct *uc); +void uc_init_mips64(struct uc_struct *uc); +void uc_init_mips64el(struct uc_struct *uc); #endif diff --git a/qemu/target/ppc/unicorn.c b/qemu/target/ppc/unicorn.c index b3e75f7d..ce86cf93 100644 --- a/qemu/target/ppc/unicorn.c +++ b/qemu/target/ppc/unicorn.c @@ -136,7 +136,7 @@ static void ppc_release(void *ctx) ppc_cpu_unrealize(tcg_ctx->uc->cpu); } -void ppc_reg_reset(struct uc_struct *uc) +static void reg_reset(struct uc_struct *uc) { CPUArchState *env; env = uc->cpu->env_ptr; @@ -146,253 +146,126 @@ void ppc_reg_reset(struct uc_struct *uc) } // http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Motorola_PowerPC/PowerPc/GenInfo/pemch2.pdf -static void reg_read(CPUPPCState *env, unsigned int regid, void *value) +DEFAULT_VISIBILITY +uc_err reg_read(void *_env, int mode, unsigned int regid, void *value, + size_t *size) { - uint32_t val; + CPUPPCState *env = _env; + uc_err ret = UC_ERR_ARG; - if (regid >= UC_PPC_REG_0 && regid <= UC_PPC_REG_31) + if (regid >= UC_PPC_REG_0 && regid <= UC_PPC_REG_31) { + CHECK_REG_TYPE(ppcreg_t); *(ppcreg_t *)value = env->gpr[regid - UC_PPC_REG_0]; - else { + } else if (regid >= UC_PPC_REG_FPR0 && regid <= UC_PPC_REG_FPR31) { + CHECK_REG_TYPE(uint64_t); + *(uint64_t *)value = env->vsr[regid - UC_PPC_REG_FPR0].VsrD(0); + } else if (regid >= UC_PPC_REG_CR0 && regid <= UC_PPC_REG_CR7) { + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->crf[regid - UC_PPC_REG_CR0]; + } else { switch (regid) { default: break; case UC_PPC_REG_PC: + CHECK_REG_TYPE(ppcreg_t); *(ppcreg_t *)value = env->nip; break; - case UC_PPC_REG_FPR0: - case UC_PPC_REG_FPR1: - case UC_PPC_REG_FPR2: - case UC_PPC_REG_FPR3: - case UC_PPC_REG_FPR4: - case UC_PPC_REG_FPR5: - case UC_PPC_REG_FPR6: - case UC_PPC_REG_FPR7: - case UC_PPC_REG_FPR8: - case UC_PPC_REG_FPR9: - case UC_PPC_REG_FPR10: - case UC_PPC_REG_FPR11: - case UC_PPC_REG_FPR12: - case UC_PPC_REG_FPR13: - case UC_PPC_REG_FPR14: - case UC_PPC_REG_FPR15: - case UC_PPC_REG_FPR16: - case UC_PPC_REG_FPR17: - case UC_PPC_REG_FPR18: - case UC_PPC_REG_FPR19: - case UC_PPC_REG_FPR20: - case UC_PPC_REG_FPR21: - case UC_PPC_REG_FPR22: - case UC_PPC_REG_FPR23: - case UC_PPC_REG_FPR24: - case UC_PPC_REG_FPR25: - case UC_PPC_REG_FPR26: - case UC_PPC_REG_FPR27: - case UC_PPC_REG_FPR28: - case UC_PPC_REG_FPR29: - case UC_PPC_REG_FPR30: - case UC_PPC_REG_FPR31: - *(uint64_t *)value = env->vsr[regid - UC_PPC_REG_FPR0].VsrD(0); - break; - case UC_PPC_REG_CR0: - case UC_PPC_REG_CR1: - case UC_PPC_REG_CR2: - case UC_PPC_REG_CR3: - case UC_PPC_REG_CR4: - case UC_PPC_REG_CR5: - case UC_PPC_REG_CR6: - case UC_PPC_REG_CR7: - *(uint32_t *)value = env->crf[regid - UC_PPC_REG_CR0]; - break; - case UC_PPC_REG_CR: - val = 0; - for (int i = 0; i < 8; i++) { + case UC_PPC_REG_CR: { + CHECK_REG_TYPE(uint32_t); + int i; + uint32_t val = 0; + for (i = 0; i < 8; i++) { val <<= 4; val |= env->crf[i]; } *(uint32_t *)value = val; break; + } case UC_PPC_REG_LR: + CHECK_REG_TYPE(ppcreg_t); *(ppcreg_t *)value = env->lr; break; case UC_PPC_REG_CTR: + CHECK_REG_TYPE(ppcreg_t); *(ppcreg_t *)value = env->ctr; break; case UC_PPC_REG_MSR: + CHECK_REG_TYPE(ppcreg_t); *(ppcreg_t *)value = env->msr; break; case UC_PPC_REG_XER: + CHECK_REG_TYPE(uint32_t); *(uint32_t *)value = env->xer; break; case UC_PPC_REG_FPSCR: + CHECK_REG_TYPE(uint32_t); *(uint32_t *)value = env->fpscr; break; } } - return; + return ret; } -static void reg_write(CPUPPCState *env, unsigned int regid, const void *value) +DEFAULT_VISIBILITY +uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc) { - uint32_t val; - int i; + CPUPPCState *env = _env; + uc_err ret = UC_ERR_ARG; - if (regid >= UC_PPC_REG_0 && regid <= UC_PPC_REG_31) + if (regid >= UC_PPC_REG_0 && regid <= UC_PPC_REG_31) { + CHECK_REG_TYPE(ppcreg_t); env->gpr[regid - UC_PPC_REG_0] = *(ppcreg_t *)value; - else { + } else if (regid >= UC_PPC_REG_FPR0 && regid <= UC_PPC_REG_FPR31) { + CHECK_REG_TYPE(uint64_t); + env->vsr[regid - UC_PPC_REG_FPR0].VsrD(0) = *(uint64_t *)value; + } else if (regid >= UC_PPC_REG_CR0 && regid <= UC_PPC_REG_CR7) { + CHECK_REG_TYPE(uint32_t); + env->crf[regid - UC_PPC_REG_CR0] = (*(uint32_t *)value) & 0b1111; + } else { switch (regid) { default: break; case UC_PPC_REG_PC: + CHECK_REG_TYPE(ppcreg_t); env->nip = *(ppcreg_t *)value; + *setpc = 1; break; - case UC_PPC_REG_FPR0: - case UC_PPC_REG_FPR1: - case UC_PPC_REG_FPR2: - case UC_PPC_REG_FPR3: - case UC_PPC_REG_FPR4: - case UC_PPC_REG_FPR5: - case UC_PPC_REG_FPR6: - case UC_PPC_REG_FPR7: - case UC_PPC_REG_FPR8: - case UC_PPC_REG_FPR9: - case UC_PPC_REG_FPR10: - case UC_PPC_REG_FPR11: - case UC_PPC_REG_FPR12: - case UC_PPC_REG_FPR13: - case UC_PPC_REG_FPR14: - case UC_PPC_REG_FPR15: - case UC_PPC_REG_FPR16: - case UC_PPC_REG_FPR17: - case UC_PPC_REG_FPR18: - case UC_PPC_REG_FPR19: - case UC_PPC_REG_FPR20: - case UC_PPC_REG_FPR21: - case UC_PPC_REG_FPR22: - case UC_PPC_REG_FPR23: - case UC_PPC_REG_FPR24: - case UC_PPC_REG_FPR25: - case UC_PPC_REG_FPR26: - case UC_PPC_REG_FPR27: - case UC_PPC_REG_FPR28: - case UC_PPC_REG_FPR29: - case UC_PPC_REG_FPR30: - case UC_PPC_REG_FPR31: - env->vsr[regid - UC_PPC_REG_FPR0].VsrD(0) = *(uint64_t *)value; - break; - case UC_PPC_REG_CR0: - case UC_PPC_REG_CR1: - case UC_PPC_REG_CR2: - case UC_PPC_REG_CR3: - case UC_PPC_REG_CR4: - case UC_PPC_REG_CR5: - case UC_PPC_REG_CR6: - case UC_PPC_REG_CR7: - env->crf[regid - UC_PPC_REG_CR0] = (*(uint32_t *)value) & 0b1111; - break; - case UC_PPC_REG_CR: - val = *(uint32_t *)value; + case UC_PPC_REG_CR: { + CHECK_REG_TYPE(uint32_t); + int i; + uint32_t val = *(uint32_t *)value; for (i = 7; i >= 0; i--) { env->crf[i] = val & 0b1111; val >>= 4; } break; + } case UC_PPC_REG_LR: + CHECK_REG_TYPE(ppcreg_t); env->lr = *(ppcreg_t *)value; break; case UC_PPC_REG_CTR: + CHECK_REG_TYPE(ppcreg_t); env->ctr = *(ppcreg_t *)value; break; case UC_PPC_REG_MSR: + CHECK_REG_TYPE(ppcreg_t); uc_ppc_store_msr(env, *(ppcreg_t *)value, 0); break; case UC_PPC_REG_XER: + CHECK_REG_TYPE(uint32_t); env->xer = *(uint32_t *)value; break; case UC_PPC_REG_FPSCR: + CHECK_REG_TYPE(uint32_t); store_fpscr(env, *(uint32_t *)value, 0xffffffff); break; } } - return; -} - -int ppc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count) -{ - CPUPPCState *env = &(POWERPC_CPU(uc->cpu)->env); - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - reg_read(env, regid, value); - } - - return 0; -} - -int ppc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, - int count) -{ - CPUPPCState *env = &(POWERPC_CPU(uc->cpu)->env); - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - reg_write(env, regid, value); - if (regid == UC_PPC_REG_PC) { - // force to quit execution and flush TB - uc->quit_request = true; - break_translation_loop(uc); - } - } - - return 0; -} - -DEFAULT_VISIBILITY -#ifdef TARGET_PPC64 -int ppc64_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) -#else -int ppc_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) -#endif -{ - CPUPPCState *env = (CPUPPCState *)ctx->data; - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - reg_read(env, regid, value); - } - - return 0; -} - -DEFAULT_VISIBILITY -#ifdef TARGET_PPC64 -int ppc64_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) -#else -int ppc_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) -#endif -{ - CPUPPCState *env = (CPUPPCState *)ctx->data; - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - reg_write(env, regid, value); - } - - return 0; + return ret; } PowerPCCPU *cpu_ppc_init(struct uc_struct *uc); @@ -408,15 +281,11 @@ static int ppc_cpus_init(struct uc_struct *uc, const char *cpu_model) } DEFAULT_VISIBILITY -#ifdef TARGET_PPC64 -void ppc64_uc_init(struct uc_struct *uc) -#else -void ppc_uc_init(struct uc_struct *uc) -#endif +void uc_init(struct uc_struct *uc) { - uc->reg_read = ppc_reg_read; - uc->reg_write = ppc_reg_write; - uc->reg_reset = ppc_reg_reset; + uc->reg_read = reg_read; + uc->reg_write = reg_write; + uc->reg_reset = reg_reset; uc->release = ppc_release; uc->set_pc = ppc_set_pc; uc->get_pc = ppc_get_pc; diff --git a/qemu/target/ppc/unicorn.h b/qemu/target/ppc/unicorn.h index 2afaa3a0..d6d47ad7 100644 --- a/qemu/target/ppc/unicorn.h +++ b/qemu/target/ppc/unicorn.h @@ -5,22 +5,15 @@ #define UC_QEMU_TARGET_PPC_H // functions to read & write registers -int ppc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count); -int ppc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, - int count); +uc_err reg_read_ppc(void *env, int mode, unsigned int regid, void *value, + size_t *size); +uc_err reg_read_ppc64(void *env, int mode, unsigned int regid, void *value, + size_t *size); +uc_err reg_write_ppc(void *env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc); +uc_err reg_write_ppc64(void *env, int mode, unsigned int regid, + const void *value, size_t *size, int *setpc); -int ppc_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); -int ppc_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); -int ppc64_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); -int ppc64_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); - -void ppc_reg_reset(struct uc_struct *uc); - -void ppc_uc_init(struct uc_struct *uc); -void ppc64_uc_init(struct uc_struct *uc); +void uc_init_ppc(struct uc_struct *uc); +void uc_init_ppc64(struct uc_struct *uc); #endif diff --git a/qemu/target/riscv/unicorn.c b/qemu/target/riscv/unicorn.c index 8970051e..8b55282f 100644 --- a/qemu/target/riscv/unicorn.c +++ b/qemu/target/riscv/unicorn.c @@ -44,6 +44,7 @@ static int csrno_map[] = { CSR_HIP, CSR_HTINST, CSR_HGATP, CSR_HTIMEDELTA, CSR_HTIMEDELTAH, }; +#define csrno_count (sizeof(csrno_map) / sizeof(int)) RISCVCPU *cpu_riscv_init(struct uc_struct *uc); @@ -76,539 +77,106 @@ static void riscv_release(void *ctx) } } -void riscv_reg_reset(struct uc_struct *uc) {} +static void reg_reset(struct uc_struct *uc) {} -static void reg_read(CPURISCVState *env, unsigned int regid, void *value) +DEFAULT_VISIBILITY +uc_err reg_read(void *_env, int mode, unsigned int regid, void *value, + size_t *size) { - switch (regid) { - case UC_RISCV_REG_X0: - case UC_RISCV_REG_X1: - case UC_RISCV_REG_X2: - case UC_RISCV_REG_X3: - case UC_RISCV_REG_X4: - case UC_RISCV_REG_X5: - case UC_RISCV_REG_X6: - case UC_RISCV_REG_X7: - case UC_RISCV_REG_X8: - case UC_RISCV_REG_X9: - case UC_RISCV_REG_X10: - case UC_RISCV_REG_X11: - case UC_RISCV_REG_X12: - case UC_RISCV_REG_X13: - case UC_RISCV_REG_X14: - case UC_RISCV_REG_X15: - case UC_RISCV_REG_X16: - case UC_RISCV_REG_X17: - case UC_RISCV_REG_X18: - case UC_RISCV_REG_X19: - case UC_RISCV_REG_X20: - case UC_RISCV_REG_X21: - case UC_RISCV_REG_X22: - case UC_RISCV_REG_X23: - case UC_RISCV_REG_X24: - case UC_RISCV_REG_X25: - case UC_RISCV_REG_X26: - case UC_RISCV_REG_X27: - case UC_RISCV_REG_X28: - case UC_RISCV_REG_X29: - case UC_RISCV_REG_X30: - case UC_RISCV_REG_X31: -#ifdef TARGET_RISCV64 - *(int64_t *)value = env->gpr[regid - UC_RISCV_REG_X0]; -#else - *(int32_t *)value = env->gpr[regid - UC_RISCV_REG_X0]; -#endif - break; - case UC_RISCV_REG_PC: -#ifdef TARGET_RISCV64 - *(int64_t *)value = env->pc; -#else - *(int32_t *)value = env->pc; -#endif - break; + CPURISCVState *env = _env; + uc_err ret = UC_ERR_ARG; - case UC_RISCV_REG_F0: // "ft0" - case UC_RISCV_REG_F1: // "ft1" - case UC_RISCV_REG_F2: // "ft2" - case UC_RISCV_REG_F3: // "ft3" - case UC_RISCV_REG_F4: // "ft4" - case UC_RISCV_REG_F5: // "ft5" - case UC_RISCV_REG_F6: // "ft6" - case UC_RISCV_REG_F7: // "ft7" - case UC_RISCV_REG_F8: // "fs0" - case UC_RISCV_REG_F9: // "fs1" - case UC_RISCV_REG_F10: // "fa0" - case UC_RISCV_REG_F11: // "fa1" - case UC_RISCV_REG_F12: // "fa2" - case UC_RISCV_REG_F13: // "fa3" - case UC_RISCV_REG_F14: // "fa4" - case UC_RISCV_REG_F15: // "fa5" - case UC_RISCV_REG_F16: // "fa6" - case UC_RISCV_REG_F17: // "fa7" - case UC_RISCV_REG_F18: // "fs2" - case UC_RISCV_REG_F19: // "fs3" - case UC_RISCV_REG_F20: // "fs4" - case UC_RISCV_REG_F21: // "fs5" - case UC_RISCV_REG_F22: // "fs6" - case UC_RISCV_REG_F23: // "fs7" - case UC_RISCV_REG_F24: // "fs8" - case UC_RISCV_REG_F25: // "fs9" - case UC_RISCV_REG_F26: // "fs10" - case UC_RISCV_REG_F27: // "fs11" - case UC_RISCV_REG_F28: // "ft8" - case UC_RISCV_REG_F29: // "ft9" - case UC_RISCV_REG_F30: // "ft10" - case UC_RISCV_REG_F31: // "ft11" + if (regid >= UC_RISCV_REG_X0 && regid <= UC_RISCV_REG_X31) { #ifdef TARGET_RISCV64 - *(int64_t *)value = env->fpr[regid - UC_RISCV_REG_F0]; + CHECK_REG_TYPE(uint64_t); + *(uint64_t *)value = env->gpr[regid - UC_RISCV_REG_X0]; #else - *(int32_t *)value = env->fpr[regid - UC_RISCV_REG_F0]; + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->gpr[regid - UC_RISCV_REG_X0]; #endif - break; - case UC_RISCV_REG_USTATUS: - case UC_RISCV_REG_UIE: - case UC_RISCV_REG_UTVEC: - case UC_RISCV_REG_USCRATCH: - case UC_RISCV_REG_UEPC: - case UC_RISCV_REG_UCAUSE: - case UC_RISCV_REG_UTVAL: - case UC_RISCV_REG_UIP: - case UC_RISCV_REG_FFLAGS: - case UC_RISCV_REG_FRM: - case UC_RISCV_REG_FCSR: - case UC_RISCV_REG_CYCLE: - case UC_RISCV_REG_TIME: - case UC_RISCV_REG_INSTRET: - case UC_RISCV_REG_HPMCOUNTER3: - case UC_RISCV_REG_HPMCOUNTER4: - case UC_RISCV_REG_HPMCOUNTER5: - case UC_RISCV_REG_HPMCOUNTER6: - case UC_RISCV_REG_HPMCOUNTER7: - case UC_RISCV_REG_HPMCOUNTER8: - case UC_RISCV_REG_HPMCOUNTER9: - case UC_RISCV_REG_HPMCOUNTER10: - case UC_RISCV_REG_HPMCOUNTER11: - case UC_RISCV_REG_HPMCOUNTER12: - case UC_RISCV_REG_HPMCOUNTER13: - case UC_RISCV_REG_HPMCOUNTER14: - case UC_RISCV_REG_HPMCOUNTER15: - case UC_RISCV_REG_HPMCOUNTER16: - case UC_RISCV_REG_HPMCOUNTER17: - case UC_RISCV_REG_HPMCOUNTER18: - case UC_RISCV_REG_HPMCOUNTER19: - case UC_RISCV_REG_HPMCOUNTER20: - case UC_RISCV_REG_HPMCOUNTER21: - case UC_RISCV_REG_HPMCOUNTER22: - case UC_RISCV_REG_HPMCOUNTER23: - case UC_RISCV_REG_HPMCOUNTER24: - case UC_RISCV_REG_HPMCOUNTER25: - case UC_RISCV_REG_HPMCOUNTER26: - case UC_RISCV_REG_HPMCOUNTER27: - case UC_RISCV_REG_HPMCOUNTER28: - case UC_RISCV_REG_HPMCOUNTER29: - case UC_RISCV_REG_HPMCOUNTER30: - case UC_RISCV_REG_HPMCOUNTER31: - case UC_RISCV_REG_CYCLEH: - case UC_RISCV_REG_TIMEH: - case UC_RISCV_REG_INSTRETH: - case UC_RISCV_REG_HPMCOUNTER3H: - case UC_RISCV_REG_HPMCOUNTER4H: - case UC_RISCV_REG_HPMCOUNTER5H: - case UC_RISCV_REG_HPMCOUNTER6H: - case UC_RISCV_REG_HPMCOUNTER7H: - case UC_RISCV_REG_HPMCOUNTER8H: - case UC_RISCV_REG_HPMCOUNTER9H: - case UC_RISCV_REG_HPMCOUNTER10H: - case UC_RISCV_REG_HPMCOUNTER11H: - case UC_RISCV_REG_HPMCOUNTER12H: - case UC_RISCV_REG_HPMCOUNTER13H: - case UC_RISCV_REG_HPMCOUNTER14H: - case UC_RISCV_REG_HPMCOUNTER15H: - case UC_RISCV_REG_HPMCOUNTER16H: - case UC_RISCV_REG_HPMCOUNTER17H: - case UC_RISCV_REG_HPMCOUNTER18H: - case UC_RISCV_REG_HPMCOUNTER19H: - case UC_RISCV_REG_HPMCOUNTER20H: - case UC_RISCV_REG_HPMCOUNTER21H: - case UC_RISCV_REG_HPMCOUNTER22H: - case UC_RISCV_REG_HPMCOUNTER23H: - case UC_RISCV_REG_HPMCOUNTER24H: - case UC_RISCV_REG_HPMCOUNTER25H: - case UC_RISCV_REG_HPMCOUNTER26H: - case UC_RISCV_REG_HPMCOUNTER27H: - case UC_RISCV_REG_HPMCOUNTER28H: - case UC_RISCV_REG_HPMCOUNTER29H: - case UC_RISCV_REG_HPMCOUNTER30H: - case UC_RISCV_REG_HPMCOUNTER31H: - case UC_RISCV_REG_MCYCLE: - case UC_RISCV_REG_MINSTRET: - case UC_RISCV_REG_MCYCLEH: - case UC_RISCV_REG_MINSTRETH: - case UC_RISCV_REG_MVENDORID: - case UC_RISCV_REG_MARCHID: - case UC_RISCV_REG_MIMPID: - case UC_RISCV_REG_MHARTID: - case UC_RISCV_REG_MSTATUS: - case UC_RISCV_REG_MISA: - case UC_RISCV_REG_MEDELEG: - case UC_RISCV_REG_MIDELEG: - case UC_RISCV_REG_MIE: - case UC_RISCV_REG_MTVEC: - case UC_RISCV_REG_MCOUNTEREN: - case UC_RISCV_REG_MSTATUSH: - case UC_RISCV_REG_MUCOUNTEREN: - case UC_RISCV_REG_MSCOUNTEREN: - case UC_RISCV_REG_MHCOUNTEREN: - case UC_RISCV_REG_MSCRATCH: - case UC_RISCV_REG_MEPC: - case UC_RISCV_REG_MCAUSE: - case UC_RISCV_REG_MTVAL: - case UC_RISCV_REG_MIP: - case UC_RISCV_REG_MBADADDR: - case UC_RISCV_REG_SSTATUS: - case UC_RISCV_REG_SEDELEG: - case UC_RISCV_REG_SIDELEG: - case UC_RISCV_REG_SIE: - case UC_RISCV_REG_STVEC: - case UC_RISCV_REG_SCOUNTEREN: - case UC_RISCV_REG_SSCRATCH: - case UC_RISCV_REG_SEPC: - case UC_RISCV_REG_SCAUSE: - case UC_RISCV_REG_STVAL: - case UC_RISCV_REG_SIP: - case UC_RISCV_REG_SBADADDR: - case UC_RISCV_REG_SPTBR: - case UC_RISCV_REG_SATP: - case UC_RISCV_REG_HSTATUS: - case UC_RISCV_REG_HEDELEG: - case UC_RISCV_REG_HIDELEG: - case UC_RISCV_REG_HIE: - case UC_RISCV_REG_HCOUNTEREN: - case UC_RISCV_REG_HTVAL: - case UC_RISCV_REG_HIP: - case UC_RISCV_REG_HTINST: - case UC_RISCV_REG_HGATP: - case UC_RISCV_REG_HTIMEDELTA: - case UC_RISCV_REG_HTIMEDELTAH: { + } else if (regid >= UC_RISCV_REG_F0 && + regid <= UC_RISCV_REG_F31) { // "ft0".."ft31" + CHECK_REG_TYPE(uint64_t); + *(uint64_t *)value = env->fpr[regid - UC_RISCV_REG_F0]; + } else if (regid >= UC_RISCV_REG_USTATUS && + regid < UC_RISCV_REG_USTATUS + csrno_count) { target_ulong val; int csrno = csrno_map[regid - UC_RISCV_REG_USTATUS]; riscv_csrrw(env, csrno, &val, -1, 0); #ifdef TARGET_RISCV64 + CHECK_REG_TYPE(uint64_t); *(uint64_t *)value = (uint64_t)val; #else + CHECK_REG_TYPE(uint32_t); *(uint32_t *)value = (uint32_t)val; #endif - break; - } - default: - break; - } - - return; -} - -static void reg_write(CPURISCVState *env, unsigned int regid, const void *value) -{ - switch (regid) { - case UC_RISCV_REG_X0: - case UC_RISCV_REG_X1: - case UC_RISCV_REG_X2: - case UC_RISCV_REG_X3: - case UC_RISCV_REG_X4: - case UC_RISCV_REG_X5: - case UC_RISCV_REG_X6: - case UC_RISCV_REG_X7: - case UC_RISCV_REG_X8: - case UC_RISCV_REG_X9: - case UC_RISCV_REG_X10: - case UC_RISCV_REG_X11: - case UC_RISCV_REG_X12: - case UC_RISCV_REG_X13: - case UC_RISCV_REG_X14: - case UC_RISCV_REG_X15: - case UC_RISCV_REG_X16: - case UC_RISCV_REG_X17: - case UC_RISCV_REG_X18: - case UC_RISCV_REG_X19: - case UC_RISCV_REG_X20: - case UC_RISCV_REG_X21: - case UC_RISCV_REG_X22: - case UC_RISCV_REG_X23: - case UC_RISCV_REG_X24: - case UC_RISCV_REG_X25: - case UC_RISCV_REG_X26: - case UC_RISCV_REG_X27: - case UC_RISCV_REG_X28: - case UC_RISCV_REG_X29: - case UC_RISCV_REG_X30: - case UC_RISCV_REG_X31: + } else { + switch (regid) { + default: + break; + case UC_RISCV_REG_PC: #ifdef TARGET_RISCV64 - env->gpr[regid - UC_RISCV_REG_X0] = *(uint64_t *)value; + CHECK_REG_TYPE(uint64_t); + *(uint64_t *)value = env->pc; #else - env->gpr[regid - UC_RISCV_REG_X0] = *(uint32_t *)value; + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->pc; #endif - break; - case UC_RISCV_REG_PC: -#ifdef TARGET_RISCV64 - env->pc = *(uint64_t *)value; -#else - env->pc = *(uint32_t *)value; -#endif - break; - case UC_RISCV_REG_F0: // "ft0" - case UC_RISCV_REG_F1: // "ft1" - case UC_RISCV_REG_F2: // "ft2" - case UC_RISCV_REG_F3: // "ft3" - case UC_RISCV_REG_F4: // "ft4" - case UC_RISCV_REG_F5: // "ft5" - case UC_RISCV_REG_F6: // "ft6" - case UC_RISCV_REG_F7: // "ft7" - case UC_RISCV_REG_F8: // "fs0" - case UC_RISCV_REG_F9: // "fs1" - case UC_RISCV_REG_F10: // "fa0" - case UC_RISCV_REG_F11: // "fa1" - case UC_RISCV_REG_F12: // "fa2" - case UC_RISCV_REG_F13: // "fa3" - case UC_RISCV_REG_F14: // "fa4" - case UC_RISCV_REG_F15: // "fa5" - case UC_RISCV_REG_F16: // "fa6" - case UC_RISCV_REG_F17: // "fa7" - case UC_RISCV_REG_F18: // "fs2" - case UC_RISCV_REG_F19: // "fs3" - case UC_RISCV_REG_F20: // "fs4" - case UC_RISCV_REG_F21: // "fs5" - case UC_RISCV_REG_F22: // "fs6" - case UC_RISCV_REG_F23: // "fs7" - case UC_RISCV_REG_F24: // "fs8" - case UC_RISCV_REG_F25: // "fs9" - case UC_RISCV_REG_F26: // "fs10" - case UC_RISCV_REG_F27: // "fs11" - case UC_RISCV_REG_F28: // "ft8" - case UC_RISCV_REG_F29: // "ft9" - case UC_RISCV_REG_F30: // "ft10" - case UC_RISCV_REG_F31: // "ft11" -#ifdef TARGET_RISCV64 - env->fpr[regid - UC_RISCV_REG_F0] = *(uint64_t *)value; -#else - env->fpr[regid - UC_RISCV_REG_F0] = *(uint32_t *)value; -#endif - break; - case UC_RISCV_REG_USTATUS: - case UC_RISCV_REG_UIE: - case UC_RISCV_REG_UTVEC: - case UC_RISCV_REG_USCRATCH: - case UC_RISCV_REG_UEPC: - case UC_RISCV_REG_UCAUSE: - case UC_RISCV_REG_UTVAL: - case UC_RISCV_REG_UIP: - case UC_RISCV_REG_FFLAGS: - case UC_RISCV_REG_FRM: - case UC_RISCV_REG_FCSR: - case UC_RISCV_REG_CYCLE: - case UC_RISCV_REG_TIME: - case UC_RISCV_REG_INSTRET: - case UC_RISCV_REG_HPMCOUNTER3: - case UC_RISCV_REG_HPMCOUNTER4: - case UC_RISCV_REG_HPMCOUNTER5: - case UC_RISCV_REG_HPMCOUNTER6: - case UC_RISCV_REG_HPMCOUNTER7: - case UC_RISCV_REG_HPMCOUNTER8: - case UC_RISCV_REG_HPMCOUNTER9: - case UC_RISCV_REG_HPMCOUNTER10: - case UC_RISCV_REG_HPMCOUNTER11: - case UC_RISCV_REG_HPMCOUNTER12: - case UC_RISCV_REG_HPMCOUNTER13: - case UC_RISCV_REG_HPMCOUNTER14: - case UC_RISCV_REG_HPMCOUNTER15: - case UC_RISCV_REG_HPMCOUNTER16: - case UC_RISCV_REG_HPMCOUNTER17: - case UC_RISCV_REG_HPMCOUNTER18: - case UC_RISCV_REG_HPMCOUNTER19: - case UC_RISCV_REG_HPMCOUNTER20: - case UC_RISCV_REG_HPMCOUNTER21: - case UC_RISCV_REG_HPMCOUNTER22: - case UC_RISCV_REG_HPMCOUNTER23: - case UC_RISCV_REG_HPMCOUNTER24: - case UC_RISCV_REG_HPMCOUNTER25: - case UC_RISCV_REG_HPMCOUNTER26: - case UC_RISCV_REG_HPMCOUNTER27: - case UC_RISCV_REG_HPMCOUNTER28: - case UC_RISCV_REG_HPMCOUNTER29: - case UC_RISCV_REG_HPMCOUNTER30: - case UC_RISCV_REG_HPMCOUNTER31: - case UC_RISCV_REG_CYCLEH: - case UC_RISCV_REG_TIMEH: - case UC_RISCV_REG_INSTRETH: - case UC_RISCV_REG_HPMCOUNTER3H: - case UC_RISCV_REG_HPMCOUNTER4H: - case UC_RISCV_REG_HPMCOUNTER5H: - case UC_RISCV_REG_HPMCOUNTER6H: - case UC_RISCV_REG_HPMCOUNTER7H: - case UC_RISCV_REG_HPMCOUNTER8H: - case UC_RISCV_REG_HPMCOUNTER9H: - case UC_RISCV_REG_HPMCOUNTER10H: - case UC_RISCV_REG_HPMCOUNTER11H: - case UC_RISCV_REG_HPMCOUNTER12H: - case UC_RISCV_REG_HPMCOUNTER13H: - case UC_RISCV_REG_HPMCOUNTER14H: - case UC_RISCV_REG_HPMCOUNTER15H: - case UC_RISCV_REG_HPMCOUNTER16H: - case UC_RISCV_REG_HPMCOUNTER17H: - case UC_RISCV_REG_HPMCOUNTER18H: - case UC_RISCV_REG_HPMCOUNTER19H: - case UC_RISCV_REG_HPMCOUNTER20H: - case UC_RISCV_REG_HPMCOUNTER21H: - case UC_RISCV_REG_HPMCOUNTER22H: - case UC_RISCV_REG_HPMCOUNTER23H: - case UC_RISCV_REG_HPMCOUNTER24H: - case UC_RISCV_REG_HPMCOUNTER25H: - case UC_RISCV_REG_HPMCOUNTER26H: - case UC_RISCV_REG_HPMCOUNTER27H: - case UC_RISCV_REG_HPMCOUNTER28H: - case UC_RISCV_REG_HPMCOUNTER29H: - case UC_RISCV_REG_HPMCOUNTER30H: - case UC_RISCV_REG_HPMCOUNTER31H: - case UC_RISCV_REG_MCYCLE: - case UC_RISCV_REG_MINSTRET: - case UC_RISCV_REG_MCYCLEH: - case UC_RISCV_REG_MINSTRETH: - case UC_RISCV_REG_MVENDORID: - case UC_RISCV_REG_MARCHID: - case UC_RISCV_REG_MIMPID: - case UC_RISCV_REG_MHARTID: - case UC_RISCV_REG_MSTATUS: - case UC_RISCV_REG_MISA: - case UC_RISCV_REG_MEDELEG: - case UC_RISCV_REG_MIDELEG: - case UC_RISCV_REG_MIE: - case UC_RISCV_REG_MTVEC: - case UC_RISCV_REG_MCOUNTEREN: - case UC_RISCV_REG_MSTATUSH: - case UC_RISCV_REG_MUCOUNTEREN: - case UC_RISCV_REG_MSCOUNTEREN: - case UC_RISCV_REG_MHCOUNTEREN: - case UC_RISCV_REG_MSCRATCH: - case UC_RISCV_REG_MEPC: - case UC_RISCV_REG_MCAUSE: - case UC_RISCV_REG_MTVAL: - case UC_RISCV_REG_MIP: - case UC_RISCV_REG_MBADADDR: - case UC_RISCV_REG_SSTATUS: - case UC_RISCV_REG_SEDELEG: - case UC_RISCV_REG_SIDELEG: - case UC_RISCV_REG_SIE: - case UC_RISCV_REG_STVEC: - case UC_RISCV_REG_SCOUNTEREN: - case UC_RISCV_REG_SSCRATCH: - case UC_RISCV_REG_SEPC: - case UC_RISCV_REG_SCAUSE: - case UC_RISCV_REG_STVAL: - case UC_RISCV_REG_SIP: - case UC_RISCV_REG_SBADADDR: - case UC_RISCV_REG_SPTBR: - case UC_RISCV_REG_SATP: - case UC_RISCV_REG_HSTATUS: - case UC_RISCV_REG_HEDELEG: - case UC_RISCV_REG_HIDELEG: - case UC_RISCV_REG_HIE: - case UC_RISCV_REG_HCOUNTEREN: - case UC_RISCV_REG_HTVAL: - case UC_RISCV_REG_HIP: - case UC_RISCV_REG_HTINST: - case UC_RISCV_REG_HGATP: - case UC_RISCV_REG_HTIMEDELTA: - case UC_RISCV_REG_HTIMEDELTAH: { - target_ulong val; - int csrno = csrno_map[regid - UC_RISCV_REG_USTATUS]; -#ifdef TARGET_RISCV64 - riscv_csrrw(env, csrno, &val, *(uint64_t *)value, -1); -#else - riscv_csrrw(env, csrno, &val, *(uint32_t *)value, -1); -#endif - break; - } - default: - break; - } -} - -int riscv_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count) -{ - CPURISCVState *env = &(RISCV_CPU(uc->cpu)->env); - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - reg_read(env, regid, value); - } - - return 0; -} - -int riscv_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, - int count) -{ - CPURISCVState *env = &(RISCV_CPU(uc->cpu)->env); - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - reg_write(env, regid, value); - if (regid == UC_RISCV_REG_PC) { - // force to quit execution and flush TB - uc->quit_request = true; - break_translation_loop(uc); + break; } } - return 0; + return ret; } DEFAULT_VISIBILITY -#ifdef TARGET_RISCV32 -int riscv32_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) -#else -/* TARGET_RISCV64 */ -int riscv64_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) -#endif +uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc) { - CPURISCVState *env = (CPURISCVState *)ctx->data; - int i; + CPURISCVState *env = _env; + uc_err ret = UC_ERR_ARG; - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - reg_read(env, regid, value); + if (regid >= UC_RISCV_REG_X0 && regid <= UC_RISCV_REG_X31) { +#ifdef TARGET_RISCV64 + CHECK_REG_TYPE(uint64_t); + env->gpr[regid - UC_RISCV_REG_X0] = *(uint64_t *)value; +#else + CHECK_REG_TYPE(uint32_t); + env->gpr[regid - UC_RISCV_REG_X0] = *(uint32_t *)value; +#endif + } else if (regid >= UC_RISCV_REG_F0 && + regid <= UC_RISCV_REG_F31) { // "ft0".."ft31" + CHECK_REG_TYPE(uint64_t); + env->fpr[regid - UC_RISCV_REG_F0] = *(uint64_t *)value; + } else if (regid >= UC_RISCV_REG_USTATUS && + regid < UC_RISCV_REG_USTATUS + csrno_count) { + target_ulong val; + int csrno = csrno_map[regid - UC_RISCV_REG_USTATUS]; +#ifdef TARGET_RISCV64 + CHECK_REG_TYPE(uint64_t); + riscv_csrrw(env, csrno, &val, *(uint64_t *)value, -1); +#else + CHECK_REG_TYPE(uint32_t); + riscv_csrrw(env, csrno, &val, *(uint32_t *)value, -1); +#endif + } else { + switch (regid) { + default: + break; + case UC_RISCV_REG_PC: +#ifdef TARGET_RISCV64 + CHECK_REG_TYPE(uint64_t); + env->pc = *(uint64_t *)value; +#else + CHECK_REG_TYPE(uint32_t); + env->pc = *(uint32_t *)value; +#endif + *setpc = 1; + break; + } } - return 0; -} - -DEFAULT_VISIBILITY -#ifdef TARGET_RISCV32 -int riscv32_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) -#else -/* TARGET_RISCV64 */ -int riscv64_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) -#endif -{ - CPURISCVState *env = (CPURISCVState *)ctx->data; - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - reg_write(env, regid, value); - } - - return 0; + return ret; } static bool riscv_stop_interrupt(struct uc_struct *uc, int intno) @@ -644,16 +212,11 @@ static int riscv_cpus_init(struct uc_struct *uc, const char *cpu_model) } DEFAULT_VISIBILITY -#ifdef TARGET_RISCV32 -void riscv32_uc_init(struct uc_struct *uc) -#else -/* TARGET_RISCV64 */ -void riscv64_uc_init(struct uc_struct *uc) -#endif +void uc_init(struct uc_struct *uc) { - uc->reg_read = riscv_reg_read; - uc->reg_write = riscv_reg_write; - uc->reg_reset = riscv_reg_reset; + uc->reg_read = reg_read; + uc->reg_write = reg_write; + uc->reg_reset = reg_reset; uc->release = riscv_release; uc->set_pc = riscv_set_pc; uc->get_pc = riscv_get_pc; diff --git a/qemu/target/riscv/unicorn.h b/qemu/target/riscv/unicorn.h index 6add9369..87cdb3f8 100644 --- a/qemu/target/riscv/unicorn.h +++ b/qemu/target/riscv/unicorn.h @@ -6,22 +6,15 @@ #define UC_QEMU_TARGET_RISCV_H // functions to read & write registers -int riscv_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count); -int riscv_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, - int count); +uc_err reg_read_riscv32(void *env, int mode, unsigned int regid, void *value, + size_t *size); +uc_err reg_read_riscv64(void *env, int mode, unsigned int regid, void *value, + size_t *size); +uc_err reg_write_riscv32(void *env, int mode, unsigned int regid, + const void *value, size_t *size, int *setpc); +uc_err reg_write_riscv64(void *env, int mode, unsigned int regid, + const void *value, size_t *size, int *setpc); -int riscv32_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); -int riscv32_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); -int riscv64_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); -int riscv64_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); - -void riscv_reg_reset(struct uc_struct *uc); - -void riscv32_uc_init(struct uc_struct *uc); -void riscv64_uc_init(struct uc_struct *uc); +void uc_init_riscv32(struct uc_struct *uc); +void uc_init_riscv64(struct uc_struct *uc); #endif diff --git a/qemu/target/s390x/unicorn.c b/qemu/target/s390x/unicorn.c index 6378fe4c..972bf9e3 100644 --- a/qemu/target/s390x/unicorn.c +++ b/qemu/target/s390x/unicorn.c @@ -43,7 +43,7 @@ static void s390_release(void *ctx) // TODO: Anymore to free? } -void s390_reg_reset(struct uc_struct *uc) +static void reg_reset(struct uc_struct *uc) { CPUArchState *env = uc->cpu->env_ptr; @@ -53,120 +53,67 @@ void s390_reg_reset(struct uc_struct *uc) env->psw.addr = 0; } -static void reg_read(CPUS390XState *env, unsigned int regid, void *value) +DEFAULT_VISIBILITY +uc_err reg_read(void *_env, int mode, unsigned int regid, void *value, + size_t *size) { + CPUS390XState *env = _env; + uc_err ret = UC_ERR_ARG; + if (regid >= UC_S390X_REG_R0 && regid <= UC_S390X_REG_R15) { + CHECK_REG_TYPE(uint64_t); *(uint64_t *)value = env->regs[regid - UC_S390X_REG_R0]; - return; - } - - if (regid >= UC_S390X_REG_A0 && regid <= UC_S390X_REG_A15) { + } else if (regid >= UC_S390X_REG_A0 && regid <= UC_S390X_REG_A15) { + CHECK_REG_TYPE(uint32_t); *(uint32_t *)value = env->regs[regid - UC_S390X_REG_A0]; - return; - } - - switch (regid) { - default: - break; - case UC_S390X_REG_PC: - *(uint64_t *)value = env->psw.addr; - break; - case UC_S390X_REG_PSWM: - *(uint64_t *)value = get_psw_mask(env); - break; - } -} - -static void reg_write(CPUS390XState *env, unsigned int regid, const void *value) -{ - if (regid >= UC_S390X_REG_R0 && regid <= UC_S390X_REG_R15) { - env->regs[regid - UC_S390X_REG_R0] = *(uint64_t *)value; - return; - } - - if (regid >= UC_S390X_REG_A0 && regid <= UC_S390X_REG_A15) { - env->regs[regid - UC_S390X_REG_A0] = *(uint32_t *)value; - return; - } - - switch (regid) { - default: - break; - case UC_S390X_REG_PC: - env->psw.addr = *(uint64_t *)value; - break; - case UC_S390X_REG_PSWM: - env->psw.mask = *(uint64_t *)value; - env->cc_op = (env->psw.mask >> 44) & 3; - break; - } -} - -static int s390_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count) -{ - CPUS390XState *env = &(S390_CPU(uc->cpu)->env); - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - reg_read(env, regid, value); - } - - return 0; -} - -static int s390_reg_write(struct uc_struct *uc, unsigned int *regs, - void *const *vals, int count) -{ - CPUS390XState *env = &(S390_CPU(uc->cpu)->env); - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - reg_write(env, regid, value); - if (regid == UC_S390X_REG_PC) { - // force to quit execution and flush TB - uc->quit_request = true; - break_translation_loop(uc); + } else { + switch (regid) { + default: + break; + case UC_S390X_REG_PC: + CHECK_REG_TYPE(uint64_t); + *(uint64_t *)value = env->psw.addr; + break; + case UC_S390X_REG_PSWM: + CHECK_REG_TYPE(uint64_t); + *(uint64_t *)value = get_psw_mask(env); + break; } } - return 0; + return ret; } DEFAULT_VISIBILITY -int s390_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) +uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc) { - CPUS390XState *env = (CPUS390XState *)ctx->data; - int i; + CPUS390XState *env = _env; + uc_err ret = UC_ERR_ARG; - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - reg_read(env, regid, value); + if (regid >= UC_S390X_REG_R0 && regid <= UC_S390X_REG_R15) { + CHECK_REG_TYPE(uint64_t); + env->regs[regid - UC_S390X_REG_R0] = *(uint64_t *)value; + } else if (regid >= UC_S390X_REG_A0 && regid <= UC_S390X_REG_A15) { + CHECK_REG_TYPE(uint32_t); + env->regs[regid - UC_S390X_REG_A0] = *(uint32_t *)value; + } else { + switch (regid) { + default: + break; + case UC_S390X_REG_PC: + CHECK_REG_TYPE(uint64_t); + env->psw.addr = *(uint64_t *)value; + *setpc = 1; + break; + case UC_S390X_REG_PSWM: + CHECK_REG_TYPE(uint64_t); + env->psw.mask = *(uint64_t *)value; + env->cc_op = (env->psw.mask >> 44) & 3; + break; + } } - - return 0; -} - -DEFAULT_VISIBILITY -int s390_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) -{ - CPUS390XState *env = (CPUS390XState *)ctx->data; - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - reg_write(env, regid, value); - } - - return 0; + return ret; } static int s390_cpus_init(struct uc_struct *uc, const char *cpu_model) @@ -181,12 +128,12 @@ static int s390_cpus_init(struct uc_struct *uc, const char *cpu_model) } DEFAULT_VISIBILITY -void s390_uc_init(struct uc_struct *uc) +void uc_init(struct uc_struct *uc) { uc->release = s390_release; - uc->reg_read = s390_reg_read; - uc->reg_write = s390_reg_write; - uc->reg_reset = s390_reg_reset; + uc->reg_read = reg_read; + uc->reg_write = reg_write; + uc->reg_reset = reg_reset; uc->set_pc = s390_set_pc; uc->get_pc = s390_get_pc; uc->cpus_init = s390_cpus_init; diff --git a/qemu/target/s390x/unicorn.h b/qemu/target/s390x/unicorn.h index 27c20653..96285f7f 100644 --- a/qemu/target/s390x/unicorn.h +++ b/qemu/target/s390x/unicorn.h @@ -5,15 +5,10 @@ #define UC_QEMU_TARGET_S390X_H // functions to read & write registers -// int s390_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int -// count); int s390_reg_write(struct uc_struct *uc, unsigned int *regs, void -// *const *vals, int count); -int s390_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); -int s390_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); +uc_err reg_read_s390x(void *env, int mode, unsigned int regid, void *value, + size_t *size); +uc_err reg_write_s390x(void *env, int mode, unsigned int regid, + const void *value, size_t *size, int *setpc); -void s390_reg_reset(struct uc_struct *uc); - -void s390_uc_init(struct uc_struct *uc); +void uc_init_s390x(struct uc_struct *uc); #endif diff --git a/qemu/target/sparc/unicorn.c b/qemu/target/sparc/unicorn.c index 2df5b9b3..39c78b68 100644 --- a/qemu/target/sparc/unicorn.c +++ b/qemu/target/sparc/unicorn.c @@ -48,7 +48,7 @@ static void sparc_release(void *ctx) } } -void sparc_reg_reset(struct uc_struct *uc) +static void reg_reset(struct uc_struct *uc) { CPUArchState *env = uc->cpu->env_ptr; @@ -61,119 +61,71 @@ void sparc_reg_reset(struct uc_struct *uc) env->regwptr = env->regbase; } -static void reg_read(CPUSPARCState *env, unsigned int regid, void *value) +DEFAULT_VISIBILITY +uc_err reg_read(void *_env, int mode, unsigned int regid, void *value, + size_t *size) { - if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) - *(int32_t *)value = env->gregs[regid - UC_SPARC_REG_G0]; - else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) - *(int32_t *)value = env->regwptr[regid - UC_SPARC_REG_O0]; - else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) - *(int32_t *)value = env->regwptr[8 + regid - UC_SPARC_REG_L0]; - else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) - *(int32_t *)value = env->regwptr[16 + regid - UC_SPARC_REG_I0]; - else { + CPUSPARCState *env = _env; + uc_err ret = UC_ERR_ARG; + + if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) { + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->gregs[regid - UC_SPARC_REG_G0]; + } else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) { + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->regwptr[regid - UC_SPARC_REG_O0]; + } else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) { + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->regwptr[8 + regid - UC_SPARC_REG_L0]; + } else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) { + *(uint32_t *)value = env->regwptr[16 + regid - UC_SPARC_REG_I0]; + } else { switch (regid) { default: break; case UC_SPARC_REG_PC: - *(int32_t *)value = env->pc; + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->pc; break; } } - return; + return ret; } -static void reg_write(CPUSPARCState *env, unsigned int regid, const void *value) +DEFAULT_VISIBILITY +uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc) { - if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) + CPUSPARCState *env = _env; + uc_err ret = UC_ERR_ARG; + + if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) { + CHECK_REG_TYPE(uint32_t); env->gregs[regid - UC_SPARC_REG_G0] = *(uint32_t *)value; - else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) + } else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) { + CHECK_REG_TYPE(uint32_t); env->regwptr[regid - UC_SPARC_REG_O0] = *(uint32_t *)value; - else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) + } else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) { + CHECK_REG_TYPE(uint32_t); env->regwptr[8 + regid - UC_SPARC_REG_L0] = *(uint32_t *)value; - else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) + } else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) { + CHECK_REG_TYPE(uint32_t); env->regwptr[16 + regid - UC_SPARC_REG_I0] = *(uint32_t *)value; - else { + } else { switch (regid) { default: break; case UC_SPARC_REG_PC: + CHECK_REG_TYPE(uint32_t); env->pc = *(uint32_t *)value; env->npc = *(uint32_t *)value + 4; + *setpc = 1; break; } } - return; -} - -int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count) -{ - CPUSPARCState *env = &(SPARC_CPU(uc->cpu)->env); - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - reg_read(env, regid, value); - } - - return 0; -} - -int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, - int count) -{ - CPUSPARCState *env = &(SPARC_CPU(uc->cpu)->env); - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - reg_write(env, regid, value); - if (regid == UC_SPARC_REG_PC) { - // force to quit execution and flush TB - uc->quit_request = true; - uc_emu_stop(uc); - break; - } - } - - return 0; -} - -DEFAULT_VISIBILITY -int sparc_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) -{ - CPUSPARCState *env = (CPUSPARCState *)ctx->data; - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - reg_read(env, regid, value); - } - - return 0; -} - -DEFAULT_VISIBILITY -int sparc_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) -{ - CPUSPARCState *env = (CPUSPARCState *)ctx->data; - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - reg_write(env, regid, value); - } - - return 0; + return ret; } static int sparc_cpus_init(struct uc_struct *uc, const char *cpu_model) @@ -188,12 +140,12 @@ static int sparc_cpus_init(struct uc_struct *uc, const char *cpu_model) } DEFAULT_VISIBILITY -void sparc_uc_init(struct uc_struct *uc) +void uc_init(struct uc_struct *uc) { uc->release = sparc_release; - uc->reg_read = sparc_reg_read; - uc->reg_write = sparc_reg_write; - uc->reg_reset = sparc_reg_reset; + uc->reg_read = reg_read; + uc->reg_write = reg_write; + uc->reg_reset = reg_reset; uc->set_pc = sparc_set_pc; uc->get_pc = sparc_get_pc; uc->stop_interrupt = sparc_stop_interrupt; diff --git a/qemu/target/sparc/unicorn.h b/qemu/target/sparc/unicorn.h index 1f9818aa..4fbd6913 100644 --- a/qemu/target/sparc/unicorn.h +++ b/qemu/target/sparc/unicorn.h @@ -5,22 +5,15 @@ #define UC_QEMU_TARGET_SPARC_H // functions to read & write registers -int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count); -int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, - int count); +uc_err reg_read_sparc(void *env, int mode, unsigned int regid, void *value, + size_t *size); +uc_err reg_read_sparc64(void *env, int mode, unsigned int regid, void *value, + size_t *size); +uc_err reg_write_sparc(void *env, int mode, unsigned int regid, + const void *value, size_t *size, int *setpc); +uc_err reg_write_sparc64(void *env, int mode, unsigned int regid, + const void *value, size_t *size, int *setpc); -int sparc_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); -int sparc_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); -int sparc64_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); -int sparc64_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); - -void sparc_reg_reset(struct uc_struct *uc); - -void sparc_uc_init(struct uc_struct *uc); -void sparc64_uc_init(struct uc_struct *uc); +void uc_init_sparc(struct uc_struct *uc); +void uc_init_sparc64(struct uc_struct *uc); #endif diff --git a/qemu/target/sparc/unicorn64.c b/qemu/target/sparc/unicorn64.c index 5b53943f..11c46c8b 100644 --- a/qemu/target/sparc/unicorn64.c +++ b/qemu/target/sparc/unicorn64.c @@ -70,7 +70,7 @@ static void sparc_release(void *ctx) #endif } -void sparc_reg_reset(struct uc_struct *uc) +static void reg_reset(struct uc_struct *uc) { CPUArchState *env = uc->cpu->env_ptr; @@ -83,103 +83,72 @@ void sparc_reg_reset(struct uc_struct *uc) env->regwptr = env->regbase; } -static void reg_read(CPUSPARCState *env, unsigned int regid, void *value) +DEFAULT_VISIBILITY +uc_err reg_read(void *_env, int mode, unsigned int regid, void *value, + size_t *size) { - if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) - *(int64_t *)value = env->gregs[regid - UC_SPARC_REG_G0]; - else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) - *(int64_t *)value = env->regwptr[regid - UC_SPARC_REG_O0]; - else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) - *(int64_t *)value = env->regwptr[8 + regid - UC_SPARC_REG_L0]; - else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) - *(int64_t *)value = env->regwptr[16 + regid - UC_SPARC_REG_I0]; - else { + CPUSPARCState *env = _env; + uc_err ret = UC_ERR_ARG; + + if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) { + CHECK_REG_TYPE(uint64_t); + *(uint64_t *)value = env->gregs[regid - UC_SPARC_REG_G0]; + } else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) { + CHECK_REG_TYPE(uint64_t); + *(uint64_t *)value = env->regwptr[regid - UC_SPARC_REG_O0]; + } else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) { + CHECK_REG_TYPE(uint64_t); + *(uint64_t *)value = env->regwptr[8 + regid - UC_SPARC_REG_L0]; + } else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) { + CHECK_REG_TYPE(uint64_t); + *(uint64_t *)value = env->regwptr[16 + regid - UC_SPARC_REG_I0]; + } else { switch(regid) { - default: break; - case UC_SPARC_REG_PC: - *(int64_t *)value = env->pc; - break; + default: + break; + case UC_SPARC_REG_PC: + CHECK_REG_TYPE(uint64_t); + *(uint64_t *)value = env->pc; + break; } } + + return ret; } -static void reg_write(CPUSPARCState *env, unsigned int regid, const void *value) +DEFAULT_VISIBILITY +uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc) { - if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) + CPUSPARCState *env = _env; + uc_err ret = UC_ERR_ARG; + + if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) { + CHECK_REG_TYPE(uint64_t); env->gregs[regid - UC_SPARC_REG_G0] = *(uint64_t *)value; - else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) + } else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) { + CHECK_REG_TYPE(uint64_t); env->regwptr[regid - UC_SPARC_REG_O0] = *(uint64_t *)value; - else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) + } else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) { + CHECK_REG_TYPE(uint64_t); env->regwptr[8 + regid - UC_SPARC_REG_L0] = *(uint64_t *)value; - else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) + } else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) { + CHECK_REG_TYPE(uint64_t); env->regwptr[16 + regid - UC_SPARC_REG_I0] = *(uint64_t *)value; - else { + } else { switch(regid) { - default: break; - case UC_SPARC_REG_PC: - env->pc = *(uint64_t *)value; - env->npc = *(uint64_t *)value + 4; - break; + default: + break; + case UC_SPARC_REG_PC: + CHECK_REG_TYPE(uint64_t); + env->pc = *(uint64_t *)value; + env->npc = *(uint64_t *)value + 4; + *setpc = 1; + break; } } -} -int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count) -{ - CPUSPARCState *env = &(SPARC_CPU(uc->cpu)->env); - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - reg_read(env, regid, value); - } - - return 0; -} - -int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void* const* vals, int count) -{ - CPUSPARCState *env = &(SPARC_CPU(uc->cpu)->env); - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - reg_write(env, regid, value); - } - - return 0; -} - -DEFAULT_VISIBILITY -int sparc64_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count) -{ - CPUSPARCState *env = (CPUSPARCState *)ctx->data; - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - reg_read(env, regid, value); - } - - return 0; -} - -DEFAULT_VISIBILITY -int sparc64_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count) -{ - CPUSPARCState *env = (CPUSPARCState *)ctx->data; - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - reg_write(env, regid, value); - } - - return 0; + return ret; } static int sparc_cpus_init(struct uc_struct *uc, const char *cpu_model) @@ -194,12 +163,12 @@ static int sparc_cpus_init(struct uc_struct *uc, const char *cpu_model) } DEFAULT_VISIBILITY -void sparc64_uc_init(struct uc_struct* uc) +void uc_init(struct uc_struct *uc) { uc->release = sparc_release; - uc->reg_read = sparc_reg_read; - uc->reg_write = sparc_reg_write; - uc->reg_reset = sparc_reg_reset; + uc->reg_read = reg_read; + uc->reg_write = reg_write; + uc->reg_reset = reg_reset; uc->set_pc = sparc_set_pc; uc->get_pc = sparc_get_pc; uc->stop_interrupt = sparc_stop_interrupt; diff --git a/qemu/target/tricore/unicorn.c b/qemu/target/tricore/unicorn.c index a3eac632..9f47a7db 100644 --- a/qemu/target/tricore/unicorn.c +++ b/qemu/target/tricore/unicorn.c @@ -27,7 +27,7 @@ static uint64_t tricore_get_pc(struct uc_struct *uc) return ((CPUTriCoreState *)uc->cpu->env_ptr)->PC; } -void tricore_reg_reset(struct uc_struct *uc) +static void reg_reset(struct uc_struct *uc) { CPUTriCoreState *env; (void)uc; @@ -39,216 +39,209 @@ void tricore_reg_reset(struct uc_struct *uc) env->PC = 0; } -static void reg_read(CPUTriCoreState *env, unsigned int regid, void *value) +DEFAULT_VISIBILITY +uc_err reg_read(void *_env, int mode, unsigned int regid, void *value, + size_t *size) { - if (regid >= UC_TRICORE_REG_A0 && regid <= UC_TRICORE_REG_A9) - *(int32_t *)value = env->gpr_a[regid - UC_TRICORE_REG_A0]; - if (regid >= UC_TRICORE_REG_A12 && regid <= UC_TRICORE_REG_A15) - *(int32_t *)value = env->gpr_a[regid - UC_TRICORE_REG_A0]; - else if (regid >= UC_TRICORE_REG_D0 && regid <= UC_TRICORE_REG_D15) - *(int32_t *)value = env->gpr_d[regid - UC_TRICORE_REG_D0]; - else { + CPUTriCoreState *env = _env; + uc_err ret = UC_ERR_ARG; + + if (regid >= UC_TRICORE_REG_A0 && regid <= UC_TRICORE_REG_A9) { + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->gpr_a[regid - UC_TRICORE_REG_A0]; + } else if (regid >= UC_TRICORE_REG_A12 && regid <= UC_TRICORE_REG_A15) { + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->gpr_a[regid - UC_TRICORE_REG_A0]; + } else if (regid >= UC_TRICORE_REG_D0 && regid <= UC_TRICORE_REG_D15) { + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->gpr_d[regid - UC_TRICORE_REG_D0]; + } else { switch (regid) { // case UC_TRICORE_REG_SP: case UC_TRICORE_REG_A10: - *(int32_t *)value = env->gpr_a[10]; + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->gpr_a[10]; break; // case UC_TRICORE_REG_LR: case UC_TRICORE_REG_A11: - *(int32_t *)value = env->gpr_a[11]; + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->gpr_a[11]; break; case UC_TRICORE_REG_PC: - *(int32_t *)value = env->PC; + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->PC; break; case UC_TRICORE_REG_PCXI: - *(int32_t *)value = env->PCXI; + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->PCXI; break; case UC_TRICORE_REG_PSW: - *(int32_t *)value = env->PSW; + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->PSW; break; case UC_TRICORE_REG_PSW_USB_C: - *(int32_t *)value = env->PSW_USB_C; + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->PSW_USB_C; break; case UC_TRICORE_REG_PSW_USB_V: - *(int32_t *)value = env->PSW_USB_V; + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->PSW_USB_V; break; case UC_TRICORE_REG_PSW_USB_SV: - *(int32_t *)value = env->PSW_USB_SV; + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->PSW_USB_SV; break; case UC_TRICORE_REG_PSW_USB_AV: - *(int32_t *)value = env->PSW_USB_AV; + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->PSW_USB_AV; break; case UC_TRICORE_REG_PSW_USB_SAV: - *(int32_t *)value = env->PSW_USB_SAV; + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->PSW_USB_SAV; break; case UC_TRICORE_REG_SYSCON: - *(int32_t *)value = env->SYSCON; + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->SYSCON; break; case UC_TRICORE_REG_CPU_ID: - *(int32_t *)value = env->CPU_ID; + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->CPU_ID; break; case UC_TRICORE_REG_BIV: - *(int32_t *)value = env->BIV; + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->BIV; break; case UC_TRICORE_REG_BTV: - *(int32_t *)value = env->BTV; + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->BTV; break; case UC_TRICORE_REG_ISP: - *(int32_t *)value = env->ISP; + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->ISP; break; case UC_TRICORE_REG_ICR: - *(int32_t *)value = env->ICR; + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->ICR; break; case UC_TRICORE_REG_FCX: - *(int32_t *)value = env->FCX; + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->FCX; break; case UC_TRICORE_REG_LCX: - *(int32_t *)value = env->LCX; + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->LCX; break; case UC_TRICORE_REG_COMPAT: - *(int32_t *)value = env->COMPAT; + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->COMPAT; break; } } + + return ret; } -int tricore_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count) +DEFAULT_VISIBILITY +uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc) { - CPUTriCoreState *env = &(TRICORE_CPU(uc->cpu)->env); - int i; + CPUTriCoreState *env = _env; + uc_err ret = UC_ERR_ARG; - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - reg_read(env, regid, value); - } - - return 0; -} - -int tricore_context_reg_read(struct uc_context *uc, unsigned int *regs, - void **vals, int count) -{ - CPUTriCoreState *env = (CPUTriCoreState *)uc->data; - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - reg_read(env, regid, value); - } - - return 0; -} - -static void reg_write(CPUTriCoreState *env, unsigned int regid, - const void *value) -{ - if (regid >= UC_TRICORE_REG_A0 && regid <= UC_TRICORE_REG_A9) - env->gpr_a[regid - UC_TRICORE_REG_A0] = *(int32_t *)value; - if (regid >= UC_TRICORE_REG_A12 && regid <= UC_TRICORE_REG_A15) - env->gpr_a[regid - UC_TRICORE_REG_A0] = *(int32_t *)value; - else if (regid >= UC_TRICORE_REG_D0 && regid <= UC_TRICORE_REG_D15) - env->gpr_d[regid - UC_TRICORE_REG_D0] = *(int32_t *)value; - else { + if (regid >= UC_TRICORE_REG_A0 && regid <= UC_TRICORE_REG_A9) { + CHECK_REG_TYPE(uint32_t); + env->gpr_a[regid - UC_TRICORE_REG_A0] = *(uint32_t *)value; + } else if (regid >= UC_TRICORE_REG_A12 && regid <= UC_TRICORE_REG_A15) { + CHECK_REG_TYPE(uint32_t); + env->gpr_a[regid - UC_TRICORE_REG_A0] = *(uint32_t *)value; + } else if (regid >= UC_TRICORE_REG_D0 && regid <= UC_TRICORE_REG_D15) { + CHECK_REG_TYPE(uint32_t); + env->gpr_d[regid - UC_TRICORE_REG_D0] = *(uint32_t *)value; + } else { switch (regid) { // case UC_TRICORE_REG_SP: case UC_TRICORE_REG_A10: - env->gpr_a[10] = *(int32_t *)value; + CHECK_REG_TYPE(uint32_t); + env->gpr_a[10] = *(uint32_t *)value; break; // case UC_TRICORE_REG_LR: case UC_TRICORE_REG_A11: - env->gpr_a[11] = *(int32_t *)value; + CHECK_REG_TYPE(uint32_t); + env->gpr_a[11] = *(uint32_t *)value; break; case UC_TRICORE_REG_PC: - env->PC = *(int32_t *)value; + CHECK_REG_TYPE(uint32_t); + env->PC = *(uint32_t *)value; + *setpc = 1; break; case UC_TRICORE_REG_PCXI: - env->PCXI = *(int32_t *)value; + CHECK_REG_TYPE(uint32_t); + env->PCXI = *(uint32_t *)value; break; case UC_TRICORE_REG_PSW: - env->PSW = *(int32_t *)value; + CHECK_REG_TYPE(uint32_t); + env->PSW = *(uint32_t *)value; break; case UC_TRICORE_REG_PSW_USB_C: - env->PSW_USB_C = *(int32_t *)value; + CHECK_REG_TYPE(uint32_t); + env->PSW_USB_C = *(uint32_t *)value; break; case UC_TRICORE_REG_PSW_USB_V: - env->PSW_USB_V = *(int32_t *)value; + CHECK_REG_TYPE(uint32_t); + env->PSW_USB_V = *(uint32_t *)value; break; case UC_TRICORE_REG_PSW_USB_SV: - env->PSW_USB_SV = *(int32_t *)value; + CHECK_REG_TYPE(uint32_t); + env->PSW_USB_SV = *(uint32_t *)value; break; case UC_TRICORE_REG_PSW_USB_AV: - env->PSW_USB_AV = *(int32_t *)value; + CHECK_REG_TYPE(uint32_t); + env->PSW_USB_AV = *(uint32_t *)value; break; case UC_TRICORE_REG_PSW_USB_SAV: - env->PSW_USB_SAV = *(int32_t *)value; + CHECK_REG_TYPE(uint32_t); + env->PSW_USB_SAV = *(uint32_t *)value; break; case UC_TRICORE_REG_SYSCON: - env->SYSCON = *(int32_t *)value; + CHECK_REG_TYPE(uint32_t); + env->SYSCON = *(uint32_t *)value; break; case UC_TRICORE_REG_CPU_ID: - env->CPU_ID = *(int32_t *)value; + CHECK_REG_TYPE(uint32_t); + env->CPU_ID = *(uint32_t *)value; break; case UC_TRICORE_REG_BIV: - env->BIV = *(int32_t *)value; + CHECK_REG_TYPE(uint32_t); + env->BIV = *(uint32_t *)value; break; case UC_TRICORE_REG_BTV: - env->BTV = *(int32_t *)value; + CHECK_REG_TYPE(uint32_t); + env->BTV = *(uint32_t *)value; break; case UC_TRICORE_REG_ISP: - env->ISP = *(int32_t *)value; + CHECK_REG_TYPE(uint32_t); + env->ISP = *(uint32_t *)value; break; case UC_TRICORE_REG_ICR: - env->ICR = *(int32_t *)value; + CHECK_REG_TYPE(uint32_t); + env->ICR = *(uint32_t *)value; break; case UC_TRICORE_REG_FCX: - env->FCX = *(int32_t *)value; + CHECK_REG_TYPE(uint32_t); + env->FCX = *(uint32_t *)value; break; case UC_TRICORE_REG_LCX: - env->LCX = *(int32_t *)value; + CHECK_REG_TYPE(uint32_t); + env->LCX = *(uint32_t *)value; break; case UC_TRICORE_REG_COMPAT: - env->COMPAT = *(int32_t *)value; + CHECK_REG_TYPE(uint32_t); + env->COMPAT = *(uint32_t *)value; break; } } -} -int tricore_reg_write(struct uc_struct *uc, unsigned int *regs, - void *const *vals, int count) -{ - CPUTriCoreState *env = &(TRICORE_CPU(uc->cpu)->env); - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - reg_write(env, regid, value); - if (regid == UC_TRICORE_REG_PC) { - // force to quit execution and flush TB - uc->quit_request = true; - break_translation_loop(uc); - } - } - - return 0; -} - -int tricore_context_reg_write(struct uc_context *uc, unsigned int *regs, - void *const *vals, int count) -{ - CPUTriCoreState *env = (CPUTriCoreState *)uc->data; - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - reg_write(env, regid, value); - } - - return 0; + return ret; } static int tricore_cpus_init(struct uc_struct *uc, const char *cpu_model) @@ -282,11 +275,12 @@ static void tricore_release(void *ctx) } } -void tricore_uc_init(struct uc_struct *uc) +DEFAULT_VISIBILITY +void uc_init(struct uc_struct *uc) { - uc->reg_read = tricore_reg_read; - uc->reg_write = tricore_reg_write; - uc->reg_reset = tricore_reg_reset; + uc->reg_read = reg_read; + uc->reg_write = reg_write; + uc->reg_reset = reg_reset; uc->set_pc = tricore_set_pc; uc->get_pc = tricore_get_pc; uc->cpus_init = tricore_cpus_init; diff --git a/qemu/target/tricore/unicorn.h b/qemu/target/tricore/unicorn.h index 36d30ee7..2958c365 100644 --- a/qemu/target/tricore/unicorn.h +++ b/qemu/target/tricore/unicorn.h @@ -10,18 +10,10 @@ #define UC_QEMU_TARGET_TRICORE_H // functions to read & write registers -int tricore_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count); -int tricore_reg_write(struct uc_struct *uc, unsigned int *regs, - void *const *vals, int count); - -int tricore_context_reg_read(struct uc_context *uc, unsigned int *regs, - void **vals, int count); -int tricore_context_reg_write(struct uc_context *uc, unsigned int *regs, - void *const *vals, int count); - -void tricore_reg_reset(struct uc_struct *uc); - -void tricore_uc_init(struct uc_struct *uc); +uc_err reg_read_tricore(void *env, int mode, unsigned int regid, void *value, + size_t *size); +uc_err reg_write_tricore(void *env, int mode, unsigned int regid, + const void *value, size_t *size, int *setpc); +void uc_init_tricore(struct uc_struct *uc); #endif diff --git a/qemu/tcg/tcg.c b/qemu/tcg/tcg.c index cb76f31a..dcacec7c 100644 --- a/qemu/tcg/tcg.c +++ b/qemu/tcg/tcg.c @@ -23,8 +23,6 @@ */ /* define it to use liveness analysis (better code) */ -#include "tcg/tcg.h" -#include #define USE_TCG_OPTIMIZATIONS #include "qemu/osdep.h" @@ -408,13 +406,7 @@ static void tcg_region_assign(TCGContext *s, size_t curr_region) s->code_gen_buffer = start; s->code_gen_ptr = start; s->code_gen_buffer_size = (char *)end - (char *)start; -#if defined(WIN32) && !defined(WIN32_QEMU_ALLOC_BUFFER) - VirtualAlloc( - s->code_gen_buffer, - ROUND_UP(s->code_gen_buffer_size, s->uc->qemu_real_host_page_size), - MEM_COMMIT, - PAGE_EXECUTE_READWRITE); -#endif + memset(s->code_gen_buffer, 0x00, s->code_gen_buffer_size); s->code_gen_highwater = (char *)end - TCG_HIGHWATER; } @@ -509,11 +501,7 @@ void tcg_region_init(TCGContext *tcg_ctx) size_t n_regions; size_t i; -#if defined(WIN32) && !defined(WIN32_QEMU_ALLOC_BUFFER) - n_regions = size / (tcg_ctx->uc->qemu_real_host_page_size * UC_TCG_REGION_PAGES_COUNT); -#else n_regions = 1; -#endif /* The first region will be 'aligned - buf' bytes larger than the others */ aligned = (void *)QEMU_ALIGN_PTR_UP(buf, page_size); @@ -551,10 +539,6 @@ void tcg_region_init(TCGContext *tcg_ctx) tcg_ctx->tree = g_tree_new(tb_tc_cmp); -#if defined(WIN32) && !defined(WIN32_QEMU_ALLOC_BUFFER) - // Allocate a region immediately, or the highwater is not set correctly. - tcg_region_alloc(tcg_ctx); -#endif } /* diff --git a/qemu/tricore.h b/qemu/tricore.h index a7219654..5fc51625 100644 --- a/qemu/tricore.h +++ b/qemu/tricore.h @@ -5,6 +5,9 @@ #define UNICORN_ARCH_POSTFIX _tricore #endif #define unicorn_fill_tlb unicorn_fill_tlb_tricore +#define reg_read reg_read_tricore +#define reg_write reg_write_tricore +#define uc_init uc_init_tricore #define uc_add_inline_hook uc_add_inline_hook_tricore #define uc_del_inline_hook uc_del_inline_hook_tricore #define tb_invalidate_phys_range tb_invalidate_phys_range_tricore @@ -120,7 +123,10 @@ #define memory_map memory_map_tricore #define memory_map_io memory_map_io_tricore #define memory_map_ptr memory_map_ptr_tricore +#define memory_cow memory_cow_tricore #define memory_unmap memory_unmap_tricore +#define memory_moveout memory_moveout_tricore +#define memory_movein memory_movein_tricore #define memory_free memory_free_tricore #define flatview_unref flatview_unref_tricore #define address_space_get_flatview address_space_get_flatview_tricore @@ -139,7 +145,9 @@ #define memory_region_get_ram_addr memory_region_get_ram_addr_tricore #define memory_region_add_subregion memory_region_add_subregion_tricore #define memory_region_del_subregion memory_region_del_subregion_tricore +#define memory_region_add_subregion_overlap memory_region_add_subregion_overlap_tricore #define memory_region_find memory_region_find_tricore +#define memory_region_filter_subregions memory_region_filter_subregions_tricore #define memory_listener_register memory_listener_register_tricore #define memory_listener_unregister memory_listener_unregister_tricore #define address_space_remove_listeners address_space_remove_listeners_tricore @@ -147,6 +155,7 @@ #define address_space_destroy address_space_destroy_tricore #define memory_region_init_ram memory_region_init_ram_tricore #define memory_mapping_list_add_merge_sorted memory_mapping_list_add_merge_sorted_tricore +#define find_memory_mapping find_memory_mapping_tricore #define exec_inline_op exec_inline_op_tricore #define floatx80_default_nan floatx80_default_nan_tricore #define float_raise float_raise_tricore diff --git a/qemu/unicorn_common.h b/qemu/unicorn_common.h index d7802b3b..def70a9e 100644 --- a/qemu/unicorn_common.h +++ b/qemu/unicorn_common.h @@ -10,7 +10,7 @@ // codes for unicorns purposes. void vm_start(struct uc_struct*); -void tcg_exec_init(struct uc_struct *uc, unsigned long tb_size); +void tcg_exec_init(struct uc_struct *uc, uint32_t tb_size); bool unicorn_fill_tlb(CPUState *cs, vaddr address, int size, MMUAccessType rw, int mmu_idx, bool probe, uintptr_t retaddr); @@ -107,6 +107,18 @@ static uc_err uc_set_tlb(struct uc_struct *uc, int mode) { } } +MemoryRegion *find_memory_mapping(struct uc_struct *uc, hwaddr address) +{ + hwaddr xlat = 0; + hwaddr len = 1; + MemoryRegion *mr = address_space_translate(&uc->address_space_memory, address, &xlat, &len, false, MEMTXATTRS_UNSPECIFIED); + + if (mr == &uc->io_mem_unassigned) { + return NULL; + } + return mr; +} + void softfloat_init(void); static inline void uc_common_init(struct uc_struct* uc) { @@ -118,14 +130,28 @@ static inline void uc_common_init(struct uc_struct* uc) uc->memory_map = memory_map; uc->memory_map_ptr = memory_map_ptr; uc->memory_unmap = memory_unmap; + uc->memory_moveout = memory_moveout; + uc->memory_movein = memory_movein; uc->readonly_mem = memory_region_set_readonly; uc->target_page = target_page_init; uc->softfloat_initialize = softfloat_init; uc->tcg_flush_tlb = tcg_flush_softmmu_tlb; uc->memory_map_io = memory_map_io; uc->set_tlb = uc_set_tlb; + uc->memory_mapping = find_memory_mapping; + uc->memory_filter_subregions = memory_region_filter_subregions; + uc->memory_cow = memory_cow; if (!uc->release) uc->release = release_common; } + +#define CHECK_REG_TYPE(type) do { \ + if (unlikely(*size < sizeof(type))) { \ + return UC_ERR_OVERFLOW; \ + } \ + *size = sizeof(type); \ + ret = UC_ERR_OK; \ +} while(0) + #endif diff --git a/qemu/util/oslib-posix.c b/qemu/util/oslib-posix.c index e480e101..3402e1d1 100644 --- a/qemu/util/oslib-posix.c +++ b/qemu/util/oslib-posix.c @@ -45,6 +45,16 @@ static void *qemu_ram_mmap(struct uc_struct *uc, static void qemu_ram_munmap(struct uc_struct *uc, void *ptr, size_t size); #endif +#if defined(__MINGW32__) && defined(__clang__) +#include +int getpagesize() +{ + SYSTEM_INFO S; + GetNativeSystemInfo(&S); + return S.dwPageSize; +} +#endif + void *qemu_oom_check(void *ptr) { if (ptr == NULL) { diff --git a/qemu/x86_64.h b/qemu/x86_64.h index aa03182d..be528692 100644 --- a/qemu/x86_64.h +++ b/qemu/x86_64.h @@ -5,6 +5,9 @@ #define UNICORN_ARCH_POSTFIX _x86_64 #endif #define unicorn_fill_tlb unicorn_fill_tlb_x86_64 +#define reg_read reg_read_x86_64 +#define reg_write reg_write_x86_64 +#define uc_init uc_init_x86_64 #define uc_add_inline_hook uc_add_inline_hook_x86_64 #define uc_del_inline_hook uc_del_inline_hook_x86_64 #define tb_invalidate_phys_range tb_invalidate_phys_range_x86_64 @@ -120,7 +123,10 @@ #define memory_map memory_map_x86_64 #define memory_map_io memory_map_io_x86_64 #define memory_map_ptr memory_map_ptr_x86_64 +#define memory_cow memory_cow_x86_64 #define memory_unmap memory_unmap_x86_64 +#define memory_moveout memory_moveout_x86_64 +#define memory_movein memory_movein_x86_64 #define memory_free memory_free_x86_64 #define flatview_unref flatview_unref_x86_64 #define address_space_get_flatview address_space_get_flatview_x86_64 @@ -139,7 +145,9 @@ #define memory_region_get_ram_addr memory_region_get_ram_addr_x86_64 #define memory_region_add_subregion memory_region_add_subregion_x86_64 #define memory_region_del_subregion memory_region_del_subregion_x86_64 +#define memory_region_add_subregion_overlap memory_region_add_subregion_overlap_x86_64 #define memory_region_find memory_region_find_x86_64 +#define memory_region_filter_subregions memory_region_filter_subregions_x86_64 #define memory_listener_register memory_listener_register_x86_64 #define memory_listener_unregister memory_listener_unregister_x86_64 #define address_space_remove_listeners address_space_remove_listeners_x86_64 @@ -147,6 +155,7 @@ #define address_space_destroy address_space_destroy_x86_64 #define memory_region_init_ram memory_region_init_ram_x86_64 #define memory_mapping_list_add_merge_sorted memory_mapping_list_add_merge_sorted_x86_64 +#define find_memory_mapping find_memory_mapping_x86_64 #define exec_inline_op exec_inline_op_x86_64 #define floatx80_default_nan floatx80_default_nan_x86_64 #define float_raise float_raise_x86_64 @@ -1879,7 +1888,4 @@ #define x86_cpu_xrstor_all_areas x86_cpu_xrstor_all_areas_x86_64 #define cpu_get_fp80 cpu_get_fp80_x86_64 #define cpu_set_fp80 cpu_set_fp80_x86_64 -#define x86_reg_reset x86_reg_reset_x86_64 -#define x86_reg_read x86_reg_read_x86_64 -#define x86_reg_write x86_reg_write_x86_64 #endif diff --git a/samples/sample_arm64.c b/samples/sample_arm64.c index 11f4ca63..84f32c29 100644 --- a/samples/sample_arm64.c +++ b/samples/sample_arm64.c @@ -10,8 +10,8 @@ #define ARM64_CODE \ "\xab\x05\x00\xb8\xaf\x05\x40\x38" // str w11, [x13], #0; ldrb w15, [x13], // #0 -//#define ARM64_CODE_EB "\xb8\x00\x05\xab\x38\x40\x05\xaf" // str w11, [x13]; -// ldrb w15, [x13] +// #define ARM64_CODE_EB "\xb8\x00\x05\xab\x38\x40\x05\xaf" // str w11, [x13]; +// ldrb w15, [x13] #define ARM64_CODE_EB ARM64_CODE // mrs x2, tpidrro_el0 diff --git a/samples/sample_mmu.c b/samples/sample_mmu.c index 84baa2a0..96c526bd 100644 --- a/samples/sample_mmu.c +++ b/samples/sample_mmu.c @@ -18,25 +18,30 @@ * mov rax, 60 * syscall */ -char code[] = "\xB8\x39\x00\x00\x00\x0F\x05\x48\x85\xC0\x74\x0F\xB8\x3C\x00\x00\x00\x48\x89\x04\x25\x00\x40\x00\x00\x0F\x05\xB9\x2A\x00\x00\x00\x48\x89\x0C\x25\x00\x40\x00\x00\xB8\x3C\x00\x00\x00\x0F\x05"; +char code[] = "\xB8\x39\x00\x00\x00\x0F\x05\x48\x85\xC0\x74\x0F\xB8\x3C\x00\x00" + "\x00\x48\x89\x04\x25\x00\x40\x00\x00\x0F\x05\xB9\x2A\x00\x00\x00" + "\x48\x89\x0C\x25\x00\x40\x00\x00\xB8\x3C\x00\x00\x00\x0F\x05"; -static void mmu_write_callback(uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data) +static void mmu_write_callback(uc_engine *uc, uc_mem_type type, + uint64_t address, int size, int64_t value, + void *user_data) { printf("write at 0x%lx: 0x%lx\n", address, value); } -static void x86_mmu_prepare_tlb(uc_engine *uc, uint64_t vaddr, uint64_t tlb_base) +static void x86_mmu_prepare_tlb(uc_engine *uc, uint64_t vaddr, + uint64_t tlb_base) { uc_err err; uint64_t cr0; uint64_t cr4; uc_x86_msr msr = {.rid = 0xC0000080, .value = 0}; - uint64_t pml4o = ((vaddr & 0x00ff8000000000) >> 39)*8; - uint64_t pdpo = ((vaddr & 0x00007fc0000000) >> 30)*8; - uint64_t pdo = ((vaddr & 0x0000003fe00000) >> 21)*8; + uint64_t pml4o = ((vaddr & 0x00ff8000000000) >> 39) * 8; + uint64_t pdpo = ((vaddr & 0x00007fc0000000) >> 30) * 8; + uint64_t pdo = ((vaddr & 0x0000003fe00000) >> 21) * 8; uint64_t pml4e = (tlb_base + 0x1000) | 1 | (1 << 2); - uint64_t pdpe = (tlb_base + 0x2000) | 1 | (1 << 2); - uint64_t pde = (tlb_base + 0x3000) | 1 | (1 << 2); + uint64_t pdpe = (tlb_base + 0x2000) | 1 | (1 << 2); + uint64_t pde = (tlb_base + 0x3000) | 1 | (1 << 2); err = uc_mem_write(uc, tlb_base + pml4o, &pml4e, sizeof(pml4o)); if (err) { printf("failed to write pml4e\n"); @@ -73,10 +78,10 @@ static void x86_mmu_prepare_tlb(uc_engine *uc, uint64_t vaddr, uint64_t tlb_base exit(1); } - cr0 |= 1; //enable protected mode - cr0 |= 1l << 31; //enable paging - cr4 |= 1l << 5; //enable physical address extension - msr.value |= 1l << 8; //enable long mode + cr0 |= 1; // enable protected mode + cr0 |= 1l << 31; // enable paging + cr4 |= 1l << 5; // enable physical address extension + msr.value |= 1l << 8; // enable long mode err = uc_reg_write(uc, UC_X86_REG_CR0, &cr0); if (err) { @@ -95,10 +100,11 @@ static void x86_mmu_prepare_tlb(uc_engine *uc, uint64_t vaddr, uint64_t tlb_base } } -static void x86_mmu_pt_set(uc_engine *uc, uint64_t vaddr, uint64_t paddr, uint64_t tlb_base) +static void x86_mmu_pt_set(uc_engine *uc, uint64_t vaddr, uint64_t paddr, + uint64_t tlb_base) { - uint64_t pto = ((vaddr & 0x000000001ff000) >> 12)*8; - uint32_t pte = (paddr) | 1 | (1 << 2); + uint64_t pto = ((vaddr & 0x000000001ff000) >> 12) * 8; + uint32_t pte = (paddr) | 1 | (1 << 2); uc_mem_write(uc, tlb_base + 0x3000 + pto, &pte, sizeof(pte)); } @@ -162,20 +168,23 @@ void cpu_tlb(void) exit(1); } - err = uc_hook_add(uc, &h1, UC_HOOK_INSN, &x86_mmu_syscall_callback, &parrent_done, 1, 0, UC_X86_INS_SYSCALL); + err = uc_hook_add(uc, &h1, UC_HOOK_INSN, &x86_mmu_syscall_callback, + &parrent_done, 1, 0, UC_X86_INS_SYSCALL); if (err) { printf("Failed on uc_hook_add() with error returned: %u\n", err); exit(1); } - // Memory hooks are called after the mmu translation, so hook the physicall addresses - err = uc_hook_add(uc, &h2, UC_HOOK_MEM_WRITE, &mmu_write_callback, NULL, 0x1000, 0x3000); + // Memory hooks are called after the mmu translation, so hook the physicall + // addresses + err = uc_hook_add(uc, &h2, UC_HOOK_MEM_WRITE, &mmu_write_callback, NULL, + 0x1000, 0x3000); if (err) { printf("Faled on uc_hook_add() with error returned: %u\n", err); } printf("map code\n"); - err = uc_mem_map(uc, 0x0, 0x1000, UC_PROT_ALL); //Code + err = uc_mem_map(uc, 0x0, 0x1000, UC_PROT_ALL); // Code if (err) { printf("Failed on uc_mem_map() with error return: %u\n", err); exit(1); @@ -186,25 +195,24 @@ void cpu_tlb(void) exit(1); } printf("map parrent memory\n"); - err = uc_mem_map(uc, 0x1000, 0x1000, UC_PROT_ALL); //Parrent + err = uc_mem_map(uc, 0x1000, 0x1000, UC_PROT_ALL); // Parrent if (err) { printf("Failed on uc_mem_map() with error return: %u\n", err); exit(1); } printf("map child memory\n"); - err = uc_mem_map(uc, 0x2000, 0x1000, UC_PROT_ALL); //Child + err = uc_mem_map(uc, 0x2000, 0x1000, UC_PROT_ALL); // Child if (err) { printf("failed to map child memory\n"); exit(1); } printf("map tlb memory\n"); - err = uc_mem_map(uc, tlb_base, 0x4000, UC_PROT_ALL); //TLB + err = uc_mem_map(uc, tlb_base, 0x4000, UC_PROT_ALL); // TLB if (err) { printf("failed to map memory for tlb\n"); exit(1); } - printf("set up the tlb\n"); x86_mmu_prepare_tlb(uc, 0x0, tlb_base); x86_mmu_pt_set(uc, 0x2000, 0x0, tlb_base); @@ -277,7 +285,8 @@ void cpu_tlb(void) uc_close(uc); } -static bool virtual_tlb_callback(uc_engine *uc, uint64_t addr, uc_mem_type type, uc_tlb_entry *result, void *user_data) +static bool virtual_tlb_callback(uc_engine *uc, uint64_t addr, uc_mem_type type, + uc_tlb_entry *result, void *user_data) { bool *parrent_done = user_data; printf("tlb lookup for address: 0x%lX\n", addr); @@ -324,20 +333,23 @@ void virtual_tlb(void) exit(1); } - err = uc_hook_add(uc, &h1, UC_HOOK_INSN, &x86_mmu_syscall_callback, &parrent_done, 1, 0, UC_X86_INS_SYSCALL); + err = uc_hook_add(uc, &h1, UC_HOOK_INSN, &x86_mmu_syscall_callback, + &parrent_done, 1, 0, UC_X86_INS_SYSCALL); if (err) { printf("Failed on uc_hook_add() with error returned: %u\n", err); exit(1); } - // Memory hooks are called after the mmu translation, so hook the physicall addresses - err = uc_hook_add(uc, &h2, UC_HOOK_MEM_WRITE, &mmu_write_callback, NULL, 0x1000, 0x3000); + // Memory hooks are called after the mmu translation, so hook the physicall + // addresses + err = uc_hook_add(uc, &h2, UC_HOOK_MEM_WRITE, &mmu_write_callback, NULL, + 0x1000, 0x3000); if (err) { printf("Faled on uc_hook_add() with error returned: %u\n", err); } printf("map code\n"); - err = uc_mem_map(uc, 0x0, 0x1000, UC_PROT_ALL); //Code + err = uc_mem_map(uc, 0x0, 0x1000, UC_PROT_ALL); // Code if (err) { printf("Failed on uc_mem_map() with error return: %u\n", err); exit(1); @@ -348,19 +360,20 @@ void virtual_tlb(void) exit(1); } printf("map parrent memory\n"); - err = uc_mem_map(uc, 0x1000, 0x1000, UC_PROT_ALL); //Parrent + err = uc_mem_map(uc, 0x1000, 0x1000, UC_PROT_ALL); // Parrent if (err) { printf("Failed on uc_mem_map() with error return: %u\n", err); exit(1); } printf("map child memory\n"); - err = uc_mem_map(uc, 0x2000, 0x1000, UC_PROT_ALL); //Child + err = uc_mem_map(uc, 0x2000, 0x1000, UC_PROT_ALL); // Child if (err) { printf("failed to map child memory\n"); exit(1); } - err = uc_hook_add(uc, &h3, UC_HOOK_TLB_FILL, virtual_tlb_callback, &parrent_done, 1, 0); + err = uc_hook_add(uc, &h3, UC_HOOK_TLB_FILL, virtual_tlb_callback, + &parrent_done, 1, 0); printf("run the parrent\n"); err = uc_emu_start(uc, 0x2000, 0x0, 0, 0); diff --git a/samples/sample_riscv.c b/samples/sample_riscv.c index 6e36f53a..4096d83b 100644 --- a/samples/sample_riscv.c +++ b/samples/sample_riscv.c @@ -11,7 +11,7 @@ $ cstool riscv64 1305100093850502 0 13 05 10 00 addi a0, zero, 1 4 93 85 05 02 addi a1, a1, 0x20 #endif -//#define RISCV_CODE "\x13\x05\x10\x00\x93\x85\x05\x02\x93\x85\x05\x02" +// #define RISCV_CODE "\x13\x05\x10\x00\x93\x85\x05\x02\x93\x85\x05\x02" #define RISCV_CODE "\x13\x05\x10\x00\x93\x85\x05\x02" // memory address where emulation starts diff --git a/samples/sample_sparc.c b/samples/sample_sparc.c index f7609282..dd847142 100644 --- a/samples/sample_sparc.c +++ b/samples/sample_sparc.c @@ -8,7 +8,7 @@ // code to be emulated #define SPARC_CODE "\x86\x00\x40\x02" // add %g1, %g2, %g3; -//#define SPARC_CODE "\xbb\x70\x00\x00" // illegal code +// #define SPARC_CODE "\xbb\x70\x00\x00" // illegal code // memory address where emulation starts #define ADDRESS 0x10000 diff --git a/samples/sample_x86.c b/samples/sample_x86.c index d8500cc4..735a9985 100644 --- a/samples/sample_x86.c +++ b/samples/sample_x86.c @@ -13,7 +13,7 @@ "\xeb\x02\x90\x90\x90\x90\x90\x90" // jmp 4; nop; nop; nop; nop; nop; nop // #define X86_CODE32_SELF // "\xeb\x1c\x5a\x89\xd6\x8b\x02\x66\x3d\xca\x7d\x75\x06\x66\x05\x03\x03\x89\x02\xfe\xc2\x3d\x41\x41\x41\x41\x75\xe9\xff\xe6\xe8\xdf\xff\xff\xff\x31\xd2\x6a\x0b\x58\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xca\x7d\x41\x41\x41\x41" -//#define X86_CODE32 "\x51\x51\x51\x51" // PUSH ecx; +// #define X86_CODE32 "\x51\x51\x51\x51" // PUSH ecx; #define X86_CODE32_LOOP "\x41\x4a\xeb\xfe" // INC ecx; DEC edx; JMP self-loop #define X86_CODE32_MEM_WRITE \ "\x89\x0D\xAA\xAA\xAA\xAA\x41\x4a" // mov [0xaaaaaaaa], ecx; INC ecx; DEC @@ -30,7 +30,7 @@ // AL; INC ebx #define X86_CODE32_INC "\x40" // INC eax -//#define X86_CODE64 "\x41\xBC\x3B\xB0\x28\x2A \x49\x0F\xC9 \x90 +// #define X86_CODE64 "\x41\xBC\x3B\xB0\x28\x2A \x49\x0F\xC9 \x90 //\x4D\x0F\xAD\xCF\x49\x87\xFD\x90\x48\x81\xD2\x8A\xCE\x77\x35\x48\xF7\xD9" // //<== still crash #define X86_CODE64 //"\x41\xBC\x3B\xB0\x28\x2A\x49\x0F\xC9\x90\x4D\x0F\xAD\xCF\x49\x87\xFD\x90\x48\x81\xD2\x8A\xCE\x77\x35\x48\xF7\xD9" diff --git a/symbols.sh b/symbols.sh index cbf5f0db..e038b46f 100755 --- a/symbols.sh +++ b/symbols.sh @@ -5,6 +5,9 @@ SOURCE_DIR=$(dirname ${CMD_PATH}) COMMON_SYMBOLS=" unicorn_fill_tlb \ +reg_read \ +reg_write \ +uc_init \ uc_add_inline_hook \ uc_del_inline_hook \ tb_invalidate_phys_range \ @@ -120,7 +123,10 @@ cpu_inl \ memory_map \ memory_map_io \ memory_map_ptr \ +memory_cow \ memory_unmap \ +memory_moveout \ +memory_movein \ memory_free \ flatview_unref \ address_space_get_flatview \ @@ -139,7 +145,9 @@ memory_region_from_host \ memory_region_get_ram_addr \ memory_region_add_subregion \ memory_region_del_subregion \ +memory_region_add_subregion_overlap \ memory_region_find \ +memory_region_filter_subregions \ memory_listener_register \ memory_listener_unregister \ address_space_remove_listeners \ @@ -147,6 +155,7 @@ address_space_init \ address_space_destroy \ memory_region_init_ram \ memory_mapping_list_add_merge_sorted \ +find_memory_mapping \ exec_inline_op \ floatx80_default_nan \ float_raise \ @@ -1882,9 +1891,6 @@ x86_cpu_xsave_all_areas \ x86_cpu_xrstor_all_areas \ cpu_get_fp80 \ cpu_set_fp80 \ -x86_reg_reset \ -x86_reg_read \ -x86_reg_write \ " arm_SYMBOLS=" @@ -2580,9 +2586,6 @@ helper_frint64_s \ helper_frint32_d \ helper_frint64_d \ helper_check_hcr_el2_trap \ -arm_reg_reset \ -arm_reg_read \ -arm_reg_write \ mla_op \ mls_op \ sshl_op \ @@ -4280,9 +4283,6 @@ helper_frint64_s \ helper_frint32_d \ helper_frint64_d \ helper_check_hcr_el2_trap \ -arm64_reg_reset \ -arm64_reg_read \ -arm64_reg_write \ mla_op \ mls_op \ sshl_op \ @@ -4385,9 +4385,6 @@ gen_intermediate_code \ riscv_translate_init \ restore_state_to_opc \ cpu_riscv_init \ -riscv_reg_reset \ -riscv_reg_read \ -riscv_reg_write \ helper_fcvt_l_s \ helper_fcvt_lu_s \ helper_fcvt_s_l \ @@ -5511,9 +5508,6 @@ mips_tcg_init \ cpu_mips_realize_env \ cpu_state_reset \ restore_state_to_opc \ -mips_reg_reset \ -mips_reg_read \ -mips_reg_write \ ieee_rm \ mips_defs \ mips_defs_number \ @@ -5665,9 +5659,6 @@ helper_wrpstate \ helper_wrpil \ helper_done \ helper_retry \ -sparc_reg_reset \ -sparc_reg_read \ -sparc_reg_write \ " sparc64_SYMBOLS=${sparc_SYMBOLS} @@ -5828,17 +5819,11 @@ m68k_tcg_init \ register_m68k_insns \ gen_intermediate_code \ restore_state_to_opc \ -m68k_reg_reset \ -m68k_reg_read \ -m68k_reg_write \ " ppc_SYMBOLS=" ppc_cpu_unrealize \ ppc_cpu_instance_finalize \ -ppc_reg_reset \ -ppc_reg_read \ -ppc_reg_write \ ppc_cpu_do_interrupt \ ppc_cpu_do_system_reset \ ppc_cpu_do_fwnmi_machine_check \ diff --git a/tests/benchmarks/cow/Makefile b/tests/benchmarks/cow/Makefile new file mode 100644 index 00000000..3c4bb8ce --- /dev/null +++ b/tests/benchmarks/cow/Makefile @@ -0,0 +1,24 @@ +CFLAGS += -Wall -Werror -I../../../include +CFLAGS += -D__USE_MINGW_ANSI_STDIO=1 +LDLIBS += -L../../../build -lgsl -lgslcblas -lm -lunicorn + +UNAME_S := $(shell uname -s) +LDLIBS += -pthread +ifeq ($(UNAME_S), Linux) +LDLIBS += -lrt +endif + +#EXECUTE_VARS = LD_LIBRARY_PATH=../../cmocka/src:../../build/ DYLD_LIBRARY_PATH=../../build/ +EXECUTE_VARS = LD_LIBRARY_PATH=../../../build/cmocka/src:../../../build/ DYLD_LIBRARY_PATH=../../../build/ + +TESTS_SOURCE = $(wildcard *.c) +TESTS = $(TESTS_SOURCE:%.c=%) + +.PHONY: all clean test + +test: $(TESTS) + +all: $(TESTS) + +clean: + rm -f $(TESTS) diff --git a/tests/benchmarks/cow/benchmark.c b/tests/benchmarks/cow/benchmark.c new file mode 100644 index 00000000..327886ce --- /dev/null +++ b/tests/benchmarks/cow/benchmark.c @@ -0,0 +1,186 @@ +#include +#include +#include +#include +#include +#include +#include + +struct data { + gsl_rstat_workspace *rstat_p; + struct timespec start; +}; + + +void update_stats(gsl_rstat_workspace *rstat_p, struct timespec *start, struct timespec *end) +{ + double dur = (end->tv_sec - start->tv_sec) * 1000.0; + dur += (end->tv_nsec - start->tv_nsec) / 1000000.0; + gsl_rstat_add(dur, rstat_p); +} + +static uint64_t CODEADDR = 0x1000; +static uint64_t DATABASE = 0x40000000; +static uint64_t BLOCKSIZE = 0x10000; + +/*static void callback_mem(uc_engine *uc, uc_mem_type type, uint64_t addr, uint32_t size, uint64_t value, void *data) +{ + printf("callback mem valid: 0x%lX, value: 0x%lX\n", addr, value); +}*/ +static int callback_mem_prot(uc_engine *uc, uc_mem_type type, uint64_t addr, uint32_t size, int64_t value, void *data) +{ + printf("callback mem prot: 0x%lX, type: %X\n", addr, type); + return false; +} + +static void callback_block(uc_engine *uc, uint64_t addr, uint32_t size, void *data) +{ + struct timespec now; + struct data *d = data; + size_t run; + uint64_t rax = 512; + uint64_t rbx = DATABASE; + uint64_t rsi; + long memblock; + long offset; + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &now); + if (d->rstat_p) { + update_stats(d->rstat_p, &d->start, &now); + } else { + d->rstat_p = gsl_rstat_alloc(); + } + run = gsl_rstat_n(d->rstat_p); + if ((run >> 4) >= 20) { + uc_emu_stop(uc); + return; + } else if (run > 0 && run % 16 == 0) { + uc_snapshot(uc); + } +/* if (run > 0 && run % 16 == 0) { + uc_emu_stop(uc); + return; + }*/ + rsi = random(); + memblock = random() & 15; + offset = random() & (BLOCKSIZE - 1) & (~0xf); +// memblock = 0; +// offset = 0; + if (memblock == 15 && (offset + 0x1000) > BLOCKSIZE) { + offset -= 0x1000; + } + rbx += (memblock * BLOCKSIZE) + offset; + printf("write at 0x%lX\n", rbx); + printf("[%li] callback block: 0x%lX\n", run, addr); + uc_reg_write(uc, UC_X86_REG_RBX, &rbx); + uc_reg_write(uc, UC_X86_REG_RAX, &rax); + uc_reg_write(uc, UC_X86_REG_RSI, &rsi); + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &d->start); +} + +static void prepare_mapping(uc_engine *uc) +{ + for (size_t i = 0; i < 16; i++) { + printf("mem map: 0x%lX\n", DATABASE+i*BLOCKSIZE); + uc_mem_map(uc, DATABASE+i*BLOCKSIZE, BLOCKSIZE, UC_PROT_READ|UC_PROT_WRITE); + } +} + +static void prepare_code(uc_engine *uc, const char *file, void **addr) +{ + uc_err err; + int fd; + fd = open(file, O_RDONLY, 0); + if (fd == -1) { + perror("open"); + exit(1); + } + *addr = mmap(*addr, 0x1000, PROT_READ, MAP_PRIVATE, fd, 0); + if (addr == MAP_FAILED) { + perror("mmap"); + exit(1); + } + err = uc_mem_map_ptr(uc, CODEADDR, 0x1000, UC_PROT_READ|UC_PROT_EXEC, *addr); + close(fd); + if (err != UC_ERR_OK) { + printf("err: %s\n", uc_strerror(err)); + exit(1); + } + printf("mapped %s\n", file); + return; +} + +void print_stats(gsl_rstat_workspace *rstat_p) +{ + double mean, variance, largest, smallest, sd, + rms, sd_mean, median, skew, kurtosis; + size_t n; + + mean = gsl_rstat_mean(rstat_p); + variance = gsl_rstat_variance(rstat_p); + largest = gsl_rstat_max(rstat_p); + smallest = gsl_rstat_min(rstat_p); + median = gsl_rstat_median(rstat_p); + sd = gsl_rstat_sd(rstat_p); + sd_mean = gsl_rstat_sd_mean(rstat_p); + skew = gsl_rstat_skew(rstat_p); + rms = gsl_rstat_rms(rstat_p); + kurtosis = gsl_rstat_kurtosis(rstat_p); + n = gsl_rstat_n(rstat_p); + + printf ("The sample mean is %g\n", mean); + printf ("The estimated variance is %g\n", variance); + printf ("The largest value is %g\n", largest); + printf ("The smallest value is %g\n", smallest); + printf( "The median is %g\n", median); + printf( "The standard deviation is %g\n", sd); + printf( "The root mean square is %g\n", rms); + printf( "The standard devation of the mean is %g\n", sd_mean); + printf( "The skew is %g\n", skew); + printf( "The kurtosis %g\n", kurtosis); + printf( "There are %zu items in the accumulator\n", n); +} +int main(int argc, char *argv[]) +{ + uc_engine *uc; + uc_err err; + uc_hook hook_block; + uc_hook hook_mem; + struct data d; + uint64_t rax = 5; + uint64_t rbx = DATABASE; + void *bin_mmap = NULL; + + if (argc != 2) { + fprintf(stderr, "usage: %s binary\n", argv[0]); + return 1; + } + + d.rstat_p = NULL; + srandom(time(NULL)); + + uc_open(UC_ARCH_X86, UC_MODE_64, &uc); + prepare_code(uc, argv[1], &bin_mmap); + prepare_mapping(uc); + err = uc_hook_add(uc, &hook_block, UC_HOOK_BLOCK, &callback_block, &d, CODEADDR, 0x1000); + if (err != UC_ERR_OK) { + return 1; + } + uc_hook_add(uc, &hook_mem, UC_HOOK_MEM_INVALID, &callback_mem_prot, NULL, CODEADDR, 0x1000); + uc_reg_write(uc, UC_X86_REG_RBX, &rbx); + uc_reg_write(uc, UC_X86_REG_RAX, &rax); +/* err = uc_hook_add(uc, &hook_mem, UC_HOOK_MEM_VALID, &callback_mem, NULL, DATABASE, 16*BLOCKSIZE); + if (err) { + printf("err: %s\n", uc_strerror(err)); + return 1; + }*/ + for (int i = 0; i < 1; i++) { + err = uc_emu_start(uc, CODEADDR, -1, 0, 0); + if (err) { + printf("err: %s\n", uc_strerror(err)); + return 1; + } + uc_snapshot(uc); + } + print_stats(d.rstat_p); + return 0; +} diff --git a/tests/benchmarks/cow/binary.S b/tests/benchmarks/cow/binary.S new file mode 100644 index 00000000..1705535c --- /dev/null +++ b/tests/benchmarks/cow/binary.S @@ -0,0 +1,13 @@ +USE64 +DEFAULT REL + +SECTION .text +loop: + xor rcx, rcx +write: + mov [rbx+rcx*8], rsi + inc rcx + mov rdi, rax + sub rdi, rcx + jnz write + jmp loop diff --git a/tests/regress/emu_stop_in_hook_overrun.c b/tests/regress/emu_stop_in_hook_overrun.c index 81ea93fd..3783ffae 100644 --- a/tests/regress/emu_stop_in_hook_overrun.c +++ b/tests/regress/emu_stop_in_hook_overrun.c @@ -9,16 +9,12 @@ Test for uc_emu_stop() in code hook not always stopping the emu at the current i #include #include #define PRIx64 "llX" -#ifdef DYNLOAD -#include -#else // DYNLOAD #include #ifdef _WIN64 #pragma comment(lib, "unicorn_staload64.lib") #else // _WIN64 #pragma comment(lib, "unicorn_staload.lib") #endif // _WIN64 -#endif // DYNLOAD // posix specific #else // _MSC_VER @@ -61,11 +57,6 @@ int main(int argc, char **argv, char **envp) uc_hook hhc; uint32_t val; - // dynamically load shared library -#ifdef DYNLOAD - uc_dyn_load(NULL, 0); -#endif - // Initialize emulator in MIPS 32bit little endian mode printf("uc_open()\n"); err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32, &uc); @@ -120,11 +111,6 @@ int main(int argc, char **argv, char **envp) else printf("\n\nTEST FAILED!\n\n"); - // dynamically free shared library -#ifdef DYNLOAD - uc_dyn_free(); -#endif - return 0; } diff --git a/tests/regress/mips_branch_likely_issue.c b/tests/regress/mips_branch_likely_issue.c index 6da33ced..dbbf10d9 100644 --- a/tests/regress/mips_branch_likely_issue.c +++ b/tests/regress/mips_branch_likely_issue.c @@ -9,16 +9,12 @@ #include #include #define PRIx64 "llX" -#ifdef DYNLOAD -#include -#else // DYNLOAD #include #ifdef _WIN64 #pragma comment(lib, "unicorn_staload64.lib") #else // _WIN64 #pragma comment(lib, "unicorn_staload.lib") #endif // _WIN64 -#endif // DYNLOAD // posix specific #else // _MSC_VER @@ -80,11 +76,6 @@ int main(int argc, char **argv, char **envp) uc_hook hhc; uint32_t val; - // dynamically load shared library -#ifdef DYNLOAD - uc_dyn_load(NULL, 0); -#endif - // Initialize emulator in MIPS 32bit little endian mode printf("uc_open()\n"); err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32, &uc); @@ -184,12 +175,6 @@ int main(int argc, char **argv, char **envp) else printf("TEST 2 FAILED!\n\n"); - - // dynamically free shared library -#ifdef DYNLOAD - uc_dyn_free(); -#endif - return 0; } diff --git a/tests/regress/mips_delay_slot_code_hook.c b/tests/regress/mips_delay_slot_code_hook.c index 4a407aec..e5452e6d 100644 --- a/tests/regress/mips_delay_slot_code_hook.c +++ b/tests/regress/mips_delay_slot_code_hook.c @@ -14,16 +14,12 @@ but that the code hook is just not occurring. #include #include #define PRIx64 "llX" -#ifdef DYNLOAD -#include -#else // DYNLOAD #include #ifdef _WIN64 #pragma comment(lib, "unicorn_staload64.lib") #else // _WIN64 #pragma comment(lib, "unicorn_staload.lib") #endif // _WIN64 -#endif // DYNLOAD // posix specific #else // _MSC_VER @@ -68,11 +64,6 @@ int main(int argc, char **argv, char **envp) uc_hook hhc; uint32_t val; - // dynamically load shared library -#ifdef DYNLOAD - uc_dyn_load(NULL, 0); -#endif - // Initialize emulator in MIPS 32bit little endian mode err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32, &uc); if (err) @@ -128,11 +119,6 @@ int main(int argc, char **argv, char **envp) else printf("\n\nTEST FAILED!\n\n"); - // dynamically free shared library -#ifdef DYNLOAD - uc_dyn_free(); -#endif - return 0; } diff --git a/tests/regress/threaded_emu_start.c b/tests/regress/threaded_emu_start.c index 05776d7a..9301803d 100644 --- a/tests/regress/threaded_emu_start.c +++ b/tests/regress/threaded_emu_start.c @@ -20,16 +20,12 @@ background. #include #include #define PRIx64 "llX" -#ifdef DYNLOAD -#include -#else // DYNLOAD #include #ifdef _WIN64 #pragma comment(lib, "unicorn_staload64.lib") #else // _WIN64 #pragma comment(lib, "unicorn_staload.lib") #endif // _WIN64 -#endif // DYNLOAD // posix specific #else // _MSC_VER @@ -128,11 +124,6 @@ int main(int argc, char **argv, char **envp) pthread_t th; #endif - // dynamically load shared library -#ifdef DYNLOAD - uc_dyn_load(NULL, 0); -#endif - // Initialize emulator in MIPS 32bit little endian mode printf("uc_open()\n"); err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32, &uc); @@ -231,11 +222,6 @@ int main(int argc, char **argv, char **envp) else printf("\n\nTEST FAILED!\n\n"); - // dynamically free shared library -#ifdef DYNLOAD - uc_dyn_free(); -#endif - return 0; } diff --git a/tests/rust-tests/main.rs b/tests/rust-tests/main.rs index b64b6aa6..1267b86f 100644 --- a/tests/rust-tests/main.rs +++ b/tests/rust-tests/main.rs @@ -3,7 +3,7 @@ extern crate alloc; use alloc::rc::Rc; use core::cell::RefCell; use unicorn_engine::unicorn_const::{ - uc_error, Arch, HookType, MemType, Mode, Permission, SECOND_SCALE, + uc_error, Arch, HookType, MemType, Mode, Permission, SECOND_SCALE, TlbEntry, TlbType }; use unicorn_engine::{InsnSysX86, RegisterARM, RegisterMIPS, RegisterPPC, RegisterX86, Unicorn}; @@ -772,3 +772,46 @@ fn x86_block_callback() { assert_eq!(expects, *blocks_cell.borrow()); assert_eq!(emu.remove_hook(hook), Ok(())); } + +#[test] +fn x86_tlb_callback() { + #[derive(PartialEq, Debug)] + struct BlockExpectation(u64, u32); + let expects:u64 = 4; + let count: u64 = 0; + let count_cell = Rc::new(RefCell::new(count)); + + let callback_counter = count_cell.clone(); + let tlb_callback = move |_: &mut Unicorn<'_, ()>, address: u64, _: MemType| -> Option { + let mut blocks = callback_counter.borrow_mut(); + *blocks += 1; + return Some(TlbEntry{paddr: address, perms: Permission::ALL}); + }; + + let syscall_callback = move |uc: &mut Unicorn<'_, ()>| { + assert_eq!(uc.ctl_flush_tlb(), Ok(())); + }; + + let code: Vec = vec![0xa3,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x0f,0x05,0xa3,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x00]; // movabs dword ptr [0x200000], eax; syscall; movabs dword ptr [0x200000], eax + + let mut emu = unicorn_engine::Unicorn::new(Arch::X86, Mode::MODE_64) + .expect("failed to initialize unicorn instance"); + assert_eq!(emu.ctl_tlb_type(TlbType::VIRTUAL), Ok(())); + assert_eq!(emu.mem_map(0x1000, 0x1000, Permission::ALL), Ok(())); + assert_eq!(emu.mem_map(0x200000, 0x1000, Permission::ALL), Ok(())); + assert_eq!(emu.mem_write(0x1000, &code), Ok(())); + + let tlb_hook = emu + .add_tlb_hook(0, !0u64, tlb_callback) + .expect("failed to add tlb hook"); + let syscall_hook = emu + .add_insn_sys_hook(InsnSysX86::SYSCALL, 0, !0u64, syscall_callback) + .expect("failed to add syscall hook"); + assert_eq!( + emu.emu_start(0x1000, (0x1000 + code.len()) as u64, 0, 0), + Ok(()) + ); + assert_eq!(expects, *count_cell.borrow()); + assert_eq!(emu.remove_hook(tlb_hook), Ok(())); + assert_eq!(emu.remove_hook(syscall_hook), Ok(())); +} diff --git a/tests/unit/acutest.h b/tests/unit/acutest.h index fbe55bc2..8ec7d989 100644 --- a/tests/unit/acutest.h +++ b/tests/unit/acutest.h @@ -270,7 +270,8 @@ #include #include -#if defined(unix) || defined(__unix__) || defined(__unix) || defined(__APPLE__) || defined(__HAIKU__) +#if defined(unix) || defined(__unix__) || defined(__unix) || \ + defined(__APPLE__) || defined(__HAIKU__) #define ACUTEST_UNIX_ 1 #include #include diff --git a/tests/unit/endian.h b/tests/unit/endian.h index a028be75..b42da241 100644 --- a/tests/unit/endian.h +++ b/tests/unit/endian.h @@ -32,53 +32,47 @@ // GNU libc offers the helpful header which defines // __BYTE_ORDER -#if defined (__GLIBC__) -# include -# if (__BYTE_ORDER == __LITTLE_ENDIAN) -# define BOOST_LITTLE_ENDIAN -# elif (__BYTE_ORDER == __BIG_ENDIAN) -# define BOOST_BIG_ENDIAN -# elif (__BYTE_ORDER == __PDP_ENDIAN) -# define BOOST_PDP_ENDIAN -# else +#if defined(__GLIBC__) +#include +#if (__BYTE_ORDER == __LITTLE_ENDIAN) +#define BOOST_LITTLE_ENDIAN +#elif (__BYTE_ORDER == __BIG_ENDIAN) +#define BOOST_BIG_ENDIAN +#elif (__BYTE_ORDER == __PDP_ENDIAN) +#define BOOST_PDP_ENDIAN +#else // Failsafe -# define BOOST_LITTLE_ENDIAN -# endif -# define BOOST_BYTE_ORDER __BYTE_ORDER +#define BOOST_LITTLE_ENDIAN +#endif +#define BOOST_BYTE_ORDER __BYTE_ORDER #elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN) -# define BOOST_BIG_ENDIAN -# define BOOST_BYTE_ORDER 4321 +#define BOOST_BIG_ENDIAN +#define BOOST_BYTE_ORDER 4321 #elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) -# define BOOST_LITTLE_ENDIAN -# define BOOST_BYTE_ORDER 1234 +#define BOOST_LITTLE_ENDIAN +#define BOOST_BYTE_ORDER 1234 // https://developer.arm.com/documentation/dui0491/i/Compiler-specific-Features/Predefined-macros -#elif defined(__sparc) || defined(__sparc__) \ - || defined(_POWER) || defined(__powerpc__) \ - || defined(__ppc__) || defined(__hpux) || defined(__hppa) \ - || defined(_MIPSEB) || defined(_POWER) \ - || defined(__s390__) \ - || defined(__ARMEB__) || defined(__AARCH64EB__) \ - || defined(__BIG_ENDIAN) || defined(__ARM_BIG_ENDIAN) -# define BOOST_BIG_ENDIAN -# define BOOST_BYTE_ORDER 4321 -#elif defined(__i386__) || defined(__alpha__) \ - || defined(__ia64) || defined(__ia64__) \ - || defined(_M_IX86) || defined(_M_IA64) \ - || defined(_M_ALPHA) || defined(__amd64) \ - || defined(__amd64__) || defined(_M_AMD64) \ - || defined(__x86_64) || defined(__x86_64__) \ - || defined(_M_X64) || defined(__bfin__) \ - || defined(__ARMEL__) || defined(__AARCH64EL__) \ - || defined(__arm64__) || defined(__arm__) -# define BOOST_LITTLE_ENDIAN -# define BOOST_BYTE_ORDER 1234 +#elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || \ + defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || \ + defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || \ + defined(__s390__) || defined(__ARMEB__) || defined(__AARCH64EB__) || \ + defined(__BIG_ENDIAN) || defined(__ARM_BIG_ENDIAN) +#define BOOST_BIG_ENDIAN +#define BOOST_BYTE_ORDER 4321 +#elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || \ + defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || \ + defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || \ + defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || \ + defined(_M_X64) || defined(__bfin__) || defined(__ARMEL__) || \ + defined(__AARCH64EL__) || defined(__arm64__) || defined(__arm__) +#define BOOST_LITTLE_ENDIAN +#define BOOST_BYTE_ORDER 1234 #else // Failsafe -# define BOOST_LITTLE_ENDIAN -# define BOOST_BYTE_ORDER 1234 +#define BOOST_LITTLE_ENDIAN +#define BOOST_BYTE_ORDER 1234 #endif - #endif diff --git a/tests/unit/test_arm64.c b/tests/unit/test_arm64.c index 8a03945c..e016dc82 100644 --- a/tests/unit/test_arm64.c +++ b/tests/unit/test_arm64.c @@ -2,6 +2,7 @@ #include "unicorn/unicorn.h" #include "unicorn_test.h" #include +#include #include const uint64_t code_start = 0x1000; @@ -379,7 +380,8 @@ static void test_arm64_mmu(void) char tlbe[8]; uint64_t x0, x1, x2; /* - * Not exact the binary, but aarch64-linux-gnu-as generate this code and reference sometimes data after ttb0_base. + * Not exact the binary, but aarch64-linux-gnu-as generate this code and + reference sometimes data after ttb0_base. * // Read data from physical address * ldr X0, =0x40000000 * ldr X1, [X0] @@ -401,16 +403,21 @@ static void test_arm64_mmu(void) * orr X0, X0, #0x1 // The M bit (MMU). * msr SCTLR_EL1, X0 * dsb SY - * isb + * isb * // Read the same memory area through virtual address * ldr X0, =0x80000000 * ldr X2, [X0] * * // Stop - * b . + * b . */ - char code[] = "\x00\x81\x00\x58\x01\x00\x40\xf9\x00\x81\x00\x58\x40\x20\x18\xd5\x00\x81\x00\x58\x00\xa2\x18\xd5\x40\x7f\x00\x10\x00\x20\x18\xd5\x00\x10\x38\xd5\x00\x00\x7e\xb2\x00\x00\x74\xb2\x00\x00\x40\xb2\x00\x10\x18\xd5\x9f\x3f\x03\xd5\xdf\x3f\x03\xd5\xe0\x7f\x00\x58\x02\x00\x40\xf9\x00\x00\x00\x14\x1f\x20\x03\xd5\x1f\x20\x03\xd5\x1F\x20\x03\xD5\x1F\x20\x03\xD5"; + char code[] = "\x00\x81\x00\x58\x01\x00\x40\xf9\x00\x81\x00\x58\x40\x20\x18" + "\xd5\x00\x81\x00\x58\x00\xa2\x18\xd5\x40\x7f\x00\x10\x00\x20" + "\x18\xd5\x00\x10\x38\xd5\x00\x00\x7e\xb2\x00\x00\x74\xb2\x00" + "\x00\x40\xb2\x00\x10\x18\xd5\x9f\x3f\x03\xd5\xdf\x3f\x03\xd5" + "\xe0\x7f\x00\x58\x02\x00\x40\xf9\x00\x00\x00\x14\x1f\x20\x03" + "\xd5\x1f\x20\x03\xd5\x1F\x20\x03\xD5\x1F\x20\x03\xD5"; data = malloc(0x1000); TEST_CHECK(data != NULL); @@ -435,7 +442,7 @@ static void test_arm64_mmu(void) OK(uc_mem_write(uc, 0x1010, tlbe, sizeof(tlbe))); OK(uc_mem_write(uc, 0x1018, tlbe, sizeof(tlbe))); - //mentioned data referenced by the asm generated my aarch64-linux-gnu-as + // mentioned data referenced by the asm generated my aarch64-linux-gnu-as tlbe[0] = 0; tlbe[1] = 0; OK(uc_mem_write(uc, 0x1020, tlbe, sizeof(tlbe))); @@ -473,6 +480,55 @@ static void test_arm64_mmu(void) free(data); } +static void test_arm64_pc_wrap(void) +{ + uc_engine *uc; + // add x1 x2 + char add_x1_x2[] = "\x20\x00\x02\x8b"; + // add x1 x3 + char add_x1_x3[] = "\x20\x00\x03\x8b"; + uint64_t x0, x1, x2, x3; + uint64_t pc = 0xFFFFFFFFFFFFFFFCULL; + uint64_t page = 0xFFFFFFFFFFFFF000ULL; + + OK(uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc)); + OK(uc_mem_map(uc, page, 4096, UC_PROT_READ | UC_PROT_EXEC)); + OK(uc_mem_write(uc, pc, add_x1_x2, sizeof(add_x1_x2) - 1)); + + x1 = 1; + x2 = 2; + OK(uc_reg_write(uc, UC_ARM64_REG_X1, &x1)); + OK(uc_reg_write(uc, UC_ARM64_REG_X2, &x2)); + + OK(uc_emu_start(uc, pc, pc + 4, 0, 1)); + + OK(uc_mem_unmap(uc, page, 4096)); + + OK(uc_reg_read(uc, UC_ARM64_REG_X0, &x0)); + + TEST_CHECK((x0 == 1 + 2)); + + OK(uc_mem_map(uc, page, 4096, UC_PROT_READ | UC_PROT_EXEC)); + OK(uc_mem_write(uc, pc, add_x1_x3, sizeof(add_x1_x3) - 1)); + + x1 = 5; + x2 = 0; + x3 = 5; + OK(uc_reg_write(uc, UC_ARM64_REG_X1, &x1)); + OK(uc_reg_write(uc, UC_ARM64_REG_X2, &x2)); + OK(uc_reg_write(uc, UC_ARM64_REG_X3, &x3)); + + OK(uc_emu_start(uc, pc, pc + 4, 0, 1)); + + OK(uc_mem_unmap(uc, page, 4096)); + + OK(uc_reg_read(uc, UC_ARM64_REG_X0, &x0)); + + TEST_CHECK((x0 == 5 + 5)); + + OK(uc_close(uc)); +} + TEST_LIST = {{"test_arm64_until", test_arm64_until}, {"test_arm64_code_patching", test_arm64_code_patching}, {"test_arm64_code_patching_count", test_arm64_code_patching_count}, @@ -486,5 +542,6 @@ TEST_LIST = {{"test_arm64_until", test_arm64_until}, {"test_arm64_block_sync_pc", test_arm64_block_sync_pc}, {"test_arm64_block_invalid_mem_read_write_sync", test_arm64_block_invalid_mem_read_write_sync}, - {"test_arm64_mmu", test_arm64_mmu}, + {"test_arm64_mmu", test_arm64_mmu}, + {"test_arm64_pc_wrap", test_arm64_pc_wrap}, {NULL, NULL}}; diff --git a/tests/unit/test_ctl.c b/tests/unit/test_ctl.c index 9cfcd7dd..795d0fe9 100644 --- a/tests/unit/test_ctl.c +++ b/tests/unit/test_ctl.c @@ -304,7 +304,8 @@ static void test_uc_hook_cached_uaf(void) #endif } -static void test_uc_emu_stop_set_ip_callback(uc_engine *uc, uint64_t address, uint32_t size, void *userdata) +static void test_uc_emu_stop_set_ip_callback(uc_engine *uc, uint64_t address, + uint32_t size, void *userdata) { uint64_t rip = code_start + 0xb; @@ -320,27 +321,31 @@ static void test_uc_emu_stop_set_ip(void) uc_hook h; uint64_t rip; - char code[] = "\x48\x31\xc0" // 0x0 xor rax, rax : rax = 0 - "\x90" // 0x3 nop : - "\x48\xff\xc0" // 0x4 inc rax : rax++ - "\x90" // 0x7 nop : <-- going to stop here - "\x48\xff\xc0" // 0x8 inc rax : rax++ - "\x90" // 0xb nop : - "\x0f\x0b" // 0xc ud2 : <-- will raise UC_ERR_INSN_INVALID, but should not never be reached - "\x90" // 0xe nop : - "\x90"; // 0xf nop : + char code[] = + "\x48\x31\xc0" // 0x0 xor rax, rax : rax = 0 + "\x90" // 0x3 nop : + "\x48\xff\xc0" // 0x4 inc rax : rax++ + "\x90" // 0x7 nop : <-- going to stop here + "\x48\xff\xc0" // 0x8 inc rax : rax++ + "\x90" // 0xb nop : + "\x0f\x0b" // 0xc ud2 : <-- will raise + // UC_ERR_INSN_INVALID, but should not never be reached + "\x90" // 0xe nop : + "\x90"; // 0xf nop : uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_64, code, sizeof(code) - 1); - OK(uc_hook_add(uc, &h, UC_HOOK_CODE, test_uc_emu_stop_set_ip_callback, NULL, 1, 0)); + OK(uc_hook_add(uc, &h, UC_HOOK_CODE, test_uc_emu_stop_set_ip_callback, NULL, + 1, 0)); OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); OK(uc_reg_read(uc, UC_X86_REG_RIP, &rip)); TEST_CHECK(rip == code_start + 0xb); OK(uc_close(uc)); } -static bool test_tlb_clear_tlb(uc_engine *uc, uint64_t addr, uc_mem_type type, uc_tlb_entry *result, void *user_data) +static bool test_tlb_clear_tlb(uc_engine *uc, uint64_t addr, uc_mem_type type, + uc_tlb_entry *result, void *user_data) { - size_t *tlbcount = (size_t*)user_data; + size_t *tlbcount = (size_t *)user_data; *tlbcount += 1; result->paddr = addr; result->perms = UC_PROT_ALL; @@ -357,14 +362,19 @@ static void test_tlb_clear(void) uc_engine *uc; uc_hook hook1, hook2; size_t tlbcount = 0; - char code[] = "\xa3\x00\x00\x20\x00\x00\x00\x00\x00\x0f\x05\xa3\x00\x00\x20\x00\x00\x00\x00\x00"; //movabs dword ptr [0x200000], eax; syscall; movabs dword ptr [0x200000], eax + char code[] = + "\xa3\x00\x00\x20\x00\x00\x00\x00\x00\x0f\x05\xa3\x00\x00\x20\x00\x00" + "\x00\x00\x00"; // movabs dword ptr [0x200000], eax; syscall; movabs + // dword ptr [0x200000], eax uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_64, code, sizeof(code) - 1); OK(uc_mem_map(uc, 0x200000, 0x1000, UC_PROT_ALL)); OK(uc_ctl_tlb_mode(uc, UC_TLB_VIRTUAL)); - OK(uc_hook_add(uc, &hook1, UC_HOOK_TLB_FILL, test_tlb_clear_tlb, &tlbcount, 1, 0)); - OK(uc_hook_add(uc, &hook2, UC_HOOK_INSN, test_tlb_clear_syscall, NULL, 1, 0, UC_X86_INS_SYSCALL)); + OK(uc_hook_add(uc, &hook1, UC_HOOK_TLB_FILL, test_tlb_clear_tlb, &tlbcount, + 1, 0)); + OK(uc_hook_add(uc, &hook2, UC_HOOK_INSN, test_tlb_clear_syscall, NULL, 1, 0, + UC_X86_INS_SYSCALL)); OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); @@ -373,7 +383,6 @@ static void test_tlb_clear(void) OK(uc_close(uc)); } - TEST_LIST = {{"test_uc_ctl_mode", test_uc_ctl_mode}, {"test_uc_ctl_page_size", test_uc_ctl_page_size}, {"test_uc_ctl_arch", test_uc_ctl_arch}, diff --git a/tests/unit/test_mem.c b/tests/unit/test_mem.c index 4e2f176a..0069c507 100644 --- a/tests/unit/test_mem.c +++ b/tests/unit/test_mem.c @@ -275,6 +275,110 @@ static void test_mem_protect_mmio(void) OK(uc_close(uc)); } +static void test_snapshot(void) +{ + uc_engine *uc; + uc_context *c0, *c1; + uint32_t mem; + // mov eax, [0x2020]; inc eax; mov [0x2020], eax + char code[] = "\xa1\x20\x20\x00\x00\x00\x00\x00\x00\xff\xc0\xa3\x20\x20\x00" + "\x00\x00\x00\x00\x00"; + + OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc)); + OK(uc_context_alloc(uc, &c0)); + OK(uc_context_alloc(uc, &c1)); + OK(uc_ctl_context_mode(uc, UC_CTL_CONTEXT_MEMORY)); + OK(uc_mem_map(uc, 0x1000, 0x1000, UC_PROT_ALL)); + OK(uc_mem_write(uc, 0x1000, code, sizeof(code) - 1)); + + OK(uc_mem_map(uc, 0x2000, 0x1000, UC_PROT_ALL)); + OK(uc_context_save(uc, c0)); + + OK(uc_emu_start(uc, 0x1000, 0x1000 + sizeof(code) - 1, 0, 0)); + OK(uc_mem_read(uc, 0x2020, &mem, sizeof(mem))); + TEST_CHECK(mem == 1); + OK(uc_context_save(uc, c1)); + OK(uc_emu_start(uc, 0x1000, 0x1000 + sizeof(code) - 1, 0, 0)); + OK(uc_mem_read(uc, 0x2020, &mem, sizeof(mem))); + TEST_CHECK(mem == 2); + OK(uc_context_restore(uc, c1)); + //TODO check mem + OK(uc_mem_read(uc, 0x2020, &mem, sizeof(mem))); + TEST_CHECK(mem == 1); + OK(uc_context_restore(uc, c0)); + OK(uc_mem_read(uc, 0x2020, &mem, sizeof(mem))); + TEST_CHECK(mem == 0); + //TODO check mem + + OK(uc_context_free(c0)); + OK(uc_context_free(c1)); + OK(uc_close(uc)); +} + +static void test_context_snapshot(void) +{ + uc_engine *uc; + uc_context *ctx; + uint64_t tmp = 1; + + OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc)); + OK(uc_ctl_context_mode(uc, UC_CTL_CONTEXT_MEMORY|UC_CTL_CONTEXT_CPU)); + OK(uc_mem_map(uc, 0x1000, 0x1000, UC_PROT_ALL)); + OK(uc_context_alloc(uc, &ctx)); + OK(uc_context_save(uc, ctx)); + + OK(uc_mem_write(uc, 0x1000, &tmp, sizeof(tmp))); + OK(uc_mem_read(uc, 0x1000, &tmp, sizeof(tmp))); + TEST_CHECK(tmp == 1); + OK(uc_context_restore(uc, ctx)); + OK(uc_mem_read(uc, 0x1000, &tmp, sizeof(tmp))); + TEST_CHECK(tmp == 0); + + tmp = 2; + OK(uc_mem_write(uc, 0x1000, &tmp, sizeof(tmp))); + OK(uc_mem_read(uc, 0x1000, &tmp, sizeof(tmp))); + TEST_CHECK(tmp == 2); + OK(uc_context_restore(uc, ctx)); + OK(uc_mem_read(uc, 0x1000, &tmp, sizeof(tmp))); + TEST_CHECK(tmp == 0); + + OK(uc_context_free(ctx)); + OK(uc_close(uc)); +} + +static void test_snapshot_unmap(void) +{ + uc_engine *uc; + uc_context *ctx; + uint64_t tmp; + + OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc)); + OK(uc_ctl_context_mode(uc, UC_CTL_CONTEXT_MEMORY|UC_CTL_CONTEXT_CPU)); + OK(uc_mem_map(uc, 0x1000, 0x2000, UC_PROT_ALL)); + + tmp = 1; + OK(uc_mem_write(uc, 0x1000, &tmp, sizeof(tmp))); + tmp = 2; + OK(uc_mem_write(uc, 0x2000, &tmp, sizeof(tmp))); + + OK(uc_context_alloc(uc, &ctx)); + OK(uc_context_save(uc, ctx)); + + uc_assert_err(UC_ERR_ARG, uc_mem_unmap(uc, 0x1000, 0x1000)); + OK(uc_mem_unmap(uc, 0x1000, 0x2000)); + uc_assert_err(UC_ERR_READ_UNMAPPED, uc_mem_read(uc, 0x1000, &tmp, sizeof(tmp))); + uc_assert_err(UC_ERR_READ_UNMAPPED, uc_mem_read(uc, 0x2000, &tmp, sizeof(tmp))); + + OK(uc_context_restore(uc, ctx)); + OK(uc_mem_read(uc, 0x1000, &tmp, sizeof(tmp))); + TEST_CHECK(tmp == 1); + OK(uc_mem_read(uc, 0x2000, &tmp, sizeof(tmp))); + TEST_CHECK(tmp == 2); + + OK(uc_context_free(ctx)); + OK(uc_close(uc)); +} + TEST_LIST = {{"test_map_correct", test_map_correct}, {"test_map_wrapping", test_map_wrapping}, {"test_mem_protect", test_mem_protect}, @@ -286,4 +390,7 @@ TEST_LIST = {{"test_map_correct", test_map_correct}, {"test_map_big_memory", test_map_big_memory}, {"test_mem_protect_remove_exec", test_mem_protect_remove_exec}, {"test_mem_protect_mmio", test_mem_protect_mmio}, + {"test_snapshot", test_snapshot}, + {"test_context_snapshot", test_context_snapshot}, + {"test_snapshot_unmap", test_snapshot_unmap}, {NULL, NULL}}; diff --git a/tests/unit/test_riscv.c b/tests/unit/test_riscv.c index 7c66f89d..880f57c9 100644 --- a/tests/unit/test_riscv.c +++ b/tests/unit/test_riscv.c @@ -222,8 +222,8 @@ static void test_riscv32_fp_move(void) uc_engine *uc; char code[] = "\xd3\x81\x10\x22"; // fmv.d f3, f1 - uint32_t r_f1 = 0x1234; - uint32_t r_f3 = 0x5678; + uint64_t r_f1 = 0x123456781a2b3c4dULL; + uint64_t r_f3 = 0x56780246aaaabbbbULL; uc_common_setup(&uc, UC_ARCH_RISCV, UC_MODE_RISCV32, code, sizeof(code) - 1); @@ -238,8 +238,8 @@ static void test_riscv32_fp_move(void) OK(uc_reg_read(uc, UC_RISCV_REG_F1, &r_f1)); OK(uc_reg_read(uc, UC_RISCV_REG_F3, &r_f3)); - TEST_CHECK(r_f1 == 0x1234); - TEST_CHECK(r_f3 == 0x1234); + TEST_CHECK(r_f1 == 0x123456781a2b3c4dULL); + TEST_CHECK(r_f3 == 0x123456781a2b3c4dULL); uc_close(uc); } @@ -249,8 +249,8 @@ static void test_riscv64_fp_move(void) uc_engine *uc; char code[] = "\xd3\x81\x10\x22"; // fmv.d f3, f1 - uint64_t r_f1 = 0x12341234; - uint64_t r_f3 = 0x56785678; + uint64_t r_f1 = 0x123456781a2b3c4dULL; + uint64_t r_f3 = 0x56780246aaaabbbbULL; uc_common_setup(&uc, UC_ARCH_RISCV, UC_MODE_RISCV64, code, sizeof(code) - 1); @@ -265,8 +265,8 @@ static void test_riscv64_fp_move(void) OK(uc_reg_read(uc, UC_RISCV_REG_F1, &r_f1)); OK(uc_reg_read(uc, UC_RISCV_REG_F3, &r_f3)); - TEST_CHECK(r_f1 == 0x12341234); - TEST_CHECK(r_f3 == 0x12341234); + TEST_CHECK(r_f1 == 0x123456781a2b3c4dULL); + TEST_CHECK(r_f3 == 0x123456781a2b3c4dULL); uc_close(uc); } @@ -634,12 +634,13 @@ static void test_riscv_correct_address_in_long_jump_hook(void) OK(uc_close(uc)); } -static void test_riscv_mmu_prepare_tlb(uc_engine *uc, uint32_t data_address, uint32_t code_address) +static void test_riscv_mmu_prepare_tlb(uc_engine *uc, uint32_t data_address, + uint32_t code_address) { uint64_t tlbe; uint32_t sptbr = 0x2000; - OK(uc_mem_map(uc, sptbr, 0x3000, UC_PROT_ALL)); //tlb base + OK(uc_mem_map(uc, sptbr, 0x3000, UC_PROT_ALL)); // tlb base tlbe = ((sptbr + 0x1000) >> 2) | 1; OK(uc_mem_write(uc, sptbr, &tlbe, sizeof(tlbe))); @@ -647,13 +648,14 @@ static void test_riscv_mmu_prepare_tlb(uc_engine *uc, uint32_t data_address, uin OK(uc_mem_write(uc, sptbr + 0x1000, &tlbe, sizeof(tlbe))); tlbe = (code_address >> 2) | (7 << 1) | 1; - OK(uc_mem_write(uc, sptbr + 0x2000 + 0x15*8, &tlbe, sizeof(tlbe))); + OK(uc_mem_write(uc, sptbr + 0x2000 + 0x15 * 8, &tlbe, sizeof(tlbe))); tlbe = (data_address >> 2) | (7 << 1) | 1; - OK(uc_mem_write(uc, sptbr + 0x2000 + 0x16*8, &tlbe, sizeof(tlbe))); + OK(uc_mem_write(uc, sptbr + 0x2000 + 0x16 * 8, &tlbe, sizeof(tlbe))); } -static void test_riscv_mmu_hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *userdata) +static void test_riscv_mmu_hook_code(uc_engine *uc, uint64_t address, + uint32_t size, void *userdata) { if (address == 0x15010) { OK(uc_emu_stop(uc)); @@ -678,7 +680,16 @@ static void test_riscv_mmu(void) csrw mepc, t1 mret */ - char code_m[] = "\x1b\x0e\xf0\xff" "\x13\x1e\xfe\x03" "\x13\x0e\x2e\x00" "\x73\x10\x0e\x18" "\xb7\x12\x00\x00" "\x9b\x82\x02\x82" "\x73\x90\x02\x30" "\x37\x53\x01\x00" "\x73\x10\x13\x34" "\x73\x00\x20\x30"; + char code_m[] = "\x1b\x0e\xf0\xff" + "\x13\x1e\xfe\x03" + "\x13\x0e\x2e\x00" + "\x73\x10\x0e\x18" + "\xb7\x12\x00\x00" + "\x9b\x82\x02\x82" + "\x73\x90\x02\x30" + "\x37\x53\x01\x00" + "\x73\x10\x13\x34" + "\x73\x00\x20\x30"; /* li t0, 0x41414141 @@ -686,7 +697,11 @@ static void test_riscv_mmu(void) sw t0, 0(t1) nop */ - char code_s[] = "\xb7\x42\x41\x41" "\x9b\x82\x12\x14" "\x37\x63\x01\x00" "\x23\x20\x53\x00" "\x13\x00\x00\x00"; + char code_s[] = "\xb7\x42\x41\x41" + "\x9b\x82\x12\x14" + "\x37\x63\x01\x00" + "\x23\x20\x53\x00" + "\x13\x00\x00\x00"; OK(uc_open(UC_ARCH_RISCV, UC_MODE_RISCV64, &uc)); OK(uc_ctl_tlb_mode(uc, UC_TLB_CPU)); diff --git a/tests/unit/test_x86.c b/tests/unit/test_x86.c index e1cc9a5c..47611b58 100644 --- a/tests/unit/test_x86.c +++ b/tests/unit/test_x86.c @@ -1125,8 +1125,8 @@ static void test_x86_invalid_vex_l(void) OK(uc_close(uc)); } -// AARCH64 inline the read while s390x won't split the access. Though not tested on other hosts -// but we restrict a bit more. +// AARCH64 inline the read while s390x won't split the access. Though not tested +// on other hosts but we restrict a bit more. #if !defined(TARGET_READ_INLINED) && defined(BOOST_LITTLE_ENDIAN) struct writelog_t { @@ -1230,7 +1230,8 @@ static void test_x86_lazy_mapping(void) OK(uc_close(uc)); } -static void test_x86_16_incorrect_ip_cb(uc_engine *uc, uint64_t address, uint32_t size, void* data) +static void test_x86_16_incorrect_ip_cb(uc_engine *uc, uint64_t address, + uint32_t size, void *data) { uint16_t cs, ip; @@ -1250,27 +1251,30 @@ static void test_x86_16_incorrect_ip(void) uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_16, code, sizeof(code) - 1); - OK(uc_hook_add(uc, &hk1, UC_HOOK_BLOCK, test_x86_16_incorrect_ip_cb, NULL, 1, 0)); - OK(uc_hook_add(uc, &hk2, UC_HOOK_CODE, test_x86_16_incorrect_ip_cb, NULL, 1, 0)); - + OK(uc_hook_add(uc, &hk1, UC_HOOK_BLOCK, test_x86_16_incorrect_ip_cb, NULL, + 1, 0)); + OK(uc_hook_add(uc, &hk2, UC_HOOK_CODE, test_x86_16_incorrect_ip_cb, NULL, 1, + 0)); + OK(uc_reg_write(uc, UC_X86_REG_CS, &cs)); - + OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); OK(uc_close(uc)); } -static void test_x86_mmu_prepare_tlb(uc_engine *uc, uint64_t vaddr, uint64_t tlb_base) +static void test_x86_mmu_prepare_tlb(uc_engine *uc, uint64_t vaddr, + uint64_t tlb_base) { uint64_t cr0; uint64_t cr4; uc_x86_msr msr = {.rid = 0x0c0000080, .value = 0}; - uint64_t pml4o = ((vaddr & 0x00ff8000000000) >> 39)*8; - uint64_t pdpo = ((vaddr & 0x00007fc0000000) >> 30)*8; - uint64_t pdo = ((vaddr & 0x0000003fe00000) >> 21)*8; + uint64_t pml4o = ((vaddr & 0x00ff8000000000) >> 39) * 8; + uint64_t pdpo = ((vaddr & 0x00007fc0000000) >> 30) * 8; + uint64_t pdo = ((vaddr & 0x0000003fe00000) >> 21) * 8; uint64_t pml4e = (tlb_base + 0x1000) | 1 | (1 << 2); - uint64_t pdpe = (tlb_base + 0x2000) | 1 | (1 << 2); - uint64_t pde = (tlb_base + 0x3000) | 1 | (1 << 2); + uint64_t pdpe = (tlb_base + 0x2000) | 1 | (1 << 2); + uint64_t pde = (tlb_base + 0x3000) | 1 | (1 << 2); OK(uc_mem_write(uc, tlb_base + pml4o, &pml4e, sizeof(pml4o))); OK(uc_mem_write(uc, tlb_base + 0x1000 + pdpo, &pdpe, sizeof(pdpe))); OK(uc_mem_write(uc, tlb_base + 0x2000 + pdo, &pde, sizeof(pde))); @@ -1287,10 +1291,11 @@ static void test_x86_mmu_prepare_tlb(uc_engine *uc, uint64_t vaddr, uint64_t tlb OK(uc_reg_write(uc, UC_X86_REG_MSR, &msr)); } -static void test_x86_mmu_pt_set(uc_engine *uc, uint64_t vaddr, uint64_t paddr, uint64_t tlb_base) +static void test_x86_mmu_pt_set(uc_engine *uc, uint64_t vaddr, uint64_t paddr, + uint64_t tlb_base) { - uint64_t pto = ((vaddr & 0x000000001ff000) >> 12)*8; - uint32_t pte = (paddr) | 1 | (1 << 2); + uint64_t pto = ((vaddr & 0x000000001ff000) >> 12) * 8; + uint32_t pte = (paddr) | 1 | (1 << 2); uc_mem_write(uc, tlb_base + 0x3000 + pto, &pte, sizeof(pte)); } @@ -1346,18 +1351,22 @@ static void test_x86_mmu(void) * mov rax, 60 * syscall */ - char code[] = "\xB8\x39\x00\x00\x00\x0F\x05\x48\x85\xC0\x74\x0F\xB8\x3C\x00\x00\x00\x48\x89\x04\x25\x00\x40\x00\x00\x0F\x05\xB9\x2A\x00\x00\x00\x48\x89\x0C\x25\x00\x40\x00\x00\xB8\x3C\x00\x00\x00\x0F\x05"; + char code[] = + "\xB8\x39\x00\x00\x00\x0F\x05\x48\x85\xC0\x74\x0F\xB8\x3C\x00\x00\x00" + "\x48\x89\x04\x25\x00\x40\x00\x00\x0F\x05\xB9\x2A\x00\x00\x00\x48\x89" + "\x0C\x25\x00\x40\x00\x00\xB8\x3C\x00\x00\x00\x0F\x05"; OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc)); OK(uc_ctl_tlb_mode(uc, UC_TLB_CPU)); - OK(uc_hook_add(uc, &h1, UC_HOOK_INSN, &test_x86_mmu_callback, &parrent_done, 1, 0, UC_X86_INS_SYSCALL)); + OK(uc_hook_add(uc, &h1, UC_HOOK_INSN, &test_x86_mmu_callback, &parrent_done, + 1, 0, UC_X86_INS_SYSCALL)); OK(uc_context_alloc(uc, &context)); - OK(uc_mem_map(uc, 0x0, 0x1000, UC_PROT_ALL)); //Code + OK(uc_mem_map(uc, 0x0, 0x1000, UC_PROT_ALL)); // Code OK(uc_mem_write(uc, 0x0, code, sizeof(code) - 1)); - OK(uc_mem_map(uc, 0x1000, 0x1000, UC_PROT_ALL)); //Parrent - OK(uc_mem_map(uc, 0x2000, 0x1000, UC_PROT_ALL)); //Child - OK(uc_mem_map(uc, tlb_base, 0x4000, UC_PROT_ALL)); //TLB + OK(uc_mem_map(uc, 0x1000, 0x1000, UC_PROT_ALL)); // Parrent + OK(uc_mem_map(uc, 0x2000, 0x1000, UC_PROT_ALL)); // Child + OK(uc_mem_map(uc, tlb_base, 0x4000, UC_PROT_ALL)); // TLB test_x86_mmu_prepare_tlb(uc, 0x0, tlb_base); test_x86_mmu_pt_set(uc, 0x2000, 0x0, tlb_base); @@ -1386,7 +1395,9 @@ static void test_x86_mmu(void) TEST_CHECK(child == 42); } -static bool test_x86_vtlb_callback(uc_engine *uc, uint64_t addr, uc_mem_type type, uc_tlb_entry *result, void *user_data) +static bool test_x86_vtlb_callback(uc_engine *uc, uint64_t addr, + uc_mem_type type, uc_tlb_entry *result, + void *user_data) { result->paddr = addr; result->perms = UC_PROT_ALL; @@ -1404,7 +1415,8 @@ static void test_x86_vtlb(void) uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1); OK(uc_ctl_tlb_mode(uc, UC_TLB_VIRTUAL)); - OK(uc_hook_add(uc, &hook, UC_HOOK_TLB_FILL, test_x86_vtlb_callback, NULL, 1, 0)); + OK(uc_hook_add(uc, &hook, UC_HOOK_TLB_FILL, test_x86_vtlb_callback, NULL, 1, + 0)); OK(uc_emu_start(uc, code_start, code_start + 4, 0, 0)); @@ -1415,6 +1427,46 @@ static void test_x86_vtlb(void) OK(uc_close(uc)); } +static void test_x86_segmentation() +{ + uc_engine *uc; + uint64_t fs = 0x53; + uc_x86_mmr gdtr = {0, 0xfffff8076d962000, 0x57, 0}; + + OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc)); + OK(uc_reg_write(uc, UC_X86_REG_GDTR, &gdtr)); + uc_assert_err(UC_ERR_EXCEPTION, uc_reg_write(uc, UC_X86_REG_FS, &fs)); +} + +static void test_x86_0xff_lcall_callback(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + // do nothing + return; +} + +// This aborts prior to a7a5d187e77f7853755eff4768658daf8095c3b7 +static void test_x86_0xff_lcall() +{ + uc_engine* uc; + uc_hook hk; + const char code[] = "\xB8\x01\x00\x00\x00\xBB\x01\x00\x00\x00\xB9\x01\x00\x00\x00\xFF\xDD\xBA\x01\x00\x00\x00\xB8\x02\x00\x00\x00\xBB\x02\x00\x00\x00"; + // Taken from #1842 + // 0: b8 01 00 00 00 mov eax,0x1 + // 5: bb 01 00 00 00 mov ebx,0x1 + // a: b9 01 00 00 00 mov ecx,0x1 + // f: ff (bad) + // 10: dd ba 01 00 00 00 fnstsw WORD PTR [edx+0x1] + // 16: b8 02 00 00 00 mov eax,0x2 + // 1b: bb 02 00 00 00 mov ebx,0x2 + + uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1); + + OK(uc_hook_add(uc, &hk, UC_HOOK_CODE, test_x86_0xff_lcall_callback, NULL, 1, 0)); + + uc_assert_err(UC_ERR_INSN_INVALID, uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); + + OK(uc_close(uc)); +} TEST_LIST = { {"test_x86_in", test_x86_in}, @@ -1461,4 +1513,6 @@ TEST_LIST = { {"test_x86_16_incorrect_ip", test_x86_16_incorrect_ip}, {"test_x86_mmu", test_x86_mmu}, {"test_x86_vtlb", test_x86_vtlb}, + {"test_x86_segmentation", test_x86_segmentation}, + {"test_x86_0xff_lcall", test_x86_0xff_lcall}, {NULL, NULL}}; diff --git a/tests/unit/unicorn_test.h b/tests/unit/unicorn_test.h index dbc17a27..86fe24a6 100644 --- a/tests/unit/unicorn_test.h +++ b/tests/unit/unicorn_test.h @@ -10,20 +10,19 @@ // Copied from glibc-2.29 /* Swap bytes in 32 bit value. */ -#define bswap_32(x) \ - ((((x) & 0xff000000u) >> 24) | (((x) & 0x00ff0000u) >> 8) | \ - (((x) & 0x0000ff00u) << 8) | (((x) & 0x000000ffu) << 24)) +#define bswap_32(x) \ + ((((x)&0xff000000u) >> 24) | (((x)&0x00ff0000u) >> 8) | \ + (((x)&0x0000ff00u) << 8) | (((x)&0x000000ffu) << 24)) /* Swap bytes in 64 bit value. */ -#define bswap_64(x) \ - ((((x) & 0xff00000000000000ull) >> 56) \ - | (((x) & 0x00ff000000000000ull) >> 40) \ - | (((x) & 0x0000ff0000000000ull) >> 24) \ - | (((x) & 0x000000ff00000000ull) >> 8) \ - | (((x) & 0x00000000ff000000ull) << 8) \ - | (((x) & 0x0000000000ff0000ull) << 24) \ - | (((x) & 0x000000000000ff00ull) << 40) \ - | (((x) & 0x00000000000000ffull) << 56)) +#define bswap_64(x) \ + ((((x)&0xff00000000000000ull) >> 56) | \ + (((x)&0x00ff000000000000ull) >> 40) | \ + (((x)&0x0000ff0000000000ull) >> 24) | \ + (((x)&0x000000ff00000000ull) >> 8) | (((x)&0x00000000ff000000ull) << 8) | \ + (((x)&0x0000000000ff0000ull) << 24) | \ + (((x)&0x000000000000ff00ull) << 40) | \ + (((x)&0x00000000000000ffull) << 56)) /** * Assert that err matches expect diff --git a/uc.c b/uc.c index 0a8626cf..ab620b55 100644 --- a/uc.c +++ b/uc.c @@ -31,6 +31,8 @@ #include "qemu-common.h" static void clear_deleted_hooks(uc_engine *uc); +static uc_err uc_snapshot(uc_engine *uc); +static uc_err uc_restore_latest_snapshot(uc_engine *uc); static void *hook_insert(struct list *l, struct hook *h) { @@ -82,6 +84,18 @@ unsigned int uc_version(unsigned int *major, unsigned int *minor) UC_API_EXTRA; } +static uc_err default_reg_read(void *env, int mode, unsigned int regid, + void *value, size_t *size) +{ + return UC_ERR_HANDLE; +} + +static uc_err default_reg_write(void *env, int mode, unsigned int regid, + const void *value, size_t *size, int *setpc) +{ + return UC_ERR_HANDLE; +} + UNICORN_EXPORT uc_err uc_errno(uc_engine *uc) { @@ -136,6 +150,8 @@ const char *uc_strerror(uc_err code) return "Insufficient resource (UC_ERR_RESOURCE)"; case UC_ERR_EXCEPTION: return "Unhandled CPU exception (UC_ERR_EXCEPTION)"; + case UC_ERR_OVERFLOW: + return "Provided buffer is too small (UC_ERR_OVERFLOW)"; } } @@ -191,7 +207,7 @@ bool uc_arch_supported(uc_arch arch) #define UC_INIT(uc) \ if (unlikely(!(uc)->init_done)) { \ - int __init_ret = uc_init(uc); \ + int __init_ret = uc_init_engine(uc); \ if (unlikely(__init_ret != UC_ERR_OK)) { \ return __init_ret; \ } \ @@ -211,7 +227,7 @@ static gint uc_exits_cmp(gconstpointer a, gconstpointer b, gpointer user_data) } } -static uc_err uc_init(uc_engine *uc) +static uc_err uc_init_engine(uc_engine *uc) { if (uc->init_done) { @@ -242,6 +258,10 @@ static uc_err uc_init(uc_engine *uc) uc->reg_reset(uc); } + uc->context_content = UC_CTL_CONTEXT_CPU; + + uc->unmapped_regions = g_array_new(false, false, sizeof(MemoryRegion*)); + uc->init_done = true; return UC_ERR_OK; @@ -264,6 +284,8 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) uc->errnum = UC_ERR_OK; uc->arch = arch; uc->mode = mode; + uc->reg_read = default_reg_read; + uc->reg_write = default_reg_write; // uc->ram_list = { .blocks = QLIST_HEAD_INITIALIZER(ram_list.blocks) }; QLIST_INIT(&uc->ram_list.blocks); @@ -281,7 +303,7 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) free(uc); return UC_ERR_MODE; } - uc->init_arch = m68k_uc_init; + uc->init_arch = uc_init_m68k; break; #endif #ifdef UNICORN_HAS_X86 @@ -291,7 +313,7 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) free(uc); return UC_ERR_MODE; } - uc->init_arch = x86_uc_init; + uc->init_arch = uc_init_x86_64; break; #endif #ifdef UNICORN_HAS_ARM @@ -300,7 +322,7 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) free(uc); return UC_ERR_MODE; } - uc->init_arch = arm_uc_init; + uc->init_arch = uc_init_arm; if (mode & UC_MODE_THUMB) { uc->thumb = 1; @@ -313,7 +335,7 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) free(uc); return UC_ERR_MODE; } - uc->init_arch = arm64_uc_init; + uc->init_arch = uc_init_aarch64; break; #endif @@ -328,23 +350,23 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) if (mode & UC_MODE_BIG_ENDIAN) { #ifdef UNICORN_HAS_MIPS if (mode & UC_MODE_MIPS32) { - uc->init_arch = mips_uc_init; + uc->init_arch = uc_init_mips; } #endif #ifdef UNICORN_HAS_MIPS64 if (mode & UC_MODE_MIPS64) { - uc->init_arch = mips64_uc_init; + uc->init_arch = uc_init_mips64; } #endif } else { // little endian #ifdef UNICORN_HAS_MIPSEL if (mode & UC_MODE_MIPS32) { - uc->init_arch = mipsel_uc_init; + uc->init_arch = uc_init_mipsel; } #endif #ifdef UNICORN_HAS_MIPS64EL if (mode & UC_MODE_MIPS64) { - uc->init_arch = mips64el_uc_init; + uc->init_arch = uc_init_mips64el; } #endif } @@ -359,9 +381,9 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) return UC_ERR_MODE; } if (mode & UC_MODE_SPARC64) { - uc->init_arch = sparc64_uc_init; + uc->init_arch = uc_init_sparc64; } else { - uc->init_arch = sparc_uc_init; + uc->init_arch = uc_init_sparc; } break; #endif @@ -373,9 +395,9 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) return UC_ERR_MODE; } if (mode & UC_MODE_PPC64) { - uc->init_arch = ppc64_uc_init; + uc->init_arch = uc_init_ppc64; } else { - uc->init_arch = ppc_uc_init; + uc->init_arch = uc_init_ppc; } break; #endif @@ -387,9 +409,9 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) return UC_ERR_MODE; } if (mode & UC_MODE_RISCV32) { - uc->init_arch = riscv32_uc_init; + uc->init_arch = uc_init_riscv32; } else if (mode & UC_MODE_RISCV64) { - uc->init_arch = riscv64_uc_init; + uc->init_arch = uc_init_riscv64; } else { free(uc); return UC_ERR_MODE; @@ -402,7 +424,7 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) free(uc); return UC_ERR_MODE; } - uc->init_arch = s390_uc_init; + uc->init_arch = uc_init_s390x; break; #endif #ifdef UNICORN_HAS_TRICORE @@ -411,7 +433,7 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result) free(uc); return UC_ERR_MODE; } - uc->init_arch = tricore_uc_init; + uc->init_arch = uc_init_tricore; break; #endif } @@ -470,6 +492,12 @@ uc_err uc_close(uc_engine *uc) mr->destructor(mr); g_free(uc->system_memory); g_free(uc->system_io); + for (size_t i = 0; i < uc->unmapped_regions->len; i++) { + mr = g_array_index(uc->unmapped_regions, MemoryRegion *, i); + mr->destructor(mr); + g_free(mr); + } + g_array_free(uc->unmapped_regions, true); // Thread relateds. if (uc->qemu_thread_data) { @@ -505,49 +533,168 @@ uc_err uc_close(uc_engine *uc) } UNICORN_EXPORT -uc_err uc_reg_read_batch(uc_engine *uc, int *ids, void **vals, int count) +uc_err uc_reg_read_batch(uc_engine *uc, int *regs, void **vals, int count) { - int ret = UC_ERR_OK; - UC_INIT(uc); + reg_read_t reg_read = uc->reg_read; + void *env = uc->cpu->env_ptr; + int mode = uc->mode; + int i; - if (uc->reg_read) { - ret = uc->reg_read(uc, (unsigned int *)ids, vals, count); - } else { - return UC_ERR_HANDLE; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + void *value = vals[i]; + size_t size = (size_t)-1; + uc_err err = reg_read(env, mode, regid, value, &size); + if (err) { + return err; + } } - return ret; + return UC_ERR_OK; } UNICORN_EXPORT -uc_err uc_reg_write_batch(uc_engine *uc, int *ids, void *const *vals, int count) +uc_err uc_reg_write_batch(uc_engine *uc, int *regs, void *const *vals, + int count) { - int ret = UC_ERR_OK; - UC_INIT(uc); + reg_write_t reg_write = uc->reg_write; + void *env = uc->cpu->env_ptr; + int mode = uc->mode; + int setpc = 0; + int i; - if (uc->reg_write) { - ret = uc->reg_write(uc, (unsigned int *)ids, vals, count); - } else { - return UC_ERR_HANDLE; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + const void *value = vals[i]; + size_t size = (size_t)-1; + uc_err err = reg_write(env, mode, regid, value, &size, &setpc); + if (err) { + return err; + } + } + if (setpc) { + // force to quit execution and flush TB + uc->quit_request = true; + break_translation_loop(uc); } - return ret; + return UC_ERR_OK; +} + +UNICORN_EXPORT +uc_err uc_reg_read_batch2(uc_engine *uc, int *regs, void *const *vals, + size_t *sizes, int count) +{ + UC_INIT(uc); + reg_read_t reg_read = uc->reg_read; + void *env = uc->cpu->env_ptr; + int mode = uc->mode; + int i; + + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + void *value = vals[i]; + uc_err err = reg_read(env, mode, regid, value, sizes + i); + if (err) { + return err; + } + } + + return UC_ERR_OK; +} + +UNICORN_EXPORT +uc_err uc_reg_write_batch2(uc_engine *uc, int *regs, const void *const *vals, + size_t *sizes, int count) +{ + UC_INIT(uc); + reg_write_t reg_write = uc->reg_write; + void *env = uc->cpu->env_ptr; + int mode = uc->mode; + int setpc = 0; + int i; + + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + const void *value = vals[i]; + uc_err err = reg_write(env, mode, regid, value, sizes + i, &setpc); + if (err) { + return err; + } + } + if (setpc) { + // force to quit execution and flush TB + uc->quit_request = true; + break_translation_loop(uc); + } + + return UC_ERR_OK; } UNICORN_EXPORT uc_err uc_reg_read(uc_engine *uc, int regid, void *value) { UC_INIT(uc); - return uc_reg_read_batch(uc, ®id, &value, 1); + size_t size = (size_t)-1; + return uc->reg_read(uc->cpu->env_ptr, uc->mode, regid, value, &size); } UNICORN_EXPORT uc_err uc_reg_write(uc_engine *uc, int regid, const void *value) { UC_INIT(uc); - return uc_reg_write_batch(uc, ®id, (void *const *)&value, 1); + int setpc = 0; + size_t size = (size_t)-1; + uc_err err = + uc->reg_write(uc->cpu->env_ptr, uc->mode, regid, value, &size, &setpc); + if (err) { + return err; + } + if (setpc) { + // force to quit execution and flush TB + uc->quit_request = true; + break_translation_loop(uc); + } + + return UC_ERR_OK; +} + +UNICORN_EXPORT +uc_err uc_reg_read2(uc_engine *uc, int regid, void *value, size_t *size) +{ + UC_INIT(uc); + return uc->reg_read(uc->cpu->env_ptr, uc->mode, regid, value, size); +} + +UNICORN_EXPORT +uc_err uc_reg_write2(uc_engine *uc, int regid, const void *value, size_t *size) +{ + UC_INIT(uc); + int setpc = 0; + uc_err err = + uc->reg_write(uc->cpu->env_ptr, uc->mode, regid, value, size, &setpc); + if (err) { + return err; + } + if (setpc) { + // force to quit execution and flush TB + uc->quit_request = true; + break_translation_loop(uc); + } + + return UC_ERR_OK; +} + +static size_t memory_region_len(uc_engine *uc, MemoryRegion *mr, uint64_t address, size_t count) +{ + hwaddr end = mr->end; + while (mr->container != uc->system_memory) { + mr = mr->container; + end += mr->addr; + } + return (size_t)MIN(count, end - address); } // check if a memory area is mapped @@ -556,10 +703,11 @@ static bool check_mem_area(uc_engine *uc, uint64_t address, size_t size) { size_t count = 0, len; + while (count < size) { - MemoryRegion *mr = find_memory_region(uc, address); + MemoryRegion *mr = uc->memory_mapping(uc, address); if (mr) { - len = (size_t)MIN(size - count, mr->end - address); + len = memory_region_len(uc, mr, address, size - count); count += len; address += len; } else { // this address is not mapped in yet @@ -588,9 +736,9 @@ uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *_bytes, size_t size) // memory area can overlap adjacent memory blocks while (count < size) { - MemoryRegion *mr = find_memory_region(uc, address); + MemoryRegion *mr = uc->memory_mapping(uc, address); if (mr) { - len = (size_t)MIN(size - count, mr->end - address); + len = memory_region_len(uc, mr, address, size - count); if (uc->read_mem(&uc->address_space_memory, address, bytes, len) == false) { break; @@ -629,7 +777,7 @@ uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *_bytes, // memory area can overlap adjacent memory blocks while (count < size) { - MemoryRegion *mr = find_memory_region(uc, address); + MemoryRegion *mr = uc->memory_mapping(uc, address); if (mr) { uint32_t operms = mr->perms; if (!(operms & UC_PROT_WRITE)) { // write protected @@ -638,7 +786,13 @@ uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *_bytes, uc->readonly_mem(mr, false); } - len = (size_t)MIN(size - count, mr->end - address); + len = memory_region_len(uc, mr, address, size - count); + if (uc->snapshot_level && uc->snapshot_level > mr->priority) { + mr = uc->memory_cow(uc, mr, address, len); + if (!mr) { + return UC_ERR_NOMEM; + } + } if (uc->write_mem(&uc->address_space_memory, address, bytes, len) == false) { break; @@ -958,12 +1112,14 @@ static bool memory_overlap(struct uc_struct *uc, uint64_t begin, size_t size) return true; // not found + return false; } // common setup/error checking shared between uc_mem_map and uc_mem_map_ptr static uc_err mem_map(uc_engine *uc, MemoryRegion *block) { + MemoryRegion **regions; int pos; @@ -1352,6 +1508,11 @@ uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size, UC_INIT(uc); + // snapshot and protection can't be mixed + if (uc->snapshot_level > 0) { + return UC_ERR_ARG; + } + if (size == 0) { // trivial case, no change return UC_ERR_OK; @@ -1373,6 +1534,8 @@ uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size, } // check that user's entire requested block is mapped + //TODO check if protected is possible + //deny after cow if (!check_mem_area(uc, address, size)) { return UC_ERR_NOMEM; } @@ -1382,14 +1545,14 @@ uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size, addr = address; count = 0; while (count < size) { - mr = find_memory_region(uc, addr); - len = (size_t)MIN(size - count, mr->end - addr); + mr = uc->memory_mapping(uc, addr); + len = memory_region_len(uc, mr, addr, size - count); if (mr->ram) { if (!split_region(uc, mr, addr, len, false)) { return UC_ERR_NOMEM; } - mr = find_memory_region(uc, addr); + mr = uc->memory_mapping(uc, addr); // will this remove EXEC permission? if (((mr->perms & UC_PROT_EXEC) != 0) && ((perms & UC_PROT_EXEC) == 0)) { @@ -1403,7 +1566,7 @@ uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size, return UC_ERR_NOMEM; } - mr = find_memory_region(uc, addr); + mr = uc->memory_mapping(uc, addr); mr->perms = perms; } @@ -1424,6 +1587,29 @@ uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size, return UC_ERR_OK; } +static +uc_err uc_mem_unmap_snapshot(struct uc_struct *uc, uint64_t address, size_t size, MemoryRegion **ret) +{ + MemoryRegion *mr; + + mr = uc->memory_mapping(uc, address); + while (mr->container != uc->system_memory) { + mr = mr->container; + } + + if (mr->addr != address || int128_get64(mr->size) != size) { + return UC_ERR_ARG; + } + + if (ret) { + *ret = mr; + } + + uc->memory_moveout(uc, mr); + + return UC_ERR_OK; +} + UNICORN_EXPORT uc_err uc_mem_unmap(struct uc_struct *uc, uint64_t address, size_t size) { @@ -1453,13 +1639,17 @@ uc_err uc_mem_unmap(struct uc_struct *uc, uint64_t address, size_t size) return UC_ERR_NOMEM; } + if (uc->snapshot_level > 0) { + return uc_mem_unmap_snapshot(uc, address, size, NULL); + } + // Now we know entire region is mapped, so do the unmap // We may need to split regions if this area spans adjacent regions addr = address; count = 0; while (count < size) { - mr = find_memory_region(uc, addr); - len = (size_t)MIN(size - count, mr->end - addr); + mr = uc->memory_mapping(uc, addr); + len = memory_region_len(uc, mr, addr, size - count); if (!mr->ram) { if (!split_mmio_region(uc, mr, addr, len, true)) { return UC_ERR_NOMEM; @@ -1472,7 +1662,7 @@ uc_err uc_mem_unmap(struct uc_struct *uc, uint64_t address, size_t size) // if we can retrieve the mapping, then no splitting took place // so unmap here - mr = find_memory_region(uc, addr); + mr = uc->memory_mapping(uc, addr); if (mr != NULL) { uc->memory_unmap(uc, mr); } @@ -1483,37 +1673,6 @@ uc_err uc_mem_unmap(struct uc_struct *uc, uint64_t address, size_t size) return UC_ERR_OK; } -// find the memory region of this address -MemoryRegion *find_memory_region(struct uc_struct *uc, uint64_t address) -{ - unsigned int i; - - if (uc->mapped_block_count == 0) { - return NULL; - } - - // try with the cache index first - i = uc->mapped_block_cache_index; - - if (i < uc->mapped_block_count && - address >= uc->mapped_blocks[i]->addr && - address <= uc->mapped_blocks[i]->end - 1) { - return uc->mapped_blocks[i]; - } - - i = bsearch_mapped_blocks(uc, address); - - if (i < uc->mapped_block_count && - address >= uc->mapped_blocks[i]->addr && - address <= uc->mapped_blocks[i]->end - 1) { - uc->mapped_block_cache_index = i; - return uc->mapped_blocks[i]; - } - - // not found - return NULL; -} - UNICORN_EXPORT uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, uint64_t begin, uint64_t end, ...) @@ -1859,59 +2018,58 @@ UNICORN_EXPORT uc_err uc_context_save(uc_engine *uc, uc_context *context) { UC_INIT(uc); + uc_err ret = UC_ERR_OK; - if (!uc->context_save) { - memcpy(context->data, uc->cpu->env_ptr, context->context_size); - return UC_ERR_OK; - } else { - return uc->context_save(uc, context); + if (uc->context_content & UC_CTL_CONTEXT_MEMORY) { + ret = uc_snapshot(uc); + if (ret != UC_ERR_OK) { + return ret; + } } -} -UNICORN_EXPORT -uc_err uc_context_reg_write(uc_context *ctx, int regid, const void *value) -{ - return uc_context_reg_write_batch(ctx, ®id, (void *const *)&value, 1); -} + context->snapshot_level = uc->snapshot_level; -UNICORN_EXPORT -uc_err uc_context_reg_read(uc_context *ctx, int regid, void *value) -{ - return uc_context_reg_read_batch(ctx, ®id, &value, 1); + if (uc->context_content & UC_CTL_CONTEXT_CPU) { + if (!uc->context_save) { + memcpy(context->data, uc->cpu->env_ptr, context->context_size); + return UC_ERR_OK; + } else { + return uc->context_save(uc, context); + } + } + return ret; } // Keep in mind that we don't a uc_engine when r/w the registers of a context. -static void find_context_reg_rw_function(uc_arch arch, uc_mode mode, - context_reg_rw_t *rw) +static context_reg_rw_t find_context_reg_rw(uc_arch arch, uc_mode mode) { // We believe that the arch/mode pair is correct. + context_reg_rw_t rw = {default_reg_read, default_reg_write}; switch (arch) { default: - rw->context_reg_read = NULL; - rw->context_reg_write = NULL; break; #ifdef UNICORN_HAS_M68K case UC_ARCH_M68K: - rw->context_reg_read = m68k_context_reg_read; - rw->context_reg_write = m68k_context_reg_write; + rw.read = reg_read_m68k; + rw.write = reg_write_m68k; break; #endif #ifdef UNICORN_HAS_X86 case UC_ARCH_X86: - rw->context_reg_read = x86_context_reg_read; - rw->context_reg_write = x86_context_reg_write; + rw.read = reg_read_x86_64; + rw.write = reg_write_x86_64; break; #endif #ifdef UNICORN_HAS_ARM case UC_ARCH_ARM: - rw->context_reg_read = arm_context_reg_read; - rw->context_reg_write = arm_context_reg_write; + rw.read = reg_read_arm; + rw.write = reg_write_arm; break; #endif #ifdef UNICORN_HAS_ARM64 case UC_ARCH_ARM64: - rw->context_reg_read = arm64_context_reg_read; - rw->context_reg_write = arm64_context_reg_write; + rw.read = reg_read_aarch64; + rw.write = reg_write_aarch64; break; #endif @@ -1921,27 +2079,27 @@ static void find_context_reg_rw_function(uc_arch arch, uc_mode mode, if (mode & UC_MODE_BIG_ENDIAN) { #ifdef UNICORN_HAS_MIPS if (mode & UC_MODE_MIPS32) { - rw->context_reg_read = mips_context_reg_read; - rw->context_reg_write = mips_context_reg_write; + rw.read = reg_read_mips; + rw.write = reg_write_mips; } #endif #ifdef UNICORN_HAS_MIPS64 if (mode & UC_MODE_MIPS64) { - rw->context_reg_read = mips64_context_reg_read; - rw->context_reg_write = mips64_context_reg_write; + rw.read = reg_read_mips64; + rw.write = reg_write_mips64; } #endif } else { // little endian #ifdef UNICORN_HAS_MIPSEL if (mode & UC_MODE_MIPS32) { - rw->context_reg_read = mipsel_context_reg_read; - rw->context_reg_write = mipsel_context_reg_write; + rw.read = reg_read_mipsel; + rw.write = reg_write_mipsel; } #endif #ifdef UNICORN_HAS_MIPS64EL if (mode & UC_MODE_MIPS64) { - rw->context_reg_read = mips64el_context_reg_read; - rw->context_reg_write = mips64el_context_reg_write; + rw.read = reg_read_mips64el; + rw.write = reg_write_mips64el; } #endif } @@ -1951,104 +2109,205 @@ static void find_context_reg_rw_function(uc_arch arch, uc_mode mode, #ifdef UNICORN_HAS_SPARC case UC_ARCH_SPARC: if (mode & UC_MODE_SPARC64) { - rw->context_reg_read = sparc64_context_reg_read; - rw->context_reg_write = sparc64_context_reg_write; + rw.read = reg_read_sparc64; + rw.write = reg_write_sparc64; } else { - rw->context_reg_read = sparc_context_reg_read; - rw->context_reg_write = sparc_context_reg_write; + rw.read = reg_read_sparc; + rw.write = reg_write_sparc; } break; #endif #ifdef UNICORN_HAS_PPC case UC_ARCH_PPC: if (mode & UC_MODE_PPC64) { - rw->context_reg_read = ppc64_context_reg_read; - rw->context_reg_write = ppc64_context_reg_write; + rw.read = reg_read_ppc64; + rw.write = reg_write_ppc64; } else { - rw->context_reg_read = ppc_context_reg_read; - rw->context_reg_write = ppc_context_reg_write; + rw.read = reg_read_ppc; + rw.write = reg_write_ppc; } break; #endif #ifdef UNICORN_HAS_RISCV case UC_ARCH_RISCV: if (mode & UC_MODE_RISCV32) { - rw->context_reg_read = riscv32_context_reg_read; - rw->context_reg_write = riscv32_context_reg_write; + rw.read = reg_read_riscv32; + rw.write = reg_write_riscv32; } else if (mode & UC_MODE_RISCV64) { - rw->context_reg_read = riscv64_context_reg_read; - rw->context_reg_write = riscv64_context_reg_write; + rw.read = reg_read_riscv64; + rw.write = reg_write_riscv64; } break; #endif #ifdef UNICORN_HAS_S390X case UC_ARCH_S390X: - rw->context_reg_read = s390_context_reg_read; - rw->context_reg_write = s390_context_reg_write; + rw.read = reg_read_s390x; + rw.write = reg_write_s390x; break; #endif #ifdef UNICORN_HAS_TRICORE case UC_ARCH_TRICORE: - rw->context_reg_read = tricore_context_reg_read; - rw->context_reg_write = tricore_context_reg_write; + rw.read = reg_read_tricore; + rw.write = reg_write_tricore; break; #endif } - return; + return rw; } UNICORN_EXPORT -uc_err uc_context_reg_write_batch(uc_context *ctx, int *ids, void *const *vals, +uc_err uc_context_reg_write(uc_context *ctx, int regid, const void *value) +{ + int setpc = 0; + size_t size = (size_t)-1; + return find_context_reg_rw(ctx->arch, ctx->mode) + .write(ctx->data, ctx->mode, regid, value, &size, &setpc); +} + +UNICORN_EXPORT +uc_err uc_context_reg_read(uc_context *ctx, int regid, void *value) +{ + size_t size = (size_t)-1; + return find_context_reg_rw(ctx->arch, ctx->mode) + .read(ctx->data, ctx->mode, regid, value, &size); +} + +UNICORN_EXPORT +uc_err uc_context_reg_write2(uc_context *ctx, int regid, const void *value, + size_t *size) +{ + int setpc = 0; + return find_context_reg_rw(ctx->arch, ctx->mode) + .write(ctx->data, ctx->mode, regid, value, size, &setpc); +} + +UNICORN_EXPORT +uc_err uc_context_reg_read2(uc_context *ctx, int regid, void *value, + size_t *size) +{ + return find_context_reg_rw(ctx->arch, ctx->mode) + .read(ctx->data, ctx->mode, regid, value, size); +} + +UNICORN_EXPORT +uc_err uc_context_reg_write_batch(uc_context *ctx, int *regs, void *const *vals, int count) { - int ret = UC_ERR_OK; - context_reg_rw_t rw; + reg_write_t reg_write = find_context_reg_rw(ctx->arch, ctx->mode).write; + void *env = ctx->data; + int mode = ctx->mode; + int setpc = 0; + int i; - find_context_reg_rw_function(ctx->arch, ctx->mode, &rw); - if (rw.context_reg_write) { - ret = rw.context_reg_write(ctx, (unsigned int *)ids, vals, count); - } else { - return UC_ERR_HANDLE; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + const void *value = vals[i]; + size_t size = (size_t)-1; + uc_err err = reg_write(env, mode, regid, value, &size, &setpc); + if (err) { + return err; + } } - return ret; + return UC_ERR_OK; } UNICORN_EXPORT -uc_err uc_context_reg_read_batch(uc_context *ctx, int *ids, void **vals, +uc_err uc_context_reg_read_batch(uc_context *ctx, int *regs, void **vals, int count) { - int ret = UC_ERR_OK; - context_reg_rw_t rw; + reg_read_t reg_read = find_context_reg_rw(ctx->arch, ctx->mode).read; + void *env = ctx->data; + int mode = ctx->mode; + int i; - find_context_reg_rw_function(ctx->arch, ctx->mode, &rw); - if (rw.context_reg_read) { - ret = rw.context_reg_read(ctx, (unsigned int *)ids, vals, count); - } else { - return UC_ERR_HANDLE; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + void *value = vals[i]; + size_t size = (size_t)-1; + uc_err err = reg_read(env, mode, regid, value, &size); + if (err) { + return err; + } } - return ret; + return UC_ERR_OK; +} + +UNICORN_EXPORT +uc_err uc_context_reg_write_batch2(uc_context *ctx, int *regs, + const void *const *vals, size_t *sizes, + int count) +{ + reg_write_t reg_write = find_context_reg_rw(ctx->arch, ctx->mode).write; + void *env = ctx->data; + int mode = ctx->mode; + int setpc = 0; + int i; + + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + const void *value = vals[i]; + uc_err err = reg_write(env, mode, regid, value, sizes + i, &setpc); + if (err) { + return err; + } + } + + return UC_ERR_OK; +} + +UNICORN_EXPORT +uc_err uc_context_reg_read_batch2(uc_context *ctx, int *regs, void *const *vals, + size_t *sizes, int count) +{ + reg_read_t reg_read = find_context_reg_rw(ctx->arch, ctx->mode).read; + void *env = ctx->data; + int mode = ctx->mode; + int i; + + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + void *value = vals[i]; + uc_err err = reg_read(env, mode, regid, value, sizes + i); + if (err) { + return err; + } + } + + return UC_ERR_OK; } UNICORN_EXPORT uc_err uc_context_restore(uc_engine *uc, uc_context *context) { UC_INIT(uc); + uc_err ret; - if (!uc->context_restore) { - memcpy(uc->cpu->env_ptr, context->data, context->context_size); - return UC_ERR_OK; - } else { - return uc->context_restore(uc, context); + if (uc->context_content & UC_CTL_CONTEXT_MEMORY) { + uc->snapshot_level = context->snapshot_level; + ret = uc_restore_latest_snapshot(uc); + if (ret != UC_ERR_OK) { + return ret; + } + uc_snapshot(uc); } + + if (uc->context_content & UC_CTL_CONTEXT_CPU) { + if (!uc->context_restore) { + memcpy(uc->cpu->env_ptr, context->data, context->context_size); + return UC_ERR_OK; + } else { + return uc->context_restore(uc, context); + } + } + return UC_ERR_OK; } UNICORN_EXPORT uc_err uc_context_free(uc_context *context) { - return uc_free(context); } @@ -2374,6 +2633,33 @@ uc_err uc_ctl(uc_engine *uc, uc_control_type control, ...) break; } + case UC_CTL_TCG_BUFFER_SIZE: { + if (rw == UC_CTL_IO_WRITE) { + uint32_t size = va_arg(args, uint32_t); + uc->tcg_buffer_size = size; + } else { + + UC_INIT(uc); + + uint32_t *size = va_arg(args, uint32_t *); + *size = uc->tcg_buffer_size; + } + break; + } + + case UC_CTL_CONTEXT_MODE: + + UC_INIT(uc); + + if (rw == UC_CTL_IO_WRITE) { + int mode = va_arg(args, int); + uc->context_content = mode; + err = UC_ERR_OK; + } else { + err = UC_ERR_ARG; + } + break; + default: err = UC_ERR_ARG; break; @@ -2384,14 +2670,54 @@ uc_err uc_ctl(uc_engine *uc, uc_control_type control, ...) return err; } -gint cmp_vaddr(gconstpointer a, gconstpointer b, gpointer user_data) +static uc_err uc_snapshot(struct uc_struct *uc) { - uint64_t va = (uint64_t)a; - uint64_t vb = (uint64_t)b; - if (va == vb) { - return 0; + if (uc->snapshot_level == INT32_MAX) { + return UC_ERR_RESOURCE; } - return va < vb ? -1 : 1; + uc->snapshot_level++; + return UC_ERR_OK; +} + +static uc_err uc_restore_latest_snapshot(struct uc_struct *uc) +{ + MemoryRegion *subregion, *subregion_next, *mr, *initial_mr; + int level; + + QTAILQ_FOREACH_SAFE(subregion, &uc->system_memory->subregions, subregions_link, subregion_next) { + uc->memory_filter_subregions(subregion, uc->snapshot_level); + if (QTAILQ_EMPTY(&subregion->subregions)) { + uc->memory_unmap(uc, subregion); + } + } + + for (size_t i = uc->unmapped_regions->len; i-- > 0;) { + mr = g_array_index(uc->unmapped_regions, MemoryRegion *, i); + // same dirty hack as in memory_moveout see qemu/softmmu/memory.c + initial_mr = QTAILQ_FIRST(&mr->subregions); + if (!initial_mr) { + initial_mr = mr; + } + /* same dirty hack as in memory_moveout see qemu/softmmu/memory.c */ + level = (intptr_t)mr->container; + mr->container = NULL; + + if (level < uc->snapshot_level) { + break; + } + if (memory_overlap(uc, mr->addr, int128_get64(mr->size))) { + return UC_ERR_MAP; + } + uc->memory_movein(uc, mr); + uc->memory_filter_subregions(mr, uc->snapshot_level); + if (initial_mr != mr && QTAILQ_EMPTY(&mr->subregions)) { + uc->memory_unmap(uc, subregion); + } + mem_map(uc, initial_mr); + g_array_remove_range(uc->unmapped_regions, i, 1); + } + uc->snapshot_level--; + return UC_ERR_OK; } #ifdef UNICORN_TRACER