mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-29 00:55:41 +00:00
System: Move GDB server into core
This commit is contained in:
parent
55d96f86f0
commit
015804c434
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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>
|
|
@ -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
|
|
@ -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
14
src/core/gdb_server.h
Normal 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
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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());
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue