System: Move GDB server into core

This commit is contained in:
Stenzek
2024-05-27 00:10:39 +10:00
parent 55d96f86f0
commit 015804c434
20 changed files with 307 additions and 274 deletions

View File

@ -40,8 +40,8 @@ add_library(core
game_database.h
game_list.cpp
game_list.h
gdb_protocol.cpp
gdb_protocol.h
gdb_server.cpp
gdb_server.h
gpu.cpp
gpu.h
gpu_backend.cpp

View File

@ -43,6 +43,7 @@
<ClCompile Include="fullscreen_ui.cpp" />
<ClCompile Include="game_database.cpp" />
<ClCompile Include="game_list.cpp" />
<ClCompile Include="gdb_server.cpp" />
<ClCompile Include="gpu_backend.cpp" />
<ClCompile Include="gpu_commands.cpp" />
<ClCompile Include="gpu_hw_shadergen.cpp" />
@ -51,7 +52,6 @@
<ClCompile Include="gpu_sw_backend.cpp" />
<ClCompile Include="gte.cpp" />
<ClCompile Include="dma.cpp" />
<ClCompile Include="gdb_protocol.cpp" />
<ClCompile Include="gpu.cpp" />
<ClCompile Include="gpu_hw.cpp" />
<ClCompile Include="host.cpp" />
@ -122,6 +122,7 @@
<ClInclude Include="fullscreen_ui.h" />
<ClInclude Include="game_database.h" />
<ClInclude Include="game_list.h" />
<ClInclude Include="gdb_server.h" />
<ClInclude Include="gpu_backend.h" />
<ClInclude Include="gpu_hw_shadergen.h" />
<ClInclude Include="gpu_shadergen.h" />
@ -131,7 +132,6 @@
<ClInclude Include="gte.h" />
<ClInclude Include="cpu_types.h" />
<ClInclude Include="dma.h" />
<ClInclude Include="gdb_protocol.h" />
<ClInclude Include="gpu.h" />
<ClInclude Include="gpu_hw.h" />
<ClInclude Include="gte_types.h" />

View File

@ -6,7 +6,6 @@
<ClCompile Include="cpu_disasm.cpp" />
<ClCompile Include="bus.cpp" />
<ClCompile Include="dma.cpp" />
<ClCompile Include="gdb_protocol.cpp" />
<ClCompile Include="gpu.cpp" />
<ClCompile Include="gpu_hw.cpp" />
<ClCompile Include="interrupt_controller.cpp" />
@ -68,6 +67,7 @@
<ClCompile Include="cpu_newrec_compiler_aarch32.cpp" />
<ClCompile Include="justifier.cpp" />
<ClCompile Include="pine_server.cpp" />
<ClCompile Include="gdb_server.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="types.h" />
@ -120,7 +120,6 @@
<ClInclude Include="gpu_sw_backend.h" />
<ClInclude Include="texture_replacements.h" />
<ClInclude Include="multitap.h" />
<ClInclude Include="gdb_protocol.h" />
<ClInclude Include="host.h" />
<ClInclude Include="achievements.h" />
<ClInclude Include="game_database.h" />
@ -142,5 +141,6 @@
<ClInclude Include="achievements_private.h" />
<ClInclude Include="justifier.h" />
<ClInclude Include="pine_server.h" />
<ClInclude Include="gdb_server.h" />
</ItemGroup>
</Project>

View File

@ -1,13 +0,0 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> and contributors.
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once
#include <string_view>
namespace GDBProtocol {
bool IsPacketInterrupt(std::string_view data);
bool IsPacketContinue(std::string_view data);
bool IsPacketComplete(std::string_view data);
std::string ProcessPacket(std::string_view data);
} // namespace GDBProtocol

View File

@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: 2019-2022 Connor McLaughlin <stenzek@gmail.com> and contributors.
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> and contributors.
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#include "gdb_protocol.h"
#include "gdb_server.h"
#include "bus.h"
#include "cpu_core.h"
#include "cpu_core_private.h"
@ -11,6 +11,8 @@
#include "common/small_string.h"
#include "common/string_util.h"
#include "util/sockets.h"
#include <functional>
#include <iomanip>
#include <map>
@ -20,6 +22,14 @@
Log_SetChannel(GDBProtocol);
namespace GDBProtocol {
static bool IsPacketInterrupt(std::string_view data);
static bool IsPacketContinue(std::string_view data);
static bool IsPacketComplete(std::string_view data);
static std::string ProcessPacket(std::string_view data);
} // namespace GDBProtocol
namespace GDBProtocol {
static u8* GetMemoryPointer(PhysicalMemoryAddress address, u32 length)
@ -345,3 +355,210 @@ std::string ProcessPacket(std::string_view data)
}
} // namespace GDBProtocol
namespace GDBServer {
namespace {
class ClientSocket final : public BufferedStreamSocket
{
public:
ClientSocket(SocketMultiplexer& multiplexer, SocketDescriptor descriptor);
~ClientSocket() override;
void OnSystemPaused();
void OnSystemResumed();
protected:
void OnConnected() override;
void OnDisconnected(const Error& error) override;
void OnRead() override;
private:
void SendPacket(std::string_view sv);
bool m_seen_resume = false;
};
} // namespace
static std::shared_ptr<ListenSocket> s_gdb_listen_socket;
static std::vector<std::shared_ptr<ClientSocket>> s_gdb_clients;
} // namespace GDBServer
GDBServer::ClientSocket::ClientSocket(SocketMultiplexer& multiplexer, SocketDescriptor descriptor)
: BufferedStreamSocket(multiplexer, descriptor, 65536, 65536)
{
}
GDBServer::ClientSocket::~ClientSocket() = default;
void GDBServer::ClientSocket::OnConnected()
{
INFO_LOG("Client {} connected.", GetRemoteAddress().ToString());
m_seen_resume = System::IsPaused();
System::PauseSystem(true);
s_gdb_clients.push_back(std::static_pointer_cast<ClientSocket>(shared_from_this()));
}
void GDBServer::ClientSocket::OnDisconnected(const Error& error)
{
INFO_LOG("Client {} disconnected: {}", GetRemoteAddress().ToString(), error.GetDescription());
const auto iter = std::find_if(s_gdb_clients.begin(), s_gdb_clients.end(),
[this](const std::shared_ptr<ClientSocket>& rhs) { return (rhs.get() == this); });
if (iter == s_gdb_clients.end())
{
ERROR_LOG("Unknown GDB client disconnected? This should never happen.");
return;
}
s_gdb_clients.erase(iter);
}
void GDBServer::ClientSocket::OnRead()
{
const std::span<const u8> buffer = AcquireReadBuffer();
if (buffer.empty())
return;
size_t buffer_offset = 0;
while (buffer_offset < buffer.size())
{
size_t current_packet_size = 1;
bool packet_complete = false;
for (; (buffer_offset + current_packet_size) <= buffer.size(); current_packet_size++)
{
const std::string_view current_packet(reinterpret_cast<const char*>(buffer.data() + buffer_offset),
current_packet_size);
if (GDBProtocol::IsPacketInterrupt(current_packet))
{
DEV_LOG("{} > Interrupt request", GetRemoteAddress().ToString());
System::PauseSystem(true);
packet_complete = true;
break;
}
else if (GDBProtocol::IsPacketContinue(current_packet))
{
DEV_LOG("{} > Continue request", GetRemoteAddress().ToString());
System::PauseSystem(false);
packet_complete = true;
break;
}
else if (GDBProtocol::IsPacketComplete(current_packet))
{
// TODO: Make this not copy.
DEV_LOG("{} > {}", GetRemoteAddress().ToString(), current_packet);
SendPacket(GDBProtocol::ProcessPacket(current_packet));
packet_complete = true;
break;
}
}
if (!packet_complete)
{
WARNING_LOG("Incomplete packet, got {} bytes.", buffer.size() - buffer_offset);
break;
}
else
{
buffer_offset += current_packet_size;
}
}
ReleaseReadBuffer(buffer_offset);
}
void GDBServer::ClientSocket::SendPacket(std::string_view sv)
{
if (sv.empty())
return;
WARNING_LOG("Write: {}", sv);
if (size_t written = Write(sv.data(), sv.length()); written != sv.length())
ERROR_LOG("Only wrote {} of {} bytes.", written, sv.length());
}
void GDBServer::ClientSocket::OnSystemPaused()
{
if (!m_seen_resume)
return;
m_seen_resume = false;
// Generate a stop reply packet, insert '?' command to generate it.
SendPacket(GDBProtocol::ProcessPacket("$?#3f"));
}
void GDBServer::ClientSocket::OnSystemResumed()
{
m_seen_resume = true;
// Send ack, in case GDB sent a continue request.
SendPacket("+");
}
bool GDBServer::Initialize(u16 port)
{
Error error;
Assert(!s_gdb_listen_socket);
const std::optional<SocketAddress> address =
SocketAddress::Parse(SocketAddress::Type::IPv4, "127.0.0.1", port, &error);
if (!address.has_value())
{
ERROR_LOG("Failed to parse address: {}", error.GetDescription());
return false;
}
SocketMultiplexer* multiplexer = System::GetSocketMultiplexer();
if (!multiplexer)
return false;
s_gdb_listen_socket = multiplexer->CreateListenSocket<ClientSocket>(address.value(), &error);
if (!s_gdb_listen_socket)
{
ERROR_LOG("Failed to create listen socket: {}", error.GetDescription());
System::ReleaseSocketMultiplexer();
return false;
}
INFO_LOG("GDB server is now listening on {}.", address->ToString());
return true;
}
bool GDBServer::HasAnyClients()
{
return !s_gdb_clients.empty();
}
void GDBServer::Shutdown()
{
if (!s_gdb_listen_socket)
return;
INFO_LOG("Disconnecting {} GDB clients...", s_gdb_clients.size());
while (!s_gdb_clients.empty())
{
// maintain a reference so we don't delete while in scope
std::shared_ptr<ClientSocket> client = s_gdb_clients.back();
client->Close();
}
INFO_LOG("Stopping GDB server.");
s_gdb_listen_socket.reset();
System::ReleaseSocketMultiplexer();
}
void GDBServer::OnSystemPaused()
{
for (auto& it : s_gdb_clients)
it->OnSystemPaused();
}
void GDBServer::OnSystemResumed()
{
for (auto& it : s_gdb_clients)
it->OnSystemResumed();
}

