diff options
Diffstat (limited to 'src/core/arm/arm_interface.cpp')
| -rw-r--r-- | src/core/arm/arm_interface.cpp | 71 |
1 files changed, 68 insertions, 3 deletions
diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp index 7e846ddd5..0951e1976 100644 --- a/src/core/arm/arm_interface.cpp +++ b/src/core/arm/arm_interface.cpp @@ -60,7 +60,7 @@ static_assert(sizeof(ELFSymbol) == 0x18, "ELFSymbol has incorrect size."); using Symbols = std::vector<std::pair<ELFSymbol, std::string>>; -Symbols GetSymbols(VAddr text_offset, Memory::Memory& memory) { +Symbols GetSymbols(VAddr text_offset, Core::Memory::Memory& memory) { const auto mod_offset = text_offset + memory.Read32(text_offset + 4); if (mod_offset < text_offset || (mod_offset & 0b11) != 0 || @@ -123,7 +123,7 @@ Symbols GetSymbols(VAddr text_offset, Memory::Memory& memory) { std::optional<std::string> GetSymbolName(const Symbols& symbols, VAddr func_address) { const auto iter = std::find_if(symbols.begin(), symbols.end(), [func_address](const auto& pair) { - const auto& [symbol, name] = pair; + const auto& symbol = pair.first; const auto end_address = symbol.value + symbol.size; return func_address >= symbol.value && func_address < end_address; }); @@ -139,6 +139,71 @@ std::optional<std::string> GetSymbolName(const Symbols& symbols, VAddr func_addr constexpr u64 SEGMENT_BASE = 0x7100000000ull; +std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktraceFromContext( + System& system, const ThreadContext64& ctx) { + std::vector<BacktraceEntry> 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<VAddr, std::string> modules; + auto& loader{system.GetAppLoader()}; + if (loader.ReadNSOModules(modules) != Loader::ResultStatus::Success) { + return {}; + } + + std::map<std::string, Symbols> symbols; + for (const auto& module : modules) { + symbols.insert_or_assign(module.second, GetSymbols(module.first, memory)); + } + + 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 = GetSymbolName(symbol_set->second, entry.offset); + if (symbol.has_value()) { + // TODO(DarkLordZach): Add demangling of symbol names. + entry.name = *symbol; + } + } + } + + return out; +} + std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktrace() const { std::vector<BacktraceEntry> out; auto& memory = system.Memory(); @@ -146,7 +211,7 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktrace() const { auto fp = GetReg(29); auto lr = GetReg(30); while (true) { - out.push_back({"", 0, lr, 0}); + out.push_back({"", 0, lr, 0, ""}); if (!fp) { break; } |
