gdbstub.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869
  1. // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <atomic>
  4. #include <numeric>
  5. #include <optional>
  6. #include <thread>
  7. #include <boost/algorithm/string.hpp>
  8. #include "common/hex_util.h"
  9. #include "common/logging/log.h"
  10. #include "common/scope_exit.h"
  11. #include "core/arm/arm_interface.h"
  12. #include "core/core.h"
  13. #include "core/debugger/gdbstub.h"
  14. #include "core/debugger/gdbstub_arch.h"
  15. #include "core/hle/kernel/k_page_table.h"
  16. #include "core/hle/kernel/k_process.h"
  17. #include "core/hle/kernel/k_thread.h"
  18. #include "core/loader/loader.h"
  19. #include "core/memory.h"
  20. namespace Core {
  21. constexpr char GDB_STUB_START = '$';
  22. constexpr char GDB_STUB_END = '#';
  23. constexpr char GDB_STUB_ACK = '+';
  24. constexpr char GDB_STUB_NACK = '-';
  25. constexpr char GDB_STUB_INT3 = 0x03;
  26. constexpr int GDB_STUB_SIGTRAP = 5;
  27. constexpr char GDB_STUB_REPLY_ERR[] = "E01";
  28. constexpr char GDB_STUB_REPLY_OK[] = "OK";
  29. constexpr char GDB_STUB_REPLY_EMPTY[] = "";
  30. static u8 CalculateChecksum(std::string_view data) {
  31. return std::accumulate(data.begin(), data.end(), u8{0},
  32. [](u8 lhs, u8 rhs) { return static_cast<u8>(lhs + rhs); });
  33. }
  34. static std::string EscapeGDB(std::string_view data) {
  35. std::string escaped;
  36. escaped.reserve(data.size());
  37. for (char c : data) {
  38. switch (c) {
  39. case '#':
  40. escaped += "}\x03";
  41. break;
  42. case '$':
  43. escaped += "}\x04";
  44. break;
  45. case '*':
  46. escaped += "}\x0a";
  47. break;
  48. case '}':
  49. escaped += "}\x5d";
  50. break;
  51. default:
  52. escaped += c;
  53. break;
  54. }
  55. }
  56. return escaped;
  57. }
  58. static std::string EscapeXML(std::string_view data) {
  59. std::string escaped;
  60. escaped.reserve(data.size());
  61. for (char c : data) {
  62. switch (c) {
  63. case '&':
  64. escaped += "&amp;";
  65. break;
  66. case '"':
  67. escaped += "&quot;";
  68. break;
  69. case '<':
  70. escaped += "&lt;";
  71. break;
  72. case '>':
  73. escaped += "&gt;";
  74. break;
  75. default:
  76. escaped += c;
  77. break;
  78. }
  79. }
  80. return escaped;
  81. }
  82. GDBStub::GDBStub(DebuggerBackend& backend_, Core::System& system_)
  83. : DebuggerFrontend(backend_), system{system_} {
  84. if (system.CurrentProcess()->Is64BitProcess()) {
  85. arch = std::make_unique<GDBStubA64>();
  86. } else {
  87. arch = std::make_unique<GDBStubA32>();
  88. }
  89. }
  90. GDBStub::~GDBStub() = default;
  91. void GDBStub::Connected() {}
  92. void GDBStub::ShuttingDown() {}
  93. void GDBStub::Stopped(Kernel::KThread* thread) {
  94. SendReply(arch->ThreadStatus(thread, GDB_STUB_SIGTRAP));
  95. }
  96. void GDBStub::Watchpoint(Kernel::KThread* thread, const Kernel::DebugWatchpoint& watch) {
  97. const auto status{arch->ThreadStatus(thread, GDB_STUB_SIGTRAP)};
  98. switch (watch.type) {
  99. case Kernel::DebugWatchpointType::Read:
  100. SendReply(fmt::format("{}rwatch:{:x};", status, watch.start_address));
  101. break;
  102. case Kernel::DebugWatchpointType::Write:
  103. SendReply(fmt::format("{}watch:{:x};", status, watch.start_address));
  104. break;
  105. case Kernel::DebugWatchpointType::ReadOrWrite:
  106. default:
  107. SendReply(fmt::format("{}awatch:{:x};", status, watch.start_address));
  108. break;
  109. }
  110. }
  111. std::vector<DebuggerAction> GDBStub::ClientData(std::span<const u8> data) {
  112. std::vector<DebuggerAction> actions;
  113. current_command.insert(current_command.end(), data.begin(), data.end());
  114. while (current_command.size() != 0) {
  115. ProcessData(actions);
  116. }
  117. return actions;
  118. }
  119. void GDBStub::ProcessData(std::vector<DebuggerAction>& actions) {
  120. const char c{current_command[0]};
  121. // Acknowledgement
  122. if (c == GDB_STUB_ACK || c == GDB_STUB_NACK) {
  123. current_command.erase(current_command.begin());
  124. return;
  125. }
  126. // Interrupt
  127. if (c == GDB_STUB_INT3) {
  128. LOG_INFO(Debug_GDBStub, "Received interrupt");
  129. current_command.erase(current_command.begin());
  130. actions.push_back(DebuggerAction::Interrupt);
  131. SendStatus(GDB_STUB_ACK);
  132. return;
  133. }
  134. // Otherwise, require the data to be the start of a command
  135. if (c != GDB_STUB_START) {
  136. LOG_ERROR(Debug_GDBStub, "Invalid command buffer contents: {}", current_command.data());
  137. current_command.clear();
  138. SendStatus(GDB_STUB_NACK);
  139. return;
  140. }
  141. // Continue reading until command is complete
  142. while (CommandEnd() == current_command.end()) {
  143. const auto new_data{backend.ReadFromClient()};
  144. current_command.insert(current_command.end(), new_data.begin(), new_data.end());
  145. }
  146. // Execute and respond to GDB
  147. const auto command{DetachCommand()};
  148. if (command) {
  149. SendStatus(GDB_STUB_ACK);
  150. ExecuteCommand(*command, actions);
  151. } else {
  152. SendStatus(GDB_STUB_NACK);
  153. }
  154. }
  155. void GDBStub::ExecuteCommand(std::string_view packet, std::vector<DebuggerAction>& actions) {
  156. LOG_TRACE(Debug_GDBStub, "Executing command: {}", packet);
  157. if (packet.length() == 0) {
  158. SendReply(GDB_STUB_REPLY_ERR);
  159. return;
  160. }
  161. if (packet.starts_with("vCont")) {
  162. HandleVCont(packet.substr(5), actions);
  163. return;
  164. }
  165. std::string_view command{packet.substr(1, packet.size())};
  166. switch (packet[0]) {
  167. case 'H': {
  168. Kernel::KThread* thread{nullptr};
  169. s64 thread_id{strtoll(command.data() + 1, nullptr, 16)};
  170. if (thread_id >= 1) {
  171. thread = GetThreadByID(thread_id);
  172. } else {
  173. thread = backend.GetActiveThread();
  174. }
  175. if (thread) {
  176. SendReply(GDB_STUB_REPLY_OK);
  177. backend.SetActiveThread(thread);
  178. } else {
  179. SendReply(GDB_STUB_REPLY_ERR);
  180. }
  181. break;
  182. }
  183. case 'T': {
  184. s64 thread_id{strtoll(command.data(), nullptr, 16)};
  185. if (GetThreadByID(thread_id)) {
  186. SendReply(GDB_STUB_REPLY_OK);
  187. } else {
  188. SendReply(GDB_STUB_REPLY_ERR);
  189. }
  190. break;
  191. }
  192. case 'Q':
  193. case 'q':
  194. HandleQuery(command);
  195. break;
  196. case '?':
  197. SendReply(arch->ThreadStatus(backend.GetActiveThread(), GDB_STUB_SIGTRAP));
  198. break;
  199. case 'k':
  200. LOG_INFO(Debug_GDBStub, "Shutting down emulation");
  201. actions.push_back(DebuggerAction::ShutdownEmulation);
  202. break;
  203. case 'g':
  204. SendReply(arch->ReadRegisters(backend.GetActiveThread()));
  205. break;
  206. case 'G':
  207. arch->WriteRegisters(backend.GetActiveThread(), command);
  208. SendReply(GDB_STUB_REPLY_OK);
  209. break;
  210. case 'p': {
  211. const size_t reg{static_cast<size_t>(strtoll(command.data(), nullptr, 16))};
  212. SendReply(arch->RegRead(backend.GetActiveThread(), reg));
  213. break;
  214. }
  215. case 'P': {
  216. const auto sep{std::find(command.begin(), command.end(), '=') - command.begin() + 1};
  217. const size_t reg{static_cast<size_t>(strtoll(command.data(), nullptr, 16))};
  218. arch->RegWrite(backend.GetActiveThread(), reg, std::string_view(command).substr(sep));
  219. SendReply(GDB_STUB_REPLY_OK);
  220. break;
  221. }
  222. case 'm': {
  223. const auto sep{std::find(command.begin(), command.end(), ',') - command.begin() + 1};
  224. const size_t addr{static_cast<size_t>(strtoll(command.data(), nullptr, 16))};
  225. const size_t size{static_cast<size_t>(strtoll(command.data() + sep, nullptr, 16))};
  226. if (system.Memory().IsValidVirtualAddressRange(addr, size)) {
  227. std::vector<u8> mem(size);
  228. system.Memory().ReadBlock(addr, mem.data(), size);
  229. SendReply(Common::HexToString(mem));
  230. } else {
  231. SendReply(GDB_STUB_REPLY_ERR);
  232. }
  233. break;
  234. }
  235. case 'M': {
  236. const auto size_sep{std::find(command.begin(), command.end(), ',') - command.begin() + 1};
  237. const auto mem_sep{std::find(command.begin(), command.end(), ':') - command.begin() + 1};
  238. const size_t addr{static_cast<size_t>(strtoll(command.data(), nullptr, 16))};
  239. const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))};
  240. const auto mem_substr{std::string_view(command).substr(mem_sep)};
  241. const auto mem{Common::HexStringToVector(mem_substr, false)};
  242. if (system.Memory().IsValidVirtualAddressRange(addr, size)) {
  243. system.Memory().WriteBlock(addr, mem.data(), size);
  244. system.InvalidateCpuInstructionCacheRange(addr, size);
  245. SendReply(GDB_STUB_REPLY_OK);
  246. } else {
  247. SendReply(GDB_STUB_REPLY_ERR);
  248. }
  249. break;
  250. }
  251. case 's':
  252. actions.push_back(DebuggerAction::StepThreadLocked);
  253. break;
  254. case 'C':
  255. case 'c':
  256. actions.push_back(DebuggerAction::Continue);
  257. break;
  258. case 'Z':
  259. HandleBreakpointInsert(command);
  260. break;
  261. case 'z':
  262. HandleBreakpointRemove(command);
  263. break;
  264. default:
  265. SendReply(GDB_STUB_REPLY_EMPTY);
  266. break;
  267. }
  268. }
  269. enum class BreakpointType {
  270. Software = 0,
  271. Hardware = 1,
  272. WriteWatch = 2,
  273. ReadWatch = 3,
  274. AccessWatch = 4,
  275. };
  276. void GDBStub::HandleBreakpointInsert(std::string_view command) {
  277. const auto type{static_cast<BreakpointType>(strtoll(command.data(), nullptr, 16))};
  278. const auto addr_sep{std::find(command.begin(), command.end(), ',') - command.begin() + 1};
  279. const auto size_sep{std::find(command.begin() + addr_sep, command.end(), ',') -
  280. command.begin() + 1};
  281. const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))};
  282. const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))};
  283. if (!system.Memory().IsValidVirtualAddressRange(addr, size)) {
  284. SendReply(GDB_STUB_REPLY_ERR);
  285. return;
  286. }
  287. bool success{};
  288. switch (type) {
  289. case BreakpointType::Software:
  290. replaced_instructions[addr] = system.Memory().Read32(addr);
  291. system.Memory().Write32(addr, arch->BreakpointInstruction());
  292. system.InvalidateCpuInstructionCacheRange(addr, sizeof(u32));
  293. success = true;
  294. break;
  295. case BreakpointType::WriteWatch:
  296. success = system.CurrentProcess()->InsertWatchpoint(system, addr, size,
  297. Kernel::DebugWatchpointType::Write);
  298. break;
  299. case BreakpointType::ReadWatch:
  300. success = system.CurrentProcess()->InsertWatchpoint(system, addr, size,
  301. Kernel::DebugWatchpointType::Read);
  302. break;
  303. case BreakpointType::AccessWatch:
  304. success = system.CurrentProcess()->InsertWatchpoint(
  305. system, addr, size, Kernel::DebugWatchpointType::ReadOrWrite);
  306. break;
  307. case BreakpointType::Hardware:
  308. default:
  309. SendReply(GDB_STUB_REPLY_EMPTY);
  310. return;
  311. }
  312. if (success) {
  313. SendReply(GDB_STUB_REPLY_OK);
  314. } else {
  315. SendReply(GDB_STUB_REPLY_ERR);
  316. }
  317. }
  318. void GDBStub::HandleBreakpointRemove(std::string_view command) {
  319. const auto type{static_cast<BreakpointType>(strtoll(command.data(), nullptr, 16))};
  320. const auto addr_sep{std::find(command.begin(), command.end(), ',') - command.begin() + 1};
  321. const auto size_sep{std::find(command.begin() + addr_sep, command.end(), ',') -
  322. command.begin() + 1};
  323. const size_t addr{static_cast<size_t>(strtoll(command.data() + addr_sep, nullptr, 16))};
  324. const size_t size{static_cast<size_t>(strtoll(command.data() + size_sep, nullptr, 16))};
  325. if (!system.Memory().IsValidVirtualAddressRange(addr, size)) {
  326. SendReply(GDB_STUB_REPLY_ERR);
  327. return;
  328. }
  329. bool success{};
  330. switch (type) {
  331. case BreakpointType::Software: {
  332. const auto orig_insn{replaced_instructions.find(addr)};
  333. if (orig_insn != replaced_instructions.end()) {
  334. system.Memory().Write32(addr, orig_insn->second);
  335. system.InvalidateCpuInstructionCacheRange(addr, sizeof(u32));
  336. replaced_instructions.erase(addr);
  337. success = true;
  338. }
  339. break;
  340. }
  341. case BreakpointType::WriteWatch:
  342. success = system.CurrentProcess()->RemoveWatchpoint(system, addr, size,
  343. Kernel::DebugWatchpointType::Write);
  344. break;
  345. case BreakpointType::ReadWatch:
  346. success = system.CurrentProcess()->RemoveWatchpoint(system, addr, size,
  347. Kernel::DebugWatchpointType::Read);
  348. break;
  349. case BreakpointType::AccessWatch:
  350. success = system.CurrentProcess()->RemoveWatchpoint(
  351. system, addr, size, Kernel::DebugWatchpointType::ReadOrWrite);
  352. break;
  353. case BreakpointType::Hardware:
  354. default:
  355. SendReply(GDB_STUB_REPLY_EMPTY);
  356. return;
  357. }
  358. if (success) {
  359. SendReply(GDB_STUB_REPLY_OK);
  360. } else {
  361. SendReply(GDB_STUB_REPLY_ERR);
  362. }
  363. }
  364. // Structure offsets are from Atmosphere
  365. // See osdbg_thread_local_region.os.horizon.hpp and osdbg_thread_type.os.horizon.hpp
  366. static std::optional<std::string> GetNameFromThreadType32(Core::Memory::Memory& memory,
  367. const Kernel::KThread* thread) {
  368. // Read thread type from TLS
  369. const VAddr tls_thread_type{memory.Read32(thread->GetTLSAddress() + 0x1fc)};
  370. const VAddr argument_thread_type{thread->GetArgument()};
  371. if (argument_thread_type && tls_thread_type != argument_thread_type) {
  372. // Probably not created by nnsdk, no name available.
  373. return std::nullopt;
  374. }
  375. if (!tls_thread_type) {
  376. return std::nullopt;
  377. }
  378. const u16 version{memory.Read16(tls_thread_type + 0x26)};
  379. VAddr name_pointer{};
  380. if (version == 1) {
  381. name_pointer = memory.Read32(tls_thread_type + 0xe4);
  382. } else {
  383. name_pointer = memory.Read32(tls_thread_type + 0xe8);
  384. }
  385. if (!name_pointer) {
  386. // No name provided.
  387. return std::nullopt;
  388. }
  389. return memory.ReadCString(name_pointer, 256);
  390. }
  391. static std::optional<std::string> GetNameFromThreadType64(Core::Memory::Memory& memory,
  392. const Kernel::KThread* thread) {
  393. // Read thread type from TLS
  394. const VAddr tls_thread_type{memory.Read64(thread->GetTLSAddress() + 0x1f8)};
  395. const VAddr argument_thread_type{thread->GetArgument()};
  396. if (argument_thread_type && tls_thread_type != argument_thread_type) {
  397. // Probably not created by nnsdk, no name available.
  398. return std::nullopt;
  399. }
  400. if (!tls_thread_type) {
  401. return std::nullopt;
  402. }
  403. const u16 version{memory.Read16(tls_thread_type + 0x46)};
  404. VAddr name_pointer{};
  405. if (version == 1) {
  406. name_pointer = memory.Read64(tls_thread_type + 0x1a0);
  407. } else {
  408. name_pointer = memory.Read64(tls_thread_type + 0x1a8);
  409. }
  410. if (!name_pointer) {
  411. // No name provided.
  412. return std::nullopt;
  413. }
  414. return memory.ReadCString(name_pointer, 256);
  415. }
  416. static std::optional<std::string> GetThreadName(Core::System& system,
  417. const Kernel::KThread* thread) {
  418. if (system.CurrentProcess()->Is64BitProcess()) {
  419. return GetNameFromThreadType64(system.Memory(), thread);
  420. } else {
  421. return GetNameFromThreadType32(system.Memory(), thread);
  422. }
  423. }
  424. static std::string_view GetThreadWaitReason(const Kernel::KThread* thread) {
  425. switch (thread->GetWaitReasonForDebugging()) {
  426. case Kernel::ThreadWaitReasonForDebugging::Sleep:
  427. return "Sleep";
  428. case Kernel::ThreadWaitReasonForDebugging::IPC:
  429. return "IPC";
  430. case Kernel::ThreadWaitReasonForDebugging::Synchronization:
  431. return "Synchronization";
  432. case Kernel::ThreadWaitReasonForDebugging::ConditionVar:
  433. return "ConditionVar";
  434. case Kernel::ThreadWaitReasonForDebugging::Arbitration:
  435. return "Arbitration";
  436. case Kernel::ThreadWaitReasonForDebugging::Suspended:
  437. return "Suspended";
  438. default:
  439. return "Unknown";
  440. }
  441. }
  442. static std::string GetThreadState(const Kernel::KThread* thread) {
  443. switch (thread->GetState()) {
  444. case Kernel::ThreadState::Initialized:
  445. return "Initialized";
  446. case Kernel::ThreadState::Waiting:
  447. return fmt::format("Waiting ({})", GetThreadWaitReason(thread));
  448. case Kernel::ThreadState::Runnable:
  449. return "Runnable";
  450. case Kernel::ThreadState::Terminated:
  451. return "Terminated";
  452. default:
  453. return "Unknown";
  454. }
  455. }
  456. static std::string PaginateBuffer(std::string_view buffer, std::string_view request) {
  457. const auto amount{request.substr(request.find(',') + 1)};
  458. const auto offset_val{static_cast<u64>(strtoll(request.data(), nullptr, 16))};
  459. const auto amount_val{static_cast<u64>(strtoll(amount.data(), nullptr, 16))};
  460. if (offset_val + amount_val > buffer.size()) {
  461. return fmt::format("l{}", buffer.substr(offset_val));
  462. } else {
  463. return fmt::format("m{}", buffer.substr(offset_val, amount_val));
  464. }
  465. }
  466. void GDBStub::HandleQuery(std::string_view command) {
  467. if (command.starts_with("TStatus")) {
  468. // no tracepoint support
  469. SendReply("T0");
  470. } else if (command.starts_with("Supported")) {
  471. SendReply("PacketSize=4000;qXfer:features:read+;qXfer:threads:read+;qXfer:libraries:read+;"
  472. "vContSupported+;QStartNoAckMode+");
  473. } else if (command.starts_with("Xfer:features:read:target.xml:")) {
  474. const auto target_xml{arch->GetTargetXML()};
  475. SendReply(PaginateBuffer(target_xml, command.substr(30)));
  476. } else if (command.starts_with("Offsets")) {
  477. Loader::AppLoader::Modules modules;
  478. system.GetAppLoader().ReadNSOModules(modules);
  479. const auto main = std::find_if(modules.begin(), modules.end(),
  480. [](const auto& key) { return key.second == "main"; });
  481. if (main != modules.end()) {
  482. SendReply(fmt::format("TextSeg={:x}", main->first));
  483. } else {
  484. SendReply(fmt::format("TextSeg={:x}",
  485. system.CurrentProcess()->PageTable().GetCodeRegionStart()));
  486. }
  487. } else if (command.starts_with("Xfer:libraries:read::")) {
  488. Loader::AppLoader::Modules modules;
  489. system.GetAppLoader().ReadNSOModules(modules);
  490. std::string buffer;
  491. buffer += R"(<?xml version="1.0"?>)";
  492. buffer += "<library-list>";
  493. for (const auto& [base, name] : modules) {
  494. buffer += fmt::format(R"(<library name="{}"><segment address="{:#x}"/></library>)",
  495. EscapeXML(name), base);
  496. }
  497. buffer += "</library-list>";
  498. SendReply(PaginateBuffer(buffer, command.substr(21)));
  499. } else if (command.starts_with("fThreadInfo")) {
  500. // beginning of list
  501. const auto& threads = system.GlobalSchedulerContext().GetThreadList();
  502. std::vector<std::string> thread_ids;
  503. for (const auto& thread : threads) {
  504. thread_ids.push_back(fmt::format("{:x}", thread->GetThreadID()));
  505. }
  506. SendReply(fmt::format("m{}", fmt::join(thread_ids, ",")));
  507. } else if (command.starts_with("sThreadInfo")) {
  508. // end of list
  509. SendReply("l");
  510. } else if (command.starts_with("Xfer:threads:read::")) {
  511. std::string buffer;
  512. buffer += R"(<?xml version="1.0"?>)";
  513. buffer += "<threads>";
  514. const auto& threads = system.GlobalSchedulerContext().GetThreadList();
  515. for (const auto* thread : threads) {
  516. auto thread_name{GetThreadName(system, thread)};
  517. if (!thread_name) {
  518. thread_name = fmt::format("Thread {:d}", thread->GetThreadID());
  519. }
  520. buffer += fmt::format(R"(<thread id="{:x}" core="{:d}" name="{}">{}</thread>)",
  521. thread->GetThreadID(), thread->GetActiveCore(),
  522. EscapeXML(*thread_name), GetThreadState(thread));
  523. }
  524. buffer += "</threads>";
  525. SendReply(PaginateBuffer(buffer, command.substr(19)));
  526. } else if (command.starts_with("Attached")) {
  527. SendReply("0");
  528. } else if (command.starts_with("StartNoAckMode")) {
  529. no_ack = true;
  530. SendReply(GDB_STUB_REPLY_OK);
  531. } else if (command.starts_with("Rcmd,")) {
  532. HandleRcmd(Common::HexStringToVector(command.substr(5), false));
  533. } else {
  534. SendReply(GDB_STUB_REPLY_EMPTY);
  535. }
  536. }
  537. void GDBStub::HandleVCont(std::string_view command, std::vector<DebuggerAction>& actions) {
  538. if (command == "?") {
  539. // Continuing and stepping are supported
  540. // (signal is ignored, but required for GDB to use vCont)
  541. SendReply("vCont;c;C;s;S");
  542. return;
  543. }
  544. Kernel::KThread* stepped_thread{nullptr};
  545. bool lock_execution{true};
  546. std::vector<std::string> entries;
  547. boost::split(entries, command.substr(1), boost::is_any_of(";"));
  548. for (const auto& thread_action : entries) {
  549. std::vector<std::string> parts;
  550. boost::split(parts, thread_action, boost::is_any_of(":"));
  551. if (parts.size() == 1 && (parts[0] == "c" || parts[0].starts_with("C"))) {
  552. lock_execution = false;
  553. }
  554. if (parts.size() == 2 && (parts[0] == "s" || parts[0].starts_with("S"))) {
  555. stepped_thread = GetThreadByID(strtoll(parts[1].data(), nullptr, 16));
  556. }
  557. }
  558. if (stepped_thread) {
  559. backend.SetActiveThread(stepped_thread);
  560. actions.push_back(lock_execution ? DebuggerAction::StepThreadLocked
  561. : DebuggerAction::StepThreadUnlocked);
  562. } else {
  563. actions.push_back(DebuggerAction::Continue);
  564. }
  565. }
  566. constexpr std::array<std::pair<const char*, Kernel::Svc::MemoryState>, 22> MemoryStateNames{{
  567. {"----- Free -----", Kernel::Svc::MemoryState::Free},
  568. {"Io ", Kernel::Svc::MemoryState::Io},
  569. {"Static ", Kernel::Svc::MemoryState::Static},
  570. {"Code ", Kernel::Svc::MemoryState::Code},
  571. {"CodeData ", Kernel::Svc::MemoryState::CodeData},
  572. {"Normal ", Kernel::Svc::MemoryState::Normal},
  573. {"Shared ", Kernel::Svc::MemoryState::Shared},
  574. {"AliasCode ", Kernel::Svc::MemoryState::AliasCode},
  575. {"AliasCodeData ", Kernel::Svc::MemoryState::AliasCodeData},
  576. {"Ipc ", Kernel::Svc::MemoryState::Ipc},
  577. {"Stack ", Kernel::Svc::MemoryState::Stack},
  578. {"ThreadLocal ", Kernel::Svc::MemoryState::ThreadLocal},
  579. {"Transfered ", Kernel::Svc::MemoryState::Transfered},
  580. {"SharedTransfered", Kernel::Svc::MemoryState::SharedTransfered},
  581. {"SharedCode ", Kernel::Svc::MemoryState::SharedCode},
  582. {"Inaccessible ", Kernel::Svc::MemoryState::Inaccessible},
  583. {"NonSecureIpc ", Kernel::Svc::MemoryState::NonSecureIpc},
  584. {"NonDeviceIpc ", Kernel::Svc::MemoryState::NonDeviceIpc},
  585. {"Kernel ", Kernel::Svc::MemoryState::Kernel},
  586. {"GeneratedCode ", Kernel::Svc::MemoryState::GeneratedCode},
  587. {"CodeOut ", Kernel::Svc::MemoryState::CodeOut},
  588. {"Coverage ", Kernel::Svc::MemoryState::Coverage},
  589. }};
  590. static constexpr const char* GetMemoryStateName(Kernel::Svc::MemoryState state) {
  591. for (size_t i = 0; i < MemoryStateNames.size(); i++) {
  592. if (std::get<1>(MemoryStateNames[i]) == state) {
  593. return std::get<0>(MemoryStateNames[i]);
  594. }
  595. }
  596. return "Unknown ";
  597. }
  598. static constexpr const char* GetMemoryPermissionString(const Kernel::Svc::MemoryInfo& info) {
  599. if (info.state == Kernel::Svc::MemoryState::Free) {
  600. return " ";
  601. }
  602. switch (info.permission) {
  603. case Kernel::Svc::MemoryPermission::ReadExecute:
  604. return "r-x";
  605. case Kernel::Svc::MemoryPermission::Read:
  606. return "r--";
  607. case Kernel::Svc::MemoryPermission::ReadWrite:
  608. return "rw-";
  609. default:
  610. return "---";
  611. }
  612. }
  613. static VAddr GetModuleEnd(Kernel::KPageTable& page_table, VAddr base) {
  614. Kernel::Svc::MemoryInfo mem_info;
  615. VAddr cur_addr{base};
  616. // Expect: r-x Code (.text)
  617. mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo();
  618. cur_addr = mem_info.base_address + mem_info.size;
  619. if (mem_info.state != Kernel::Svc::MemoryState::Code ||
  620. mem_info.permission != Kernel::Svc::MemoryPermission::ReadExecute) {
  621. return cur_addr - 1;
  622. }
  623. // Expect: r-- Code (.rodata)
  624. mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo();
  625. cur_addr = mem_info.base_address + mem_info.size;
  626. if (mem_info.state != Kernel::Svc::MemoryState::Code ||
  627. mem_info.permission != Kernel::Svc::MemoryPermission::Read) {
  628. return cur_addr - 1;
  629. }
  630. // Expect: rw- CodeData (.data)
  631. mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo();
  632. cur_addr = mem_info.base_address + mem_info.size;
  633. return cur_addr - 1;
  634. }
  635. void GDBStub::HandleRcmd(const std::vector<u8>& command) {
  636. std::string_view command_str{reinterpret_cast<const char*>(&command[0]), command.size()};
  637. std::string reply;
  638. auto* process = system.CurrentProcess();
  639. auto& page_table = process->PageTable();
  640. if (command_str == "get info") {
  641. Loader::AppLoader::Modules modules;
  642. system.GetAppLoader().ReadNSOModules(modules);
  643. reply = fmt::format("Process: {:#x} ({})\n"
  644. "Program Id: {:#018x}\n",
  645. process->GetProcessID(), process->GetName(), process->GetProgramID());
  646. reply +=
  647. fmt::format("Layout:\n"
  648. " Alias: {:#012x} - {:#012x}\n"
  649. " Heap: {:#012x} - {:#012x}\n"
  650. " Aslr: {:#012x} - {:#012x}\n"
  651. " Stack: {:#012x} - {:#012x}\n"
  652. "Modules:\n",
  653. page_table.GetAliasRegionStart(), page_table.GetAliasRegionEnd(),
  654. page_table.GetHeapRegionStart(), page_table.GetHeapRegionEnd(),
  655. page_table.GetAliasCodeRegionStart(), page_table.GetAliasCodeRegionEnd(),
  656. page_table.GetStackRegionStart(), page_table.GetStackRegionEnd());
  657. for (const auto& [vaddr, name] : modules) {
  658. reply += fmt::format(" {:#012x} - {:#012x} {}\n", vaddr,
  659. GetModuleEnd(page_table, vaddr), name);
  660. }
  661. } else if (command_str == "get mappings") {
  662. reply = "Mappings:\n";
  663. VAddr cur_addr = 0;
  664. while (true) {
  665. using MemoryAttribute = Kernel::Svc::MemoryAttribute;
  666. auto mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo();
  667. if (mem_info.state != Kernel::Svc::MemoryState::Inaccessible ||
  668. mem_info.base_address + mem_info.size - 1 != std::numeric_limits<u64>::max()) {
  669. const char* state = GetMemoryStateName(mem_info.state);
  670. const char* perm = GetMemoryPermissionString(mem_info);
  671. const char l = True(mem_info.attribute & MemoryAttribute::Locked) ? 'L' : '-';
  672. const char i = True(mem_info.attribute & MemoryAttribute::IpcLocked) ? 'I' : '-';
  673. const char d = True(mem_info.attribute & MemoryAttribute::DeviceShared) ? 'D' : '-';
  674. const char u = True(mem_info.attribute & MemoryAttribute::Uncached) ? 'U' : '-';
  675. reply +=
  676. fmt::format(" {:#012x} - {:#012x} {} {} {}{}{}{} [{}, {}]\n",
  677. mem_info.base_address, mem_info.base_address + mem_info.size - 1,
  678. perm, state, l, i, d, u, mem_info.ipc_count, mem_info.device_count);
  679. }
  680. const uintptr_t next_address = mem_info.base_address + mem_info.size;
  681. if (next_address <= cur_addr) {
  682. break;
  683. }
  684. cur_addr = next_address;
  685. }
  686. } else if (command_str == "help") {
  687. reply = "Commands:\n get info\n get mappings\n";
  688. } else {
  689. reply = "Unknown command.\nCommands:\n get info\n get mappings\n";
  690. }
  691. std::span<const u8> reply_span{reinterpret_cast<u8*>(&reply.front()), reply.size()};
  692. SendReply(Common::HexToString(reply_span, false));
  693. }
  694. Kernel::KThread* GDBStub::GetThreadByID(u64 thread_id) {
  695. const auto& threads{system.GlobalSchedulerContext().GetThreadList()};
  696. for (auto* thread : threads) {
  697. if (thread->GetThreadID() == thread_id) {
  698. return thread;
  699. }
  700. }
  701. return nullptr;
  702. }
  703. std::vector<char>::const_iterator GDBStub::CommandEnd() const {
  704. // Find the end marker
  705. const auto end{std::find(current_command.begin(), current_command.end(), GDB_STUB_END)};
  706. // Require the checksum to be present
  707. return std::min(end + 2, current_command.end());
  708. }
  709. std::optional<std::string> GDBStub::DetachCommand() {
  710. // Slice the string part from the beginning to the end marker
  711. const auto end{CommandEnd()};
  712. // Extract possible command data
  713. std::string data(current_command.data(), end - current_command.begin() + 1);
  714. // Shift over the remaining contents
  715. current_command.erase(current_command.begin(), end + 1);
  716. // Validate received command
  717. if (data[0] != GDB_STUB_START) {
  718. LOG_ERROR(Debug_GDBStub, "Invalid start data: {}", data[0]);
  719. return std::nullopt;
  720. }
  721. u8 calculated = CalculateChecksum(std::string_view(data).substr(1, data.size() - 4));
  722. u8 received = static_cast<u8>(strtoll(data.data() + data.size() - 2, nullptr, 16));
  723. // Verify checksum
  724. if (calculated != received) {
  725. LOG_ERROR(Debug_GDBStub, "Checksum mismatch: calculated {:02x}, received {:02x}",
  726. calculated, received);
  727. return std::nullopt;
  728. }
  729. return data.substr(1, data.size() - 4);
  730. }
  731. void GDBStub::SendReply(std::string_view data) {
  732. const auto escaped{EscapeGDB(data)};
  733. const auto output{fmt::format("{}{}{}{:02x}", GDB_STUB_START, escaped, GDB_STUB_END,
  734. CalculateChecksum(escaped))};
  735. LOG_TRACE(Debug_GDBStub, "Writing reply: {}", output);
  736. // C++ string support is complete rubbish
  737. const u8* output_begin = reinterpret_cast<const u8*>(output.data());
  738. const u8* output_end = output_begin + output.size();
  739. backend.WriteToClient(std::span<const u8>(output_begin, output_end));
  740. }
  741. void GDBStub::SendStatus(char status) {
  742. if (no_ack) {
  743. return;
  744. }
  745. std::array<u8, 1> buf = {static_cast<u8>(status)};
  746. LOG_TRACE(Debug_GDBStub, "Writing status: {}", status);
  747. backend.WriteToClient(buf);
  748. }
  749. } // namespace Core