From ed4fbb4f5a6b71830e89197c1419a95fb9ac4d51 Mon Sep 17 00:00:00 2001 From: chaoticgd <43898262+chaoticgd@users.noreply.github.com> Date: Mon, 14 Oct 2024 14:45:09 +0100 Subject: [PATCH] Debugger: Hash functions scanned in by the MIPS analyst --- .../Debugger/SymbolTree/SymbolTreeWidgets.cpp | 5 +- pcsx2/DebugTools/MIPSAnalyst.cpp | 18 ++++-- pcsx2/DebugTools/MIPSAnalyst.h | 2 +- pcsx2/DebugTools/SymbolGuardian.cpp | 48 +++++++++++++++ pcsx2/DebugTools/SymbolGuardian.h | 13 ++++ pcsx2/DebugTools/SymbolImporter.cpp | 61 ++----------------- pcsx2/DebugTools/SymbolImporter.h | 8 --- 7 files changed, 85 insertions(+), 70 deletions(-) diff --git a/pcsx2-qt/Debugger/SymbolTree/SymbolTreeWidgets.cpp b/pcsx2-qt/Debugger/SymbolTree/SymbolTreeWidgets.cpp index 5cbd0067bc..a5907ee468 100644 --- a/pcsx2-qt/Debugger/SymbolTree/SymbolTreeWidgets.cpp +++ b/pcsx2-qt/Debugger/SymbolTree/SymbolTreeWidgets.cpp @@ -61,8 +61,9 @@ void SymbolTreeWidget::reset() m_ui.treeView->setColumnHidden(SymbolTreeModel::SIZE, !m_show_size_column || !m_show_size_column->isChecked()); - if (m_cpu.GetSymbolImporter()) - m_cpu.GetSymbolImporter()->UpdateFunctionHashes(m_cpu); + m_cpu.GetSymbolGuardian().ReadWrite([&](ccc::SymbolDatabase& database) { + m_cpu.GetSymbolGuardian().UpdateFunctionHashes(database, m_cpu); + }); SymbolFilters filters; std::unique_ptr root; diff --git a/pcsx2/DebugTools/MIPSAnalyst.cpp b/pcsx2/DebugTools/MIPSAnalyst.cpp index 5ae4f13d8e..75ba50e230 100644 --- a/pcsx2/DebugTools/MIPSAnalyst.cpp +++ b/pcsx2/DebugTools/MIPSAnalyst.cpp @@ -174,7 +174,7 @@ namespace MIPSAnalyst return furthestJumpbackAddr; } - void ScanForFunctions(ccc::SymbolDatabase& database, MemoryReader& reader, u32 startAddr, u32 endAddr) { + void ScanForFunctions(ccc::SymbolDatabase& database, MemoryReader& reader, u32 startAddr, u32 endAddr, bool generateHashes) { std::vector functions; AnalyzedFunction currentFunction = {startAddr}; @@ -317,10 +317,11 @@ namespace MIPSAnalyst for (const AnalyzedFunction& function : functions) { ccc::FunctionHandle handle = database.functions.first_handle_from_starting_address(function.start); ccc::Function* symbol = database.functions.symbol_from_handle(handle); + bool generateHash = false; if (!symbol) { std::string name; - + // The SNDLL importer may create label symbols for functions if // they're not in a section named ".text" since it can't // otherwise distinguish between functions and globals. @@ -331,7 +332,7 @@ namespace MIPSAnalyst break; } } - + if (name.empty()) { name = StringUtil::StdStringFromFormat("z_un_%08x", function.start); } @@ -342,13 +343,22 @@ namespace MIPSAnalyst Console.Error("MIPSAnalyst: %s", symbol_result.error().message.c_str()); return; } + symbol = *symbol_result; + generateHash = generateHashes; } if (symbol->size() == 0) { symbol->set_size(function.end - function.start + 4); } - + + if (generateHash) { + std::optional hash = SymbolGuardian::HashFunction(*symbol, reader); + if (hash.has_value()) { + symbol->set_original_hash(hash->get()); + } + } + symbol->is_no_return = function.suspectedNoReturn; } } diff --git a/pcsx2/DebugTools/MIPSAnalyst.h b/pcsx2/DebugTools/MIPSAnalyst.h index 9c5e411e11..073d996d86 100644 --- a/pcsx2/DebugTools/MIPSAnalyst.h +++ b/pcsx2/DebugTools/MIPSAnalyst.h @@ -27,7 +27,7 @@ namespace MIPSAnalyst char name[64]; }; - void ScanForFunctions(ccc::SymbolDatabase& database, MemoryReader& reader, u32 startAddr, u32 endAddr); + void ScanForFunctions(ccc::SymbolDatabase& database, MemoryReader& reader, u32 startAddr, u32 endAddr, bool generateHashes); enum LoadStoreLRType { LOADSTORE_NORMAL, LOADSTORE_LEFT, LOADSTORE_RIGHT }; diff --git a/pcsx2/DebugTools/SymbolGuardian.cpp b/pcsx2/DebugTools/SymbolGuardian.cpp index d3d159dc02..78d97ec8a6 100644 --- a/pcsx2/DebugTools/SymbolGuardian.cpp +++ b/pcsx2/DebugTools/SymbolGuardian.cpp @@ -3,6 +3,8 @@ #include "SymbolGuardian.h" +#include "DebugInterface.h" + SymbolGuardian R5900SymbolGuardian; SymbolGuardian R3000SymbolGuardian; @@ -149,6 +151,52 @@ FunctionInfo SymbolGuardian::FunctionOverlappingAddress(u32 address) const return info; } +void SymbolGuardian::GenerateFunctionHashes(ccc::SymbolDatabase& database, MemoryReader& reader) +{ + for (ccc::Function& function : database.functions) + { + std::optional hash = HashFunction(function, reader); + if (!hash.has_value()) + continue; + + function.set_original_hash(hash->get()); + } +} + +void SymbolGuardian::UpdateFunctionHashes(ccc::SymbolDatabase& database, MemoryReader& reader) +{ + for (ccc::Function& function : database.functions) + { + if (function.original_hash() == 0) + continue; + + std::optional hash = HashFunction(function, reader); + if (!hash.has_value()) + continue; + + function.set_current_hash(*hash); + } + + for (ccc::SourceFile& source_file : database.source_files) + source_file.check_functions_match(database); +} + +std::optional SymbolGuardian::HashFunction(const ccc::Function& function, MemoryReader& reader) +{ + if (!function.address().valid()) + return std::nullopt; + + if (function.size() == 0 || function.size() > _1mb) + return std::nullopt; + + ccc::FunctionHash hash; + + for (u32 i = 0; i < function.size() / 4; i++) + hash.update(reader.read32(function.address().value + i * 4)); + + return hash; +} + void SymbolGuardian::ClearIrxModules() { ReadWrite([&](ccc::SymbolDatabase& database) { diff --git a/pcsx2/DebugTools/SymbolGuardian.h b/pcsx2/DebugTools/SymbolGuardian.h index 2d5dc2841e..67bfd129c7 100644 --- a/pcsx2/DebugTools/SymbolGuardian.h +++ b/pcsx2/DebugTools/SymbolGuardian.h @@ -14,6 +14,8 @@ #include "common/Pcsx2Types.h" +class MemoryReader; + struct SymbolInfo { std::optional descriptor; @@ -71,6 +73,17 @@ public: FunctionInfo FunctionStartingAtAddress(u32 address) const; FunctionInfo FunctionOverlappingAddress(u32 address) const; + // Hash all the functions in the database and store the hashes in the + // original hash field of said objects. + static void GenerateFunctionHashes(ccc::SymbolDatabase& database, MemoryReader& reader); + + // Hash all the functions in the database that have original hashes and + // store the results in the current hash fields of said objects. + static void UpdateFunctionHashes(ccc::SymbolDatabase& database, MemoryReader& reader); + + // Hash a function and return the result. + static std::optional HashFunction(const ccc::Function& function, MemoryReader& reader); + // Delete all symbols from modules that have the "is_irx" flag set. void ClearIrxModules(); diff --git a/pcsx2/DebugTools/SymbolImporter.cpp b/pcsx2/DebugTools/SymbolImporter.cpp index 21781d3269..334168a0b0 100644 --- a/pcsx2/DebugTools/SymbolImporter.cpp +++ b/pcsx2/DebugTools/SymbolImporter.cpp @@ -204,7 +204,10 @@ void SymbolImporter::AnalyseElf( return; if (options.GenerateFunctionHashes) - ComputeOriginalFunctionHashes(temp_database, worker_symbol_file.elf()); + { + ElfMemoryReader reader(worker_symbol_file.elf()); + SymbolGuardian::GenerateFunctionHashes(temp_database, reader); + } if (m_interrupt_import_thread) return; @@ -506,12 +509,12 @@ void SymbolImporter::ScanForFunctions( case DebugFunctionScanMode::SCAN_ELF: { ElfMemoryReader reader(elf.elf()); - MIPSAnalyst::ScanForFunctions(database, reader, start_address, end_address); + MIPSAnalyst::ScanForFunctions(database, reader, start_address, end_address, options.GenerateFunctionHashes); break; } case DebugFunctionScanMode::SCAN_MEMORY: { - MIPSAnalyst::ScanForFunctions(database, r5900Debug, start_address, end_address); + MIPSAnalyst::ScanForFunctions(database, r5900Debug, start_address, end_address, options.GenerateFunctionHashes); break; } case DebugFunctionScanMode::SKIP: @@ -520,55 +523,3 @@ void SymbolImporter::ScanForFunctions( } } } - -void SymbolImporter::ComputeOriginalFunctionHashes(ccc::SymbolDatabase& database, const ccc::ElfFile& elf) -{ - for (ccc::Function& function : database.functions) - { - if (!function.address().valid()) - continue; - - if (function.size() == 0) - continue; - - ccc::Result> text = elf.get_array_virtual( - function.address().value, function.size() / 4); - if (!text.success()) - { - ccc::report_warning(text.error()); - break; - } - - ccc::FunctionHash hash; - for (u32 instruction : *text) - hash.update(instruction); - - function.set_original_hash(hash.get()); - } -} - -void SymbolImporter::UpdateFunctionHashes(DebugInterface& cpu) -{ - m_guardian.ReadWrite([&](ccc::SymbolDatabase& database) { - for (ccc::Function& function : database.functions) - { - if (!function.address().valid()) - continue; - - if (function.size() == 0) - continue; - - if (function.original_hash() == 0) - continue; - - ccc::FunctionHash hash; - for (u32 i = 0; i < function.size() / 4; i++) - hash.update(cpu.read32(function.address().value + i * 4)); - - function.set_current_hash(hash); - } - - for (ccc::SourceFile& source_file : database.source_files) - source_file.check_functions_match(database); - }); -} diff --git a/pcsx2/DebugTools/SymbolImporter.h b/pcsx2/DebugTools/SymbolImporter.h index cac10ff176..882f900bc1 100644 --- a/pcsx2/DebugTools/SymbolImporter.h +++ b/pcsx2/DebugTools/SymbolImporter.h @@ -49,14 +49,6 @@ public: static void ScanForFunctions( ccc::SymbolDatabase& database, const ccc::ElfSymbolFile& elf, const Pcsx2Config::DebugAnalysisOptions& options); - // Compute original hashes for all the functions based on the code stored in - // the ELF file. - static void ComputeOriginalFunctionHashes(ccc::SymbolDatabase& database, const ccc::ElfFile& elf); - - // Compute new hashes for all the functions to check if any of them have - // been overwritten. - void UpdateFunctionHashes(DebugInterface& cpu); - protected: SymbolGuardian& m_guardian;