mirror of
https://github.com/momo5502/emulator.git
synced 2026-01-21 04:33:56 +00:00
Prepare custom gdb-stub implementation
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
21
src/gdb-stub/CMakeLists.txt
Normal file
21
src/gdb-stub/CMakeLists.txt
Normal 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
130
src/gdb-stub/gdb_stub.cpp
Normal 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
48
src/gdb-stub/gdb_stub.hpp
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user