|
@@ -42,6 +42,16 @@ static std::span<const u8> ReceiveInto(Readable& r, Buffer& buffer) {
|
|
|
return received_data;
|
|
return received_data;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+enum class SignalType {
|
|
|
|
|
+ Stopped,
|
|
|
|
|
+ ShuttingDown,
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+struct SignalInfo {
|
|
|
|
|
+ SignalType type;
|
|
|
|
|
+ Kernel::KThread* thread;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
namespace Core {
|
|
namespace Core {
|
|
|
|
|
|
|
|
class DebuggerImpl : public DebuggerBackend {
|
|
class DebuggerImpl : public DebuggerBackend {
|
|
@@ -56,7 +66,7 @@ public:
|
|
|
ShutdownServer();
|
|
ShutdownServer();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- bool NotifyThreadStopped(Kernel::KThread* thread) {
|
|
|
|
|
|
|
+ bool SignalDebugger(SignalInfo signal_info) {
|
|
|
std::scoped_lock lk{connection_lock};
|
|
std::scoped_lock lk{connection_lock};
|
|
|
|
|
|
|
|
if (stopped) {
|
|
if (stopped) {
|
|
@@ -64,9 +74,13 @@ public:
|
|
|
// It should be ignored.
|
|
// It should be ignored.
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ // Set up the state.
|
|
|
stopped = true;
|
|
stopped = true;
|
|
|
|
|
+ info = signal_info;
|
|
|
|
|
|
|
|
- boost::asio::write(signal_pipe, boost::asio::buffer(&thread, sizeof(thread)));
|
|
|
|
|
|
|
+ // Write a single byte into the pipe to wake up the debug interface.
|
|
|
|
|
+ boost::asio::write(signal_pipe, boost::asio::buffer(&stopped, sizeof(stopped)));
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -124,7 +138,7 @@ private:
|
|
|
Common::SetCurrentThreadName("yuzu:Debugger");
|
|
Common::SetCurrentThreadName("yuzu:Debugger");
|
|
|
|
|
|
|
|
// Set up the client signals for new data.
|
|
// Set up the client signals for new data.
|
|
|
- AsyncReceiveInto(signal_pipe, active_thread, [&](auto d) { PipeData(d); });
|
|
|
|
|
|
|
+ AsyncReceiveInto(signal_pipe, pipe_data, [&](auto d) { PipeData(d); });
|
|
|
AsyncReceiveInto(client_socket, client_data, [&](auto d) { ClientData(d); });
|
|
AsyncReceiveInto(client_socket, client_data, [&](auto d) { ClientData(d); });
|
|
|
|
|
|
|
|
// Stop the emulated CPU.
|
|
// Stop the emulated CPU.
|
|
@@ -142,9 +156,28 @@ private:
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void PipeData(std::span<const u8> data) {
|
|
void PipeData(std::span<const u8> data) {
|
|
|
- AllCoreStop();
|
|
|
|
|
- UpdateActiveThread();
|
|
|
|
|
- frontend->Stopped(active_thread);
|
|
|
|
|
|
|
+ switch (info.type) {
|
|
|
|
|
+ case SignalType::Stopped:
|
|
|
|
|
+ // Stop emulation.
|
|
|
|
|
+ AllCoreStop();
|
|
|
|
|
+
|
|
|
|
|
+ // Notify the client.
|
|
|
|
|
+ active_thread = info.thread;
|
|
|
|
|
+ UpdateActiveThread();
|
|
|
|
|
+ frontend->Stopped(active_thread);
|
|
|
|
|
+
|
|
|
|
|
+ break;
|
|
|
|
|
+ case SignalType::ShuttingDown:
|
|
|
|
|
+ frontend->ShuttingDown();
|
|
|
|
|
+
|
|
|
|
|
+ // Wait for emulation to shut down gracefully now.
|
|
|
|
|
+ suspend.reset();
|
|
|
|
|
+ signal_pipe.close();
|
|
|
|
|
+ client_socket.shutdown(boost::asio::socket_base::shutdown_both);
|
|
|
|
|
+ LOG_INFO(Debug_GDBStub, "Shut down server");
|
|
|
|
|
+
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void ClientData(std::span<const u8> data) {
|
|
void ClientData(std::span<const u8> data) {
|
|
@@ -246,7 +279,9 @@ private:
|
|
|
boost::asio::ip::tcp::socket client_socket;
|
|
boost::asio::ip::tcp::socket client_socket;
|
|
|
std::optional<std::unique_lock<std::mutex>> suspend;
|
|
std::optional<std::unique_lock<std::mutex>> suspend;
|
|
|
|
|
|
|
|
|
|
+ SignalInfo info;
|
|
|
Kernel::KThread* active_thread;
|
|
Kernel::KThread* active_thread;
|
|
|
|
|
+ bool pipe_data;
|
|
|
bool stopped;
|
|
bool stopped;
|
|
|
|
|
|
|
|
std::array<u8, 4096> client_data;
|
|
std::array<u8, 4096> client_data;
|
|
@@ -263,7 +298,13 @@ Debugger::Debugger(Core::System& system, u16 port) {
|
|
|
Debugger::~Debugger() = default;
|
|
Debugger::~Debugger() = default;
|
|
|
|
|
|
|
|
bool Debugger::NotifyThreadStopped(Kernel::KThread* thread) {
|
|
bool Debugger::NotifyThreadStopped(Kernel::KThread* thread) {
|
|
|
- return impl && impl->NotifyThreadStopped(thread);
|
|
|
|
|
|
|
+ return impl && impl->SignalDebugger(SignalInfo{SignalType::Stopped, thread});
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void Debugger::NotifyShutdown() {
|
|
|
|
|
+ if (impl) {
|
|
|
|
|
+ impl->SignalDebugger(SignalInfo{SignalType::ShuttingDown, nullptr});
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
} // namespace Core
|
|
} // namespace Core
|