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