mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-11 16:46:16 +00:00
Simplify hooking interface
This commit is contained in:
@@ -42,13 +42,15 @@ namespace
|
||||
|
||||
win_emu.emu().hook_memory_write(
|
||||
win_emu.process.peb.value() + offsetof(PEB64, ProcessParameters), 0x8,
|
||||
[&win_emu, cache_logging, params_hook, modules](const uint64_t address, size_t,
|
||||
const uint64_t value) mutable {
|
||||
[&win_emu, cache_logging, params_hook, modules](const uint64_t address, const void*, size_t) mutable {
|
||||
const auto target_address = win_emu.process.peb.value() + offsetof(PEB64, ProcessParameters);
|
||||
|
||||
if (address == target_address)
|
||||
{
|
||||
const emulator_object<RTL_USER_PROCESS_PARAMETERS64> obj{win_emu.emu(), value};
|
||||
const emulator_object<RTL_USER_PROCESS_PARAMETERS64> obj{
|
||||
win_emu.emu(),
|
||||
win_emu.emu().read_memory<uint64_t>(address),
|
||||
};
|
||||
|
||||
win_emu.emu().delete_hook(params_hook);
|
||||
params_hook = watch_object(win_emu, modules, obj, cache_logging);
|
||||
@@ -236,7 +238,7 @@ namespace
|
||||
continue;
|
||||
}
|
||||
|
||||
auto read_handler = [&, section, concise_logging](const uint64_t address, size_t, uint64_t) {
|
||||
auto read_handler = [&, section, concise_logging](const uint64_t address, const void*, size_t) {
|
||||
const auto rip = win_emu->emu().read_instruction_pointer();
|
||||
if (!win_emu->mod_manager.executable->is_within(rip))
|
||||
{
|
||||
@@ -258,7 +260,7 @@ namespace
|
||||
section.name.c_str(), address, rip);
|
||||
};
|
||||
|
||||
const auto write_handler = [&, section, concise_logging](const uint64_t address, size_t, uint64_t) {
|
||||
const auto write_handler = [&, section, concise_logging](const uint64_t address, const void*, size_t) {
|
||||
const auto rip = win_emu->emu().read_instruction_pointer();
|
||||
if (!win_emu->mod_manager.executable->is_within(rip))
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@ emulator_hook* watch_object(windows_emulator& emu, const std::set<std::string, s
|
||||
|
||||
return emu.emu().hook_memory_read(
|
||||
object.value(), object.size(),
|
||||
[i = std::move(info), object, &emu, cache_logging, modules](const uint64_t address, size_t, uint64_t) {
|
||||
[i = std::move(info), object, &emu, cache_logging, modules](const uint64_t address, const void*, size_t) {
|
||||
const auto rip = emu.emu().read_instruction_pointer();
|
||||
const auto* mod = emu.mod_manager.find_by_address(rip);
|
||||
const auto is_main_access = mod == emu.mod_manager.executable || modules.contains(mod->name);
|
||||
|
||||
@@ -40,11 +40,11 @@ using edge_generation_hook_callback =
|
||||
using basic_block_hook_callback = std::function<void(const basic_block& block)>;
|
||||
|
||||
using instruction_hook_callback = std::function<instruction_hook_continuation()>;
|
||||
|
||||
using interrupt_hook_callback = std::function<void(int interrupt)>;
|
||||
using simple_memory_hook_callback = std::function<void(uint64_t address, size_t size, uint64_t value)>;
|
||||
using complex_memory_hook_callback =
|
||||
std::function<void(uint64_t address, size_t size, uint64_t value, memory_operation operation)>;
|
||||
|
||||
using memory_access_hook_callback = std::function<void(uint64_t address, const void* data, size_t size)>;
|
||||
using memory_execution_hook_callback = std::function<void(uint64_t address)>;
|
||||
|
||||
using memory_violation_hook_callback = std::function<memory_violation_continuation(
|
||||
uint64_t address, size_t size, memory_operation operation, memory_violation_type type)>;
|
||||
|
||||
@@ -53,43 +53,18 @@ class hook_interface
|
||||
public:
|
||||
virtual ~hook_interface() = default;
|
||||
|
||||
virtual emulator_hook* hook_memory_violation(memory_violation_hook_callback callback) = 0;
|
||||
virtual emulator_hook* hook_memory_execution(memory_execution_hook_callback callback) = 0;
|
||||
virtual emulator_hook* hook_memory_execution(uint64_t address, memory_execution_hook_callback callback) = 0;
|
||||
virtual emulator_hook* hook_memory_read(uint64_t address, size_t size, memory_access_hook_callback callback) = 0;
|
||||
virtual emulator_hook* hook_memory_write(uint64_t address, size_t size, memory_access_hook_callback callback) = 0;
|
||||
|
||||
virtual emulator_hook* hook_memory_access(uint64_t address, size_t size, memory_operation filter,
|
||||
complex_memory_hook_callback callback) = 0;
|
||||
virtual emulator_hook* hook_instruction(int instruction_type, instruction_hook_callback callback) = 0;
|
||||
|
||||
virtual emulator_hook* hook_interrupt(interrupt_hook_callback callback) = 0;
|
||||
virtual emulator_hook* hook_memory_violation(memory_violation_hook_callback callback) = 0;
|
||||
|
||||
virtual emulator_hook* hook_edge_generation(edge_generation_hook_callback callback) = 0;
|
||||
virtual emulator_hook* hook_basic_block(basic_block_hook_callback callback) = 0;
|
||||
|
||||
virtual void delete_hook(emulator_hook* hook) = 0;
|
||||
|
||||
emulator_hook* hook_memory_read(const uint64_t address, const size_t size, simple_memory_hook_callback callback)
|
||||
{
|
||||
return this->hook_simple_memory_access(address, size, std::move(callback), memory_operation::read);
|
||||
}
|
||||
|
||||
emulator_hook* hook_memory_write(const uint64_t address, const size_t size, simple_memory_hook_callback callback)
|
||||
{
|
||||
return this->hook_simple_memory_access(address, size, std::move(callback), memory_operation::write);
|
||||
}
|
||||
|
||||
emulator_hook* hook_memory_execution(const uint64_t address, const size_t size,
|
||||
simple_memory_hook_callback callback)
|
||||
{
|
||||
return this->hook_simple_memory_access(address, size, std::move(callback), memory_operation::exec);
|
||||
}
|
||||
|
||||
private:
|
||||
emulator_hook* hook_simple_memory_access(const uint64_t address, const size_t size,
|
||||
simple_memory_hook_callback callback, const memory_operation operation)
|
||||
{
|
||||
assert((static_cast<uint8_t>(operation) & (static_cast<uint8_t>(operation) - 1)) == 0);
|
||||
return this->hook_memory_access(address, size, operation,
|
||||
[c = std::move(callback)](const uint64_t a, const size_t s,
|
||||
const uint64_t value,
|
||||
memory_operation) { c(a, s, value); });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -7,8 +7,13 @@ class scoped_hook
|
||||
scoped_hook() = default;
|
||||
|
||||
scoped_hook(emulator& emu, emulator_hook* hook)
|
||||
: scoped_hook(emu, std::vector{hook})
|
||||
{
|
||||
}
|
||||
|
||||
scoped_hook(emulator& emu, std::vector<emulator_hook*> hooks)
|
||||
: emu_(&emu),
|
||||
hook_(hook)
|
||||
hooks_(std::move(hooks))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -31,9 +36,9 @@ class scoped_hook
|
||||
{
|
||||
this->remove();
|
||||
this->emu_ = obj.emu_;
|
||||
this->hook_ = obj.hook_;
|
||||
this->hooks_ = std::move(obj.hooks_);
|
||||
|
||||
obj.hook_ = {};
|
||||
obj.hooks_ = {};
|
||||
}
|
||||
|
||||
return *this;
|
||||
@@ -41,14 +46,22 @@ class scoped_hook
|
||||
|
||||
void remove()
|
||||
{
|
||||
if (this->hook_)
|
||||
auto hooks = std::move(this->hooks_);
|
||||
this->hooks_ = {};
|
||||
|
||||
for (auto* hook : hooks_)
|
||||
{
|
||||
this->emu_->delete_hook(this->hook_);
|
||||
this->hook_ = {};
|
||||
try
|
||||
{
|
||||
this->emu_->delete_hook(hook);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
emulator* emu_{};
|
||||
emulator_hook* hook_{};
|
||||
std::vector<emulator_hook*> hooks_{};
|
||||
};
|
||||
|
||||
@@ -35,7 +35,9 @@ namespace
|
||||
void forward_emulator(windows_emulator& win_emu)
|
||||
{
|
||||
const auto target = win_emu.mod_manager.executable->find_export("vulnerable");
|
||||
win_emu.emu().hook_memory_execution(target, 1, [&](uint64_t, size_t, uint64_t) { win_emu.emu().stop(); });
|
||||
win_emu.emu().hook_memory_execution(target, [&](uint64_t) {
|
||||
win_emu.emu().stop(); //
|
||||
});
|
||||
|
||||
run_emulation(win_emu);
|
||||
}
|
||||
@@ -64,7 +66,9 @@ namespace
|
||||
|
||||
const auto ret = emu.emu().read_stack(0);
|
||||
|
||||
emu.emu().hook_memory_execution(ret, 1, [&](uint64_t, size_t, uint64_t) { emu.emu().stop(); });
|
||||
emu.emu().hook_memory_execution(ret, [&](uint64_t) {
|
||||
emu.emu().stop(); //
|
||||
});
|
||||
}
|
||||
|
||||
void restore_emulator()
|
||||
|
||||
@@ -298,36 +298,46 @@ namespace icicle
|
||||
return wrap_hook(id);
|
||||
}
|
||||
|
||||
emulator_hook* hook_memory_access(const uint64_t address, const size_t size, const memory_operation filter,
|
||||
complex_memory_hook_callback callback) override
|
||||
emulator_hook* hook_memory_execution(const uint64_t address, memory_execution_hook_callback callback) override
|
||||
{
|
||||
if (filter == memory_permission::none)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
// TODO
|
||||
(void)address;
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
const auto shared_callback = std::make_shared<complex_memory_hook_callback>(std::move(callback));
|
||||
emulator_hook* hook_memory_execution(memory_execution_hook_callback callback) override
|
||||
{
|
||||
auto wrapper = make_function_object(std::move(callback));
|
||||
auto* ptr = wrapper.get();
|
||||
auto* func = +[](void* user, const uint64_t addr) {
|
||||
auto& func = *static_cast<memory_execution_hook_callback*>(user);
|
||||
(func)(addr);
|
||||
};
|
||||
|
||||
if ((filter & memory_permission::exec) == memory_permission::exec)
|
||||
{
|
||||
if (address != 0 || size != std::numeric_limits<size_t>::max())
|
||||
{
|
||||
throw std::runtime_error("Not supported!");
|
||||
}
|
||||
const auto id = icicle_add_execution_hook(this->emu_, func, ptr);
|
||||
this->hooks_[id] = std::move(wrapper);
|
||||
|
||||
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);
|
||||
};
|
||||
return wrap_hook(id);
|
||||
}
|
||||
|
||||
const auto id = icicle_add_execution_hook(this->emu_, func, ptr);
|
||||
this->hooks_[id] = std::move(wrapper);
|
||||
emulator_hook* hook_memory_read(const uint64_t address, const size_t size,
|
||||
memory_access_hook_callback callback) override
|
||||
{
|
||||
// TODO
|
||||
(void)address;
|
||||
(void)size;
|
||||
(void)callback;
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
return wrap_hook(id);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
emulator_hook* hook_memory_write(const uint64_t address, const size_t size,
|
||||
const memory_access_hook_callback callback) override
|
||||
{
|
||||
// TODO
|
||||
(void)address;
|
||||
(void)size;
|
||||
(void)callback;
|
||||
throw std::runtime_error("Not implemented");
|
||||
}
|
||||
|
||||
void delete_hook(emulator_hook* hook) override
|
||||
|
||||
@@ -175,63 +175,6 @@ namespace unicorn
|
||||
size_t size_{};
|
||||
};
|
||||
|
||||
void add_read_hook(uc_engine* uc, const uint64_t address, const size_t size, hook_container& container,
|
||||
const std::shared_ptr<complex_memory_hook_callback>& callback)
|
||||
{
|
||||
function_wrapper<void, uc_engine*, uc_mem_type, uint64_t, int, int64_t> wrapper(
|
||||
[callback](uc_engine*, const uc_mem_type type, const uint64_t address, const int size, const int64_t) {
|
||||
const auto operation = map_memory_operation(type);
|
||||
if (operation != memory_permission::none)
|
||||
{
|
||||
(*callback)(address, static_cast<uint64_t>(size), 0, operation);
|
||||
}
|
||||
});
|
||||
|
||||
unicorn_hook hook{uc};
|
||||
|
||||
uce(uc_hook_add(uc, hook.make_reference(), UC_HOOK_MEM_READ, wrapper.get_function(),
|
||||
wrapper.get_user_data(), address, address + size));
|
||||
|
||||
container.add(std::move(wrapper), std::move(hook));
|
||||
}
|
||||
|
||||
void add_write_hook(uc_engine* uc, const uint64_t address, const size_t size, hook_container& container,
|
||||
const std::shared_ptr<complex_memory_hook_callback>& callback)
|
||||
{
|
||||
function_wrapper<void, uc_engine*, uc_mem_type, uint64_t, int, int64_t> wrapper(
|
||||
[callback](uc_engine*, const uc_mem_type type, const uint64_t address, const int size,
|
||||
const uint64_t value) {
|
||||
const auto operation = map_memory_operation(type);
|
||||
if (operation != memory_permission::none)
|
||||
{
|
||||
(*callback)(address, static_cast<uint64_t>(size), value, operation);
|
||||
}
|
||||
});
|
||||
|
||||
unicorn_hook hook{uc};
|
||||
|
||||
uce(uc_hook_add(uc, hook.make_reference(), UC_HOOK_MEM_WRITE, wrapper.get_function(),
|
||||
wrapper.get_user_data(), address, address + size));
|
||||
|
||||
container.add(std::move(wrapper), std::move(hook));
|
||||
}
|
||||
|
||||
void add_exec_hook(uc_engine* uc, const uint64_t address, const size_t size, hook_container& container,
|
||||
const std::shared_ptr<complex_memory_hook_callback>& callback)
|
||||
{
|
||||
function_wrapper<void, uc_engine*, uint64_t, uint32_t> wrapper(
|
||||
[callback](uc_engine*, const uint64_t address, const uint32_t size) {
|
||||
(*callback)(address, size, 0, memory_permission::exec);
|
||||
});
|
||||
|
||||
unicorn_hook hook{uc};
|
||||
|
||||
uce(uc_hook_add(uc, hook.make_reference(), UC_HOOK_CODE, wrapper.get_function(), wrapper.get_user_data(),
|
||||
address, address + size));
|
||||
|
||||
container.add(std::move(wrapper), std::move(hook));
|
||||
}
|
||||
|
||||
basic_block map_block(const uc_tb& translation_block)
|
||||
{
|
||||
basic_block block{};
|
||||
@@ -581,38 +524,94 @@ namespace unicorn
|
||||
return result;
|
||||
}
|
||||
|
||||
emulator_hook* hook_memory_access(const uint64_t address, const size_t size, const memory_operation filter,
|
||||
complex_memory_hook_callback callback) override
|
||||
emulator_hook* hook_memory_execution(uint64_t address, uint64_t size,
|
||||
memory_execution_hook_callback callback)
|
||||
{
|
||||
if (filter == memory_permission::none)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
auto exec_wrapper = [c = std::move(callback)](uc_engine*, const uint64_t address,
|
||||
const uint32_t /*size*/) {
|
||||
c(address); //
|
||||
};
|
||||
|
||||
const auto shared_callback = std::make_shared<complex_memory_hook_callback>(std::move(callback));
|
||||
function_wrapper<void, uc_engine*, uint64_t, uint32_t> wrapper(std::move(exec_wrapper));
|
||||
|
||||
unicorn_hook hook{*this};
|
||||
|
||||
uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_CODE, wrapper.get_function(),
|
||||
wrapper.get_user_data(), address, address + size));
|
||||
|
||||
auto* container = this->create_hook_container();
|
||||
container->add(std::move(wrapper), std::move(hook));
|
||||
return container->as_opaque_hook();
|
||||
}
|
||||
|
||||
emulator_hook* hook_memory_execution(memory_execution_hook_callback callback) override
|
||||
{
|
||||
return this->hook_memory_execution(0, std::numeric_limits<uint64_t>::max(), std::move(callback));
|
||||
}
|
||||
|
||||
emulator_hook* hook_memory_execution(const uint64_t address,
|
||||
memory_execution_hook_callback callback) override
|
||||
{
|
||||
return this->hook_memory_execution(address, 1, std::move(callback));
|
||||
}
|
||||
|
||||
emulator_hook* hook_memory_read(uint64_t address, size_t size,
|
||||
memory_access_hook_callback callback) override
|
||||
{
|
||||
auto read_wrapper = [c = std::move(callback)](uc_engine*, const uc_mem_type type,
|
||||
const uint64_t address, const int size,
|
||||
const uint64_t value) {
|
||||
const auto operation = map_memory_operation(type);
|
||||
if (operation != memory_permission::none && size > 0)
|
||||
{
|
||||
c(address, &value, std::min(static_cast<size_t>(size), sizeof(value)));
|
||||
}
|
||||
};
|
||||
|
||||
function_wrapper<void, uc_engine*, uc_mem_type, uint64_t, int, int64_t> wrapper(
|
||||
std::move(read_wrapper));
|
||||
|
||||
unicorn_hook hook{*this};
|
||||
uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_MEM_READ_AFTER, wrapper.get_function(),
|
||||
wrapper.get_user_data(), address, address + size));
|
||||
|
||||
auto* container = this->create_hook_container();
|
||||
container->add(std::move(wrapper), std::move(hook));
|
||||
return container->as_opaque_hook();
|
||||
}
|
||||
|
||||
emulator_hook* hook_memory_write(uint64_t address, size_t size,
|
||||
memory_access_hook_callback callback) override
|
||||
{
|
||||
auto write_wrapper = [c = std::move(callback)](uc_engine*, const uc_mem_type type,
|
||||
const uint64_t address, const int size,
|
||||
const uint64_t value) {
|
||||
const auto operation = map_memory_operation(type);
|
||||
if (operation != memory_permission::none && size > 0)
|
||||
{
|
||||
c(address, &value, std::min(static_cast<size_t>(size), sizeof(value)));
|
||||
}
|
||||
};
|
||||
|
||||
function_wrapper<void, uc_engine*, uc_mem_type, uint64_t, int, int64_t> wrapper(
|
||||
std::move(write_wrapper));
|
||||
|
||||
unicorn_hook hook{*this};
|
||||
|
||||
uce(uc_hook_add(*this, hook.make_reference(), UC_HOOK_MEM_WRITE, wrapper.get_function(),
|
||||
wrapper.get_user_data(), address, address + size));
|
||||
|
||||
auto* container = this->create_hook_container();
|
||||
container->add(std::move(wrapper), std::move(hook));
|
||||
return container->as_opaque_hook();
|
||||
}
|
||||
|
||||
hook_container* create_hook_container()
|
||||
{
|
||||
auto container = std::make_unique<hook_container>();
|
||||
|
||||
if ((filter & memory_operation::read) != memory_operation::none)
|
||||
{
|
||||
add_read_hook(*this, address, size, *container, shared_callback);
|
||||
}
|
||||
|
||||
if ((filter & memory_operation::write) != memory_operation::none)
|
||||
{
|
||||
add_write_hook(*this, address, size, *container, shared_callback);
|
||||
}
|
||||
|
||||
if ((filter & memory_operation::exec) != memory_operation::none)
|
||||
{
|
||||
add_exec_hook(*this, address, size, *container, shared_callback);
|
||||
}
|
||||
|
||||
auto* result = container->as_opaque_hook();
|
||||
|
||||
auto* ptr = container.get();
|
||||
this->hooks_.push_back(std::move(container));
|
||||
|
||||
return result;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void delete_hook(emulator_hook* hook) override
|
||||
|
||||
@@ -517,9 +517,9 @@ void windows_emulator::setup_hooks()
|
||||
return memory_violation_continuation::resume;
|
||||
});
|
||||
|
||||
this->emu().hook_memory_execution(
|
||||
0, std::numeric_limits<size_t>::max(),
|
||||
[&](const uint64_t address, const size_t, const uint64_t) { this->on_instruction_execution(address); });
|
||||
this->emu().hook_memory_execution([&](const uint64_t address) {
|
||||
this->on_instruction_execution(address); //
|
||||
});
|
||||
}
|
||||
|
||||
void windows_emulator::start(size_t count)
|
||||
|
||||
@@ -8,26 +8,6 @@
|
||||
#include "x64_register_mapping.hpp"
|
||||
#include "x64_target_descriptions.hpp"
|
||||
|
||||
inline memory_operation map_breakpoint_type(const gdb_stub::breakpoint_type type)
|
||||
{
|
||||
using enum gdb_stub::breakpoint_type;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case software:
|
||||
case hardware_exec:
|
||||
return memory_operation::exec;
|
||||
case hardware_read:
|
||||
return memory_permission::read;
|
||||
case hardware_write:
|
||||
return memory_permission::write;
|
||||
case hardware_read_write:
|
||||
return memory_permission::read_write;
|
||||
default:
|
||||
throw std::runtime_error("Bad bp type");
|
||||
}
|
||||
}
|
||||
|
||||
struct breakpoint_key
|
||||
{
|
||||
size_t addr{};
|
||||
@@ -196,11 +176,9 @@ class x64_gdb_stub_handler : public gdb_stub::debugging_handler
|
||||
try
|
||||
{
|
||||
return this->hooks_.access<bool>([&](hook_map& hooks) {
|
||||
hooks[{addr, size, type}] = scoped_hook(
|
||||
*this->emu_, this->emu_->hook_memory_access(addr, size, map_breakpoint_type(type),
|
||||
[this](uint64_t, size_t, uint64_t, memory_operation) {
|
||||
this->on_interrupt(); //
|
||||
}));
|
||||
auto hook_vector = this->create_hook(type, addr, size);
|
||||
|
||||
hooks[{addr, size, type}] = scoped_hook(*this->emu_, std::move(hook_vector));
|
||||
|
||||
return true;
|
||||
});
|
||||
@@ -264,4 +242,64 @@ class x64_gdb_stub_handler : public gdb_stub::debugging_handler
|
||||
|
||||
using hook_map = std::unordered_map<breakpoint_key, scoped_hook>;
|
||||
utils::concurrency::container<hook_map> hooks_{};
|
||||
|
||||
std::vector<emulator_hook*> create_execute_hook(const uint64_t addr, const size_t size)
|
||||
{
|
||||
std::vector<emulator_hook*> hooks{};
|
||||
hooks.reserve(size);
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
auto* hook = this->emu_->hook_memory_execution(addr + i, [this](const uint64_t) {
|
||||
this->on_interrupt(); //
|
||||
});
|
||||
|
||||
hooks.push_back(hook);
|
||||
}
|
||||
|
||||
return hooks;
|
||||
}
|
||||
|
||||
std::vector<emulator_hook*> create_read_hook(const uint64_t addr, const size_t size)
|
||||
{
|
||||
auto* hook = this->emu_->hook_memory_read(addr, size, [this](const uint64_t, const void*, const size_t) {
|
||||
this->on_interrupt(); //
|
||||
});
|
||||
|
||||
return {hook};
|
||||
}
|
||||
|
||||
std::vector<emulator_hook*> create_write_hook(const uint64_t addr, const size_t size)
|
||||
{
|
||||
auto* hook = this->emu_->hook_memory_write(addr, size, [this](const uint64_t, const void*, const size_t) {
|
||||
this->on_interrupt(); //
|
||||
});
|
||||
|
||||
return {hook};
|
||||
}
|
||||
|
||||
std::vector<emulator_hook*> create_hook(const gdb_stub::breakpoint_type type, const uint64_t addr,
|
||||
const size_t size)
|
||||
{
|
||||
using enum gdb_stub::breakpoint_type;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case software:
|
||||
case hardware_exec:
|
||||
return this->create_execute_hook(addr, size);
|
||||
case hardware_read:
|
||||
return this->create_read_hook(addr, size);
|
||||
case hardware_write:
|
||||
return this->create_write_hook(addr, size);
|
||||
case hardware_read_write: {
|
||||
auto hooks1 = this->create_hook(hardware_read, addr, size);
|
||||
auto hooks2 = this->create_hook(hardware_write, addr, size);
|
||||
hooks1.insert(hooks1.end(), hooks2.begin(), hooks2.end());
|
||||
return hooks1;
|
||||
}
|
||||
default:
|
||||
throw std::runtime_error("Bad bp type");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user