Prepare custom gdb-stub implementation

This commit is contained in:
momo5502
2025-01-12 11:39:20 +01:00
parent e28317ea8f
commit 8adc73de71
6 changed files with 204 additions and 0 deletions

View File

@@ -1,5 +1,6 @@
add_subdirectory(common)
add_subdirectory(emulator)
add_subdirectory(gdb-stub)
add_subdirectory(unicorn-emulator)
add_subdirectory(windows-emulator)
if (NOT MOMO_BUILD_AS_LIBRARY)

View File

@@ -15,6 +15,7 @@ target_precompile_headers(analyzer PRIVATE std_include.hpp)
target_link_libraries(analyzer PRIVATE
reflect
windows-emulator
gdb-stub
)
set_property(GLOBAL PROPERTY VS_STARTUP_PROJECT analyzer)

View File

@@ -4,6 +4,7 @@
#include <debugging/win_x64_gdb_stub_handler.hpp>
#include "object_watching.hpp"
#include "gdb-stub/gdb_stub.hpp"
namespace
{
@@ -229,6 +230,8 @@ 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

@@ -0,0 +1,21 @@
file(GLOB_RECURSE SRC_FILES CONFIGURE_DEPENDS
*.cpp
*.hpp
*.rc
)
list(SORT SRC_FILES)
add_library(gdb-stub ${SRC_FILES})
momo_assign_source_group(${SRC_FILES})
target_link_libraries(gdb-stub PRIVATE
common
)
target_include_directories(gdb-stub INTERFACE
"${CMAKE_CURRENT_LIST_DIR}"
)
momo_strip_target(gdb-stub)

130
src/gdb-stub/gdb_stub.cpp Normal file
View File

@@ -0,0 +1,130 @@
#include "gdb_stub.hpp"
#include <cassert>
#include <queue>
#include <network/tcp_server_socket.hpp>
namespace gdb_stub
{
namespace
{
constexpr size_t CHECKSUM_SIZE = 2;
uint8_t compute_checksum(const std::string_view data)
{
uint8_t csum = 0;
for (const auto c : data)
{
csum += static_cast<uint8_t>(c);
}
return csum;
}
network::tcp_client_socket accept_client(const network::address& bind_address)
{
network::tcp_server_socket server{bind_address.get_family()};
if (!server.bind(bind_address))
{
return false;
}
return server.accept();
}
struct packet_queue
{
std::string buffer{};
std::queue<std::string> packets{};
void enqueue(const std::string& data)
{
buffer.append(data);
this->process();
}
void process()
{
while (true)
{
this->trim_start();
const auto end = this->buffer.find_first_of('#');
if (end == std::string::npos)
{
break;
}
const auto packet_size = end + CHECKSUM_SIZE + 1;
if (packet_size > this->buffer.size())
{
break;
}
auto packet = this->buffer.substr(0, packet_size);
this->buffer.erase(0, packet_size);
this->enqueue_packet(std::move(packet));
}
}
void enqueue_packet(std::string packet)
{
constexpr auto END_BYTES = CHECKSUM_SIZE + 1;
if (packet.size() < (END_BYTES + 1) //
|| packet.front() != '$' //
|| packet[packet.size() - END_BYTES] != '#')
{
return;
}
const auto checksum = strtoul(packet.c_str() + packet.size() - CHECKSUM_SIZE, nullptr, 16);
assert((checksum & 0xFF) == checksum);
packet.erase(packet.begin());
packet.erase(packet.size() - END_BYTES, END_BYTES);
const auto computed_checksum = compute_checksum(packet);
if (computed_checksum == checksum)
{
this->packets.push(std::move(packet));
}
}
void trim_start()
{
while (!this->buffer.empty() && this->buffer.front() != '$')
{
buffer.erase(buffer.begin());
}
}
};
}
bool run_gdb_stub(const network::address& bind_address)
{
const auto client = accept_client(bind_address);
if (!client)
{
return false;
}
packet_queue queue{};
while (true)
{
std::string packet{};
if (!client.receive(packet))
{
break;
}
queue.enqueue(packet);
}
return true;
}
}

48
src/gdb-stub/gdb_stub.hpp Normal file
View File

@@ -0,0 +1,48 @@
#pragma once
#include <cstdint>
#include <network/address.hpp>
namespace gdb_stub
{
/*
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;
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);
}