Integrate new gdb stub

This commit is contained in:
momo5502
2025-01-17 17:23:05 +01:00
parent 7d62d1e20e
commit 0253592ae9
9 changed files with 58 additions and 207 deletions

View File

@@ -4,7 +4,6 @@
#include <debugging/win_x64_gdb_stub_handler.hpp>
#include "object_watching.hpp"
#include "gdb-stub/gdb_stub.hpp"
namespace
{
@@ -53,7 +52,7 @@ namespace
win_emu.log.print(color::pink, "Waiting for GDB connection on %s...\n", address);
win_x64_gdb_stub_handler handler{win_emu};
run_gdb_stub(handler, "i386:x86-64", gdb_registers.size(), address);
gdb_stub::run_gdb_stub(network::address{"0.0.0.0:28960", AF_INET}, handler);
}
else
{
@@ -182,7 +181,7 @@ namespace
for (int i = 1; i < argc; ++i)
{
args.push_back(argv[i]);
args.emplace_back(argv[i]);
}
return args;
@@ -230,8 +229,6 @@ int main(const int argc, char** argv)
{
try
{
gdb_stub::run_gdb_stub(network::address{"0.0.0.0:28960", AF_INET});
auto args = bundle_arguments(argc, argv);
const auto options = parse_options(args);

View File

@@ -9,7 +9,7 @@ namespace gdb_stub
class async_handler
{
public:
using handler = void(const std::atomic_bool& should_run);
using handler = void(std::atomic_bool& should_run);
using handler_function = std::function<handler>;
async_handler(handler_function handler);

View File

@@ -1,5 +1,6 @@
#pragma once
#include <cstdint>
#include <sstream>
namespace gdb_stub

View File

@@ -3,8 +3,11 @@
#include <network/tcp_server_socket.hpp>
#include "stream_processor.hpp"
#include "async_handler.hpp"
#include "checksum.hpp"
using namespace std::literals;
namespace gdb_stub
{
namespace
@@ -111,10 +114,16 @@ namespace gdb_stub
const auto command = packet.front();
const auto event = handle_command(client, command, packet.substr(1));
(void)event;
}
bool is_interrupt_packet(const std::optional<std::string>& data)
{
return data && data->size() == 1 && data->front() == '\x03';
}
}
bool run_gdb_stub(const network::address& bind_address)
bool run_gdb_stub(const network::address& bind_address, gdb_stub_handler& handler)
{
stream_processor processor{};
@@ -124,6 +133,21 @@ namespace gdb_stub
return false;
}
async_handler async{[&](std::atomic_bool& can_run) {
while (can_run)
{
std::this_thread::sleep_for(10ms);
const auto data = client.receive(1);
if (is_interrupt_packet(data) || !client.is_valid())
{
handler.on_interrupt();
can_run = false;
}
}
}};
client.set_blocking(false);
while (client.is_valid())

View File

@@ -4,7 +4,6 @@
namespace gdb_stub
{
/*
enum class gdb_action : uint8_t
{
none,
@@ -42,7 +41,5 @@ namespace gdb_stub
virtual std::string get_target_description() const = 0;
};
bool run_gdb_stub(gdb_stub_handler& handler, size_t register_count, const network::address& bind_address);
*/
bool run_gdb_stub(const network::address& bind_address);
bool run_gdb_stub(const network::address& bind_address, gdb_stub_handler& handler);
}

View File

@@ -1,136 +0,0 @@
#include "../std_include.hpp"
#include "gdb_stub.hpp"
#include <utils/finally.hpp>
extern "C"
{
#include <gdbstub.h>
}
namespace
{
gdb_action_t map_gdb_action(const gdb_action action)
{
switch (action)
{
case gdb_action::none:
return ACT_NONE;
case gdb_action::resume:
return ACT_RESUME;
case gdb_action::shutdown:
return ACT_SHUTDOWN;
}
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<gdb_stub_handler*>(args);
}
gdb_action_t cont(void* args)
{
return map_gdb_action(get_handler(args).cont());
}
gdb_action_t stepi(void* args)
{
return map_gdb_action(get_handler(args).stepi());
}
int read_reg(void* args, const int regno, size_t* value)
{
return get_handler(args).read_reg(regno, value) ? 0 : 1;
}
int write_reg(void* args, const int regno, const size_t value)
{
return get_handler(args).write_reg(regno, value) ? 0 : 1;
}
int read_mem(void* args, const size_t addr, const size_t len, void* val)
{
return get_handler(args).read_mem(addr, len, val) ? 0 : 1;
}
int write_mem(void* args, const size_t addr, const size_t len, void* val)
{
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, const size_t size)
{
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, const size_t size)
{
return get_handler(args).del_bp(map_breakpoint_type(type), addr, size);
}
void on_interrupt(void* args)
{
get_handler(args).on_interrupt();
}
target_ops get_target_ops()
{
target_ops ops{};
ops.cont = cont;
ops.stepi = stepi;
ops.read_reg = read_reg;
ops.write_reg = write_reg;
ops.read_mem = read_mem;
ops.write_mem = write_mem;
ops.set_bp = set_bp;
ops.del_bp = del_bp;
ops.on_interrupt = on_interrupt;
return ops;
}
}
bool run_gdb_stub(gdb_stub_handler& handler, std::string target_description, const size_t register_count,
std::string bind_address)
{
const arch_info_t info{
target_description.data(),
static_cast<int>(register_count),
sizeof(uint64_t),
};
auto ops = get_target_ops();
gdbstub_t stub{};
if (!gdbstub_init(&stub, &ops, info, bind_address.data()))
{
return false;
}
const auto _ = utils::finally([&] { gdbstub_close(&stub); });
return gdbstub_run(&stub, &handler);
}

View File

@@ -1,39 +0,0 @@
#pragma once
enum class gdb_action : uint8_t
{
none,
resume,
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;
virtual gdb_action cont() = 0;
virtual gdb_action stepi() = 0;
virtual bool read_reg(int regno, size_t* value) = 0;
virtual bool write_reg(int regno, size_t value) = 0;
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(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;
};
bool run_gdb_stub(gdb_stub_handler& handler, std::string target_description, size_t register_count,
std::string bind_address);

View File

@@ -12,7 +12,7 @@ class win_x64_gdb_stub_handler : public x64_gdb_stub_handler
{
}
gdb_action cont() override
gdb_stub::gdb_action cont() override
{
try
{
@@ -20,13 +20,13 @@ class win_x64_gdb_stub_handler : public x64_gdb_stub_handler
}
catch (const std::exception& e)
{
puts(e.what());
this->win_emu_->log.error("%s\n", e.what());
}
return gdb_action::resume;
return gdb_stub::gdb_action::resume;
}
gdb_action stepi() override
gdb_stub::gdb_action stepi() override
{
try
{
@@ -34,10 +34,15 @@ class win_x64_gdb_stub_handler : public x64_gdb_stub_handler
}
catch (const std::exception& e)
{
puts(e.what());
this->win_emu_->log.error("%s\n", e.what());
}
return gdb_action::resume;
return gdb_stub::gdb_action::resume;
}
std::string get_target_description() const override
{
return "i386:x86-64";
}
private:

View File

@@ -1,8 +1,8 @@
#pragma once
#include <x64_emulator.hpp>
#include "gdb_stub.hpp"
#include "scoped_hook.hpp"
#include <utils/concurrency.hpp>
#include <gdb-stub/gdb_stub.hpp>
inline std::vector gdb_registers{
x64_register::rax, x64_register::rbx, x64_register::rcx, x64_register::rdx, x64_register::rsi, x64_register::rdi,
@@ -16,18 +16,20 @@ inline std::vector gdb_registers{
x64_register::gs,*/
};
inline memory_operation map_breakpoint_type(const breakpoint_type type)
inline memory_operation map_breakpoint_type(const gdb_stub::breakpoint_type type)
{
using enum gdb_stub::breakpoint_type;
switch (type)
{
case breakpoint_type::software:
case breakpoint_type::hardware_exec:
case software:
case hardware_exec:
return memory_operation::exec;
case breakpoint_type::hardware_read:
case hardware_read:
return memory_permission::read;
case breakpoint_type::hardware_write:
case hardware_write:
return memory_permission::write;
case breakpoint_type::hardware_read_write:
case hardware_read_write:
return memory_permission::read_write;
default:
throw std::runtime_error("Bad bp type");
@@ -38,7 +40,7 @@ struct breakpoint_key
{
size_t addr{};
size_t size{};
breakpoint_type type{};
gdb_stub::breakpoint_type type{};
bool operator==(const breakpoint_key& other) const
{
@@ -56,7 +58,7 @@ struct std::hash<breakpoint_key>
}
};
class x64_gdb_stub_handler : public gdb_stub_handler
class x64_gdb_stub_handler : public gdb_stub::gdb_stub_handler
{
public:
x64_gdb_stub_handler(x64_emulator& emu)
@@ -66,7 +68,7 @@ class x64_gdb_stub_handler : public gdb_stub_handler
~x64_gdb_stub_handler() override = default;
gdb_action cont() override
gdb_stub::gdb_action cont() override
{
try
{
@@ -77,10 +79,10 @@ class x64_gdb_stub_handler : public gdb_stub_handler
puts(e.what());
}
return gdb_action::resume;
return gdb_stub::gdb_action::resume;
}
gdb_action stepi() override
gdb_stub::gdb_action stepi() override
{
try
{
@@ -91,7 +93,7 @@ class x64_gdb_stub_handler : public gdb_stub_handler
puts(e.what());
}
return gdb_action::resume;
return gdb_stub::gdb_action::resume;
}
bool read_reg(const int regno, size_t* value) override
@@ -150,7 +152,7 @@ class x64_gdb_stub_handler : public gdb_stub_handler
}
}
bool set_bp(const breakpoint_type type, const size_t addr, const size_t size) override
bool set_bp(const gdb_stub::breakpoint_type type, const size_t addr, const size_t size) override
{
try
{
@@ -170,7 +172,7 @@ class x64_gdb_stub_handler : public gdb_stub_handler
}
}
bool del_bp(const breakpoint_type type, const size_t addr, const size_t size) override
bool del_bp(const gdb_stub::breakpoint_type type, const size_t addr, const size_t size) override
{
try
{