summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Morph2022-06-13 14:38:37 -0400
committerGravatar GitHub2022-06-13 14:38:37 -0400
commita0407a8e646172392514dd996d62464db64aee83 (patch)
treeb13a559bcb4a9f9641730d58285a56bde6d5cc80
parentMerge pull request #8454 from liamwhite/inaddr-any (diff)
parentyuzu-cmd: ignore bogus timeous from SDL (diff)
downloadyuzu-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.cpp6
-rw-r--r--src/core/core.h3
-rw-r--r--src/core/debugger/debugger.cpp55
-rw-r--r--src/core/debugger/debugger.h5
-rw-r--r--src/core/debugger/debugger_interface.h5
-rw-r--r--src/core/debugger/gdbstub.cpp2
-rw-r--r--src/core/debugger/gdbstub.h1
-rw-r--r--src/yuzu/main.cpp1
-rw-r--r--src/yuzu_cmd/config.cpp2
-rw-r--r--src/yuzu_cmd/default_ini.h5
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp10
-rw-r--r--src/yuzu_cmd/yuzu.cpp9
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
496void System::DetachDebugger() {
497 if (impl->debugger) {
498 impl->debugger->NotifyShutdown();
499 }
500}
501
496std::unique_lock<std::mutex> System::StallCPU() { 502std::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
45enum class SignalType {
46 Stopped,
47 ShuttingDown,
48};
49
50struct SignalInfo {
51 SignalType type;
52 Kernel::KThread* thread;
53};
54
45namespace Core { 55namespace Core {
46 56
47class DebuggerImpl : public DebuggerBackend { 57class 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) {
263Debugger::~Debugger() = default; 298Debugger::~Debugger() = default;
264 299
265bool Debugger::NotifyThreadStopped(Kernel::KThread* thread) { 300bool Debugger::NotifyThreadStopped(Kernel::KThread* thread) {
266 return impl && impl->NotifyThreadStopped(thread); 301 return impl && impl->SignalDebugger(SignalInfo{SignalType::Stopped, thread});
302}
303
304void 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
38private: 43private:
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
107void GDBStub::Connected() {} 107void GDBStub::Connected() {}
108 108
109void GDBStub::ShuttingDown() {}
110
109void GDBStub::Stopped(Kernel::KThread* thread) { 111void 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
28private: 29private:
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
439disable_fps_limit=false 439disable_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
442use_gdbstub=false
443# The port to use for the GDB server, if it is enabled.
444gdbstub_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