diff options
| author | 2022-06-13 14:38:37 -0400 | |
|---|---|---|
| committer | 2022-06-13 14:38:37 -0400 | |
| commit | a0407a8e646172392514dd996d62464db64aee83 (patch) | |
| tree | b13a559bcb4a9f9641730d58285a56bde6d5cc80 | |
| parent | Merge pull request #8454 from liamwhite/inaddr-any (diff) | |
| parent | yuzu-cmd: ignore bogus timeous from SDL (diff) | |
| download | yuzu-a0407a8e646172392514dd996d62464db64aee83.tar.gz yuzu-a0407a8e646172392514dd996d62464db64aee83.tar.xz yuzu-a0407a8e646172392514dd996d62464db64aee83.zip | |
Merge pull request #8446 from liamwhite/cmd-gdb
core/debugger: support operation in yuzu-cmd
Diffstat (limited to '')
| -rw-r--r-- | src/core/core.cpp | 6 | ||||
| -rw-r--r-- | src/core/core.h | 3 | ||||
| -rw-r--r-- | src/core/debugger/debugger.cpp | 55 | ||||
| -rw-r--r-- | src/core/debugger/debugger.h | 5 | ||||
| -rw-r--r-- | src/core/debugger/debugger_interface.h | 5 | ||||
| -rw-r--r-- | src/core/debugger/gdbstub.cpp | 2 | ||||
| -rw-r--r-- | src/core/debugger/gdbstub.h | 1 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 1 | ||||
| -rw-r--r-- | src/yuzu_cmd/config.cpp | 2 | ||||
| -rw-r--r-- | src/yuzu_cmd/default_ini.h | 5 | ||||
| -rw-r--r-- | src/yuzu_cmd/emu_window/emu_window_sdl2.cpp | 10 | ||||
| -rw-r--r-- | src/yuzu_cmd/yuzu.cpp | 9 |
12 files changed, 96 insertions, 8 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp index 7d974ba65..954136adb 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -493,6 +493,12 @@ void System::Shutdown() { | |||
| 493 | impl->Shutdown(); | 493 | impl->Shutdown(); |
| 494 | } | 494 | } |
| 495 | 495 | ||
| 496 | void System::DetachDebugger() { | ||
| 497 | if (impl->debugger) { | ||
| 498 | impl->debugger->NotifyShutdown(); | ||
| 499 | } | ||
| 500 | } | ||
| 501 | |||
| 496 | std::unique_lock<std::mutex> System::StallCPU() { | 502 | std::unique_lock<std::mutex> System::StallCPU() { |
| 497 | return impl->StallCPU(); | 503 | return impl->StallCPU(); |
| 498 | } | 504 | } |
diff --git a/src/core/core.h b/src/core/core.h index 94477206e..5c367349e 100644 --- a/src/core/core.h +++ b/src/core/core.h | |||
| @@ -160,6 +160,9 @@ public: | |||
| 160 | /// Shutdown the emulated system. | 160 | /// Shutdown the emulated system. |
| 161 | void Shutdown(); | 161 | void Shutdown(); |
| 162 | 162 | ||
| 163 | /// Forcibly detach the debugger if it is running. | ||
| 164 | void DetachDebugger(); | ||
| 165 | |||
| 163 | std::unique_lock<std::mutex> StallCPU(); | 166 | std::unique_lock<std::mutex> StallCPU(); |
| 164 | void UnstallCPU(); | 167 | void UnstallCPU(); |
| 165 | 168 | ||
diff --git a/src/core/debugger/debugger.cpp b/src/core/debugger/debugger.cpp index 7774ffdef..edf991d71 100644 --- a/src/core/debugger/debugger.cpp +++ b/src/core/debugger/debugger.cpp | |||
| @@ -42,6 +42,16 @@ static std::span<const u8> ReceiveInto(Readable& r, Buffer& buffer) { | |||
| 42 | return received_data; | 42 | return received_data; |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | enum class SignalType { | ||
| 46 | Stopped, | ||
| 47 | ShuttingDown, | ||
| 48 | }; | ||
| 49 | |||
| 50 | struct SignalInfo { | ||
| 51 | SignalType type; | ||
| 52 | Kernel::KThread* thread; | ||
| 53 | }; | ||
| 54 | |||
| 45 | namespace Core { | 55 | namespace Core { |
| 46 | 56 | ||
| 47 | class DebuggerImpl : public DebuggerBackend { | 57 | class DebuggerImpl : public DebuggerBackend { |
| @@ -56,7 +66,7 @@ public: | |||
| 56 | ShutdownServer(); | 66 | ShutdownServer(); |
| 57 | } | 67 | } |
| 58 | 68 | ||
| 59 | bool NotifyThreadStopped(Kernel::KThread* thread) { | 69 | bool SignalDebugger(SignalInfo signal_info) { |
| 60 | std::scoped_lock lk{connection_lock}; | 70 | std::scoped_lock lk{connection_lock}; |
| 61 | 71 | ||
| 62 | if (stopped) { | 72 | if (stopped) { |
| @@ -64,9 +74,13 @@ public: | |||
| 64 | // It should be ignored. | 74 | // It should be ignored. |
| 65 | return false; | 75 | return false; |
| 66 | } | 76 | } |
| 77 | |||
| 78 | // Set up the state. | ||
| 67 | stopped = true; | 79 | stopped = true; |
| 80 | info = signal_info; | ||
| 68 | 81 | ||
| 69 | boost::asio::write(signal_pipe, boost::asio::buffer(&thread, sizeof(thread))); | 82 | // Write a single byte into the pipe to wake up the debug interface. |
| 83 | boost::asio::write(signal_pipe, boost::asio::buffer(&stopped, sizeof(stopped))); | ||
| 70 | return true; | 84 | return true; |
| 71 | } | 85 | } |
| 72 | 86 | ||
| @@ -124,7 +138,7 @@ private: | |||
| 124 | Common::SetCurrentThreadName("yuzu:Debugger"); | 138 | Common::SetCurrentThreadName("yuzu:Debugger"); |
| 125 | 139 | ||
| 126 | // Set up the client signals for new data. | 140 | // Set up the client signals for new data. |
| 127 | AsyncReceiveInto(signal_pipe, active_thread, [&](auto d) { PipeData(d); }); | 141 | AsyncReceiveInto(signal_pipe, pipe_data, [&](auto d) { PipeData(d); }); |
| 128 | AsyncReceiveInto(client_socket, client_data, [&](auto d) { ClientData(d); }); | 142 | AsyncReceiveInto(client_socket, client_data, [&](auto d) { ClientData(d); }); |
| 129 | 143 | ||
| 130 | // Stop the emulated CPU. | 144 | // Stop the emulated CPU. |
| @@ -142,9 +156,28 @@ private: | |||
| 142 | } | 156 | } |
| 143 | 157 | ||
| 144 | void PipeData(std::span<const u8> data) { | 158 | void PipeData(std::span<const u8> data) { |
| 145 | AllCoreStop(); | 159 | switch (info.type) { |
| 146 | UpdateActiveThread(); | 160 | case SignalType::Stopped: |
| 147 | frontend->Stopped(active_thread); | 161 | // Stop emulation. |
| 162 | AllCoreStop(); | ||
| 163 | |||
| 164 | // Notify the client. | ||
| 165 | active_thread = info.thread; | ||
| 166 | UpdateActiveThread(); | ||
| 167 | frontend->Stopped(active_thread); | ||
| 168 | |||
| 169 | break; | ||
| 170 | case SignalType::ShuttingDown: | ||
| 171 | frontend->ShuttingDown(); | ||
| 172 | |||
| 173 | // Wait for emulation to shut down gracefully now. | ||
| 174 | suspend.reset(); | ||
| 175 | signal_pipe.close(); | ||
| 176 | client_socket.shutdown(boost::asio::socket_base::shutdown_both); | ||
| 177 | LOG_INFO(Debug_GDBStub, "Shut down server"); | ||
| 178 | |||
| 179 | break; | ||
| 180 | } | ||
| 148 | } | 181 | } |
| 149 | 182 | ||
| 150 | void ClientData(std::span<const u8> data) { | 183 | void ClientData(std::span<const u8> data) { |
| @@ -246,7 +279,9 @@ private: | |||
| 246 | boost::asio::ip::tcp::socket client_socket; | 279 | boost::asio::ip::tcp::socket client_socket; |
| 247 | std::optional<std::unique_lock<std::mutex>> suspend; | 280 | std::optional<std::unique_lock<std::mutex>> suspend; |
| 248 | 281 | ||
| 282 | SignalInfo info; | ||
| 249 | Kernel::KThread* active_thread; | 283 | Kernel::KThread* active_thread; |
| 284 | bool pipe_data; | ||
| 250 | bool stopped; | 285 | bool stopped; |
| 251 | 286 | ||
| 252 | std::array<u8, 4096> client_data; | 287 | std::array<u8, 4096> client_data; |
| @@ -263,7 +298,13 @@ Debugger::Debugger(Core::System& system, u16 port) { | |||
| 263 | Debugger::~Debugger() = default; | 298 | Debugger::~Debugger() = default; |
| 264 | 299 | ||
| 265 | bool Debugger::NotifyThreadStopped(Kernel::KThread* thread) { | 300 | bool Debugger::NotifyThreadStopped(Kernel::KThread* thread) { |
| 266 | return impl && impl->NotifyThreadStopped(thread); | 301 | return impl && impl->SignalDebugger(SignalInfo{SignalType::Stopped, thread}); |
| 302 | } | ||
| 303 | |||
| 304 | void Debugger::NotifyShutdown() { | ||
| 305 | if (impl) { | ||
| 306 | impl->SignalDebugger(SignalInfo{SignalType::ShuttingDown, nullptr}); | ||
| 307 | } | ||
| 267 | } | 308 | } |
| 268 | 309 | ||
| 269 | } // namespace Core | 310 | } // namespace Core |
diff --git a/src/core/debugger/debugger.h b/src/core/debugger/debugger.h index ea36c6ab2..f9738ca3d 100644 --- a/src/core/debugger/debugger.h +++ b/src/core/debugger/debugger.h | |||
| @@ -35,6 +35,11 @@ public: | |||
| 35 | */ | 35 | */ |
| 36 | bool NotifyThreadStopped(Kernel::KThread* thread); | 36 | bool NotifyThreadStopped(Kernel::KThread* thread); |
| 37 | 37 | ||
| 38 | /** | ||
| 39 | * Notify the debugger that a shutdown is being performed now and disconnect. | ||
| 40 | */ | ||
| 41 | void NotifyShutdown(); | ||
| 42 | |||
| 38 | private: | 43 | private: |
| 39 | std::unique_ptr<DebuggerImpl> impl; | 44 | std::unique_ptr<DebuggerImpl> impl; |
| 40 | }; | 45 | }; |
diff --git a/src/core/debugger/debugger_interface.h b/src/core/debugger/debugger_interface.h index 35ba0bc61..c0bb4ecaf 100644 --- a/src/core/debugger/debugger_interface.h +++ b/src/core/debugger/debugger_interface.h | |||
| @@ -67,6 +67,11 @@ public: | |||
| 67 | virtual void Stopped(Kernel::KThread* thread) = 0; | 67 | virtual void Stopped(Kernel::KThread* thread) = 0; |
| 68 | 68 | ||
| 69 | /** | 69 | /** |
| 70 | * Called when emulation is shutting down. | ||
| 71 | */ | ||
| 72 | virtual void ShuttingDown() = 0; | ||
| 73 | |||
| 74 | /** | ||
| 70 | * Called when new data is asynchronously received on the client socket. | 75 | * Called when new data is asynchronously received on the client socket. |
| 71 | * A list of actions to perform is returned. | 76 | * A list of actions to perform is returned. |
| 72 | */ | 77 | */ |
diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp index f52d78829..52e76f659 100644 --- a/src/core/debugger/gdbstub.cpp +++ b/src/core/debugger/gdbstub.cpp | |||
| @@ -106,6 +106,8 @@ GDBStub::~GDBStub() = default; | |||
| 106 | 106 | ||
| 107 | void GDBStub::Connected() {} | 107 | void GDBStub::Connected() {} |
| 108 | 108 | ||
| 109 | void GDBStub::ShuttingDown() {} | ||
| 110 | |||
| 109 | void GDBStub::Stopped(Kernel::KThread* thread) { | 111 | void GDBStub::Stopped(Kernel::KThread* thread) { |
| 110 | SendReply(arch->ThreadStatus(thread, GDB_STUB_SIGTRAP)); | 112 | SendReply(arch->ThreadStatus(thread, GDB_STUB_SIGTRAP)); |
| 111 | } | 113 | } |
diff --git a/src/core/debugger/gdbstub.h b/src/core/debugger/gdbstub.h index 1bb638187..ec934c77e 100644 --- a/src/core/debugger/gdbstub.h +++ b/src/core/debugger/gdbstub.h | |||
| @@ -23,6 +23,7 @@ public: | |||
| 23 | 23 | ||
| 24 | void Connected() override; | 24 | void Connected() override; |
| 25 | void Stopped(Kernel::KThread* thread) override; | 25 | void Stopped(Kernel::KThread* thread) override; |
| 26 | void ShuttingDown() override; | ||
| 26 | std::vector<DebuggerAction> ClientData(std::span<const u8> data) override; | 27 | std::vector<DebuggerAction> ClientData(std::span<const u8> data) override; |
| 27 | 28 | ||
| 28 | private: | 29 | private: |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 27f23bcb0..33886e50e 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -1591,6 +1591,7 @@ void GMainWindow::ShutdownGame() { | |||
| 1591 | 1591 | ||
| 1592 | AllowOSSleep(); | 1592 | AllowOSSleep(); |
| 1593 | 1593 | ||
| 1594 | system->DetachDebugger(); | ||
| 1594 | discord_rpc->Pause(); | 1595 | discord_rpc->Pause(); |
| 1595 | emu_thread->RequestStop(); | 1596 | emu_thread->RequestStop(); |
| 1596 | 1597 | ||
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index fc16f0f0c..fc4744fb0 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp | |||
| @@ -344,6 +344,8 @@ void Config::ReadValues() { | |||
| 344 | ReadSetting("Debugging", Settings::values.use_debug_asserts); | 344 | ReadSetting("Debugging", Settings::values.use_debug_asserts); |
| 345 | ReadSetting("Debugging", Settings::values.use_auto_stub); | 345 | ReadSetting("Debugging", Settings::values.use_auto_stub); |
| 346 | ReadSetting("Debugging", Settings::values.disable_macro_jit); | 346 | ReadSetting("Debugging", Settings::values.disable_macro_jit); |
| 347 | ReadSetting("Debugging", Settings::values.use_gdbstub); | ||
| 348 | ReadSetting("Debugging", Settings::values.gdbstub_port); | ||
| 347 | 349 | ||
| 348 | const auto title_list = sdl2_config->Get("AddOns", "title_ids", ""); | 350 | const auto title_list = sdl2_config->Get("AddOns", "title_ids", ""); |
| 349 | std::stringstream ss(title_list); | 351 | std::stringstream ss(title_list); |
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index 39063e32b..a3b8432f5 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h | |||
| @@ -437,6 +437,11 @@ disable_macro_jit=false | |||
| 437 | # Presents guest frames as they become available. Experimental. | 437 | # Presents guest frames as they become available. Experimental. |
| 438 | # false: Disabled (default), true: Enabled | 438 | # false: Disabled (default), true: Enabled |
| 439 | disable_fps_limit=false | 439 | disable_fps_limit=false |
| 440 | # Determines whether to enable the GDB stub and wait for the debugger to attach before running. | ||
| 441 | # false: Disabled (default), true: Enabled | ||
| 442 | use_gdbstub=false | ||
| 443 | # The port to use for the GDB server, if it is enabled. | ||
| 444 | gdbstub_port=6543 | ||
| 440 | 445 | ||
| 441 | [WebService] | 446 | [WebService] |
| 442 | # Whether or not to enable telemetry | 447 | # Whether or not to enable telemetry |
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp index 71c413e64..8e38724db 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp | |||
| @@ -162,7 +162,15 @@ void EmuWindow_SDL2::WaitEvent() { | |||
| 162 | SDL_Event event; | 162 | SDL_Event event; |
| 163 | 163 | ||
| 164 | if (!SDL_WaitEvent(&event)) { | 164 | if (!SDL_WaitEvent(&event)) { |
| 165 | LOG_CRITICAL(Frontend, "SDL_WaitEvent failed: {}", SDL_GetError()); | 165 | const char* error = SDL_GetError(); |
| 166 | if (!error || strcmp(error, "") == 0) { | ||
| 167 | // https://github.com/libsdl-org/SDL/issues/5780 | ||
| 168 | // Sometimes SDL will return without actually having hit an error condition; | ||
| 169 | // just ignore it in this case. | ||
| 170 | return; | ||
| 171 | } | ||
| 172 | |||
| 173 | LOG_CRITICAL(Frontend, "SDL_WaitEvent failed: {}", error); | ||
| 166 | exit(1); | 174 | exit(1); |
| 167 | } | 175 | } |
| 168 | 176 | ||
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index ab12dd15d..0dce5e274 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp | |||
| @@ -217,10 +217,19 @@ int main(int argc, char** argv) { | |||
| 217 | [](VideoCore::LoadCallbackStage, size_t value, size_t total) {}); | 217 | [](VideoCore::LoadCallbackStage, size_t value, size_t total) {}); |
| 218 | } | 218 | } |
| 219 | 219 | ||
| 220 | system.RegisterExitCallback([&] { | ||
| 221 | // Just exit right away. | ||
| 222 | exit(0); | ||
| 223 | }); | ||
| 224 | |||
| 220 | void(system.Run()); | 225 | void(system.Run()); |
| 226 | if (system.DebuggerEnabled()) { | ||
| 227 | system.InitializeDebugger(); | ||
| 228 | } | ||
| 221 | while (emu_window->IsOpen()) { | 229 | while (emu_window->IsOpen()) { |
| 222 | emu_window->WaitEvent(); | 230 | emu_window->WaitEvent(); |
| 223 | } | 231 | } |
| 232 | system.DetachDebugger(); | ||
| 224 | void(system.Pause()); | 233 | void(system.Pause()); |
| 225 | system.Shutdown(); | 234 | system.Shutdown(); |
| 226 | 235 | ||