Skip to content

Commit

Permalink
Debugger: Hash functions scanned in by the MIPS analyst
Browse files Browse the repository at this point in the history
  • Loading branch information
chaoticgd authored and F0bes committed Oct 18, 2024
1 parent f963291 commit ed4fbb4
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 70 deletions.
5 changes: 3 additions & 2 deletions pcsx2-qt/Debugger/SymbolTree/SymbolTreeWidgets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
18 changes: 14 additions & 4 deletions pcsx2/DebugTools/MIPSAnalyst.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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.
Expand All @@ -331,7 +332,7 @@ namespace MIPSAnalyst
break;
}
}

if (name.empty()) {
name = StringUtil::StdStringFromFormat("z_un_%08x", function.start);
}
Expand All @@ -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;
}
}
Expand Down
2 changes: 1 addition & 1 deletion pcsx2/DebugTools/MIPSAnalyst.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 };

Expand Down
48 changes: 48 additions & 0 deletions pcsx2/DebugTools/SymbolGuardian.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

#include "SymbolGuardian.h"

#include "DebugInterface.h"

SymbolGuardian R5900SymbolGuardian;
SymbolGuardian R3000SymbolGuardian;

Expand Down Expand Up @@ -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) {
Expand Down
13 changes: 13 additions & 0 deletions pcsx2/DebugTools/SymbolGuardian.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

#include "common/Pcsx2Types.h"

class MemoryReader;

struct SymbolInfo
{
std::optional<ccc::SymbolDescriptor> descriptor;
Expand Down Expand Up @@ -71,6 +73,17 @@ class SymbolGuardian
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();

Expand Down
61 changes: 6 additions & 55 deletions pcsx2/DebugTools/SymbolImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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:
Expand All @@ -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);
});
}
8 changes: 0 additions & 8 deletions pcsx2/DebugTools/SymbolImporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,6 @@ class SymbolImporter
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;

Expand Down

0 comments on commit ed4fbb4

Please sign in to comment.