mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 06:09:50 -06:00
HLE: Differentiate Address hooks from Symbol hooks
GeckoCodes require address hooks which don't correspond to any symbol in the symbol table. The hooks get deleted when repatching the game because they did not persist across calls to HLE::PatchFunctions.
This commit is contained in:
@ -38,6 +38,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#include "Core/Boot/Boot.h"
|
#include "Core/Boot/Boot.h"
|
||||||
#include "Core/FifoPlayer/FifoPlayer.h"
|
#include "Core/FifoPlayer/FifoPlayer.h"
|
||||||
|
#include "Core/HLE/HLE.h"
|
||||||
#include "Core/HW/AudioInterface.h"
|
#include "Core/HW/AudioInterface.h"
|
||||||
#include "Core/HW/CPU.h"
|
#include "Core/HW/CPU.h"
|
||||||
#include "Core/HW/DSP.h"
|
#include "Core/HW/DSP.h"
|
||||||
@ -674,6 +675,7 @@ void EmuThread()
|
|||||||
INFO_LOG(CONSOLE, "Stop [Video Thread]\t\t---- Shutdown complete ----");
|
INFO_LOG(CONSOLE, "Stop [Video Thread]\t\t---- Shutdown complete ----");
|
||||||
Movie::Shutdown();
|
Movie::Shutdown();
|
||||||
PatchEngine::Shutdown();
|
PatchEngine::Shutdown();
|
||||||
|
HLE::Clear();
|
||||||
|
|
||||||
s_is_stopping = false;
|
s_is_stopping = false;
|
||||||
|
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
// Licensed under GPLv2+
|
// Licensed under GPLv2+
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
@ -33,11 +36,12 @@ struct SPatch
|
|||||||
{
|
{
|
||||||
char m_szPatchName[128];
|
char m_szPatchName[128];
|
||||||
TPatchFunction PatchFunction;
|
TPatchFunction PatchFunction;
|
||||||
int type;
|
HookType type;
|
||||||
int flags;
|
HookFlag flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const SPatch OSPatches[] = {
|
static const SPatch OSPatches[] = {
|
||||||
|
// Placeholder, OSPatches[0] is the "non-existent function" index
|
||||||
{"FAKE_TO_SKIP_0", HLE_Misc::UnimplementedFunction, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC},
|
{"FAKE_TO_SKIP_0", HLE_Misc::UnimplementedFunction, HLE_HOOK_REPLACE, HLE_TYPE_GENERIC},
|
||||||
|
|
||||||
{"PanicAlert", HLE_Misc::HLEPanicAlert, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG},
|
{"PanicAlert", HLE_Misc::HLEPanicAlert, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG},
|
||||||
@ -60,9 +64,10 @@ static const SPatch OSPatches[] = {
|
|||||||
{"___blank", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG},
|
{"___blank", HLE_OS::HLE_GeneralDebugPrint, HLE_HOOK_REPLACE, HLE_TYPE_DEBUG},
|
||||||
{"__write_console", HLE_OS::HLE_write_console, HLE_HOOK_REPLACE,
|
{"__write_console", HLE_OS::HLE_write_console, HLE_HOOK_REPLACE,
|
||||||
HLE_TYPE_DEBUG}, // used by sysmenu (+more?)
|
HLE_TYPE_DEBUG}, // used by sysmenu (+more?)
|
||||||
{"GeckoCodehandler", HLE_Misc::GeckoCodeHandlerICacheFlush, HLE_HOOK_START, HLE_TYPE_GENERIC},
|
|
||||||
|
{"GeckoCodehandler", HLE_Misc::GeckoCodeHandlerICacheFlush, HLE_HOOK_START, HLE_TYPE_FIXED},
|
||||||
{"GeckoHandlerReturnTrampoline", HLE_Misc::GeckoReturnTrampoline, HLE_HOOK_REPLACE,
|
{"GeckoHandlerReturnTrampoline", HLE_Misc::GeckoReturnTrampoline, HLE_HOOK_REPLACE,
|
||||||
HLE_TYPE_GENERIC},
|
HLE_TYPE_FIXED},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const SPatch OSBreakPoints[] = {
|
static const SPatch OSBreakPoints[] = {
|
||||||
@ -71,11 +76,12 @@ static const SPatch OSBreakPoints[] = {
|
|||||||
|
|
||||||
void Patch(u32 addr, const char* hle_func_name)
|
void Patch(u32 addr, const char* hle_func_name)
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < sizeof(OSPatches) / sizeof(SPatch); i++)
|
for (u32 i = 1; i < ArraySize(OSPatches); ++i)
|
||||||
{
|
{
|
||||||
if (!strcmp(OSPatches[i].m_szPatchName, hle_func_name))
|
if (!strcmp(OSPatches[i].m_szPatchName, hle_func_name))
|
||||||
{
|
{
|
||||||
s_original_instructions[addr] = i;
|
s_original_instructions[addr] = i;
|
||||||
|
PowerPC::ppcState.iCache.Invalidate(addr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,15 +89,33 @@ void Patch(u32 addr, const char* hle_func_name)
|
|||||||
|
|
||||||
void PatchFunctions()
|
void PatchFunctions()
|
||||||
{
|
{
|
||||||
s_original_instructions.clear();
|
// Remove all hooks that aren't fixed address hooks
|
||||||
for (u32 i = 0; i < sizeof(OSPatches) / sizeof(SPatch); i++)
|
for (auto i = s_original_instructions.begin(); i != s_original_instructions.end();)
|
||||||
{
|
{
|
||||||
|
if (OSPatches[i->second].flags != HLE_TYPE_FIXED)
|
||||||
|
{
|
||||||
|
PowerPC::ppcState.iCache.Invalidate(i->first);
|
||||||
|
i = s_original_instructions.erase(i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u32 i = 1; i < ArraySize(OSPatches); ++i)
|
||||||
|
{
|
||||||
|
// Fixed hooks don't map to symbols
|
||||||
|
if (OSPatches[i].flags == HLE_TYPE_FIXED)
|
||||||
|
continue;
|
||||||
|
|
||||||
Symbol* symbol = g_symbolDB.GetSymbolFromName(OSPatches[i].m_szPatchName);
|
Symbol* symbol = g_symbolDB.GetSymbolFromName(OSPatches[i].m_szPatchName);
|
||||||
if (symbol)
|
if (symbol)
|
||||||
{
|
{
|
||||||
for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4)
|
for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4)
|
||||||
{
|
{
|
||||||
s_original_instructions[addr] = i;
|
s_original_instructions[addr] = i;
|
||||||
|
PowerPC::ppcState.iCache.Invalidate(addr);
|
||||||
}
|
}
|
||||||
INFO_LOG(OSHLE, "Patching %s %08x", OSPatches[i].m_szPatchName, symbol->address);
|
INFO_LOG(OSHLE, "Patching %s %08x", OSPatches[i].m_szPatchName, symbol->address);
|
||||||
}
|
}
|
||||||
@ -99,7 +123,7 @@ void PatchFunctions()
|
|||||||
|
|
||||||
if (SConfig::GetInstance().bEnableDebugging)
|
if (SConfig::GetInstance().bEnableDebugging)
|
||||||
{
|
{
|
||||||
for (size_t i = 1; i < sizeof(OSBreakPoints) / sizeof(SPatch); i++)
|
for (size_t i = 1; i < ArraySize(OSBreakPoints); ++i)
|
||||||
{
|
{
|
||||||
Symbol* symbol = g_symbolDB.GetSymbolFromName(OSPatches[i].m_szPatchName);
|
Symbol* symbol = g_symbolDB.GetSymbolFromName(OSPatches[i].m_szPatchName);
|
||||||
if (symbol)
|
if (symbol)
|
||||||
@ -113,10 +137,15 @@ void PatchFunctions()
|
|||||||
// CBreakPoints::AddBreakPoint(0x8000D3D0, false);
|
// CBreakPoints::AddBreakPoint(0x8000D3D0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Clear()
|
||||||
|
{
|
||||||
|
s_original_instructions.clear();
|
||||||
|
}
|
||||||
|
|
||||||
void Execute(u32 _CurrentPC, u32 _Instruction)
|
void Execute(u32 _CurrentPC, u32 _Instruction)
|
||||||
{
|
{
|
||||||
unsigned int FunctionIndex = _Instruction & 0xFFFFF;
|
unsigned int FunctionIndex = _Instruction & 0xFFFFF;
|
||||||
if ((FunctionIndex > 0) && (FunctionIndex < (sizeof(OSPatches) / sizeof(SPatch))))
|
if (FunctionIndex > 0 && FunctionIndex < ArraySize(OSPatches))
|
||||||
{
|
{
|
||||||
OSPatches[FunctionIndex].PatchFunction();
|
OSPatches[FunctionIndex].PatchFunction();
|
||||||
}
|
}
|
||||||
@ -154,15 +183,40 @@ bool IsEnabled(int flags)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 UnPatch(const std::string& patchName)
|
u32 UnPatch(const std::string& patch_name)
|
||||||
{
|
{
|
||||||
Symbol* symbol = g_symbolDB.GetSymbolFromName(patchName);
|
auto* patch = std::find_if(std::begin(OSPatches), std::end(OSPatches), [&](const SPatch& patch) {
|
||||||
|
return patch_name == patch.m_szPatchName;
|
||||||
|
});
|
||||||
|
if (patch == std::end(OSPatches))
|
||||||
|
return 0;
|
||||||
|
|
||||||
if (symbol)
|
if (patch->type == HLE_TYPE_FIXED)
|
||||||
|
{
|
||||||
|
u32 patch_idx = static_cast<u32>(patch - OSPatches);
|
||||||
|
u32 addr = 0;
|
||||||
|
// Reverse search by OSPatch key instead of address
|
||||||
|
for (auto i = s_original_instructions.begin(); i != s_original_instructions.end();)
|
||||||
|
{
|
||||||
|
if (i->second == patch_idx)
|
||||||
|
{
|
||||||
|
addr = i->first;
|
||||||
|
PowerPC::ppcState.iCache.Invalidate(i->first);
|
||||||
|
i = s_original_instructions.erase(i);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Symbol* symbol = g_symbolDB.GetSymbolFromName(patch_name))
|
||||||
{
|
{
|
||||||
for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4)
|
for (u32 addr = symbol->address; addr < symbol->address + symbol->size; addr += 4)
|
||||||
{
|
{
|
||||||
s_original_instructions[addr] = 0;
|
s_original_instructions.erase(addr);
|
||||||
PowerPC::ppcState.iCache.Invalidate(addr);
|
PowerPC::ppcState.iCache.Invalidate(addr);
|
||||||
}
|
}
|
||||||
return symbol->address;
|
return symbol->address;
|
||||||
@ -171,4 +225,18 @@ u32 UnPatch(const std::string& patchName)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UnPatch(u32 addr, const std::string& name)
|
||||||
|
{
|
||||||
|
auto itr = s_original_instructions.find(addr);
|
||||||
|
if (itr == s_original_instructions.end())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!name.empty() && name != OSPatches[itr->second].m_szPatchName)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
s_original_instructions.erase(itr);
|
||||||
|
PowerPC::ppcState.iCache.Invalidate(addr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // end of namespace HLE
|
} // end of namespace HLE
|
||||||
|
@ -10,23 +10,26 @@
|
|||||||
|
|
||||||
namespace HLE
|
namespace HLE
|
||||||
{
|
{
|
||||||
enum
|
enum HookType
|
||||||
{
|
{
|
||||||
HLE_HOOK_START = 0, // Hook the beginning of the function and execute the function afterwards
|
HLE_HOOK_START = 0, // Hook the beginning of the function and execute the function afterwards
|
||||||
HLE_HOOK_REPLACE = 1, // Replace the function with the HLE version
|
HLE_HOOK_REPLACE = 1, // Replace the function with the HLE version
|
||||||
HLE_HOOK_NONE = 2, // Do not hook the function
|
HLE_HOOK_NONE = 2, // Do not hook the function
|
||||||
};
|
};
|
||||||
|
|
||||||
enum
|
enum HookFlag
|
||||||
{
|
{
|
||||||
HLE_TYPE_GENERIC = 0, // Miscellaneous function
|
HLE_TYPE_GENERIC = 0, // Miscellaneous function
|
||||||
HLE_TYPE_DEBUG = 1, // Debug output function
|
HLE_TYPE_DEBUG = 1, // Debug output function
|
||||||
|
HLE_TYPE_FIXED = 2, // An arbitrary hook mapped to a fixed address instead of a symbol
|
||||||
};
|
};
|
||||||
|
|
||||||
void PatchFunctions();
|
void PatchFunctions();
|
||||||
|
void Clear();
|
||||||
|
|
||||||
void Patch(u32 pc, const char* func_name);
|
void Patch(u32 pc, const char* func_name);
|
||||||
u32 UnPatch(const std::string& patchName);
|
u32 UnPatch(const std::string& patchName);
|
||||||
|
bool UnPatch(u32 addr, const std::string& name = {});
|
||||||
void Execute(u32 _CurrentPC, u32 _Instruction);
|
void Execute(u32 _CurrentPC, u32 _Instruction);
|
||||||
|
|
||||||
u32 GetFunctionIndex(u32 em_address);
|
u32 GetFunctionIndex(u32 em_address);
|
||||||
|
Reference in New Issue
Block a user