diff --git a/src/gdb-stub/connection_handler.cpp b/src/gdb-stub/connection_handler.cpp index 3738456b..9ef40d21 100644 --- a/src/gdb-stub/connection_handler.cpp +++ b/src/gdb-stub/connection_handler.cpp @@ -47,7 +47,7 @@ namespace gdb_stub return std::nullopt; } - void connection_handler::send_packet(const std::string_view data) const + void connection_handler::send_reply(const std::string_view data) const { const auto checksum = utils::string::to_hex_string(compute_checksum(data)); this->send_raw_data("$" + std::string(data) + "#" + checksum); diff --git a/src/gdb-stub/connection_handler.hpp b/src/gdb-stub/connection_handler.hpp index bd1f13af..afd326ca 100644 --- a/src/gdb-stub/connection_handler.hpp +++ b/src/gdb-stub/connection_handler.hpp @@ -11,7 +11,7 @@ namespace gdb_stub std::optional get_packet(); - void send_packet(std::string_view data) const; + void send_reply(std::string_view data) const; void send_raw_data(std::string_view data) const; void close() const; diff --git a/src/gdb-stub/gdb_stub.cpp b/src/gdb-stub/gdb_stub.cpp index 676ae1d6..2dfa44e2 100644 --- a/src/gdb-stub/gdb_stub.cpp +++ b/src/gdb-stub/gdb_stub.cpp @@ -6,12 +6,20 @@ #include "async_handler.hpp" #include "connection_handler.hpp" +#include +#include + using namespace std::literals; namespace gdb_stub { namespace { + void rt_assert(const bool condition) + { + assert(condition); + } + network::tcp_client_socket accept_client(const network::address& bind_address) { network::tcp_server_socket server{bind_address.get_family()}; @@ -23,7 +31,7 @@ namespace gdb_stub return server.accept(); } - void process_query(const connection_handler& connection, const std::string_view payload) + std::pair split_colon(const std::string_view payload) { auto name = payload; std::string_view args{}; @@ -36,25 +44,50 @@ namespace gdb_stub args = payload.substr(separator + 1); } - if (name == "Supported") + return {name, args}; + } + + void process_xfer(const connection_handler& connection, gdb_stub_handler& handler, + const std::string_view payload) + { + auto [name, args] = split_colon(payload); + + if (name == "features") { - connection.send_packet("PacketSize=1024;qXfer:features:read+"); - } - else if (name == "Attached") - { - connection.send_packet("1"); - } - else if (name == "Xfer") - { - // process_xfer(gdbstub, args); - } - else if (name == "Symbol") - { - connection.send_packet("OK"); + connection.send_reply("l" // + + handler.get_target_description() // + + "%s"); } else { - connection.send_packet({}); + connection.send_reply({}); + } + } + + void process_query(const connection_handler& connection, gdb_stub_handler& handler, + const std::string_view payload) + { + auto [name, args] = split_colon(payload); + + if (name == "Supported") + { + connection.send_reply("PacketSize=1024;qXfer:features:read+"); + } + else if (name == "Attached") + { + connection.send_reply("1"); + } + else if (name == "Xfer") + { + process_xfer(connection, handler, args); + } + else if (name == "Symbol") + { + connection.send_reply("OK"); + } + else + { + connection.send_reply({}); } } @@ -66,8 +99,54 @@ namespace gdb_stub } } - void read_registers() + breakpoint_type translate_breakpoint_type(const uint32_t type) { + if (type >= static_cast(breakpoint_type::END)) + { + return breakpoint_type::software; + } + + return static_cast(type); + } + + bool change_breakpoint(gdb_stub_handler& handler, const bool set, const breakpoint_type type, + const uint64_t address, const size_t size) + { + if (set) + { + return handler.set_breakpoint(type, address, size); + } + + return handler.delete_breakpoint(type, address, size); + } + + void handle_breakpoint(const connection_handler& connection, gdb_stub_handler& handler, const std::string& data, + const bool set) + { + uint32_t type{}; + uint64_t addr{}; + size_t kind{}; + rt_assert(sscanf(data.c_str(), "%x,%" PRIX64 ",%zx", &type, &addr, &kind) == 3); + + const auto res = change_breakpoint(handler, set, translate_breakpoint_type(type), addr, kind); + connection.send_reply(res ? "OK" : "E01"); + } + + void handle_v_packet(const connection_handler& connection, const std::string_view data) + { + auto [name, args] = split_colon(data); + + if (name == "Cont?") + { + // IDA pro gets confused if the reply arrives too early :( + std::this_thread::sleep_for(1s); + + connection.send_reply("vCont;s;c;"); + } + else + { + connection.send_reply({}); + } } void handle_command(const connection_handler& connection, async_handler& async, gdb_stub_handler& handler, @@ -86,13 +165,36 @@ namespace gdb_stub break; case 'q': - process_query(connection, data); + process_query(connection, handler, data); break; - case 'g': + case 'D': + connection.close(); + break; + case 'z': + case 'Z': + handle_breakpoint(connection, handler, std::string(data), command == 'Z'); + break; + + case '?': + connection.send_reply("S05"); + break; + + case 'v': + handle_v_packet(connection, data); + break; + + // TODO + case 'g': + case 'm': + case 'p': + case 'G': + case 'M': + case 'P': + case 'X': default: - connection.send_packet({}); + connection.send_reply({}); break; } } diff --git a/src/gdb-stub/gdb_stub.hpp b/src/gdb-stub/gdb_stub.hpp index c1e946df..40ce53d6 100644 --- a/src/gdb-stub/gdb_stub.hpp +++ b/src/gdb-stub/gdb_stub.hpp @@ -13,11 +13,12 @@ namespace gdb_stub enum class breakpoint_type : uint8_t { - software, - hardware_exec, - hardware_write, - hardware_read, - hardware_read_write, + software = 0, + hardware_exec = 1, + hardware_write = 2, + hardware_read = 3, + hardware_read_write = 4, + END, }; struct gdb_stub_handler @@ -33,11 +34,11 @@ namespace gdb_stub virtual bool read_register(size_t reg, void* data, size_t max_length) = 0; virtual bool write_register(size_t reg, const void* data, size_t size) = 0; - virtual bool read_memory(size_t address, void* data, size_t length) = 0; - virtual bool write_memory(size_t address, const void* data, size_t length) = 0; + virtual bool read_memory(uint64_t address, void* data, size_t length) = 0; + virtual bool write_memory(uint64_t address, const void* data, size_t length) = 0; - virtual bool set_breakpoint(breakpoint_type type, size_t address, size_t size) = 0; - virtual bool delete_breakpoint(breakpoint_type type, size_t address, size_t size) = 0; + virtual bool set_breakpoint(breakpoint_type type, uint64_t address, size_t size) = 0; + virtual bool delete_breakpoint(breakpoint_type type, uint64_t address, size_t size) = 0; virtual void on_interrupt() = 0;