summaryrefslogtreecommitdiff
path: root/src/core/debugger/gdbstub.cpp
diff options
context:
space:
mode:
authorGravatar Narr the Reg2022-11-20 09:31:20 -0600
committerGravatar GitHub2022-11-20 09:31:20 -0600
commitdb7bcd51ae09c4ef25e08096de563903f61e2380 (patch)
tree5ae9977b48e1aff118fae3ebffb215b0b4afa887 /src/core/debugger/gdbstub.cpp
parentservice: nfc: Implement nfc user (diff)
parentMerge pull request #9238 from german77/cabinet_applet (diff)
downloadyuzu-db7bcd51ae09c4ef25e08096de563903f61e2380.tar.gz
yuzu-db7bcd51ae09c4ef25e08096de563903f61e2380.tar.xz
yuzu-db7bcd51ae09c4ef25e08096de563903f61e2380.zip
Merge branch 'master' into nfc_impl
Diffstat (limited to 'src/core/debugger/gdbstub.cpp')
-rw-r--r--src/core/debugger/gdbstub.cpp151
1 files changed, 151 insertions, 0 deletions
diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp
index 884229c77..a64a9ac64 100644
--- a/src/core/debugger/gdbstub.cpp
+++ b/src/core/debugger/gdbstub.cpp
@@ -606,6 +606,8 @@ void GDBStub::HandleQuery(std::string_view command) {
606 } else if (command.starts_with("StartNoAckMode")) { 606 } else if (command.starts_with("StartNoAckMode")) {
607 no_ack = true; 607 no_ack = true;
608 SendReply(GDB_STUB_REPLY_OK); 608 SendReply(GDB_STUB_REPLY_OK);
609 } else if (command.starts_with("Rcmd,")) {
610 HandleRcmd(Common::HexStringToVector(command.substr(5), false));
609 } else { 611 } else {
610 SendReply(GDB_STUB_REPLY_EMPTY); 612 SendReply(GDB_STUB_REPLY_EMPTY);
611 } 613 }
@@ -645,6 +647,155 @@ void GDBStub::HandleVCont(std::string_view command, std::vector<DebuggerAction>&
645 } 647 }
646} 648}
647 649
650constexpr std::array<std::pair<const char*, Kernel::Svc::MemoryState>, 22> MemoryStateNames{{
651 {"----- Free -----", Kernel::Svc::MemoryState::Free},
652 {"Io ", Kernel::Svc::MemoryState::Io},
653 {"Static ", Kernel::Svc::MemoryState::Static},
654 {"Code ", Kernel::Svc::MemoryState::Code},
655 {"CodeData ", Kernel::Svc::MemoryState::CodeData},
656 {"Normal ", Kernel::Svc::MemoryState::Normal},
657 {"Shared ", Kernel::Svc::MemoryState::Shared},
658 {"AliasCode ", Kernel::Svc::MemoryState::AliasCode},
659 {"AliasCodeData ", Kernel::Svc::MemoryState::AliasCodeData},
660 {"Ipc ", Kernel::Svc::MemoryState::Ipc},
661 {"Stack ", Kernel::Svc::MemoryState::Stack},
662 {"ThreadLocal ", Kernel::Svc::MemoryState::ThreadLocal},
663 {"Transfered ", Kernel::Svc::MemoryState::Transfered},
664 {"SharedTransfered", Kernel::Svc::MemoryState::SharedTransfered},
665 {"SharedCode ", Kernel::Svc::MemoryState::SharedCode},
666 {"Inaccessible ", Kernel::Svc::MemoryState::Inaccessible},
667 {"NonSecureIpc ", Kernel::Svc::MemoryState::NonSecureIpc},
668 {"NonDeviceIpc ", Kernel::Svc::MemoryState::NonDeviceIpc},
669 {"Kernel ", Kernel::Svc::MemoryState::Kernel},
670 {"GeneratedCode ", Kernel::Svc::MemoryState::GeneratedCode},
671 {"CodeOut ", Kernel::Svc::MemoryState::CodeOut},
672 {"Coverage ", Kernel::Svc::MemoryState::Coverage},
673}};
674
675static constexpr const char* GetMemoryStateName(Kernel::Svc::MemoryState state) {
676 for (size_t i = 0; i < MemoryStateNames.size(); i++) {
677 if (std::get<1>(MemoryStateNames[i]) == state) {
678 return std::get<0>(MemoryStateNames[i]);
679 }
680 }
681 return "Unknown ";
682}
683
684static constexpr const char* GetMemoryPermissionString(const Kernel::Svc::MemoryInfo& info) {
685 if (info.state == Kernel::Svc::MemoryState::Free) {
686 return " ";
687 }
688
689 switch (info.permission) {
690 case Kernel::Svc::MemoryPermission::ReadExecute:
691 return "r-x";
692 case Kernel::Svc::MemoryPermission::Read:
693 return "r--";
694 case Kernel::Svc::MemoryPermission::ReadWrite:
695 return "rw-";
696 default:
697 return "---";
698 }
699}
700
701static VAddr GetModuleEnd(Kernel::KPageTable& page_table, VAddr base) {
702 Kernel::Svc::MemoryInfo mem_info;
703 VAddr cur_addr{base};
704
705 // Expect: r-x Code (.text)
706 mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo();
707 cur_addr = mem_info.base_address + mem_info.size;
708 if (mem_info.state != Kernel::Svc::MemoryState::Code ||
709 mem_info.permission != Kernel::Svc::MemoryPermission::ReadExecute) {
710 return cur_addr - 1;
711 }
712
713 // Expect: r-- Code (.rodata)
714 mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo();
715 cur_addr = mem_info.base_address + mem_info.size;
716 if (mem_info.state != Kernel::Svc::MemoryState::Code ||
717 mem_info.permission != Kernel::Svc::MemoryPermission::Read) {
718 return cur_addr - 1;
719 }
720
721 // Expect: rw- CodeData (.data)
722 mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo();
723 cur_addr = mem_info.base_address + mem_info.size;
724 return cur_addr - 1;
725}
726
727void GDBStub::HandleRcmd(const std::vector<u8>& command) {
728 std::string_view command_str{reinterpret_cast<const char*>(&command[0]), command.size()};
729 std::string reply;
730
731 auto* process = system.CurrentProcess();
732 auto& page_table = process->PageTable();
733
734 if (command_str == "get info") {
735 Loader::AppLoader::Modules modules;
736 system.GetAppLoader().ReadNSOModules(modules);
737
738 reply = fmt::format("Process: {:#x} ({})\n"
739 "Program Id: {:#018x}\n",
740 process->GetProcessID(), process->GetName(), process->GetProgramID());
741 reply +=
742 fmt::format("Layout:\n"
743 " Alias: {:#012x} - {:#012x}\n"
744 " Heap: {:#012x} - {:#012x}\n"
745 " Aslr: {:#012x} - {:#012x}\n"
746 " Stack: {:#012x} - {:#012x}\n"
747 "Modules:\n",
748 page_table.GetAliasRegionStart(), page_table.GetAliasRegionEnd(),
749 page_table.GetHeapRegionStart(), page_table.GetHeapRegionEnd(),
750 page_table.GetAliasCodeRegionStart(), page_table.GetAliasCodeRegionEnd(),
751 page_table.GetStackRegionStart(), page_table.GetStackRegionEnd());
752
753 for (const auto& [vaddr, name] : modules) {
754 reply += fmt::format(" {:#012x} - {:#012x} {}\n", vaddr,
755 GetModuleEnd(page_table, vaddr), name);
756 }
757 } else if (command_str == "get mappings") {
758 reply = "Mappings:\n";
759 VAddr cur_addr = 0;
760
761 while (true) {
762 using MemoryAttribute = Kernel::Svc::MemoryAttribute;
763
764 auto mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo();
765
766 if (mem_info.state != Kernel::Svc::MemoryState::Inaccessible ||
767 mem_info.base_address + mem_info.size - 1 != std::numeric_limits<u64>::max()) {
768 const char* state = GetMemoryStateName(mem_info.state);
769 const char* perm = GetMemoryPermissionString(mem_info);
770
771 const char l = True(mem_info.attribute & MemoryAttribute::Locked) ? 'L' : '-';
772 const char i = True(mem_info.attribute & MemoryAttribute::IpcLocked) ? 'I' : '-';
773 const char d = True(mem_info.attribute & MemoryAttribute::DeviceShared) ? 'D' : '-';
774 const char u = True(mem_info.attribute & MemoryAttribute::Uncached) ? 'U' : '-';
775
776 reply +=
777 fmt::format(" {:#012x} - {:#012x} {} {} {}{}{}{} [{}, {}]\n",
778 mem_info.base_address, mem_info.base_address + mem_info.size - 1,
779 perm, state, l, i, d, u, mem_info.ipc_count, mem_info.device_count);
780 }
781
782 const uintptr_t next_address = mem_info.base_address + mem_info.size;
783 if (next_address <= cur_addr) {
784 break;
785 }
786
787 cur_addr = next_address;
788 }
789 } else if (command_str == "help") {
790 reply = "Commands:\n get info\n get mappings\n";
791 } else {
792 reply = "Unknown command.\nCommands:\n get info\n get mappings\n";
793 }
794
795 std::span<const u8> reply_span{reinterpret_cast<u8*>(&reply.front()), reply.size()};
796 SendReply(Common::HexToString(reply_span, false));
797}
798
648Kernel::KThread* GDBStub::GetThreadByID(u64 thread_id) { 799Kernel::KThread* GDBStub::GetThreadByID(u64 thread_id) {
649 const auto& threads{system.GlobalSchedulerContext().GetThreadList()}; 800 const auto& threads{system.GlobalSchedulerContext().GetThreadList()};
650 for (auto* thread : threads) { 801 for (auto* thread : threads) {