debugger.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <algorithm>
  4. #include <mutex>
  5. #include <thread>
  6. #include <boost/asio.hpp>
  7. #include <boost/process/async_pipe.hpp>
  8. #include "common/logging/log.h"
  9. #include "common/thread.h"
  10. #include "core/core.h"
  11. #include "core/debugger/debugger.h"
  12. #include "core/debugger/debugger_interface.h"
  13. #include "core/debugger/gdbstub.h"
  14. #include "core/hle/kernel/global_scheduler_context.h"
  15. #include "core/hle/kernel/k_scheduler.h"
  16. template <typename Readable, typename Buffer, typename Callback>
  17. static void AsyncReceiveInto(Readable& r, Buffer& buffer, Callback&& c) {
  18. static_assert(std::is_trivial_v<Buffer>);
  19. auto boost_buffer{boost::asio::buffer(&buffer, sizeof(Buffer))};
  20. r.async_read_some(
  21. boost_buffer, [&, c](const boost::system::error_code& error, size_t bytes_read) {
  22. if (!error.failed()) {
  23. const u8* buffer_start = reinterpret_cast<const u8*>(&buffer);
  24. std::span<const u8> received_data{buffer_start, buffer_start + bytes_read};
  25. c(received_data);
  26. }
  27. AsyncReceiveInto(r, buffer, c);
  28. });
  29. }
  30. template <typename Readable, typename Buffer>
  31. static std::span<const u8> ReceiveInto(Readable& r, Buffer& buffer) {
  32. static_assert(std::is_trivial_v<Buffer>);
  33. auto boost_buffer{boost::asio::buffer(&buffer, sizeof(Buffer))};
  34. size_t bytes_read = r.read_some(boost_buffer);
  35. const u8* buffer_start = reinterpret_cast<const u8*>(&buffer);
  36. std::span<const u8> received_data{buffer_start, buffer_start + bytes_read};
  37. return received_data;
  38. }
  39. enum class SignalType {
  40. Stopped,
  41. Watchpoint,
  42. ShuttingDown,
  43. };
  44. struct SignalInfo {
  45. SignalType type;
  46. Kernel::KThread* thread;
  47. const Kernel::DebugWatchpoint* watchpoint;
  48. };
  49. namespace Core {
  50. class DebuggerImpl : public DebuggerBackend {
  51. public:
  52. explicit DebuggerImpl(Core::System& system_, u16 port)
  53. : system{system_}, signal_pipe{io_context}, client_socket{io_context} {
  54. frontend = std::make_unique<GDBStub>(*this, system);
  55. InitializeServer(port);
  56. }
  57. ~DebuggerImpl() override {
  58. ShutdownServer();
  59. }
  60. bool SignalDebugger(SignalInfo signal_info) {
  61. {
  62. std::scoped_lock lk{connection_lock};
  63. if (stopped) {
  64. // Do not notify the debugger about another event.
  65. // It should be ignored.
  66. return false;
  67. }
  68. // Set up the state.
  69. stopped = true;
  70. info = signal_info;
  71. }
  72. // Write a single byte into the pipe to wake up the debug interface.
  73. boost::asio::write(signal_pipe, boost::asio::buffer(&stopped, sizeof(stopped)));
  74. return true;
  75. }
  76. std::span<const u8> ReadFromClient() override {
  77. return ReceiveInto(client_socket, client_data);
  78. }
  79. void WriteToClient(std::span<const u8> data) override {
  80. boost::asio::write(client_socket, boost::asio::buffer(data.data(), data.size_bytes()));
  81. }
  82. void SetActiveThread(Kernel::KThread* thread) override {
  83. active_thread = thread;
  84. }
  85. Kernel::KThread* GetActiveThread() override {
  86. return active_thread;
  87. }
  88. private:
  89. void InitializeServer(u16 port) {
  90. using boost::asio::ip::tcp;
  91. LOG_INFO(Debug_GDBStub, "Starting server on port {}...", port);
  92. // Run the connection thread.
  93. connection_thread = std::jthread([&, port](std::stop_token stop_token) {
  94. try {
  95. // Initialize the listening socket and accept a new client.
  96. tcp::endpoint endpoint{boost::asio::ip::address_v4::any(), port};
  97. tcp::acceptor acceptor{io_context, endpoint};
  98. acceptor.async_accept(client_socket, [](const auto&) {});
  99. io_context.run_one();
  100. io_context.restart();
  101. if (stop_token.stop_requested()) {
  102. return;
  103. }
  104. ThreadLoop(stop_token);
  105. } catch (const std::exception& ex) {
  106. LOG_CRITICAL(Debug_GDBStub, "Stopping server: {}", ex.what());
  107. }
  108. });
  109. }
  110. void ShutdownServer() {
  111. connection_thread.request_stop();
  112. io_context.stop();
  113. connection_thread.join();
  114. }
  115. void ThreadLoop(std::stop_token stop_token) {
  116. Common::SetCurrentThreadName("Debugger");
  117. // Set up the client signals for new data.
  118. AsyncReceiveInto(signal_pipe, pipe_data, [&](auto d) { PipeData(d); });
  119. AsyncReceiveInto(client_socket, client_data, [&](auto d) { ClientData(d); });
  120. // Set the active thread.
  121. UpdateActiveThread();
  122. // Set up the frontend.
  123. frontend->Connected();
  124. // Main event loop.
  125. while (!stop_token.stop_requested() && io_context.run()) {
  126. }
  127. }
  128. void PipeData(std::span<const u8> data) {
  129. switch (info.type) {
  130. case SignalType::Stopped:
  131. case SignalType::Watchpoint:
  132. // Stop emulation.
  133. PauseEmulation();
  134. // Notify the client.
  135. active_thread = info.thread;
  136. UpdateActiveThread();
  137. if (info.type == SignalType::Watchpoint) {
  138. frontend->Watchpoint(active_thread, *info.watchpoint);
  139. } else {
  140. frontend->Stopped(active_thread);
  141. }
  142. break;
  143. case SignalType::ShuttingDown:
  144. frontend->ShuttingDown();
  145. // Wait for emulation to shut down gracefully now.
  146. signal_pipe.close();
  147. client_socket.shutdown(boost::asio::socket_base::shutdown_both);
  148. LOG_INFO(Debug_GDBStub, "Shut down server");
  149. break;
  150. }
  151. }
  152. void ClientData(std::span<const u8> data) {
  153. const auto actions{frontend->ClientData(data)};
  154. for (const auto action : actions) {
  155. switch (action) {
  156. case DebuggerAction::Interrupt: {
  157. {
  158. std::scoped_lock lk{connection_lock};
  159. stopped = true;
  160. }
  161. PauseEmulation();
  162. UpdateActiveThread();
  163. frontend->Stopped(active_thread);
  164. break;
  165. }
  166. case DebuggerAction::Continue:
  167. MarkResumed([&] { ResumeEmulation(); });
  168. break;
  169. case DebuggerAction::StepThreadUnlocked:
  170. MarkResumed([&] {
  171. active_thread->SetStepState(Kernel::StepState::StepPending);
  172. active_thread->Resume(Kernel::SuspendType::Debug);
  173. ResumeEmulation(active_thread);
  174. });
  175. break;
  176. case DebuggerAction::StepThreadLocked: {
  177. MarkResumed([&] {
  178. active_thread->SetStepState(Kernel::StepState::StepPending);
  179. active_thread->Resume(Kernel::SuspendType::Debug);
  180. });
  181. break;
  182. }
  183. case DebuggerAction::ShutdownEmulation: {
  184. // Spawn another thread that will exit after shutdown,
  185. // to avoid a deadlock
  186. Core::System* system_ref{&system};
  187. std::thread t([system_ref] { system_ref->Exit(); });
  188. t.detach();
  189. break;
  190. }
  191. }
  192. }
  193. }
  194. void PauseEmulation() {
  195. Kernel::KScopedSchedulerLock sl{system.Kernel()};
  196. // Put all threads to sleep on next scheduler round.
  197. for (auto* thread : ThreadList()) {
  198. thread->RequestSuspend(Kernel::SuspendType::Debug);
  199. }
  200. }
  201. void ResumeEmulation(Kernel::KThread* except = nullptr) {
  202. // Wake up all threads.
  203. for (auto* thread : ThreadList()) {
  204. if (thread == except) {
  205. continue;
  206. }
  207. thread->SetStepState(Kernel::StepState::NotStepping);
  208. thread->Resume(Kernel::SuspendType::Debug);
  209. }
  210. }
  211. template <typename Callback>
  212. void MarkResumed(Callback&& cb) {
  213. Kernel::KScopedSchedulerLock sl{system.Kernel()};
  214. std::scoped_lock cl{connection_lock};
  215. stopped = false;
  216. cb();
  217. }
  218. void UpdateActiveThread() {
  219. const auto& threads{ThreadList()};
  220. if (std::find(threads.begin(), threads.end(), active_thread) == threads.end()) {
  221. active_thread = threads[0];
  222. }
  223. }
  224. const std::vector<Kernel::KThread*>& ThreadList() {
  225. return system.GlobalSchedulerContext().GetThreadList();
  226. }
  227. private:
  228. System& system;
  229. std::unique_ptr<DebuggerFrontend> frontend;
  230. std::jthread connection_thread;
  231. std::mutex connection_lock;
  232. boost::asio::io_context io_context;
  233. boost::process::async_pipe signal_pipe;
  234. boost::asio::ip::tcp::socket client_socket;
  235. SignalInfo info;
  236. Kernel::KThread* active_thread;
  237. bool pipe_data;
  238. bool stopped;
  239. std::array<u8, 4096> client_data;
  240. };
  241. Debugger::Debugger(Core::System& system, u16 port) {
  242. try {
  243. impl = std::make_unique<DebuggerImpl>(system, port);
  244. } catch (const std::exception& ex) {
  245. LOG_CRITICAL(Debug_GDBStub, "Failed to initialize debugger: {}", ex.what());
  246. }
  247. }
  248. Debugger::~Debugger() = default;
  249. bool Debugger::NotifyThreadStopped(Kernel::KThread* thread) {
  250. return impl && impl->SignalDebugger(SignalInfo{SignalType::Stopped, thread, nullptr});
  251. }
  252. bool Debugger::NotifyThreadWatchpoint(Kernel::KThread* thread,
  253. const Kernel::DebugWatchpoint& watch) {
  254. return impl && impl->SignalDebugger(SignalInfo{SignalType::Watchpoint, thread, &watch});
  255. }
  256. void Debugger::NotifyShutdown() {
  257. if (impl) {
  258. impl->SignalDebugger(SignalInfo{SignalType::ShuttingDown, nullptr, nullptr});
  259. }
  260. }
  261. } // namespace Core