diff options
Diffstat (limited to '')
| -rw-r--r-- | src/core/arm/arm_interface.cpp | 97 | ||||
| -rw-r--r-- | src/core/arm/arm_interface.h | 18 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_32.cpp | 19 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_32.h | 8 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_64.cpp | 38 | ||||
| -rw-r--r-- | src/core/arm/dynarmic/arm_dynarmic_64.h | 8 |
6 files changed, 98 insertions, 90 deletions
diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp index 08bf1201d..2a9390e26 100644 --- a/src/core/arm/arm_interface.cpp +++ b/src/core/arm/arm_interface.cpp | |||
| @@ -14,96 +14,28 @@ | |||
| 14 | #include "core/loader/loader.h" | 14 | #include "core/loader/loader.h" |
| 15 | #include "core/memory.h" | 15 | #include "core/memory.h" |
| 16 | 16 | ||
| 17 | #include "core/arm/dynarmic/arm_dynarmic_32.h" | ||
| 18 | #include "core/arm/dynarmic/arm_dynarmic_64.h" | ||
| 19 | |||
| 17 | namespace Core { | 20 | namespace Core { |
| 18 | 21 | ||
| 19 | constexpr u64 SEGMENT_BASE = 0x7100000000ull; | 22 | constexpr u64 SEGMENT_BASE = 0x7100000000ull; |
| 20 | 23 | ||
| 21 | std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktraceFromContext( | 24 | std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktraceFromContext( |
| 22 | System& system, const ThreadContext64& ctx) { | 25 | Core::System& system, const ARM_Interface::ThreadContext32& ctx) { |
| 23 | std::vector<BacktraceEntry> out; | 26 | return ARM_Dynarmic_32::GetBacktraceFromContext(system, ctx); |
| 24 | auto& memory = system.Memory(); | ||
| 25 | |||
| 26 | auto fp = ctx.cpu_registers[29]; | ||
| 27 | auto lr = ctx.cpu_registers[30]; | ||
| 28 | while (true) { | ||
| 29 | out.push_back({ | ||
| 30 | .module = "", | ||
| 31 | .address = 0, | ||
| 32 | .original_address = lr, | ||
| 33 | .offset = 0, | ||
| 34 | .name = {}, | ||
| 35 | }); | ||
| 36 | |||
| 37 | if (fp == 0) { | ||
| 38 | break; | ||
| 39 | } | ||
| 40 | |||
| 41 | lr = memory.Read64(fp + 8) - 4; | ||
| 42 | fp = memory.Read64(fp); | ||
| 43 | } | ||
| 44 | |||
| 45 | std::map<VAddr, std::string> modules; | ||
| 46 | auto& loader{system.GetAppLoader()}; | ||
| 47 | if (loader.ReadNSOModules(modules) != Loader::ResultStatus::Success) { | ||
| 48 | return {}; | ||
| 49 | } | ||
| 50 | |||
| 51 | std::map<std::string, Symbols::Symbols> symbols; | ||
| 52 | for (const auto& module : modules) { | ||
| 53 | symbols.insert_or_assign(module.second, | ||
| 54 | Symbols::GetSymbols(module.first, system.Memory(), | ||
| 55 | system.CurrentProcess()->Is64BitProcess())); | ||
| 56 | } | ||
| 57 | |||
| 58 | for (auto& entry : out) { | ||
| 59 | VAddr base = 0; | ||
| 60 | for (auto iter = modules.rbegin(); iter != modules.rend(); ++iter) { | ||
| 61 | const auto& module{*iter}; | ||
| 62 | if (entry.original_address >= module.first) { | ||
| 63 | entry.module = module.second; | ||
| 64 | base = module.first; | ||
| 65 | break; | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
| 69 | entry.offset = entry.original_address - base; | ||
| 70 | entry.address = SEGMENT_BASE + entry.offset; | ||
| 71 | |||
| 72 | if (entry.module.empty()) | ||
| 73 | entry.module = "unknown"; | ||
| 74 | |||
| 75 | const auto symbol_set = symbols.find(entry.module); | ||
| 76 | if (symbol_set != symbols.end()) { | ||
| 77 | const auto symbol = Symbols::GetSymbolName(symbol_set->second, entry.offset); | ||
| 78 | if (symbol.has_value()) { | ||
| 79 | // TODO(DarkLordZach): Add demangling of symbol names. | ||
| 80 | entry.name = *symbol; | ||
| 81 | } | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | return out; | ||
| 86 | } | 27 | } |
| 87 | 28 | ||
| 88 | std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktrace() const { | 29 | std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktraceFromContext( |
| 89 | std::vector<BacktraceEntry> out; | 30 | Core::System& system, const ARM_Interface::ThreadContext64& ctx) { |
| 90 | auto& memory = system.Memory(); | 31 | return ARM_Dynarmic_64::GetBacktraceFromContext(system, ctx); |
| 91 | 32 | } | |
| 92 | auto fp = GetReg(29); | ||
| 93 | auto lr = GetReg(30); | ||
| 94 | while (true) { | ||
| 95 | out.push_back({"", 0, lr, 0, ""}); | ||
| 96 | if (!fp) { | ||
| 97 | break; | ||
| 98 | } | ||
| 99 | lr = memory.Read64(fp + 8) - 4; | ||
| 100 | fp = memory.Read64(fp); | ||
| 101 | } | ||
| 102 | 33 | ||
| 34 | void ARM_Interface::SymbolicateBacktrace(Core::System& system, std::vector<BacktraceEntry>& out) { | ||
| 103 | std::map<VAddr, std::string> modules; | 35 | std::map<VAddr, std::string> modules; |
| 104 | auto& loader{system.GetAppLoader()}; | 36 | auto& loader{system.GetAppLoader()}; |
| 105 | if (loader.ReadNSOModules(modules) != Loader::ResultStatus::Success) { | 37 | if (loader.ReadNSOModules(modules) != Loader::ResultStatus::Success) { |
| 106 | return {}; | 38 | return; |
| 107 | } | 39 | } |
| 108 | 40 | ||
| 109 | std::map<std::string, Symbols::Symbols> symbols; | 41 | std::map<std::string, Symbols::Symbols> symbols; |
| @@ -127,8 +59,9 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktrace() const { | |||
| 127 | entry.offset = entry.original_address - base; | 59 | entry.offset = entry.original_address - base; |
| 128 | entry.address = SEGMENT_BASE + entry.offset; | 60 | entry.address = SEGMENT_BASE + entry.offset; |
| 129 | 61 | ||
| 130 | if (entry.module.empty()) | 62 | if (entry.module.empty()) { |
| 131 | entry.module = "unknown"; | 63 | entry.module = "unknown"; |
| 64 | } | ||
| 132 | 65 | ||
| 133 | const auto symbol_set = symbols.find(entry.module); | 66 | const auto symbol_set = symbols.find(entry.module); |
| 134 | if (symbol_set != symbols.end()) { | 67 | if (symbol_set != symbols.end()) { |
| @@ -139,12 +72,10 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktrace() const { | |||
| 139 | } | 72 | } |
| 140 | } | 73 | } |
| 141 | } | 74 | } |
| 142 | |||
| 143 | return out; | ||
| 144 | } | 75 | } |
| 145 | 76 | ||
| 146 | void ARM_Interface::LogBacktrace() const { | 77 | void ARM_Interface::LogBacktrace() const { |
| 147 | const VAddr sp = GetReg(13); | 78 | const VAddr sp = GetSP(); |
| 148 | const VAddr pc = GetPC(); | 79 | const VAddr pc = GetPC(); |
| 149 | LOG_ERROR(Core_ARM, "Backtrace, sp={:016X}, pc={:016X}", sp, pc); | 80 | LOG_ERROR(Core_ARM, "Backtrace, sp={:016X}, pc={:016X}", sp, pc); |
| 150 | LOG_ERROR(Core_ARM, "{:20}{:20}{:20}{:20}{}", "Module Name", "Address", "Original Address", | 81 | LOG_ERROR(Core_ARM, "{:20}{:20}{:20}{:20}{}", "Module Name", "Address", "Original Address", |
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index dce2f4195..bcec4b3b8 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h | |||
| @@ -101,6 +101,12 @@ public: | |||
| 101 | virtual u64 GetPC() const = 0; | 101 | virtual u64 GetPC() const = 0; |
| 102 | 102 | ||
| 103 | /** | 103 | /** |
| 104 | * Get the current Stack Pointer | ||
| 105 | * @return Returns current SP | ||
| 106 | */ | ||
| 107 | virtual u64 GetSP() const = 0; | ||
| 108 | |||
| 109 | /** | ||
| 104 | * Get an ARM register | 110 | * Get an ARM register |
| 105 | * @param index Register index | 111 | * @param index Register index |
| 106 | * @return Returns the value in the register | 112 | * @return Returns the value in the register |
| @@ -183,16 +189,12 @@ public: | |||
| 183 | }; | 189 | }; |
| 184 | 190 | ||
| 185 | static std::vector<BacktraceEntry> GetBacktraceFromContext(System& system, | 191 | static std::vector<BacktraceEntry> GetBacktraceFromContext(System& system, |
| 192 | const ThreadContext32& ctx); | ||
| 193 | static std::vector<BacktraceEntry> GetBacktraceFromContext(System& system, | ||
| 186 | const ThreadContext64& ctx); | 194 | const ThreadContext64& ctx); |
| 187 | 195 | ||
| 188 | std::vector<BacktraceEntry> GetBacktrace() const; | 196 | virtual std::vector<BacktraceEntry> GetBacktrace() const = 0; |
| 189 | 197 | ||
| 190 | /// fp (= r29) points to the last frame record. | ||
| 191 | /// Note that this is the frame record for the *previous* frame, not the current one. | ||
| 192 | /// Note we need to subtract 4 from our last read to get the proper address | ||
| 193 | /// Frame records are two words long: | ||
| 194 | /// fp+0 : pointer to previous frame record | ||
| 195 | /// fp+8 : value of lr for frame | ||
| 196 | void LogBacktrace() const; | 198 | void LogBacktrace() const; |
| 197 | 199 | ||
| 198 | protected: | 200 | protected: |
| @@ -200,6 +202,8 @@ protected: | |||
| 200 | System& system; | 202 | System& system; |
| 201 | CPUInterrupts& interrupt_handlers; | 203 | CPUInterrupts& interrupt_handlers; |
| 202 | bool uses_wall_clock; | 204 | bool uses_wall_clock; |
| 205 | |||
| 206 | static void SymbolicateBacktrace(Core::System& system, std::vector<BacktraceEntry>& out); | ||
| 203 | }; | 207 | }; |
| 204 | 208 | ||
| 205 | } // namespace Core | 209 | } // namespace Core |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp index 5de4384db..da5659046 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp | |||
| @@ -268,6 +268,10 @@ u64 ARM_Dynarmic_32::GetPC() const { | |||
| 268 | return jit.load()->Regs()[15]; | 268 | return jit.load()->Regs()[15]; |
| 269 | } | 269 | } |
| 270 | 270 | ||
| 271 | u64 ARM_Dynarmic_32::GetSP() const { | ||
| 272 | return jit.load()->Regs()[13]; | ||
| 273 | } | ||
| 274 | |||
| 271 | u64 ARM_Dynarmic_32::GetReg(int index) const { | 275 | u64 ARM_Dynarmic_32::GetReg(int index) const { |
| 272 | return jit.load()->Regs()[index]; | 276 | return jit.load()->Regs()[index]; |
| 273 | } | 277 | } |
| @@ -362,4 +366,19 @@ void ARM_Dynarmic_32::PageTableChanged(Common::PageTable& page_table, | |||
| 362 | jit_cache.emplace(key, std::move(new_jit)); | 366 | jit_cache.emplace(key, std::move(new_jit)); |
| 363 | } | 367 | } |
| 364 | 368 | ||
| 369 | std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace(Core::System& system, | ||
| 370 | u64 sp, u64 lr) { | ||
| 371 | // No way to get accurate stack traces in A32 yet | ||
| 372 | return {}; | ||
| 373 | } | ||
| 374 | |||
| 375 | std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktraceFromContext( | ||
| 376 | System& system, const ThreadContext32& ctx) { | ||
| 377 | return GetBacktrace(system, ctx.cpu_registers[13], ctx.cpu_registers[14]); | ||
| 378 | } | ||
| 379 | |||
| 380 | std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_32::GetBacktrace() const { | ||
| 381 | return GetBacktrace(system, GetReg(13), GetReg(14)); | ||
| 382 | } | ||
| 383 | |||
| 365 | } // namespace Core | 384 | } // namespace Core |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.h b/src/core/arm/dynarmic/arm_dynarmic_32.h index 684937353..1b628f94d 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_32.h +++ b/src/core/arm/dynarmic/arm_dynarmic_32.h | |||
| @@ -35,6 +35,7 @@ public: | |||
| 35 | 35 | ||
| 36 | void SetPC(u64 pc) override; | 36 | void SetPC(u64 pc) override; |
| 37 | u64 GetPC() const override; | 37 | u64 GetPC() const override; |
| 38 | u64 GetSP() const override; | ||
| 38 | u64 GetReg(int index) const override; | 39 | u64 GetReg(int index) const override; |
| 39 | void SetReg(int index, u64 value) override; | 40 | void SetReg(int index, u64 value) override; |
| 40 | u128 GetVectorReg(int index) const override; | 41 | u128 GetVectorReg(int index) const override; |
| @@ -66,9 +67,16 @@ public: | |||
| 66 | void PageTableChanged(Common::PageTable& new_page_table, | 67 | void PageTableChanged(Common::PageTable& new_page_table, |
| 67 | std::size_t new_address_space_size_in_bits) override; | 68 | std::size_t new_address_space_size_in_bits) override; |
| 68 | 69 | ||
| 70 | static std::vector<BacktraceEntry> GetBacktraceFromContext(System& system, | ||
| 71 | const ThreadContext32& ctx); | ||
| 72 | |||
| 73 | std::vector<BacktraceEntry> GetBacktrace() const override; | ||
| 74 | |||
| 69 | private: | 75 | private: |
| 70 | std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const; | 76 | std::shared_ptr<Dynarmic::A32::Jit> MakeJit(Common::PageTable* page_table) const; |
| 71 | 77 | ||
| 78 | static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 sp, u64 lr); | ||
| 79 | |||
| 72 | using JitCacheKey = std::pair<Common::PageTable*, std::size_t>; | 80 | using JitCacheKey = std::pair<Common::PageTable*, std::size_t>; |
| 73 | using JitCacheType = | 81 | using JitCacheType = |
| 74 | std::unordered_map<JitCacheKey, std::shared_ptr<Dynarmic::A32::Jit>, Common::PairHash>; | 82 | std::unordered_map<JitCacheKey, std::shared_ptr<Dynarmic::A32::Jit>, Common::PairHash>; |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index ae0b158c2..871d9d10e 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp | |||
| @@ -328,6 +328,10 @@ u64 ARM_Dynarmic_64::GetPC() const { | |||
| 328 | return jit.load()->GetPC(); | 328 | return jit.load()->GetPC(); |
| 329 | } | 329 | } |
| 330 | 330 | ||
| 331 | u64 ARM_Dynarmic_64::GetSP() const { | ||
| 332 | return jit.load()->GetSP(); | ||
| 333 | } | ||
| 334 | |||
| 331 | u64 ARM_Dynarmic_64::GetReg(int index) const { | 335 | u64 ARM_Dynarmic_64::GetReg(int index) const { |
| 332 | return jit.load()->GetRegister(index); | 336 | return jit.load()->GetRegister(index); |
| 333 | } | 337 | } |
| @@ -430,4 +434,38 @@ void ARM_Dynarmic_64::PageTableChanged(Common::PageTable& page_table, | |||
| 430 | jit_cache.emplace(key, std::move(new_jit)); | 434 | jit_cache.emplace(key, std::move(new_jit)); |
| 431 | } | 435 | } |
| 432 | 436 | ||
| 437 | std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace(Core::System& system, | ||
| 438 | u64 fp, u64 lr) { | ||
| 439 | std::vector<BacktraceEntry> out; | ||
| 440 | auto& memory = system.Memory(); | ||
| 441 | |||
| 442 | // fp (= r29) points to the last frame record. | ||
| 443 | // Note that this is the frame record for the *previous* frame, not the current one. | ||
| 444 | // Note we need to subtract 4 from our last read to get the proper address | ||
| 445 | // Frame records are two words long: | ||
| 446 | // fp+0 : pointer to previous frame record | ||
| 447 | // fp+8 : value of lr for frame | ||
| 448 | while (true) { | ||
| 449 | out.push_back({"", 0, lr, 0, ""}); | ||
| 450 | if (!fp) { | ||
| 451 | break; | ||
| 452 | } | ||
| 453 | lr = memory.Read64(fp + 8) - 4; | ||
| 454 | fp = memory.Read64(fp); | ||
| 455 | } | ||
| 456 | |||
| 457 | SymbolicateBacktrace(system, out); | ||
| 458 | |||
| 459 | return out; | ||
| 460 | } | ||
| 461 | |||
| 462 | std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktraceFromContext( | ||
| 463 | System& system, const ThreadContext64& ctx) { | ||
| 464 | return GetBacktrace(system, ctx.cpu_registers[29], ctx.cpu_registers[30]); | ||
| 465 | } | ||
| 466 | |||
| 467 | std::vector<ARM_Interface::BacktraceEntry> ARM_Dynarmic_64::GetBacktrace() const { | ||
| 468 | return GetBacktrace(system, GetReg(29), GetReg(30)); | ||
| 469 | } | ||
| 470 | |||
| 433 | } // namespace Core | 471 | } // namespace Core |
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.h b/src/core/arm/dynarmic/arm_dynarmic_64.h index 86018f196..78773e293 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.h +++ b/src/core/arm/dynarmic/arm_dynarmic_64.h | |||
| @@ -33,6 +33,7 @@ public: | |||
| 33 | 33 | ||
| 34 | void SetPC(u64 pc) override; | 34 | void SetPC(u64 pc) override; |
| 35 | u64 GetPC() const override; | 35 | u64 GetPC() const override; |
| 36 | u64 GetSP() const override; | ||
| 36 | u64 GetReg(int index) const override; | 37 | u64 GetReg(int index) const override; |
| 37 | void SetReg(int index, u64 value) override; | 38 | void SetReg(int index, u64 value) override; |
| 38 | u128 GetVectorReg(int index) const override; | 39 | u128 GetVectorReg(int index) const override; |
| @@ -60,10 +61,17 @@ public: | |||
| 60 | void PageTableChanged(Common::PageTable& new_page_table, | 61 | void PageTableChanged(Common::PageTable& new_page_table, |
| 61 | std::size_t new_address_space_size_in_bits) override; | 62 | std::size_t new_address_space_size_in_bits) override; |
| 62 | 63 | ||
| 64 | static std::vector<BacktraceEntry> GetBacktraceFromContext(System& system, | ||
| 65 | const ThreadContext64& ctx); | ||
| 66 | |||
| 67 | std::vector<BacktraceEntry> GetBacktrace() const override; | ||
| 68 | |||
| 63 | private: | 69 | private: |
| 64 | std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table, | 70 | std::shared_ptr<Dynarmic::A64::Jit> MakeJit(Common::PageTable* page_table, |
| 65 | std::size_t address_space_bits) const; | 71 | std::size_t address_space_bits) const; |
| 66 | 72 | ||
| 73 | static std::vector<BacktraceEntry> GetBacktrace(Core::System& system, u64 fp, u64 lr); | ||
| 74 | |||
| 67 | using JitCacheKey = std::pair<Common::PageTable*, std::size_t>; | 75 | using JitCacheKey = std::pair<Common::PageTable*, std::size_t>; |
| 68 | using JitCacheType = | 76 | using JitCacheType = |
| 69 | std::unordered_map<JitCacheKey, std::shared_ptr<Dynarmic::A64::Jit>, Common::PairHash>; | 77 | std::unordered_map<JitCacheKey, std::shared_ptr<Dynarmic::A64::Jit>, Common::PairHash>; |