Debugger: Hash functions scanned in by the MIPS analyst

This commit is contained in:
chaoticgd 2024-10-14 14:45:09 +01:00 committed by Ty
parent f963291970
commit ed4fbb4f5a
7 changed files with 85 additions and 70 deletions

View File

@ -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<SymbolTreeNode> root;

View File

@ -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<MIPSAnalyst::AnalyzedFunction> 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<ccc::FunctionHash> hash = SymbolGuardian::HashFunction(*symbol, reader);
if (hash.has_value()) {
symbol->set_original_hash(hash->get());
}
}
symbol->is_no_return = function.suspectedNoReturn;
}
}

View File

@ -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 };

View File

@ -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<ccc::FunctionHash> 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<ccc::FunctionHash> 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<ccc::FunctionHash> 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) {

View File

@ -14,6 +14,8 @@
#include "common/Pcsx2Types.h"
class MemoryReader;
struct SymbolInfo
{
std::optional<ccc::SymbolDescriptor> 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<ccc::FunctionHash> HashFunction(const ccc::Function& function, MemoryReader& reader);
// Delete all symbols from modules that have the "is_irx" flag set.
void ClearIrxModules();

View File

@ -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<std::span<const u32>> text = elf.get_array_virtual<u32>(
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);
});
}

View File

@ -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;