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

@ -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).