duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

gdb_server.cpp (14170B)


      1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> and contributors.
      2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
      3 
      4 #include "gdb_server.h"
      5 #include "bus.h"
      6 #include "cpu_core.h"
      7 #include "cpu_core_private.h"
      8 #include "system.h"
      9 
     10 #include "common/assert.h"
     11 #include "common/log.h"
     12 #include "common/small_string.h"
     13 #include "common/string_util.h"
     14 
     15 #include "util/sockets.h"
     16 
     17 #include <functional>
     18 #include <iomanip>
     19 #include <map>
     20 #include <optional>
     21 #include <sstream>
     22 #include <string>
     23 
     24 Log_SetChannel(GDBProtocol);
     25 
     26 namespace GDBProtocol {
     27 static bool IsPacketInterrupt(std::string_view data);
     28 static bool IsPacketContinue(std::string_view data);
     29 
     30 static bool IsPacketComplete(std::string_view data);
     31 static std::string ProcessPacket(std::string_view data);
     32 } // namespace GDBProtocol
     33 
     34 namespace GDBProtocol {
     35 
     36 static u8* GetMemoryPointer(PhysicalMemoryAddress address, u32 length)
     37 {
     38   auto region = Bus::GetMemoryRegionForAddress(address);
     39   if (region)
     40   {
     41     u8* data = GetMemoryRegionPointer(*region);
     42     if (data && (address + length <= GetMemoryRegionEnd(*region)))
     43     {
     44       return data + (address - GetMemoryRegionStart(*region));
     45     }
     46   }
     47 
     48   return nullptr;
     49 }
     50 
     51 static u8 ComputeChecksum(std::string_view str)
     52 {
     53   u8 checksum = 0;
     54   for (char c : str)
     55   {
     56     checksum = (checksum + c) % 256;
     57   }
     58   return checksum;
     59 }
     60 
     61 static std::optional<std::string_view> DeserializePacket(std::string_view in)
     62 {
     63   if ((in.size() < 4) || (in[0] != '$') || (in[in.size() - 3] != '#'))
     64   {
     65     return std::nullopt;
     66   }
     67   std::string_view data = in.substr(1, in.size() - 4);
     68 
     69   u8 packetChecksum = StringUtil::FromChars<u8>(in.substr(in.size() - 2, 2), 16).value_or(0);
     70   u8 computedChecksum = ComputeChecksum(data);
     71 
     72   if (packetChecksum == computedChecksum)
     73   {
     74     return {data};
     75   }
     76   else
     77   {
     78     return std::nullopt;
     79   }
     80 }
     81 
     82 static std::string SerializePacket(std::string_view in)
     83 {
     84   std::stringstream ss;
     85   ss << '$' << in << '#' << TinyString::from_format("{:02x}", ComputeChecksum(in));
     86   return ss.str();
     87 }
     88 
     89 /// List of GDB remote protocol registers for MIPS III (excluding FP).
     90 static const std::array<u32*, 38> REGISTERS{
     91   &CPU::g_state.regs.r[0],
     92   &CPU::g_state.regs.r[1],
     93   &CPU::g_state.regs.r[2],
     94   &CPU::g_state.regs.r[3],
     95   &CPU::g_state.regs.r[4],
     96   &CPU::g_state.regs.r[5],
     97   &CPU::g_state.regs.r[6],
     98   &CPU::g_state.regs.r[7],
     99   &CPU::g_state.regs.r[8],
    100   &CPU::g_state.regs.r[9],
    101   &CPU::g_state.regs.r[10],
    102   &CPU::g_state.regs.r[11],
    103   &CPU::g_state.regs.r[12],
    104   &CPU::g_state.regs.r[13],
    105   &CPU::g_state.regs.r[14],
    106   &CPU::g_state.regs.r[15],
    107   &CPU::g_state.regs.r[16],
    108   &CPU::g_state.regs.r[17],
    109   &CPU::g_state.regs.r[18],
    110   &CPU::g_state.regs.r[19],
    111   &CPU::g_state.regs.r[20],
    112   &CPU::g_state.regs.r[21],
    113   &CPU::g_state.regs.r[22],
    114   &CPU::g_state.regs.r[23],
    115   &CPU::g_state.regs.r[24],
    116   &CPU::g_state.regs.r[25],
    117   &CPU::g_state.regs.r[26],
    118   &CPU::g_state.regs.r[27],
    119   &CPU::g_state.regs.r[28],
    120   &CPU::g_state.regs.r[29],
    121   &CPU::g_state.regs.r[30],
    122   &CPU::g_state.regs.r[31],
    123 
    124   &CPU::g_state.cop0_regs.sr.bits,
    125   &CPU::g_state.regs.lo,
    126   &CPU::g_state.regs.hi,
    127   &CPU::g_state.cop0_regs.BadVaddr,
    128   &CPU::g_state.cop0_regs.cause.bits,
    129   &CPU::g_state.pc,
    130 };
    131 
    132 /// Number of registers in GDB remote protocol for MIPS III.
    133 constexpr int NUM_GDB_REGISTERS = 73;
    134 
    135 /// Get stop reason.
    136 static std::optional<std::string> Cmd$_questionMark(std::string_view data)
    137 {
    138   return {"S02"};
    139 }
    140 
    141 /// Get general registers.
    142 static std::optional<std::string> Cmd$g(std::string_view data)
    143 {
    144   std::stringstream ss;
    145 
    146   for (u32* reg : REGISTERS)
    147   {
    148     // Data is in host order (little endian).
    149     ss << StringUtil::EncodeHex(reinterpret_cast<u8*>(reg), 4);
    150   }
    151 
    152   // Pad with dummy data (FP registers stuff).
    153   for (int i = 0; i < NUM_GDB_REGISTERS - static_cast<int>(REGISTERS.size()); i++)
    154   {
    155     ss << "00000000";
    156   }
    157 
    158   return {ss.str()};
    159 }
    160 
    161 /// Set general registers.
    162 static std::optional<std::string> Cmd$G(std::string_view data)
    163 {
    164   if (data.size() == NUM_GDB_REGISTERS * 8)
    165   {
    166     int offset = 0;
    167 
    168     for (u32* reg : REGISTERS)
    169     {
    170       // Data is in host order (little endian).
    171       auto value = StringUtil::DecodeHex({data.data() + offset, 8});
    172       if (value)
    173       {
    174         *reg = *reinterpret_cast<u32*>(&(*value)[0]);
    175       }
    176       offset += 8;
    177     }
    178   }
    179   else
    180   {
    181     ERROR_LOG("Wrong payload size for 'G' command, expected {} got {}", NUM_GDB_REGISTERS * 8, data.size());
    182   }
    183 
    184   return {""};
    185 }
    186 
    187 /// Get memory.
    188 static std::optional<std::string> Cmd$m(std::string_view data)
    189 {
    190   std::stringstream ss{std::string{data}};
    191   std::string dataAddress, dataLength;
    192 
    193   std::getline(ss, dataAddress, ',');
    194   std::getline(ss, dataLength, '\0');
    195 
    196   auto address = StringUtil::FromChars<VirtualMemoryAddress>(dataAddress, 16);
    197   auto length = StringUtil::FromChars<u32>(dataLength, 16);
    198 
    199   if (address && length)
    200   {
    201     PhysicalMemoryAddress phys_addr = *address & CPU::PHYSICAL_MEMORY_ADDRESS_MASK;
    202     u32 phys_length = *length;
    203 
    204     u8* ptr_data = GetMemoryPointer(phys_addr, phys_length);
    205     if (ptr_data)
    206     {
    207       return {StringUtil::EncodeHex(ptr_data, phys_length)};
    208     }
    209   }
    210   return {"E00"};
    211 }
    212 
    213 /// Set memory.
    214 static std::optional<std::string> Cmd$M(std::string_view data)
    215 {
    216   std::stringstream ss{std::string{data}};
    217   std::string dataAddress, dataLength, dataPayload;
    218 
    219   std::getline(ss, dataAddress, ',');
    220   std::getline(ss, dataLength, ':');
    221   std::getline(ss, dataPayload, '\0');
    222 
    223   auto address = StringUtil::FromChars<VirtualMemoryAddress>(dataAddress, 16);
    224   auto length = StringUtil::FromChars<u32>(dataLength, 16);
    225   auto payload = StringUtil::DecodeHex(dataPayload);
    226 
    227   if (address && length && payload && (payload->size() == *length))
    228   {
    229     u32 phys_addr = *address & CPU::PHYSICAL_MEMORY_ADDRESS_MASK;
    230     u32 phys_length = *length;
    231 
    232     u8* ptr_data = GetMemoryPointer(phys_addr, phys_length);
    233     if (ptr_data)
    234     {
    235       memcpy(ptr_data, payload->data(), phys_length);
    236       return {"OK"};
    237     }
    238   }
    239 
    240   return {"E00"};
    241 }
    242 
    243 /// Remove hardware breakpoint.
    244 static std::optional<std::string> Cmd$z1(std::string_view data)
    245 {
    246   auto address = StringUtil::FromChars<VirtualMemoryAddress>(data, 16);
    247   if (address)
    248   {
    249     CPU::RemoveBreakpoint(CPU::BreakpointType::Execute, *address);
    250     return {"OK"};
    251   }
    252   else
    253   {
    254     return std::nullopt;
    255   }
    256 }
    257 
    258 /// Insert hardware breakpoint.
    259 static std::optional<std::string> Cmd$Z1(std::string_view data)
    260 {
    261   auto address = StringUtil::FromChars<VirtualMemoryAddress>(data, 16);
    262   if (address)
    263   {
    264     CPU::AddBreakpoint(CPU::BreakpointType::Execute, *address, false);
    265     return {"OK"};
    266   }
    267   else
    268   {
    269     return std::nullopt;
    270   }
    271 }
    272 
    273 static std::optional<std::string> Cmd$vMustReplyEmpty(std::string_view data)
    274 {
    275   return {""};
    276 }
    277 
    278 static std::optional<std::string> Cmd$qSupported(std::string_view data)
    279 {
    280   return {""};
    281 }
    282 
    283 /// List of all GDB remote protocol packets supported by us.
    284 static const std::map<const char*, std::function<std::optional<std::string>(std::string_view)>> COMMANDS{
    285   {"?", Cmd$_questionMark},
    286   {"g", Cmd$g},
    287   {"G", Cmd$G},
    288   {"m", Cmd$m},
    289   {"M", Cmd$M},
    290   {"z0,", Cmd$z1},
    291   {"Z0,", Cmd$Z1},
    292   {"z1,", Cmd$z1},
    293   {"Z1,", Cmd$Z1},
    294   {"vMustReplyEmpty", Cmd$vMustReplyEmpty},
    295   {"qSupported", Cmd$qSupported},
    296 };
    297 
    298 bool IsPacketInterrupt(std::string_view data)
    299 {
    300   return (data.size() >= 1) && (data[data.size() - 1] == '\003');
    301 }
    302 
    303 bool IsPacketContinue(std::string_view data)
    304 {
    305   return (data.size() >= 5) && (data.substr(data.size() - 5) == "$c#63");
    306 }
    307 
    308 bool IsPacketComplete(std::string_view data)
    309 {
    310   return ((data.size() == 1) && (data[0] == '\003')) || ((data.size() > 3) && (*(data.end() - 3) == '#'));
    311 }
    312 
    313 std::string ProcessPacket(std::string_view data)
    314 {
    315   std::string_view trimmedData = data;
    316 
    317   // Eat ACKs.
    318   while (!trimmedData.empty() && (trimmedData[0] == '+' || trimmedData[0] == '-'))
    319   {
    320     if (trimmedData[0] == '-')
    321     {
    322       ERROR_LOG("Received negative ack");
    323     }
    324     trimmedData = trimmedData.substr(1);
    325   }
    326 
    327   // Validate packet.
    328   auto packet = DeserializePacket(trimmedData);
    329   if (!packet)
    330   {
    331     ERROR_LOG("Malformed packet '{}'", trimmedData);
    332     return "-";
    333   }
    334 
    335   std::optional<std::string> reply = {""};
    336 
    337   // Try to invoke packet command.
    338   bool processed = false;
    339   for (const auto& command : COMMANDS)
    340   {
    341     if (packet->starts_with(command.first))
    342     {
    343       DEBUG_LOG("Processing command '{}'", command.first);
    344 
    345       // Invoke command, remove command name from payload.
    346       reply = command.second(packet->substr(strlen(command.first)));
    347       processed = true;
    348       break;
    349     }
    350   }
    351 
    352   if (!processed)
    353     WARNING_LOG("Failed to process packet '{}'", trimmedData);
    354 
    355   return reply ? "+" + SerializePacket(*reply) : "+";
    356 }
    357 
    358 } // namespace GDBProtocol
    359 
    360 namespace GDBServer {
    361 
    362 namespace {
    363 class ClientSocket final : public BufferedStreamSocket
    364 {
    365 public:
    366   ClientSocket(SocketMultiplexer& multiplexer, SocketDescriptor descriptor);
    367   ~ClientSocket() override;
    368 
    369   void OnSystemPaused();
    370   void OnSystemResumed();
    371 
    372 protected:
    373   void OnConnected() override;
    374   void OnDisconnected(const Error& error) override;
    375   void OnRead() override;
    376 
    377 private:
    378   void SendPacket(std::string_view sv);
    379 
    380   bool m_seen_resume = false;
    381 };
    382 } // namespace
    383 
    384 static std::shared_ptr<ListenSocket> s_gdb_listen_socket;
    385 static std::vector<std::shared_ptr<ClientSocket>> s_gdb_clients;
    386 } // namespace GDBServer
    387 
    388 GDBServer::ClientSocket::ClientSocket(SocketMultiplexer& multiplexer, SocketDescriptor descriptor)
    389   : BufferedStreamSocket(multiplexer, descriptor, 65536, 65536)
    390 {
    391 }
    392 
    393 GDBServer::ClientSocket::~ClientSocket() = default;
    394 
    395 void GDBServer::ClientSocket::OnConnected()
    396 {
    397   INFO_LOG("Client {} connected.", GetRemoteAddress().ToString());
    398 
    399   m_seen_resume = System::IsPaused();
    400   System::PauseSystem(true);
    401 
    402   s_gdb_clients.push_back(std::static_pointer_cast<ClientSocket>(shared_from_this()));
    403 }
    404 
    405 void GDBServer::ClientSocket::OnDisconnected(const Error& error)
    406 {
    407   INFO_LOG("Client {} disconnected: {}", GetRemoteAddress().ToString(), error.GetDescription());
    408 
    409   const auto iter = std::find_if(s_gdb_clients.begin(), s_gdb_clients.end(),
    410                                  [this](const std::shared_ptr<ClientSocket>& rhs) { return (rhs.get() == this); });
    411   if (iter == s_gdb_clients.end())
    412   {
    413     ERROR_LOG("Unknown GDB client disconnected? This should never happen.");
    414     return;
    415   }
    416 
    417   s_gdb_clients.erase(iter);
    418 }
    419 
    420 void GDBServer::ClientSocket::OnRead()
    421 {
    422   const std::span<const u8> buffer = AcquireReadBuffer();
    423   if (buffer.empty())
    424     return;
    425 
    426   size_t buffer_offset = 0;
    427   while (buffer_offset < buffer.size())
    428   {
    429     size_t current_packet_size = 1;
    430     bool packet_complete = false;
    431     for (; (buffer_offset + current_packet_size) <= buffer.size(); current_packet_size++)
    432     {
    433       const std::string_view current_packet(reinterpret_cast<const char*>(buffer.data() + buffer_offset),
    434                                             current_packet_size);
    435 
    436       if (GDBProtocol::IsPacketInterrupt(current_packet))
    437       {
    438         DEV_LOG("{} > Interrupt request", GetRemoteAddress().ToString());
    439         System::PauseSystem(true);
    440         packet_complete = true;
    441         break;
    442       }
    443       else if (GDBProtocol::IsPacketContinue(current_packet))
    444       {
    445         DEV_LOG("{} > Continue request", GetRemoteAddress().ToString());
    446         System::PauseSystem(false);
    447         packet_complete = true;
    448         break;
    449       }
    450       else if (GDBProtocol::IsPacketComplete(current_packet))
    451       {
    452         // TODO: Make this not copy.
    453         DEV_LOG("{} > {}", GetRemoteAddress().ToString(), current_packet);
    454         SendPacket(GDBProtocol::ProcessPacket(current_packet));
    455         packet_complete = true;
    456         break;
    457       }
    458     }
    459 
    460     if (!packet_complete)
    461     {
    462       WARNING_LOG("Incomplete packet, got {} bytes.", buffer.size() - buffer_offset);
    463       break;
    464     }
    465     else
    466     {
    467       buffer_offset += current_packet_size;
    468     }
    469   }
    470 
    471   ReleaseReadBuffer(buffer_offset);
    472 }
    473 
    474 void GDBServer::ClientSocket::SendPacket(std::string_view sv)
    475 {
    476   if (sv.empty())
    477     return;
    478 
    479   WARNING_LOG("Write: {}", sv);
    480   if (size_t written = Write(sv.data(), sv.length()); written != sv.length())
    481     ERROR_LOG("Only wrote {} of {} bytes.", written, sv.length());
    482 }
    483 
    484 void GDBServer::ClientSocket::OnSystemPaused()
    485 {
    486   if (!m_seen_resume)
    487     return;
    488 
    489   m_seen_resume = false;
    490 
    491   // Generate a stop reply packet, insert '?' command to generate it.
    492   SendPacket(GDBProtocol::ProcessPacket("$?#3f"));
    493 }
    494 
    495 void GDBServer::ClientSocket::OnSystemResumed()
    496 {
    497   m_seen_resume = true;
    498 
    499   // Send ack, in case GDB sent a continue request.
    500   SendPacket("+");
    501 }
    502 
    503 bool GDBServer::Initialize(u16 port)
    504 {
    505   Error error;
    506   Assert(!s_gdb_listen_socket);
    507 
    508   const std::optional<SocketAddress> address =
    509     SocketAddress::Parse(SocketAddress::Type::IPv4, "127.0.0.1", port, &error);
    510   if (!address.has_value())
    511   {
    512     ERROR_LOG("Failed to parse address: {}", error.GetDescription());
    513     return false;
    514   }
    515 
    516   SocketMultiplexer* multiplexer = System::GetSocketMultiplexer();
    517   if (!multiplexer)
    518     return false;
    519 
    520   s_gdb_listen_socket = multiplexer->CreateListenSocket<ClientSocket>(address.value(), &error);
    521   if (!s_gdb_listen_socket)
    522   {
    523     ERROR_LOG("Failed to create listen socket: {}", error.GetDescription());
    524     System::ReleaseSocketMultiplexer();
    525     return false;
    526   }
    527 
    528   INFO_LOG("GDB server is now listening on {}.", address->ToString());
    529   return true;
    530 }
    531 
    532 bool GDBServer::HasAnyClients()
    533 {
    534   return !s_gdb_clients.empty();
    535 }
    536 
    537 void GDBServer::Shutdown()
    538 {
    539   if (!s_gdb_listen_socket)
    540     return;
    541 
    542   INFO_LOG("Disconnecting {} GDB clients...", s_gdb_clients.size());
    543   while (!s_gdb_clients.empty())
    544   {
    545     // maintain a reference so we don't delete while in scope
    546     std::shared_ptr<ClientSocket> client = s_gdb_clients.back();
    547     client->Close();
    548   }
    549 
    550   INFO_LOG("Stopping GDB server.");
    551   s_gdb_listen_socket->Close();
    552   s_gdb_listen_socket.reset();
    553   System::ReleaseSocketMultiplexer();
    554 }
    555 
    556 void GDBServer::OnSystemPaused()
    557 {
    558   for (auto& it : s_gdb_clients)
    559     it->OnSystemPaused();
    560 }
    561 
    562 void GDBServer::OnSystemResumed()
    563 {
    564   for (auto& it : s_gdb_clients)
    565     it->OnSystemResumed();
    566 }