mirror of https://github.com/PCSX2/pcsx2.git
Debugger: Hash functions scanned in by the MIPS analyst
This commit is contained in:
parent
f963291970
commit
ed4fbb4f5a
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue