ARM/WaitTree: Better track the CallStack for each thread.
This commit is contained in:
		
							parent
							
								
									87c49aa7be
								
							
						
					
					
						commit
						7b18174eef
					
				| @ -139,6 +139,63 @@ 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({"", 0, lr, 0}); | ||||
|         if (!fp) { | ||||
|             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(); | ||||
|  | ||||
| @ -164,6 +164,9 @@ public: | ||||
|         std::string name; | ||||
|     }; | ||||
| 
 | ||||
|     static std::vector<BacktraceEntry> GetBacktraceFromContext(System& system, | ||||
|                                                                const ThreadContext64& ctx); | ||||
| 
 | ||||
|     std::vector<BacktraceEntry> GetBacktrace() const; | ||||
| 
 | ||||
|     /// fp (= r29) points to the last frame record.
 | ||||
|  | ||||
| @ -2,10 +2,13 @@ | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <fmt/format.h> | ||||
| 
 | ||||
| #include "yuzu/debugger/wait_tree.h" | ||||
| #include "yuzu/util/util.h" | ||||
| 
 | ||||
| #include "common/assert.h" | ||||
| #include "core/arm/arm_interface.h" | ||||
| #include "core/core.h" | ||||
| #include "core/hle/kernel/handle_table.h" | ||||
| #include "core/hle/kernel/mutex.h" | ||||
| @ -116,20 +119,20 @@ QString WaitTreeCallstack::GetText() const { | ||||
| std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() const { | ||||
|     std::vector<std::unique_ptr<WaitTreeItem>> list; | ||||
| 
 | ||||
|     constexpr std::size_t BaseRegister = 29; | ||||
|     auto& memory = Core::System::GetInstance().Memory(); | ||||
|     u64 base_pointer = thread.GetContext64().cpu_registers[BaseRegister]; | ||||
|     if (thread.IsHLEThread()) { | ||||
|         return list; | ||||
|     } | ||||
| 
 | ||||
|     while (base_pointer != 0) { | ||||
|         const u64 lr = memory.Read64(base_pointer + sizeof(u64)); | ||||
|         if (lr == 0) { | ||||
|             break; | ||||
|         } | ||||
|     if (thread.GetOwnerProcess() == nullptr || !thread.GetOwnerProcess()->Is64BitProcess()) { | ||||
|         return list; | ||||
|     } | ||||
| 
 | ||||
|         list.push_back(std::make_unique<WaitTreeText>( | ||||
|             tr("0x%1").arg(lr - sizeof(u32), 16, 16, QLatin1Char{'0'}))); | ||||
|     auto backtrace = Core::ARM_Interface::GetBacktraceFromContext(Core::System::GetInstance(), thread.GetContext64()); | ||||
| 
 | ||||
|         base_pointer = memory.Read64(base_pointer); | ||||
|     for (auto& entry : backtrace) { | ||||
|         std::string s = fmt::format("{:20}{:016X} {:016X} {:016X} {}", entry.module, entry.address, | ||||
|                   entry.original_address, entry.offset, entry.name); | ||||
|         list.push_back(std::make_unique<WaitTreeText>(QString::fromStdString(s))); | ||||
|     } | ||||
| 
 | ||||
|     return list; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Fernando Sahmkow
						Fernando Sahmkow