summaryrefslogtreecommitdiff
path: root/src/core/arm/arm_interface.cpp
diff options
context:
space:
mode:
authorGravatar bunnei2019-06-21 14:05:18 -0400
committerGravatar GitHub2019-06-21 14:05:18 -0400
commit96412848a9db0643198ea882824688f23dc19606 (patch)
tree2824eafaf4bc026cc3fc0ee498d1c5c623f3aa65 /src/core/arm/arm_interface.cpp
parentMerge pull request #2291 from DarkLordZach/homebrew-testing (diff)
parentloader: Move NSO module tracking to AppLoader (diff)
downloadyuzu-96412848a9db0643198ea882824688f23dc19606.tar.gz
yuzu-96412848a9db0643198ea882824688f23dc19606.tar.xz
yuzu-96412848a9db0643198ea882824688f23dc19606.zip
Merge pull request #2482 from DarkLordZach/prepo
core: Add detailed local reporting feature for development
Diffstat (limited to 'src/core/arm/arm_interface.cpp')
-rw-r--r--src/core/arm/arm_interface.cpp201
1 files changed, 194 insertions, 7 deletions
diff --git a/src/core/arm/arm_interface.cpp b/src/core/arm/arm_interface.cpp
index 2223cbeed..372612c9b 100644
--- a/src/core/arm/arm_interface.cpp
+++ b/src/core/arm/arm_interface.cpp
@@ -2,26 +2,213 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <map>
6#include <optional>
7#include "common/bit_field.h"
5#include "common/common_types.h" 8#include "common/common_types.h"
6#include "common/logging/log.h" 9#include "common/logging/log.h"
7#include "core/arm/arm_interface.h" 10#include "core/arm/arm_interface.h"
11#include "core/core.h"
12#include "core/loader/loader.h"
8#include "core/memory.h" 13#include "core/memory.h"
9 14
10namespace Core { 15namespace Core {
11void ARM_Interface::LogBacktrace() const {
12 VAddr fp = GetReg(29);
13 VAddr lr = GetReg(30);
14 const VAddr sp = GetReg(13);
15 const VAddr pc = GetPC();
16 16
17 LOG_ERROR(Core_ARM, "Backtrace, sp={:016X}, pc={:016X}", sp, pc); 17namespace {
18
19constexpr u64 ELF_DYNAMIC_TAG_NULL = 0;
20constexpr u64 ELF_DYNAMIC_TAG_STRTAB = 5;
21constexpr u64 ELF_DYNAMIC_TAG_SYMTAB = 6;
22constexpr u64 ELF_DYNAMIC_TAG_SYMENT = 11;
23
24enum class ELFSymbolType : u8 {
25 None = 0,
26 Object = 1,
27 Function = 2,
28 Section = 3,
29 File = 4,
30 Common = 5,
31 TLS = 6,
32};
33
34enum class ELFSymbolBinding : u8 {
35 Local = 0,
36 Global = 1,
37 Weak = 2,
38};
39
40enum class ELFSymbolVisibility : u8 {
41 Default = 0,
42 Internal = 1,
43 Hidden = 2,
44 Protected = 3,
45};
46
47struct ELFSymbol {
48 u32 name_index;
49 union {
50 u8 info;
51
52 BitField<0, 4, ELFSymbolType> type;
53 BitField<4, 4, ELFSymbolBinding> binding;
54 };
55 ELFSymbolVisibility visibility;
56 u16 sh_index;
57 u64 value;
58 u64 size;
59};
60static_assert(sizeof(ELFSymbol) == 0x18, "ELFSymbol has incorrect size.");
61
62using Symbols = std::vector<std::pair<ELFSymbol, std::string>>;
63
64Symbols GetSymbols(VAddr text_offset) {
65 const auto mod_offset = text_offset + Memory::Read32(text_offset + 4);
66
67 if (mod_offset < text_offset || (mod_offset & 0b11) != 0 ||
68 Memory::Read32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0')) {
69 return {};
70 }
71
72 const auto dynamic_offset = Memory::Read32(mod_offset + 0x4) + mod_offset;
73
74 VAddr string_table_offset{};
75 VAddr symbol_table_offset{};
76 u64 symbol_entry_size{};
77
78 VAddr dynamic_index = dynamic_offset;
79 while (true) {
80 const auto tag = Memory::Read64(dynamic_index);
81 const auto value = Memory::Read64(dynamic_index + 0x8);
82 dynamic_index += 0x10;
83
84 if (tag == ELF_DYNAMIC_TAG_NULL) {
85 break;
86 }
87
88 if (tag == ELF_DYNAMIC_TAG_STRTAB) {
89 string_table_offset = value;
90 } else if (tag == ELF_DYNAMIC_TAG_SYMTAB) {
91 symbol_table_offset = value;
92 } else if (tag == ELF_DYNAMIC_TAG_SYMENT) {
93 symbol_entry_size = value;
94 }
95 }
96
97 if (string_table_offset == 0 || symbol_table_offset == 0 || symbol_entry_size == 0) {
98 return {};
99 }
100
101 const auto string_table_address = text_offset + string_table_offset;
102 const auto symbol_table_address = text_offset + symbol_table_offset;
103
104 Symbols out;
105
106 VAddr symbol_index = symbol_table_address;
107 while (symbol_index < string_table_address) {
108 ELFSymbol symbol{};
109 Memory::ReadBlock(symbol_index, &symbol, sizeof(ELFSymbol));
110
111 VAddr string_offset = string_table_address + symbol.name_index;
112 std::string name;
113 for (u8 c = Memory::Read8(string_offset); c != 0; c = Memory::Read8(++string_offset)) {
114 name += static_cast<char>(c);
115 }
116
117 symbol_index += symbol_entry_size;
118 out.push_back({symbol, name});
119 }
120
121 return out;
122}
123
124std::optional<std::string> GetSymbolName(const Symbols& symbols, VAddr func_address) {
125 const auto iter =
126 std::find_if(symbols.begin(), symbols.end(), [func_address](const auto& pair) {
127 const auto& [symbol, name] = pair;
128 const auto end_address = symbol.value + symbol.size;
129 return func_address >= symbol.value && func_address < end_address;
130 });
131
132 if (iter == symbols.end()) {
133 return std::nullopt;
134 }
135
136 return iter->second;
137}
138
139} // Anonymous namespace
140
141constexpr u64 SEGMENT_BASE = 0x7100000000ull;
142
143std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktrace() const {
144 std::vector<BacktraceEntry> out;
145
146 auto fp = GetReg(29);
147 auto lr = GetReg(30);
148
18 while (true) { 149 while (true) {
19 LOG_ERROR(Core_ARM, "{:016X}", lr); 150 out.push_back({"", 0, lr, 0});
20 if (!fp) { 151 if (!fp) {
21 break; 152 break;
22 } 153 }
23 lr = Memory::Read64(fp + 8) - 4; 154 lr = Memory::Read64(fp + 8) - 4;
24 fp = Memory::Read64(fp); 155 fp = Memory::Read64(fp);
25 } 156 }
157
158 std::map<VAddr, std::string> modules;
159 auto& loader{System::GetInstance().GetAppLoader()};
160 if (loader.ReadNSOModules(modules) != Loader::ResultStatus::Success) {
161 return {};
162 }
163
164 std::map<std::string, Symbols> symbols;
165 for (const auto& module : modules) {
166 symbols.insert_or_assign(module.second, GetSymbols(module.first));
167 }
168
169 for (auto& entry : out) {
170 VAddr base = 0;
171 for (auto iter = modules.rbegin(); iter != modules.rend(); ++iter) {
172 const auto& module{*iter};
173 if (entry.original_address >= module.first) {
174 entry.module = module.second;
175 base = module.first;
176 break;
177 }
178 }
179
180 entry.offset = entry.original_address - base;
181 entry.address = SEGMENT_BASE + entry.offset;
182
183 if (entry.module.empty())
184 entry.module = "unknown";
185
186 const auto symbol_set = symbols.find(entry.module);
187 if (symbol_set != symbols.end()) {
188 const auto symbol = GetSymbolName(symbol_set->second, entry.offset);
189 if (symbol.has_value()) {
190 // TODO(DarkLordZach): Add demangling of symbol names.
191 entry.name = *symbol;
192 }
193 }
194 }
195
196 return out;
197}
198
199void ARM_Interface::LogBacktrace() const {
200 const VAddr sp = GetReg(13);
201 const VAddr pc = GetPC();
202 LOG_ERROR(Core_ARM, "Backtrace, sp={:016X}, pc={:016X}", sp, pc);
203 LOG_ERROR(Core_ARM, "{:20}{:20}{:20}{:20}{}", "Module Name", "Address", "Original Address",
204 "Offset", "Symbol");
205 LOG_ERROR(Core_ARM, "");
206
207 const auto backtrace = GetBacktrace();
208 for (const auto& entry : backtrace) {
209 LOG_ERROR(Core_ARM, "{:20}{:016X} {:016X} {:016X} {}", entry.module, entry.address,
210 entry.original_address, entry.offset, entry.name);
211 }
26} 212}
213
27} // namespace Core 214} // namespace Core