mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-18 19:23:56 +00:00
More icicle progress
This commit is contained in:
@@ -7,11 +7,13 @@ using icicle_emulator = struct icicle_emulator_;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
using raw_func = void(void*);
|
||||
using ptr_func = void(void*, uint64_t);
|
||||
using data_accessor_func = void(void* user, const void* data, size_t length);
|
||||
|
||||
using icicle_mmio_read_func = void(void* user, uint64_t address, size_t length, void* data);
|
||||
using icicle_mmio_write_func = void(void* user, uint64_t address, size_t length, const void* data);
|
||||
|
||||
using data_accessor_func = void(void* user, const void* data, size_t length);
|
||||
|
||||
icicle_emulator* icicle_create_emulator();
|
||||
int32_t icicle_protect_memory(icicle_emulator*, uint64_t address, uint64_t length, uint8_t permissions);
|
||||
int32_t icicle_map_memory(icicle_emulator*, uint64_t address, uint64_t length, uint8_t permissions);
|
||||
@@ -22,11 +24,13 @@ extern "C"
|
||||
int32_t icicle_write_memory(icicle_emulator*, uint64_t address, const void* data, size_t length);
|
||||
int32_t icicle_save_registers(icicle_emulator*, data_accessor_func* accessor, void* accessor_data);
|
||||
int32_t icicle_restore_registers(icicle_emulator*, const void* data, size_t length);
|
||||
uint32_t icicle_add_syscall_hook(icicle_emulator*, void (*callback)(void*), void* data);
|
||||
uint32_t icicle_add_syscall_hook(icicle_emulator*, raw_func* callback, void* data);
|
||||
uint32_t icicle_add_execution_hook(icicle_emulator*, ptr_func* callback, void* data);
|
||||
void icicle_remove_syscall_hook(icicle_emulator*, uint32_t id);
|
||||
size_t icicle_read_register(icicle_emulator*, int reg, void* data, size_t length);
|
||||
size_t icicle_write_register(icicle_emulator*, int reg, const void* data, size_t length);
|
||||
void icicle_start(icicle_emulator*);
|
||||
void icicle_stop(icicle_emulator*);
|
||||
void icicle_destroy_emulator(icicle_emulator*);
|
||||
}
|
||||
|
||||
@@ -48,6 +52,21 @@ namespace icicle
|
||||
using std::function<T>::function;
|
||||
~function_object() override = default;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
std::unique_ptr<utils::object> wrap_shared(std::shared_ptr<T> shared_ptr)
|
||||
{
|
||||
struct shard_wrapper : utils::object
|
||||
{
|
||||
std::shared_ptr<T> ptr{};
|
||||
~shard_wrapper() override = default;
|
||||
};
|
||||
|
||||
auto wrapper = std::make_unique<shard_wrapper>();
|
||||
wrapper->ptr = std::move(shared_ptr);
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
}
|
||||
|
||||
class icicle_x64_emulator : public x64_emulator
|
||||
@@ -87,6 +106,7 @@ namespace icicle
|
||||
|
||||
void stop() override
|
||||
{
|
||||
icicle_stop(this->emu_);
|
||||
}
|
||||
|
||||
void load_gdt(const pointer_type address, const uint32_t limit) override
|
||||
@@ -149,28 +169,30 @@ namespace icicle
|
||||
auto* ptr = wrapper.get();
|
||||
this->storage_.push_back(std::move(wrapper));
|
||||
|
||||
auto* read_wrapper = +[](void* user, const uint64_t address, const size_t length, void* data) {
|
||||
auto* read_wrapper = +[](void* user, const uint64_t addr, const size_t length, void* data) {
|
||||
constexpr auto limit = sizeof(uint64_t);
|
||||
const auto* w = static_cast<mmio_wrapper*>(user);
|
||||
|
||||
// TODO: Change interface to get rid of loop
|
||||
for (size_t offset = 0; offset < length; offset += limit)
|
||||
{
|
||||
const auto max_read = std::min(limit, length - offset);
|
||||
const auto value = w->read_cb(address + offset - w->base, max_read);
|
||||
const auto value = w->read_cb(addr + offset - w->base, max_read);
|
||||
memcpy(static_cast<uint8_t*>(data) + offset, &value, max_read);
|
||||
}
|
||||
};
|
||||
|
||||
auto* write_wrapper = +[](void* user, const uint64_t address, const size_t length, const void* data) {
|
||||
auto* write_wrapper = +[](void* user, const uint64_t addr, const size_t length, const void* data) {
|
||||
constexpr auto limit = sizeof(uint64_t);
|
||||
const auto* w = static_cast<mmio_wrapper*>(user);
|
||||
|
||||
// TODO: Change interface to get rid of loop
|
||||
for (size_t offset = 0; offset < length; offset += limit)
|
||||
{
|
||||
uint64_t value{};
|
||||
const auto max_read = std::min(limit, length - offset);
|
||||
memcpy(&value, static_cast<const uint8_t*>(data) + offset, max_read);
|
||||
w->write_cb(address + offset - w->base, max_read, value);
|
||||
w->write_cb(addr + offset - w->base, max_read, value);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -216,6 +238,7 @@ namespace icicle
|
||||
{
|
||||
if (static_cast<x64_hookable_instructions>(instruction_type) != x64_hookable_instructions::syscall)
|
||||
{
|
||||
// TODO
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -235,18 +258,21 @@ namespace icicle
|
||||
|
||||
emulator_hook* hook_basic_block(basic_block_hook_callback callback) override
|
||||
{
|
||||
// TODO
|
||||
(void)callback;
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
emulator_hook* hook_edge_generation(edge_generation_hook_callback callback) override
|
||||
{
|
||||
// TODO
|
||||
(void)callback;
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
emulator_hook* hook_interrupt(interrupt_hook_callback callback) override
|
||||
{
|
||||
// TODO
|
||||
(void)callback;
|
||||
return nullptr;
|
||||
// throw std::runtime_error("Not implemented");
|
||||
@@ -255,6 +281,7 @@ namespace icicle
|
||||
emulator_hook* hook_memory_violation(uint64_t address, size_t size,
|
||||
memory_violation_hook_callback callback) override
|
||||
{
|
||||
// TODO
|
||||
(void)address;
|
||||
(void)size;
|
||||
(void)callback;
|
||||
@@ -270,11 +297,28 @@ namespace icicle
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
(void)address;
|
||||
(void)size;
|
||||
(void)callback;
|
||||
auto shared_callback = std::make_shared<complex_memory_hook_callback>(std::move(callback));
|
||||
|
||||
if ((filter & memory_permission::exec) == memory_permission::exec)
|
||||
{
|
||||
if (address != 0 || size != std::numeric_limits<size_t>::max())
|
||||
{
|
||||
throw std::runtime_error("Not supported!");
|
||||
}
|
||||
|
||||
auto* ptr = shared_callback.get();
|
||||
auto wrapper = wrap_shared(shared_callback);
|
||||
auto* func = +[](void* user, const uint64_t ptr) {
|
||||
(*static_cast<complex_memory_hook_callback*>(user))(ptr, 0, 0, memory_permission::exec);
|
||||
};
|
||||
|
||||
const auto id = icicle_add_execution_hook(this->emu_, func, ptr);
|
||||
this->hooks_[id] = std::move(wrapper);
|
||||
|
||||
return reinterpret_cast<emulator_hook*>(static_cast<size_t>(id));
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
// throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
void delete_hook(emulator_hook* hook) override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use icicle_cpu::ValueSource;
|
||||
use std::collections::HashMap;
|
||||
use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
||||
|
||||
use crate::registers;
|
||||
|
||||
@@ -133,6 +133,7 @@ pub struct IcicleEmulator {
|
||||
vm: icicle_vm::Vm,
|
||||
reg: registers::X64RegisterNodes,
|
||||
syscall_hooks: HookContainer<dyn Fn()>,
|
||||
execution_hooks: Rc<RefCell<HookContainer<dyn Fn(u64)>>>,
|
||||
}
|
||||
|
||||
pub struct MmioHandler {
|
||||
@@ -167,8 +168,14 @@ impl icicle_cpu::mem::IoMemory for MmioHandler {
|
||||
impl IcicleEmulator {
|
||||
pub fn new() -> Self {
|
||||
let mut virtual_machine = create_x64_vm();
|
||||
let exec_hooks: Rc<RefCell<HookContainer<dyn Fn(u64)>>> = Rc::new(RefCell::new(HookContainer::new()));
|
||||
|
||||
let exec_hooks_clone = Rc::clone(&exec_hooks);
|
||||
|
||||
let hook = icicle_cpu::InstHook::new(move |_: &mut icicle_cpu::Cpu, addr: u64| {
|
||||
println!("TEST hook: {:#x}", addr);
|
||||
for (_key, func) in exec_hooks_clone.borrow().get_hooks() {
|
||||
func(addr);
|
||||
}
|
||||
});
|
||||
|
||||
let hook = virtual_machine.cpu.add_hook(hook);
|
||||
@@ -178,6 +185,7 @@ impl IcicleEmulator {
|
||||
reg: registers::X64RegisterNodes::new(&virtual_machine.cpu.arch),
|
||||
vm: virtual_machine,
|
||||
syscall_hooks: HookContainer::new(),
|
||||
execution_hooks: exec_hooks,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,6 +194,8 @@ impl IcicleEmulator {
|
||||
}
|
||||
|
||||
pub fn start(&mut self) {
|
||||
self.vm.icount_limit = u64::MAX;
|
||||
|
||||
loop {
|
||||
let reason = self.vm.run();
|
||||
|
||||
@@ -208,6 +218,15 @@ impl IcicleEmulator {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn stop(&mut self) {
|
||||
self.vm.icount_limit = self.vm.cpu.icount + 1;
|
||||
}
|
||||
|
||||
pub fn add_execution_hook(&mut self, callback: Box<dyn Fn(u64)>) -> u32 {
|
||||
let hook_id = self.execution_hooks.borrow_mut().add_hook(callback);
|
||||
return qualify_hook_id(hook_id, HookType::Execute);
|
||||
}
|
||||
|
||||
pub fn add_syscall_hook(&mut self, callback: Box<dyn Fn()>) -> u32 {
|
||||
let hook_id = self.syscall_hooks.add_hook(callback);
|
||||
return qualify_hook_id(hook_id, HookType::Syscall);
|
||||
@@ -218,6 +237,7 @@ impl IcicleEmulator {
|
||||
|
||||
match hook_type {
|
||||
HookType::Syscall => self.syscall_hooks.remove_hook(hook_id),
|
||||
HookType::Execute => self.execution_hooks.borrow_mut().remove_hook(hook_id),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,16 @@ pub fn icicle_start(ptr: *mut c_void) {
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub fn icicle_stop(ptr: *mut c_void) {
|
||||
unsafe {
|
||||
let emulator = &mut *(ptr as *mut IcicleEmulator);
|
||||
emulator.stop();
|
||||
}
|
||||
}
|
||||
|
||||
type RawFunction = extern "C" fn(*mut c_void);
|
||||
type PtrFunction = extern "C" fn(*mut c_void, u64);
|
||||
type DataFunction = extern "C" fn(*mut c_void, *const c_void, usize);
|
||||
type MmioReadFunction = extern "C" fn(*mut c_void, u64, usize, *mut c_void);
|
||||
type MmioWriteFunction = extern "C" fn(*mut c_void, u64, usize, *const c_void);
|
||||
@@ -138,6 +147,14 @@ pub fn icicle_add_syscall_hook(ptr: *mut c_void, callback: RawFunction, data: *m
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub fn icicle_add_execution_hook(ptr: *mut c_void, callback: PtrFunction, data: *mut c_void) {
|
||||
unsafe {
|
||||
let emulator = &mut *(ptr as *mut IcicleEmulator);
|
||||
emulator.add_execution_hook(Box::new(move |ptr: u64| callback(data, ptr)));
|
||||
}
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub fn icicle_remove_syscall_hook(ptr: *mut c_void, id: u32) {
|
||||
unsafe {
|
||||
|
||||
Reference in New Issue
Block a user