mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-01 18:42:38 +01:00
206 lines
4.4 KiB
C++
206 lines
4.4 KiB
C++
// Copyright 2013 Dolphin Emulator Project
|
|
// Licensed under GPLv2
|
|
// Refer to the license.txt file included.
|
|
|
|
#include <string>
|
|
|
|
#include "Common/CommonTypes.h"
|
|
#include "Common/FileUtil.h"
|
|
|
|
#include "Core/HW/Memmap.h"
|
|
|
|
#include "Core/PowerPC/PPCAnalyst.h"
|
|
#include "Core/PowerPC/PPCSymbolDB.h"
|
|
#include "Core/PowerPC/SignatureDB.h"
|
|
|
|
namespace
|
|
{
|
|
|
|
// On-disk format for SignatureDB entries.
|
|
struct FuncDesc
|
|
{
|
|
u32 checkSum;
|
|
u32 size;
|
|
char name[128];
|
|
};
|
|
|
|
} // namespace
|
|
|
|
bool SignatureDB::Load(const std::string& filename)
|
|
{
|
|
File::IOFile f(filename, "rb");
|
|
if (!f)
|
|
return false;
|
|
u32 fcount = 0;
|
|
f.ReadArray(&fcount, 1);
|
|
for (size_t i = 0; i < fcount; i++)
|
|
{
|
|
FuncDesc temp;
|
|
memset(&temp, 0, sizeof(temp));
|
|
|
|
f.ReadArray(&temp, 1);
|
|
temp.name[sizeof(temp.name)-1] = 0;
|
|
|
|
DBFunc dbf;
|
|
dbf.name = temp.name;
|
|
dbf.size = temp.size;
|
|
database[temp.checkSum] = dbf;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool SignatureDB::Save(const std::string& filename)
|
|
{
|
|
File::IOFile f(filename, "wb");
|
|
if (!f)
|
|
{
|
|
ERROR_LOG(OSHLE, "Database save failed");
|
|
return false;
|
|
}
|
|
u32 fcount = (u32)database.size();
|
|
f.WriteArray(&fcount, 1);
|
|
for (const auto& entry : database)
|
|
{
|
|
FuncDesc temp;
|
|
memset(&temp, 0, sizeof(temp));
|
|
temp.checkSum = entry.first;
|
|
temp.size = entry.second.size;
|
|
strncpy(temp.name, entry.second.name.c_str(), 127);
|
|
f.WriteArray(&temp, 1);
|
|
}
|
|
|
|
INFO_LOG(OSHLE, "Database save successful");
|
|
return true;
|
|
}
|
|
|
|
//Adds a known function to the hash database
|
|
u32 SignatureDB::Add(u32 startAddr, u32 size, const std::string& name)
|
|
{
|
|
u32 hash = ComputeCodeChecksum(startAddr, startAddr + size);
|
|
|
|
DBFunc temp_dbfunc;
|
|
temp_dbfunc.size = size;
|
|
temp_dbfunc.name = name;
|
|
|
|
FuncDB::iterator iter = database.find(hash);
|
|
if (iter == database.end())
|
|
database[hash] = temp_dbfunc;
|
|
|
|
return hash;
|
|
}
|
|
|
|
void SignatureDB::List()
|
|
{
|
|
for (const auto& entry : database)
|
|
{
|
|
INFO_LOG(OSHLE, "%s : %i bytes, hash = %08x", entry.second.name.c_str(), entry.second.size, entry.first);
|
|
}
|
|
INFO_LOG(OSHLE, "%lu functions known in current database.",
|
|
(unsigned long)database.size());
|
|
}
|
|
|
|
void SignatureDB::Clear()
|
|
{
|
|
database.clear();
|
|
}
|
|
|
|
void SignatureDB::Apply(PPCSymbolDB *symbol_db)
|
|
{
|
|
for (const auto& entry : database)
|
|
{
|
|
u32 hash = entry.first;
|
|
Symbol *function = symbol_db->GetSymbolFromHash(hash);
|
|
if (function)
|
|
{
|
|
// Found the function. Let's rename it according to the symbol file.
|
|
if (entry.second.size == (unsigned int)function->size)
|
|
{
|
|
function->name = entry.second.name;
|
|
INFO_LOG(OSHLE, "Found %s at %08x (size: %08x)!", entry.second.name.c_str(), function->address, function->size);
|
|
}
|
|
else
|
|
{
|
|
function->name = entry.second.name;
|
|
ERROR_LOG(OSHLE, "Wrong size! Found %s at %08x (size: %08x instead of %08x)!",
|
|
entry.second.name.c_str(), function->address, function->size, entry.second.size);
|
|
}
|
|
}
|
|
}
|
|
symbol_db->Index();
|
|
}
|
|
|
|
void SignatureDB::Initialize(PPCSymbolDB *symbol_db, const std::string& prefix)
|
|
{
|
|
for (const auto& symbol : symbol_db->Symbols())
|
|
{
|
|
if ((symbol.second.name.substr(0, prefix.size()) == prefix) || prefix.empty())
|
|
{
|
|
DBFunc temp_dbfunc;
|
|
temp_dbfunc.name = symbol.second.name;
|
|
temp_dbfunc.size = symbol.second.size;
|
|
database[symbol.second.hash] = temp_dbfunc;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*static*/ u32 SignatureDB::ComputeCodeChecksum(u32 offsetStart, u32 offsetEnd)
|
|
{
|
|
u32 sum = 0;
|
|
for (u32 offset = offsetStart; offset <= offsetEnd; offset += 4)
|
|
{
|
|
u32 opcode = Memory::Read_Instruction(offset);
|
|
u32 op = opcode & 0xFC000000;
|
|
u32 op2 = 0;
|
|
u32 op3 = 0;
|
|
u32 auxop = op >> 26;
|
|
switch (auxop)
|
|
{
|
|
case 4: //PS instructions
|
|
op2 = opcode & 0x0000003F;
|
|
switch ( op2 )
|
|
{
|
|
case 0:
|
|
case 8:
|
|
case 16:
|
|
case 21:
|
|
case 22:
|
|
op3 = opcode & 0x000007C0;
|
|
}
|
|
break;
|
|
|
|
case 7: //addi muli etc
|
|
case 8:
|
|
case 10:
|
|
case 11:
|
|
case 12:
|
|
case 13:
|
|
case 14:
|
|
case 15:
|
|
op2 = opcode & 0x03FF0000;
|
|
break;
|
|
|
|
case 19: // MCRF??
|
|
case 31: //integer
|
|
case 63: //fpu
|
|
op2 = opcode & 0x000007FF;
|
|
break;
|
|
case 59: //fpu
|
|
op2 = opcode & 0x0000003F;
|
|
if (op2 < 16)
|
|
op3 = opcode & 0x000007C0;
|
|
break;
|
|
default:
|
|
if (auxop >= 32 && auxop < 56)
|
|
op2 = opcode & 0x03FF0000;
|
|
break;
|
|
}
|
|
// Checksum only uses opcode, not opcode data, because opcode data changes
|
|
// in all compilations, but opcodes don't!
|
|
sum = ( ( (sum << 17 ) & 0xFFFE0000 ) | ( (sum >> 15) & 0x0001FFFF ) );
|
|
sum = sum ^ (op | op2 | op3);
|
|
}
|
|
return sum;
|
|
}
|
|
|