System: Move GDB server into core

This commit is contained in:
Stenzek 2024-05-27 00:10:39 +10:00
parent 55d96f86f0
commit 015804c434
No known key found for this signature in database
20 changed files with 307 additions and 274 deletions

View file

@ -32,7 +32,7 @@
</ClCompile>
<Link>
<AdditionalLibraryDirectories>$(QtLibDir);%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>Qt6Core$(QtLibSuffix).lib;Qt6Gui$(QtLibSuffix).lib;Qt6Widgets$(QtLibSuffix).lib;Qt6Network$(QtLibSuffix).lib;Qt6Concurrent$(QtLibSuffix).lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>Qt6Core$(QtLibSuffix).lib;Qt6Gui$(QtLibSuffix).lib;Qt6Widgets$(QtLibSuffix).lib;Qt6Concurrent$(QtLibSuffix).lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
@ -118,24 +118,21 @@
<!--Copy the needed dlls-->
<ItemGroup>
<QtLibNames Include="Qt6Core$(QtLibSuffix);Qt6Gui$(QtLibSuffix);Qt6Widgets$(QtLibSuffix);Qt6Network$(QtLibSuffix);Qt6Svg$(QtLibSuffix);Qt6Concurrent$(QtLibSuffix)" />
<QtLibNames Include="Qt6Core$(QtLibSuffix);Qt6Gui$(QtLibSuffix);Qt6Widgets$(QtLibSuffix);Qt6Svg$(QtLibSuffix);Qt6Concurrent$(QtLibSuffix)" />
<QtDlls Include="@(QtLibNames -> '$(QtBinDir)%(Identity).dll')" />
<!--Filter plugins to copy based on the observation that all debug versions end in "d"-->
<QtAllPlugins Include="$(QtPluginsDir)**\*$(QtLibSuffix).dll" />
<QtPlugins Condition="$(Configuration.Contains(Debug))" Include="@(QtAllPlugins)" />
<QtPlugins Condition="!$(Configuration.Contains(Debug))" Exclude="$(QtPluginsDir)**\*$(QtDebugSuffix).dll" Include="@(QtAllPlugins)" />
<QtPluginsDest Include="@(QtPlugins -> '$(BinaryOutputDir)$(QtPluginFolder)\%(RecursiveDir)%(Filename)%(Extension)')" />
<!--Our normal *d filter fails for the TLS DLLs, because backend ends in d. -->
<QtTLSDlls Include="$(QtPluginsDir)tls\qcertonlybackend$(QtLibSuffix).dll;$(QtPluginsDir)tls\qschannelbackend$(QtLibSuffix).dll" />
<QtTLSDllsDest Include="@(QtTLSDlls -> '$(BinaryOutputDir)$(QtPluginFolder)\tls\%(Filename)%(Extension)')" />
</ItemGroup>
<PropertyGroup>
<QtConfFile>$(BinaryOutputDir)qt.conf</QtConfFile>
</PropertyGroup>
<Target Name="QtCopyBinaries"
AfterTargets="Build"
Inputs="@(QtDlls);@(QtPlugins);@(QtTLSDlls)"
Outputs="@(QtDlls -> '$(BinaryOutputDir)%(RecursiveDir)%(Filename)%(Extension)');@(QtPluginsDest);@(QtTLSDllsDest)">
Inputs="@(QtDlls);@(QtPlugins)"
Outputs="@(QtDlls -> '$(BinaryOutputDir)%(RecursiveDir)%(Filename)%(Extension)');@(QtPluginsDest)">
<Message Text="Copying Qt .dlls" />
<Copy
SourceFiles="@(QtDlls)"
@ -147,11 +144,6 @@
DestinationFiles="@(QtPluginsDest)"
SkipUnchangedFiles="true"
/>
<Copy
SourceFiles="@(QtTLSDlls)"
DestinationFiles="@(QtTLSDllsDest)"
SkipUnchangedFiles="true"
/>
</Target>
<Target Name="QtCreateConf"
BeforeTargets="QtCopyBinaries"

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
{

View file

@ -1,4 +1,4 @@
find_package(Qt6 6.6.0 COMPONENTS Core Gui Widgets Network LinguistTools REQUIRED)
find_package(Qt6 6.7.0 COMPONENTS Core Gui Widgets LinguistTools REQUIRED)
include(CopyBaseTranslations)
@ -96,10 +96,6 @@ set(SRCS
gamesummarywidget.cpp
gamesummarywidget.h
gamesummarywidget.ui
gdbconnection.cpp
gdbconnection.h
gdbserver.cpp
gdbserver.h
graphicssettingswidget.cpp
graphicssettingswidget.h
graphicssettingswidget.ui
@ -175,7 +171,7 @@ set(TS_FILES
add_executable(duckstation-qt ${SRCS} ${QM_FILES})
target_precompile_headers(duckstation-qt PRIVATE "pch.h")
target_include_directories(duckstation-qt PRIVATE "${Qt6Gui_PRIVATE_INCLUDE_DIRS}" "${CMAKE_CURRENT_SOURCE_DIR}")
target_link_libraries(duckstation-qt PRIVATE core common imgui minizip scmversion Qt6::Core Qt6::Gui Qt6::Widgets Qt6::Network)
target_link_libraries(duckstation-qt PRIVATE core common imgui minizip scmversion Qt6::Core Qt6::Gui Qt6::Widgets)
# Our Qt builds may have exceptions on, so force them off.
target_compile_definitions(duckstation-qt PRIVATE QT_NO_EXCEPTIONS)

View file

@ -36,8 +36,6 @@
<ClCompile Include="gamelistrefreshthread.cpp" />
<ClCompile Include="gamelistwidget.cpp" />
<ClCompile Include="gamesummarywidget.cpp" />
<ClCompile Include="gdbconnection.cpp" />
<ClCompile Include="gdbserver.cpp" />
<ClCompile Include="mainwindow.cpp" />
<ClCompile Include="memorycardsettingswidget.cpp" />
<ClCompile Include="memorycardeditorwindow.cpp" />
@ -97,8 +95,6 @@
<QtMoc Include="gamelistrefreshthread.h" />
<QtMoc Include="gamelistwidget.h" />
<QtMoc Include="gamesummarywidget.h" />
<QtMoc Include="gdbconnection.h" />
<QtMoc Include="gdbserver.h" />
<QtMoc Include="postprocessingsettingswidget.h" />
<QtMoc Include="mainwindow.h" />
<QtMoc Include="qthost.h" />
@ -243,8 +239,6 @@
<ClCompile Include="$(IntDir)moc_gamelistsettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_gamelistwidget.cpp" />
<ClCompile Include="$(IntDir)moc_gamesummarywidget.cpp" />
<ClCompile Include="$(IntDir)moc_gdbconnection.cpp" />
<ClCompile Include="$(IntDir)moc_gdbserver.cpp" />
<ClCompile Include="$(IntDir)moc_graphicssettingswidget.cpp" />
<ClCompile Include="$(IntDir)moc_debuggermodels.cpp" />
<ClCompile Include="$(IntDir)moc_debuggerwindow.cpp" />

View file

@ -15,8 +15,6 @@
<ClCompile Include="qtprogresscallback.cpp" />
<ClCompile Include="interfacesettingswidget.cpp" />
<ClCompile Include="advancedsettingswidget.cpp" />
<ClCompile Include="gdbconnection.cpp" />
<ClCompile Include="gdbserver.cpp" />
<ClCompile Include="aboutdialog.cpp" />
<ClCompile Include="memorycardsettingswidget.cpp" />
<ClCompile Include="$(IntDir)qrc_resources.cpp" />
@ -126,12 +124,6 @@
<ClCompile Include="$(IntDir)moc_gamesummarywidget.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)moc_gdbconnection.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)moc_gdbserver.cpp">
<Filter>moc</Filter>
</ClCompile>
<ClCompile Include="$(IntDir)moc_hotkeysettingswidget.cpp">
<Filter>moc</Filter>
</ClCompile>
@ -219,8 +211,6 @@
<QtMoc Include="interfacesettingswidget.h" />
<QtMoc Include="qtprogresscallback.h" />
<QtMoc Include="advancedsettingswidget.h" />
<QtMoc Include="gdbconnection.h" />
<QtMoc Include="gdbserver.h" />
<QtMoc Include="aboutdialog.h" />
<QtMoc Include="memorycardsettingswidget.h" />
<QtMoc Include="inputbindingdialog.h" />

View file

@ -1,95 +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)
#include "gdbconnection.h"
#include "common/log.h"
#include "core/gdb_protocol.h"
#include "qthost.h"
Log_SetChannel(GDBConnection);
GDBConnection::GDBConnection(GDBServer* parent, intptr_t descriptor) : QTcpSocket(parent), m_descriptor(descriptor)
{
if (!setSocketDescriptor(descriptor))
{
ERROR_LOG("{} failed to set socket descriptor: {}", descriptor, errorString().toStdString());
deleteLater();
return;
}
connect(g_emu_thread, &EmuThread::systemPaused, this, &GDBConnection::onEmulationPaused);
connect(g_emu_thread, &EmuThread::systemResumed, this, &GDBConnection::onEmulationResumed);
connect(this, &QTcpSocket::readyRead, this, &GDBConnection::receivedData);
connect(this, &QTcpSocket::disconnected, this, &GDBConnection::gotDisconnected);
INFO_LOG("{} client connected", m_descriptor);
m_seen_resume = System::IsPaused();
g_emu_thread->setSystemPaused(true);
}
void GDBConnection::gotDisconnected()
{
INFO_LOG("{} client disconnected", m_descriptor);
deleteLater();
}
void GDBConnection::receivedData()
{
qint64 bytesRead;
char buffer[256];
while ((bytesRead = read(buffer, sizeof(buffer))) > 0)
{
for (char c : std::string_view(buffer, bytesRead))
{
m_readBuffer.push_back(c);
if (GDBProtocol::IsPacketInterrupt(m_readBuffer))
{
DEBUG_LOG("{} > Interrupt request", m_descriptor);
g_emu_thread->setSystemPaused(true);
m_readBuffer.erase();
}
else if (GDBProtocol::IsPacketContinue(m_readBuffer))
{
DEBUG_LOG("{} > Continue request", m_descriptor);
g_emu_thread->setSystemPaused(false);
m_readBuffer.erase();
}
else if (GDBProtocol::IsPacketComplete(m_readBuffer))
{
DEBUG_LOG("{} > {}", m_descriptor, m_readBuffer);
writePacket(GDBProtocol::ProcessPacket(m_readBuffer));
m_readBuffer.erase();
}
}
}
if (bytesRead == -1)
{
ERROR_LOG("{} failed to read from socket: {}", m_descriptor, errorString().toStdString());
}
}
void GDBConnection::onEmulationPaused()
{
if (m_seen_resume)
{
m_seen_resume = false;
// Generate a stop reply packet, insert '?' command to generate it.
writePacket(GDBProtocol::ProcessPacket("$?#3f"));
}
}
void GDBConnection::onEmulationResumed()
{
m_seen_resume = true;
// Send ack, in case GDB sent a continue request.
writePacket("+");
}
void GDBConnection::writePacket(std::string_view packet)
{
DEBUG_LOG("{} < {}", m_descriptor, packet);
if (write(packet.data(), packet.length()) == -1)
ERROR_LOG("{} failed to write to socket: {}", m_descriptor, errorString().toStdString());
}

View file

@ -1,29 +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 <QtCore/QThread>
#include <QtNetwork/QTcpSocket>
class GDBServer;
class GDBConnection : public QTcpSocket
{
Q_OBJECT
public:
GDBConnection(GDBServer *parent, intptr_t descriptor);
public Q_SLOTS:
void gotDisconnected();
void receivedData();
void onEmulationPaused();
void onEmulationResumed();
private:
void writePacket(std::string_view data);
intptr_t m_descriptor;
std::string m_readBuffer;
bool m_seen_resume;
};

View file

@ -1,52 +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)
#include "gdbserver.h"
#include "common/log.h"
#include "gdbconnection.h"
#include "qthost.h"
Log_SetChannel(GDBServer);
GDBServer::GDBServer(QObject* parent) : QTcpServer(parent)
{
}
GDBServer::~GDBServer()
{
stop();
}
void GDBServer::start(quint16 port)
{
if (isListening())
{
return;
}
if (!listen(QHostAddress::LocalHost, port))
{
ERROR_LOG("Failed to listen on TCP port {} for GDB server: {}", port, errorString().toUtf8().constData());
return;
}
INFO_LOG("GDB server listening on TCP port {}", port);
}
void GDBServer::stop()
{
if (isListening())
{
close();
INFO_LOG("GDB server stopped");
}
for (QObject* connection : children())
{
connection->deleteLater();
}
}
void GDBServer::incomingConnection(qintptr descriptor)
{
new GDBConnection(this, descriptor);
}

View file

@ -1,23 +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 "core/types.h"
#include "gdbconnection.h"
#include <QtNetwork/QTcpServer>
class GDBServer : public QTcpServer
{
Q_OBJECT
public:
GDBServer(QObject* parent = nullptr);
~GDBServer();
public Q_SLOTS:
void start(quint16 port);
void stop();
protected:
void incomingConnection(qintptr socketDescriptor) override;
};

View file

@ -1826,16 +1826,6 @@ void MainWindow::updateEmulationActions(bool starting, bool running, bool cheevo
if ((!starting && !running) || running)
m_open_debugger_on_start = false;
if (!g_gdb_server->isListening() && g_settings.debugging.enable_gdb_server && starting)
{
QMetaObject::invokeMethod(g_gdb_server, "start", Qt::QueuedConnection,
Q_ARG(quint16, g_settings.debugging.gdb_server_port));
}
else if (g_gdb_server->isListening() && !running)
{
QMetaObject::invokeMethod(g_gdb_server, "stop", Qt::QueuedConnection);
}
m_ui.statusBar->clearMessage();
}

View file

@ -16,6 +16,7 @@
#include "core/fullscreen_ui.h"
#include "core/game_database.h"
#include "core/game_list.h"
#include "core/gdb_server.h"
#include "core/gpu.h"
#include "core/host.h"
#include "core/imgui_overlays.h"
@ -81,6 +82,9 @@ static constexpr u32 BACKGROUND_CONTROLLER_POLLING_INTERVAL = 100;
/// Poll at half the vsync rate for FSUI to reduce the chance of getting a press+release in the same frame.
static constexpr u32 FULLSCREEN_UI_CONTROLLER_POLLING_INTERVAL = 8;
/// Poll at 1ms when running GDB server. We can get rid of this once we move networking to its own thread.
static constexpr u32 GDB_SERVER_POLLING_INTERVAL = 1;
//////////////////////////////////////////////////////////////////////////
// Local function declarations
//////////////////////////////////////////////////////////////////////////
@ -116,8 +120,7 @@ static bool s_start_fullscreen_ui_fullscreen = false;
static bool s_run_setup_wizard = false;
static bool s_cleanup_after_update = false;
EmuThread* g_emu_thread;
GDBServer* g_gdb_server;
EmuThread* g_emu_thread = nullptr;
EmuThread::EmuThread(QThread* ui_thread) : QThread(), m_ui_thread(ui_thread)
{
@ -1670,8 +1673,13 @@ void EmuThread::startBackgroundControllerPollTimer()
if (m_background_controller_polling_timer->isActive())
return;
m_background_controller_polling_timer->start(
FullscreenUI::IsInitialized() ? FULLSCREEN_UI_CONTROLLER_POLLING_INTERVAL : BACKGROUND_CONTROLLER_POLLING_INTERVAL);
u32 poll_interval = BACKGROUND_CONTROLLER_POLLING_INTERVAL;
if (FullscreenUI::IsInitialized())
poll_interval = FULLSCREEN_UI_CONTROLLER_POLLING_INTERVAL;
if (GDBServer::HasAnyClients())
poll_interval = GDB_SERVER_POLLING_INTERVAL;
m_background_controller_polling_timer->start(poll_interval);
}
void EmuThread::stopBackgroundControllerPollTimer()
@ -1687,8 +1695,6 @@ void EmuThread::start()
AssertMsg(!g_emu_thread, "Emu thread does not exist");
g_emu_thread = new EmuThread(QThread::currentThread());
g_gdb_server = new GDBServer();
g_gdb_server->moveToThread(g_emu_thread);
g_emu_thread->QThread::start();
g_emu_thread->m_started_semaphore.acquire();
g_emu_thread->moveToThread(g_emu_thread);

View file

@ -3,7 +3,6 @@
#pragma once
#include "gdbserver.h"
#include "qtutils.h"
#include "core/game_list.h"
@ -246,7 +245,6 @@ private:
};
extern EmuThread* g_emu_thread;
extern GDBServer* g_gdb_server;
namespace QtHost {
/// Sets batch mode (exit after game shutdown).

View file

@ -755,6 +755,9 @@ void BufferedStreamSocket::ReleaseReadBuffer(size_t bytes_consumed)
std::span<u8> BufferedStreamSocket::AcquireWriteBuffer(size_t wanted_bytes, bool allow_smaller /* = false */)
{
if (!m_connected)
return {};
// If to get the desired space, we need to move backwards, do so.
if ((m_send_buffer_offset + m_send_buffer_size + wanted_bytes) > m_send_buffer.size())
{
@ -776,6 +779,9 @@ std::span<u8> BufferedStreamSocket::AcquireWriteBuffer(size_t wanted_bytes, bool
void BufferedStreamSocket::ReleaseWriteBuffer(size_t bytes_written, bool commit /* = true */)
{
if (!m_connected)
return;
DebugAssert((m_send_buffer_offset + m_send_buffer_size + bytes_written) <= m_send_buffer.size());
m_send_buffer_size += static_cast<u32>(bytes_written);
@ -819,6 +825,9 @@ size_t BufferedStreamSocket::Read(void* buffer, size_t buffer_size)
size_t BufferedStreamSocket::Write(const void* buffer, size_t buffer_size)
{
if (!m_connected)
return 0;
// Read from receive buffer.
const std::span<u8> wrbuf = AcquireWriteBuffer(buffer_size, true);
if (wrbuf.empty())
@ -857,6 +866,16 @@ size_t BufferedStreamSocket::WriteVector(const void** buffers, const size_t* buf
return written_bytes;
}
void BufferedStreamSocket::Close()
{
StreamSocket::Close();
m_receive_buffer_offset = 0;
m_receive_buffer_size = 0;
m_send_buffer_offset = 0;
m_send_buffer_size = 0;
}
void BufferedStreamSocket::OnReadEvent()
{
std::unique_lock lock(m_lock);

View file

@ -197,7 +197,7 @@ public:
static u32 GetSocketProtocolForAddress(const SocketAddress& sa);
virtual void Close() override final;
virtual void Close() override;
// Accessors
const SocketAddress& GetLocalAddress() const { return m_local_address; }
@ -251,6 +251,7 @@ public:
size_t Read(void* buffer, size_t buffer_size);
size_t Write(const void* buffer, size_t buffer_size);
size_t WriteVector(const void** buffers, const size_t* buffer_lengths, size_t num_buffers);
virtual void Close() override;
protected:
void OnReadEvent() override final;