core/arm: better support for backtrace generation
This commit is contained in:
		| @@ -1,6 +1,10 @@ | |||||||
| // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||||||
| // SPDX-License-Identifier: GPL-2.0-or-later | // SPDX-License-Identifier: GPL-2.0-or-later | ||||||
|  |  | ||||||
|  | #ifndef _MSC_VER | ||||||
|  | #include <cxxabi.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #include <map> | #include <map> | ||||||
| #include <optional> | #include <optional> | ||||||
| #include "common/bit_field.h" | #include "common/bit_field.h" | ||||||
| @@ -68,8 +72,19 @@ void ARM_Interface::SymbolicateBacktrace(Core::System& system, std::vector<Backt | |||||||
|         if (symbol_set != symbols.end()) { |         if (symbol_set != symbols.end()) { | ||||||
|             const auto symbol = Symbols::GetSymbolName(symbol_set->second, entry.offset); |             const auto symbol = Symbols::GetSymbolName(symbol_set->second, entry.offset); | ||||||
|             if (symbol.has_value()) { |             if (symbol.has_value()) { | ||||||
|  | #ifdef _MSC_VER | ||||||
|                 // TODO(DarkLordZach): Add demangling of symbol names. |                 // TODO(DarkLordZach): Add demangling of symbol names. | ||||||
|                 entry.name = *symbol; |                 entry.name = *symbol; | ||||||
|  | #else | ||||||
|  |                 int status{-1}; | ||||||
|  |                 char* demangled{abi::__cxa_demangle(symbol->c_str(), nullptr, nullptr, &status)}; | ||||||
|  |                 if (status == 0 && demangled != nullptr) { | ||||||
|  |                     entry.name = demangled; | ||||||
|  |                     std::free(demangled); | ||||||
|  |                 } else { | ||||||
|  |                     entry.name = *symbol; | ||||||
|  |                 } | ||||||
|  | #endif | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -409,18 +409,38 @@ void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table, | |||||||
| } | } | ||||||
|  |  | ||||||
| std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace(Core::System& system, | std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace(Core::System& system, | ||||||
|                                                                          u64 sp, u64 lr) { |                                                                          u64 fp, u64 lr, u64 pc) { | ||||||
|     // No way to get accurate stack traces in A32 yet |     std::vector<BacktraceEntry> out; | ||||||
|     return {}; |     auto& memory = system.Memory(); | ||||||
|  |  | ||||||
|  |     out.push_back({"", 0, pc, 0, ""}); | ||||||
|  |  | ||||||
|  |     // fp (= r11) points to the last frame record. | ||||||
|  |     // Frame records are two words long: | ||||||
|  |     // fp+0 : pointer to previous frame record | ||||||
|  |     // fp+4 : value of lr for frame | ||||||
|  |     while (true) { | ||||||
|  |         out.push_back({"", 0, lr, 0, ""}); | ||||||
|  |         if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 8)) { | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |         lr = memory.Read32(fp + 4); | ||||||
|  |         fp = memory.Read32(fp); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     SymbolicateBacktrace(system, out); | ||||||
|  |  | ||||||
|  |     return out; | ||||||
| } | } | ||||||
|  |  | ||||||
| std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktraceFromContext( | std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktraceFromContext( | ||||||
|     System& system, const ThreadContext32& ctx) { |     System& system, const ThreadContext32& ctx) { | ||||||
|     return GetBacktrace(system, ctx.cpu_registers[13], ctx.cpu_registers[14]); |     const auto& reg = ctx.cpu_registers; | ||||||
|  |     return GetBacktrace(system, reg[11], reg[14], reg[15]); | ||||||
| } | } | ||||||
|  |  | ||||||
| std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace() const { | std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace() const { | ||||||
|     return GetBacktrace(system, GetReg(13), GetReg(14)); |     return GetBacktrace(system, GetReg(11), GetReg(14), GetReg(15)); | ||||||
| } | } | ||||||
|  |  | ||||||
| } // namespace Core | } // namespace Core | ||||||
|   | |||||||
| @@ -78,7 +78,7 @@ protected: | |||||||
| private: | private: | ||||||
|     std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const; |     std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const; | ||||||
|  |  | ||||||
|     static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 sp, u64 lr); |     static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 fp, u64 lr, u64 pc); | ||||||
|  |  | ||||||
|     using JitCacheKey = std::pair<Common::PageTable*, std::size_t>; |     using JitCacheKey = std::pair<Common::PageTable*, std::size_t>; | ||||||
|     using JitCacheType = |     using JitCacheType = | ||||||
|   | |||||||
| @@ -480,22 +480,22 @@ void ARM_Dynarmic_64::PageTableChanged(Common::PageTable& page_table, | |||||||
| } | } | ||||||
|  |  | ||||||
| std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace(Core::System& system, | std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace(Core::System& system, | ||||||
|                                                                          u64 fp, u64 lr) { |                                                                          u64 fp, u64 lr, u64 pc) { | ||||||
|     std::vector<BacktraceEntry> out; |     std::vector<BacktraceEntry> out; | ||||||
|     auto& memory = system.Memory(); |     auto& memory = system.Memory(); | ||||||
|  |  | ||||||
|     // fp (= r29) points to the last frame record. |     out.push_back({"", 0, pc, 0, ""}); | ||||||
|     // 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 |     // fp (= x29) points to the previous frame record. | ||||||
|     // Frame records are two words long: |     // Frame records are two words long: | ||||||
|     // fp+0 : pointer to previous frame record |     // fp+0 : pointer to previous frame record | ||||||
|     // fp+8 : value of lr for frame |     // fp+8 : value of lr for frame | ||||||
|     while (true) { |     while (true) { | ||||||
|         out.push_back({"", 0, lr, 0, ""}); |         out.push_back({"", 0, lr, 0, ""}); | ||||||
|         if (!fp) { |         if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 16)) { | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|         lr = memory.Read64(fp + 8) - 4; |         lr = memory.Read64(fp + 8); | ||||||
|         fp = memory.Read64(fp); |         fp = memory.Read64(fp); | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -506,11 +506,12 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace(Core::S | |||||||
|  |  | ||||||
| std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktraceFromContext( | std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktraceFromContext( | ||||||
|     System& system, const ThreadContext64& ctx) { |     System& system, const ThreadContext64& ctx) { | ||||||
|     return GetBacktrace(system, ctx.cpu_registers[29], ctx.cpu_registers[30]); |     const auto& reg = ctx.cpu_registers; | ||||||
|  |     return GetBacktrace(system, reg[29], reg[30], ctx.pc); | ||||||
| } | } | ||||||
|  |  | ||||||
| std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace() const { | std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace() const { | ||||||
|     return GetBacktrace(system, GetReg(29), GetReg(30)); |     return GetBacktrace(system, GetReg(29), GetReg(30), GetPC()); | ||||||
| } | } | ||||||
|  |  | ||||||
| } // namespace Core | } // namespace Core | ||||||
|   | |||||||
| @@ -73,7 +73,7 @@ private: | |||||||
|     std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table, |     std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table, | ||||||
|                                                 std::size_t address_space_bits) const; |                                                 std::size_t address_space_bits) const; | ||||||
|  |  | ||||||
|     static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 fp, u64 lr); |     static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 fp, u64 lr, u64 pc); | ||||||
|  |  | ||||||
|     using JitCacheKey = std::pair<Common::PageTable*, std::size_t>; |     using JitCacheKey = std::pair<Common::PageTable*, std::size_t>; | ||||||
|     using JitCacheType = |     using JitCacheType = | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user