StaticFuncManager removed

This commit is contained in:
Nekotekina 2015-02-21 17:07:22 +03:00
parent a182743561
commit 9ee9523680
12 changed files with 209 additions and 254 deletions

View file

@ -4,7 +4,6 @@
#include "Emu/SysCalls/SysCalls.h"
#include "rpcs3/Ini.h"
#include "Emu/System.h"
#include "Emu/SysCalls/Static.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/Memory/Memory.h"
#include "Emu/SysCalls/lv2/sys_time.h"

View file

@ -6,7 +6,6 @@
#include "Emu/Cell/PPUThread.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/Static.h"
#include "Emu/Cell/PPUDecoder.h"
#include "Emu/Cell/PPUInterpreter.h"
#include "Emu/Cell/PPULLVMRecompiler.h"

View file

@ -1,16 +1,17 @@
#include "stdafx.h"
#include "Ini.h"
#include "Utilities/Log.h"
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/SysCalls/Modules.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/SysCalls/Static.h"
#include "Emu/SysCalls/CB_FUNC.h"
#include "Crypto/sha1.h"
#include "ModuleManager.h"
#include "Emu/Cell/PPUInstrTable.h"
std::vector<ModuleFunc> g_ppu_func_list;
std::vector<StaticFunc> g_ppu_func_subs;
u32 add_ppu_func(ModuleFunc func)
{
@ -38,6 +39,33 @@ u32 add_ppu_func(ModuleFunc func)
return (u32)g_ppu_func_list.size() - 1;
}
u32 add_ppu_func_sub(StaticFunc func)
{
g_ppu_func_subs.push_back(func);
return func.index;
}
u32 add_ppu_func_sub(const char group[8], const u64 ops[], const char* name, Module* module, ppu_func_caller func)
{
StaticFunc sf;
sf.index = add_ppu_func(ModuleFunc(get_function_id(name), module, func));
sf.name = name;
sf.group = *(u64*)group;
sf.found = 0;
// TODO: check for self-inclusions, use CRC
for (u32 i = 0; ops[i]; i++)
{
SFuncOp op;
op.mask = re32((u32)(ops[i] >> 32));
op.crc = re32((u32)(ops[i]));
if (op.mask) op.crc &= op.mask;
sf.ops.push_back(op);
}
return add_ppu_func_sub(sf);
}
ModuleFunc* get_ppu_func_by_nid(u32 nid, u32* out_index)
{
for (auto& f : g_ppu_func_list)
@ -101,6 +129,7 @@ void execute_ppu_func_by_index(PPUThread& CPU, u32 index)
void clear_ppu_functions()
{
g_ppu_func_list.clear();
g_ppu_func_subs.clear();
}
u32 get_function_id(const char* name)
@ -119,6 +148,180 @@ u32 get_function_id(const char* name)
return (u32&)output[0];
}
void hook_ppu_funcs(u32* base, u32 size)
{
size /= 4;
if (!Ini.HLEHookStFunc.GetValue())
return;
// TODO: optimize search
for (u32 i = 0; i < size; i++)
{
for (u32 j = 0; j < g_ppu_func_subs.size(); j++)
{
if ((base[i] & g_ppu_func_subs[j].ops[0].mask) == g_ppu_func_subs[j].ops[0].crc)
{
bool found = true;
u32 can_skip = 0;
for (u32 k = i, x = 0; x + 1 <= g_ppu_func_subs[j].ops.size(); k++, x++)
{
if (k >= size)
{
found = false;
break;
}
// skip NOP
if (base[k] == se32(0x60000000))
{
x--;
continue;
}
const u32 mask = g_ppu_func_subs[j].ops[x].mask;
const u32 crc = g_ppu_func_subs[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 (base[k] != crc) // skippable pattern ("optional" instruction), no mask allowed
{
k--;
if (can_skip) // cannot define this behaviour properly
{
LOG_WARNING(LOADER, "hook_ppu_funcs(): can_skip = %d (unchanged)", can_skip);
}
}
else
{
if (can_skip) // cannot define this behaviour properly
{
LOG_WARNING(LOADER, "hook_ppu_funcs(): can_skip = %d (set to 0)", can_skip);
can_skip = 0;
}
}
}
else if ((base[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)", g_ppu_func_subs[j].name, vm::get_addr(base + i * 4));
g_ppu_func_subs[j].found++;
base[i + 0] = re32(0x04000000 | g_ppu_func_subs[j].index); // hack
base[i + 1] = se32(0x4e800020); // blr
i += 1; // skip modified code
}
}
}
}
// check function groups
for (u32 i = 0; i < g_ppu_func_subs.size(); i++)
{
if (g_ppu_func_subs[i].found) // start from some group
{
const u64 group = g_ppu_func_subs[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 < g_ppu_func_subs.size(); j++) if (g_ppu_func_subs[j].group == group)
{
u32 count = g_ppu_func_subs[j].found;
if (count == 0) // not found
{
// check if this function has been found with different pattern
for (u32 k = 0; k < g_ppu_func_subs.size(); k++) if (g_ppu_func_subs[k].group == group)
{
if (k != j && g_ppu_func_subs[k].index == g_ppu_func_subs[j].index)
{
count += g_ppu_func_subs[k].found;
}
}
if (count == 0)
{
res |= GSR_MISSING;
LOG_ERROR(LOADER, "Function '%s' not found", g_ppu_func_subs[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 < g_ppu_func_subs.size(); k++) if (g_ppu_func_subs[k].group == group)
{
if (k != j && g_ppu_func_subs[k].index == g_ppu_func_subs[j].index)
{
if (g_ppu_func_subs[k].found)
{
res |= GSR_EXCESS;
LOG_ERROR(LOADER, "Function '%s' hooked twice", g_ppu_func_subs[j].name);
}
}
}
}
else
{
res |= GSR_EXCESS;
LOG_ERROR(LOADER, "Function '%s' hooked twice", g_ppu_func_subs[j].name);
}
}
// clear data
for (u32 j = 0; j < g_ppu_func_subs.size(); j++)
{
if (g_ppu_func_subs[j].group == group) g_ppu_func_subs[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;" : ""));
}
}
}
}
Module::Module(const char* name, void(*init)())
: m_is_loaded(false)
, m_name(name)

View file

@ -28,7 +28,7 @@ struct SFuncOp
u32 mask;
};
struct SFunc
struct StaticFunc
{
u32 index;
const char* name;
@ -37,8 +37,6 @@ struct SFunc
u32 found;
};
class StaticFuncManager;
class Module : public LogBase
{
std::string m_name;
@ -118,9 +116,11 @@ void execute_ppu_func_by_index(PPUThread& CPU, u32 id);
void clear_ppu_functions();
u32 get_function_id(const char* name);
u32 add_ppu_func_sub(SFunc sf);
u32 add_ppu_func_sub(StaticFunc sf);
u32 add_ppu_func_sub(const char group[8], const u64 ops[], const char* name, Module* module, ppu_func_caller func);
void hook_ppu_funcs(u32* base, u32 size);
#define REG_FUNC(module, name) add_ppu_func(ModuleFunc(get_function_id(#name), &module, bind_func(name)))
#define REG_UNNAMED(module, nid) add_ppu_func(ModuleFunc(0x##nid, &module, bind_func(_nid_##nid)))

View file

@ -1,215 +0,0 @@
#include "stdafx.h"
#include "rpcs3/Ini.h"
#include "Utilities/Log.h"
#include "Emu/SysCalls/Modules.h"
#include "Static.h"
std::vector<SFunc> g_ppu_func_subs;
u32 add_ppu_func_sub(SFunc func)
{
g_ppu_func_subs.push_back(func);
return func.index;
}
u32 add_ppu_func_sub(const char group[8], const u64 ops[], const char* name, Module* module, ppu_func_caller func)
{
SFunc sf;
sf.index = add_ppu_func(ModuleFunc(get_function_id(name), module, func));
sf.name = name;
sf.group = *(u64*)group;
sf.found = 0;
// TODO: check for self-inclusions, use CRC
for (u32 i = 0; ops[i]; i++)
{
SFuncOp op;
op.mask = ops[i] >> 32;
op.crc = (u32)ops[i];
if (op.mask) op.crc &= op.mask;
op.mask = re32(op.mask);
op.crc = re32(op.crc);
sf.ops.push_back(op);
}
return add_ppu_func_sub(sf);
}
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 < g_ppu_func_subs.size(); j++)
{
if ((data[i] & g_ppu_func_subs[j].ops[0].mask) == g_ppu_func_subs[j].ops[0].crc)
{
bool found = true;
u32 can_skip = 0;
for (u32 k = i, x = 0; x + 1 <= g_ppu_func_subs[j].ops.size(); k++, x++)
{
if (k >= size)
{
found = false;
break;
}
// skip NOP
if (data[k] == se32(0x60000000))
{
x--;
continue;
}
const u32 mask = g_ppu_func_subs[j].ops[x].mask;
const u32 crc = g_ppu_func_subs[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)", g_ppu_func_subs[j].name, i * 4 + base);
g_ppu_func_subs[j].found++;
data[i + 0] = re32(0x04000000 | g_ppu_func_subs[j].index); // hack
data[i + 1] = se32(0x4e800020); // blr
i += 1; // skip modified code
}
}
}
}
// check function groups
for (u32 i = 0; i < g_ppu_func_subs.size(); i++)
{
if (g_ppu_func_subs[i].found) // start from some group
{
const u64 group = g_ppu_func_subs[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 < g_ppu_func_subs.size(); j++) if (g_ppu_func_subs[j].group == group)
{
u32 count = g_ppu_func_subs[j].found;
if (count == 0) // not found
{
// check if this function has been found with different pattern
for (u32 k = 0; k < g_ppu_func_subs.size(); k++) if (g_ppu_func_subs[k].group == group)
{
if (k != j && g_ppu_func_subs[k].index == g_ppu_func_subs[j].index)
{
count += g_ppu_func_subs[k].found;
}
}
if (count == 0)
{
res |= GSR_MISSING;
LOG_ERROR(LOADER, "Function '%s' not found", g_ppu_func_subs[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 < g_ppu_func_subs.size(); k++) if (g_ppu_func_subs[k].group == group)
{
if (k != j && g_ppu_func_subs[k].index == g_ppu_func_subs[j].index)
{
if (g_ppu_func_subs[k].found)
{
res |= GSR_EXCESS;
LOG_ERROR(LOADER, "Function '%s' hooked twice", g_ppu_func_subs[j].name);
}
}
}
}
else
{
res |= GSR_EXCESS;
LOG_ERROR(LOADER, "Function '%s' hooked twice", g_ppu_func_subs[j].name);
}
}
// clear data
for (u32 j = 0; j < g_ppu_func_subs.size(); j++)
{
if (g_ppu_func_subs[j].group == group) g_ppu_func_subs[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()
{
g_ppu_func_subs.clear();
}

View file

@ -1,8 +0,0 @@
#pragma once
class StaticFuncManager
{
public:
void StaticAnalyse(void* ptr, u32 size, u32 base);
void StaticFinalize();
};

View file

@ -7,7 +7,6 @@
#include "Emu/GameInfo.h"
#include "Emu/ARMv7/PSVFuncList.h"
#include "Emu/ARMv7/PSVObjectList.h"
#include "Emu/SysCalls/Static.h"
#include "Emu/SysCalls/ModuleManager.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/Cell/SPUThread.h"
@ -57,7 +56,6 @@ Emulator::Emulator()
, m_audio_manager(new AudioManager())
, m_callback_manager(new CallbackManager())
, m_event_manager(new EventManager())
, m_sfunc_manager(new StaticFuncManager())
, m_module_manager(new ModuleManager())
, m_sync_prim_manager(new SyncPrimManager())
, m_vfs(new VFS())
@ -77,7 +75,6 @@ Emulator::~Emulator()
delete m_audio_manager;
delete m_callback_manager;
delete m_event_manager;
delete m_sfunc_manager;
delete m_module_manager;
delete m_sync_prim_manager;
delete m_vfs;
@ -397,7 +394,6 @@ void Emulator::Stop()
GetMouseManager().Close();
GetCallbackManager().Clear();
GetModuleManager().Close();
GetSFuncManager().StaticFinalize();
GetSyncPrimManager().Close();
CurGameInfo.Reset();

View file

@ -21,7 +21,6 @@ class CallbackManager;
class CPUThread;
class EventManager;
class ModuleManager;
class StaticFuncManager;
class SyncPrimManager;
struct VFS;
@ -100,7 +99,6 @@ class Emulator
AudioManager* m_audio_manager;
CallbackManager* m_callback_manager;
EventManager* m_event_manager;
StaticFuncManager* m_sfunc_manager;
ModuleManager* m_module_manager;
SyncPrimManager* m_sync_prim_manager;
VFS* m_vfs;
@ -163,7 +161,6 @@ public:
std::vector<u64>& GetBreakPoints() { return m_break_points; }
std::vector<u64>& GetMarkedPoints() { return m_marked_points; }
EventManager& GetEventManager() { return *m_event_manager; }
StaticFuncManager& GetSFuncManager() { return *m_sfunc_manager; }
ModuleManager& GetModuleManager() { return *m_module_manager; }
SyncPrimManager& GetSyncPrimManager() { return *m_sync_prim_manager; }

View file

@ -542,13 +542,6 @@ void MainFrame::Config(wxCommandEvent& WXUNUSED(event))
cbox_hle_loglvl ->SetSelection(Ini.HLELogLvl.GetValue());
cbox_sys_lang ->SetSelection(Ini.SysLanguage.GetValue());
// Enable/Disable parameters
chbox_audio_dump->Enable(Emu.IsStopped());
chbox_audio_conv->Enable(Emu.IsStopped());
chbox_hle_logging->Enable(Emu.IsStopped());
chbox_rsx_logging->Enable(Emu.IsStopped());
chbox_hle_hook_stfunc->Enable(Emu.IsStopped());
s_round_cpu_decoder->Add(cbox_cpu_decoder, wxSizerFlags().Border(wxALL, 5).Expand());
s_round_spu_decoder->Add(cbox_spu_decoder, wxSizerFlags().Border(wxALL, 5).Expand());

View file

@ -7,7 +7,6 @@
#include "Emu/Memory/Memory.h"
#include "Emu/System.h"
#include "Emu/SysCalls/SysCalls.h"
#include "Emu/SysCalls/Static.h"
#include "Emu/SysCalls/ModuleManager.h"
#include "Emu/SysCalls/lv2/sys_prx.h"
#include "Emu/Cell/PPUInstrTable.h"
@ -532,7 +531,7 @@ namespace loader
{
m_stream->Seek(handler::get_stream_offset() + phdr.p_offset);
m_stream->Read(phdr.p_vaddr.get_ptr(), phdr.p_filesz);
Emu.GetSFuncManager().StaticAnalyse(phdr.p_vaddr.get_ptr(), (u32)phdr.p_filesz, phdr.p_vaddr.addr());
hook_ppu_funcs((u32*)phdr.p_vaddr.get_ptr(), vm::cast(phdr.p_filesz));
}
}
break;

View file

@ -278,7 +278,6 @@
<ClCompile Include="Emu\SysCalls\Modules\sys_http.cpp" />
<ClCompile Include="Emu\SysCalls\Modules\sys_io.cpp" />
<ClCompile Include="Emu\SysCalls\Modules\sys_net.cpp" />
<ClCompile Include="Emu\SysCalls\Static.cpp" />
<ClCompile Include="Emu\SysCalls\SyncPrimitivesManager.cpp" />
<ClCompile Include="Emu\SysCalls\SysCalls.cpp" />
<ClCompile Include="Emu\System.cpp" />
@ -511,7 +510,6 @@
<ClInclude Include="Emu\SysCalls\Modules\sysPrxForUser.h" />
<ClInclude Include="Emu\SysCalls\Modules\sys_net.h" />
<ClInclude Include="Emu\SysCalls\SC_FUNC.h" />
<ClInclude Include="Emu\SysCalls\Static.h" />
<ClInclude Include="Emu\SysCalls\SyncPrimitivesManager.h" />
<ClInclude Include="Emu\SysCalls\SysCalls.h" />
<ClInclude Include="Emu\System.h" />

View file

@ -131,9 +131,6 @@
<ClCompile Include="Emu\SysCalls\Modules.cpp">
<Filter>Emu\SysCalls</Filter>
</ClCompile>
<ClCompile Include="Emu\SysCalls\Static.cpp">
<Filter>Emu\SysCalls</Filter>
</ClCompile>
<ClCompile Include="Emu\SysCalls\SysCalls.cpp">
<Filter>Emu\SysCalls</Filter>
</ClCompile>
@ -1228,9 +1225,6 @@
<ClInclude Include="Emu\SysCalls\ModuleManager.h">
<Filter>Emu\SysCalls</Filter>
</ClInclude>
<ClInclude Include="Emu\SysCalls\Static.h">
<Filter>Emu\SysCalls</Filter>
</ClInclude>
<ClInclude Include="..\Utilities\simpleini\ConvertUTF.h">
<Filter>Utilities\SimpleIni</Filter>
</ClInclude>