Files
dolphin/Source/Core/Core/PowerPC/SignatureDB.cpp
magumagu ac54c6a4e2 Make address translation respect the CPU translation mode.
The PowerPC CPU has bits in MSR (DR and IR) which control whether
addresses are translated. We should respect these instead of mixing
physical addresses and translated addresses into the same address space.

This is mostly mass-renaming calls to memory accesses APIs from places
which expect address translation to use a different version from those
which do not expect address translation.

This does very little on its own, but it's the first step to a correct BAT
implementation.
2015-02-11 13:56:22 -08:00

207 lines
4.5 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 - 4);
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 ((prefix.empty() && (!symbol.second.name.empty()) && symbol.second.name.substr(0, 3) != "zz_" && symbol.second.name.substr(0, 1) != ".") ||
((!prefix.empty()) && symbol.second.name.substr(0, prefix.size()) == prefix))
{
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 = PowerPC::HostRead_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;
}