diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/android/app/src/main/jni/emu_window/emu_window.cpp | 8 | ||||
| -rw-r--r-- | src/android/app/src/main/jni/emu_window/emu_window.h | 4 | ||||
| -rw-r--r-- | src/android/app/src/main/jni/native.cpp | 2 | ||||
| -rw-r--r-- | src/android/app/src/main/jni/native.h | 3 | ||||
| -rw-r--r-- | src/core/debugger/gdbstub.cpp | 165 |
5 files changed, 131 insertions, 51 deletions
diff --git a/src/android/app/src/main/jni/emu_window/emu_window.cpp b/src/android/app/src/main/jni/emu_window/emu_window.cpp index a7e414b81..c4f631924 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window.cpp +++ b/src/android/app/src/main/jni/emu_window/emu_window.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "input_common/drivers/virtual_gamepad.h" | 9 | #include "input_common/drivers/virtual_gamepad.h" |
| 10 | #include "input_common/main.h" | 10 | #include "input_common/main.h" |
| 11 | #include "jni/emu_window/emu_window.h" | 11 | #include "jni/emu_window/emu_window.h" |
| 12 | #include "jni/native.h" | ||
| 12 | 13 | ||
| 13 | void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) { | 14 | void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) { |
| 14 | m_window_width = ANativeWindow_getWidth(surface); | 15 | m_window_width = ANativeWindow_getWidth(surface); |
| @@ -57,6 +58,13 @@ void EmuWindow_Android::OnRemoveNfcTag() { | |||
| 57 | m_input_subsystem->GetVirtualAmiibo()->CloseAmiibo(); | 58 | m_input_subsystem->GetVirtualAmiibo()->CloseAmiibo(); |
| 58 | } | 59 | } |
| 59 | 60 | ||
| 61 | void EmuWindow_Android::OnFrameDisplayed() { | ||
| 62 | if (!m_first_frame) { | ||
| 63 | EmulationSession::GetInstance().OnEmulationStarted(); | ||
| 64 | m_first_frame = true; | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 60 | EmuWindow_Android::EmuWindow_Android(InputCommon::InputSubsystem* input_subsystem, | 68 | EmuWindow_Android::EmuWindow_Android(InputCommon::InputSubsystem* input_subsystem, |
| 61 | ANativeWindow* surface, | 69 | ANativeWindow* surface, |
| 62 | std::shared_ptr<Common::DynamicLibrary> driver_library) | 70 | std::shared_ptr<Common::DynamicLibrary> driver_library) |
diff --git a/src/android/app/src/main/jni/emu_window/emu_window.h b/src/android/app/src/main/jni/emu_window/emu_window.h index b38087f73..a34a0e479 100644 --- a/src/android/app/src/main/jni/emu_window/emu_window.h +++ b/src/android/app/src/main/jni/emu_window/emu_window.h | |||
| @@ -45,7 +45,7 @@ public: | |||
| 45 | float gyro_z, float accel_x, float accel_y, float accel_z); | 45 | float gyro_z, float accel_x, float accel_y, float accel_z); |
| 46 | void OnReadNfcTag(std::span<u8> data); | 46 | void OnReadNfcTag(std::span<u8> data); |
| 47 | void OnRemoveNfcTag(); | 47 | void OnRemoveNfcTag(); |
| 48 | void OnFrameDisplayed() override {} | 48 | void OnFrameDisplayed() override; |
| 49 | 49 | ||
| 50 | std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override { | 50 | std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override { |
| 51 | return {std::make_unique<GraphicsContext_Android>(m_driver_library)}; | 51 | return {std::make_unique<GraphicsContext_Android>(m_driver_library)}; |
| @@ -61,4 +61,6 @@ private: | |||
| 61 | float m_window_height{}; | 61 | float m_window_height{}; |
| 62 | 62 | ||
| 63 | std::shared_ptr<Common::DynamicLibrary> m_driver_library; | 63 | std::shared_ptr<Common::DynamicLibrary> m_driver_library; |
| 64 | |||
| 65 | bool m_first_frame = false; | ||
| 64 | }; | 66 | }; |
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 1484cc224..64663b084 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp | |||
| @@ -372,8 +372,6 @@ void EmulationSession::RunEmulation() { | |||
| 372 | m_system.InitializeDebugger(); | 372 | m_system.InitializeDebugger(); |
| 373 | } | 373 | } |
| 374 | 374 | ||
| 375 | OnEmulationStarted(); | ||
| 376 | |||
| 377 | while (true) { | 375 | while (true) { |
| 378 | { | 376 | { |
| 379 | [[maybe_unused]] std::unique_lock lock(m_mutex); | 377 | [[maybe_unused]] std::unique_lock lock(m_mutex); |
diff --git a/src/android/app/src/main/jni/native.h b/src/android/app/src/main/jni/native.h index 6b02c44b5..78ef96802 100644 --- a/src/android/app/src/main/jni/native.h +++ b/src/android/app/src/main/jni/native.h | |||
| @@ -52,9 +52,10 @@ public: | |||
| 52 | void OnGamepadDisconnectEvent([[maybe_unused]] int index); | 52 | void OnGamepadDisconnectEvent([[maybe_unused]] int index); |
| 53 | SoftwareKeyboard::AndroidKeyboard* SoftwareKeyboard(); | 53 | SoftwareKeyboard::AndroidKeyboard* SoftwareKeyboard(); |
| 54 | 54 | ||
| 55 | static void OnEmulationStarted(); | ||
| 56 | |||
| 55 | private: | 57 | private: |
| 56 | static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max); | 58 | static void LoadDiskCacheProgress(VideoCore::LoadCallbackStage stage, int progress, int max); |
| 57 | static void OnEmulationStarted(); | ||
| 58 | static void OnEmulationStopped(Core::SystemResultStatus result); | 59 | static void OnEmulationStopped(Core::SystemResultStatus result); |
| 59 | 60 | ||
| 60 | private: | 61 | private: |
diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp index e9bf57895..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 | ||
| 565 | static 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 | |||
| 596 | static 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 | |||
| 657 | static 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 | |||
| 565 | void GDBStub::HandleQuery(std::string_view command) { | 679 | void 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,37 +830,6 @@ static constexpr const char* GetMemoryPermissionString(const Kernel::Svc::Memory | |||
| 727 | } | 830 | } |
| 728 | } | 831 | } |
| 729 | 832 | ||
| 730 | static VAddr GetModuleEnd(Kernel::KProcessPageTable& page_table, VAddr base) { | ||
| 731 | Kernel::KMemoryInfo mem_info; | ||
| 732 | Kernel::Svc::MemoryInfo svc_mem_info; | ||
| 733 | Kernel::Svc::PageInfo page_info; | ||
| 734 | VAddr cur_addr{base}; | ||
| 735 | |||
| 736 | // Expect: r-x Code (.text) | ||
| 737 | R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr)); | ||
| 738 | svc_mem_info = mem_info.GetSvcMemoryInfo(); | ||
| 739 | cur_addr = svc_mem_info.base_address + svc_mem_info.size; | ||
| 740 | if (svc_mem_info.state != Kernel::Svc::MemoryState::Code || | ||
| 741 | svc_mem_info.permission != Kernel::Svc::MemoryPermission::ReadExecute) { | ||
| 742 | return cur_addr - 1; | ||
| 743 | } | ||
| 744 | |||
| 745 | // Expect: r-- Code (.rodata) | ||
| 746 | R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr)); | ||
| 747 | svc_mem_info = mem_info.GetSvcMemoryInfo(); | ||
| 748 | cur_addr = svc_mem_info.base_address + svc_mem_info.size; | ||
| 749 | if (svc_mem_info.state != Kernel::Svc::MemoryState::Code || | ||
| 750 | svc_mem_info.permission != Kernel::Svc::MemoryPermission::Read) { | ||
| 751 | return cur_addr - 1; | ||
| 752 | } | ||
| 753 | |||
| 754 | // Expect: rw- CodeData (.data) | ||
| 755 | R_ASSERT(page_table.QueryInfo(std::addressof(mem_info), std::addressof(page_info), cur_addr)); | ||
| 756 | svc_mem_info = mem_info.GetSvcMemoryInfo(); | ||
| 757 | cur_addr = svc_mem_info.base_address + svc_mem_info.size; | ||
| 758 | return cur_addr - 1; | ||
| 759 | } | ||
| 760 | |||
| 761 | void GDBStub::HandleRcmd(const std::vector<u8>& command) { | 833 | void GDBStub::HandleRcmd(const std::vector<u8>& command) { |
| 762 | 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()}; |
| 763 | std::string reply; | 835 | std::string reply; |
| @@ -784,8 +856,7 @@ void GDBStub::HandleRcmd(const std::vector<u8>& command) { | |||
| 784 | reply = "Fastmem is not enabled.\n"; | 856 | reply = "Fastmem is not enabled.\n"; |
| 785 | } | 857 | } |
| 786 | } else if (command_str == "get info") { | 858 | } else if (command_str == "get info") { |
| 787 | Loader::AppLoader::Modules modules; | 859 | auto modules = FindModules(system); |
| 788 | system.GetAppLoader().ReadNSOModules(modules); | ||
| 789 | 860 | ||
| 790 | reply = fmt::format("Process: {:#x} ({})\n" | 861 | reply = fmt::format("Process: {:#x} ({})\n" |
| 791 | "Program Id: {:#018x}\n", | 862 | "Program Id: {:#018x}\n", |