Merge pull request #8501 from liamwhite/backtrace-again
core/arm: better support for backtrace generation
This commit is contained in:
		| @@ -1,6 +1,10 @@ | ||||
| // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project | ||||
| // SPDX-License-Identifier: GPL-2.0-or-later | ||||
|  | ||||
| #ifndef _MSC_VER | ||||
| #include <cxxabi.h> | ||||
| #endif | ||||
|  | ||||
| #include <map> | ||||
| #include <optional> | ||||
| #include "common/bit_field.h" | ||||
| @@ -68,8 +72,19 @@ void ARM_Interface::SymbolicateBacktrace(Core::System& system, std::vector<Backt | ||||
|         if (symbol_set != symbols.end()) { | ||||
|             const auto symbol = Symbols::GetSymbolName(symbol_set->second, entry.offset); | ||||
|             if (symbol.has_value()) { | ||||
| #ifdef _MSC_VER | ||||
|                 // TODO(DarkLordZach): Add demangling of symbol names. | ||||
|                 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 | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|   | ||||
| @@ -427,18 +427,38 @@ void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table, | ||||
| } | ||||
|  | ||||
| std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace(Core::System& system, | ||||
|                                                                          u64 sp, u64 lr) { | ||||
|     // No way to get accurate stack traces in A32 yet | ||||
|     return {}; | ||||
|                                                                          u64 fp, u64 lr, u64 pc) { | ||||
|     std::vector<BacktraceEntry> out; | ||||
|     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( | ||||
|     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 { | ||||
|     return GetBacktrace(system, GetReg(13), GetReg(14)); | ||||
|     return GetBacktrace(system, GetReg(11), GetReg(14), GetReg(15)); | ||||
| } | ||||
|  | ||||
| } // namespace Core | ||||
|   | ||||
| @@ -78,7 +78,7 @@ protected: | ||||
| private: | ||||
|     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 JitCacheType = | ||||
|   | ||||
| @@ -494,22 +494,22 @@ void ARM_Dynarmic_64::PageTableChanged(Common::PageTable& page_table, | ||||
| } | ||||
|  | ||||
| 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; | ||||
|     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 | ||||
|     out.push_back({"", 0, pc, 0, ""}); | ||||
|  | ||||
|     // fp (= x29) points to the previous frame record. | ||||
|     // 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) { | ||||
|         if (!fp || (fp % 4 != 0) || !memory.IsValidVirtualAddressRange(fp, 16)) { | ||||
|             break; | ||||
|         } | ||||
|         lr = memory.Read64(fp + 8) - 4; | ||||
|         lr = memory.Read64(fp + 8); | ||||
|         fp = memory.Read64(fp); | ||||
|     } | ||||
|  | ||||
| @@ -520,11 +520,12 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace(Core::S | ||||
|  | ||||
| std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktraceFromContext( | ||||
|     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 { | ||||
|     return GetBacktrace(system, GetReg(29), GetReg(30)); | ||||
|     return GetBacktrace(system, GetReg(29), GetReg(30), GetPC()); | ||||
| } | ||||
|  | ||||
| } // namespace Core | ||||
|   | ||||
| @@ -73,7 +73,7 @@ private: | ||||
|     std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table, | ||||
|                                                 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 JitCacheType = | ||||
|   | ||||
		Reference in New Issue
	
	Block a user