Light refactor of the IDetour interface

- Use std::map for mapping vtables to interface objects, previously done with a set and a vector.
- Objects are no longer inline, which significantly reduced output code size as all redundant dynamic initializers (created for each translation unit) have been pruned.
This commit is contained in:
Kawe Mazidjatari 2023-07-03 13:37:41 +02:00
parent ed1b365c12
commit 7762c4b2ce
4 changed files with 56 additions and 37 deletions

View File

@ -170,9 +170,10 @@ void Systems_Init()
DetourUpdateThread(GetCurrentThread());
// Hook functions
for (const IDetour* pDetour : g_DetourVector)
for (const auto& elem : g_DetourMap)
{
pDetour->Attach();
const IDetour* detour = elem.second;
detour->Attach();
}
// Patch instructions
@ -215,9 +216,10 @@ void Systems_Shutdown()
DetourUpdateThread(GetCurrentThread());
// Unhook functions
for (const IDetour* pDetour : g_DetourVector)
for (const auto& elem : g_DetourMap)
{
pDetour->Detach();
const IDetour* detour = elem.second;
detour->Detach();
}
// Commit the transaction
@ -342,11 +344,13 @@ void DetourInit() // Run the sigscan
g_SigCache.SetDisabled(bNoSmap);
g_SigCache.LoadCache(SIGDB_FILE);
for (const IDetour* pDetour : g_DetourVector)
for (const auto& elem : g_DetourMap)
{
pDetour->GetCon(); // Constants.
pDetour->GetFun(); // Functions.
pDetour->GetVar(); // Variables.
const IDetour* detour = elem.second;
detour->GetCon(); // Constants.
detour->GetFun(); // Functions.
detour->GetVar(); // Variables.
if (bLogAdr)
{
@ -355,7 +359,7 @@ void DetourInit() // Run the sigscan
bInitDivider = true;
spdlog::debug("+---------------------------------------------------------------------+\n");
}
pDetour->GetAdr();
detour->GetAdr();
spdlog::debug("+---------------------------------------------------------------------+\n");
}
}
@ -372,9 +376,11 @@ void DetourInit() // Run the sigscan
void DetourAddress() // Test the sigscan results
{
spdlog::debug("+---------------------------------------------------------------------+\n");
for (const IDetour* pDetour : g_DetourVector)
for (const auto& elem : g_DetourMap)
{
pDetour->GetAdr();
const IDetour* detour = elem.second;
detour->GetAdr();
spdlog::debug("+---------------------------------------------------------------------+\n");
}
}

View File

@ -7,6 +7,7 @@ add_sources( SOURCE_GROUP "Source"
"src/creatwth.cpp"
"src/detours.cpp"
"src/disasm.cpp"
"src/idetour.cpp"
"src/modules.cpp"
)

View File

@ -1,10 +1,9 @@
#ifndef IDETOUR_H
#define IDETOUR_H
#define ADDDETOUR(x,y) static std::size_t dummy_reg_##y = AddDetour( new x() );
#define XREGISTER(x,y) ADDDETOUR(x, y)
#define REGISTER(x) XREGISTER(x, __COUNTER__)
//-----------------------------------------------------------------------------
// Interface class for context hooks
//-----------------------------------------------------------------------------
class IDetour
{
public:
@ -18,28 +17,11 @@ public:
virtual void Detach(void) const = 0;
};
class VDetour : public IDetour
{
virtual void GetAdr(void) const { }
virtual void GetFun(void) const { }
virtual void GetVar(void) const { }
virtual void GetCon(void) const { }
extern std::map<const void*, const IDetour*> g_DetourMap;
std::size_t AddDetour(IDetour* pDetour);
virtual void Attach(void) const { }
virtual void Detach(void) const { }
};
inline static std::vector<IDetour*> g_DetourVector;
inline static std::unordered_set<IDetour*> g_DetourSet;
inline std::size_t AddDetour(IDetour* pDetour)
{
IDetour* pVFTable = reinterpret_cast<IDetour**>(pDetour)[0];
auto p = g_DetourSet.insert(pVFTable); // Only register if VFTable isn't already registered.
assert(p.second); // Code bug: duplicate registration!!! (called 'REGISTER(...)' from a header file?).
p.second ? g_DetourVector.push_back(pDetour) : delete pDetour;
return g_DetourVector.size();
}
#define ADDDETOUR(x,y) static std::size_t dummy_reg_##y = AddDetour( new x() );
#define XREGISTER(x,y) ADDDETOUR(x, y)
#define REGISTER(x) XREGISTER(x, __COUNTER__)
#endif // IDETOUR_H

View File

@ -0,0 +1,30 @@
//===========================================================================//
//
// Purpose: Hook interface
//
//===========================================================================//
#include <cassert>
#include <map>
#include "../include/idetour.h"
//-----------------------------------------------------------------------------
// Contains a VFTable pointer, and the class instance. A VFTable can only be
// used by one class instance. This is to avoid duplicate registrations.
//-----------------------------------------------------------------------------
std::map<const void*, const IDetour*> g_DetourMap;
//-----------------------------------------------------------------------------
// Purpose: adds a detour context to the list
//-----------------------------------------------------------------------------
std::size_t AddDetour(IDetour* pDetour)
{
const void* pVFTable = reinterpret_cast<const void**>(pDetour)[0];
auto p = g_DetourMap.emplace(pVFTable, pDetour); // Only register if VFTable isn't already registered.
assert(p.second); // Code bug: duplicate registration!!! (called 'REGISTER(...)' from a header file?).
if (!p.second)
delete pDetour;
return g_DetourMap.size();
}