mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-11 16:46:16 +00:00
Minor interface refactorings (#62)
This commit is contained in:
22
src/emulator/cpu_interface.hpp
Normal file
22
src/emulator/cpu_interface.hpp
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
struct cpu_interface
|
||||||
|
{
|
||||||
|
virtual ~cpu_interface() = default;
|
||||||
|
|
||||||
|
virtual void start(uint64_t start, uint64_t end = 0, std::chrono::nanoseconds timeout = {}, size_t count = 0) = 0;
|
||||||
|
virtual void stop() = 0;
|
||||||
|
|
||||||
|
virtual void read_raw_register(int reg, void* value, size_t size) = 0;
|
||||||
|
virtual void write_raw_register(int reg, const void* value, size_t size) = 0;
|
||||||
|
|
||||||
|
virtual std::vector<std::byte> save_registers() = 0;
|
||||||
|
virtual void restore_registers(const std::vector<std::byte>& register_data) = 0;
|
||||||
|
|
||||||
|
virtual bool has_violation() const = 0;
|
||||||
|
};
|
||||||
@@ -1,56 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <chrono>
|
|
||||||
#include <functional>
|
|
||||||
#include <cassert>
|
|
||||||
|
|
||||||
|
#include "cpu_interface.hpp"
|
||||||
|
#include "hook_interface.hpp"
|
||||||
#include "memory_manager.hpp"
|
#include "memory_manager.hpp"
|
||||||
|
|
||||||
struct emulator_hook;
|
class emulator : public cpu_interface, public memory_manager, public hook_interface
|
||||||
|
|
||||||
using memory_operation = memory_permission;
|
|
||||||
|
|
||||||
enum class instruction_hook_continuation : bool
|
|
||||||
{
|
|
||||||
run_instruction = false,
|
|
||||||
skip_instruction = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class memory_violation_continuation : bool
|
|
||||||
{
|
|
||||||
stop = false,
|
|
||||||
resume = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class memory_violation_type : uint8_t
|
|
||||||
{
|
|
||||||
unmapped,
|
|
||||||
protection,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct basic_block
|
|
||||||
{
|
|
||||||
uint64_t address;
|
|
||||||
size_t instruction_count;
|
|
||||||
size_t size;
|
|
||||||
};
|
|
||||||
|
|
||||||
using edge_generation_hook_callback =
|
|
||||||
std::function<void(const basic_block& current_block, const basic_block& previous_block)>;
|
|
||||||
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_violation_hook_callback = std::function<memory_violation_continuation(
|
|
||||||
uint64_t address, size_t size, memory_operation operation, memory_violation_type type)>;
|
|
||||||
|
|
||||||
class emulator : public memory_manager
|
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
emulator() = default;
|
emulator() = default;
|
||||||
|
~emulator() override = default;
|
||||||
|
|
||||||
emulator(const emulator&) = delete;
|
emulator(const emulator&) = delete;
|
||||||
emulator& operator=(const emulator&) = delete;
|
emulator& operator=(const emulator&) = delete;
|
||||||
@@ -58,50 +16,6 @@ class emulator : public memory_manager
|
|||||||
emulator(emulator&&) = delete;
|
emulator(emulator&&) = delete;
|
||||||
emulator& operator=(emulator&&) = delete;
|
emulator& operator=(emulator&&) = delete;
|
||||||
|
|
||||||
virtual void start(uint64_t start, uint64_t end = 0, std::chrono::nanoseconds timeout = {}, size_t count = 0) = 0;
|
|
||||||
virtual void stop() = 0;
|
|
||||||
|
|
||||||
virtual void read_raw_register(int reg, void* value, size_t size) = 0;
|
|
||||||
virtual void write_raw_register(int reg, const void* value, size_t size) = 0;
|
|
||||||
|
|
||||||
virtual std::vector<std::byte> save_registers() = 0;
|
|
||||||
virtual void restore_registers(const std::vector<std::byte>& register_data) = 0;
|
|
||||||
|
|
||||||
virtual emulator_hook* hook_memory_violation(uint64_t address, size_t size,
|
|
||||||
memory_violation_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_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_violation(memory_violation_hook_callback callback)
|
|
||||||
{
|
|
||||||
return this->hook_memory_violation(0, std::numeric_limits<size_t>::max(), std::move(callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
void serialize(utils::buffer_serializer& buffer) const
|
void serialize(utils::buffer_serializer& buffer) const
|
||||||
{
|
{
|
||||||
this->perform_serialization(buffer, false);
|
this->perform_serialization(buffer, false);
|
||||||
@@ -130,21 +44,9 @@ class emulator : public memory_manager
|
|||||||
this->perform_deserialization(deserializer, true);
|
this->perform_deserialization(deserializer, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool has_violation() const = 0;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::byte> last_snapshot_data_{};
|
std::vector<std::byte> last_snapshot_data_{};
|
||||||
|
|
||||||
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); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void perform_serialization(utils::buffer_serializer& buffer, const bool is_snapshot) const
|
void perform_serialization(utils::buffer_serializer& buffer, const bool is_snapshot) const
|
||||||
{
|
{
|
||||||
this->serialize_state(buffer, is_snapshot);
|
this->serialize_state(buffer, is_snapshot);
|
||||||
|
|||||||
101
src/emulator/hook_interface.hpp
Normal file
101
src/emulator/hook_interface.hpp
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "memory_permission.hpp"
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cassert>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
struct emulator_hook;
|
||||||
|
|
||||||
|
using memory_operation = memory_permission;
|
||||||
|
|
||||||
|
enum class instruction_hook_continuation : bool
|
||||||
|
{
|
||||||
|
run_instruction = false,
|
||||||
|
skip_instruction = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class memory_violation_continuation : bool
|
||||||
|
{
|
||||||
|
stop = false,
|
||||||
|
resume = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class memory_violation_type : uint8_t
|
||||||
|
{
|
||||||
|
unmapped,
|
||||||
|
protection,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct basic_block
|
||||||
|
{
|
||||||
|
uint64_t address;
|
||||||
|
size_t instruction_count;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
using edge_generation_hook_callback =
|
||||||
|
std::function<void(const basic_block& current_block, const basic_block& previous_block)>;
|
||||||
|
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_violation_hook_callback = std::function<memory_violation_continuation(
|
||||||
|
uint64_t address, size_t size, memory_operation operation, memory_violation_type type)>;
|
||||||
|
|
||||||
|
class hook_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~hook_interface() = default;
|
||||||
|
|
||||||
|
virtual emulator_hook* hook_memory_violation(uint64_t address, size_t size,
|
||||||
|
memory_violation_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_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_violation(memory_violation_hook_callback callback)
|
||||||
|
{
|
||||||
|
return this->hook_memory_violation(0, std::numeric_limits<size_t>::max(), std::move(callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
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); });
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -20,15 +20,6 @@ namespace utils
|
|||||||
{ a.deserialize(deserializer) } -> std::same_as<void>;
|
{ a.deserialize(deserializer) } -> std::same_as<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Use concept instead, to prevent overhead of virtual function calls
|
|
||||||
struct serializable
|
|
||||||
{
|
|
||||||
virtual ~serializable() = default;
|
|
||||||
virtual void serialize(buffer_serializer& buffer) const = 0;
|
|
||||||
virtual void deserialize(buffer_deserializer& buffer) = 0;
|
|
||||||
};
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace detail
|
namespace detail
|
||||||
{
|
{
|
||||||
template <typename, typename = void>
|
template <typename, typename = void>
|
||||||
@@ -66,7 +57,7 @@ namespace utils
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
template <typename T>
|
template <typename T>
|
||||||
buffer_deserializer(const std::span<T> buffer, bool no_debugging = false)
|
buffer_deserializer(const std::span<T> buffer, const bool no_debugging = false)
|
||||||
: no_debugging_(no_debugging),
|
: no_debugging_(no_debugging),
|
||||||
buffer_(reinterpret_cast<const std::byte*>(buffer.data()), buffer.size() * sizeof(T))
|
buffer_(reinterpret_cast<const std::byte*>(buffer.data()), buffer.size() * sizeof(T))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "std_include.hpp"
|
#include "std_include.hpp"
|
||||||
#include "windows_emulator.hpp"
|
#include "windows_emulator.hpp"
|
||||||
|
|
||||||
|
#include "address_utils.hpp"
|
||||||
#include "context_frame.hpp"
|
#include "context_frame.hpp"
|
||||||
|
|
||||||
#include <unicorn_x64_emulator.hpp>
|
#include <unicorn_x64_emulator.hpp>
|
||||||
|
|||||||
Reference in New Issue
Block a user