From 0ca4dff62c61570828ec563d6200ca47b3d02569 Mon Sep 17 00:00:00 2001 From: Liam Date: Wed, 20 Apr 2022 20:17:48 -0400 Subject: [PATCH] core/arm: separate backtrace collection --- src/core/arm/arm_interface.cpp | 97 ++++------------------- src/core/arm/arm_interface.h | 18 +++-- src/core/arm/dynarmic/arm_dynarmic_32.cpp | 19 +++++ src/core/arm/dynarmic/arm_dynarmic_32.h | 8 ++ src/core/arm/dynarmic/arm_dynarmic_64.cpp | 38 +++++++++ src/core/arm/dynarmic/arm_dynarmic_64.h | 8 ++ 6 files changed, 98 insertions(+), 90 deletions(-) diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp index 08bf1201d4..2a9390e265 100644 --- a/src/core/arm/arm_interface.cpp +++ b/src/core/arm/arm_interface.cpp @@ -14,96 +14,28 @@ #include "core/loader/loader.h" #include "core/memory.h" +#include "core/arm/dynarmic/arm_dynarmic_32.h" +#include "core/arm/dynarmic/arm_dynarmic_64.h" + namespace Core { constexpr u64 SEGMENT_BASE = 0x7100000000ull; std::vector ARM_Interface::GetBacktraceFromContext( - System& system, const ThreadContext64& ctx) { - std::vector out; - auto& memory = system.Memory(); - - auto fp = ctx.cpu_registers[29]; - auto lr = ctx.cpu_registers[30]; - while (true) { - out.push_back({ - .module = "", - .address = 0, - .original_address = lr, - .offset = 0, - .name = {}, - }); - - if (fp == 0) { - break; - } - - lr = memory.Read64(fp + 8) - 4; - fp = memory.Read64(fp); - } - - std::map modules; - auto& loader{system.GetAppLoader()}; - if (loader.ReadNSOModules(modules) != Loader::ResultStatus::Success) { - return {}; - } - - std::map symbols; - for (const auto& module : modules) { - symbols.insert_or_assign(module.second, - Symbols::GetSymbols(module.first, system.Memory(), - system.CurrentProcess()->Is64BitProcess())); - } - - for (auto& entry : out) { - VAddr base = 0; - for (auto iter = modules.rbegin(); iter != modules.rend(); ++iter) { - const auto& module{*iter}; - if (entry.original_address >= module.first) { - entry.module = module.second; - base = module.first; - break; - } - } - - entry.offset = entry.original_address - base; - entry.address = SEGMENT_BASE + entry.offset; - - if (entry.module.empty()) - entry.module = "unknown"; - - const auto symbol_set = symbols.find(entry.module); - if (symbol_set != symbols.end()) { - const auto symbol = Symbols::GetSymbolName(symbol_set->second, entry.offset); - if (symbol.has_value()) { - // TODO(DarkLordZach): Add demangling of symbol names. - entry.name = *symbol; - } - } - } - - return out; + Core::System& system, const ARM_Interface::ThreadContext32& ctx) { + return ARM_Dynarmic_32::GetBacktraceFromContext(system, ctx); } -std::vector ARM_Interface::GetBacktrace() const { - std::vector out; - auto& memory = system.Memory(); - - auto fp = GetReg(29); - auto lr = GetReg(30); - while (true) { - out.push_back({"", 0, lr, 0, ""}); - if (!fp) { - break; - } - lr = memory.Read64(fp + 8) - 4; - fp = memory.Read64(fp); - } +std::vector ARM_Interface::GetBacktraceFromContext( + Core::System& system, const ARM_Interface::ThreadContext64& ctx) { + return ARM_Dynarmic_64::GetBacktraceFromContext(system, ctx); +} +void ARM_Interface::SymbolicateBacktrace(Core::System& system, std::vector& out) { std::map modules; auto& loader{system.GetAppLoader()}; if (loader.ReadNSOModules(modules) != Loader::ResultStatus::Success) { - return {}; + return; } std::map symbols; @@ -127,8 +59,9 @@ std::vector ARM_Interface::GetBacktrace() const { entry.offset = entry.original_address - base; entry.address = SEGMENT_BASE + entry.offset; - if (entry.module.empty()) + if (entry.module.empty()) { entry.module = "unknown"; + } const auto symbol_set = symbols.find(entry.module); if (symbol_set != symbols.end()) { @@ -139,12 +72,10 @@ std::vector ARM_Interface::GetBacktrace() const { } } } - - return out; } void ARM_Interface::LogBacktrace() const { - const VAddr sp = GetReg(13); + const VAddr sp = GetSP(); const VAddr pc = GetPC(); LOG_ERROR(Core_ARM, "Backtrace, sp={:016X}, pc={:016X}", sp, pc); LOG_ERROR(Core_ARM, "{:20}{:20}{:20}{:20}{}", "Module Name", "Address", "Original Address", diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index dce2f41952..bcec4b3b85 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -100,6 +100,12 @@ public: */ virtual u64 GetPC() const = 0; + /** + * Get the current Stack Pointer + * @return Returns current SP + */ + virtual u64 GetSP() const = 0; + /** * Get an ARM register * @param index Register index @@ -182,17 +188,13 @@ public: std::string name; }; + static std::vector GetBacktraceFromContext(System& system, + const ThreadContext32& ctx); static std::vector GetBacktraceFromContext(System& system, const ThreadContext64& ctx); - std::vector GetBacktrace() const; + virtual std::vector GetBacktrace() const = 0; - /// fp (= r29) points to the last frame record. - /// Note that this is the frame record for the *previous* frame, not the current one. - /// Note we need to subtract 4 from our last read to get the proper address - /// Frame records are two words long: - /// fp+0 : pointer to previous frame record - /// fp+8 : value of lr for frame void LogBacktrace() const; protected: @@ -200,6 +202,8 @@ protected: System& system; CPUInterrupts& interrupt_handlers; bool uses_wall_clock; + + static void SymbolicateBacktrace(Core::System& system, std::vector& out); }; } // namespace Core diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 5de4384dbc..da5659046a 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp @@ -268,6 +268,10 @@ u64 ARM_Dynarmic_32::GetPC() const { return jit.load()->Regs()[15]; } +u64 ARM_Dynarmic_32::GetSP() const { + return jit.load()->Regs()[13]; +} + u64 ARM_Dynarmic_32::GetReg(int index) const { return jit.load()->Regs()[index]; } @@ -362,4 +366,19 @@ void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table, jit_cache.emplace(key, std::move(new_jit)); } +std::vector ARM_Dynarmic_32::GetBacktrace(Core::System& system, + u64 sp, u64 lr) { + // No way to get accurate stack traces in A32 yet + return {}; +} + +std::vector ARM_Dynarmic_32::GetBacktraceFromContext( + System& system, const ThreadContext32& ctx) { + return GetBacktrace(system, ctx.cpu_registers[13], ctx.cpu_registers[14]); +} + +std::vector ARM_Dynarmic_32::GetBacktrace() const { + return GetBacktrace(system, GetReg(13), GetReg(14)); +} + } // namespace Core diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index 6849373532..1b628f94d4 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h @@ -35,6 +35,7 @@ public: void SetPC(u64 pc) override; u64 GetPC() const override; + u64 GetSP() const override; u64 GetReg(int index) const override; void SetReg(int index, u64 value) override; u128 GetVectorReg(int index) const override; @@ -66,9 +67,16 @@ public: void PageTableChanged(Common::PageTable& new_page_table, std::size_t new_address_space_size_in_bits) override; + static std::vector GetBacktraceFromContext(System& system, + const ThreadContext32& ctx); + + std::vector GetBacktrace() const override; + private: std::shared_ptr MakeJit(Common::PageTable* page_table) const; + static std::vector GetBacktrace(Core::System& system, u64 sp, u64 lr); + using JitCacheKey = std::pair; using JitCacheType = std::unordered_map, Common::PairHash>; diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index ae0b158c26..871d9d10e9 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -328,6 +328,10 @@ u64 ARM_Dynarmic_64::GetPC() const { return jit.load()->GetPC(); } +u64 ARM_Dynarmic_64::GetSP() const { + return jit.load()->GetSP(); +} + u64 ARM_Dynarmic_64::GetReg(int index) const { return jit.load()->GetRegister(index); } @@ -430,4 +434,38 @@ void ARM_Dynarmic_64::PageTableChanged(Common::PageTable& page_table, jit_cache.emplace(key, std::move(new_jit)); } +std::vector ARM_Dynarmic_64::GetBacktrace(Core::System& system, + u64 fp, u64 lr) { + std::vector out; + auto& memory = system.Memory(); + + // fp (= r29) points to the last frame record. + // Note that this is the frame record for the *previous* frame, not the current one. + // Note we need to subtract 4 from our last read to get the proper address + // Frame records are two words long: + // fp+0 : pointer to previous frame record + // fp+8 : value of lr for frame + while (true) { + out.push_back({"", 0, lr, 0, ""}); + if (!fp) { + break; + } + lr = memory.Read64(fp + 8) - 4; + fp = memory.Read64(fp); + } + + SymbolicateBacktrace(system, out); + + return out; +} + +std::vector ARM_Dynarmic_64::GetBacktraceFromContext( + System& system, const ThreadContext64& ctx) { + return GetBacktrace(system, ctx.cpu_registers[29], ctx.cpu_registers[30]); +} + +std::vector ARM_Dynarmic_64::GetBacktrace() const { + return GetBacktrace(system, GetReg(29), GetReg(30)); +} + } // namespace Core diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index 86018f1961..78773e293f 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h @@ -33,6 +33,7 @@ public: void SetPC(u64 pc) override; u64 GetPC() const override; + u64 GetSP() const override; u64 GetReg(int index) const override; void SetReg(int index, u64 value) override; u128 GetVectorReg(int index) const override; @@ -60,10 +61,17 @@ public: void PageTableChanged(Common::PageTable& new_page_table, std::size_t new_address_space_size_in_bits) override; + static std::vector GetBacktraceFromContext(System& system, + const ThreadContext64& ctx); + + std::vector GetBacktrace() const override; + private: std::shared_ptr MakeJit(Common::PageTable* page_table, std::size_t address_space_bits) const; + static std::vector GetBacktrace(Core::System& system, u64 fp, u64 lr); + using JitCacheKey = std::pair; using JitCacheType = std::unordered_map, Common::PairHash>;