mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-05 14:31:24 +12:00
204 lines
4.9 KiB
C++
204 lines
4.9 KiB
C++
#include "stdafx.h"
|
|
#include "rpcs3/Ini.h"
|
|
#include "Utilities/Log.h"
|
|
#include "Emu/SysCalls/Modules.h"
|
|
#include "Static.h"
|
|
|
|
void StaticFuncManager::StaticAnalyse(void* ptr, u32 size, u32 base)
|
|
{
|
|
u32* data = (u32*)ptr; size /= 4;
|
|
|
|
if(!Ini.HLEHookStFunc.GetValue())
|
|
return;
|
|
|
|
// TODO: optimize search
|
|
for (u32 i = 0; i < size; i++)
|
|
{
|
|
for (u32 j = 0; j < m_static_funcs_list.size(); j++)
|
|
{
|
|
if ((data[i] & m_static_funcs_list[j]->ops[0].mask) == m_static_funcs_list[j]->ops[0].crc)
|
|
{
|
|
bool found = true;
|
|
u32 can_skip = 0;
|
|
for (u32 k = i, x = 0; x + 1 <= m_static_funcs_list[j]->ops.size(); k++, x++)
|
|
{
|
|
if (k >= size)
|
|
{
|
|
found = false;
|
|
break;
|
|
}
|
|
|
|
// skip NOP
|
|
if (data[k] == se32(0x60000000))
|
|
{
|
|
x--;
|
|
continue;
|
|
}
|
|
|
|
const u32 mask = m_static_funcs_list[j]->ops[x].mask;
|
|
const u32 crc = m_static_funcs_list[j]->ops[x].crc;
|
|
|
|
if (!mask)
|
|
{
|
|
// TODO: define syntax
|
|
if (crc < 4) // skip various number of instructions that don't match next pattern entry
|
|
{
|
|
can_skip += crc;
|
|
k--; // process this position again
|
|
}
|
|
else if (data[k] != crc) // skippable pattern ("optional" instruction), no mask allowed
|
|
{
|
|
k--;
|
|
if (can_skip) // cannot define this behaviour properly
|
|
{
|
|
LOG_WARNING(LOADER, "StaticAnalyse(): can_skip = %d (unchanged)", can_skip);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (can_skip) // cannot define this behaviour properly
|
|
{
|
|
LOG_WARNING(LOADER, "StaticAnalyse(): can_skip = %d (set to 0)", can_skip);
|
|
can_skip = 0;
|
|
}
|
|
}
|
|
}
|
|
else if ((data[k] & mask) != crc) // masked pattern
|
|
{
|
|
if (can_skip)
|
|
{
|
|
can_skip--;
|
|
}
|
|
else
|
|
{
|
|
found = false;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
can_skip = 0;
|
|
}
|
|
}
|
|
if (found)
|
|
{
|
|
LOG_NOTICE(LOADER, "Function '%s' hooked (addr=0x%x)", m_static_funcs_list[j]->name, i * 4 + base);
|
|
m_static_funcs_list[j]->found++;
|
|
data[i+0] = re32(0x04000000 | m_static_funcs_list[j]->index); // hack
|
|
data[i+2] = se32(0x4e800020); // blr
|
|
i += 1; // skip modified code
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// check function groups
|
|
for (u32 i = 0; i < m_static_funcs_list.size(); i++)
|
|
{
|
|
if (m_static_funcs_list[i]->found) // start from some group
|
|
{
|
|
const u64 group = m_static_funcs_list[i]->group;
|
|
|
|
enum GroupSearchResult : u32
|
|
{
|
|
GSR_SUCCESS = 0, // every function from this group has been found once
|
|
GSR_MISSING = 1, // (error) some function not found
|
|
GSR_EXCESS = 2, // (error) some function found twice or more
|
|
};
|
|
u32 res = GSR_SUCCESS;
|
|
|
|
// analyse
|
|
for (u32 j = 0; j < m_static_funcs_list.size(); j++) if (m_static_funcs_list[j]->group == group)
|
|
{
|
|
u32 count = m_static_funcs_list[j]->found;
|
|
|
|
if (count == 0) // not found
|
|
{
|
|
// check if this function has been found with different pattern
|
|
for (u32 k = 0; k < m_static_funcs_list.size(); k++) if (m_static_funcs_list[k]->group == group)
|
|
{
|
|
if (k != j && m_static_funcs_list[k]->index == m_static_funcs_list[j]->index)
|
|
{
|
|
count += m_static_funcs_list[k]->found;
|
|
}
|
|
}
|
|
if (count == 0)
|
|
{
|
|
res |= GSR_MISSING;
|
|
LOG_ERROR(LOADER, "Function '%s' not found", m_static_funcs_list[j]->name);
|
|
}
|
|
else if (count > 1)
|
|
{
|
|
res |= GSR_EXCESS;
|
|
}
|
|
}
|
|
else if (count == 1) // found
|
|
{
|
|
// ensure that this function has NOT been found with different pattern
|
|
for (u32 k = 0; k < m_static_funcs_list.size(); k++) if (m_static_funcs_list[k]->group == group)
|
|
{
|
|
if (k != j && m_static_funcs_list[k]->index == m_static_funcs_list[j]->index)
|
|
{
|
|
if (m_static_funcs_list[k]->found)
|
|
{
|
|
res |= GSR_EXCESS;
|
|
LOG_ERROR(LOADER, "Function '%s' hooked twice", m_static_funcs_list[j]->name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
res |= GSR_EXCESS;
|
|
LOG_ERROR(LOADER, "Function '%s' hooked twice", m_static_funcs_list[j]->name);
|
|
}
|
|
}
|
|
|
|
// clear data
|
|
for (u32 j = 0; j < m_static_funcs_list.size(); j++)
|
|
{
|
|
if (m_static_funcs_list[j]->group == group) m_static_funcs_list[j]->found = 0;
|
|
}
|
|
|
|
char name[9] = "????????";
|
|
|
|
*(u64*)name = group;
|
|
|
|
if (res == GSR_SUCCESS)
|
|
{
|
|
LOG_SUCCESS(LOADER, "Function group [%s] successfully hooked", std::string(name, 9).c_str());
|
|
}
|
|
else
|
|
{
|
|
LOG_ERROR(LOADER, "Function group [%s] failed:%s%s", std::string(name, 9).c_str(),
|
|
(res & GSR_MISSING ? " missing;" : ""),
|
|
(res & GSR_EXCESS ? " excess;" : ""));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void StaticFuncManager::StaticFinalize()
|
|
{
|
|
for (SFunc *s : m_static_funcs_list)
|
|
{
|
|
delete s;
|
|
}
|
|
m_static_funcs_list.clear();
|
|
}
|
|
|
|
void StaticFuncManager::push_back(SFunc *ele)
|
|
{
|
|
m_static_funcs_list.push_back(ele);
|
|
}
|
|
|
|
SFunc *StaticFuncManager::operator[](size_t i)
|
|
{
|
|
return m_static_funcs_list[i];
|
|
}
|
|
|
|
StaticFuncManager::~StaticFuncManager()
|
|
{
|
|
StaticFinalize();
|
|
}
|
|
|