Merge pull request #8501 from liamwhite/backtrace-again

core/arm: better support for backtrace generation
This commit is contained in:
Mai 2022-07-07 23:49:54 -04:00 committed by GitHub
commit 313f047f97
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 51 additions and 15 deletions

View File

@ -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
} }
} }
} }

View File

@ -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, 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

View File

@ -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 =

View File

@ -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, 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);
} }
@ -520,11 +520,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

View File

@ -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 =