14
src/core/gdb_server.h Normal file
View File

@ -0,0 +1,14 @@
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> and contributors.
// SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0)
#pragma once
#include <string_view>
namespace GDBServer {
bool Initialize(u16 port);
bool HasAnyClients();
void Shutdown();
void OnSystemPaused();
void OnSystemResumed();
} // namespace GDBServer

View File

@ -82,8 +82,9 @@ Log_SetChannel(System);
#ifndef __ANDROID__
#define ENABLE_PINE_SERVER 1
// #define ENABLE_GDB_SERVER 1
#define ENABLE_GDB_SERVER 1
#define ENABLE_SOCKET_MULTIPLEXER 1
#include "gdb_server.h"
#include "pine_server.h"
#endif
@ -1289,6 +1290,10 @@ void System::PauseSystem(bool paused)
if (g_settings.inhibit_screensaver)
PlatformMisc::ResumeScreensaver();
#ifdef ENABLE_GDB_SERVER
GDBServer::OnSystemPaused();
#endif
Host::OnSystemPaused();
Host::OnIdleStateChanged();
UpdateDisplayVSync();
@ -1303,6 +1308,10 @@ void System::PauseSystem(bool paused)
if (g_settings.inhibit_screensaver)
PlatformMisc::SuspendScreensaver();
#ifdef ENABLE_GDB_SERVER
GDBServer::OnSystemResumed();
#endif
Host::OnSystemResumed();
Host::OnIdleStateChanged();
@ -1670,6 +1679,11 @@ bool System::BootSystem(SystemBootParameters parameters, Error* error)
if (g_settings.inhibit_screensaver)
PlatformMisc::SuspendScreensaver();
#ifdef ENABLE_GDB_SERVER
if (g_settings.debugging.enable_gdb_server)
GDBServer::Initialize(g_settings.debugging.gdb_server_port);
#endif
Host::OnSystemStarted();
Host::OnIdleStateChanged();
@ -1816,6 +1830,10 @@ void System::DestroySystem()
if (s_state == State::Shutdown)
return;
#ifdef ENABLE_GDB_SERVER
GDBServer::Shutdown();
#endif
Host::ClearOSDMessages();
PostProcessing::Shutdown();
@ -4072,6 +4090,16 @@ void System::CheckForSettingsChanges(const Settings& old_settings)
}
PostProcessing::UpdateSettings();
#ifdef ENABLE_GDB_SERVER
if (g_settings.debugging.enable_gdb_server != old_settings.debugging.enable_gdb_server ||
g_settings.debugging.gdb_server_port != old_settings.debugging.gdb_server_port)
{
GDBServer::Shutdown();
if (g_settings.debugging.enable_gdb_server)
GDBServer::Initialize(g_settings.debugging.gdb_server_port);
}
#endif
}
else
{