From 2d94e30988575caf9cce028d5b4a305b75c21d58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matheus=20C=2E=20Fran=C3=A7a?= Date: Mon, 3 Apr 2023 10:58:50 -0300 Subject: [PATCH 01/44] Fix clang/mingw - missing getpagesize Based on msys2-packages patch: https://github.com/msys2/MINGW-packages/pull/10543 --- qemu/util/oslib-posix.c | 10 ++++++++++ 1 file changed, 10 insertions(+) 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) { From 5ff654c77b17141b5fb8f377a18e26368737a62d Mon Sep 17 00:00:00 2001 From: Kevin Schneider Date: Thu, 30 Mar 2023 13:44:59 +0200 Subject: [PATCH 02/44] add rust bindings for uc_ctl --- bindings/rust/src/ffi.rs | 1 + bindings/rust/src/lib.rs | 146 +++++++++++++++++++++++++++++ bindings/rust/src/unicorn_const.rs | 43 +++++++++ 3 files changed, 190 insertions(+) diff --git a/bindings/rust/src/ffi.rs b/bindings/rust/src/ffi.rs index b1c04f57..37602392 100644 --- a/bindings/rust/src/ffi.rs +++ b/bindings/rust/src/ffi.rs @@ -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> { diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index cb8497c7..0f1c7049 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; @@ -1051,4 +1053,148 @@ 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_tlb(&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) + } + } } diff --git a/bindings/rust/src/unicorn_const.rs b/bindings/rust/src/unicorn_const.rs index 7e8185d2..b0b440c4 100644 --- a/bindings/rust/src/unicorn_const.rs +++ b/bindings/rust/src/unicorn_const.rs @@ -187,3 +187,46 @@ 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_IO_READ = 1<<31, + UC_CTL_IO_WRITE = 1<<30, +} From 0729dc031247a58c1a37380cb6f124b0d353e990 Mon Sep 17 00:00:00 2001 From: Philipp Takacs Date: Wed, 5 Apr 2023 12:35:05 +0200 Subject: [PATCH 03/44] rust update uc_ctl_flush_tlb and add uc_ctl_tlb_mode --- bindings/rust/src/lib.rs | 20 +++++++++++++++++++- bindings/rust/src/unicorn_const.rs | 9 +++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index 0f1c7049..d72f82ad 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -1189,7 +1189,7 @@ impl<'a, D> Unicorn<'a, D> { } } - pub fn ctl_flush_tlb(&self) -> Result<(), uc_error> { + 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(()) @@ -1197,4 +1197,22 @@ impl<'a, D> Unicorn<'a, D> { 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 b0b440c4..d5c60c1c 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 { @@ -227,6 +234,8 @@ pub enum ControlType { 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, } From a9f0dabc64bd0c0d9289538765b16b572b2519f1 Mon Sep 17 00:00:00 2001 From: Philipp Takacs Date: Wed, 5 Apr 2023 11:26:02 +0200 Subject: [PATCH 04/44] rust add tlb callback --- bindings/rust/src/ffi.rs | 24 +++++++++++++++- bindings/rust/src/lib.rs | 27 ++++++++++++++++++ bindings/rust/src/unicorn_const.rs | 9 ++++++ tests/rust-tests/main.rs | 45 +++++++++++++++++++++++++++++- 4 files changed, 103 insertions(+), 2 deletions(-) diff --git a/bindings/rust/src/ffi.rs b/bindings/rust/src/ffi.rs index 37602392..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}; @@ -252,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 d72f82ad..5b4e7d33 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -885,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. diff --git a/bindings/rust/src/unicorn_const.rs b/bindings/rust/src/unicorn_const.rs index d5c60c1c..2ef7622e 100644 --- a/bindings/rust/src/unicorn_const.rs +++ b/bindings/rust/src/unicorn_const.rs @@ -93,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); } } @@ -239,3 +241,10 @@ pub enum ControlType { 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/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(())); +} From bbbc7856accbae7697db84d10a28c5a6aec81856 Mon Sep 17 00:00:00 2001 From: Mio Date: Wed, 12 Apr 2023 20:56:54 +0800 Subject: [PATCH 05/44] Invalidate tb cache once mapping is removed --- qemu/accel/tcg/translate-all.c | 8 ++++-- qemu/softmmu/memory.c | 11 +++++--- tests/unit/test_arm64.c | 51 ++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 7 deletions(-) diff --git a/qemu/accel/tcg/translate-all.c b/qemu/accel/tcg/translate-all.c index 56ddb35e..ac71e391 100644 --- a/qemu/accel/tcg/translate-all.c +++ b/qemu/accel/tcg/translate-all.c @@ -1018,11 +1018,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--; diff --git a/qemu/softmmu/memory.c b/qemu/softmmu/memory.c index c58bd79f..9d856472 100644 --- a/qemu/softmmu/memory.c +++ b/qemu/softmmu/memory.c @@ -153,12 +153,15 @@ void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) 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) { + // We also need to remove all tb cache + uc->uc_invalidate_tb(uc, mr->addr, 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); diff --git a/tests/unit/test_arm64.c b/tests/unit/test_arm64.c index 8a03945c..44f0ad9c 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; @@ -473,6 +474,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}, @@ -487,4 +537,5 @@ TEST_LIST = {{"test_arm64_until", test_arm64_until}, {"test_arm64_block_invalid_mem_read_write_sync", test_arm64_block_invalid_mem_read_write_sync}, {"test_arm64_mmu", test_arm64_mmu}, + {"test_arm64_pc_wrap", test_arm64_pc_wrap}, {NULL, NULL}}; From 7bb1501bc269387e00a1936fe37fdc23510f7935 Mon Sep 17 00:00:00 2001 From: "Takacs, Philipp" Date: Mon, 17 Apr 2023 17:33:37 +0200 Subject: [PATCH 06/44] use int128_get64 in memory_unmap This fixes build errors introduced by bbbc7856accbae7697db84d10a28c5a6aec81856 --- qemu/softmmu/memory.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qemu/softmmu/memory.c b/qemu/softmmu/memory.c index 9d856472..bf6341d9 100644 --- a/qemu/softmmu/memory.c +++ b/qemu/softmmu/memory.c @@ -155,13 +155,13 @@ void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) if (uc->cpu) { // We also need to remove all tb cache - uc->uc_invalidate_tb(uc, mr->addr, mr->size); + 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); From a998231a0ea2353b255c00d0a8912289d7509fe0 Mon Sep 17 00:00:00 2001 From: Robert Xiao Date: Sat, 6 May 2023 01:42:15 -0700 Subject: [PATCH 07/44] Fix sample_ctl.py. Commit 640251e1aa added a size parameter to uc_hook_tcg_op_2, but this was not reflected in the Python bindings. Commit fbf4078d65 added a len parameter to ctl_remove_cache, but this was not reflected in sample_ctl.py. --- bindings/python/sample_ctl.py | 4 ++-- bindings/python/unicorn/unicorn.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/bindings/python/sample_ctl.py b/bindings/python/sample_ctl.py index 202a2094..1578a010 100755 --- a/bindings/python/sample_ctl.py +++ b/bindings/python/sample_ctl.py @@ -57,7 +57,7 @@ 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) + uc.ctl_remove_cache(addr + i * 512, addr + i * 512 + 1) evicted = time_emulation(uc, addr, addr + len(code)) @@ -66,7 +66,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 e893d6fe..bd266935 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -210,7 +210,7 @@ UC_HOOK_EDGE_GEN_CB = ctypes.CFUNCTYPE( None, uc_engine, ctypes.POINTER(uc_tb), ctypes.POINTER(uc_tb), ctypes.c_void_p ) UC_HOOK_TCG_OPCODE_CB = ctypes.CFUNCTYPE( - None, uc_engine, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_void_p + None, uc_engine, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_uint64, ctypes.c_uint32, ctypes.c_void_p ) # access to error code via @errno of UcError @@ -647,9 +647,9 @@ class Uc(object): return result.value @_catch_hook_exception - def _hook_tcg_op_cb(self, handle, address, arg1, arg2, user_data): + def _hook_tcg_op_cb(self, handle, address, arg1, arg2, size, user_data): (cb, data) = self._callbacks[user_data] - cb(self, address, arg1, arg2, user_data) + cb(self, address, arg1, arg2, size, user_data) @_catch_hook_exception def _hook_edge_gen_cb(self, handle, cur, prev, user_data): From d27ca4530b8bd776b92c0f0f31735a58e02b8605 Mon Sep 17 00:00:00 2001 From: Robert Xiao Date: Sat, 6 May 2023 02:07:26 -0700 Subject: [PATCH 08/44] Minor Python fixes. - Match the types of UC_HOOK_CODE_CB and UC_HOOK_INSN_SYS_CB to C - Avoid building a new namedtuple class in every call to _hook_insn_sys_cb --- bindings/python/unicorn/unicorn.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index bd266935..b752d0b0 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -177,7 +177,7 @@ _setup_prototype(_uc, "uc_mem_regions", ucerr, uc_engine, ctypes.POINTER(ctypes. _setup_prototype(_uc, "uc_hook_add", ucerr, uc_engine, ctypes.POINTER(uc_hook_h), ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p, ctypes.c_uint64, ctypes.c_uint64) _setup_prototype(_uc, "uc_ctl", ucerr, uc_engine, ctypes.c_int) -UC_HOOK_CODE_CB = ctypes.CFUNCTYPE(None, uc_engine, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_void_p) +UC_HOOK_CODE_CB = ctypes.CFUNCTYPE(None, uc_engine, ctypes.c_uint64, ctypes.c_uint32, ctypes.c_void_p) UC_HOOK_INSN_INVALID_CB = ctypes.CFUNCTYPE(ctypes.c_bool, uc_engine, ctypes.c_void_p) UC_HOOK_MEM_INVALID_CB = ctypes.CFUNCTYPE( ctypes.c_bool, uc_engine, ctypes.c_int, @@ -198,7 +198,7 @@ UC_HOOK_INSN_OUT_CB = ctypes.CFUNCTYPE( ctypes.c_int, ctypes.c_uint32, ctypes.c_void_p ) UC_HOOK_INSN_SYSCALL_CB = ctypes.CFUNCTYPE(None, uc_engine, ctypes.c_void_p) -UC_HOOK_INSN_SYS_CB = ctypes.CFUNCTYPE(ctypes.c_uint32, uc_engine, ctypes.c_uint32, ctypes.c_void_p, ctypes.c_void_p) +UC_HOOK_INSN_SYS_CB = ctypes.CFUNCTYPE(ctypes.c_uint32, uc_engine, ctypes.c_int, ctypes.c_void_p, ctypes.c_void_p) UC_HOOK_INSN_CPUID_CB = ctypes.CFUNCTYPE(ctypes.c_uint32, uc_engine, ctypes.c_void_p) UC_MMIO_READ_CB = ctypes.CFUNCTYPE( ctypes.c_uint64, uc_engine, ctypes.c_uint64, ctypes.c_int, ctypes.c_void_p @@ -424,6 +424,9 @@ class uc_arm64_cp_reg(ctypes.Structure): ("val", ctypes.c_uint64) ] + def __repr__(self): + return "%s(%s)" % (self.__class__.__name__, ", ".join("%s=%s" % (k, getattr(self, k)) for (k, _) in self._fields_)) + class uc_x86_mmr(ctypes.Structure): """Memory-Management Register for instructions IDTR, GDTR, LDTR, TR.""" _fields_ = [ @@ -696,11 +699,9 @@ class Uc(object): def _hook_insn_sys_cb(self, handle, reg, pcp_reg, user_data): cp_reg = ctypes.cast(pcp_reg, ctypes.POINTER(uc_arm64_cp_reg)).contents - uc_arm64_cp_reg_tuple = namedtuple("uc_arm64_cp_reg_tuple", ["crn", "crm", "op0", "op1", "op2", "val"]) - (cb, data) = self._callbacks[user_data] - return cb(self, reg, uc_arm64_cp_reg_tuple(cp_reg.crn, cp_reg.crm, cp_reg.op0, cp_reg.op1, cp_reg.op2, cp_reg.val), data) + return cb(self, reg, cp_reg, data) @_catch_hook_exception def _hook_insn_out_cb(self, handle, port, size, value, user_data): From 54870cca0ec31c31db3c957dfd471e87b7733a87 Mon Sep 17 00:00:00 2001 From: "Takacs, Philipp" Date: Mon, 8 May 2023 15:32:58 +0200 Subject: [PATCH 09/44] remove unused function cmp_vaddr --- uc.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/uc.c b/uc.c index 0a8626cf..0b464a4d 100644 --- a/uc.c +++ b/uc.c @@ -2384,16 +2384,6 @@ uc_err uc_ctl(uc_engine *uc, uc_control_type control, ...) return err; } -gint cmp_vaddr(gconstpointer a, gconstpointer b, gpointer user_data) -{ - uint64_t va = (uint64_t)a; - uint64_t vb = (uint64_t)b; - if (va == vb) { - return 0; - } - return va < vb ? -1 : 1; -} - #ifdef UNICORN_TRACER uc_tracer *get_tracer() { From 227e578660b1ca1c4158970eecb4cb4376855b32 Mon Sep 17 00:00:00 2001 From: "Takacs, Philipp" Date: Mon, 8 May 2023 15:38:43 +0200 Subject: [PATCH 10/44] move typedef definition of enum uc_mem_type forword references to enum types are forbidden in C. Also C++ will not build if this is used --- include/unicorn/unicorn.h | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index ed016dc0..feae9eea 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -245,7 +245,19 @@ 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 @@ -310,20 +322,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. From 073c4b74cad5c6aa273caf156b38bec4f6179d54 Mon Sep 17 00:00:00 2001 From: "Takacs, Philipp" Date: Tue, 9 May 2023 14:20:11 +0200 Subject: [PATCH 11/44] load_helper only call cpu_loop_exit() when emulation is running The load_helper is sometimes called from register writes. When the load fails check if emulation is running before jump out of the emulated code. --- qemu/accel/tcg/cputlb.c | 38 +++++++++++++++++++++++--------------- tests/unit/test_x86.c | 12 ++++++++++++ 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/qemu/accel/tcg/cputlb.c b/qemu/accel/tcg/cputlb.c index 659faf3f..29c6555b 100644 --- a/qemu/accel/tcg/cputlb.c +++ b/qemu/accel/tcg/cputlb.c @@ -1520,21 +1520,25 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, mr = find_memory_region(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->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->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->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->cpu->stopped) { + cpu_exit(uc->cpu); + // See comments above + cpu_loop_exit(uc->cpu); + } return 0; } } diff --git a/tests/unit/test_x86.c b/tests/unit/test_x86.c index e1cc9a5c..61625e82 100644 --- a/tests/unit/test_x86.c +++ b/tests/unit/test_x86.c @@ -1415,6 +1415,17 @@ 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)); +} + TEST_LIST = { {"test_x86_in", test_x86_in}, @@ -1461,4 +1472,5 @@ 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}, {NULL, NULL}}; From 06a76e98c482e9d886b60a7a020596f5f3843079 Mon Sep 17 00:00:00 2001 From: Robert Xiao Date: Wed, 10 May 2023 12:57:36 -0700 Subject: [PATCH 12/44] Add __repr__ to all ctypes.Structure subclasses --- bindings/python/unicorn/unicorn.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index b752d0b0..7313bd98 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -130,6 +130,9 @@ uc_engine = ctypes.c_void_p uc_context = ctypes.c_void_p uc_hook_h = ctypes.c_size_t +def _structure_repr(self): + return "%s(%s)" % (self.__class__.__name__, ", ".join("%s=%s" % (k, getattr(self, k)) for (k, _) in self._fields_)) + class _uc_mem_region(ctypes.Structure): _fields_ = [ ("begin", ctypes.c_uint64), @@ -137,6 +140,8 @@ class _uc_mem_region(ctypes.Structure): ("perms", ctypes.c_uint32), ] + __repr__ = _structure_repr + class uc_tb(ctypes.Structure): """"TranslationBlock""" _fields_ = [ @@ -145,6 +150,8 @@ class uc_tb(ctypes.Structure): ("size", ctypes.c_uint16) ] + __repr__ = _structure_repr + _setup_prototype(_uc, "uc_version", ctypes.c_uint, ctypes.POINTER(ctypes.c_int), ctypes.POINTER(ctypes.c_int)) _setup_prototype(_uc, "uc_arch_supported", ctypes.c_bool, ctypes.c_int) _setup_prototype(_uc, "uc_open", ucerr, ctypes.c_uint, ctypes.c_uint, ctypes.POINTER(uc_engine)) @@ -413,6 +420,8 @@ class uc_arm_cp_reg(ctypes.Structure): ("val", ctypes.c_uint64) ] + __repr__ = _structure_repr + class uc_arm64_cp_reg(ctypes.Structure): """ARM64 coprocessors registers for instructions MRS, MSR""" _fields_ = [ @@ -424,8 +433,7 @@ class uc_arm64_cp_reg(ctypes.Structure): ("val", ctypes.c_uint64) ] - def __repr__(self): - return "%s(%s)" % (self.__class__.__name__, ", ".join("%s=%s" % (k, getattr(self, k)) for (k, _) in self._fields_)) + __repr__ = _structure_repr class uc_x86_mmr(ctypes.Structure): """Memory-Management Register for instructions IDTR, GDTR, LDTR, TR.""" @@ -436,12 +444,16 @@ class uc_x86_mmr(ctypes.Structure): ("flags", ctypes.c_uint32), # not used by GDTR and IDTR ] + __repr__ = _structure_repr + class uc_x86_msr(ctypes.Structure): _fields_ = [ ("rid", ctypes.c_uint32), ("value", ctypes.c_uint64), ] + __repr__ = _structure_repr + class uc_x86_float80(ctypes.Structure): """Float80""" _fields_ = [ @@ -449,6 +461,7 @@ class uc_x86_float80(ctypes.Structure): ("exponent", ctypes.c_uint16), ] + __repr__ = _structure_repr class uc_x86_xmm(ctypes.Structure): """128-bit xmm register""" @@ -457,6 +470,8 @@ class uc_x86_xmm(ctypes.Structure): ("high_qword", ctypes.c_uint64), ] + __repr__ = _structure_repr + class uc_x86_ymm(ctypes.Structure): """256-bit ymm register""" _fields_ = [ @@ -466,6 +481,8 @@ class uc_x86_ymm(ctypes.Structure): ("fourth_qword", ctypes.c_uint64), ] + __repr__ = _structure_repr + class uc_arm64_neon128(ctypes.Structure): """128-bit neon register""" _fields_ = [ @@ -473,6 +490,8 @@ class uc_arm64_neon128(ctypes.Structure): ("high_qword", ctypes.c_uint64), ] + __repr__ = _structure_repr + # Subclassing ref to allow property assignment. class UcRef(weakref.ref): pass From 4a7b3b7a3ab7b6f872ff134542245e2e23d71101 Mon Sep 17 00:00:00 2001 From: "Takacs, Philipp" Date: Fri, 12 May 2023 12:28:39 +0200 Subject: [PATCH 13/44] fixup! load_helper only call cpu_loop_exit() when emulation is running --- qemu/accel/tcg/cputlb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/qemu/accel/tcg/cputlb.c b/qemu/accel/tcg/cputlb.c index 29c6555b..3d0ae80f 100644 --- a/qemu/accel/tcg/cputlb.c +++ b/qemu/accel/tcg/cputlb.c @@ -1520,7 +1520,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, mr = find_memory_region(uc, paddr); if (mr == NULL) { uc->invalid_error = UC_ERR_MAP; - if (!uc->cpu->stopped) { + if (uc->nested_level > 0) { 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: @@ -1534,7 +1534,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uc->invalid_addr = paddr; uc->invalid_error = error_code; // printf("***** Invalid fetch (unmapped memory) at " TARGET_FMT_lx "\n", addr); - if (!uc->cpu->stopped) { + if (uc->nested_level > 0) { cpu_exit(uc->cpu); // See comments above cpu_loop_exit(uc->cpu); @@ -1592,7 +1592,7 @@ 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); - if (!uc->cpu->stopped) { + if (uc->nested_level > 0) { cpu_exit(uc->cpu); // See comments above cpu_loop_exit(uc->cpu); @@ -1624,7 +1624,7 @@ 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); - if (!uc->cpu->stopped) { + if (uc->nested_level > 0) { cpu_exit(uc->cpu); // See comments above cpu_loop_exit(uc->cpu); From a24e53d7944110f8a3010436dc0b5bc79cc9776c Mon Sep 17 00:00:00 2001 From: mio Date: Sun, 14 May 2023 13:35:10 +0200 Subject: [PATCH 14/44] Rebuild flags after writing to cp registers This is buggy as this momemt per https://github.com/unicorn-engine/unicorn/issues/1789#issuecomment-1546807410 We need either doc this or save more information for a context --- qemu/target/arm/unicorn_aarch64.c | 1 + 1 file changed, 1 insertion(+) diff --git a/qemu/target/arm/unicorn_aarch64.c b/qemu/target/arm/unicorn_aarch64.c index fa40330f..e3bc63a3 100644 --- a/qemu/target/arm/unicorn_aarch64.c +++ b/qemu/target/arm/unicorn_aarch64.c @@ -323,6 +323,7 @@ static uc_err reg_write(CPUARMState *env, unsigned int regid, const void *value) break; case UC_ARM64_REG_CP_REG: ret = write_cp_reg(env, (uc_arm64_cp_reg *)value); + arm_rebuild_hflags(env); break; case UC_ARM64_REG_FPCR: vfp_set_fpcr(env, *(uint32_t *)value); From 994813a0e55731b84ff81a1ceb5a31a589062e6a Mon Sep 17 00:00:00 2001 From: mio Date: Fri, 19 May 2023 23:24:42 +0200 Subject: [PATCH 15/44] Also check cpu->stopped --- qemu/accel/tcg/cputlb.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/qemu/accel/tcg/cputlb.c b/qemu/accel/tcg/cputlb.c index 3d0ae80f..65b77bf0 100644 --- a/qemu/accel/tcg/cputlb.c +++ b/qemu/accel/tcg/cputlb.c @@ -1520,7 +1520,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, mr = find_memory_region(uc, paddr); if (mr == NULL) { uc->invalid_error = UC_ERR_MAP; - if (uc->nested_level > 0) { + 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: @@ -1534,7 +1534,7 @@ load_helper(CPUArchState *env, target_ulong addr, TCGMemOpIdx oi, uc->invalid_addr = paddr; uc->invalid_error = error_code; // printf("***** Invalid fetch (unmapped memory) at " TARGET_FMT_lx "\n", addr); - if (uc->nested_level > 0) { + if (uc->nested_level > 0 && !uc->cpu->stopped) { cpu_exit(uc->cpu); // See comments above cpu_loop_exit(uc->cpu); @@ -1592,7 +1592,7 @@ 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); - if (uc->nested_level > 0) { + if (uc->nested_level > 0 && !uc->cpu->stopped) { cpu_exit(uc->cpu); // See comments above cpu_loop_exit(uc->cpu); @@ -1624,7 +1624,7 @@ 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); - if (uc->nested_level > 0) { + if (uc->nested_level > 0 && !uc->cpu->stopped) { cpu_exit(uc->cpu); // See comments above cpu_loop_exit(uc->cpu); From fa457a3a97ca15c22014d66078633366d4fe9d77 Mon Sep 17 00:00:00 2001 From: "Takacs, Philipp" Date: Mon, 22 May 2023 15:38:37 +0200 Subject: [PATCH 16/44] fix UC_MEM_WRITE_PROT callback callbacks work on the physical address. --- qemu/accel/tcg/cputlb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qemu/accel/tcg/cputlb.c b/qemu/accel/tcg/cputlb.c index 65b77bf0..f805b44a 100644 --- a/qemu/accel/tcg/cputlb.c +++ b/qemu/accel/tcg/cputlb.c @@ -2125,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 @@ -2147,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); From 67f03862990647f1570d65de340e5a68ebb33619 Mon Sep 17 00:00:00 2001 From: Choongwoo Han Date: Tue, 23 May 2023 13:14:50 -0700 Subject: [PATCH 17/44] Add apt update --- .github/workflows/Nuget-publishing.yml | 1 + 1 file changed, 1 insertion(+) 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 From 3d5b2643f0af742d9b90b4511d0ee137775c8526 Mon Sep 17 00:00:00 2001 From: mio Date: Sat, 10 Jun 2023 14:04:56 +0200 Subject: [PATCH 18/44] Support demand paging via closures and seh Reverts 12a79192ee6a4ec5b69130ff3481ac64d93a9b25 which exploits normal tcg mechanism This uses a trampoline to pass extra data to seh handlers --- include/uc_priv.h | 5 ++ msvc/config-host.h | 9 +-- qemu/accel/tcg/translate-all.c | 112 ++++++++++++++++++++++++++++----- qemu/include/sysemu/os-win32.h | 1 + qemu/include/tcg/tcg.h | 5 -- qemu/tcg/tcg.c | 18 +----- 6 files changed, 103 insertions(+), 47 deletions(-) diff --git a/include/uc_priv.h b/include/uc_priv.h index 5b2bfed0..968ab22f 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -399,6 +399,11 @@ struct uc_struct { struct TranslationBlock *last_tb; // The real last tb we executed. FlatView *empty_view; // Static function variable moved from flatviews_init + +#ifdef WIN32 + PVOID seh_handle; + void* seh_closure; +#endif }; // Metadata stub for the variable-size cpu context used with uc_context_*() diff --git a/msvc/config-host.h b/msvc/config-host.h index a5e1e190..d07f74ac 100644 --- a/msvc/config-host.h +++ b/msvc/config-host.h @@ -6,11 +6,4 @@ // #define CONFIG_INT128 1 #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 +#define CONFIG_PLUGIN 1 \ No newline at end of file diff --git a/qemu/accel/tcg/translate-all.c b/qemu/accel/tcg/translate-all.c index ac71e391..ac7f084c 100644 --- a/qemu/accel/tcg/translate-all.c +++ b/qemu/accel/tcg/translate-all.c @@ -869,35 +869,113 @@ 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) { + RemoveVectoredContinueHandler(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; + 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 + closure[0] = 0x48; // REX.w + closure[1] = 0xb8; // mov rax + memcpy(closure + 2, &data, 8); // mov rax, &data + // ; rax = &data + // mov [rax], rdx ; save rdx + // mov rdx, [rax+0x8] ; move uc pointer to 2nd arg + // jmp [rax + 0x10] ; go to handler + // mov rdx, [rax] ; restore rdx + const char tramp[] = "\x48\x89\x10\x48\x8b\x50\x08\xff\x60\x10\x48\x8b\x10"; + memcpy(closure + 2 + 8, (void*)tramp, sizeof(tramp)); + memcpy(data + 0x8, (void*)&uc, 8); + memcpy(data + 0x10, (void*)&handler, 8); +#else + closure[0] = 0xb8; // mov eax + memcpy(closure + 1, &data, 4); // mov eax, &data + // ; 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 + // jmp [eax + 0xC]; get ptr to our handler, it's fastcall so we don't clean stack + // mov edx, [eax] ; restore edx + // mov ecx, [eax+4] ; restore ecx + const char tramp[] = "\x89\x10\x89\x48\x04\x8b\x4c\x24\x04\x8b\x50\x08\xff\x60\x0c\x8b\x10\x8b\x48\x04"; + memcpy(closure + 1 + 4, (void*)tramp, sizeof(tramp)); + 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); } } 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/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/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 } /* From 9de80cb62529c5182697df5488288d0ebd1dfd54 Mon Sep 17 00:00:00 2001 From: mio Date: Sat, 10 Jun 2023 15:03:59 +0200 Subject: [PATCH 19/44] Correct calling convention --- qemu/accel/tcg/translate-all.c | 60 ++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/qemu/accel/tcg/translate-all.c b/qemu/accel/tcg/translate-all.c index ac7f084c..999321a7 100644 --- a/qemu/accel/tcg/translate-all.c +++ b/qemu/accel/tcg/translate-all.c @@ -920,6 +920,7 @@ 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; may_remove_handler(uc); @@ -933,31 +934,62 @@ static inline void *alloc_code_gen_buffer(struct uc_struct *uc) data = closure + CLOSURE_SIZE /2; #ifdef _WIN64 - closure[0] = 0x48; // REX.w - closure[1] = 0xb8; // mov rax - memcpy(closure + 2, &data, 8); // mov rax, &data + 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 - // jmp [rax + 0x10] ; go to handler - // mov rdx, [rax] ; restore rdx - const char tramp[] = "\x48\x89\x10\x48\x8b\x50\x08\xff\x60\x10\x48\x8b\x10"; - memcpy(closure + 2 + 8, (void*)tramp, sizeof(tramp)); + // 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 - closure[0] = 0xb8; // mov eax - memcpy(closure + 1, &data, 4); // mov eax, &data + 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 - // jmp [eax + 0xC]; get ptr to our handler, it's fastcall so we don't clean stack - // mov edx, [eax] ; restore edx - // mov ecx, [eax+4] ; restore ecx - const char tramp[] = "\x89\x10\x89\x48\x04\x8b\x4c\x24\x04\x8b\x50\x08\xff\x60\x0c\x8b\x10\x8b\x48\x04"; - memcpy(closure + 1 + 4, (void*)tramp, sizeof(tramp)); + // 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 From 5057f9925bb236268b8724e595afe0c61718340c Mon Sep 17 00:00:00 2001 From: mio Date: Sat, 10 Jun 2023 15:26:29 +0200 Subject: [PATCH 20/44] Fix typo --- qemu/accel/tcg/translate-all.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu/accel/tcg/translate-all.c b/qemu/accel/tcg/translate-all.c index 999321a7..835c054f 100644 --- a/qemu/accel/tcg/translate-all.c +++ b/qemu/accel/tcg/translate-all.c @@ -909,7 +909,7 @@ static LONG __fastcall code_gen_buffer_handler(PEXCEPTION_POINTERS ptr, struct u static inline void may_remove_handler(struct uc_struct *uc) { if (uc->seh_closure) { if (uc->seh_handle) { - RemoveVectoredContinueHandler(uc->seh_handle); + RemoveVectoredExceptionHandler(uc->seh_handle); } VirtualFree(uc->seh_closure, 0, MEM_RELEASE); } From 3145e3c4267ef287a780643d3ca0de70a173aa8c Mon Sep 17 00:00:00 2001 From: mio Date: Sat, 10 Jun 2023 16:08:29 +0200 Subject: [PATCH 21/44] Add uc_ctl_get/set_tcg_buffer_size --- include/uc_priv.h | 1 + include/unicorn/unicorn.h | 13 +++++++++++-- qemu/accel/tcg/translate-all.c | 1 + qemu/softmmu/vl.c | 2 +- uc.c | 14 ++++++++++++++ 5 files changed, 28 insertions(+), 3 deletions(-) diff --git a/include/uc_priv.h b/include/uc_priv.h index 968ab22f..62115278 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -400,6 +400,7 @@ struct uc_struct { FlatView *empty_view; // Static function variable moved from flatviews_init + uint64_t tcg_buffer_size; // The buffer size we are going to use #ifdef WIN32 PVOID seh_handle; void* seh_closure; diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index feae9eea..74193a6e 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -571,8 +571,12 @@ 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 = (uint64_t) + // Read: @args = (uint64_t*) + UC_CTL_TCG_BUFFER_SIZE, } uc_control_type; /* @@ -649,6 +653,11 @@ See sample_ctl.c for a detailed example. #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_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)) + // Opaque storage for CPU context, used with uc_context_*() struct uc_context; typedef struct uc_context uc_context; diff --git a/qemu/accel/tcg/translate-all.c b/qemu/accel/tcg/translate-all.c index 835c054f..9d728523 100644 --- a/qemu/accel/tcg/translate-all.c +++ b/qemu/accel/tcg/translate-all.c @@ -1085,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); 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/uc.c b/uc.c index 0b464a4d..2c4cb8de 100644 --- a/uc.c +++ b/uc.c @@ -2374,6 +2374,20 @@ uc_err uc_ctl(uc_engine *uc, uc_control_type control, ...) break; } + case UC_CTL_TCG_BUFFER_SIZE: { + if (rw == UC_CTL_IO_WRITE) { + uint64_t size = va_arg(args, uint64_t); + uc->tcg_buffer_size = size; + } else { + + UC_INIT(uc); + + uint64_t *size = va_arg(args, uint64_t *); + *size = uc->tcg_buffer_size; + } + break; + } + default: err = UC_ERR_ARG; break; From f8c7969d655c894800aaa2cf3520c398f34d4202 Mon Sep 17 00:00:00 2001 From: mio Date: Sat, 10 Jun 2023 23:29:56 +0200 Subject: [PATCH 22/44] Revert "Add uc_ctl_get/set_tcg_buffer_size" This reverts commit 3145e3c4267ef287a780643d3ca0de70a173aa8c because not properly co-authoer-ed. --- include/uc_priv.h | 1 - include/unicorn/unicorn.h | 13 ++----------- qemu/accel/tcg/translate-all.c | 1 - qemu/softmmu/vl.c | 2 +- uc.c | 14 -------------- 5 files changed, 3 insertions(+), 28 deletions(-) diff --git a/include/uc_priv.h b/include/uc_priv.h index 62115278..968ab22f 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -400,7 +400,6 @@ struct uc_struct { FlatView *empty_view; // Static function variable moved from flatviews_init - uint64_t tcg_buffer_size; // The buffer size we are going to use #ifdef WIN32 PVOID seh_handle; void* seh_closure; diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 74193a6e..feae9eea 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -571,12 +571,8 @@ typedef enum uc_control_type { // Change the tlb implementation // see uc_tlb_type for current implemented types // Write: @args = (int) - UC_CTL_TLB_TYPE, - // Change the tcg translation buffer size, note that - // unicorn may adjust this value. - // Write: @args = (uint64_t) - // Read: @args = (uint64_t*) - UC_CTL_TCG_BUFFER_SIZE, + UC_CTL_TLB_TYPE + } uc_control_type; /* @@ -653,11 +649,6 @@ See sample_ctl.c for a detailed example. #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_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)) - // Opaque storage for CPU context, used with uc_context_*() struct uc_context; typedef struct uc_context uc_context; diff --git a/qemu/accel/tcg/translate-all.c b/qemu/accel/tcg/translate-all.c index 9d728523..835c054f 100644 --- a/qemu/accel/tcg/translate-all.c +++ b/qemu/accel/tcg/translate-all.c @@ -1085,7 +1085,6 @@ 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); diff --git a/qemu/softmmu/vl.c b/qemu/softmmu/vl.c index 7802a2d5..6860afd9 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, uc->tcg_buffer_size); + uc->tcg_exec_init(uc, 0); /* Init cpu. use default cpu_model. */ return uc->cpus_init(uc, NULL); diff --git a/uc.c b/uc.c index 2c4cb8de..0b464a4d 100644 --- a/uc.c +++ b/uc.c @@ -2374,20 +2374,6 @@ uc_err uc_ctl(uc_engine *uc, uc_control_type control, ...) break; } - case UC_CTL_TCG_BUFFER_SIZE: { - if (rw == UC_CTL_IO_WRITE) { - uint64_t size = va_arg(args, uint64_t); - uc->tcg_buffer_size = size; - } else { - - UC_INIT(uc); - - uint64_t *size = va_arg(args, uint64_t *); - *size = uc->tcg_buffer_size; - } - break; - } - default: err = UC_ERR_ARG; break; From 8dffbc159c1d9d59611b9329287b4ea307be88c1 Mon Sep 17 00:00:00 2001 From: mio Date: Sat, 10 Jun 2023 23:36:02 +0200 Subject: [PATCH 23/44] Add uc_ctl_get/set_tcg_buffer_size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We still need this API because the virtual memory address space of 32 bits os is only 4GB and we default need 1G per instance Credits to @ZehMatt for original idea Co-authored-by: ζeh Matt <5415177+ZehMatt@users.noreply.github.com> --- include/uc_priv.h | 3 ++- include/unicorn/unicorn.h | 8 ++++++-- qemu/accel/tcg/translate-all.c | 2 +- qemu/include/sysemu/tcg.h | 2 +- qemu/unicorn_common.h | 2 +- uc.c | 14 ++++++++++++++ 6 files changed, 25 insertions(+), 6 deletions(-) diff --git a/include/uc_priv.h b/include/uc_priv.h index 968ab22f..d1a3dab2 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -90,7 +90,7 @@ 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); @@ -400,6 +400,7 @@ struct uc_struct { 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; diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index feae9eea..8c7dc3e6 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -571,8 +571,12 @@ 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, } uc_control_type; /* diff --git a/qemu/accel/tcg/translate-all.c b/qemu/accel/tcg/translate-all.c index 835c054f..8d6cb251 100644 --- a/qemu/accel/tcg/translate-all.c +++ b/qemu/accel/tcg/translate-all.c @@ -1209,7 +1209,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/include/sysemu/tcg.h b/qemu/include/sysemu/tcg.h index ea267831..77ab926a 100644 --- a/qemu/include/sysemu/tcg.h +++ b/qemu/include/sysemu/tcg.h @@ -14,6 +14,6 @@ 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/unicorn_common.h b/qemu/unicorn_common.h index d7802b3b..98b8cf37 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); diff --git a/uc.c b/uc.c index 0b464a4d..a07ff789 100644 --- a/uc.c +++ b/uc.c @@ -2374,6 +2374,20 @@ 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; + } + default: err = UC_ERR_ARG; break; From 49ccbde2d06bfffb3fa677a64630105d352202f1 Mon Sep 17 00:00:00 2001 From: mio Date: Sat, 10 Jun 2023 23:44:05 +0200 Subject: [PATCH 24/44] Leave out essential files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: ζeh Matt <5415177+ZehMatt@users.noreply.github.com> --- include/unicorn/unicorn.h | 5 +++++ qemu/accel/tcg/translate-all.c | 1 + qemu/softmmu/vl.c | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 8c7dc3e6..f44f6ed9 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -653,6 +653,11 @@ See sample_ctl.c for a detailed example. #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_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)) + // Opaque storage for CPU context, used with uc_context_*() struct uc_context; typedef struct uc_context uc_context; diff --git a/qemu/accel/tcg/translate-all.c b/qemu/accel/tcg/translate-all.c index 8d6cb251..e476c89e 100644 --- a/qemu/accel/tcg/translate-all.c +++ b/qemu/accel/tcg/translate-all.c @@ -1085,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); 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); From fa1f26138e57ea98a623caeff60b4fdadabcfec0 Mon Sep 17 00:00:00 2001 From: mio Date: Sat, 10 Jun 2023 23:48:18 +0200 Subject: [PATCH 25/44] Fix missing stdint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: ζeh Matt <5415177+ZehMatt@users.noreply.github.com> --- qemu/include/sysemu/tcg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu/include/sysemu/tcg.h b/qemu/include/sysemu/tcg.h index 77ab926a..2aa7296f 100644 --- a/qemu/include/sysemu/tcg.h +++ b/qemu/include/sysemu/tcg.h @@ -9,7 +9,7 @@ #define SYSEMU_TCG_H #include - +#include //#include "uc_priv.h" struct uc_struct; From d7a806c026246f69a3223278e3a891b875b6f6be Mon Sep 17 00:00:00 2001 From: Robert Xiao Date: Thu, 11 May 2023 12:42:20 -0700 Subject: [PATCH 26/44] Reformat code with format.sh --- include/uc_priv.h | 2 +- include/unicorn/unicorn.h | 16 +++++--- msvc/config-host.h | 2 +- qemu/target/i386/unicorn.c | 10 ++--- samples/sample_arm64.c | 4 +- samples/sample_mmu.c | 75 ++++++++++++++++++++++---------------- samples/sample_riscv.c | 2 +- samples/sample_sparc.c | 2 +- samples/sample_x86.c | 4 +- tests/unit/acutest.h | 3 +- tests/unit/endian.h | 72 +++++++++++++++++------------------- tests/unit/test_arm64.c | 26 ++++++++----- tests/unit/test_ctl.c | 43 +++++++++++++--------- tests/unit/test_riscv.c | 29 +++++++++++---- tests/unit/test_x86.c | 63 +++++++++++++++++++------------- tests/unit/unicorn_test.h | 23 ++++++------ uc.c | 6 +-- 17 files changed, 216 insertions(+), 166 deletions(-) diff --git a/include/uc_priv.h b/include/uc_priv.h index d1a3dab2..a65664a4 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -403,7 +403,7 @@ struct uc_struct { uint32_t tcg_buffer_size; // The buffer size we are going to use #ifdef WIN32 PVOID seh_handle; - void* seh_closure; + void *seh_closure; #endif }; diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index f44f6ed9..e7d9d4d1 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -264,13 +264,15 @@ typedef enum uc_mem_type { @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 { @@ -510,11 +512,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; @@ -652,7 +655,8 @@ 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) \ diff --git a/msvc/config-host.h b/msvc/config-host.h index d07f74ac..943d8593 100644 --- a/msvc/config-host.h +++ b/msvc/config-host.h @@ -6,4 +6,4 @@ // #define CONFIG_INT128 1 #define CONFIG_CMPXCHG128 1 // #define CONFIG_ATOMIC64 1 -#define CONFIG_PLUGIN 1 \ No newline at end of file +#define CONFIG_PLUGIN 1 diff --git a/qemu/target/i386/unicorn.c b/qemu/target/i386/unicorn.c index a7a93628..540ebd96 100644 --- a/qemu/target/i386/unicorn.c +++ b/qemu/target/i386/unicorn.c @@ -986,7 +986,7 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, goto write_cr; case UC_X86_REG_CR4: 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: @@ -1169,16 +1169,16 @@ write_cr: default: break; case UC_X86_REG_CR0: - cpu_x86_update_cr0(env, *(uint32_t *) value); + 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); + 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: + 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: 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/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 44f0ad9c..e016dc82 100644 --- a/tests/unit/test_arm64.c +++ b/tests/unit/test_arm64.c @@ -380,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] @@ -402,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); @@ -436,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))); @@ -484,7 +490,7 @@ static void test_arm64_pc_wrap(void) 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)); @@ -500,7 +506,7 @@ static void test_arm64_pc_wrap(void) OK(uc_reg_read(uc, UC_ARM64_REG_X0, &x0)); - TEST_CHECK( (x0 == 1 + 2) ); + 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)); @@ -518,7 +524,7 @@ static void test_arm64_pc_wrap(void) OK(uc_reg_read(uc, UC_ARM64_REG_X0, &x0)); - TEST_CHECK( (x0 == 5 + 5) ); + TEST_CHECK((x0 == 5 + 5)); OK(uc_close(uc)); } @@ -536,6 +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_pc_wrap", test_arm64_pc_wrap}, + {"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_riscv.c b/tests/unit/test_riscv.c index 7c66f89d..cf8b8fbe 100644 --- a/tests/unit/test_riscv.c +++ b/tests/unit/test_riscv.c @@ -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 61625e82..c55b9e36 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)); @@ -1419,14 +1431,13 @@ static void test_x86_segmentation() { uc_engine *uc; uint64_t fs = 0x53; - uc_x86_mmr gdtr = { 0, 0xfffff8076d962000, 0x57, 0 }; + 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)); } - TEST_LIST = { {"test_x86_in", test_x86_in}, {"test_x86_out", test_x86_out}, 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 a07ff789..81a89861 100644 --- a/uc.c +++ b/uc.c @@ -1495,16 +1495,14 @@ MemoryRegion *find_memory_region(struct uc_struct *uc, uint64_t address) // try with the cache index first i = uc->mapped_block_cache_index; - if (i < uc->mapped_block_count && - address >= uc->mapped_blocks[i]->addr && + 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 && + 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]; From 4055a5ab109c1d8d2da06515f3e117ca57faf179 Mon Sep 17 00:00:00 2001 From: Robert Xiao Date: Thu, 11 May 2023 12:43:15 -0700 Subject: [PATCH 27/44] Implement uc_reg_{read,write}{,_batch}2 APIs. These APIs take size parameters, which can be used to properly bounds-check the inputs and outputs for various registers. Additionally, all backends now throw UC_ERR_ARG if the input register numbers are invalid. Completes #1831. --- include/uc_priv.h | 11 +- include/unicorn/unicorn.h | 157 ++++++++- qemu/target/arm/unicorn.h | 24 +- qemu/target/arm/unicorn_aarch64.c | 114 +++++-- qemu/target/arm/unicorn_arm.c | 113 ++++++- qemu/target/i386/unicorn.c | 446 +++++++++++++++++++++---- qemu/target/i386/unicorn.h | 12 +- qemu/target/m68k/unicorn.c | 86 +++-- qemu/target/m68k/unicorn.h | 12 +- qemu/target/mips/unicorn.c | 93 ++++-- qemu/target/mips/unicorn.h | 25 +- qemu/target/ppc/unicorn.c | 195 +++++------ qemu/target/ppc/unicorn.h | 16 +- qemu/target/riscv/unicorn.c | 530 ++++++------------------------ qemu/target/riscv/unicorn.h | 18 +- qemu/target/s390x/unicorn.c | 123 ++++--- qemu/target/s390x/unicorn.h | 11 +- qemu/target/sparc/unicorn.c | 100 ++++-- qemu/target/sparc/unicorn.h | 17 +- qemu/target/sparc/unicorn64.c | 115 ++++--- qemu/target/tricore/unicorn.c | 207 ++++++++---- qemu/target/tricore/unicorn.h | 11 +- qemu/unicorn_common.h | 11 + uc.c | 108 ++++-- 24 files changed, 1523 insertions(+), 1032 deletions(-) diff --git a/include/uc_priv.h b/include/uc_priv.h index a65664a4..5fbdda07 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -63,15 +63,16 @@ 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_read_t)(struct uc_struct *uc, unsigned int *regs, + void *const *vals, size_t *sizes, int count); typedef int (*reg_write_t)(struct uc_struct *uc, unsigned int *regs, - void *const *vals, int count); + const void *const *vals, size_t *sizes, int count); typedef int (*context_reg_read_t)(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); + void *const *vals, size_t *sizes, int count); typedef int (*context_reg_write_t)(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); + const void *const *vals, size_t *sizes, + int count); typedef struct { context_reg_read_t context_reg_read; context_reg_write_t context_reg_write; diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index e7d9d4d1..dbe8d027 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -779,10 +779,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); @@ -794,22 +793,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_NOMEM if value is not large enough. +*/ +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_NOMEM if value is not large enough. +*/ +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, @@ -819,16 +845,49 @@ 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_NOMEM if some value is not large enough. +*/ +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_NOMEM if some value is not large enough. +*/ +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. @@ -1131,10 +1190,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); @@ -1146,12 +1204,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_NOMEM if value is not large enough. +*/ +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_NOMEM if value is not large enough. +*/ +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. @@ -1182,6 +1269,40 @@ 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_NOMEM if some value is not large enough. +*/ +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_NOMEM if some value is not large enough. +*/ +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/qemu/target/arm/unicorn.h b/qemu/target/arm/unicorn.h index df0b20a0..18612489 100644 --- a/qemu/target/arm/unicorn.h +++ b/qemu/target/arm/unicorn.h @@ -5,23 +5,23 @@ #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); +int arm_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count); +int arm_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count); +int arm64_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count); +int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count); int arm_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); + void *const *vals, size_t *sizes, int count); int arm_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); + const void *const *vals, size_t *sizes, int count); int arm64_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); + void *const *vals, size_t *sizes, int count); int arm64_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); + const void *const *vals, size_t *sizes, int count); void arm_reg_reset(struct uc_struct *uc); void arm64_reg_reset(struct uc_struct *uc); diff --git a/qemu/target/arm/unicorn_aarch64.c b/qemu/target/arm/unicorn_aarch64.c index e3bc63a3..f8d4446d 100644 --- a/qemu/target/arm/unicorn_aarch64.c +++ b/qemu/target/arm/unicorn_aarch64.c @@ -138,97 +138,127 @@ 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) +static uc_err reg_read(CPUARMState *env, unsigned int regid, void *value, + size_t *size) { - uc_err ret = UC_ERR_OK; + 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,98 +267,128 @@ 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) +static uc_err reg_write(CPUARMState *env, unsigned int regid, const void *value, + size_t *size) { - uc_err ret = UC_ERR_OK; + 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; 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; } @@ -337,8 +397,8 @@ 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) +int arm64_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count) { CPUARMState *env = &(ARM_CPU(uc->cpu)->env); int i; @@ -347,7 +407,7 @@ int arm64_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, for (i = 0; i < count; i++) { unsigned int regid = regs[i]; void *value = vals[i]; - err = reg_read(env, regid, value); + err = reg_read(env, regid, value, sizes ? sizes + i : NULL); if (err) { return err; } @@ -356,8 +416,8 @@ int arm64_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, return UC_ERR_OK; } -int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, - int count) +int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count) { CPUARMState *env = &(ARM_CPU(uc->cpu)->env); int i; @@ -366,7 +426,7 @@ int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, for (i = 0; i < count; i++) { unsigned int regid = regs[i]; const void *value = vals[i]; - err = reg_write(env, regid, value); + err = reg_write(env, regid, value, sizes ? sizes + i : NULL); if (err) { return err; } @@ -383,10 +443,10 @@ int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, DEFAULT_VISIBILITY #ifdef TARGET_WORDS_BIGENDIAN int arm64eb_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) + void *const *vals, size_t *sizes, int count) #else int arm64_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) + void *const *vals, size_t *sizes, int count) #endif { CPUARMState *env = (CPUARMState *)ctx->data; @@ -396,22 +456,22 @@ int arm64_context_reg_read(struct uc_context *ctx, unsigned int *regs, for (i = 0; i < count; i++) { unsigned int regid = regs[i]; void *value = vals[i]; - err = reg_read(env, regid, value); + err = reg_read(env, regid, value, sizes ? sizes + i : NULL); if (err) { return err; } } - return 0; + return UC_ERR_OK; } DEFAULT_VISIBILITY #ifdef TARGET_WORDS_BIGENDIAN int arm64eb_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) + const void *const *vals, size_t *sizes, int count) #else int arm64_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) + const void *const *vals, size_t *sizes, int count) #endif { CPUARMState *env = (CPUARMState *)ctx->data; @@ -421,13 +481,13 @@ int arm64_context_reg_write(struct uc_context *ctx, unsigned int *regs, for (i = 0; i < count; i++) { unsigned int regid = regs[i]; const void *value = vals[i]; - err = reg_write(env, regid, value); + err = reg_write(env, regid, value, sizes ? sizes + i : NULL); if (err) { return err; } } - return 0; + return UC_ERR_OK; } static int arm64_cpus_init(struct uc_struct *uc, const char *cpu_model) diff --git a/qemu/target/arm/unicorn_arm.c b/qemu/target/arm/unicorn_arm.c index e706b12b..3fc9704f 100644 --- a/qemu/target/arm/unicorn_arm.c +++ b/qemu/target/arm/unicorn_arm.c @@ -206,20 +206,25 @@ 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) +static uc_err reg_read(CPUARMState *env, unsigned int regid, void *value, + size_t *size) { - uc_err ret = UC_ERR_OK; + 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 +237,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 +354,25 @@ 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) +static uc_err reg_write(CPUARMState *env, unsigned int regid, const void *value, + size_t *size) { - uc_err ret = UC_ERR_OK; + 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 +387,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,26 +398,32 @@ 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); @@ -390,87 +434,114 @@ static uc_err reg_write(CPUARMState *env, unsigned int regid, const void *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); break; } @@ -479,8 +550,8 @@ 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) +int arm_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count) { CPUARMState *env = &(ARM_CPU(uc->cpu)->env); int i; @@ -489,17 +560,20 @@ int arm_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, for (i = 0; i < count; i++) { unsigned int regid = regs[i]; void *value = vals[i]; - err = reg_read(env, regid, value); + err = reg_read(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } if (err) { return err; } } - return 0; + return UC_ERR_OK; } -int arm_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, - int count) +int arm_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count) { CPUArchState *env = &(ARM_CPU(uc->cpu)->env); int i; @@ -508,7 +582,7 @@ int arm_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, for (i = 0; i < count; i++) { unsigned int regid = regs[i]; const void *value = vals[i]; - err = reg_write(env, regid, value); + err = reg_write(env, regid, value, sizes ? sizes + i : NULL); if (err) { return err; } @@ -519,12 +593,12 @@ int arm_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, } } - return 0; + return UC_ERR_OK; } DEFAULT_VISIBILITY int arm_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) + void *const *vals, size_t *sizes, int count) { CPUARMState *env = (CPUARMState *)ctx->data; int i; @@ -533,18 +607,21 @@ int arm_context_reg_read(struct uc_context *ctx, unsigned int *regs, for (i = 0; i < count; i++) { unsigned int regid = regs[i]; void *value = vals[i]; - err = reg_read(env, regid, value); + err = reg_read(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } if (err) { return err; } } - return 0; + return UC_ERR_OK; } DEFAULT_VISIBILITY int arm_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) + const void *const *vals, size_t *sizes, int count) { CPUARMState *env = (CPUARMState *)ctx->data; int i; @@ -553,13 +630,13 @@ int arm_context_reg_write(struct uc_context *ctx, unsigned int *regs, for (i = 0; i < count; i++) { unsigned int regid = regs[i]; const void *value = vals[i]; - err = reg_write(env, regid, value); + err = reg_write(env, regid, value, sizes ? sizes + i : NULL); if (err) { return err; } } - return 0; + return UC_ERR_OK; } static bool arm_stop_interrupt(struct uc_struct *uc, int intno) diff --git a/qemu/target/i386/unicorn.c b/qemu/target/i386/unicorn.c index 540ebd96..24d85754 100644 --- a/qemu/target/i386/unicorn.c +++ b/qemu/target/i386/unicorn.c @@ -211,9 +211,11 @@ 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) +static uc_err reg_read(CPUX86State *env, unsigned int regid, void *value, + size_t *size, uc_mode mode) { + uc_err ret = UC_ERR_ARG; + switch (regid) { default: break; @@ -225,22 +227,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 +273,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 +283,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 +298,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 +318,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 +326,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 +359,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 +393,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 +404,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 +592,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 +603,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 +966,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 +974,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 +986,13 @@ 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) +static uc_err reg_write(CPUX86State *env, unsigned int regid, const void *value, + size_t *size, uc_mode mode) { - int ret; + uc_err ret = UC_ERR_ARG; switch (regid) { default: @@ -852,21 +1005,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 +1031,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 +1041,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 +1056,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 +1076,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 +1086,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 +1120,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,14 +1146,17 @@ 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: env->cr[regid - UC_X86_REG_CR0] = *(uint32_t *)value; @@ -997,93 +1169,123 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, 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; break; case UC_X86_REG_IP: + CHECK_REG_TYPE(uint16_t); env->eip = *(uint16_t *)value; 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 +1293,7 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, 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 +1301,7 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, 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 +1309,7 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, 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 +1317,7 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, 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 +1325,7 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, 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 +1333,45 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, 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,14 +1384,17 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, default: break; case UC_X86_REG_CR0: + 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: + CHECK_REG_TYPE(uint64_t); cpu_x86_update_cr3(env, *(uint32_t *)value); goto write_cr64; case UC_X86_REG_CR4: + 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; @@ -1189,147 +1407,195 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, 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; break; case UC_X86_REG_EIP: + CHECK_REG_TYPE(uint32_t); env->eip = *(uint32_t *)value; break; case UC_X86_REG_IP: + CHECK_REG_TYPE(uint16_t); WRITE_WORD(env->eip, *(uint16_t *)value); 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 +1603,7 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, 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 +1611,163 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, 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 +1778,7 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, 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 +1786,11 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, 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,37 +1798,41 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, #endif } - return 0; + return ret; } -int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count) +int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count) { CPUX86State *env = &(X86_CPU(uc->cpu)->env); int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; void *value = vals[i]; - reg_read(env, regid, value, uc->mode); + err = reg_read(env, regid, value, sizes ? sizes + i : NULL, uc->mode); + if (err) { + return err; + } } - return 0; + return UC_ERR_OK; } -int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, - int count) +int x86_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count) { CPUX86State *env = &(X86_CPU(uc->cpu)->env); int i; - int ret; + uc_err err; 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; + err = reg_write(env, regid, value, sizes ? sizes + i : NULL, uc->mode); + if (err) { + return err; } switch (uc->mode) { default: @@ -1554,43 +1866,47 @@ int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, } } - return 0; + return UC_ERR_OK; } DEFAULT_VISIBILITY int x86_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) + void *const *vals, size_t *sizes, int count) { CPUX86State *env = (CPUX86State *)ctx->data; int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; void *value = vals[i]; - reg_read(env, regid, value, ctx->mode); + err = reg_read(env, regid, value, sizes ? sizes + i : NULL, ctx->mode); + if (err) { + return err; + } } - return 0; + return UC_ERR_OK; } DEFAULT_VISIBILITY int x86_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) + const void *const *vals, size_t *sizes, int count) { CPUX86State *env = (CPUX86State *)ctx->data; int i; - int ret; + uc_err err; 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; + err = reg_write(env, regid, value, sizes ? sizes + i : NULL, ctx->mode); + if (err) { + return err; } } - return 0; + return UC_ERR_OK; } static bool x86_stop_interrupt(struct uc_struct *uc, int intno) diff --git a/qemu/target/i386/unicorn.h b/qemu/target/i386/unicorn.h index 7c456cfb..fe5688ad 100644 --- a/qemu/target/i386/unicorn.h +++ b/qemu/target/i386/unicorn.h @@ -6,14 +6,14 @@ #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_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count); +int x86_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count); int x86_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); + void *const *vals, size_t *sizes, int count); int x86_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); + const void *const *vals, size_t *sizes, int count); void x86_reg_reset(struct uc_struct *uc); diff --git a/qemu/target/m68k/unicorn.c b/qemu/target/m68k/unicorn.c index d0a091fa..414a94ce 100644 --- a/qemu/target/m68k/unicorn.c +++ b/qemu/target/m68k/unicorn.c @@ -49,71 +49,97 @@ void m68k_reg_reset(struct uc_struct *uc) env->pc = 0; } -static void reg_read(CPUM68KState *env, unsigned int regid, void *value) +static uc_err reg_read(CPUM68KState *env, 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 { + 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) +static uc_err reg_write(CPUM68KState *env, unsigned int regid, + const void *value, size_t *size) { - if (regid >= UC_M68K_REG_A0 && regid <= UC_M68K_REG_A7) + 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; break; case UC_M68K_REG_SR: + CHECK_REG_TYPE(uint32_t); cpu_m68k_set_sr(env, *(uint32_t *)value); break; } } + + return ret; } -int m68k_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count) +int m68k_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count) { CPUM68KState *env = &(M68K_CPU(uc->cpu)->env); int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; void *value = vals[i]; - reg_read(env, regid, value); + err = reg_read(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } } - return 0; + return UC_ERR_OK; } -int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, - int count) +int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count) { CPUM68KState *env = &(M68K_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]; - reg_write(env, regid, value); + err = reg_write(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } if (regid == UC_M68K_REG_PC) { // force to quit execution and flush TB uc->quit_request = true; @@ -121,39 +147,47 @@ int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, } } - return 0; + return UC_ERR_OK; } DEFAULT_VISIBILITY int m68k_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) + void *const *vals, size_t *sizes, int count) { CPUM68KState *env = (CPUM68KState *)ctx->data; int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; void *value = vals[i]; - reg_read(env, regid, value); + err = reg_read(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } } - return 0; + return UC_ERR_OK; } DEFAULT_VISIBILITY int m68k_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) + const void *const *vals, size_t *sizes, int count) { CPUM68KState *env = (CPUM68KState *)ctx->data; int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; const void *value = vals[i]; - reg_write(env, regid, value); + err = reg_write(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } } - return 0; + return UC_ERR_OK; } static int m68k_cpus_init(struct uc_struct *uc, const char *cpu_model) diff --git a/qemu/target/m68k/unicorn.h b/qemu/target/m68k/unicorn.h index ebd5c310..463cfd33 100644 --- a/qemu/target/m68k/unicorn.h +++ b/qemu/target/m68k/unicorn.h @@ -5,14 +5,14 @@ #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_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count); +int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count); int m68k_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); + void *const *vals, size_t *sizes, int count); int m68k_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); + const void *const *vals, size_t *sizes, int count); void m68k_reg_reset(struct uc_struct *uc); diff --git a/qemu/target/mips/unicorn.c b/qemu/target/mips/unicorn.c index fb91e9c1..786e014d 100644 --- a/qemu/target/mips/unicorn.c +++ b/qemu/target/mips/unicorn.c @@ -59,99 +59,127 @@ void mips_reg_reset(struct uc_struct *uc) env->active_tc.PC = 0; } -static void reg_read(CPUMIPSState *env, unsigned int regid, void *value) +static uc_err reg_read(CPUMIPSState *env, unsigned int regid, void *value, + size_t *size) { - if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31) + 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) +static uc_err reg_write(CPUMIPSState *env, unsigned int regid, + const void *value, size_t *size) { - if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31) + 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; 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; + return ret; } -int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count) +int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count) { CPUMIPSState *env = &(MIPS_CPU(uc->cpu)->env); int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; void *value = vals[i]; - reg_read(env, regid, value); + err = reg_read(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } } - return 0; + return UC_ERR_OK; } -int mips_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, - int count) +int mips_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count) { CPUMIPSState *env = &(MIPS_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]; - reg_write(env, regid, value); + err = reg_write(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } if (regid == UC_MIPS_REG_PC) { // force to quit execution and flush TB uc->quit_request = true; @@ -159,69 +187,78 @@ int mips_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, } } - return 0; + return UC_ERR_OK; } 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) + void *const *vals, size_t *sizes, int count) #else int mips64el_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) + void *const *vals, size_t *sizes, 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) + void *const *vals, size_t *sizes, int count) #else int mipsel_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) + void *const *vals, size_t *sizes, int count) #endif #endif { CPUMIPSState *env = (CPUMIPSState *)ctx->data; int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; void *value = vals[i]; - reg_read(env, regid, value); + err = reg_read(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } } - return 0; + return UC_ERR_OK; } 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) + const void *const *vals, size_t *sizes, int count) #else int mips64el_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) + const void *const *vals, size_t *sizes, + 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) + const void *const *vals, size_t *sizes, int count) #else int mipsel_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) + const void *const *vals, size_t *sizes, int count) #endif #endif { CPUMIPSState *env = (CPUMIPSState *)ctx->data; int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; const void *value = vals[i]; - reg_write(env, regid, value); + err = reg_write(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } } - return 0; + return UC_ERR_OK; } static int mips_cpus_init(struct uc_struct *uc, const char *cpu_model) diff --git a/qemu/target/mips/unicorn.h b/qemu/target/mips/unicorn.h index 5a806522..caaa414c 100644 --- a/qemu/target/mips/unicorn.h +++ b/qemu/target/mips/unicorn.h @@ -5,27 +5,28 @@ #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); +int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count); +int mips_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count); int mips_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); + void *const *vals, size_t *sizes, int count); int mips_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); + const void *const *vals, size_t *sizes, int count); int mipsel_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); + void *const *vals, size_t *sizes, int count); int mipsel_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); + const void *const *vals, size_t *sizes, int count); int mips64_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); + void *const *vals, size_t *sizes, int count); int mips64_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); + const void *const *vals, size_t *sizes, int count); int mips64el_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); + void *const *vals, size_t *sizes, int count); int mips64el_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); + const void *const *vals, size_t *sizes, + int count); void mips_reg_reset(struct uc_struct *uc); diff --git a/qemu/target/ppc/unicorn.c b/qemu/target/ppc/unicorn.c index b3e75f7d..b0f02ce2 100644 --- a/qemu/target/ppc/unicorn.c +++ b/qemu/target/ppc/unicorn.c @@ -146,64 +146,31 @@ 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) +static uc_err reg_read(CPUPPCState *env, unsigned int regid, void *value, + size_t *size) { - uint32_t val; + 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: + case UC_PPC_REG_CR: { + CHECK_REG_TYPE(uint32_t); + uint32_t val; val = 0; for (int i = 0; i < 8; i++) { val <<= 4; @@ -211,138 +178,124 @@ static void reg_read(CPUPPCState *env, unsigned int regid, void *value) } *(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) +static uc_err reg_write(CPUPPCState *env, unsigned int regid, const void *value, + size_t *size) { - uint32_t val; int i; + 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; 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); + 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; + return ret; } -int ppc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count) +int ppc_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count) { CPUPPCState *env = &(POWERPC_CPU(uc->cpu)->env); int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; void *value = vals[i]; - reg_read(env, regid, value); + err = reg_read(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } } - return 0; + return UC_ERR_OK; } -int ppc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, - int count) +int ppc_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count) { CPUPPCState *env = &(POWERPC_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]; - reg_write(env, regid, value); + err = reg_write(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } if (regid == UC_PPC_REG_PC) { // force to quit execution and flush TB uc->quit_request = true; @@ -350,49 +303,57 @@ int ppc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, } } - return 0; + return UC_ERR_OK; } DEFAULT_VISIBILITY #ifdef TARGET_PPC64 int ppc64_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) + void *const *vals, size_t *sizes, int count) #else int ppc_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) + void *const *vals, size_t *sizes, int count) #endif { CPUPPCState *env = (CPUPPCState *)ctx->data; int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; void *value = vals[i]; - reg_read(env, regid, value); + err = reg_read(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } } - return 0; + return UC_ERR_OK; } DEFAULT_VISIBILITY #ifdef TARGET_PPC64 int ppc64_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) + const void *const *vals, size_t *sizes, int count) #else int ppc_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) + const void *const *vals, size_t *sizes, int count) #endif { CPUPPCState *env = (CPUPPCState *)ctx->data; int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; const void *value = vals[i]; - reg_write(env, regid, value); + err = reg_write(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } } - return 0; + return UC_ERR_OK; } PowerPCCPU *cpu_ppc_init(struct uc_struct *uc); diff --git a/qemu/target/ppc/unicorn.h b/qemu/target/ppc/unicorn.h index 2afaa3a0..df1d901f 100644 --- a/qemu/target/ppc/unicorn.h +++ b/qemu/target/ppc/unicorn.h @@ -5,19 +5,19 @@ #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); +int ppc_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count); +int ppc_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count); int ppc_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); + void *const *vals, size_t *sizes, int count); int ppc_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); + const void *const *vals, size_t *sizes, int count); int ppc64_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); + void *const *vals, size_t *sizes, int count); int ppc64_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); + const void *const *vals, size_t *sizes, int count); void ppc_reg_reset(struct uc_struct *uc); diff --git a/qemu/target/riscv/unicorn.c b/qemu/target/riscv/unicorn.c index 8970051e..846d2c17 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); @@ -78,485 +79,134 @@ static void riscv_release(void *ctx) void riscv_reg_reset(struct uc_struct *uc) {} -static void reg_read(CPURISCVState *env, unsigned int regid, void *value) +static uc_err reg_read(CPURISCVState *env, 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; + 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; + } else { + switch (regid) { + default: + break; + case UC_RISCV_REG_PC: +#ifdef TARGET_RISCV64 + CHECK_REG_TYPE(uint64_t); + *(uint64_t *)value = env->pc; +#else + CHECK_REG_TYPE(uint32_t); + *(uint32_t *)value = env->pc; +#endif + break; + } } - return; + return ret; } -static void reg_write(CPURISCVState *env, unsigned int regid, const void *value) +static uc_err reg_write(CPURISCVState *env, unsigned int regid, + const 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: + uc_err ret = UC_ERR_ARG; + + 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 - 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 + } 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 - 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: { + } 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 - break; - } - default: - break; + } 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 + break; + } } + + return ret; } -int riscv_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count) +int riscv_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count) { CPURISCVState *env = &(RISCV_CPU(uc->cpu)->env); int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; void *value = vals[i]; - reg_read(env, regid, value); + err = reg_read(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } } - return 0; + return UC_ERR_OK; } -int riscv_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, - int count) +int riscv_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count) { CPURISCVState *env = &(RISCV_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]; - reg_write(env, regid, value); + err = reg_write(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } if (regid == UC_RISCV_REG_PC) { // force to quit execution and flush TB uc->quit_request = true; @@ -564,51 +214,59 @@ int riscv_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, } } - return 0; + return UC_ERR_OK; } DEFAULT_VISIBILITY #ifdef TARGET_RISCV32 int riscv32_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) + void *const *vals, size_t *sizes, int count) #else /* TARGET_RISCV64 */ int riscv64_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) + void *const *vals, size_t *sizes, int count) #endif { CPURISCVState *env = (CPURISCVState *)ctx->data; int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; void *value = vals[i]; - reg_read(env, regid, value); + err = reg_read(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } } - return 0; + return UC_ERR_OK; } DEFAULT_VISIBILITY #ifdef TARGET_RISCV32 int riscv32_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) + const void *const *vals, size_t *sizes, int count) #else /* TARGET_RISCV64 */ int riscv64_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) + const void *const *vals, size_t *sizes, int count) #endif { CPURISCVState *env = (CPURISCVState *)ctx->data; int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; const void *value = vals[i]; - reg_write(env, regid, value); + err = reg_write(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } } - return 0; + return UC_ERR_OK; } static bool riscv_stop_interrupt(struct uc_struct *uc, int intno) diff --git a/qemu/target/riscv/unicorn.h b/qemu/target/riscv/unicorn.h index 6add9369..c7eeb450 100644 --- a/qemu/target/riscv/unicorn.h +++ b/qemu/target/riscv/unicorn.h @@ -6,19 +6,21 @@ #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); +int riscv_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count); +int riscv_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count); int riscv32_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); + void *const *vals, size_t *sizes, int count); int riscv32_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); + const void *const *vals, size_t *sizes, + int count); int riscv64_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); + void *const *vals, size_t *sizes, int count); int riscv64_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); + const void *const *vals, size_t *sizes, + int count); void riscv_reg_reset(struct uc_struct *uc); diff --git a/qemu/target/s390x/unicorn.c b/qemu/target/s390x/unicorn.c index 6378fe4c..f2e54d02 100644 --- a/qemu/target/s390x/unicorn.c +++ b/qemu/target/s390x/unicorn.c @@ -53,80 +53,99 @@ void s390_reg_reset(struct uc_struct *uc) env->psw.addr = 0; } -static void reg_read(CPUS390XState *env, unsigned int regid, void *value) +static uc_err reg_read(CPUS390XState *env, unsigned int regid, void *value, + size_t *size) { + 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; + } 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; + } } - 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; - } + return ret; } -static void reg_write(CPUS390XState *env, unsigned int regid, const void *value) +static uc_err reg_write(CPUS390XState *env, unsigned int regid, + const void *value, size_t *size) { + uc_err ret = UC_ERR_ARG; + 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; - 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); 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; + } else { + switch (regid) { + default: + break; + case UC_S390X_REG_PC: + CHECK_REG_TYPE(uint64_t); + env->psw.addr = *(uint64_t *)value; + 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 ret; } -static int s390_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count) +DEFAULT_VISIBILITY +int s390_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count) { CPUS390XState *env = &(S390_CPU(uc->cpu)->env); int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; void *value = vals[i]; - reg_read(env, regid, value); + err = reg_read(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } } - return 0; + return UC_ERR_OK; } -static int s390_reg_write(struct uc_struct *uc, unsigned int *regs, - void *const *vals, int count) +DEFAULT_VISIBILITY +int s390_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count) { CPUS390XState *env = &(S390_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]; - reg_write(env, regid, value); + err = reg_write(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } if (regid == UC_S390X_REG_PC) { // force to quit execution and flush TB uc->quit_request = true; @@ -134,39 +153,47 @@ static int s390_reg_write(struct uc_struct *uc, unsigned int *regs, } } - return 0; + return UC_ERR_OK; } DEFAULT_VISIBILITY int s390_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) + void *const *vals, size_t *sizes, int count) { CPUS390XState *env = (CPUS390XState *)ctx->data; int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; void *value = vals[i]; - reg_read(env, regid, value); + err = reg_read(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } } - return 0; + return UC_ERR_OK; } DEFAULT_VISIBILITY int s390_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) + const void *const *vals, size_t *sizes, int count) { CPUS390XState *env = (CPUS390XState *)ctx->data; int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; const void *value = vals[i]; - reg_write(env, regid, value); + err = reg_write(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } } - return 0; + return UC_ERR_OK; } static int s390_cpus_init(struct uc_struct *uc, const char *cpu_model) diff --git a/qemu/target/s390x/unicorn.h b/qemu/target/s390x/unicorn.h index 27c20653..50d507e6 100644 --- a/qemu/target/s390x/unicorn.h +++ b/qemu/target/s390x/unicorn.h @@ -5,13 +5,14 @@ #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_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count); +int s390_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count); int s390_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); + void *const *vals, size_t *sizes, int count); int s390_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); + const void *const *vals, size_t *sizes, int count); void s390_reg_reset(struct uc_struct *uc); diff --git a/qemu/target/sparc/unicorn.c b/qemu/target/sparc/unicorn.c index 2df5b9b3..d000b7de 100644 --- a/qemu/target/sparc/unicorn.c +++ b/qemu/target/sparc/unicorn.c @@ -61,119 +61,149 @@ void sparc_reg_reset(struct uc_struct *uc) env->regwptr = env->regbase; } -static void reg_read(CPUSPARCState *env, unsigned int regid, void *value) +static uc_err reg_read(CPUSPARCState *env, 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 { + 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) +static uc_err reg_write(CPUSPARCState *env, unsigned int regid, + const void *value, size_t *size) { - if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) + 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; break; } } - return; + return ret; } -int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, - int count) +int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count) { CPUSPARCState *env = &(SPARC_CPU(uc->cpu)->env); int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; void *value = vals[i]; - reg_read(env, regid, value); + err = reg_read(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } } - return 0; + return UC_ERR_OK; } -int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, - int count) +int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count) { CPUSPARCState *env = &(SPARC_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]; - reg_write(env, regid, value); + err = reg_write(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } if (regid == UC_SPARC_REG_PC) { // force to quit execution and flush TB uc->quit_request = true; - uc_emu_stop(uc); - break; + break_translation_loop(uc); } } - return 0; + return UC_ERR_OK; } DEFAULT_VISIBILITY int sparc_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count) + void *const *vals, size_t *sizes, int count) { CPUSPARCState *env = (CPUSPARCState *)ctx->data; int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; void *value = vals[i]; - reg_read(env, regid, value); + err = reg_read(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } } - return 0; + return UC_ERR_OK; } DEFAULT_VISIBILITY int sparc_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count) + const void *const *vals, size_t *sizes, int count) { CPUSPARCState *env = (CPUSPARCState *)ctx->data; int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; const void *value = vals[i]; - reg_write(env, regid, value); + err = reg_write(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } } - return 0; + return UC_ERR_OK; } static int sparc_cpus_init(struct uc_struct *uc, const char *cpu_model) diff --git a/qemu/target/sparc/unicorn.h b/qemu/target/sparc/unicorn.h index 1f9818aa..62c82ba2 100644 --- a/qemu/target/sparc/unicorn.h +++ b/qemu/target/sparc/unicorn.h @@ -5,19 +5,20 @@ #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); +int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count); +int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count); int sparc_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); + void *const *vals, size_t *sizes, int count); int sparc_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); + const void *const *vals, size_t *sizes, int count); int sparc64_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void **vals, int count); + void *const *vals, size_t *sizes, int count); int sparc64_context_reg_write(struct uc_context *ctx, unsigned int *regs, - void *const *vals, int count); + const void *const *vals, size_t *sizes, + int count); void sparc_reg_reset(struct uc_struct *uc); diff --git a/qemu/target/sparc/unicorn64.c b/qemu/target/sparc/unicorn64.c index 5b53943f..f477ea06 100644 --- a/qemu/target/sparc/unicorn64.c +++ b/qemu/target/sparc/unicorn64.c @@ -83,103 +83,144 @@ void sparc_reg_reset(struct uc_struct *uc) env->regwptr = env->regbase; } -static void reg_read(CPUSPARCState *env, unsigned int regid, void *value) +static uc_err reg_read(CPUSPARCState *env, 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 { + 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) +static uc_err reg_write(CPUSPARCState *env, unsigned int regid, const void *value, size_t *size) { - if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) + 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; + break; } } + + return ret; } -int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count) +int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, size_t *sizes, int count) { CPUSPARCState *env = &(SPARC_CPU(uc->cpu)->env); int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; void *value = vals[i]; - reg_read(env, regid, value); + err = reg_read(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } } - return 0; + return UC_ERR_OK; } -int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void* const* vals, int count) +int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, const void* const* vals, size_t *sizes, int count) { CPUSPARCState *env = &(SPARC_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]; - reg_write(env, regid, value); + err = reg_write(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } + if (regid == UC_SPARC_REG_PC) { + // force to quit execution and flush TB + uc->quit_request = true; + break_translation_loop(uc); + } } - return 0; + return UC_ERR_OK; } DEFAULT_VISIBILITY -int sparc64_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count) +int sparc64_context_reg_read(struct uc_context *ctx, unsigned int *regs, void *const *vals, size_t *sizes, int count) { CPUSPARCState *env = (CPUSPARCState *)ctx->data; int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; void *value = vals[i]; - reg_read(env, regid, value); + err = reg_read(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } } - return 0; + return UC_ERR_OK; } DEFAULT_VISIBILITY -int sparc64_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count) +int sparc64_context_reg_write(struct uc_context *ctx, unsigned int *regs, const void *const *vals, size_t *sizes, int count) { CPUSPARCState *env = (CPUSPARCState *)ctx->data; int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; const void *value = vals[i]; - reg_write(env, regid, value); + err = reg_write(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } } - return 0; + return UC_ERR_OK; } static int sparc_cpus_init(struct uc_struct *uc, const char *cpu_model) diff --git a/qemu/target/tricore/unicorn.c b/qemu/target/tricore/unicorn.c index a3eac632..155cff15 100644 --- a/qemu/target/tricore/unicorn.c +++ b/qemu/target/tricore/unicorn.c @@ -39,193 +39,258 @@ void tricore_reg_reset(struct uc_struct *uc) env->PC = 0; } -static void reg_read(CPUTriCoreState *env, unsigned int regid, void *value) +static uc_err reg_read(CPUTriCoreState *env, 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 { + 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) +int tricore_reg_read(struct uc_struct *uc, unsigned int *regs, + void *const *vals, size_t *sizes, int count) { CPUTriCoreState *env = &(TRICORE_CPU(uc->cpu)->env); int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; void *value = vals[i]; - reg_read(env, regid, value); + err = reg_read(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } } - return 0; + return UC_ERR_OK; } int tricore_context_reg_read(struct uc_context *uc, unsigned int *regs, - void **vals, int count) + void *const *vals, size_t *sizes, int count) { CPUTriCoreState *env = (CPUTriCoreState *)uc->data; int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; void *value = vals[i]; - reg_read(env, regid, value); + err = reg_read(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } } - return 0; + return UC_ERR_OK; } -static void reg_write(CPUTriCoreState *env, unsigned int regid, - const void *value) +static uc_err reg_write(CPUTriCoreState *env, unsigned int regid, + const void *value, size_t *size) { - 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 { + uc_err ret = UC_ERR_ARG; + + 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; 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; } } + + return ret; } int tricore_reg_write(struct uc_struct *uc, unsigned int *regs, - void *const *vals, int count) + const void *const *vals, size_t *sizes, int count) { CPUTriCoreState *env = &(TRICORE_CPU(uc->cpu)->env); int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; - void *value = vals[i]; - reg_write(env, regid, value); + const void *value = vals[i]; + err = reg_write(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } if (regid == UC_TRICORE_REG_PC) { // force to quit execution and flush TB uc->quit_request = true; @@ -233,22 +298,26 @@ int tricore_reg_write(struct uc_struct *uc, unsigned int *regs, } } - return 0; + return UC_ERR_OK; } int tricore_context_reg_write(struct uc_context *uc, unsigned int *regs, - void *const *vals, int count) + const void *const *vals, size_t *sizes, int count) { CPUTriCoreState *env = (CPUTriCoreState *)uc->data; int i; + uc_err err; for (i = 0; i < count; i++) { unsigned int regid = regs[i]; const void *value = vals[i]; - reg_write(env, regid, value); + err = reg_write(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } } - return 0; + return UC_ERR_OK; } static int tricore_cpus_init(struct uc_struct *uc, const char *cpu_model) diff --git a/qemu/target/tricore/unicorn.h b/qemu/target/tricore/unicorn.h index 36d30ee7..e298da05 100644 --- a/qemu/target/tricore/unicorn.h +++ b/qemu/target/tricore/unicorn.h @@ -10,15 +10,16 @@ #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_read(struct uc_struct *uc, unsigned int *regs, + void *const *vals, size_t *sizes, int count); int tricore_reg_write(struct uc_struct *uc, unsigned int *regs, - void *const *vals, int count); + const void *const *vals, size_t *sizes, int count); int tricore_context_reg_read(struct uc_context *uc, unsigned int *regs, - void **vals, int count); + void *const *vals, size_t *sizes, int count); int tricore_context_reg_write(struct uc_context *uc, unsigned int *regs, - void *const *vals, int count); + const void *const *vals, size_t *sizes, + int count); void tricore_reg_reset(struct uc_struct *uc); diff --git a/qemu/unicorn_common.h b/qemu/unicorn_common.h index 98b8cf37..b5cb5610 100644 --- a/qemu/unicorn_common.h +++ b/qemu/unicorn_common.h @@ -128,4 +128,15 @@ static inline void uc_common_init(struct uc_struct* uc) if (!uc->release) uc->release = release_common; } + +#define CHECK_REG_TYPE(type) do { \ + if (size) { \ + if (*size < sizeof(type)) { \ + return UC_ERR_NOMEM; \ + } \ + *size = sizeof(type); \ + } \ + ret = UC_ERR_OK; \ +} while(0) + #endif diff --git a/uc.c b/uc.c index 81a89861..1152f3ee 100644 --- a/uc.c +++ b/uc.c @@ -507,47 +507,63 @@ uc_err uc_close(uc_engine *uc) UNICORN_EXPORT uc_err uc_reg_read_batch(uc_engine *uc, int *ids, void **vals, int count) { - int ret = UC_ERR_OK; - - UC_INIT(uc); - - if (uc->reg_read) { - ret = uc->reg_read(uc, (unsigned int *)ids, vals, count); - } else { - return UC_ERR_HANDLE; - } - - return ret; + return uc_reg_read_batch2(uc, ids, vals, NULL, count); } UNICORN_EXPORT uc_err uc_reg_write_batch(uc_engine *uc, int *ids, void *const *vals, int count) { - int ret = UC_ERR_OK; + return uc_reg_write_batch2(uc, ids, (const void *const *)vals, NULL, count); +} +UNICORN_EXPORT +uc_err uc_reg_read_batch2(uc_engine *uc, int *ids, void *const *vals, + size_t *sizes, int count) +{ UC_INIT(uc); - if (uc->reg_write) { - ret = uc->reg_write(uc, (unsigned int *)ids, vals, count); + if (uc->reg_read) { + return uc->reg_read(uc, (unsigned int *)ids, vals, sizes, count); } else { return UC_ERR_HANDLE; } +} - return ret; +UNICORN_EXPORT +uc_err uc_reg_write_batch2(uc_engine *uc, int *ids, const void *const *vals, + size_t *sizes, int count) +{ + UC_INIT(uc); + + if (uc->reg_write) { + return uc->reg_write(uc, (unsigned int *)ids, vals, sizes, count); + } else { + return UC_ERR_HANDLE; + } } 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); + return uc_reg_read_batch2(uc, ®id, &value, NULL, 1); } 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); + return uc_reg_write_batch2(uc, ®id, &value, NULL, 1); +} + +UNICORN_EXPORT +uc_err uc_reg_read2(uc_engine *uc, int regid, void *value, size_t *size) +{ + return uc_reg_read_batch2(uc, ®id, &value, size, 1); +} + +UNICORN_EXPORT +uc_err uc_reg_write2(uc_engine *uc, int regid, const void *value, size_t *size) +{ + return uc_reg_write_batch2(uc, ®id, &value, size, 1); } // check if a memory area is mapped @@ -1869,13 +1885,42 @@ uc_err uc_context_save(uc_engine *uc, uc_context *context) 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); + return uc_context_reg_write_batch2(ctx, ®id, &value, NULL, 1); } 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); + return uc_context_reg_read_batch2(ctx, ®id, &value, NULL, 1); +} + +UNICORN_EXPORT +uc_err uc_context_reg_write2(uc_context *ctx, int regid, const void *value, + size_t *size) +{ + return uc_context_reg_write_batch2(ctx, ®id, &value, size, 1); +} + +UNICORN_EXPORT +uc_err uc_context_reg_read2(uc_context *ctx, int regid, void *value, + size_t *size) +{ + return uc_context_reg_read_batch2(ctx, ®id, &value, size, 1); +} + +UNICORN_EXPORT +uc_err uc_context_reg_write_batch(uc_context *ctx, int *ids, void *const *vals, + int count) +{ + return uc_context_reg_write_batch2(ctx, ids, (const void *const *)vals, + NULL, count); +} + +UNICORN_EXPORT +uc_err uc_context_reg_read_batch(uc_context *ctx, int *ids, void **vals, + int count) +{ + return uc_context_reg_read_batch2(ctx, ids, vals, NULL, count); } // Keep in mind that we don't a uc_engine when r/w the registers of a context. @@ -1997,37 +2042,34 @@ static void find_context_reg_rw_function(uc_arch arch, uc_mode mode, } UNICORN_EXPORT -uc_err uc_context_reg_write_batch(uc_context *ctx, int *ids, void *const *vals, - int count) +uc_err uc_context_reg_write_batch2(uc_context *ctx, int *ids, + const void *const *vals, size_t *sizes, + int count) { - int ret = UC_ERR_OK; context_reg_rw_t rw; 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); + return rw.context_reg_write(ctx, (unsigned int *)ids, vals, sizes, + count); } else { return UC_ERR_HANDLE; } - - return ret; } UNICORN_EXPORT -uc_err uc_context_reg_read_batch(uc_context *ctx, int *ids, void **vals, - int count) +uc_err uc_context_reg_read_batch2(uc_context *ctx, int *ids, void *const *vals, + size_t *sizes, int count) { - int ret = UC_ERR_OK; context_reg_rw_t rw; 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); + return rw.context_reg_read(ctx, (unsigned int *)ids, vals, sizes, + count); } else { return UC_ERR_HANDLE; } - - return ret; } UNICORN_EXPORT From 074566cf697bfa38b3c9dd283c52ef4e4549c208 Mon Sep 17 00:00:00 2001 From: Robert Xiao Date: Thu, 11 May 2023 20:08:27 -0700 Subject: [PATCH 28/44] Slight refactoring to reduce code duplication. This also comes with a performance bump due to inlining of reg_read/reg_write (as they're only called once now) and the unlikely() on CHECK_REG_TYPE. --- qemu/target/arm/unicorn_aarch64.c | 80 +++++++++++----------- qemu/target/arm/unicorn_arm.c | 86 +++++++++++------------- qemu/target/i386/unicorn.c | 107 ++++++++++++------------------ qemu/target/m68k/unicorn.c | 80 +++++++++++----------- qemu/target/mips/unicorn.c | 80 +++++++++++----------- qemu/target/ppc/unicorn.c | 80 +++++++++++----------- qemu/target/riscv/unicorn.c | 80 +++++++++++----------- qemu/target/s390x/unicorn.c | 92 ++++++++++++------------- qemu/target/sparc/unicorn.c | 80 +++++++++++----------- qemu/target/sparc/unicorn64.c | 72 +++++++++----------- qemu/target/tricore/unicorn.c | 106 ++++++++++++++--------------- qemu/unicorn_common.h | 16 ++--- uc.c | 47 ++++++++----- 13 files changed, 473 insertions(+), 533 deletions(-) diff --git a/qemu/target/arm/unicorn_aarch64.c b/qemu/target/arm/unicorn_aarch64.c index f8d4446d..06320819 100644 --- a/qemu/target/arm/unicorn_aarch64.c +++ b/qemu/target/arm/unicorn_aarch64.c @@ -268,7 +268,7 @@ static uc_err reg_read(CPUARMState *env, unsigned int regid, void *value, } static uc_err reg_write(CPUARMState *env, unsigned int regid, const void *value, - size_t *size) + size_t *size, int *setpc) { uc_err ret = UC_ERR_ARG; @@ -349,6 +349,7 @@ static uc_err reg_write(CPUARMState *env, unsigned int regid, const void *value, 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); @@ -397,17 +398,15 @@ 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 *const *vals, - size_t *sizes, int count) +static uc_err reg_read_batch(CPUARMState *env, unsigned int *regs, + void *const *vals, size_t *sizes, 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, sizes ? sizes + i : NULL); + uc_err err = reg_read(env, regid, value, sizes ? sizes + i : NULL); if (err) { return err; } @@ -416,25 +415,45 @@ int arm64_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, return UC_ERR_OK; } -int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) +static uc_err reg_write_batch(CPUARMState *env, unsigned int *regs, + const void *const *vals, size_t *sizes, int count, + int *setpc) { - 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, sizes ? sizes + i : NULL); + uc_err err = + reg_write(env, regid, value, sizes ? sizes + i : NULL, setpc); 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; +} + +int arm64_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count) +{ + CPUARMState *env = &(ARM_CPU(uc->cpu)->env); + return reg_read_batch(env, regs, vals, sizes, count); +} + +int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count) +{ + CPUARMState *env = &(ARM_CPU(uc->cpu)->env); + int setpc = 0; + uc_err err = reg_write_batch(env, regs, vals, sizes, count, &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; @@ -450,19 +469,7 @@ int arm64_context_reg_read(struct uc_context *ctx, unsigned int *regs, #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, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; + return reg_read_batch(env, regs, vals, sizes, count); } DEFAULT_VISIBILITY @@ -475,19 +482,8 @@ int arm64_context_reg_write(struct uc_context *ctx, unsigned int *regs, #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, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; + int setpc = 0; + return reg_write_batch(env, regs, vals, sizes, count, &setpc); } static int arm64_cpus_init(struct uc_struct *uc, const char *cpu_model) diff --git a/qemu/target/arm/unicorn_arm.c b/qemu/target/arm/unicorn_arm.c index 3fc9704f..3582532e 100644 --- a/qemu/target/arm/unicorn_arm.c +++ b/qemu/target/arm/unicorn_arm.c @@ -355,7 +355,7 @@ static uc_err reg_read(CPUARMState *env, unsigned int regid, void *value, } static uc_err reg_write(CPUARMState *env, unsigned int regid, const void *value, - size_t *size) + size_t *size, int *setpc) { uc_err ret = UC_ERR_ARG; @@ -428,6 +428,7 @@ static uc_err reg_write(CPUARMState *env, unsigned int regid, const void *value, 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; @@ -550,20 +551,15 @@ 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 *const *vals, - size_t *sizes, int count) +static uc_err reg_read_batch(CPUARMState *env, unsigned int *regs, + void *const *vals, size_t *sizes, 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, sizes ? sizes + i : NULL); - if (err) { - return err; - } + uc_err err = reg_read(env, regid, value, sizes ? sizes + i : NULL); if (err) { return err; } @@ -572,25 +568,45 @@ int arm_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, return UC_ERR_OK; } -int arm_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) +static uc_err reg_write_batch(CPUARMState *env, unsigned int *regs, + const void *const *vals, size_t *sizes, int count, + int *setpc) { - 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, sizes ? sizes + i : NULL); + uc_err err = + reg_write(env, regid, value, sizes ? sizes + i : NULL, setpc); 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 UC_ERR_OK; +} + +int arm_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count) +{ + CPUARMState *env = &(ARM_CPU(uc->cpu)->env); + return reg_read_batch(env, regs, vals, sizes, count); +} + +int arm_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count) +{ + CPUArchState *env = &(ARM_CPU(uc->cpu)->env); + int setpc = 0; + uc_err err = reg_write_batch(env, regs, vals, sizes, count, &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; @@ -601,22 +617,7 @@ int arm_context_reg_read(struct uc_context *ctx, unsigned int *regs, void *const *vals, size_t *sizes, 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, sizes ? sizes + i : NULL); - if (err) { - return err; - } - if (err) { - return err; - } - } - - return UC_ERR_OK; + return reg_read_batch(env, regs, vals, sizes, count); } DEFAULT_VISIBILITY @@ -624,19 +625,8 @@ int arm_context_reg_write(struct uc_context *ctx, unsigned int *regs, const void *const *vals, size_t *sizes, 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, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; + int setpc = 0; + return reg_write_batch(env, regs, vals, sizes, count, &setpc); } static bool arm_stop_interrupt(struct uc_struct *uc, int intno) diff --git a/qemu/target/i386/unicorn.c b/qemu/target/i386/unicorn.c index 24d85754..6da03f2a 100644 --- a/qemu/target/i386/unicorn.c +++ b/qemu/target/i386/unicorn.c @@ -990,7 +990,7 @@ static uc_err reg_read(CPUX86State *env, unsigned int regid, void *value, } static uc_err reg_write(CPUX86State *env, unsigned int regid, const void *value, - size_t *size, uc_mode mode) + size_t *size, uc_mode mode, int *setpc) { uc_err ret = UC_ERR_ARG; @@ -1279,10 +1279,12 @@ static uc_err reg_write(CPUX86State *env, unsigned int regid, const void *value, 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); @@ -1569,14 +1571,17 @@ static uc_err reg_write(CPUX86State *env, unsigned int regid, const void *value, 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); @@ -1801,17 +1806,17 @@ static uc_err reg_write(CPUX86State *env, unsigned int regid, const void *value, return ret; } -int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, - size_t *sizes, int count) +static uc_err reg_read_batch(CPUX86State *env, unsigned int *regs, + void *const *vals, size_t *sizes, int count, + int mode) { - CPUX86State *env = &(X86_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, sizes ? sizes + i : NULL, uc->mode); + err = reg_read(env, regid, value, sizes ? sizes + i : NULL, mode); if (err) { return err; } @@ -1820,50 +1825,47 @@ int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, return UC_ERR_OK; } -int x86_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) +static uc_err reg_write_batch(CPUX86State *env, unsigned int *regs, + const void *const *vals, size_t *sizes, int count, + int mode, int *setpc) { - CPUX86State *env = &(X86_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, sizes ? sizes + i : NULL, uc->mode); + err = + reg_write(env, regid, value, sizes ? sizes + i : NULL, mode, setpc); if (err) { return err; } - 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 UC_ERR_OK; +} + +int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count) +{ + CPUX86State *env = &(X86_CPU(uc->cpu)->env); + return reg_read_batch(env, regs, vals, sizes, count, uc->mode); +} + +int x86_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count) +{ + CPUX86State *env = &(X86_CPU(uc->cpu)->env); + int setpc = 0; + uc_err err = + reg_write_batch(env, regs, vals, sizes, count, uc->mode, &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; @@ -1874,19 +1876,7 @@ int x86_context_reg_read(struct uc_context *ctx, unsigned int *regs, void *const *vals, size_t *sizes, int count) { CPUX86State *env = (CPUX86State *)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, sizes ? sizes + i : NULL, ctx->mode); - if (err) { - return err; - } - } - - return UC_ERR_OK; + return reg_read_batch(env, regs, vals, sizes, count, ctx->mode); } DEFAULT_VISIBILITY @@ -1894,19 +1884,8 @@ int x86_context_reg_write(struct uc_context *ctx, unsigned int *regs, const void *const *vals, size_t *sizes, int count) { CPUX86State *env = (CPUX86State *)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, sizes ? sizes + i : NULL, ctx->mode); - if (err) { - return err; - } - } - - return UC_ERR_OK; + int setpc = 0; + return reg_write_batch(env, regs, vals, sizes, count, ctx->mode, &setpc); } static bool x86_stop_interrupt(struct uc_struct *uc, int intno) diff --git a/qemu/target/m68k/unicorn.c b/qemu/target/m68k/unicorn.c index 414a94ce..93bc7170 100644 --- a/qemu/target/m68k/unicorn.c +++ b/qemu/target/m68k/unicorn.c @@ -79,7 +79,7 @@ static uc_err reg_read(CPUM68KState *env, unsigned int regid, void *value, } static uc_err reg_write(CPUM68KState *env, unsigned int regid, - const void *value, size_t *size) + const void *value, size_t *size, int *setpc) { uc_err ret = UC_ERR_ARG; @@ -96,6 +96,7 @@ static uc_err reg_write(CPUM68KState *env, unsigned int regid, 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); @@ -107,17 +108,15 @@ static uc_err reg_write(CPUM68KState *env, unsigned int regid, return ret; } -int m68k_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, - size_t *sizes, int count) +static uc_err reg_read_batch(CPUM68KState *env, unsigned int *regs, + void *const *vals, size_t *sizes, int count) { - CPUM68KState *env = &(M68K_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, sizes ? sizes + i : NULL); + uc_err err = reg_read(env, regid, value, sizes ? sizes + i : NULL); if (err) { return err; } @@ -126,25 +125,45 @@ int m68k_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, return UC_ERR_OK; } -int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) +static uc_err reg_write_batch(CPUM68KState *env, unsigned int *regs, + const void *const *vals, size_t *sizes, int count, + int *setpc) { - CPUM68KState *env = &(M68K_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, sizes ? sizes + i : NULL); + uc_err err = + reg_write(env, regid, value, sizes ? sizes + i : NULL, setpc); if (err) { return err; } - if (regid == UC_M68K_REG_PC) { - // force to quit execution and flush TB - uc->quit_request = true; - break_translation_loop(uc); - } + } + + return UC_ERR_OK; +} + +int m68k_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count) +{ + CPUM68KState *env = &(M68K_CPU(uc->cpu)->env); + return reg_read_batch(env, regs, vals, sizes, count); +} + +int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count) +{ + CPUM68KState *env = &(M68K_CPU(uc->cpu)->env); + int setpc = 0; + uc_err err = reg_write_batch(env, regs, vals, sizes, count, &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; @@ -155,19 +174,7 @@ int m68k_context_reg_read(struct uc_context *ctx, unsigned int *regs, void *const *vals, size_t *sizes, int count) { CPUM68KState *env = (CPUM68KState *)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, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; + return reg_read_batch(env, regs, vals, sizes, count); } DEFAULT_VISIBILITY @@ -175,19 +182,8 @@ int m68k_context_reg_write(struct uc_context *ctx, unsigned int *regs, const void *const *vals, size_t *sizes, int count) { CPUM68KState *env = (CPUM68KState *)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, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; + int setpc = 0; + return reg_write_batch(env, regs, vals, sizes, count, &setpc); } static int m68k_cpus_init(struct uc_struct *uc, const char *cpu_model) diff --git a/qemu/target/mips/unicorn.c b/qemu/target/mips/unicorn.c index 786e014d..4edb7d33 100644 --- a/qemu/target/mips/unicorn.c +++ b/qemu/target/mips/unicorn.c @@ -102,7 +102,7 @@ static uc_err reg_read(CPUMIPSState *env, unsigned int regid, void *value, } static uc_err reg_write(CPUMIPSState *env, unsigned int regid, - const void *value, size_t *size) + const void *value, size_t *size, int *setpc) { uc_err ret = UC_ERR_ARG; @@ -124,6 +124,7 @@ static uc_err reg_write(CPUMIPSState *env, unsigned int regid, 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); @@ -147,17 +148,15 @@ static uc_err reg_write(CPUMIPSState *env, unsigned int regid, return ret; } -int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, - size_t *sizes, int count) +static uc_err reg_read_batch(CPUMIPSState *env, unsigned int *regs, + void *const *vals, size_t *sizes, int count) { - CPUMIPSState *env = &(MIPS_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, sizes ? sizes + i : NULL); + uc_err err = reg_read(env, regid, value, sizes ? sizes + i : NULL); if (err) { return err; } @@ -166,25 +165,45 @@ int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, return UC_ERR_OK; } -int mips_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) +static uc_err reg_write_batch(CPUMIPSState *env, unsigned int *regs, + const void *const *vals, size_t *sizes, int count, + int *setpc) { - CPUMIPSState *env = &(MIPS_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, sizes ? sizes + i : NULL); + uc_err err = + reg_write(env, regid, value, sizes ? sizes + i : NULL, setpc); if (err) { return err; } - if (regid == UC_MIPS_REG_PC) { - // force to quit execution and flush TB - uc->quit_request = true; - break_translation_loop(uc); - } + } + + return UC_ERR_OK; +} + +int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count) +{ + CPUMIPSState *env = &(MIPS_CPU(uc->cpu)->env); + return reg_read_batch(env, regs, vals, sizes, count); +} + +int mips_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count) +{ + CPUMIPSState *env = &(MIPS_CPU(uc->cpu)->env); + int setpc = 0; + uc_err err = reg_write_batch(env, regs, vals, sizes, count, &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; @@ -210,19 +229,7 @@ int mipsel_context_reg_read(struct uc_context *ctx, unsigned int *regs, #endif { CPUMIPSState *env = (CPUMIPSState *)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, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; + return reg_read_batch(env, regs, vals, sizes, count); } DEFAULT_VISIBILITY @@ -246,19 +253,8 @@ int mipsel_context_reg_write(struct uc_context *ctx, unsigned int *regs, #endif { CPUMIPSState *env = (CPUMIPSState *)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, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; + int setpc = 0; + return reg_write_batch(env, regs, vals, sizes, count, &setpc); } static int mips_cpus_init(struct uc_struct *uc, const char *cpu_model) diff --git a/qemu/target/ppc/unicorn.c b/qemu/target/ppc/unicorn.c index b0f02ce2..edda420b 100644 --- a/qemu/target/ppc/unicorn.c +++ b/qemu/target/ppc/unicorn.c @@ -206,7 +206,7 @@ static uc_err reg_read(CPUPPCState *env, unsigned int regid, void *value, } static uc_err reg_write(CPUPPCState *env, unsigned int regid, const void *value, - size_t *size) + size_t *size, int *setpc) { int i; uc_err ret = UC_ERR_ARG; @@ -227,6 +227,7 @@ static uc_err reg_write(CPUPPCState *env, unsigned int regid, const void *value, case UC_PPC_REG_PC: CHECK_REG_TYPE(ppcreg_t); env->nip = *(ppcreg_t *)value; + *setpc = 1; break; case UC_PPC_REG_CR: { CHECK_REG_TYPE(uint32_t); @@ -263,17 +264,15 @@ static uc_err reg_write(CPUPPCState *env, unsigned int regid, const void *value, return ret; } -int ppc_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, - size_t *sizes, int count) +static uc_err reg_read_batch(CPUPPCState *env, unsigned int *regs, + void *const *vals, size_t *sizes, int count) { - CPUPPCState *env = &(POWERPC_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, sizes ? sizes + i : NULL); + uc_err err = reg_read(env, regid, value, sizes ? sizes + i : NULL); if (err) { return err; } @@ -282,25 +281,45 @@ int ppc_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, return UC_ERR_OK; } -int ppc_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) +static uc_err reg_write_batch(CPUPPCState *env, unsigned int *regs, + const void *const *vals, size_t *sizes, int count, + int *setpc) { - CPUPPCState *env = &(POWERPC_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, sizes ? sizes + i : NULL); + uc_err err = + reg_write(env, regid, value, sizes ? sizes + i : NULL, setpc); if (err) { return err; } - if (regid == UC_PPC_REG_PC) { - // force to quit execution and flush TB - uc->quit_request = true; - break_translation_loop(uc); - } + } + + return UC_ERR_OK; +} + +int ppc_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count) +{ + CPUPPCState *env = &(POWERPC_CPU(uc->cpu)->env); + return reg_read_batch(env, regs, vals, sizes, count); +} + +int ppc_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count) +{ + CPUPPCState *env = &(POWERPC_CPU(uc->cpu)->env); + int setpc = 0; + uc_err err = reg_write_batch(env, regs, vals, sizes, count, &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; @@ -316,19 +335,7 @@ int ppc_context_reg_read(struct uc_context *ctx, unsigned int *regs, #endif { CPUPPCState *env = (CPUPPCState *)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, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; + return reg_read_batch(env, regs, vals, sizes, count); } DEFAULT_VISIBILITY @@ -341,19 +348,8 @@ int ppc_context_reg_write(struct uc_context *ctx, unsigned int *regs, #endif { CPUPPCState *env = (CPUPPCState *)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, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; + int setpc = 0; + return reg_write_batch(env, regs, vals, sizes, count, &setpc); } PowerPCCPU *cpu_ppc_init(struct uc_struct *uc); diff --git a/qemu/target/riscv/unicorn.c b/qemu/target/riscv/unicorn.c index 846d2c17..86ab8746 100644 --- a/qemu/target/riscv/unicorn.c +++ b/qemu/target/riscv/unicorn.c @@ -128,7 +128,7 @@ static uc_err reg_read(CPURISCVState *env, unsigned int regid, void *value, } static uc_err reg_write(CPURISCVState *env, unsigned int regid, - const void *value, size_t *size) + const void *value, size_t *size, int *setpc) { uc_err ret = UC_ERR_ARG; @@ -167,6 +167,7 @@ static uc_err reg_write(CPURISCVState *env, unsigned int regid, CHECK_REG_TYPE(uint32_t); env->pc = *(uint32_t *)value; #endif + *setpc = 1; break; } } @@ -174,17 +175,15 @@ static uc_err reg_write(CPURISCVState *env, unsigned int regid, return ret; } -int riscv_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, - size_t *sizes, int count) +static uc_err reg_read_batch(CPURISCVState *env, unsigned int *regs, + void *const *vals, size_t *sizes, int count) { - CPURISCVState *env = &(RISCV_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, sizes ? sizes + i : NULL); + uc_err err = reg_read(env, regid, value, sizes ? sizes + i : NULL); if (err) { return err; } @@ -193,25 +192,45 @@ int riscv_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, return UC_ERR_OK; } -int riscv_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) +static uc_err reg_write_batch(CPURISCVState *env, unsigned int *regs, + const void *const *vals, size_t *sizes, int count, + int *setpc) { - CPURISCVState *env = &(RISCV_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, sizes ? sizes + i : NULL); + uc_err err = + reg_write(env, regid, value, sizes ? sizes + i : NULL, setpc); if (err) { return err; } - if (regid == UC_RISCV_REG_PC) { - // force to quit execution and flush TB - uc->quit_request = true; - break_translation_loop(uc); - } + } + + return UC_ERR_OK; +} + +int riscv_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count) +{ + CPURISCVState *env = &(RISCV_CPU(uc->cpu)->env); + return reg_read_batch(env, regs, vals, sizes, count); +} + +int riscv_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count) +{ + CPURISCVState *env = &(RISCV_CPU(uc->cpu)->env); + int setpc = 0; + uc_err err = reg_write_batch(env, regs, vals, sizes, count, &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; @@ -228,19 +247,7 @@ int riscv64_context_reg_read(struct uc_context *ctx, unsigned int *regs, #endif { CPURISCVState *env = (CPURISCVState *)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, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; + return reg_read_batch(env, regs, vals, sizes, count); } DEFAULT_VISIBILITY @@ -254,19 +261,8 @@ int riscv64_context_reg_write(struct uc_context *ctx, unsigned int *regs, #endif { CPURISCVState *env = (CPURISCVState *)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, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; + int setpc = 0; + return reg_write_batch(env, regs, vals, sizes, count, &setpc); } static bool riscv_stop_interrupt(struct uc_struct *uc, int intno) diff --git a/qemu/target/s390x/unicorn.c b/qemu/target/s390x/unicorn.c index f2e54d02..9d4ac0b0 100644 --- a/qemu/target/s390x/unicorn.c +++ b/qemu/target/s390x/unicorn.c @@ -83,7 +83,7 @@ static uc_err reg_read(CPUS390XState *env, unsigned int regid, void *value, } static uc_err reg_write(CPUS390XState *env, unsigned int regid, - const void *value, size_t *size) + const void *value, size_t *size, int *setpc) { uc_err ret = UC_ERR_ARG; @@ -100,6 +100,7 @@ static uc_err reg_write(CPUS390XState *env, unsigned int regid, 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); @@ -111,18 +112,34 @@ static uc_err reg_write(CPUS390XState *env, unsigned int regid, return ret; } -DEFAULT_VISIBILITY -int s390_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, - size_t *sizes, int count) +static uc_err reg_read_batch(CPUS390XState *env, unsigned int *regs, + void *const *vals, size_t *sizes, int count) { - CPUS390XState *env = &(S390_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, sizes ? sizes + i : NULL); + uc_err err = reg_read(env, regid, value, sizes ? sizes + i : NULL); + if (err) { + return err; + } + } + + return UC_ERR_OK; +} + +static uc_err reg_write_batch(CPUS390XState *env, unsigned int *regs, + const void *const *vals, size_t *sizes, int count, + int *setpc) +{ + int i; + + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + const void *value = vals[i]; + uc_err err = + reg_write(env, regid, value, sizes ? sizes + i : NULL, setpc); if (err) { return err; } @@ -131,26 +148,28 @@ int s390_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, return UC_ERR_OK; } +DEFAULT_VISIBILITY +int s390_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count) +{ + CPUS390XState *env = &(S390_CPU(uc->cpu)->env); + return reg_read_batch(env, regs, vals, sizes, count); +} + DEFAULT_VISIBILITY int s390_reg_write(struct uc_struct *uc, unsigned int *regs, const void *const *vals, size_t *sizes, int count) { CPUS390XState *env = &(S390_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, sizes ? sizes + i : NULL); - if (err) { - return err; - } - if (regid == UC_S390X_REG_PC) { - // force to quit execution and flush TB - uc->quit_request = true; - break_translation_loop(uc); - } + int setpc = 0; + uc_err err = reg_write_batch(env, regs, vals, sizes, count, &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; @@ -161,19 +180,7 @@ int s390_context_reg_read(struct uc_context *ctx, unsigned int *regs, void *const *vals, size_t *sizes, int count) { CPUS390XState *env = (CPUS390XState *)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, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; + return reg_read_batch(env, regs, vals, sizes, count); } DEFAULT_VISIBILITY @@ -181,19 +188,8 @@ int s390_context_reg_write(struct uc_context *ctx, unsigned int *regs, const void *const *vals, size_t *sizes, int count) { CPUS390XState *env = (CPUS390XState *)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, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; + int setpc = 0; + return reg_write_batch(env, regs, vals, sizes, count, &setpc); } static int s390_cpus_init(struct uc_struct *uc, const char *cpu_model) diff --git a/qemu/target/sparc/unicorn.c b/qemu/target/sparc/unicorn.c index d000b7de..030d3b12 100644 --- a/qemu/target/sparc/unicorn.c +++ b/qemu/target/sparc/unicorn.c @@ -92,7 +92,7 @@ static uc_err reg_read(CPUSPARCState *env, unsigned int regid, void *value, } static uc_err reg_write(CPUSPARCState *env, unsigned int regid, - const void *value, size_t *size) + const void *value, size_t *size, int *setpc) { uc_err ret = UC_ERR_ARG; @@ -116,6 +116,7 @@ static uc_err reg_write(CPUSPARCState *env, unsigned int regid, CHECK_REG_TYPE(uint32_t); env->pc = *(uint32_t *)value; env->npc = *(uint32_t *)value + 4; + *setpc = 1; break; } } @@ -123,17 +124,15 @@ static uc_err reg_write(CPUSPARCState *env, unsigned int regid, return ret; } -int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, - size_t *sizes, int count) +static uc_err reg_read_batch(CPUSPARCState *env, unsigned int *regs, + void *const *vals, size_t *sizes, int count) { - CPUSPARCState *env = &(SPARC_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, sizes ? sizes + i : NULL); + uc_err err = reg_read(env, regid, value, sizes ? sizes + i : NULL); if (err) { return err; } @@ -142,25 +141,45 @@ int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, return UC_ERR_OK; } -int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) +static uc_err reg_write_batch(CPUSPARCState *env, unsigned int *regs, + const void *const *vals, size_t *sizes, int count, + int *setpc) { - CPUSPARCState *env = &(SPARC_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, sizes ? sizes + i : NULL); + uc_err err = + reg_write(env, regid, value, sizes ? sizes + i : NULL, setpc); if (err) { return err; } - if (regid == UC_SPARC_REG_PC) { - // force to quit execution and flush TB - uc->quit_request = true; - break_translation_loop(uc); - } + } + + return UC_ERR_OK; +} + +int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, + size_t *sizes, int count) +{ + CPUSPARCState *env = &(SPARC_CPU(uc->cpu)->env); + return reg_read_batch(env, regs, vals, sizes, count); +} + +int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count) +{ + CPUSPARCState *env = &(SPARC_CPU(uc->cpu)->env); + int setpc = 0; + uc_err err = reg_write_batch(env, regs, vals, sizes, count, &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; @@ -171,19 +190,7 @@ int sparc_context_reg_read(struct uc_context *ctx, unsigned int *regs, void *const *vals, size_t *sizes, int count) { CPUSPARCState *env = (CPUSPARCState *)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, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; + return reg_read_batch(env, regs, vals, sizes, count); } DEFAULT_VISIBILITY @@ -191,19 +198,8 @@ int sparc_context_reg_write(struct uc_context *ctx, unsigned int *regs, const void *const *vals, size_t *sizes, int count) { CPUSPARCState *env = (CPUSPARCState *)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, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; + int setpc = 0; + return reg_write_batch(env, regs, vals, sizes, count, &setpc); } static int sparc_cpus_init(struct uc_struct *uc, const char *cpu_model) diff --git a/qemu/target/sparc/unicorn64.c b/qemu/target/sparc/unicorn64.c index f477ea06..6c7bfae9 100644 --- a/qemu/target/sparc/unicorn64.c +++ b/qemu/target/sparc/unicorn64.c @@ -113,7 +113,7 @@ static uc_err reg_read(CPUSPARCState *env, unsigned int regid, void *value, size return ret; } -static uc_err reg_write(CPUSPARCState *env, unsigned int regid, const void *value, size_t *size) +static uc_err reg_write(CPUSPARCState *env, unsigned int regid, const void *value, size_t *size, int *setpc) { uc_err ret = UC_ERR_ARG; @@ -137,6 +137,7 @@ static uc_err reg_write(CPUSPARCState *env, unsigned int regid, const void *valu CHECK_REG_TYPE(uint64_t); env->pc = *(uint64_t *)value; env->npc = *(uint64_t *)value + 4; + *setpc = 1; break; } } @@ -144,16 +145,14 @@ static uc_err reg_write(CPUSPARCState *env, unsigned int regid, const void *valu return ret; } -int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, size_t *sizes, int count) +static uc_err reg_read_batch(CPUSPARCState *env, unsigned int *regs, void *const *vals, size_t *sizes, int count) { - CPUSPARCState *env = &(SPARC_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, sizes ? sizes + i : NULL); + uc_err err = reg_read(env, regid, value, sizes ? sizes + i : NULL); if (err) { return err; } @@ -162,24 +161,40 @@ int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, return UC_ERR_OK; } -int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, const void* const* vals, size_t *sizes, int count) +static uc_err reg_write_batch(CPUSPARCState *env, unsigned int *regs, const void* const* vals, size_t *sizes, int count, int *setpc) { - CPUSPARCState *env = &(SPARC_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, sizes ? sizes + i : NULL); + uc_err err = reg_write(env, regid, value, sizes ? sizes + i : NULL, setpc); if (err) { return err; } - if (regid == UC_SPARC_REG_PC) { - // force to quit execution and flush TB - uc->quit_request = true; - break_translation_loop(uc); - } + } + + return UC_ERR_OK; +} + +int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, size_t *sizes, int count) +{ + CPUSPARCState *env = &(SPARC_CPU(uc->cpu)->env); + return reg_read_batch(env, regs, vals, sizes, count); +} + +int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, const void* const* vals, size_t *sizes, int count) +{ + CPUSPARCState *env = &(SPARC_CPU(uc->cpu)->env); + int setpc = 0; + uc_err err = reg_write_batch(env, regs, vals, sizes, count, &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; @@ -189,38 +204,15 @@ DEFAULT_VISIBILITY int sparc64_context_reg_read(struct uc_context *ctx, unsigned int *regs, void *const *vals, size_t *sizes, int count) { CPUSPARCState *env = (CPUSPARCState *)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, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; + return reg_read_batch(env, regs, vals, sizes, count); } DEFAULT_VISIBILITY int sparc64_context_reg_write(struct uc_context *ctx, unsigned int *regs, const void *const *vals, size_t *sizes, int count) { CPUSPARCState *env = (CPUSPARCState *)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, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; + int setpc = 0; + return reg_write_batch(env, regs, vals, sizes, count, &setpc); } static int sparc_cpus_init(struct uc_struct *uc, const char *cpu_model) diff --git a/qemu/target/tricore/unicorn.c b/qemu/target/tricore/unicorn.c index 155cff15..3d35846b 100644 --- a/qemu/target/tricore/unicorn.c +++ b/qemu/target/tricore/unicorn.c @@ -139,46 +139,8 @@ static uc_err reg_read(CPUTriCoreState *env, unsigned int regid, void *value, return ret; } -int tricore_reg_read(struct uc_struct *uc, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -{ - CPUTriCoreState *env = &(TRICORE_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, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; -} - -int tricore_context_reg_read(struct uc_context *uc, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -{ - CPUTriCoreState *env = (CPUTriCoreState *)uc->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, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; -} - static uc_err reg_write(CPUTriCoreState *env, unsigned int regid, - const void *value, size_t *size) + const void *value, size_t *size, int *setpc) { uc_err ret = UC_ERR_ARG; @@ -206,6 +168,7 @@ static uc_err reg_write(CPUTriCoreState *env, unsigned int regid, case UC_TRICORE_REG_PC: CHECK_REG_TYPE(uint32_t); env->PC = *(uint32_t *)value; + *setpc = 1; break; case UC_TRICORE_REG_PCXI: CHECK_REG_TYPE(uint32_t); @@ -277,41 +240,34 @@ static uc_err reg_write(CPUTriCoreState *env, unsigned int regid, return ret; } -int tricore_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) +static uc_err reg_read_batch(CPUTriCoreState *env, unsigned int *regs, + void *const *vals, size_t *sizes, int count) { - CPUTriCoreState *env = &(TRICORE_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, sizes ? sizes + i : NULL); + void *value = vals[i]; + uc_err err = reg_read(env, regid, value, sizes ? sizes + i : NULL); if (err) { return err; } - if (regid == UC_TRICORE_REG_PC) { - // force to quit execution and flush TB - uc->quit_request = true; - break_translation_loop(uc); - } } return UC_ERR_OK; } -int tricore_context_reg_write(struct uc_context *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) +static uc_err reg_write_batch(CPUTriCoreState *env, unsigned int *regs, + const void *const *vals, size_t *sizes, int count, + int *setpc) { - CPUTriCoreState *env = (CPUTriCoreState *)uc->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, sizes ? sizes + i : NULL); + uc_err err = + reg_write(env, regid, value, sizes ? sizes + i : NULL, setpc); if (err) { return err; } @@ -320,6 +276,46 @@ int tricore_context_reg_write(struct uc_context *uc, unsigned int *regs, return UC_ERR_OK; } +int tricore_reg_read(struct uc_struct *uc, unsigned int *regs, + void *const *vals, size_t *sizes, int count) +{ + CPUTriCoreState *env = &(TRICORE_CPU(uc->cpu)->env); + return reg_read_batch(env, regs, vals, sizes, count); +} + +int tricore_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count) +{ + CPUTriCoreState *env = &(TRICORE_CPU(uc->cpu)->env); + int setpc = 0; + uc_err err = reg_write_batch(env, regs, vals, sizes, count, &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; +} + +int tricore_context_reg_read(struct uc_context *uc, unsigned int *regs, + void *const *vals, size_t *sizes, int count) +{ + CPUTriCoreState *env = (CPUTriCoreState *)uc->data; + return reg_read_batch(env, regs, vals, sizes, count); +} + +int tricore_context_reg_write(struct uc_context *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count) +{ + CPUTriCoreState *env = (CPUTriCoreState *)uc->data; + int setpc = 0; + return reg_write_batch(env, regs, vals, sizes, count, &setpc); +} + static int tricore_cpus_init(struct uc_struct *uc, const char *cpu_model) { TriCoreCPU *cpu; diff --git a/qemu/unicorn_common.h b/qemu/unicorn_common.h index b5cb5610..3059eb74 100644 --- a/qemu/unicorn_common.h +++ b/qemu/unicorn_common.h @@ -129,14 +129,14 @@ static inline void uc_common_init(struct uc_struct* uc) uc->release = release_common; } -#define CHECK_REG_TYPE(type) do { \ - if (size) { \ - if (*size < sizeof(type)) { \ - return UC_ERR_NOMEM; \ - } \ - *size = sizeof(type); \ - } \ - ret = UC_ERR_OK; \ +#define CHECK_REG_TYPE(type) do { \ + if (unlikely(size)) { \ + if (unlikely(*size < sizeof(type))) { \ + return UC_ERR_NOMEM; \ + } \ + *size = sizeof(type); \ + } \ + ret = UC_ERR_OK; \ } while(0) #endif diff --git a/uc.c b/uc.c index 1152f3ee..0581c408 100644 --- a/uc.c +++ b/uc.c @@ -82,6 +82,18 @@ unsigned int uc_version(unsigned int *major, unsigned int *minor) UC_API_EXTRA; } +static int default_reg_read(struct uc_struct *uc, unsigned int *regs, + void *const *vals, size_t *sizes, int count) +{ + return UC_ERR_HANDLE; +} + +static int default_reg_write(struct uc_struct *uc, unsigned int *regs, + const void *const *vals, size_t *sizes, int count) +{ + return UC_ERR_HANDLE; +} + UNICORN_EXPORT uc_err uc_errno(uc_engine *uc) { @@ -264,6 +276,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); @@ -507,13 +521,16 @@ uc_err uc_close(uc_engine *uc) UNICORN_EXPORT uc_err uc_reg_read_batch(uc_engine *uc, int *ids, void **vals, int count) { - return uc_reg_read_batch2(uc, ids, vals, NULL, count); + UC_INIT(uc); + return uc->reg_read(uc, (unsigned int *)ids, vals, NULL, count); } UNICORN_EXPORT uc_err uc_reg_write_batch(uc_engine *uc, int *ids, void *const *vals, int count) { - return uc_reg_write_batch2(uc, ids, (const void *const *)vals, NULL, count); + UC_INIT(uc); + return uc->reg_write(uc, (unsigned int *)ids, (const void *const *)vals, + NULL, count); } UNICORN_EXPORT @@ -521,12 +538,7 @@ uc_err uc_reg_read_batch2(uc_engine *uc, int *ids, void *const *vals, size_t *sizes, int count) { UC_INIT(uc); - - if (uc->reg_read) { - return uc->reg_read(uc, (unsigned int *)ids, vals, sizes, count); - } else { - return UC_ERR_HANDLE; - } + return uc->reg_read(uc, (unsigned int *)ids, vals, sizes, count); } UNICORN_EXPORT @@ -534,36 +546,35 @@ uc_err uc_reg_write_batch2(uc_engine *uc, int *ids, const void *const *vals, size_t *sizes, int count) { UC_INIT(uc); - - if (uc->reg_write) { - return uc->reg_write(uc, (unsigned int *)ids, vals, sizes, count); - } else { - return UC_ERR_HANDLE; - } + return uc->reg_write(uc, (unsigned int *)ids, vals, sizes, count); } UNICORN_EXPORT uc_err uc_reg_read(uc_engine *uc, int regid, void *value) { - return uc_reg_read_batch2(uc, ®id, &value, NULL, 1); + UC_INIT(uc); + return uc->reg_read(uc, (unsigned int *)®id, &value, NULL, 1); } UNICORN_EXPORT uc_err uc_reg_write(uc_engine *uc, int regid, const void *value) { - return uc_reg_write_batch2(uc, ®id, &value, NULL, 1); + UC_INIT(uc); + return uc->reg_write(uc, (unsigned int *)®id, &value, NULL, 1); } UNICORN_EXPORT uc_err uc_reg_read2(uc_engine *uc, int regid, void *value, size_t *size) { - return uc_reg_read_batch2(uc, ®id, &value, size, 1); + UC_INIT(uc); + return uc->reg_read(uc, (unsigned int *)®id, &value, size, 1); } UNICORN_EXPORT uc_err uc_reg_write2(uc_engine *uc, int regid, const void *value, size_t *size) { - return uc_reg_write_batch2(uc, ®id, &value, size, 1); + UC_INIT(uc); + return uc->reg_write(uc, (unsigned int *)®id, &value, size, 1); } // check if a memory area is mapped From 30d202b89e5f9efe50b3f42324652b9aabdf52e1 Mon Sep 17 00:00:00 2001 From: Robert Xiao Date: Thu, 11 May 2023 22:54:03 -0700 Subject: [PATCH 29/44] Simplify reg_read/reg_write, obtaining a perf boost. Single reg_read/reg_write is now about 25% faster. --- include/uc_priv.h | 18 +- qemu/aarch64.h | 6 +- qemu/arm.h | 6 +- qemu/m68k.h | 6 +- qemu/mips.h | 6 +- qemu/mips64.h | 6 +- qemu/mips64el.h | 6 +- qemu/mipsel.h | 6 +- qemu/ppc.h | 6 +- qemu/ppc64.h | 6 +- qemu/riscv32.h | 6 +- qemu/riscv64.h | 6 +- qemu/s390x.h | 3 + qemu/sparc.h | 6 +- qemu/sparc64.h | 6 +- qemu/target/arm/unicorn.h | 33 +-- qemu/target/arm/unicorn_aarch64.c | 110 +------- qemu/target/arm/unicorn_arm.c | 101 ++------ qemu/target/i386/unicorn.c | 104 +------- qemu/target/i386/unicorn.h | 16 +- qemu/target/m68k/unicorn.c | 100 +------- qemu/target/m68k/unicorn.h | 16 +- qemu/target/mips/unicorn.c | 143 +---------- qemu/target/mips/unicorn.h | 47 ++-- qemu/target/ppc/unicorn.c | 122 ++------- qemu/target/ppc/unicorn.h | 27 +- qemu/target/riscv/unicorn.c | 117 +-------- qemu/target/riscv/unicorn.h | 29 +-- qemu/target/s390x/unicorn.c | 102 +------- qemu/target/s390x/unicorn.h | 16 +- qemu/target/sparc/unicorn.c | 100 +------- qemu/target/sparc/unicorn.h | 28 +-- qemu/target/sparc/unicorn64.c | 90 +------ qemu/target/tricore/unicorn.c | 99 ++------ qemu/target/tricore/unicorn.h | 19 +- qemu/tricore.h | 3 + qemu/unicorn_common.h | 8 +- qemu/x86_64.h | 6 +- symbols.sh | 27 +- uc.c | 404 ++++++++++++++++++++---------- 40 files changed, 563 insertions(+), 1403 deletions(-) diff --git a/include/uc_priv.h b/include/uc_priv.h index 5fbdda07..ef3d30e3 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -62,20 +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 *const *vals, size_t *sizes, int count); -typedef int (*reg_write_t)(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, 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 *const *vals, size_t *sizes, int count); -typedef int (*context_reg_write_t)(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, - 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); diff --git a/qemu/aarch64.h b/qemu/aarch64.h index c678501b..aba5a963 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 @@ -2959,9 +2962,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/arm.h b/qemu/arm.h index 13e8ffee..be8271c6 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 @@ -1970,9 +1973,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/m68k.h b/qemu/m68k.h index 23f5d93a..ab97771b 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 @@ -1433,7 +1436,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..95f0abda 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 @@ -2385,9 +2388,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..e29e20e5 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 @@ -2385,9 +2388,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..6f94f431 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 @@ -2385,9 +2388,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..1b313d4b 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 @@ -2385,9 +2388,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..a3a339fb 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 @@ -1280,9 +1283,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..04564484 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 @@ -1280,9 +1283,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..a7a91fa7 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 @@ -1361,9 +1364,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..6934d749 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 @@ -1361,9 +1364,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..e00bcae9 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 diff --git a/qemu/sparc.h b/qemu/sparc.h index 7083a74f..596d8328 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 @@ -1415,7 +1418,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..223832ee 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 @@ -1415,7 +1418,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 18612489..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 *const *vals, - size_t *sizes, int count); -int arm_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count); -int arm64_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, - size_t *sizes, int count); -int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, 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 *const *vals, size_t *sizes, int count); -int arm_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, int count); -int arm64_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void *const *vals, size_t *sizes, int count); -int arm64_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, 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 06320819..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,9 +138,11 @@ 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, - size_t *size) +DEFAULT_VISIBILITY +uc_err reg_read(void *_env, int mode, unsigned int regid, void *value, + size_t *size) { + CPUARMState *env = _env; uc_err ret = UC_ERR_ARG; if (regid >= UC_ARM64_REG_V0 && regid <= UC_ARM64_REG_V31) { @@ -267,9 +269,11 @@ 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, - size_t *size, int *setpc) +DEFAULT_VISIBILITY +uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc) { + CPUARMState *env = _env; uc_err ret = UC_ERR_ARG; if (regid >= UC_ARM64_REG_V0 && regid <= UC_ARM64_REG_V31) { @@ -398,94 +402,6 @@ static uc_err reg_write(CPUARMState *env, unsigned int regid, const void *value, return ret; } -static uc_err reg_read_batch(CPUARMState *env, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -{ - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - uc_err err = reg_read(env, regid, value, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; -} - -static uc_err reg_write_batch(CPUARMState *env, unsigned int *regs, - const void *const *vals, size_t *sizes, int count, - int *setpc) -{ - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - uc_err err = - reg_write(env, regid, value, sizes ? sizes + i : NULL, setpc); - if (err) { - return err; - } - } - - return UC_ERR_OK; -} - -int arm64_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, - size_t *sizes, int count) -{ - CPUARMState *env = &(ARM_CPU(uc->cpu)->env); - return reg_read_batch(env, regs, vals, sizes, count); -} - -int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) -{ - CPUARMState *env = &(ARM_CPU(uc->cpu)->env); - int setpc = 0; - uc_err err = reg_write_batch(env, regs, vals, sizes, count, &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; -} - -DEFAULT_VISIBILITY -#ifdef TARGET_WORDS_BIGENDIAN -int arm64eb_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -#else -int arm64_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -#endif -{ - CPUARMState *env = (CPUARMState *)ctx->data; - return reg_read_batch(env, regs, vals, sizes, count); -} - -DEFAULT_VISIBILITY -#ifdef TARGET_WORDS_BIGENDIAN -int arm64eb_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) -#else -int arm64_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) -#endif -{ - CPUARMState *env = (CPUARMState *)ctx->data; - int setpc = 0; - return reg_write_batch(env, regs, vals, sizes, count, &setpc); -} - static int arm64_cpus_init(struct uc_struct *uc, const char *cpu_model) { ARMCPU *cpu; @@ -499,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 3582532e..f50ac0e1 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,9 +206,11 @@ 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, - size_t *size) +DEFAULT_VISIBILITY +uc_err reg_read(void *_env, int mode, unsigned int regid, void *value, + size_t *size) { + CPUARMState *env = _env; uc_err ret = UC_ERR_ARG; if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12) { @@ -354,9 +356,11 @@ 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, - size_t *size, int *setpc) +DEFAULT_VISIBILITY +uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc) { + CPUARMState *env = _env; uc_err ret = UC_ERR_ARG; if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12) { @@ -551,84 +555,6 @@ static uc_err reg_write(CPUARMState *env, unsigned int regid, const void *value, return ret; } -static uc_err reg_read_batch(CPUARMState *env, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -{ - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - uc_err err = reg_read(env, regid, value, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; -} - -static uc_err reg_write_batch(CPUARMState *env, unsigned int *regs, - const void *const *vals, size_t *sizes, int count, - int *setpc) -{ - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - uc_err err = - reg_write(env, regid, value, sizes ? sizes + i : NULL, setpc); - if (err) { - return err; - } - } - - return UC_ERR_OK; -} - -int arm_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, - size_t *sizes, int count) -{ - CPUARMState *env = &(ARM_CPU(uc->cpu)->env); - return reg_read_batch(env, regs, vals, sizes, count); -} - -int arm_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) -{ - CPUArchState *env = &(ARM_CPU(uc->cpu)->env); - int setpc = 0; - uc_err err = reg_write_batch(env, regs, vals, sizes, count, &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; -} - -DEFAULT_VISIBILITY -int arm_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -{ - CPUARMState *env = (CPUARMState *)ctx->data; - return reg_read_batch(env, regs, vals, sizes, count); -} - -DEFAULT_VISIBILITY -int arm_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) -{ - CPUARMState *env = (CPUARMState *)ctx->data; - int setpc = 0; - return reg_write_batch(env, regs, vals, sizes, count, &setpc); -} - static bool arm_stop_interrupt(struct uc_struct *uc, int intno) { switch (intno) { @@ -827,11 +753,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/unicorn.c b/qemu/target/i386/unicorn.c index 6da03f2a..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,11 @@ static int x86_msr_write(CPUX86State *env, uc_x86_msr *msr) return 0; } -static uc_err reg_read(CPUX86State *env, unsigned int regid, void *value, - size_t *size, 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) { @@ -989,9 +991,11 @@ static uc_err reg_read(CPUX86State *env, unsigned int regid, void *value, return ret; } -static uc_err reg_write(CPUX86State *env, unsigned int regid, const void *value, - size_t *size, uc_mode mode, int *setpc) +DEFAULT_VISIBILITY +uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc) { + CPUX86State *env = _env; uc_err ret = UC_ERR_ARG; switch (regid) { @@ -1806,88 +1810,6 @@ static uc_err reg_write(CPUX86State *env, unsigned int regid, const void *value, return ret; } -static uc_err reg_read_batch(CPUX86State *env, unsigned int *regs, - void *const *vals, size_t *sizes, int count, - int mode) -{ - 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, sizes ? sizes + i : NULL, mode); - if (err) { - return err; - } - } - - return UC_ERR_OK; -} - -static uc_err reg_write_batch(CPUX86State *env, unsigned int *regs, - const void *const *vals, size_t *sizes, int count, - int mode, int *setpc) -{ - 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, sizes ? sizes + i : NULL, mode, setpc); - if (err) { - return err; - } - } - - return UC_ERR_OK; -} - -int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, - size_t *sizes, int count) -{ - CPUX86State *env = &(X86_CPU(uc->cpu)->env); - return reg_read_batch(env, regs, vals, sizes, count, uc->mode); -} - -int x86_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) -{ - CPUX86State *env = &(X86_CPU(uc->cpu)->env); - int setpc = 0; - uc_err err = - reg_write_batch(env, regs, vals, sizes, count, uc->mode, &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; -} - -DEFAULT_VISIBILITY -int x86_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -{ - CPUX86State *env = (CPUX86State *)ctx->data; - return reg_read_batch(env, regs, vals, sizes, count, ctx->mode); -} - -DEFAULT_VISIBILITY -int x86_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) -{ - CPUX86State *env = (CPUX86State *)ctx->data; - int setpc = 0; - return reg_write_batch(env, regs, vals, sizes, count, ctx->mode, &setpc); -} - static bool x86_stop_interrupt(struct uc_struct *uc, int intno) { switch (intno) { @@ -1945,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 fe5688ad..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 *const *vals, - size_t *sizes, int count); -int x86_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count); -int x86_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void *const *vals, size_t *sizes, int count); -int x86_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, 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 93bc7170..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,9 +49,11 @@ void m68k_reg_reset(struct uc_struct *uc) env->pc = 0; } -static uc_err reg_read(CPUM68KState *env, unsigned int regid, void *value, - size_t *size) +DEFAULT_VISIBILITY +uc_err reg_read(void *_env, int mode, unsigned int regid, void *value, + size_t *size) { + CPUM68KState *env = _env; uc_err ret = UC_ERR_ARG; if (regid >= UC_M68K_REG_A0 && regid <= UC_M68K_REG_A7) { @@ -78,9 +80,11 @@ static uc_err reg_read(CPUM68KState *env, unsigned int regid, void *value, return ret; } -static uc_err reg_write(CPUM68KState *env, unsigned int regid, - const void *value, size_t *size, int *setpc) +DEFAULT_VISIBILITY +uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc) { + CPUM68KState *env = _env; uc_err ret = UC_ERR_ARG; if (regid >= UC_M68K_REG_A0 && regid <= UC_M68K_REG_A7) { @@ -108,84 +112,6 @@ static uc_err reg_write(CPUM68KState *env, unsigned int regid, return ret; } -static uc_err reg_read_batch(CPUM68KState *env, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -{ - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - uc_err err = reg_read(env, regid, value, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; -} - -static uc_err reg_write_batch(CPUM68KState *env, unsigned int *regs, - const void *const *vals, size_t *sizes, int count, - int *setpc) -{ - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - uc_err err = - reg_write(env, regid, value, sizes ? sizes + i : NULL, setpc); - if (err) { - return err; - } - } - - return UC_ERR_OK; -} - -int m68k_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, - size_t *sizes, int count) -{ - CPUM68KState *env = &(M68K_CPU(uc->cpu)->env); - return reg_read_batch(env, regs, vals, sizes, count); -} - -int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) -{ - CPUM68KState *env = &(M68K_CPU(uc->cpu)->env); - int setpc = 0; - uc_err err = reg_write_batch(env, regs, vals, sizes, count, &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; -} - -DEFAULT_VISIBILITY -int m68k_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -{ - CPUM68KState *env = (CPUM68KState *)ctx->data; - return reg_read_batch(env, regs, vals, sizes, count); -} - -DEFAULT_VISIBILITY -int m68k_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) -{ - CPUM68KState *env = (CPUM68KState *)ctx->data; - int setpc = 0; - return reg_write_batch(env, regs, vals, sizes, count, &setpc); -} - static int m68k_cpus_init(struct uc_struct *uc, const char *cpu_model) { M68kCPU *cpu; @@ -198,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 463cfd33..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 *const *vals, - size_t *sizes, int count); -int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count); -int m68k_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void *const *vals, size_t *sizes, int count); -int m68k_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, 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 4edb7d33..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,9 +59,11 @@ void mips_reg_reset(struct uc_struct *uc) env->active_tc.PC = 0; } -static uc_err reg_read(CPUMIPSState *env, unsigned int regid, void *value, - size_t *size) +DEFAULT_VISIBILITY +uc_err reg_read(void *_env, int mode, unsigned int regid, void *value, + size_t *size) { + CPUMIPSState *env = _env; uc_err ret = UC_ERR_ARG; if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31) { @@ -101,9 +103,11 @@ static uc_err reg_read(CPUMIPSState *env, unsigned int regid, void *value, return ret; } -static uc_err reg_write(CPUMIPSState *env, unsigned int regid, - const void *value, size_t *size, int *setpc) +DEFAULT_VISIBILITY +uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc) { + CPUMIPSState *env = _env; uc_err ret = UC_ERR_ARG; if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31) { @@ -148,115 +152,6 @@ static uc_err reg_write(CPUMIPSState *env, unsigned int regid, return ret; } -static uc_err reg_read_batch(CPUMIPSState *env, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -{ - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - uc_err err = reg_read(env, regid, value, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; -} - -static uc_err reg_write_batch(CPUMIPSState *env, unsigned int *regs, - const void *const *vals, size_t *sizes, int count, - int *setpc) -{ - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - uc_err err = - reg_write(env, regid, value, sizes ? sizes + i : NULL, setpc); - if (err) { - return err; - } - } - - return UC_ERR_OK; -} - -int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, - size_t *sizes, int count) -{ - CPUMIPSState *env = &(MIPS_CPU(uc->cpu)->env); - return reg_read_batch(env, regs, vals, sizes, count); -} - -int mips_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) -{ - CPUMIPSState *env = &(MIPS_CPU(uc->cpu)->env); - int setpc = 0; - uc_err err = reg_write_batch(env, regs, vals, sizes, count, &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; -} - -DEFAULT_VISIBILITY -#ifdef TARGET_MIPS64 -#ifdef TARGET_WORDS_BIGENDIAN -int mips64_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -#else -int mips64el_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -#endif -#else // if TARGET_MIPS -#ifdef TARGET_WORDS_BIGENDIAN -int mips_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -#else -int mipsel_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -#endif -#endif -{ - CPUMIPSState *env = (CPUMIPSState *)ctx->data; - return reg_read_batch(env, regs, vals, sizes, count); -} - -DEFAULT_VISIBILITY -#ifdef TARGET_MIPS64 -#ifdef TARGET_WORDS_BIGENDIAN -int mips64_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) -#else -int mips64el_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, - int count) -#endif -#else // if TARGET_MIPS -#ifdef TARGET_WORDS_BIGENDIAN -int mips_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) -#else -int mipsel_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) -#endif -#endif -{ - CPUMIPSState *env = (CPUMIPSState *)ctx->data; - int setpc = 0; - return reg_write_batch(env, regs, vals, sizes, count, &setpc); -} - static int mips_cpus_init(struct uc_struct *uc, const char *cpu_model) { MIPSCPU *cpu; @@ -270,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 caaa414c..f089e5df 100644 --- a/qemu/target/mips/unicorn.h +++ b/qemu/target/mips/unicorn.h @@ -5,33 +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 *const *vals, - size_t *sizes, int count); -int mips_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, 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 *const *vals, size_t *sizes, int count); -int mips_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, int count); -int mipsel_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void *const *vals, size_t *sizes, int count); -int mipsel_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, int count); -int mips64_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void *const *vals, size_t *sizes, int count); -int mips64_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, int count); -int mips64el_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void *const *vals, size_t *sizes, int count); -int mips64el_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, - 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 edda420b..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,9 +146,11 @@ void ppc_reg_reset(struct uc_struct *uc) } // http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Motorola_PowerPC/PowerPc/GenInfo/pemch2.pdf -static uc_err reg_read(CPUPPCState *env, unsigned int regid, void *value, - size_t *size) +DEFAULT_VISIBILITY +uc_err reg_read(void *_env, int mode, unsigned int regid, void *value, + size_t *size) { + CPUPPCState *env = _env; uc_err ret = UC_ERR_ARG; if (regid >= UC_PPC_REG_0 && regid <= UC_PPC_REG_31) { @@ -170,9 +172,9 @@ static uc_err reg_read(CPUPPCState *env, unsigned int regid, void *value, break; case UC_PPC_REG_CR: { CHECK_REG_TYPE(uint32_t); - uint32_t val; - val = 0; - for (int i = 0; i < 8; i++) { + int i; + uint32_t val = 0; + for (i = 0; i < 8; i++) { val <<= 4; val |= env->crf[i]; } @@ -205,10 +207,11 @@ static uc_err reg_read(CPUPPCState *env, unsigned int regid, void *value, return ret; } -static uc_err reg_write(CPUPPCState *env, unsigned int regid, const void *value, - size_t *size, int *setpc) +DEFAULT_VISIBILITY +uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc) { - int i; + CPUPPCState *env = _env; uc_err ret = UC_ERR_ARG; if (regid >= UC_PPC_REG_0 && regid <= UC_PPC_REG_31) { @@ -231,6 +234,7 @@ static uc_err reg_write(CPUPPCState *env, unsigned int regid, const void *value, break; 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; @@ -264,94 +268,6 @@ static uc_err reg_write(CPUPPCState *env, unsigned int regid, const void *value, return ret; } -static uc_err reg_read_batch(CPUPPCState *env, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -{ - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - uc_err err = reg_read(env, regid, value, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; -} - -static uc_err reg_write_batch(CPUPPCState *env, unsigned int *regs, - const void *const *vals, size_t *sizes, int count, - int *setpc) -{ - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - uc_err err = - reg_write(env, regid, value, sizes ? sizes + i : NULL, setpc); - if (err) { - return err; - } - } - - return UC_ERR_OK; -} - -int ppc_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, - size_t *sizes, int count) -{ - CPUPPCState *env = &(POWERPC_CPU(uc->cpu)->env); - return reg_read_batch(env, regs, vals, sizes, count); -} - -int ppc_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) -{ - CPUPPCState *env = &(POWERPC_CPU(uc->cpu)->env); - int setpc = 0; - uc_err err = reg_write_batch(env, regs, vals, sizes, count, &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; -} - -DEFAULT_VISIBILITY -#ifdef TARGET_PPC64 -int ppc64_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -#else -int ppc_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -#endif -{ - CPUPPCState *env = (CPUPPCState *)ctx->data; - return reg_read_batch(env, regs, vals, sizes, count); -} - -DEFAULT_VISIBILITY -#ifdef TARGET_PPC64 -int ppc64_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) -#else -int ppc_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) -#endif -{ - CPUPPCState *env = (CPUPPCState *)ctx->data; - int setpc = 0; - return reg_write_batch(env, regs, vals, sizes, count, &setpc); -} - PowerPCCPU *cpu_ppc_init(struct uc_struct *uc); static int ppc_cpus_init(struct uc_struct *uc, const char *cpu_model) { @@ -365,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 df1d901f..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 *const *vals, - size_t *sizes, int count); -int ppc_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, 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 *const *vals, size_t *sizes, int count); -int ppc_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, int count); -int ppc64_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void *const *vals, size_t *sizes, int count); -int ppc64_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, 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 86ab8746..8b55282f 100644 --- a/qemu/target/riscv/unicorn.c +++ b/qemu/target/riscv/unicorn.c @@ -77,11 +77,13 @@ static void riscv_release(void *ctx) } } -void riscv_reg_reset(struct uc_struct *uc) {} +static void reg_reset(struct uc_struct *uc) {} -static uc_err reg_read(CPURISCVState *env, unsigned int regid, void *value, - size_t *size) +DEFAULT_VISIBILITY +uc_err reg_read(void *_env, int mode, unsigned int regid, void *value, + size_t *size) { + CPURISCVState *env = _env; uc_err ret = UC_ERR_ARG; if (regid >= UC_RISCV_REG_X0 && regid <= UC_RISCV_REG_X31) { @@ -127,9 +129,11 @@ static uc_err reg_read(CPURISCVState *env, unsigned int regid, void *value, return ret; } -static uc_err reg_write(CPURISCVState *env, unsigned int regid, - const void *value, size_t *size, int *setpc) +DEFAULT_VISIBILITY +uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc) { + CPURISCVState *env = _env; uc_err ret = UC_ERR_ARG; if (regid >= UC_RISCV_REG_X0 && regid <= UC_RISCV_REG_X31) { @@ -175,96 +179,6 @@ static uc_err reg_write(CPURISCVState *env, unsigned int regid, return ret; } -static uc_err reg_read_batch(CPURISCVState *env, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -{ - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - uc_err err = reg_read(env, regid, value, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; -} - -static uc_err reg_write_batch(CPURISCVState *env, unsigned int *regs, - const void *const *vals, size_t *sizes, int count, - int *setpc) -{ - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - uc_err err = - reg_write(env, regid, value, sizes ? sizes + i : NULL, setpc); - if (err) { - return err; - } - } - - return UC_ERR_OK; -} - -int riscv_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, - size_t *sizes, int count) -{ - CPURISCVState *env = &(RISCV_CPU(uc->cpu)->env); - return reg_read_batch(env, regs, vals, sizes, count); -} - -int riscv_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) -{ - CPURISCVState *env = &(RISCV_CPU(uc->cpu)->env); - int setpc = 0; - uc_err err = reg_write_batch(env, regs, vals, sizes, count, &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; -} - -DEFAULT_VISIBILITY -#ifdef TARGET_RISCV32 -int riscv32_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -#else -/* TARGET_RISCV64 */ -int riscv64_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -#endif -{ - CPURISCVState *env = (CPURISCVState *)ctx->data; - return reg_read_batch(env, regs, vals, sizes, count); -} - -DEFAULT_VISIBILITY -#ifdef TARGET_RISCV32 -int riscv32_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) -#else -/* TARGET_RISCV64 */ -int riscv64_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) -#endif -{ - CPURISCVState *env = (CPURISCVState *)ctx->data; - int setpc = 0; - return reg_write_batch(env, regs, vals, sizes, count, &setpc); -} - static bool riscv_stop_interrupt(struct uc_struct *uc, int intno) { // detect stop exception @@ -298,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 c7eeb450..87cdb3f8 100644 --- a/qemu/target/riscv/unicorn.h +++ b/qemu/target/riscv/unicorn.h @@ -6,24 +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 *const *vals, - size_t *sizes, int count); -int riscv_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, 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 *const *vals, size_t *sizes, int count); -int riscv32_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, - int count); -int riscv64_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void *const *vals, size_t *sizes, int count); -int riscv64_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, - 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 9d4ac0b0..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,9 +53,11 @@ void s390_reg_reset(struct uc_struct *uc) env->psw.addr = 0; } -static uc_err reg_read(CPUS390XState *env, unsigned int regid, void *value, - size_t *size) +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) { @@ -82,9 +84,11 @@ static uc_err reg_read(CPUS390XState *env, unsigned int regid, void *value, return ret; } -static uc_err reg_write(CPUS390XState *env, unsigned int regid, - const void *value, size_t *size, int *setpc) +DEFAULT_VISIBILITY +uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc) { + CPUS390XState *env = _env; uc_err ret = UC_ERR_ARG; if (regid >= UC_S390X_REG_R0 && regid <= UC_S390X_REG_R15) { @@ -112,86 +116,6 @@ static uc_err reg_write(CPUS390XState *env, unsigned int regid, return ret; } -static uc_err reg_read_batch(CPUS390XState *env, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -{ - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - uc_err err = reg_read(env, regid, value, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; -} - -static uc_err reg_write_batch(CPUS390XState *env, unsigned int *regs, - const void *const *vals, size_t *sizes, int count, - int *setpc) -{ - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - uc_err err = - reg_write(env, regid, value, sizes ? sizes + i : NULL, setpc); - if (err) { - return err; - } - } - - return UC_ERR_OK; -} - -DEFAULT_VISIBILITY -int s390_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, - size_t *sizes, int count) -{ - CPUS390XState *env = &(S390_CPU(uc->cpu)->env); - return reg_read_batch(env, regs, vals, sizes, count); -} - -DEFAULT_VISIBILITY -int s390_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) -{ - CPUS390XState *env = &(S390_CPU(uc->cpu)->env); - int setpc = 0; - uc_err err = reg_write_batch(env, regs, vals, sizes, count, &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; -} - -DEFAULT_VISIBILITY -int s390_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -{ - CPUS390XState *env = (CPUS390XState *)ctx->data; - return reg_read_batch(env, regs, vals, sizes, count); -} - -DEFAULT_VISIBILITY -int s390_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) -{ - CPUS390XState *env = (CPUS390XState *)ctx->data; - int setpc = 0; - return reg_write_batch(env, regs, vals, sizes, count, &setpc); -} - static int s390_cpus_init(struct uc_struct *uc, const char *cpu_model) { S390CPU *cpu; @@ -204,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 50d507e6..96285f7f 100644 --- a/qemu/target/s390x/unicorn.h +++ b/qemu/target/s390x/unicorn.h @@ -5,16 +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 *const *vals, - size_t *sizes, int count); -int s390_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count); -int s390_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void *const *vals, size_t *sizes, int count); -int s390_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, 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 030d3b12..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,9 +61,11 @@ void sparc_reg_reset(struct uc_struct *uc) env->regwptr = env->regbase; } -static uc_err reg_read(CPUSPARCState *env, unsigned int regid, void *value, - size_t *size) +DEFAULT_VISIBILITY +uc_err reg_read(void *_env, int mode, unsigned int regid, void *value, + size_t *size) { + CPUSPARCState *env = _env; uc_err ret = UC_ERR_ARG; if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) { @@ -91,9 +93,11 @@ static uc_err reg_read(CPUSPARCState *env, unsigned int regid, void *value, return ret; } -static uc_err reg_write(CPUSPARCState *env, unsigned int regid, - const void *value, size_t *size, int *setpc) +DEFAULT_VISIBILITY +uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc) { + CPUSPARCState *env = _env; uc_err ret = UC_ERR_ARG; if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) { @@ -124,84 +128,6 @@ static uc_err reg_write(CPUSPARCState *env, unsigned int regid, return ret; } -static uc_err reg_read_batch(CPUSPARCState *env, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -{ - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - uc_err err = reg_read(env, regid, value, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; -} - -static uc_err reg_write_batch(CPUSPARCState *env, unsigned int *regs, - const void *const *vals, size_t *sizes, int count, - int *setpc) -{ - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - uc_err err = - reg_write(env, regid, value, sizes ? sizes + i : NULL, setpc); - if (err) { - return err; - } - } - - return UC_ERR_OK; -} - -int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, - size_t *sizes, int count) -{ - CPUSPARCState *env = &(SPARC_CPU(uc->cpu)->env); - return reg_read_batch(env, regs, vals, sizes, count); -} - -int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) -{ - CPUSPARCState *env = &(SPARC_CPU(uc->cpu)->env); - int setpc = 0; - uc_err err = reg_write_batch(env, regs, vals, sizes, count, &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; -} - -DEFAULT_VISIBILITY -int sparc_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -{ - CPUSPARCState *env = (CPUSPARCState *)ctx->data; - return reg_read_batch(env, regs, vals, sizes, count); -} - -DEFAULT_VISIBILITY -int sparc_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) -{ - CPUSPARCState *env = (CPUSPARCState *)ctx->data; - int setpc = 0; - return reg_write_batch(env, regs, vals, sizes, count, &setpc); -} - static int sparc_cpus_init(struct uc_struct *uc, const char *cpu_model) { SPARCCPU *cpu; @@ -214,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 62c82ba2..4fbd6913 100644 --- a/qemu/target/sparc/unicorn.h +++ b/qemu/target/sparc/unicorn.h @@ -5,23 +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 *const *vals, - size_t *sizes, int count); -int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, 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 *const *vals, size_t *sizes, int count); -int sparc_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, int count); -int sparc64_context_reg_read(struct uc_context *ctx, unsigned int *regs, - void *const *vals, size_t *sizes, int count); -int sparc64_context_reg_write(struct uc_context *ctx, unsigned int *regs, - const void *const *vals, size_t *sizes, - 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 6c7bfae9..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,8 +83,11 @@ void sparc_reg_reset(struct uc_struct *uc) env->regwptr = env->regbase; } -static uc_err reg_read(CPUSPARCState *env, unsigned int regid, void *value, size_t *size) +DEFAULT_VISIBILITY +uc_err reg_read(void *_env, int mode, unsigned int regid, void *value, + size_t *size) { + CPUSPARCState *env = _env; uc_err ret = UC_ERR_ARG; if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) { @@ -113,8 +116,11 @@ static uc_err reg_read(CPUSPARCState *env, unsigned int regid, void *value, size return ret; } -static uc_err reg_write(CPUSPARCState *env, unsigned int regid, const void *value, size_t *size, int *setpc) +DEFAULT_VISIBILITY +uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc) { + CPUSPARCState *env = _env; uc_err ret = UC_ERR_ARG; if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) { @@ -145,76 +151,6 @@ static uc_err reg_write(CPUSPARCState *env, unsigned int regid, const void *valu return ret; } -static uc_err reg_read_batch(CPUSPARCState *env, unsigned int *regs, void *const *vals, size_t *sizes, int count) -{ - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - uc_err err = reg_read(env, regid, value, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; -} - -static uc_err reg_write_batch(CPUSPARCState *env, unsigned int *regs, const void* const* vals, size_t *sizes, int count, int *setpc) -{ - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - uc_err err = reg_write(env, regid, value, sizes ? sizes + i : NULL, setpc); - if (err) { - return err; - } - } - - return UC_ERR_OK; -} - -int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void *const *vals, size_t *sizes, int count) -{ - CPUSPARCState *env = &(SPARC_CPU(uc->cpu)->env); - return reg_read_batch(env, regs, vals, sizes, count); -} - -int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, const void* const* vals, size_t *sizes, int count) -{ - CPUSPARCState *env = &(SPARC_CPU(uc->cpu)->env); - int setpc = 0; - uc_err err = reg_write_batch(env, regs, vals, sizes, count, &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; -} - -DEFAULT_VISIBILITY -int sparc64_context_reg_read(struct uc_context *ctx, unsigned int *regs, void *const *vals, size_t *sizes, int count) -{ - CPUSPARCState *env = (CPUSPARCState *)ctx->data; - return reg_read_batch(env, regs, vals, sizes, count); -} - -DEFAULT_VISIBILITY -int sparc64_context_reg_write(struct uc_context *ctx, unsigned int *regs, const void *const *vals, size_t *sizes, int count) -{ - CPUSPARCState *env = (CPUSPARCState *)ctx->data; - int setpc = 0; - return reg_write_batch(env, regs, vals, sizes, count, &setpc); -} - static int sparc_cpus_init(struct uc_struct *uc, const char *cpu_model) { SPARCCPU *cpu; @@ -227,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 3d35846b..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,9 +39,11 @@ void tricore_reg_reset(struct uc_struct *uc) env->PC = 0; } -static uc_err reg_read(CPUTriCoreState *env, unsigned int regid, void *value, - size_t *size) +DEFAULT_VISIBILITY +uc_err reg_read(void *_env, int mode, unsigned int regid, void *value, + size_t *size) { + CPUTriCoreState *env = _env; uc_err ret = UC_ERR_ARG; if (regid >= UC_TRICORE_REG_A0 && regid <= UC_TRICORE_REG_A9) { @@ -139,9 +141,11 @@ static uc_err reg_read(CPUTriCoreState *env, unsigned int regid, void *value, return ret; } -static uc_err reg_write(CPUTriCoreState *env, unsigned int regid, - const void *value, size_t *size, int *setpc) +DEFAULT_VISIBILITY +uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, + size_t *size, int *setpc) { + CPUTriCoreState *env = _env; uc_err ret = UC_ERR_ARG; if (regid >= UC_TRICORE_REG_A0 && regid <= UC_TRICORE_REG_A9) { @@ -240,82 +244,6 @@ static uc_err reg_write(CPUTriCoreState *env, unsigned int regid, return ret; } -static uc_err reg_read_batch(CPUTriCoreState *env, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -{ - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - void *value = vals[i]; - uc_err err = reg_read(env, regid, value, sizes ? sizes + i : NULL); - if (err) { - return err; - } - } - - return UC_ERR_OK; -} - -static uc_err reg_write_batch(CPUTriCoreState *env, unsigned int *regs, - const void *const *vals, size_t *sizes, int count, - int *setpc) -{ - int i; - - for (i = 0; i < count; i++) { - unsigned int regid = regs[i]; - const void *value = vals[i]; - uc_err err = - reg_write(env, regid, value, sizes ? sizes + i : NULL, setpc); - if (err) { - return err; - } - } - - return UC_ERR_OK; -} - -int tricore_reg_read(struct uc_struct *uc, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -{ - CPUTriCoreState *env = &(TRICORE_CPU(uc->cpu)->env); - return reg_read_batch(env, regs, vals, sizes, count); -} - -int tricore_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) -{ - CPUTriCoreState *env = &(TRICORE_CPU(uc->cpu)->env); - int setpc = 0; - uc_err err = reg_write_batch(env, regs, vals, sizes, count, &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; -} - -int tricore_context_reg_read(struct uc_context *uc, unsigned int *regs, - void *const *vals, size_t *sizes, int count) -{ - CPUTriCoreState *env = (CPUTriCoreState *)uc->data; - return reg_read_batch(env, regs, vals, sizes, count); -} - -int tricore_context_reg_write(struct uc_context *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) -{ - CPUTriCoreState *env = (CPUTriCoreState *)uc->data; - int setpc = 0; - return reg_write_batch(env, regs, vals, sizes, count, &setpc); -} - static int tricore_cpus_init(struct uc_struct *uc, const char *cpu_model) { TriCoreCPU *cpu; @@ -347,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 e298da05..2958c365 100644 --- a/qemu/target/tricore/unicorn.h +++ b/qemu/target/tricore/unicorn.h @@ -10,19 +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 *const *vals, size_t *sizes, int count); -int tricore_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count); - -int tricore_context_reg_read(struct uc_context *uc, unsigned int *regs, - void *const *vals, size_t *sizes, int count); -int tricore_context_reg_write(struct uc_context *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, - 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/tricore.h b/qemu/tricore.h index a7219654..a953ce0b 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 diff --git a/qemu/unicorn_common.h b/qemu/unicorn_common.h index 3059eb74..035fe061 100644 --- a/qemu/unicorn_common.h +++ b/qemu/unicorn_common.h @@ -130,12 +130,10 @@ static inline void uc_common_init(struct uc_struct* uc) } #define CHECK_REG_TYPE(type) do { \ - if (unlikely(size)) { \ - if (unlikely(*size < sizeof(type))) { \ - return UC_ERR_NOMEM; \ - } \ - *size = sizeof(type); \ + if (unlikely(*size < sizeof(type))) { \ + return UC_ERR_NOMEM; \ } \ + *size = sizeof(type); \ ret = UC_ERR_OK; \ } while(0) diff --git a/qemu/x86_64.h b/qemu/x86_64.h index aa03182d..860707b1 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 @@ -1879,7 +1882,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/symbols.sh b/symbols.sh index cbf5f0db..1c4f31f2 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 \ @@ -1882,9 +1885,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 +2580,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 +4277,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 +4379,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 +5502,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 +5653,6 @@ helper_wrpstate \ helper_wrpil \ helper_done \ helper_retry \ -sparc_reg_reset \ -sparc_reg_read \ -sparc_reg_write \ " sparc64_SYMBOLS=${sparc_SYMBOLS} @@ -5828,17 +5813,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/uc.c b/uc.c index 0581c408..0c7a8f32 100644 --- a/uc.c +++ b/uc.c @@ -82,14 +82,14 @@ unsigned int uc_version(unsigned int *major, unsigned int *minor) UC_API_EXTRA; } -static int default_reg_read(struct uc_struct *uc, unsigned int *regs, - void *const *vals, size_t *sizes, int count) +static uc_err default_reg_read(void *env, int mode, unsigned int regid, + void *value, size_t *size) { return UC_ERR_HANDLE; } -static int default_reg_write(struct uc_struct *uc, unsigned int *regs, - const void *const *vals, size_t *sizes, int count) +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; } @@ -203,7 +203,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; \ } \ @@ -223,7 +223,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) { @@ -295,7 +295,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 @@ -305,7 +305,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 @@ -314,7 +314,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; @@ -327,7 +327,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 @@ -342,23 +342,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 } @@ -373,9 +373,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 @@ -387,9 +387,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 @@ -401,9 +401,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; @@ -416,7 +416,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 @@ -425,7 +425,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 } @@ -519,62 +519,158 @@ 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) { UC_INIT(uc); - return uc->reg_read(uc, (unsigned int *)ids, vals, NULL, count); + 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]; + size_t size = (size_t)-1; + uc_err err = reg_read(env, mode, regid, value, &size); + if (err) { + return err; + } + } + + 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) { UC_INIT(uc); - return uc->reg_write(uc, (unsigned int *)ids, (const void *const *)vals, - NULL, count); + 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]; + 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 UC_ERR_OK; } UNICORN_EXPORT -uc_err uc_reg_read_batch2(uc_engine *uc, int *ids, void *const *vals, +uc_err uc_reg_read_batch2(uc_engine *uc, int *regs, void *const *vals, size_t *sizes, int count) { UC_INIT(uc); - return uc->reg_read(uc, (unsigned int *)ids, vals, sizes, count); + 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 *ids, const void *const *vals, +uc_err uc_reg_write_batch2(uc_engine *uc, int *regs, const void *const *vals, size_t *sizes, int count) { UC_INIT(uc); - return uc->reg_write(uc, (unsigned int *)ids, vals, sizes, count); + 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(uc, (unsigned int *)®id, &value, NULL, 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(uc, (unsigned int *)®id, &value, NULL, 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, (unsigned int *)®id, &value, size, 1); + 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); - return uc->reg_write(uc, (unsigned int *)®id, &value, size, 1); + 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; } // check if a memory area is mapped @@ -1893,79 +1989,36 @@ uc_err uc_context_save(uc_engine *uc, uc_context *context) } } -UNICORN_EXPORT -uc_err uc_context_reg_write(uc_context *ctx, int regid, const void *value) -{ - return uc_context_reg_write_batch2(ctx, ®id, &value, NULL, 1); -} - -UNICORN_EXPORT -uc_err uc_context_reg_read(uc_context *ctx, int regid, void *value) -{ - return uc_context_reg_read_batch2(ctx, ®id, &value, NULL, 1); -} - -UNICORN_EXPORT -uc_err uc_context_reg_write2(uc_context *ctx, int regid, const void *value, - size_t *size) -{ - return uc_context_reg_write_batch2(ctx, ®id, &value, size, 1); -} - -UNICORN_EXPORT -uc_err uc_context_reg_read2(uc_context *ctx, int regid, void *value, - size_t *size) -{ - return uc_context_reg_read_batch2(ctx, ®id, &value, size, 1); -} - -UNICORN_EXPORT -uc_err uc_context_reg_write_batch(uc_context *ctx, int *ids, void *const *vals, - int count) -{ - return uc_context_reg_write_batch2(ctx, ids, (const void *const *)vals, - NULL, count); -} - -UNICORN_EXPORT -uc_err uc_context_reg_read_batch(uc_context *ctx, int *ids, void **vals, - int count) -{ - return uc_context_reg_read_batch2(ctx, ids, vals, NULL, count); -} - // 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 @@ -1975,27 +2028,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 } @@ -2005,82 +2058,174 @@ 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_batch2(uc_context *ctx, int *ids, +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) +{ + 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]; + size_t size = (size_t)-1; + uc_err err = reg_write(env, mode, regid, value, &size, &setpc); + if (err) { + return err; + } + } + + return UC_ERR_OK; +} + +UNICORN_EXPORT +uc_err uc_context_reg_read_batch(uc_context *ctx, int *regs, void **vals, + 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]; + size_t size = (size_t)-1; + uc_err err = reg_read(env, mode, regid, value, &size); + if (err) { + return err; + } + } + + 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) { - 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) { - return rw.context_reg_write(ctx, (unsigned int *)ids, vals, sizes, - count); - } else { - return UC_ERR_HANDLE; + 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 *ids, void *const *vals, +uc_err uc_context_reg_read_batch2(uc_context *ctx, int *regs, void *const *vals, size_t *sizes, int count) { - 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) { - return rw.context_reg_read(ctx, (unsigned int *)ids, vals, sizes, - count); - } else { - return UC_ERR_HANDLE; + 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 @@ -2099,7 +2244,6 @@ uc_err uc_context_restore(uc_engine *uc, uc_context *context) UNICORN_EXPORT uc_err uc_context_free(uc_context *context) { - return uc_free(context); } From b041345a7386f999bcc1bcbd81b5fad90955e48d Mon Sep 17 00:00:00 2001 From: Robert Xiao Date: Thu, 11 May 2023 23:39:15 -0700 Subject: [PATCH 30/44] Fix RISCV test_riscv32_fp_move test RISCV FP registers are 64-bit in size, even in 32-bit mode, because they can hold doubles. The test even uses the double-precision instruction fmv.d. Thus, the reads should be reading 64-bit registers. --- tests/unit/test_riscv.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/unit/test_riscv.c b/tests/unit/test_riscv.c index cf8b8fbe..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); } From 2b80ab425b266e1b6f61a74b8ee1f04b6b6213bf Mon Sep 17 00:00:00 2001 From: Robert Xiao Date: Fri, 16 Jun 2023 14:47:03 -0700 Subject: [PATCH 31/44] Return new UC_ERR_OVERFLOW instead of UC_ERR_NOMEM when reg buffer is too small --- include/unicorn/unicorn.h | 21 +++++++++++++-------- qemu/unicorn_common.h | 2 +- uc.c | 2 ++ 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index dbe8d027..3814b8e0 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; /* @@ -807,7 +808,7 @@ uc_err uc_reg_read(uc_engine *uc, int regid, void *value); @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_NOMEM if value is not large enough. + 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); @@ -821,7 +822,7 @@ uc_err uc_reg_write2(uc_engine *uc, int regid, const void *value, size_t *size); @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_NOMEM if value is not large enough. + 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); @@ -865,7 +866,8 @@ uc_err uc_reg_read_batch(uc_engine *uc, int *regs, void **vals, int count); @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_NOMEM if some value is not large enough. + 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, @@ -882,7 +884,8 @@ uc_err uc_reg_write_batch2(uc_engine *uc, int *regs, const void *const *vals, @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_NOMEM if some value is not large enough. + 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, @@ -1218,7 +1221,7 @@ uc_err uc_context_reg_read(uc_context *ctx, int regid, void *value); @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_NOMEM if value is not large enough. + 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, @@ -1233,7 +1236,7 @@ uc_err uc_context_reg_write2(uc_context *ctx, int regid, const void *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_NOMEM if value is not large enough. + 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, @@ -1279,7 +1282,8 @@ uc_err uc_context_reg_read_batch(uc_context *ctx, int *regs, void **vals, @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_NOMEM if some value is not large enough. + 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, @@ -1297,7 +1301,8 @@ uc_err uc_context_reg_write_batch2(uc_context *ctx, int *regs, @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_NOMEM if some value is not large enough. + 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, diff --git a/qemu/unicorn_common.h b/qemu/unicorn_common.h index 035fe061..1a622fe7 100644 --- a/qemu/unicorn_common.h +++ b/qemu/unicorn_common.h @@ -131,7 +131,7 @@ static inline void uc_common_init(struct uc_struct* uc) #define CHECK_REG_TYPE(type) do { \ if (unlikely(*size < sizeof(type))) { \ - return UC_ERR_NOMEM; \ + return UC_ERR_OVERFLOW; \ } \ *size = sizeof(type); \ ret = UC_ERR_OK; \ diff --git a/uc.c b/uc.c index 0c7a8f32..b92dddc1 100644 --- a/uc.c +++ b/uc.c @@ -148,6 +148,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)"; } } From 3bba11c40219929a3ecae3440dbec379e628e072 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 22 Jun 2023 12:19:06 +0800 Subject: [PATCH 32/44] remove all legacy DYNLOAD code --- tests/regress/emu_stop_in_hook_overrun.c | 14 -------------- tests/regress/mips_branch_likely_issue.c | 15 --------------- tests/regress/mips_delay_slot_code_hook.c | 14 -------------- tests/regress/threaded_emu_start.c | 14 -------------- 4 files changed, 57 deletions(-) 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; } From 75676eb0cd2d7815500dd392d5050e38332c14b9 Mon Sep 17 00:00:00 2001 From: mio Date: Wed, 28 Jun 2023 10:39:25 +0800 Subject: [PATCH 33/44] Also rebuild flags for aarch32 --- qemu/target/arm/unicorn_arm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/qemu/target/arm/unicorn_arm.c b/qemu/target/arm/unicorn_arm.c index f50ac0e1..eda70af5 100644 --- a/qemu/target/arm/unicorn_arm.c +++ b/qemu/target/arm/unicorn_arm.c @@ -548,6 +548,7 @@ uc_err reg_write(void *_env, int mode, unsigned int regid, const void *value, 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; } } From a7a5d187e77f7853755eff4768658daf8095c3b7 Mon Sep 17 00:00:00 2001 From: mio Date: Fri, 30 Jun 2023 20:21:56 +0800 Subject: [PATCH 34/44] Backport https://github.com/qemu/qemu/commit/10b8eb94c0902b58d83df84a9eeae709a3480e82 target/i386: Verify memory operand for lcall and ljmp These two opcodes only allow a memory operand. Lacking the check for a register operand, we used the A0 temp without initialization, which led to a tcg abort. --- qemu/target/i386/translate.c | 6 ++++++ 1 file changed, 6 insertions(+) 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); From 2325f41ead99b1cb73a01c3f35d842f926f34136 Mon Sep 17 00:00:00 2001 From: mio Date: Fri, 30 Jun 2023 20:28:59 +0800 Subject: [PATCH 35/44] Add a unit test for a7a5d187e77f7853755eff4768658daf8095c3b7 --- tests/unit/test_x86.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/unit/test_x86.c b/tests/unit/test_x86.c index c55b9e36..d74401b6 100644 --- a/tests/unit/test_x86.c +++ b/tests/unit/test_x86.c @@ -1438,6 +1438,36 @@ static void test_x86_segmentation() 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)); + + OK(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}, {"test_x86_out", test_x86_out}, @@ -1484,4 +1514,5 @@ TEST_LIST = { {"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}}; From aee4038526f88450b63e4bb7c38afa7ef35d0a50 Mon Sep 17 00:00:00 2001 From: mio Date: Fri, 7 Jul 2023 18:50:55 +0800 Subject: [PATCH 36/44] Fix test_x86_0xff_lcall test --- tests/unit/test_x86.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/test_x86.c b/tests/unit/test_x86.c index d74401b6..47611b58 100644 --- a/tests/unit/test_x86.c +++ b/tests/unit/test_x86.c @@ -1463,7 +1463,7 @@ static void test_x86_0xff_lcall() OK(uc_hook_add(uc, &hk, UC_HOOK_CODE, test_x86_0xff_lcall_callback, NULL, 1, 0)); - OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 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)); } From cd85f589a2aaa3bccc8b86099ebda3947116693c Mon Sep 17 00:00:00 2001 From: "Takacs, Philipp" Date: Fri, 16 Dec 2022 13:46:24 +0100 Subject: [PATCH 37/44] add memory_region_add_subregion_overlap --- qemu/aarch64.h | 1 + qemu/arm.h | 1 + qemu/include/exec/memory.h | 1 + qemu/m68k.h | 1 + qemu/mips.h | 1 + qemu/mips64.h | 1 + qemu/mips64el.h | 1 + qemu/mipsel.h | 1 + qemu/ppc.h | 1 + qemu/ppc64.h | 1 + qemu/riscv32.h | 1 + qemu/riscv64.h | 1 + qemu/s390x.h | 1 + qemu/softmmu/memory.c | 16 ++++++++++++++-- qemu/sparc.h | 1 + qemu/sparc64.h | 1 + qemu/tricore.h | 1 + qemu/x86_64.h | 1 + symbols.sh | 1 + 19 files changed, 32 insertions(+), 2 deletions(-) diff --git a/qemu/aarch64.h b/qemu/aarch64.h index aba5a963..6e17c390 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -142,6 +142,7 @@ #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_listener_register memory_listener_register_aarch64 #define memory_listener_unregister memory_listener_unregister_aarch64 diff --git a/qemu/arm.h b/qemu/arm.h index be8271c6..3676b360 100644 --- a/qemu/arm.h +++ b/qemu/arm.h @@ -142,6 +142,7 @@ #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_listener_register memory_listener_register_arm #define memory_listener_unregister memory_listener_unregister_arm diff --git a/qemu/include/exec/memory.h b/qemu/include/exec/memory.h index a4b36e53..88da991e 100644 --- a/qemu/include/exec/memory.h +++ b/qemu/include/exec/memory.h @@ -1186,6 +1186,7 @@ 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); int memory_free(struct uc_struct *uc); diff --git a/qemu/m68k.h b/qemu/m68k.h index ab97771b..061297d6 100644 --- a/qemu/m68k.h +++ b/qemu/m68k.h @@ -142,6 +142,7 @@ #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_listener_register memory_listener_register_m68k #define memory_listener_unregister memory_listener_unregister_m68k diff --git a/qemu/mips.h b/qemu/mips.h index 95f0abda..98447291 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -142,6 +142,7 @@ #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_listener_register memory_listener_register_mips #define memory_listener_unregister memory_listener_unregister_mips diff --git a/qemu/mips64.h b/qemu/mips64.h index e29e20e5..8a7dbe77 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -142,6 +142,7 @@ #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_listener_register memory_listener_register_mips64 #define memory_listener_unregister memory_listener_unregister_mips64 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index 6f94f431..5ae511bc 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -142,6 +142,7 @@ #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_listener_register memory_listener_register_mips64el #define memory_listener_unregister memory_listener_unregister_mips64el diff --git a/qemu/mipsel.h b/qemu/mipsel.h index 1b313d4b..dc0a2a41 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -142,6 +142,7 @@ #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_listener_register memory_listener_register_mipsel #define memory_listener_unregister memory_listener_unregister_mipsel diff --git a/qemu/ppc.h b/qemu/ppc.h index a3a339fb..d2761616 100644 --- a/qemu/ppc.h +++ b/qemu/ppc.h @@ -142,6 +142,7 @@ #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_listener_register memory_listener_register_ppc #define memory_listener_unregister memory_listener_unregister_ppc diff --git a/qemu/ppc64.h b/qemu/ppc64.h index 04564484..51f94d12 100644 --- a/qemu/ppc64.h +++ b/qemu/ppc64.h @@ -142,6 +142,7 @@ #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_listener_register memory_listener_register_ppc64 #define memory_listener_unregister memory_listener_unregister_ppc64 diff --git a/qemu/riscv32.h b/qemu/riscv32.h index a7a91fa7..8d373290 100644 --- a/qemu/riscv32.h +++ b/qemu/riscv32.h @@ -142,6 +142,7 @@ #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_listener_register memory_listener_register_riscv32 #define memory_listener_unregister memory_listener_unregister_riscv32 diff --git a/qemu/riscv64.h b/qemu/riscv64.h index 6934d749..e1593cde 100644 --- a/qemu/riscv64.h +++ b/qemu/riscv64.h @@ -142,6 +142,7 @@ #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_listener_register memory_listener_register_riscv64 #define memory_listener_unregister memory_listener_unregister_riscv64 diff --git a/qemu/s390x.h b/qemu/s390x.h index e00bcae9..b2350ce2 100644 --- a/qemu/s390x.h +++ b/qemu/s390x.h @@ -142,6 +142,7 @@ #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_listener_register memory_listener_register_s390x #define memory_listener_unregister memory_listener_unregister_s390x diff --git a/qemu/softmmu/memory.c b/qemu/softmmu/memory.c index bf6341d9..a0fdf5fb 100644 --- a/qemu/softmmu/memory.c +++ b/qemu/softmmu/memory.c @@ -1116,8 +1116,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); @@ -1141,6 +1143,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/sparc.h b/qemu/sparc.h index 596d8328..75ec3b29 100644 --- a/qemu/sparc.h +++ b/qemu/sparc.h @@ -142,6 +142,7 @@ #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_listener_register memory_listener_register_sparc #define memory_listener_unregister memory_listener_unregister_sparc diff --git a/qemu/sparc64.h b/qemu/sparc64.h index 223832ee..89ad6790 100644 --- a/qemu/sparc64.h +++ b/qemu/sparc64.h @@ -142,6 +142,7 @@ #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_listener_register memory_listener_register_sparc64 #define memory_listener_unregister memory_listener_unregister_sparc64 diff --git a/qemu/tricore.h b/qemu/tricore.h index a953ce0b..560e868e 100644 --- a/qemu/tricore.h +++ b/qemu/tricore.h @@ -142,6 +142,7 @@ #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_listener_register memory_listener_register_tricore #define memory_listener_unregister memory_listener_unregister_tricore diff --git a/qemu/x86_64.h b/qemu/x86_64.h index 860707b1..a52f8e13 100644 --- a/qemu/x86_64.h +++ b/qemu/x86_64.h @@ -142,6 +142,7 @@ #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_listener_register memory_listener_register_x86_64 #define memory_listener_unregister memory_listener_unregister_x86_64 diff --git a/symbols.sh b/symbols.sh index 1c4f31f2..6a21a98b 100755 --- a/symbols.sh +++ b/symbols.sh @@ -142,6 +142,7 @@ 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_listener_register \ memory_listener_unregister \ From 065af19dc5b60a4a0c650b1c13979dde80d0f502 Mon Sep 17 00:00:00 2001 From: "Takacs, Philipp" Date: Thu, 22 Dec 2022 12:20:36 +0100 Subject: [PATCH 38/44] use address_space_translate to find memory mapping first version has bugs --- include/uc_priv.h | 6 +++--- qemu/aarch64.h | 1 + qemu/accel/tcg/cputlb.c | 8 ++++---- qemu/arm.h | 1 + qemu/m68k.h | 1 + qemu/mips.h | 1 + qemu/mips64.h | 1 + qemu/mips64el.h | 1 + qemu/mipsel.h | 1 + qemu/ppc.h | 1 + qemu/ppc64.h | 1 + qemu/riscv32.h | 1 + qemu/riscv64.h | 1 + qemu/s390x.h | 1 + qemu/softmmu/memory.c | 2 +- qemu/sparc.h | 1 + qemu/sparc64.h | 1 + qemu/tricore.h | 1 + qemu/unicorn_common.h | 13 +++++++++++++ qemu/x86_64.h | 1 + symbols.sh | 1 + uc.c | 5 ++++- 22 files changed, 42 insertions(+), 9 deletions(-) diff --git a/include/uc_priv.h b/include/uc_priv.h index ef3d30e3..a6c86e70 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -100,6 +100,8 @@ 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_readonly_mem_t)(MemoryRegion *mr, bool readonly); typedef int (*uc_cpus_init)(struct uc_struct *, const char *); @@ -277,6 +279,7 @@ 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_mem_unmap_t memory_unmap; uc_readonly_mem_t readonly_mem; uc_cpus_init cpus_init; @@ -410,9 +413,6 @@ struct uc_context { 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/qemu/aarch64.h b/qemu/aarch64.h index 6e17c390..d7349535 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -151,6 +151,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 diff --git a/qemu/accel/tcg/cputlb.c b/qemu/accel/tcg/cputlb.c index f805b44a..e4c2d9a3 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,7 +1517,7 @@ 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; if (uc->nested_level > 0 && !uc->cpu->stopped) { @@ -2053,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 @@ -2107,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); diff --git a/qemu/arm.h b/qemu/arm.h index 3676b360..1fe1fc5c 100644 --- a/qemu/arm.h +++ b/qemu/arm.h @@ -151,6 +151,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 diff --git a/qemu/m68k.h b/qemu/m68k.h index 061297d6..d4a7c133 100644 --- a/qemu/m68k.h +++ b/qemu/m68k.h @@ -151,6 +151,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 diff --git a/qemu/mips.h b/qemu/mips.h index 98447291..44d22db0 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -151,6 +151,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 diff --git a/qemu/mips64.h b/qemu/mips64.h index 8a7dbe77..759f4552 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -151,6 +151,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 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index 5ae511bc..4700a912 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -151,6 +151,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 diff --git a/qemu/mipsel.h b/qemu/mipsel.h index dc0a2a41..f42638b0 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -151,6 +151,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 diff --git a/qemu/ppc.h b/qemu/ppc.h index d2761616..a2a7a814 100644 --- a/qemu/ppc.h +++ b/qemu/ppc.h @@ -151,6 +151,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 diff --git a/qemu/ppc64.h b/qemu/ppc64.h index 51f94d12..07f0a5ce 100644 --- a/qemu/ppc64.h +++ b/qemu/ppc64.h @@ -151,6 +151,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 diff --git a/qemu/riscv32.h b/qemu/riscv32.h index 8d373290..a33a0068 100644 --- a/qemu/riscv32.h +++ b/qemu/riscv32.h @@ -151,6 +151,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 diff --git a/qemu/riscv64.h b/qemu/riscv64.h index e1593cde..ba926a07 100644 --- a/qemu/riscv64.h +++ b/qemu/riscv64.h @@ -151,6 +151,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 diff --git a/qemu/s390x.h b/qemu/s390x.h index b2350ce2..e989949b 100644 --- a/qemu/s390x.h +++ b/qemu/s390x.h @@ -151,6 +151,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 a0fdf5fb..9e3e9a77 100644 --- a/qemu/softmmu/memory.c +++ b/qemu/softmmu/memory.c @@ -179,8 +179,8 @@ void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) int memory_free(struct uc_struct *uc) { - MemoryRegion *mr; int i; + MemoryRegion *mr; for (i = 0; i < uc->mapped_block_count; i++) { mr = uc->mapped_blocks[i]; diff --git a/qemu/sparc.h b/qemu/sparc.h index 75ec3b29..d5effee6 100644 --- a/qemu/sparc.h +++ b/qemu/sparc.h @@ -151,6 +151,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 diff --git a/qemu/sparc64.h b/qemu/sparc64.h index 89ad6790..462466cf 100644 --- a/qemu/sparc64.h +++ b/qemu/sparc64.h @@ -151,6 +151,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 diff --git a/qemu/tricore.h b/qemu/tricore.h index 560e868e..28b6f82d 100644 --- a/qemu/tricore.h +++ b/qemu/tricore.h @@ -151,6 +151,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 1a622fe7..10252c05 100644 --- a/qemu/unicorn_common.h +++ b/qemu/unicorn_common.h @@ -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) { @@ -124,6 +136,7 @@ static inline void uc_common_init(struct uc_struct* uc) 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; if (!uc->release) uc->release = release_common; diff --git a/qemu/x86_64.h b/qemu/x86_64.h index a52f8e13..a118e747 100644 --- a/qemu/x86_64.h +++ b/qemu/x86_64.h @@ -151,6 +151,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 diff --git a/symbols.sh b/symbols.sh index 6a21a98b..80f213b6 100755 --- a/symbols.sh +++ b/symbols.sh @@ -151,6 +151,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 \ diff --git a/uc.c b/uc.c index b92dddc1..7eb4beea 100644 --- a/uc.c +++ b/uc.c @@ -31,6 +31,7 @@ #include "qemu-common.h" static void clear_deleted_hooks(uc_engine *uc); +static MemoryRegion *find_memory_region(struct uc_struct *uc, uint64_t address); static void *hook_insert(struct list *l, struct hook *h) { @@ -1083,12 +1084,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; @@ -1609,7 +1612,7 @@ uc_err uc_mem_unmap(struct uc_struct *uc, uint64_t address, size_t size) } // find the memory region of this address -MemoryRegion *find_memory_region(struct uc_struct *uc, uint64_t address) +static MemoryRegion *find_memory_region(struct uc_struct *uc, uint64_t address) { unsigned int i; From 80bd825420fe7425f545e29d779e97409b990448 Mon Sep 17 00:00:00 2001 From: "Takacs, Philipp" Date: Thu, 22 Dec 2022 15:14:07 +0100 Subject: [PATCH 39/44] implement simple memory snapshot mechanismus Uses Copy on Write to make it posible to restore the memory state after a snapshot was made. To restore all MemoryRegions created after the snapshot are removed. --- include/uc_priv.h | 9 +++ include/unicorn/unicorn.h | 6 ++ qemu/aarch64.h | 2 + qemu/accel/tcg/cputlb.c | 16 ++++++ qemu/arm.h | 2 + qemu/include/exec/memory.h | 29 ++++++++++ qemu/m68k.h | 2 + qemu/mips.h | 2 + qemu/mips64.h | 2 + qemu/mips64el.h | 2 + qemu/mipsel.h | 2 + qemu/ppc.h | 2 + qemu/ppc64.h | 2 + qemu/riscv32.h | 2 + qemu/riscv64.h | 2 + qemu/s390x.h | 2 + qemu/softmmu/memory.c | 78 +++++++++++++++++++++++--- qemu/sparc.h | 2 + qemu/sparc64.h | 2 + qemu/tricore.h | 2 + qemu/unicorn_common.h | 2 + qemu/x86_64.h | 2 + symbols.sh | 2 + tests/unit/test_mem.c | 69 +++++++++++++++++++++++ uc.c | 111 +++++++++++++++++++++++-------------- 25 files changed, 302 insertions(+), 52 deletions(-) diff --git a/include/uc_priv.h b/include/uc_priv.h index a6c86e70..14ed07bd 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -80,6 +80,10 @@ 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 *); @@ -102,6 +106,8 @@ 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 *); @@ -267,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; @@ -280,6 +287,7 @@ struct uc_struct { 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_readonly_mem_t readonly_mem; uc_cpus_init cpus_init; @@ -403,6 +411,7 @@ struct uc_struct { PVOID seh_handle; void *seh_closure; #endif + int32_t snapshot_level; }; // Metadata stub for the variable-size cpu context used with uc_context_*() diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 3814b8e0..f2030546 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -1345,6 +1345,12 @@ size_t uc_context_size(uc_engine *uc); UNICORN_EXPORT uc_err uc_context_free(uc_context *context); +UNICORN_EXPORT +uc_err uc_snapshot(uc_engine *uc); + +UNICORN_EXPORT +uc_err uc_restore_latest_snapshot(uc_engine *uc); + #ifdef __cplusplus } #endif diff --git a/qemu/aarch64.h b/qemu/aarch64.h index d7349535..91b27ae5 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -123,6 +123,7 @@ #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_free memory_free_aarch64 #define flatview_unref flatview_unref_aarch64 @@ -144,6 +145,7 @@ #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 diff --git a/qemu/accel/tcg/cputlb.c b/qemu/accel/tcg/cputlb.c index e4c2d9a3..c120d27b 100644 --- a/qemu/accel/tcg/cputlb.c +++ b/qemu/accel/tcg/cputlb.c @@ -2155,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/arm.h b/qemu/arm.h index 1fe1fc5c..82b34564 100644 --- a/qemu/arm.h +++ b/qemu/arm.h @@ -123,6 +123,7 @@ #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_free memory_free_arm #define flatview_unref flatview_unref_arm @@ -144,6 +145,7 @@ #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 diff --git a/qemu/include/exec/memory.h b/qemu/include/exec/memory.h index 88da991e..c2661663 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 diff --git a/qemu/m68k.h b/qemu/m68k.h index d4a7c133..a2958aa0 100644 --- a/qemu/m68k.h +++ b/qemu/m68k.h @@ -123,6 +123,7 @@ #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_free memory_free_m68k #define flatview_unref flatview_unref_m68k @@ -144,6 +145,7 @@ #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 diff --git a/qemu/mips.h b/qemu/mips.h index 44d22db0..496bf5b2 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -123,6 +123,7 @@ #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_free memory_free_mips #define flatview_unref flatview_unref_mips @@ -144,6 +145,7 @@ #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 diff --git a/qemu/mips64.h b/qemu/mips64.h index 759f4552..84bfef10 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -123,6 +123,7 @@ #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_free memory_free_mips64 #define flatview_unref flatview_unref_mips64 @@ -144,6 +145,7 @@ #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 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index 4700a912..0c3af187 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -123,6 +123,7 @@ #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_free memory_free_mips64el #define flatview_unref flatview_unref_mips64el @@ -144,6 +145,7 @@ #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 diff --git a/qemu/mipsel.h b/qemu/mipsel.h index f42638b0..be52b6b8 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -123,6 +123,7 @@ #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_free memory_free_mipsel #define flatview_unref flatview_unref_mipsel @@ -144,6 +145,7 @@ #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 diff --git a/qemu/ppc.h b/qemu/ppc.h index a2a7a814..e44076db 100644 --- a/qemu/ppc.h +++ b/qemu/ppc.h @@ -123,6 +123,7 @@ #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_free memory_free_ppc #define flatview_unref flatview_unref_ppc @@ -144,6 +145,7 @@ #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 diff --git a/qemu/ppc64.h b/qemu/ppc64.h index 07f0a5ce..2a3527d4 100644 --- a/qemu/ppc64.h +++ b/qemu/ppc64.h @@ -123,6 +123,7 @@ #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_free memory_free_ppc64 #define flatview_unref flatview_unref_ppc64 @@ -144,6 +145,7 @@ #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 diff --git a/qemu/riscv32.h b/qemu/riscv32.h index a33a0068..eb978cb1 100644 --- a/qemu/riscv32.h +++ b/qemu/riscv32.h @@ -123,6 +123,7 @@ #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_free memory_free_riscv32 #define flatview_unref flatview_unref_riscv32 @@ -144,6 +145,7 @@ #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 diff --git a/qemu/riscv64.h b/qemu/riscv64.h index ba926a07..73b2d161 100644 --- a/qemu/riscv64.h +++ b/qemu/riscv64.h @@ -123,6 +123,7 @@ #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_free memory_free_riscv64 #define flatview_unref flatview_unref_riscv64 @@ -144,6 +145,7 @@ #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 diff --git a/qemu/s390x.h b/qemu/s390x.h index e989949b..da86a856 100644 --- a/qemu/s390x.h +++ b/qemu/s390x.h @@ -123,6 +123,7 @@ #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_free memory_free_s390x #define flatview_unref flatview_unref_s390x @@ -144,6 +145,7 @@ #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 diff --git a/qemu/softmmu/memory.c b/qemu/softmmu/memory.c index 9e3e9a77..0f0c5ed2 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,6 +193,21 @@ MemoryRegion *memory_map_io(struct uc_struct *uc, ram_addr_t begin, size_t size, return mmio; } +void memory_region_filter_subregions(MemoryRegion *mr, int32_t level) +{ + 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_transaction_commit(mr); +} + void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) { int i; @@ -179,16 +239,15 @@ void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) int memory_free(struct uc_struct *uc) { - int i; - MemoryRegion *mr; + 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; @@ -886,6 +945,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); } diff --git a/qemu/sparc.h b/qemu/sparc.h index d5effee6..e3edae06 100644 --- a/qemu/sparc.h +++ b/qemu/sparc.h @@ -123,6 +123,7 @@ #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_free memory_free_sparc #define flatview_unref flatview_unref_sparc @@ -144,6 +145,7 @@ #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 diff --git a/qemu/sparc64.h b/qemu/sparc64.h index 462466cf..ac9583bd 100644 --- a/qemu/sparc64.h +++ b/qemu/sparc64.h @@ -123,6 +123,7 @@ #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_free memory_free_sparc64 #define flatview_unref flatview_unref_sparc64 @@ -144,6 +145,7 @@ #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 diff --git a/qemu/tricore.h b/qemu/tricore.h index 28b6f82d..8dfd48dc 100644 --- a/qemu/tricore.h +++ b/qemu/tricore.h @@ -123,6 +123,7 @@ #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_free memory_free_tricore #define flatview_unref flatview_unref_tricore @@ -144,6 +145,7 @@ #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 diff --git a/qemu/unicorn_common.h b/qemu/unicorn_common.h index 10252c05..c3ae499e 100644 --- a/qemu/unicorn_common.h +++ b/qemu/unicorn_common.h @@ -137,6 +137,8 @@ static inline void uc_common_init(struct uc_struct* uc) 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; diff --git a/qemu/x86_64.h b/qemu/x86_64.h index a118e747..0ce52d2a 100644 --- a/qemu/x86_64.h +++ b/qemu/x86_64.h @@ -123,6 +123,7 @@ #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_free memory_free_x86_64 #define flatview_unref flatview_unref_x86_64 @@ -144,6 +145,7 @@ #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 diff --git a/symbols.sh b/symbols.sh index 80f213b6..ddea708f 100755 --- a/symbols.sh +++ b/symbols.sh @@ -123,6 +123,7 @@ cpu_inl \ memory_map \ memory_map_io \ memory_map_ptr \ +memory_cow \ memory_unmap \ memory_free \ flatview_unref \ @@ -144,6 +145,7 @@ 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 \ diff --git a/tests/unit/test_mem.c b/tests/unit/test_mem.c index 4e2f176a..d25b3448 100644 --- a/tests/unit/test_mem.c +++ b/tests/unit/test_mem.c @@ -275,6 +275,73 @@ static void test_mem_protect_mmio(void) OK(uc_close(uc)); } +static void test_snapshot(void) +{ + uc_engine *uc; + 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_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_snapshot(uc)); + + 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_snapshot(uc)); + 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_restore_latest_snapshot(uc)); + //TODO check mem + OK(uc_mem_read(uc, 0x2020, &mem, sizeof(mem))); + TEST_CHECK(mem == 1); + OK(uc_restore_latest_snapshot(uc)); + 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_use_snapshots(uc, 1)); + 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)); +} + TEST_LIST = {{"test_map_correct", test_map_correct}, {"test_map_wrapping", test_map_wrapping}, {"test_mem_protect", test_mem_protect}, @@ -286,4 +353,6 @@ 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}, {NULL, NULL}}; diff --git a/uc.c b/uc.c index 7eb4beea..184aba32 100644 --- a/uc.c +++ b/uc.c @@ -31,7 +31,6 @@ #include "qemu-common.h" static void clear_deleted_hooks(uc_engine *uc); -static MemoryRegion *find_memory_region(struct uc_struct *uc, uint64_t address); static void *hook_insert(struct list *l, struct hook *h) { @@ -676,16 +675,27 @@ uc_err uc_reg_write2(uc_engine *uc, int regid, const void *value, size_t *size) 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 // this is complicated because an area can overlap adjacent blocks 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 @@ -714,9 +724,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; @@ -755,7 +765,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 @@ -764,7 +774,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; @@ -1480,6 +1496,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; @@ -1501,6 +1522,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; } @@ -1510,14 +1533,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)) { @@ -1531,7 +1554,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; } @@ -1561,6 +1584,11 @@ uc_err uc_mem_unmap(struct uc_struct *uc, uint64_t address, size_t size) UC_INIT(uc); + // snapshot and unmapping can't be mixed + if (uc->snapshot_level > 0) { + return UC_ERR_ARG; + } + if (size == 0) { // nothing to unmap return UC_ERR_OK; @@ -1577,6 +1605,7 @@ uc_err uc_mem_unmap(struct uc_struct *uc, uint64_t address, size_t size) } // check that user's entire requested block is mapped + // TODO check for cow if (!check_mem_area(uc, address, size)) { return UC_ERR_NOMEM; } @@ -1586,8 +1615,8 @@ uc_err uc_mem_unmap(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_mmio_region(uc, mr, addr, len, true)) { return UC_ERR_NOMEM; @@ -1600,7 +1629,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); } @@ -1611,35 +1640,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 -static 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, ...) @@ -2598,6 +2598,31 @@ uc_err uc_ctl(uc_engine *uc, uc_control_type control, ...) return err; } +UNICORN_EXPORT +uc_err uc_snapshot(struct uc_struct *uc) +{ + if (uc->snapshot_level == INT32_MAX) { + return UC_ERR_RESOURCE; + } + uc->snapshot_level++; + return UC_ERR_OK; +} + +UNICORN_EXPORT +uc_err uc_restore_latest_snapshot(struct uc_struct *uc) +{ + MemoryRegion *subregion, *subregion_next; + + 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); + } + } + uc->snapshot_level--; + return UC_ERR_OK; +} + #ifdef UNICORN_TRACER uc_tracer *get_tracer() { From 550265f3c1430b55dcf62962991365d142be0b72 Mon Sep 17 00:00:00 2001 From: "Takacs, Philipp" Date: Fri, 27 Jan 2023 18:31:17 +0100 Subject: [PATCH 40/44] snapshot benchmark simple benchmark for the snapshots --- tests/benchmarks/cow/Makefile | 24 ++++ tests/benchmarks/cow/benchmark.c | 186 +++++++++++++++++++++++++++++++ tests/benchmarks/cow/binary.S | 13 +++ 3 files changed, 223 insertions(+) create mode 100644 tests/benchmarks/cow/Makefile create mode 100644 tests/benchmarks/cow/benchmark.c create mode 100644 tests/benchmarks/cow/binary.S 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 From e54cf7ee036c0a888ae77832c3ca321ba0b42c5c Mon Sep 17 00:00:00 2001 From: "Takacs, Philipp" Date: Tue, 28 Feb 2023 16:09:45 +0100 Subject: [PATCH 41/44] find_ram_offset optimization The ram_offset allocator searches the smalest gap in the ram_offset address space. This is slow especialy in combination with many allocation (i.e. snapshots). When it is known that there is no gap, this is now optimized. --- include/qemu.h | 1 + qemu/exec.c | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) 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/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); From 716c8f1c4ca999c87ecae989305b025f88d4d766 Mon Sep 17 00:00:00 2001 From: "Takacs, Philipp" Date: Tue, 11 Apr 2023 14:23:38 +0200 Subject: [PATCH 42/44] handle snapshots over context_save context_restore --- include/uc_priv.h | 2 ++ include/unicorn/unicorn.h | 15 +++++---- tests/unit/test_mem.c | 14 +++++--- uc.c | 69 +++++++++++++++++++++++++++++++-------- 4 files changed, 75 insertions(+), 25 deletions(-) diff --git a/include/uc_priv.h b/include/uc_priv.h index 14ed07bd..c2b7baa0 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -389,6 +389,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 @@ -419,6 +420,7 @@ 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 }; diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index f2030546..85a1ade8 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -581,6 +581,9 @@ typedef enum uc_control_type { // 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; /* @@ -662,6 +665,7 @@ See sample_ctl.c for a detailed example. 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; @@ -1015,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. @@ -1345,12 +1354,6 @@ size_t uc_context_size(uc_engine *uc); UNICORN_EXPORT uc_err uc_context_free(uc_context *context); -UNICORN_EXPORT -uc_err uc_snapshot(uc_engine *uc); - -UNICORN_EXPORT -uc_err uc_restore_latest_snapshot(uc_engine *uc); - #ifdef __cplusplus } #endif diff --git a/tests/unit/test_mem.c b/tests/unit/test_mem.c index d25b3448..8f6bcf4f 100644 --- a/tests/unit/test_mem.c +++ b/tests/unit/test_mem.c @@ -278,30 +278,34 @@ static void test_mem_protect_mmio(void) 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_snapshot(uc)); + 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_snapshot(uc)); + 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_restore_latest_snapshot(uc)); + OK(uc_context_restore(uc, c1)); //TODO check mem OK(uc_mem_read(uc, 0x2020, &mem, sizeof(mem))); TEST_CHECK(mem == 1); - OK(uc_restore_latest_snapshot(uc)); + OK(uc_context_restore(uc, c0)); OK(uc_mem_read(uc, 0x2020, &mem, sizeof(mem))); TEST_CHECK(mem == 0); //TODO check mem @@ -318,7 +322,7 @@ static void test_context_snapshot(void) uint64_t tmp = 1; OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc)); - OK(uc_ctl_context_use_snapshots(uc, 1)); + 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)); diff --git a/uc.c b/uc.c index 184aba32..90bc779e 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) { @@ -256,6 +258,8 @@ static uc_err uc_init_engine(uc_engine *uc) uc->reg_reset(uc); } + uc->context_content = UC_CTL_CONTEXT_CPU; + uc->init_done = true; return UC_ERR_OK; @@ -1985,13 +1989,26 @@ 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; + } } + + context->snapshot_level = uc->snapshot_level; + + 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. @@ -2237,13 +2254,26 @@ 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 @@ -2588,6 +2618,19 @@ uc_err uc_ctl(uc_engine *uc, uc_control_type control, ...) 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; @@ -2598,8 +2641,7 @@ uc_err uc_ctl(uc_engine *uc, uc_control_type control, ...) return err; } -UNICORN_EXPORT -uc_err uc_snapshot(struct uc_struct *uc) +static uc_err uc_snapshot(struct uc_struct *uc) { if (uc->snapshot_level == INT32_MAX) { return UC_ERR_RESOURCE; @@ -2608,8 +2650,7 @@ uc_err uc_snapshot(struct uc_struct *uc) return UC_ERR_OK; } -UNICORN_EXPORT -uc_err uc_restore_latest_snapshot(struct uc_struct *uc) +static uc_err uc_restore_latest_snapshot(struct uc_struct *uc) { MemoryRegion *subregion, *subregion_next; From df18756234ec5614d0194d7225ae2af3c279d59c Mon Sep 17 00:00:00 2001 From: "Takacs, Philipp" Date: Tue, 30 May 2023 16:18:17 +0200 Subject: [PATCH 43/44] implement uc_mem_unmap with snapshots still has todos and need tests --- include/uc_priv.h | 3 ++ qemu/aarch64.h | 2 ++ qemu/arm.h | 2 ++ qemu/include/exec/memory.h | 2 ++ qemu/m68k.h | 2 ++ qemu/mips.h | 2 ++ qemu/mips64.h | 2 ++ qemu/mips64el.h | 2 ++ qemu/mipsel.h | 2 ++ qemu/ppc.h | 2 ++ qemu/ppc64.h | 2 ++ qemu/riscv32.h | 2 ++ qemu/riscv64.h | 2 ++ qemu/s390x.h | 2 ++ qemu/softmmu/memory.c | 74 +++++++++++++++++++++++++++++++------- qemu/sparc.h | 2 ++ qemu/sparc64.h | 2 ++ qemu/tricore.h | 2 ++ qemu/unicorn_common.h | 2 ++ qemu/x86_64.h | 2 ++ symbols.sh | 2 ++ tests/unit/test_mem.c | 34 ++++++++++++++++++ uc.c | 70 ++++++++++++++++++++++++++++++++---- 23 files changed, 200 insertions(+), 19 deletions(-) diff --git a/include/uc_priv.h b/include/uc_priv.h index c2b7baa0..a9dca9fb 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -289,6 +289,8 @@ struct uc_struct { 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; @@ -412,6 +414,7 @@ struct uc_struct { PVOID seh_handle; void *seh_closure; #endif + GArray *unmapped_regions; int32_t snapshot_level; }; diff --git a/qemu/aarch64.h b/qemu/aarch64.h index 91b27ae5..106ffd2f 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -125,6 +125,8 @@ #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 diff --git a/qemu/arm.h b/qemu/arm.h index 82b34564..42ad9c51 100644 --- a/qemu/arm.h +++ b/qemu/arm.h @@ -125,6 +125,8 @@ #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 diff --git a/qemu/include/exec/memory.h b/qemu/include/exec/memory.h index c2661663..8a8d13c3 100644 --- a/qemu/include/exec/memory.h +++ b/qemu/include/exec/memory.h @@ -1217,6 +1217,8 @@ MemoryRegion *memory_map_ptr(struct uc_struct *uc, hwaddr begin, size_t size, ui 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/m68k.h b/qemu/m68k.h index a2958aa0..a743b019 100644 --- a/qemu/m68k.h +++ b/qemu/m68k.h @@ -125,6 +125,8 @@ #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 diff --git a/qemu/mips.h b/qemu/mips.h index 496bf5b2..af08a938 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -125,6 +125,8 @@ #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 diff --git a/qemu/mips64.h b/qemu/mips64.h index 84bfef10..0b46bae1 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -125,6 +125,8 @@ #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 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index 0c3af187..dd28ff03 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -125,6 +125,8 @@ #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 diff --git a/qemu/mipsel.h b/qemu/mipsel.h index be52b6b8..864857c8 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -125,6 +125,8 @@ #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 diff --git a/qemu/ppc.h b/qemu/ppc.h index e44076db..710231b8 100644 --- a/qemu/ppc.h +++ b/qemu/ppc.h @@ -125,6 +125,8 @@ #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 diff --git a/qemu/ppc64.h b/qemu/ppc64.h index 2a3527d4..41a4a3e3 100644 --- a/qemu/ppc64.h +++ b/qemu/ppc64.h @@ -125,6 +125,8 @@ #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 diff --git a/qemu/riscv32.h b/qemu/riscv32.h index eb978cb1..e4e24f52 100644 --- a/qemu/riscv32.h +++ b/qemu/riscv32.h @@ -125,6 +125,8 @@ #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 diff --git a/qemu/riscv64.h b/qemu/riscv64.h index 73b2d161..95a4b6ed 100644 --- a/qemu/riscv64.h +++ b/qemu/riscv64.h @@ -125,6 +125,8 @@ #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 diff --git a/qemu/s390x.h b/qemu/s390x.h index da86a856..97e8ecd7 100644 --- a/qemu/s390x.h +++ b/qemu/s390x.h @@ -125,6 +125,8 @@ #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 diff --git a/qemu/softmmu/memory.c b/qemu/softmmu/memory.c index 0f0c5ed2..2c52539c 100644 --- a/qemu/softmmu/memory.c +++ b/qemu/softmmu/memory.c @@ -208,9 +208,69 @@ void memory_region_filter_subregions(MemoryRegion *mr, int32_t level) 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)); + 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) { - int i; hwaddr addr; if (uc->cpu) { @@ -224,17 +284,7 @@ void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) } } memory_region_del_subregion(uc->system_memory, mr); - - 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); - break; - } - } + memory_region_remove_mapped_block(uc, mr, true); } int memory_free(struct uc_struct *uc) diff --git a/qemu/sparc.h b/qemu/sparc.h index e3edae06..51d623da 100644 --- a/qemu/sparc.h +++ b/qemu/sparc.h @@ -125,6 +125,8 @@ #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 diff --git a/qemu/sparc64.h b/qemu/sparc64.h index ac9583bd..5779f315 100644 --- a/qemu/sparc64.h +++ b/qemu/sparc64.h @@ -125,6 +125,8 @@ #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 diff --git a/qemu/tricore.h b/qemu/tricore.h index 8dfd48dc..5fc51625 100644 --- a/qemu/tricore.h +++ b/qemu/tricore.h @@ -125,6 +125,8 @@ #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 diff --git a/qemu/unicorn_common.h b/qemu/unicorn_common.h index c3ae499e..def70a9e 100644 --- a/qemu/unicorn_common.h +++ b/qemu/unicorn_common.h @@ -130,6 +130,8 @@ 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; diff --git a/qemu/x86_64.h b/qemu/x86_64.h index 0ce52d2a..be528692 100644 --- a/qemu/x86_64.h +++ b/qemu/x86_64.h @@ -125,6 +125,8 @@ #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 diff --git a/symbols.sh b/symbols.sh index ddea708f..e038b46f 100755 --- a/symbols.sh +++ b/symbols.sh @@ -125,6 +125,8 @@ memory_map_io \ memory_map_ptr \ memory_cow \ memory_unmap \ +memory_moveout \ +memory_movein \ memory_free \ flatview_unref \ address_space_get_flatview \ diff --git a/tests/unit/test_mem.c b/tests/unit/test_mem.c index 8f6bcf4f..0069c507 100644 --- a/tests/unit/test_mem.c +++ b/tests/unit/test_mem.c @@ -346,6 +346,39 @@ static void test_context_snapshot(void) 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}, @@ -359,4 +392,5 @@ TEST_LIST = {{"test_map_correct", test_map_correct}, {"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/uc.c b/uc.c index 90bc779e..ab620b55 100644 --- a/uc.c +++ b/uc.c @@ -260,6 +260,8 @@ static uc_err uc_init_engine(uc_engine *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; @@ -490,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) { @@ -1579,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) { @@ -1588,11 +1619,6 @@ uc_err uc_mem_unmap(struct uc_struct *uc, uint64_t address, size_t size) UC_INIT(uc); - // snapshot and unmapping can't be mixed - if (uc->snapshot_level > 0) { - return UC_ERR_ARG; - } - if (size == 0) { // nothing to unmap return UC_ERR_OK; @@ -1609,11 +1635,14 @@ uc_err uc_mem_unmap(struct uc_struct *uc, uint64_t address, size_t size) } // check that user's entire requested block is mapped - // TODO check for cow if (!check_mem_area(uc, address, 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; @@ -2652,7 +2681,8 @@ static uc_err uc_snapshot(struct uc_struct *uc) static uc_err uc_restore_latest_snapshot(struct uc_struct *uc) { - MemoryRegion *subregion, *subregion_next; + 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); @@ -2660,6 +2690,32 @@ static uc_err uc_restore_latest_snapshot(struct uc_struct *uc) 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; } From ab5938b3f679fb60bbdb80b8399549f7182b74f6 Mon Sep 17 00:00:00 2001 From: "Takacs, Philipp" Date: Tue, 13 Jun 2023 11:04:48 +0200 Subject: [PATCH 44/44] Update CREDITS.TXT --- CREDITS.TXT | 1 + 1 file changed, 1 insertion(+) 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