diff options
| author | 2022-11-20 09:31:20 -0600 | |
|---|---|---|
| committer | 2022-11-20 09:31:20 -0600 | |
| commit | db7bcd51ae09c4ef25e08096de563903f61e2380 (patch) | |
| tree | 5ae9977b48e1aff118fae3ebffb215b0b4afa887 /src/core/debugger/gdbstub.cpp | |
| parent | service: nfc: Implement nfc user (diff) | |
| parent | Merge pull request #9238 from german77/cabinet_applet (diff) | |
| download | yuzu-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.cpp | 151 |
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 | ||
| 650 | constexpr 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 | |||
| 675 | static 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 | |||
| 684 | static 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 | |||
| 701 | static 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 | |||
| 727 | void 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 | |||
| 648 | Kernel::KThread* GDBStub::GetThreadByID(u64 thread_id) { | 799 | Kernel::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) { |