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());
|
m_ui.treeView->setColumnHidden(SymbolTreeModel::SIZE, !m_show_size_column || !m_show_size_column->isChecked());
|
||||||
|
|
||||||
if (m_cpu.GetSymbolImporter())
|
m_cpu.GetSymbolGuardian().ReadWrite([&](ccc::SymbolDatabase& database) {
|
||||||
m_cpu.GetSymbolImporter()->UpdateFunctionHashes(m_cpu);
|
m_cpu.GetSymbolGuardian().UpdateFunctionHashes(database, m_cpu);
|
||||||
|
});
|
||||||
|
|
||||||
SymbolFilters filters;
|
SymbolFilters filters;
|
||||||
std::unique_ptr<SymbolTreeNode> root;
|
std::unique_ptr<SymbolTreeNode> root;
|
||||||
|
|
|
@ -174,7 +174,7 @@ namespace MIPSAnalyst
|
||||||
return furthestJumpbackAddr;
|
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;
|
std::vector<MIPSAnalyst::AnalyzedFunction> functions;
|
||||||
AnalyzedFunction currentFunction = {startAddr};
|
AnalyzedFunction currentFunction = {startAddr};
|
||||||
|
|
||||||
|
@ -317,10 +317,11 @@ namespace MIPSAnalyst
|
||||||
for (const AnalyzedFunction& function : functions) {
|
for (const AnalyzedFunction& function : functions) {
|
||||||
ccc::FunctionHandle handle = database.functions.first_handle_from_starting_address(function.start);
|
ccc::FunctionHandle handle = database.functions.first_handle_from_starting_address(function.start);
|
||||||
ccc::Function* symbol = database.functions.symbol_from_handle(handle);
|
ccc::Function* symbol = database.functions.symbol_from_handle(handle);
|
||||||
|
bool generateHash = false;
|
||||||
|
|
||||||
if (!symbol) {
|
if (!symbol) {
|
||||||
std::string name;
|
std::string name;
|
||||||
|
|
||||||
// The SNDLL importer may create label symbols for functions if
|
// The SNDLL importer may create label symbols for functions if
|
||||||
// they're not in a section named ".text" since it can't
|
// they're not in a section named ".text" since it can't
|
||||||
// otherwise distinguish between functions and globals.
|
// otherwise distinguish between functions and globals.
|
||||||
|
@ -331,7 +332,7 @@ namespace MIPSAnalyst
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name.empty()) {
|
if (name.empty()) {
|
||||||
name = StringUtil::StdStringFromFormat("z_un_%08x", function.start);
|
name = StringUtil::StdStringFromFormat("z_un_%08x", function.start);
|
||||||
}
|
}
|
||||||
|
@ -342,13 +343,22 @@ namespace MIPSAnalyst
|
||||||
Console.Error("MIPSAnalyst: %s", symbol_result.error().message.c_str());
|
Console.Error("MIPSAnalyst: %s", symbol_result.error().message.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
symbol = *symbol_result;
|
symbol = *symbol_result;
|
||||||
|
generateHash = generateHashes;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (symbol->size() == 0) {
|
if (symbol->size() == 0) {
|
||||||
symbol->set_size(function.end - function.start + 4);
|
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;
|
symbol->is_no_return = function.suspectedNoReturn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ namespace MIPSAnalyst
|
||||||
char name[64];
|
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 };
|
enum LoadStoreLRType { LOADSTORE_NORMAL, LOADSTORE_LEFT, LOADSTORE_RIGHT };
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
#include "SymbolGuardian.h"
|
#include "SymbolGuardian.h"
|
||||||
|
|
||||||
|
#include "DebugInterface.h"
|
||||||
|
|
||||||
SymbolGuardian R5900SymbolGuardian;
|
SymbolGuardian R5900SymbolGuardian;
|
||||||
SymbolGuardian R3000SymbolGuardian;
|
SymbolGuardian R3000SymbolGuardian;
|
||||||
|
|
||||||
|
@ -149,6 +151,52 @@ FunctionInfo SymbolGuardian::FunctionOverlappingAddress(u32 address) const
|
||||||
return info;
|
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()
|
void SymbolGuardian::ClearIrxModules()
|
||||||
{
|
{
|
||||||
ReadWrite([&](ccc::SymbolDatabase& database) {
|
ReadWrite([&](ccc::SymbolDatabase& database) {
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
|
|
||||||
#include "common/Pcsx2Types.h"
|
#include "common/Pcsx2Types.h"
|
||||||
|
|
||||||
|
class MemoryReader;
|
||||||
|
|
||||||
struct SymbolInfo
|
struct SymbolInfo
|
||||||
{
|
{
|
||||||
std::optional<ccc::SymbolDescriptor> descriptor;
|
std::optional<ccc::SymbolDescriptor> descriptor;
|
||||||
|
@ -71,6 +73,17 @@ public:
|
||||||
FunctionInfo FunctionStartingAtAddress(u32 address) const;
|
FunctionInfo FunctionStartingAtAddress(u32 address) const;
|
||||||
FunctionInfo FunctionOverlappingAddress(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.
|
// Delete all symbols from modules that have the "is_irx" flag set.
|
||||||
void ClearIrxModules();
|
void ClearIrxModules();
|
||||||
|
|
||||||
|
|
|
@ -204,7 +204,10 @@ void SymbolImporter::AnalyseElf(
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (options.GenerateFunctionHashes)
|
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)
|
if (m_interrupt_import_thread)
|
||||||
return;
|
return;
|
||||||
|
@ -506,12 +509,12 @@ void SymbolImporter::ScanForFunctions(
|
||||||
case DebugFunctionScanMode::SCAN_ELF:
|
case DebugFunctionScanMode::SCAN_ELF:
|
||||||
{
|
{
|
||||||
ElfMemoryReader reader(elf.elf());
|
ElfMemoryReader reader(elf.elf());
|
||||||
MIPSAnalyst::ScanForFunctions(database, reader, start_address, end_address);
|
MIPSAnalyst::ScanForFunctions(database, reader, start_address, end_address, options.GenerateFunctionHashes);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DebugFunctionScanMode::SCAN_MEMORY:
|
case DebugFunctionScanMode::SCAN_MEMORY:
|
||||||
{
|
{
|
||||||
MIPSAnalyst::ScanForFunctions(database, r5900Debug, start_address, end_address);
|
MIPSAnalyst::ScanForFunctions(database, r5900Debug, start_address, end_address, options.GenerateFunctionHashes);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DebugFunctionScanMode::SKIP:
|
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(
|
static void ScanForFunctions(
|
||||||
ccc::SymbolDatabase& database, const ccc::ElfSymbolFile& elf, const Pcsx2Config::DebugAnalysisOptions& options);
|
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:
|
protected:
|
||||||
SymbolGuardian& m_guardian;
|
SymbolGuardian& m_guardian;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue