summaryrefslogtreecommitdiff
path: root/src/core/debugger/gdbstub.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/debugger/gdbstub.cpp')
-rw-r--r--src/core/debugger/gdbstub.cpp233
1 files changed, 159 insertions, 74 deletions
diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp
index 6f5f5156b..148dd3e39 100644
--- a/src/core/debugger/gdbstub.cpp
+++ b/src/core/debugger/gdbstub.cpp
@@ -562,6 +562,120 @@ static std::string PaginateBuffer(std::string_view buffer, std::string_view requ
562 } 562 }
563} 563}
564 564
565static VAddr GetModuleEnd(Kernel::KProcessPageTable& page_table, VAddr base) {
566 Kernel::KMemoryInfo mem_info;
567 Kernel::Svc::MemoryInfo svc_mem_info;
568 Kernel::Svc::PageInfo page_info;
569 VAddr cur_addr{base};
570
571 // Expect: r-x Code (.text)
572 R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr));
573 svc_mem_info = mem_info.GetSvcMemoryInfo();
574 cur_addr = svc_mem_info.base_address + svc_mem_info.size;
575 if (svc_mem_info.state != Kernel::Svc::MemoryState::Code ||
576 svc_mem_info.permission != Kernel::Svc::MemoryPermission::ReadExecute) {
577 return cur_addr - 1;
578 }
579
580 // Expect: r-- Code (.rodata)
581 R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr));
582 svc_mem_info = mem_info.GetSvcMemoryInfo();
583 cur_addr = svc_mem_info.base_address + svc_mem_info.size;
584 if (svc_mem_info.state != Kernel::Svc::MemoryState::Code ||
585 svc_mem_info.permission != Kernel::Svc::MemoryPermission::Read) {
586 return cur_addr - 1;
587 }
588
589 // Expect: rw- CodeData (.data)
590 R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr));
591 svc_mem_info = mem_info.GetSvcMemoryInfo();
592 cur_addr = svc_mem_info.base_address + svc_mem_info.size;
593 return cur_addr - 1;
594}
595
596static Loader::AppLoader::Modules FindModules(Core::System& system) {
597 Loader::AppLoader::Modules modules;
598
599 auto& page_table = system.ApplicationProcess()->GetPageTable();
600 auto& memory = system.ApplicationMemory();
601 VAddr cur_addr = 0;
602
603 // Look for executable sections in Code or AliasCode regions.
604 while (true) {
605 Kernel::KMemoryInfo mem_info{};
606 Kernel::Svc::PageInfo page_info{};
607 R_ASSERT(
608 page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr));
609 auto svc_mem_info = mem_info.GetSvcMemoryInfo();
610
611 if (svc_mem_info.permission == Kernel::Svc::MemoryPermission::ReadExecute &&
612 (svc_mem_info.state == Kernel::Svc::MemoryState::Code ||
613 svc_mem_info.state == Kernel::Svc::MemoryState::AliasCode)) {
614 // Try to read the module name from its path.
615 constexpr s32 PathLengthMax = 0x200;
616 struct {
617 u32 zero;
618 s32 path_length;
619 std::array<char, PathLengthMax> path;
620 } module_path;
621
622 if (memory.ReadBlock(svc_mem_info.base_address + svc_mem_info.size, &module_path,
623 sizeof(module_path))) {
624 if (module_path.zero == 0 && module_path.path_length > 0) {
625 // Truncate module name.
626 module_path.path[PathLengthMax - 1] = '\0';
627
628 // Ignore leading directories.
629 char* path_pointer = module_path.path.data();
630
631 for (s32 i = 0; i < std::min(PathLengthMax, module_path.path_length) &&
632 module_path.path[i] != '\0';
633 i++) {
634 if (module_path.path[i] == '/' || module_path.path[i] == '\\') {
635 path_pointer = module_path.path.data() + i + 1;
636 }
637 }
638
639 // Insert output.
640 modules.emplace(svc_mem_info.base_address, path_pointer);
641 }
642 }
643 }
644
645 // Check if we're done.
646 const uintptr_t next_address = svc_mem_info.base_address + svc_mem_info.size;
647 if (next_address <= cur_addr) {
648 break;
649 }
650
651 cur_addr = next_address;
652 }
653
654 return modules;
655}
656
657static VAddr FindMainModuleEntrypoint(Core::System& system) {
658 Loader::AppLoader::Modules modules;
659 system.GetAppLoader().ReadNSOModules(modules);
660
661 // Do we have a module named main?
662 const auto main = std::find_if(modules.begin(), modules.end(),
663 [](const auto& key) { return key.second == "main"; });
664
665 if (main != modules.end()) {
666 return main->first;
667 }
668
669 // Do we have any loaded executable sections?
670 modules = FindModules(system);
671 if (!modules.empty()) {
672 return modules.begin()->first;
673 }
674
675 // As a last resort, use the start of the code region.
676 return GetInteger(system.ApplicationProcess()->GetPageTable().GetCodeRegionStart());
677}
678
565void GDBStub::HandleQuery(std::string_view command) { 679void GDBStub::HandleQuery(std::string_view command) {
566 if (command.starts_with("TStatus")) { 680 if (command.starts_with("TStatus")) {
567 // no tracepoint support 681 // no tracepoint support
@@ -573,21 +687,10 @@ void GDBStub::HandleQuery(std::string_view command) {
573 const auto target_xml{arch->GetTargetXML()}; 687 const auto target_xml{arch->GetTargetXML()};
574 SendReply(PaginateBuffer(target_xml, command.substr(30))); 688 SendReply(PaginateBuffer(target_xml, command.substr(30)));
575 } else if (command.starts_with("Offsets")) { 689 } else if (command.starts_with("Offsets")) {
576 Loader::AppLoader::Modules modules; 690 const auto main_offset = FindMainModuleEntrypoint(system);
577 system.GetAppLoader().ReadNSOModules(modules); 691 SendReply(fmt::format("TextSeg={:x}", main_offset));
578
579 const auto main = std::find_if(modules.begin(), modules.end(),
580 [](const auto& key) { return key.second == "main"; });
581 if (main != modules.end()) {
582 SendReply(fmt::format("TextSeg={:x}", main->first));
583 } else {
584 SendReply(fmt::format(
585 "TextSeg={:x}",
586 GetInteger(system.ApplicationProcess()->GetPageTable().GetCodeRegionStart())));
587 }
588 } else if (command.starts_with("Xfer:libraries:read::")) { 692 } else if (command.starts_with("Xfer:libraries:read::")) {
589 Loader::AppLoader::Modules modules; 693 auto modules = FindModules(system);
590 system.GetAppLoader().ReadNSOModules(modules);
591 694
592 std::string buffer; 695 std::string buffer;
593 buffer += R"(<?xml version="1.0"?>)"; 696 buffer += R"(<?xml version="1.0"?>)";
@@ -727,32 +830,6 @@ static constexpr const char* GetMemoryPermissionString(const Kernel::Svc::Memory
727 } 830 }
728} 831}
729 832
730static VAddr GetModuleEnd(Kernel::KPageTable& page_table, VAddr base) {
731 Kernel::Svc::MemoryInfo mem_info;
732 VAddr cur_addr{base};
733
734 // Expect: r-x Code (.text)
735 mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo();
736 cur_addr = mem_info.base_address + mem_info.size;
737 if (mem_info.state != Kernel::Svc::MemoryState::Code ||
738 mem_info.permission != Kernel::Svc::MemoryPermission::ReadExecute) {
739 return cur_addr - 1;
740 }
741
742 // Expect: r-- Code (.rodata)
743 mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo();
744 cur_addr = mem_info.base_address + mem_info.size;
745 if (mem_info.state != Kernel::Svc::MemoryState::Code ||
746 mem_info.permission != Kernel::Svc::MemoryPermission::Read) {
747 return cur_addr - 1;
748 }
749
750 // Expect: rw- CodeData (.data)
751 mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo();
752 cur_addr = mem_info.base_address + mem_info.size;
753 return cur_addr - 1;
754}
755
756void GDBStub::HandleRcmd(const std::vector<u8>& command) { 833void GDBStub::HandleRcmd(const std::vector<u8>& command) {
757 std::string_view command_str{reinterpret_cast<const char*>(&command[0]), command.size()}; 834 std::string_view command_str{reinterpret_cast<const char*>(&command[0]), command.size()};
758 std::string reply; 835 std::string reply;
@@ -767,7 +844,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
767 844
768 if (command_str == "get fastmem") { 845 if (command_str == "get fastmem") {
769 if (Settings::IsFastmemEnabled()) { 846 if (Settings::IsFastmemEnabled()) {
770 const auto& impl = page_table.PageTableImpl(); 847 const auto& impl = page_table.GetImpl();
771 const auto region = reinterpret_cast<uintptr_t>(impl.fastmem_arena); 848 const auto region = reinterpret_cast<uintptr_t>(impl.fastmem_arena);
772 const auto region_bits = impl.current_address_space_width_in_bits; 849 const auto region_bits = impl.current_address_space_width_in_bits;
773 const auto region_size = 1ULL << region_bits; 850 const auto region_size = 1ULL << region_bits;
@@ -779,26 +856,27 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
779 reply = "Fastmem is not enabled.\n"; 856 reply = "Fastmem is not enabled.\n";
780 } 857 }
781 } else if (command_str == "get info") { 858 } else if (command_str == "get info") {
782 Loader::AppLoader::Modules modules; 859 auto modules = FindModules(system);
783 system.GetAppLoader().ReadNSOModules(modules);
784 860
785 reply = fmt::format("Process: {:#x} ({})\n" 861 reply = fmt::format("Process: {:#x} ({})\n"
786 "Program Id: {:#018x}\n", 862 "Program Id: {:#018x}\n",
787 process->GetProcessId(), process->GetName(), process->GetProgramId()); 863 process->GetProcessId(), process->GetName(), process->GetProgramId());
788 reply += fmt::format("Layout:\n" 864 reply += fmt::format(
789 " Alias: {:#012x} - {:#012x}\n" 865 "Layout:\n"
790 " Heap: {:#012x} - {:#012x}\n" 866 " Alias: {:#012x} - {:#012x}\n"
791 " Aslr: {:#012x} - {:#012x}\n" 867 " Heap: {:#012x} - {:#012x}\n"
792 " Stack: {:#012x} - {:#012x}\n" 868 " Aslr: {:#012x} - {:#012x}\n"
793 "Modules:\n", 869 " Stack: {:#012x} - {:#012x}\n"
794 GetInteger(page_table.GetAliasRegionStart()), 870 "Modules:\n",
795 GetInteger(page_table.GetAliasRegionEnd()), 871 GetInteger(page_table.GetAliasRegionStart()),
796 GetInteger(page_table.GetHeapRegionStart()), 872 GetInteger(page_table.GetAliasRegionStart()) + page_table.GetAliasRegionSize() - 1,
797 GetInteger(page_table.GetHeapRegionEnd()), 873 GetInteger(page_table.GetHeapRegionStart()),
798 GetInteger(page_table.GetAliasCodeRegionStart()), 874 GetInteger(page_table.GetHeapRegionStart()) + page_table.GetHeapRegionSize() - 1,
799 GetInteger(page_table.GetAliasCodeRegionEnd()), 875 GetInteger(page_table.GetAliasCodeRegionStart()),
800 GetInteger(page_table.GetStackRegionStart()), 876 GetInteger(page_table.GetAliasCodeRegionStart()) + page_table.GetAliasCodeRegionSize() -
801 GetInteger(page_table.GetStackRegionEnd())); 877 1,
878 GetInteger(page_table.GetStackRegionStart()),
879 GetInteger(page_table.GetStackRegionStart()) + page_table.GetStackRegionSize() - 1);
802 880
803 for (const auto& [vaddr, name] : modules) { 881 for (const auto& [vaddr, name] : modules) {
804 reply += fmt::format(" {:#012x} - {:#012x} {}\n", vaddr, 882 reply += fmt::format(" {:#012x} - {:#012x} {}\n", vaddr,
@@ -811,27 +889,34 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) {
811 while (true) { 889 while (true) {
812 using MemoryAttribute = Kernel::Svc::MemoryAttribute; 890 using MemoryAttribute = Kernel::Svc::MemoryAttribute;
813 891
814 auto mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo(); 892 Kernel::KMemoryInfo mem_info{};
815 893 Kernel::Svc::PageInfo page_info{};
816 if (mem_info.state != Kernel::Svc::MemoryState::Inaccessible || 894 R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info),
817 mem_info.base_address + mem_info.size - 1 != std::numeric_limits<u64>::max()) { 895 cur_addr));
818 const char* state = GetMemoryStateName(mem_info.state); 896 auto svc_mem_info = mem_info.GetSvcMemoryInfo();
819 const char* perm = GetMemoryPermissionString(mem_info); 897
820 898 if (svc_mem_info.state != Kernel::Svc::MemoryState::Inaccessible ||
821 const char l = True(mem_info.attribute & MemoryAttribute::Locked) ? 'L' : '-'; 899 svc_mem_info.base_address + svc_mem_info.size - 1 !=
822 const char i = True(mem_info.attribute & MemoryAttribute::IpcLocked) ? 'I' : '-'; 900 std::numeric_limits<u64>::max()) {
823 const char d = True(mem_info.attribute & MemoryAttribute::DeviceShared) ? 'D' : '-'; 901 const char* state = GetMemoryStateName(svc_mem_info.state);
824 const char u = True(mem_info.attribute & MemoryAttribute::Uncached) ? 'U' : '-'; 902 const char* perm = GetMemoryPermissionString(svc_mem_info);
903
904 const char l = True(svc_mem_info.attribute & MemoryAttribute::Locked) ? 'L' : '-';
905 const char i =
906 True(svc_mem_info.attribute & MemoryAttribute::IpcLocked) ? 'I' : '-';
907 const char d =
908 True(svc_mem_info.attribute & MemoryAttribute::DeviceShared) ? 'D' : '-';
909 const char u = True(svc_mem_info.attribute & MemoryAttribute::Uncached) ? 'U' : '-';
825 const char p = 910 const char p =
826 True(mem_info.attribute & MemoryAttribute::PermissionLocked) ? 'P' : '-'; 911 True(svc_mem_info.attribute & MemoryAttribute::PermissionLocked) ? 'P' : '-';
827 912
828 reply += fmt::format(" {:#012x} - {:#012x} {} {} {}{}{}{}{} [{}, {}]\n", 913 reply += fmt::format(
829 mem_info.base_address, 914 " {:#012x} - {:#012x} {} {} {}{}{}{}{} [{}, {}]\n", svc_mem_info.base_address,
830 mem_info.base_address + mem_info.size - 1, perm, state, l, i, 915 svc_mem_info.base_address + svc_mem_info.size - 1, perm, state, l, i, d, u, p,
831 d, u, p, mem_info.ipc_count, mem_info.device_count); 916 svc_mem_info.ipc_count, svc_mem_info.device_count);
832 } 917 }
833 918
834 const uintptr_t next_address = mem_info.base_address + mem_info.size; 919 const uintptr_t next_address = svc_mem_info.base_address + svc_mem_info.size;
835 if (next_address <= cur_addr) { 920 if (next_address <= cur_addr) {
836 break; 921 break;
837 } 922 }