From 405a53ccef48c101197713d309f97d02a28a9ea0 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 1 Sep 2024 20:10:10 +0200 Subject: [PATCH] Support hardware breakpoints --- deps/mini-gdbstub | 2 +- src/windows_emulator/gdb_stub.cpp | 33 +++++++++++----- src/windows_emulator/gdb_stub.hpp | 13 +++++- src/windows_emulator/main.cpp | 66 +++++++++++++++++++++++++------ 4 files changed, 89 insertions(+), 25 deletions(-) diff --git a/deps/mini-gdbstub b/deps/mini-gdbstub index 982172eb..4628d9df 160000 --- a/deps/mini-gdbstub +++ b/deps/mini-gdbstub @@ -1 +1 @@ -Subproject commit 982172ebf4cb80f84076e32f903a3a082d52b5e8 +Subproject commit 4628d9dfd2af21d95fc0f64ea3982ea3fdf3f72e diff --git a/src/windows_emulator/gdb_stub.cpp b/src/windows_emulator/gdb_stub.cpp index 388ed646..9af16516 100644 --- a/src/windows_emulator/gdb_stub.cpp +++ b/src/windows_emulator/gdb_stub.cpp @@ -24,6 +24,25 @@ namespace throw std::runtime_error("Bad action"); } + breakpoint_type map_breakpoint_type(const bp_type_t type) + { + switch (type) + { + case BP_SOFTWARE: + return breakpoint_type::software; + case BP_HARDWARE_EXEC: + return breakpoint_type::hardware_exec; + case BP_HARDWARE_WRITE: + return breakpoint_type::hardware_write; + case BP_HARDWARE_READ: + return breakpoint_type::hardware_read; + case BP_HARDWARE_READ_WRITE: + return breakpoint_type::hardware_read_write; + } + + throw std::runtime_error("Bad breakpoint type"); + } + gdb_stub_handler& get_handler(void* args) { return *static_cast(args); @@ -59,20 +78,14 @@ namespace return get_handler(args).write_mem(addr, len, val) ? 0 : 1; } - bool set_bp(void* args, const size_t addr, const bp_type_t type) + bool set_bp(void* args, const size_t addr, const bp_type_t type, const size_t size) { - (void)type; - assert(type == BP_SOFTWARE); - - return get_handler(args).set_bp(addr); + return get_handler(args).set_bp(map_breakpoint_type(type), addr, size); } - bool del_bp(void* args, const size_t addr, const bp_type_t type) + bool del_bp(void* args, const size_t addr, const bp_type_t type, const size_t size) { - (void)type; - assert(type == BP_SOFTWARE); - - return get_handler(args).del_bp(addr); + return get_handler(args).del_bp(map_breakpoint_type(type), addr, size); } void on_interrupt(void* args) diff --git a/src/windows_emulator/gdb_stub.hpp b/src/windows_emulator/gdb_stub.hpp index 7a4ed4d5..4248737e 100644 --- a/src/windows_emulator/gdb_stub.hpp +++ b/src/windows_emulator/gdb_stub.hpp @@ -7,6 +7,15 @@ enum class gdb_action : uint8_t shutdown, }; +enum class breakpoint_type : uint8_t +{ + software, + hardware_exec, + hardware_write, + hardware_read, + hardware_read_write, +}; + struct gdb_stub_handler { virtual ~gdb_stub_handler() = default; @@ -20,8 +29,8 @@ struct gdb_stub_handler virtual bool read_mem(size_t addr, size_t len, void* val) = 0; virtual bool write_mem(size_t addr, size_t len, void* val) = 0; - virtual bool set_bp(size_t addr) = 0; - virtual bool del_bp(size_t addr) = 0; + virtual bool set_bp(breakpoint_type type, size_t addr, size_t size) = 0; + virtual bool del_bp(breakpoint_type type, size_t addr, size_t size) = 0; virtual void on_interrupt() = 0; }; diff --git a/src/windows_emulator/main.cpp b/src/windows_emulator/main.cpp index 985e834a..c52070bd 100644 --- a/src/windows_emulator/main.cpp +++ b/src/windows_emulator/main.cpp @@ -21,11 +21,34 @@ #define IA32_GS_BASE_MSR 0xC0000101 #define STACK_SIZE 0x40000 -#define STACK_ADDRESS (0x800000000000 - STACK_SIZE) - +#define STACK_ADDRESS (0x80000000000 - STACK_SIZE) #define KUSD_ADDRESS 0x7ffe0000 -bool use_gdb = false; +bool use_gdb = true; + +struct breakpoint_key +{ + size_t addr{}; + size_t size{}; + breakpoint_type type{}; + + bool operator==(const breakpoint_key& other) const + { + return this->addr == other.addr && this->size == other.size && this->type == other.type; + } +}; + +template <> +struct std::hash +{ + std::size_t operator()(const breakpoint_key& k) const noexcept + { + return ((std::hash()(k.addr) + ^ (std::hash()(k.size) << 1)) >> 1) + ^ (std::hash()(static_cast(k.type)) << 1); + } +}; + namespace { @@ -352,6 +375,24 @@ namespace {gdb_registers::eflags, x64_register::rflags}, }; + memory_operation map_breakpoint_type(const breakpoint_type type) + { + switch (type) + { + case breakpoint_type::software: + case breakpoint_type::hardware_exec: + return memory_operation::exec; + case breakpoint_type::hardware_read: + return memory_permission::read; + case breakpoint_type::hardware_write: + return memory_permission::write; + case breakpoint_type::hardware_read_write: + return memory_permission::read_write; + default: + throw std::runtime_error("Bad bp type"); + } + } + class scoped_emulator_hook { public: @@ -499,15 +540,16 @@ namespace } } - bool set_bp(const size_t addr) override + bool set_bp(const breakpoint_type type, const size_t addr, const size_t size) override { try { - this->hooks_[addr] = scoped_emulator_hook(*this->emu_, this->emu_->hook_memory_execution( - addr, 1, [this](uint64_t, size_t) - { - this->on_interrupt(); - })); + this->hooks_[{addr, size, type}] = scoped_emulator_hook(*this->emu_, this->emu_->hook_memory_access( + addr, size, map_breakpoint_type(type), + [this](uint64_t, size_t, memory_operation) + { + this->on_interrupt(); + })); return true; } @@ -517,11 +559,11 @@ namespace } } - bool del_bp(const size_t addr) override + bool del_bp(const breakpoint_type type, const size_t addr, const size_t size) override { try { - const auto entry = this->hooks_.find(addr); + const auto entry = this->hooks_.find({addr, size, type}); if (entry == this->hooks_.end()) { return false; @@ -544,7 +586,7 @@ namespace private: x64_emulator* emu_{}; - std::unordered_map hooks_{}; + std::unordered_map hooks_{}; }; uint64_t find_exported_function(const std::vector& exports, const std::string_view name)