From c70c116bd7c47eb0bc2d713fd49fc5bd13eb5b19 Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 26 Jun 2018 13:54:02 +0100 Subject: [PATCH] Refactor hooks towards more unified/clean approach * Hooking is now done the same way across platform, with different OS implementations. * Regardless of how exactly hooks are implemented, we register libraries to hook and functions to hook within those libraries, and provide a location to store the original/onwards function pointer. This allows hooking to work whether it's done using import hooking that doesn't modify target libraries (so using dlsym or GetProcAddress will return the same value for the onwards function pointer) or whether it's implemented with prologue patching and trampolines, where we'd create an infinite loop if we did that. * We also provide stronger guarantees - the original function pointers will _always_ be made available as soon as the library is loaded, whether hooked or not, no exceptions. This means less uncertainty in hooking code about when or how onward functions will be available. * OS-specific hook functions are changed to just be implementations of LibraryHooks functions rather than indirected through macros and pre-processor definitions. * In this commit we provide some temporary functions providing the old interface to reduce churn - the library-specific hook code will be updated shortly after --- renderdoc/CMakeLists.txt | 3 - renderdoc/core/core.cpp | 2 +- renderdoc/driver/d3d11/d3d11_hooks.cpp | 70 +-- renderdoc/driver/d3d12/d3d12_hooks.cpp | 20 +- renderdoc/driver/d3d8/d3d8_hooks.cpp | 9 +- renderdoc/driver/d3d9/d3d9_hooks.cpp | 28 +- renderdoc/driver/dxgi/dxgi_hooks.cpp | 24 +- renderdoc/driver/gl/gl_hooks_apple.cpp | 2 +- renderdoc/driver/gl/gl_hooks_egl.cpp | 21 +- renderdoc/driver/gl/gl_hooks_linux.cpp | 6 +- renderdoc/driver/gl/gl_hooks_linux_shared.cpp | 6 +- renderdoc/driver/gl/gl_hooks_win32.cpp | 550 +++++++++--------- renderdoc/driver/gl/gl_library_egl.cpp | 2 +- renderdoc/driver/vulkan/vk_layer.cpp | 6 +- renderdoc/hooks/hooks.cpp | 62 +- renderdoc/hooks/hooks.h | 237 ++++++-- renderdoc/os/posix/android/android_hook.cpp | 348 ++++++----- renderdoc/os/posix/apple/apple_hook.cpp | 43 +- renderdoc/os/posix/linux/linux_hook.cpp | 182 +++--- renderdoc/os/posix/posix_hook.h | 51 -- renderdoc/os/posix/posix_libentry.cpp | 4 +- renderdoc/os/win32/sys_win32_hooks.cpp | 103 ++-- renderdoc/os/win32/win32_hook.cpp | 239 +++++--- renderdoc/os/win32/win32_hook.h | 34 -- renderdoc/os/win32/win32_libentry.cpp | 4 +- renderdoc/renderdoc.vcxproj | 4 - renderdoc/renderdoc.vcxproj.filters | 6 - renderdoc/replay/app_api.cpp | 2 +- 28 files changed, 1146 insertions(+), 922 deletions(-) delete mode 100644 renderdoc/os/posix/posix_hook.h delete mode 100644 renderdoc/os/win32/win32_hook.h diff --git a/renderdoc/CMakeLists.txt b/renderdoc/CMakeLists.txt index 1c4906ce8..6b9c6bf91 100644 --- a/renderdoc/CMakeLists.txt +++ b/renderdoc/CMakeLists.txt @@ -214,7 +214,6 @@ if(ANDROID) os/posix/android/android_threading.cpp os/posix/android/android_hook.cpp os/posix/android/android_network.cpp - os/posix/posix_hook.h os/posix/posix_network.h os/posix/posix_network.cpp os/posix/posix_process.cpp @@ -230,7 +229,6 @@ elseif(APPLE) os/posix/apple/apple_threading.cpp os/posix/apple/apple_hook.cpp os/posix/apple/apple_network.cpp - os/posix/posix_hook.h os/posix/posix_network.h os/posix/posix_network.cpp os/posix/posix_process.cpp @@ -248,7 +246,6 @@ elseif(UNIX) os/posix/linux/linux_network.cpp 3rdparty/plthook/plthook.h 3rdparty/plthook/plthook_elf.c - os/posix/posix_hook.h os/posix/posix_network.h os/posix/posix_network.cpp os/posix/posix_process.cpp diff --git a/renderdoc/core/core.cpp b/renderdoc/core/core.cpp index f8f029f15..a0c9d4096 100644 --- a/renderdoc/core/core.cpp +++ b/renderdoc/core/core.cpp @@ -1043,7 +1043,7 @@ void RenderDoc::SetCaptureOptions(const CaptureOptions &opts) { m_Options = opts; - LibraryHooks::GetInstance().OptionsUpdated(); + LibraryHooks::OptionsUpdated(); } void RenderDoc::SetCaptureFileTemplate(const char *pathtemplate) diff --git a/renderdoc/driver/d3d11/d3d11_hooks.cpp b/renderdoc/driver/d3d11/d3d11_hooks.cpp index 8c426ced4..dbfcd7315 100644 --- a/renderdoc/driver/d3d11/d3d11_hooks.cpp +++ b/renderdoc/driver/d3d11/d3d11_hooks.cpp @@ -28,6 +28,16 @@ #include "driver/ihv/amd/official/DXExt/AmdDxExtApi.h" #include "hooks/hooks.h" +#if ENABLED(RDOC_X64) + +#define BIT_SPECIFIC_DLL(dll32, dll64) dll64 + +#else + +#define BIT_SPECIFIC_DLL(dll32, dll64) dll32 + +#endif + ID3D11Resource *UnwrapDXResource(void *dxObject); ID3DDevice *GetD3D11DeviceIfAlloc(IUnknown *dev) @@ -110,7 +120,7 @@ class D3D11Hook : LibraryHook { public: D3D11Hook() { m_InsideCreate = false; } - bool CreateHooks(const char *libName) + void RegisterHooks() { WrappedIDXGISwapChain4::RegisterD3DDeviceCallback(GetD3D11DeviceIfAlloc); @@ -118,52 +128,44 @@ public: if(GetD3DCompiler() == NULL) { RDCERR("Failed to load d3dcompiler_??.dll - not inserting D3D11 hooks."); - return false; + return; } - CreateDevice.Initialize("D3D11CreateDevice", "d3d11.dll", D3D11CreateDevice_hook); - CreateDeviceAndSwapChain.Initialize("D3D11CreateDeviceAndSwapChain", "d3d11.dll", - D3D11CreateDeviceAndSwapChain_hook); + LibraryHooks::RegisterLibraryHook("d3d11.dll", NULL); -// these are hooked to prevent AMD extensions from activating and causing later crashes when not -// replayed correctly -#if ENABLED(RDOC_X64) - AmdCreate11.Initialize("AmdDxExtCreate11", "atidxx64.dll", AmdCreate11_hook); -#else - AmdCreate11.Initialize("AmdDxExtCreate11", "atidxx32.dll", AmdCreate11_hook); -#endif + CreateDevice.Register("d3d11.dll", "D3D11CreateDevice", D3D11CreateDevice_hook); + CreateDeviceAndSwapChain.Register("d3d11.dll", "D3D11CreateDeviceAndSwapChain", + D3D11CreateDeviceAndSwapChain_hook); -// nvapi has some seriously awful ""feature"" where it can wrap CreateDevice with some other -// extra parameter. Since we don't want to hook nvapi when it calls out to d3d11.dll, we have to -// intercept it here. -#if ENABLED(RDOC_X64) - nvapi_QueryInterface.Initialize("nvapi_QueryInterface", "nvapi64.dll", nvapi_QueryInterface_hook); -#else - nvapi_QueryInterface.Initialize("nvapi_QueryInterface", "nvapi.dll", nvapi_QueryInterface_hook); -#endif + // these are hooked to prevent AMD extensions from activating and causing later crashes when not + // replayed correctly + LibraryHooks::RegisterLibraryHook(BIT_SPECIFIC_DLL("atidxx32.dll", "atidxx64.dll"), NULL); + AmdCreate11.Register(BIT_SPECIFIC_DLL("atidxx32.dll", "atidxx64.dll"), "AmdDxExtCreate11", + AmdCreate11_hook); -// we need to wrap nvcodec to handle unwrapping D3D11 pointers passed to it -#if ENABLED(RDOC_X64) - NvEncodeCreate.Initialize("NvEncodeAPICreateInstance", "nvEncodeAPI64.dll", - NvEncodeAPICreateInstance_hook); -#else - NvEncodeCreate.Initialize("NvEncodeAPICreateInstance", "nvEncodeAPI.dll", - NvEncodeAPICreateInstance_hook); -#endif + // nvapi has some seriously awful ""feature"" where it can wrap CreateDevice with some other + // extra parameter. Since we don't want to hook nvapi when it calls out to d3d11.dll, we have to + // intercept it here. + LibraryHooks::RegisterLibraryHook(BIT_SPECIFIC_DLL("nvapi.dll", "nvapi64.dll"), NULL); + nvapi_QueryInterface.Register(BIT_SPECIFIC_DLL("nvapi.dll", "nvapi64.dll"), + "nvapi_QueryInterface", nvapi_QueryInterface_hook); - return true; + // we need to wrap nvcodec to handle unwrapping D3D11 pointers passed to it + LibraryHooks::RegisterLibraryHook(BIT_SPECIFIC_DLL("nvEncodeAPI.dll", "nvEncodeAPI64.dll"), NULL); + NvEncodeCreate.Register(BIT_SPECIFIC_DLL("nvEncodeAPI.dll", "nvEncodeAPI64.dll"), + "NvEncodeAPICreateInstance", NvEncodeAPICreateInstance_hook); } private: static D3D11Hook d3d11hooks; - Hook CreateDeviceAndSwapChain; - Hook CreateDevice; + HookedFunction CreateDeviceAndSwapChain; + HookedFunction CreateDevice; // optional extension hooks - Hook AmdCreate11; - Hook nvapi_QueryInterface; - Hook NvEncodeCreate; + HookedFunction AmdCreate11; + HookedFunction nvapi_QueryInterface; + HookedFunction NvEncodeCreate; // re-entrancy detection (can happen in rare cases with e.g. fraps) bool m_InsideCreate; diff --git a/renderdoc/driver/d3d12/d3d12_hooks.cpp b/renderdoc/driver/d3d12/d3d12_hooks.cpp index 457a1fd3b..61c110536 100644 --- a/renderdoc/driver/d3d12/d3d12_hooks.cpp +++ b/renderdoc/driver/d3d12/d3d12_hooks.cpp @@ -86,7 +86,7 @@ public: class D3D12Hook : LibraryHook { public: - bool CreateHooks(const char *libName) + void RegisterHooks() { WrappedIDXGISwapChain4::RegisterD3DDeviceCallback(GetD3D12DeviceIfAlloc); @@ -94,23 +94,23 @@ public: if(GetD3DCompiler() == NULL) { RDCERR("Failed to load d3dcompiler_??.dll - not inserting D3D12 hooks."); - return false; + return; } - CreateDevice.Initialize("D3D12CreateDevice", "d3d12.dll", D3D12CreateDevice_hook); - GetDebugInterface.Initialize("D3D12GetDebugInterface", "d3d12.dll", D3D12GetDebugInterface_hook); - EnableExperimentalFeatures.Initialize("D3D12EnableExperimentalFeatures", "d3d12.dll", - D3D12EnableExperimentalFeatures_hook); + LibraryHooks::RegisterLibraryHook("d3d12.dll", NULL); - return true; + CreateDevice.Register("d3d12.dll", "D3D12CreateDevice", D3D12CreateDevice_hook); + GetDebugInterface.Register("d3d12.dll", "D3D12GetDebugInterface", D3D12GetDebugInterface_hook); + EnableExperimentalFeatures.Register("d3d12.dll", "D3D12EnableExperimentalFeatures", + D3D12EnableExperimentalFeatures_hook); } private: static D3D12Hook d3d12hooks; - Hook GetDebugInterface; - Hook CreateDevice; - Hook EnableExperimentalFeatures; + HookedFunction GetDebugInterface; + HookedFunction CreateDevice; + HookedFunction EnableExperimentalFeatures; // re-entrancy detection (can happen in rare cases with e.g. fraps) bool m_InsideCreate = false; diff --git a/renderdoc/driver/d3d8/d3d8_hooks.cpp b/renderdoc/driver/d3d8/d3d8_hooks.cpp index 704d9877a..734cb4119 100644 --- a/renderdoc/driver/d3d8/d3d8_hooks.cpp +++ b/renderdoc/driver/d3d8/d3d8_hooks.cpp @@ -31,17 +31,16 @@ typedef IDirect3D8 *(WINAPI *PFN_D3D8_CREATE)(UINT); class D3D8Hook : LibraryHook { public: - bool CreateHooks(const char *libName) + void RegisterHooks() { - Create8.Initialize("Direct3DCreate8", "d3d8.dll", Create8_hook); - - return true; + LibraryHooks::RegisterLibraryHook("d3d8.dll", NULL); + Create8.Register("d3d8.dll", "Direct3DCreate8", Create8_hook); } private: static D3D8Hook d3d8hooks; - Hook Create8; + HookedFunction Create8; static IDirect3D8 *WINAPI Create8_hook(UINT SDKVersion) { diff --git a/renderdoc/driver/d3d9/d3d9_hooks.cpp b/renderdoc/driver/d3d9/d3d9_hooks.cpp index 253c834df..f5a9eb791 100644 --- a/renderdoc/driver/d3d9/d3d9_hooks.cpp +++ b/renderdoc/driver/d3d9/d3d9_hooks.cpp @@ -40,29 +40,29 @@ typedef IDirect3D9 *(WINAPI *PFN_D3D9_CREATE)(UINT); class D3D9Hook : LibraryHook { public: - bool CreateHooks(const char *libName) + void RegisterHooks() { - PERF_BeginEvent.Initialize("D3DPERF_BeginEvent", "d3d9.dll", PERF_BeginEvent_hook); - PERF_EndEvent.Initialize("D3DPERF_EndEvent", "d3d9.dll", PERF_EndEvent_hook); - PERF_SetMarker.Initialize("D3DPERF_SetMarker", "d3d9.dll", PERF_SetMarker_hook); - PERF_SetOptions.Initialize("D3DPERF_SetOptions", "d3d9.dll", PERF_SetOptions_hook); - PERF_GetStatus.Initialize("D3DPERF_GetStatus", "d3d9.dll", PERF_GetStatus_hook); + LibraryHooks::RegisterLibraryHook("d3d9.dll", NULL); - Create9.Initialize("Direct3DCreate9", "d3d9.dll", Create9_hook); + PERF_BeginEvent.Register("d3d9.dll", "D3DPERF_BeginEvent", PERF_BeginEvent_hook); + PERF_EndEvent.Register("d3d9.dll", "D3DPERF_EndEvent", PERF_EndEvent_hook); + PERF_SetMarker.Register("d3d9.dll", "D3DPERF_SetMarker", PERF_SetMarker_hook); + PERF_SetOptions.Register("d3d9.dll", "D3DPERF_SetOptions", PERF_SetOptions_hook); + PERF_GetStatus.Register("d3d9.dll", "D3DPERF_GetStatus", PERF_GetStatus_hook); - return true; + Create9.Register("d3d9.dll", "Direct3DCreate9", Create9_hook); } private: static D3D9Hook d3d9hooks; // D3DPERF api - Hook PERF_BeginEvent; - Hook PERF_EndEvent; - Hook PERF_SetMarker; - Hook PERF_SetOptions; - Hook PERF_GetStatus; - Hook Create9; + HookedFunction PERF_BeginEvent; + HookedFunction PERF_EndEvent; + HookedFunction PERF_SetMarker; + HookedFunction PERF_SetOptions; + HookedFunction PERF_GetStatus; + HookedFunction Create9; static int WINAPI PERF_BeginEvent_hook(DWORD col, WCHAR *wszName) { diff --git a/renderdoc/driver/dxgi/dxgi_hooks.cpp b/renderdoc/driver/dxgi/dxgi_hooks.cpp index d43a524c7..609923ddd 100644 --- a/renderdoc/driver/dxgi/dxgi_hooks.cpp +++ b/renderdoc/driver/dxgi/dxgi_hooks.cpp @@ -72,15 +72,15 @@ struct RenderDocAnalysis : IDXGraphicsAnalysis class DXGIHook : LibraryHook { public: - bool CreateHooks(const char *libName) + void RegisterHooks() { - CreateDXGIFactory.Initialize("CreateDXGIFactory", "dxgi.dll", CreateDXGIFactory_hook); - CreateDXGIFactory1.Initialize("CreateDXGIFactory1", "dxgi.dll", CreateDXGIFactory1_hook); - CreateDXGIFactory2.Initialize("CreateDXGIFactory2", "dxgi.dll", CreateDXGIFactory2_hook); - GetDebugInterface.Initialize("DXGIGetDebugInterface", "dxgi.dll", DXGIGetDebugInterface_hook); - GetDebugInterface1.Initialize("DXGIGetDebugInterface1", "dxgi.dll", DXGIGetDebugInterface1_hook); + LibraryHooks::RegisterLibraryHook("dxgi.dll", NULL); - return true; + CreateDXGIFactory.Register("dxgi.dll", "CreateDXGIFactory", CreateDXGIFactory_hook); + CreateDXGIFactory1.Register("dxgi.dll", "CreateDXGIFactory1", CreateDXGIFactory1_hook); + CreateDXGIFactory2.Register("dxgi.dll", "CreateDXGIFactory2", CreateDXGIFactory2_hook); + GetDebugInterface.Register("dxgi.dll", "DXGIGetDebugInterface", DXGIGetDebugInterface_hook); + GetDebugInterface1.Register("dxgi.dll", "DXGIGetDebugInterface1", DXGIGetDebugInterface1_hook); } private: @@ -88,11 +88,11 @@ private: RenderDocAnalysis m_RenderDocAnalysis; - Hook CreateDXGIFactory; - Hook CreateDXGIFactory1; - Hook CreateDXGIFactory2; - Hook GetDebugInterface; - Hook GetDebugInterface1; + HookedFunction CreateDXGIFactory; + HookedFunction CreateDXGIFactory1; + HookedFunction CreateDXGIFactory2; + HookedFunction GetDebugInterface; + HookedFunction GetDebugInterface1; static HRESULT WINAPI CreateDXGIFactory_hook(__in REFIID riid, __out void **ppFactory) { diff --git a/renderdoc/driver/gl/gl_hooks_apple.cpp b/renderdoc/driver/gl/gl_hooks_apple.cpp index fd4d32705..2185036b8 100644 --- a/renderdoc/driver/gl/gl_hooks_apple.cpp +++ b/renderdoc/driver/gl/gl_hooks_apple.cpp @@ -38,7 +38,7 @@ class OpenGLHook : LibraryHook public: OpenGLHook() {} ~OpenGLHook() {} - bool CreateHooks(const char *libName) { return false; } + bool RegisterHooks() { return false; } virtual GLWindowingData MakeContext(GLWindowingData share) { RDCUNIMPLEMENTED("MakeContext"); diff --git a/renderdoc/driver/gl/gl_hooks_egl.cpp b/renderdoc/driver/gl/gl_hooks_egl.cpp index 1ccd9c2d1..b4f08a631 100644 --- a/renderdoc/driver/gl/gl_hooks_egl.cpp +++ b/renderdoc/driver/gl/gl_hooks_egl.cpp @@ -52,6 +52,7 @@ public: bool CreateHooks(const char *libName); + void RegisterHooks() { CreateHooks("dummy"); } void PopulateEGLFunctions() { if(!m_PopulatedHooks) @@ -214,7 +215,7 @@ __attribute__((visibility("default"))) EGLContext eglCreateContext(EGLDisplay di EGLContext shareContext, EGLint const *attribList) { - PosixHookReapply(); + LibraryHooks::Refresh(); vector attribs; @@ -374,7 +375,7 @@ __attribute__((visibility("default"))) __eglMustCastToProperFunctionPointerType __eglMustCastToProperFunctionPointerType realFunc = NULL; { - PosixScopedSuppressHooking suppress; + ScopedSuppressHooking suppress; realFunc = eglhooks.real.GetProcAddress(func); } @@ -422,13 +423,13 @@ bool EGLHook::CreateHooks(const char *libName) PosixHookFunction("eglGetProcAddress", (void *)&eglGetProcAddress); // load the libEGL.so library and when loaded call libHooked which initialises GLES capture - PosixHookLibrary("libEGL.so", &libHooked); - PosixHookLibrary("libEGL.so.1", NULL); - PosixHookLibrary("libGL.so.1", NULL); - PosixHookLibrary("libGLESv1_CM.so", NULL); - PosixHookLibrary("libGLESv2.so", NULL); - PosixHookLibrary("libGLESv2.so.2", NULL); - PosixHookLibrary("libGLESv3.so", NULL); + LibraryHooks::RegisterLibraryHook("libEGL.so", &libHooked); + LibraryHooks::RegisterLibraryHook("libEGL.so.1", NULL); + LibraryHooks::RegisterLibraryHook("libGL.so.1", NULL); + LibraryHooks::RegisterLibraryHook("libGLESv1_CM.so", NULL); + LibraryHooks::RegisterLibraryHook("libGLESv2.so", NULL); + LibraryHooks::RegisterLibraryHook("libGLESv2.so.2", NULL); + LibraryHooks::RegisterLibraryHook("libGLESv3.so", NULL); #if ENABLED(RDOC_ANDROID) return true; @@ -463,7 +464,7 @@ bool EGLHook::PopulateHooks() m_PopulatedHooks = SharedPopulateHooks(dlsymFirst, [](const char *funcName) { // on some android devices we need to hook dlsym, but eglGetProcAddress might call dlsym so we // need to ensure we return the 'real' pointers - PosixScopedSuppressHooking suppress; + ScopedSuppressHooking suppress; return (void *)eglGetProcAddress(funcName); }); diff --git a/renderdoc/driver/gl/gl_hooks_linux.cpp b/renderdoc/driver/gl/gl_hooks_linux.cpp index 33039f03f..ff58c5dff 100644 --- a/renderdoc/driver/gl/gl_hooks_linux.cpp +++ b/renderdoc/driver/gl/gl_hooks_linux.cpp @@ -63,13 +63,17 @@ public: bool CreateHooks(const char *libName) { if(libName) - PosixHookLibrary("libGL.so", &libHooked); + { + LibraryHooks::RegisterLibraryHook("libGL.so", &libHooked); + LibraryHooks::RegisterLibraryHook("libGL.so.1", &libHooked); + } SetupHooks(); return true; } + void RegisterHooks() { CreateHooks("dummy"); } // see callsite in glXSwapBuffers for explanation of why this is necessary XID UnwrapGLXWindow(XID id) { diff --git a/renderdoc/driver/gl/gl_hooks_linux_shared.cpp b/renderdoc/driver/gl/gl_hooks_linux_shared.cpp index e8e5fa9ad..4e3725c10 100644 --- a/renderdoc/driver/gl/gl_hooks_linux_shared.cpp +++ b/renderdoc/driver/gl/gl_hooks_linux_shared.cpp @@ -1422,7 +1422,7 @@ bool SharedPopulateHooks(bool dlsymFirst, void *(*lookupFunc)(const char *)) #define HookInit(function) \ if(GL.function == NULL) \ { \ - PosixScopedSuppressHooking suppress; \ + ScopedSuppressHooking suppress; \ if(dlsymFirst && GL.function == NULL) \ { \ GL.function = \ @@ -1436,7 +1436,7 @@ bool SharedPopulateHooks(bool dlsymFirst, void *(*lookupFunc)(const char *)) #define HookExtension(funcPtrType, function) \ if(GL.function == NULL) \ { \ - PosixScopedSuppressHooking suppress; \ + ScopedSuppressHooking suppress; \ if(dlsymFirst && GL.function == NULL) \ { \ GL.function = (funcPtrType)PosixGetFunction(libGLdlsymHandle, STRINGIZE(function)); \ @@ -1447,7 +1447,7 @@ bool SharedPopulateHooks(bool dlsymFirst, void *(*lookupFunc)(const char *)) #define HookExtensionAlias(funcPtrType, function, alias) \ if(GL.function == NULL) \ { \ - PosixScopedSuppressHooking suppress; \ + ScopedSuppressHooking suppress; \ if(dlsymFirst && GL.function == NULL) \ { \ GL.function = (funcPtrType)PosixGetFunction(libGLdlsymHandle, STRINGIZE(alias)); \ diff --git a/renderdoc/driver/gl/gl_hooks_win32.cpp b/renderdoc/driver/gl/gl_hooks_win32.cpp index 8498258c9..aa7514c9c 100644 --- a/renderdoc/driver/gl/gl_hooks_win32.cpp +++ b/renderdoc/driver/gl/gl_hooks_win32.cpp @@ -31,9 +31,9 @@ #include "hooks/hooks.h" #include "strings/string_utils.h" -#define HookInit(function) \ - CONCAT(function, _hook) \ - .Initialize(STRINGIZE(function), "opengl32.dll", CONCAT(function, _hooked)); \ +#define HookInit(function) \ + CONCAT(function, _hook) \ + .Register("opengl32.dll", STRINGIZE(function), CONCAT(function, _hooked)); \ GL.function = CONCAT(function, _hook)(); #define HookExtension(funcPtrType, function) \ @@ -85,7 +85,7 @@ for I in `seq 1 $N`; do echo -n ", t$I, p$I"; done; echo ") \\"; - echo -en " Hook CONCAT(function, _hook); \\"; @@ -133,56 +133,56 @@ #undef far #endif -#define HookWrapper0(ret, function) \ - Hook CONCAT(function, _hook); \ - typedef ret(WINAPI *CONCAT(function, _hooktype))(); \ - static ret WINAPI CONCAT(function, _hooked)() \ - { \ - SCOPED_LOCK(glLock); \ - if(!glhooks.m_HaveContextCreation) \ - return GL.function(); \ - gl_CurChunk = GLChunk::function; \ - return glhooks.GetDriver()->function(); \ +#define HookWrapper0(ret, function) \ + HookedFunction CONCAT(function, _hook); \ + typedef ret(WINAPI *CONCAT(function, _hooktype))(); \ + static ret WINAPI CONCAT(function, _hooked)() \ + { \ + SCOPED_LOCK(glLock); \ + if(!glhooks.m_HaveContextCreation) \ + return GL.function(); \ + gl_CurChunk = GLChunk::function; \ + return glhooks.GetDriver()->function(); \ } -#define HookWrapper1(ret, function, t1, p1) \ - Hook CONCAT(function, _hook); \ - typedef ret(WINAPI *CONCAT(function, _hooktype))(t1); \ - static ret WINAPI CONCAT(function, _hooked)(t1 p1) \ - { \ - SCOPED_LOCK(glLock); \ - if(!glhooks.m_HaveContextCreation) \ - return GL.function(p1); \ - gl_CurChunk = GLChunk::function; \ - return glhooks.GetDriver()->function(p1); \ +#define HookWrapper1(ret, function, t1, p1) \ + HookedFunction CONCAT(function, _hook); \ + typedef ret(WINAPI *CONCAT(function, _hooktype))(t1); \ + static ret WINAPI CONCAT(function, _hooked)(t1 p1) \ + { \ + SCOPED_LOCK(glLock); \ + if(!glhooks.m_HaveContextCreation) \ + return GL.function(p1); \ + gl_CurChunk = GLChunk::function; \ + return glhooks.GetDriver()->function(p1); \ } -#define HookWrapper2(ret, function, t1, p1, t2, p2) \ - Hook CONCAT(function, _hook); \ - typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2); \ - static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2) \ - { \ - SCOPED_LOCK(glLock); \ - if(!glhooks.m_HaveContextCreation) \ - return GL.function(p1, p2); \ - gl_CurChunk = GLChunk::function; \ - return glhooks.GetDriver()->function(p1, p2); \ +#define HookWrapper2(ret, function, t1, p1, t2, p2) \ + HookedFunction CONCAT(function, _hook); \ + typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2); \ + static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2) \ + { \ + SCOPED_LOCK(glLock); \ + if(!glhooks.m_HaveContextCreation) \ + return GL.function(p1, p2); \ + gl_CurChunk = GLChunk::function; \ + return glhooks.GetDriver()->function(p1, p2); \ } -#define HookWrapper3(ret, function, t1, p1, t2, p2, t3, p3) \ - Hook CONCAT(function, _hook); \ - typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3); \ - static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3) \ - { \ - SCOPED_LOCK(glLock); \ - if(!glhooks.m_HaveContextCreation) \ - return GL.function(p1, p2, p3); \ - gl_CurChunk = GLChunk::function; \ - return glhooks.GetDriver()->function(p1, p2, p3); \ +#define HookWrapper3(ret, function, t1, p1, t2, p2, t3, p3) \ + HookedFunction CONCAT(function, _hook); \ + typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3); \ + static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3) \ + { \ + SCOPED_LOCK(glLock); \ + if(!glhooks.m_HaveContextCreation) \ + return GL.function(p1, p2, p3); \ + gl_CurChunk = GLChunk::function; \ + return glhooks.GetDriver()->function(p1, p2, p3); \ } #define HookWrapper4(ret, function, t1, p1, t2, p2, t3, p3, t4, p4) \ - Hook CONCAT(function, _hook); \ + HookedFunction CONCAT(function, _hook); \ typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4); \ static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4) \ { \ @@ -194,7 +194,7 @@ } #define HookWrapper5(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5) \ - Hook CONCAT(function, _hook); \ + HookedFunction CONCAT(function, _hook); \ typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5); \ static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5) \ { \ @@ -206,7 +206,7 @@ } #define HookWrapper6(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6) \ - Hook CONCAT(function, _hook); \ + HookedFunction CONCAT(function, _hook); \ typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6); \ static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6) \ { \ @@ -218,7 +218,7 @@ } #define HookWrapper7(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7) \ - Hook CONCAT(function, _hook); \ + HookedFunction CONCAT(function, _hook); \ typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7); \ static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7) \ { \ @@ -230,7 +230,7 @@ } #define HookWrapper8(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, p8) \ - Hook CONCAT(function, _hook); \ + HookedFunction CONCAT(function, _hook); \ typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8); \ static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8) \ { \ @@ -243,7 +243,7 @@ #define HookWrapper9(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \ p8, t9, p9) \ - Hook CONCAT(function, _hook); \ + HookedFunction CONCAT(function, _hook); \ typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9); \ static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \ t8 p8, t9 p9) \ @@ -255,23 +255,24 @@ return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9); \ } -#define HookWrapper10(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \ - p8, t9, p9, t10, p10) \ - Hook CONCAT(function, _hook); \ - typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); \ - static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \ - t8 p8, t9 p9, t10 p10) \ - { \ - SCOPED_LOCK(glLock); \ - if(!glhooks.m_HaveContextCreation) \ - return GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \ - gl_CurChunk = GLChunk::function; \ - return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \ +#define HookWrapper10(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \ + p8, t9, p9, t10, p10) \ + HookedFunction CONCAT(function, _hook); \ + typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); \ + static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \ + t8 p8, t9 p9, t10 p10) \ + { \ + SCOPED_LOCK(glLock); \ + if(!glhooks.m_HaveContextCreation) \ + return GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \ + gl_CurChunk = GLChunk::function; \ + return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \ } #define HookWrapper11(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \ p8, t9, p9, t10, p10, t11, p11) \ - Hook CONCAT(function, _hook); \ + HookedFunction CONCAT(function, \ + _hook); \ typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11); \ static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \ t8 p8, t9 p9, t10 p10, t11 p11) \ @@ -283,25 +284,26 @@ return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \ } -#define HookWrapper12(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \ - p8, t9, p9, t10, p10, t11, p11, t12, p12) \ - Hook CONCAT(function, _hook); \ - typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \ - t12); \ - static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \ - t8 p8, t9 p9, t10 p10, t11 p11, t12 p12) \ - { \ - SCOPED_LOCK(glLock); \ - if(!glhooks.m_HaveContextCreation) \ - return GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \ - gl_CurChunk = GLChunk::function; \ - return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \ +#define HookWrapper12(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \ + p8, t9, p9, t10, p10, t11, p11, t12, p12) \ + HookedFunction CONCAT( \ + function, _hook); \ + typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \ + t12); \ + static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \ + t8 p8, t9 p9, t10 p10, t11 p11, t12 p12) \ + { \ + SCOPED_LOCK(glLock); \ + if(!glhooks.m_HaveContextCreation) \ + return GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \ + gl_CurChunk = GLChunk::function; \ + return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \ } #define HookWrapper13(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \ p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13) \ - Hook CONCAT(function, \ - _hook); \ + HookedFunction CONCAT( \ + function, _hook); \ typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \ t12, t13); \ static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \ @@ -314,107 +316,108 @@ return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \ } -#define HookWrapper14(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \ - p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14) \ - Hook CONCAT( \ - function, _hook); \ - typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \ - t12, t13, t14); \ - static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \ - t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \ - t14 p14) \ - { \ - SCOPED_LOCK(glLock); \ - if(!glhooks.m_HaveContextCreation) \ - return GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \ - gl_CurChunk = GLChunk::function; \ - return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \ - p14); \ - } - -#define HookWrapper15(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \ - p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14, t15, p15) \ - Hook CONCAT( \ - function, _hook); \ - typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \ - t12, t13, t14, t15); \ - static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \ - t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \ - t14 p14, t15 p15) \ - { \ - SCOPED_LOCK(glLock); \ - if(!glhooks.m_HaveContextCreation) \ - return GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); \ - gl_CurChunk = GLChunk::function; \ - return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \ - p14, p15); \ - } - -#define HookWrapper16(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \ - p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14, t15, p15, t16, \ - p16) \ - Hook CONCAT( \ +#define HookWrapper14(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \ + p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14) \ + HookedFunction CONCAT( \ function, _hook); \ typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \ - t12, t13, t14, t15, t16); \ + t12, t13, t14); \ static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \ t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \ - t14 p14, t15 p15, t16 p16) \ + t14 p14) \ { \ SCOPED_LOCK(glLock); \ if(!glhooks.m_HaveContextCreation) \ - return GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16); \ + return GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \ gl_CurChunk = GLChunk::function; \ return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \ - p14, p15, p16); \ + p14); \ } -#define HookWrapper17(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \ - p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14, t15, p15, t16, \ - p16, t17, p17) \ - Hook CONCAT( \ +#define HookWrapper15(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \ + p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14, t15, p15) \ + HookedFunction CONCAT( \ function, _hook); \ typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \ - t12, t13, t14, t15, t16, t17); \ + t12, t13, t14, t15); \ static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \ t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \ - t14 p14, t15 p15, t16 p16, t17 p17) \ + t14 p14, t15 p15) \ { \ SCOPED_LOCK(glLock); \ if(!glhooks.m_HaveContextCreation) \ - return GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, \ - p17); \ + return GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); \ gl_CurChunk = GLChunk::function; \ return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \ - p14, p15, p16, p17); \ + p14, p15); \ } -#define HookAliasWrapper0(ret, function, realfunc) \ - Hook CONCAT(function, _hook); \ - typedef ret(WINAPI *CONCAT(function, _hooktype))(); \ - static ret WINAPI CONCAT(function, _hooked)() \ - { \ - SCOPED_LOCK(glLock); \ - if(!glhooks.m_HaveContextCreation) \ - return GL.realfunc(); \ - gl_CurChunk = GLChunk::function; \ - return glhooks.GetDriver()->realfunc(); \ +#define HookWrapper16(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \ + p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14, t15, p15, t16, \ + p16) \ + HookedFunction \ + CONCAT(function, _hook); \ + typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \ + t12, t13, t14, t15, t16); \ + static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \ + t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \ + t14 p14, t15 p15, t16 p16) \ + { \ + SCOPED_LOCK(glLock); \ + if(!glhooks.m_HaveContextCreation) \ + return GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16); \ + gl_CurChunk = GLChunk::function; \ + return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \ + p14, p15, p16); \ } -#define HookAliasWrapper1(ret, function, realfunc, t1, p1) \ - Hook CONCAT(function, _hook); \ - typedef ret(WINAPI *CONCAT(function, _hooktype))(t1); \ - static ret WINAPI CONCAT(function, _hooked)(t1 p1) \ +#define HookWrapper17(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, \ + p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, t14, p14, t15, p15, t16, \ + p16, t17, p17) \ + HookedFunction \ + CONCAT(function, _hook); \ + typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \ + t12, t13, t14, t15, t16, t17); \ + static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \ + t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \ + t14 p14, t15 p15, t16 p16, t17 p17) \ + { \ + SCOPED_LOCK(glLock); \ + if(!glhooks.m_HaveContextCreation) \ + return GL.function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, \ + p17); \ + gl_CurChunk = GLChunk::function; \ + return glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \ + p14, p15, p16, p17); \ + } + +#define HookAliasWrapper0(ret, function, realfunc) \ + HookedFunction CONCAT(function, _hook); \ + typedef ret(WINAPI *CONCAT(function, _hooktype))(); \ + static ret WINAPI CONCAT(function, _hooked)() \ { \ SCOPED_LOCK(glLock); \ if(!glhooks.m_HaveContextCreation) \ - return GL.realfunc(p1); \ + return GL.realfunc(); \ gl_CurChunk = GLChunk::function; \ - return glhooks.GetDriver()->realfunc(p1); \ + return glhooks.GetDriver()->realfunc(); \ + } + +#define HookAliasWrapper1(ret, function, realfunc, t1, p1) \ + HookedFunction CONCAT(function, _hook); \ + typedef ret(WINAPI *CONCAT(function, _hooktype))(t1); \ + static ret WINAPI CONCAT(function, _hooked)(t1 p1) \ + { \ + SCOPED_LOCK(glLock); \ + if(!glhooks.m_HaveContextCreation) \ + return GL.realfunc(p1); \ + gl_CurChunk = GLChunk::function; \ + return glhooks.GetDriver()->realfunc(p1); \ } #define HookAliasWrapper2(ret, function, realfunc, t1, p1, t2, p2) \ - Hook CONCAT(function, _hook); \ + HookedFunction CONCAT(function, _hook); \ typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2); \ static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2) \ { \ @@ -426,7 +429,7 @@ } #define HookAliasWrapper3(ret, function, realfunc, t1, p1, t2, p2, t3, p3) \ - Hook CONCAT(function, _hook); \ + HookedFunction CONCAT(function, _hook); \ typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3); \ static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3) \ { \ @@ -438,7 +441,7 @@ } #define HookAliasWrapper4(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4) \ - Hook CONCAT(function, _hook); \ + HookedFunction CONCAT(function, _hook); \ typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4); \ static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4) \ { \ @@ -450,7 +453,7 @@ } #define HookAliasWrapper5(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5) \ - Hook CONCAT(function, _hook); \ + HookedFunction CONCAT(function, _hook); \ typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5); \ static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5) \ { \ @@ -462,7 +465,7 @@ } #define HookAliasWrapper6(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6) \ - Hook CONCAT(function, _hook); \ + HookedFunction CONCAT(function, _hook); \ typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6); \ static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6) \ { \ @@ -475,7 +478,7 @@ #define HookAliasWrapper7(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, \ t7, p7) \ - Hook CONCAT(function, _hook); \ + HookedFunction CONCAT(function, _hook); \ typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7); \ static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7) \ { \ @@ -488,7 +491,7 @@ #define HookAliasWrapper8(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, \ t7, p7, t8, p8) \ - Hook CONCAT(function, _hook); \ + HookedFunction CONCAT(function, _hook); \ typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8); \ static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8) \ { \ @@ -501,7 +504,7 @@ #define HookAliasWrapper9(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, \ t7, p7, t8, p8, t9, p9) \ - Hook CONCAT(function, _hook); \ + HookedFunction CONCAT(function, _hook); \ typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9); \ static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \ t8 p8, t9 p9) \ @@ -513,23 +516,24 @@ return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9); \ } -#define HookAliasWrapper10(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \ - p6, t7, p7, t8, p8, t9, p9, t10, p10) \ - Hook CONCAT(function, _hook); \ - typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); \ - static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \ - t8 p8, t9 p9, t10 p10) \ - { \ - SCOPED_LOCK(glLock); \ - if(!glhooks.m_HaveContextCreation) \ - return GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \ - gl_CurChunk = GLChunk::function; \ - return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \ +#define HookAliasWrapper10(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \ + p6, t7, p7, t8, p8, t9, p9, t10, p10) \ + HookedFunction CONCAT(function, _hook); \ + typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); \ + static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \ + t8 p8, t9 p9, t10 p10) \ + { \ + SCOPED_LOCK(glLock); \ + if(!glhooks.m_HaveContextCreation) \ + return GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \ + gl_CurChunk = GLChunk::function; \ + return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \ } #define HookAliasWrapper11(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \ p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11) \ - Hook CONCAT(function, _hook); \ + HookedFunction CONCAT(function, \ + _hook); \ typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11); \ static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \ t8 p8, t9 p9, t10 p10, t11 p11) \ @@ -541,25 +545,26 @@ return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \ } -#define HookAliasWrapper12(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \ - p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11, t12, p12) \ - Hook CONCAT(function, _hook); \ - typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \ - t12); \ - static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \ - t8 p8, t9 p9, t10 p10, t11 p11, t12 p12) \ - { \ - SCOPED_LOCK(glLock); \ - if(!glhooks.m_HaveContextCreation) \ - return GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \ - gl_CurChunk = GLChunk::function; \ - return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \ +#define HookAliasWrapper12(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \ + p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11, t12, p12) \ + HookedFunction CONCAT( \ + function, _hook); \ + typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \ + t12); \ + static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \ + t8 p8, t9 p9, t10 p10, t11 p11, t12 p12) \ + { \ + SCOPED_LOCK(glLock); \ + if(!glhooks.m_HaveContextCreation) \ + return GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \ + gl_CurChunk = GLChunk::function; \ + return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \ } #define HookAliasWrapper13(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \ p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13) \ - Hook CONCAT(function, \ - _hook); \ + HookedFunction CONCAT( \ + function, _hook); \ typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \ t12, t13); \ static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \ @@ -572,81 +577,82 @@ return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \ } -#define HookAliasWrapper14(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \ - p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, \ - t14, p14) \ - Hook CONCAT( \ - function, _hook); \ - typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \ - t12, t13, t14); \ - static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \ - t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \ - t14 p14) \ - { \ - SCOPED_LOCK(glLock); \ - if(!glhooks.m_HaveContextCreation) \ - return GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \ - gl_CurChunk = GLChunk::function; \ - return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \ - p14); \ - } - -#define HookAliasWrapper15(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \ - p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, \ - t14, p14, t15, p15) \ - Hook CONCAT( \ - function, _hook); \ - typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \ - t12, t13, t14, t15); \ - static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \ - t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \ - t14 p14, t15 p15) \ - { \ - SCOPED_LOCK(glLock); \ - if(!glhooks.m_HaveContextCreation) \ - return GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); \ - gl_CurChunk = GLChunk::function; \ - return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \ - p14, p15); \ - } - -#define HookAliasWrapper16(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \ +#define HookAliasWrapper14(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \ p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, \ - t14, p14, t15, p15, t16, p16) \ - Hook CONCAT( \ + t14, p14) \ + HookedFunction CONCAT( \ function, _hook); \ typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \ - t12, t13, t14, t15, t16); \ + t12, t13, t14); \ static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \ t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \ - t14 p14, t15 p15, t16 p16) \ + t14 p14) \ { \ SCOPED_LOCK(glLock); \ if(!glhooks.m_HaveContextCreation) \ - return GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16); \ + return GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \ gl_CurChunk = GLChunk::function; \ return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \ - p14, p15, p16); \ + p14); \ } -#define HookAliasWrapper17(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \ +#define HookAliasWrapper15(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \ p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, \ - t14, p14, t15, p15, t16, p16, t17, p17) \ - Hook CONCAT( \ + t14, p14, t15, p15) \ + HookedFunction CONCAT( \ function, _hook); \ typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \ - t12, t13, t14, t15, t16, t17); \ + t12, t13, t14, t15); \ static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \ t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \ - t14 p14, t15 p15, t16 p16, t17 p17) \ + t14 p14, t15 p15) \ { \ SCOPED_LOCK(glLock); \ if(!glhooks.m_HaveContextCreation) \ - return GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, \ - p17); \ + return GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); \ gl_CurChunk = GLChunk::function; \ return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \ - p14, p15, p16, p17); \ + p14, p15); \ + } + +#define HookAliasWrapper16(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \ + p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, \ + t14, p14, t15, p15, t16, p16) \ + HookedFunction \ + CONCAT(function, _hook); \ + typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \ + t12, t13, t14, t15, t16); \ + static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \ + t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \ + t14 p14, t15 p15, t16 p16) \ + { \ + SCOPED_LOCK(glLock); \ + if(!glhooks.m_HaveContextCreation) \ + return GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16); \ + gl_CurChunk = GLChunk::function; \ + return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \ + p14, p15, p16); \ + } + +#define HookAliasWrapper17(ret, function, realfunc, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, \ + p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11, t12, p12, t13, p13, \ + t14, p14, t15, p15, t16, p16, t17, p17) \ + HookedFunction \ + CONCAT(function, _hook); \ + typedef ret(WINAPI *CONCAT(function, _hooktype))(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, \ + t12, t13, t14, t15, t16, t17); \ + static ret WINAPI CONCAT(function, _hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, \ + t8 p8, t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, \ + t14 p14, t15 p15, t16 p16, t17 p17) \ + { \ + SCOPED_LOCK(glLock); \ + if(!glhooks.m_HaveContextCreation) \ + return GL.realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, \ + p17); \ + gl_CurChunk = GLChunk::function; \ + return glhooks.GetDriver()->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, \ + p14, p15, p16, p17); \ } typedef BOOL(WINAPI *WGLMAKECURRENTPROC)(HDC, HGLRC); @@ -673,11 +679,11 @@ public: SetUnsupportedFunctionPointersToNULL(); } ~OpenGLHook() { delete m_GLDriver; } - bool CreateHooks(const char *libName) + void RegisterHooks() { - SetupHooks(); + LibraryHooks::RegisterLibraryHook("opengl32.dll", NULL); - return true; + SetupHooks(); } static OpenGLHook glhooks; @@ -901,19 +907,19 @@ private: // and never being called by the app. bool m_HaveContextCreation; - Hook wglCreateContext_hook; - Hook wglDeleteContext_hook; - Hook wglCreateLayerContext_hook; - Hook wglMakeCurrent_hook; - Hook wglGetProcAddress_hook; - Hook SwapBuffers_hook; - Hook wglSwapBuffers_hook; - Hook wglSwapLayerBuffers_hook; - Hook wglSwapMultipleBuffers_hook; - Hook ChangeDisplaySettingsA_hook; - Hook ChangeDisplaySettingsW_hook; - Hook ChangeDisplaySettingsExA_hook; - Hook ChangeDisplaySettingsExW_hook; + HookedFunction wglCreateContext_hook; + HookedFunction wglDeleteContext_hook; + HookedFunction wglCreateLayerContext_hook; + HookedFunction wglMakeCurrent_hook; + HookedFunction wglGetProcAddress_hook; + HookedFunction SwapBuffers_hook; + HookedFunction wglSwapBuffers_hook; + HookedFunction wglSwapLayerBuffers_hook; + HookedFunction wglSwapMultipleBuffers_hook; + HookedFunction ChangeDisplaySettingsA_hook; + HookedFunction ChangeDisplaySettingsW_hook; + HookedFunction ChangeDisplaySettingsExA_hook; + HookedFunction ChangeDisplaySettingsExW_hook; PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB_realfunc; PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB_realfunc; @@ -1354,27 +1360,27 @@ private: void SetupHooks() { - wglCreateContext_hook.Initialize("wglCreateContext", "opengl32.dll", wglCreateContext_hooked); - wglDeleteContext_hook.Initialize("wglDeleteContext", "opengl32.dll", wglDeleteContext_hooked); - wglCreateLayerContext_hook.Initialize("wglCreateLayerContext", "opengl32.dll", - wglCreateLayerContext_hooked); - wglMakeCurrent_hook.Initialize("wglMakeCurrent", "opengl32.dll", wglMakeCurrent_hooked); + wglCreateContext_hook.Register("opengl32.dll", "wglCreateContext", wglCreateContext_hooked); + wglDeleteContext_hook.Register("opengl32.dll", "wglDeleteContext", wglDeleteContext_hooked); + wglCreateLayerContext_hook.Register("opengl32.dll", "wglCreateLayerContext", + wglCreateLayerContext_hooked); + wglMakeCurrent_hook.Register("opengl32.dll", "wglMakeCurrent", wglMakeCurrent_hooked); - wglGetProcAddress_hook.Initialize("wglGetProcAddress", "opengl32.dll", wglGetProcAddress_hooked); - wglSwapBuffers_hook.Initialize("wglSwapBuffers", "opengl32.dll", wglSwapBuffers_hooked); - wglSwapLayerBuffers_hook.Initialize("wglSwapLayerBuffers", "opengl32.dll", - wglSwapLayerBuffers_hooked); - wglSwapMultipleBuffers_hook.Initialize("wglSwapMultipleBuffers", "opengl32.dll", - wglSwapMultipleBuffers_hooked); - SwapBuffers_hook.Initialize("SwapBuffers", "gdi32.dll", SwapBuffers_hooked); - ChangeDisplaySettingsA_hook.Initialize("ChangeDisplaySettingsA", "user32.dll", - ChangeDisplaySettingsA_hooked); - ChangeDisplaySettingsW_hook.Initialize("ChangeDisplaySettingsW", "user32.dll", - ChangeDisplaySettingsW_hooked); - ChangeDisplaySettingsExA_hook.Initialize("ChangeDisplaySettingsExA", "user32.dll", - ChangeDisplaySettingsExA_hooked); - ChangeDisplaySettingsExW_hook.Initialize("ChangeDisplaySettingsExW", "user32.dll", - ChangeDisplaySettingsExW_hooked); + wglGetProcAddress_hook.Register("opengl32.dll", "wglGetProcAddress", wglGetProcAddress_hooked); + wglSwapBuffers_hook.Register("opengl32.dll", "wglSwapBuffers", wglSwapBuffers_hooked); + wglSwapLayerBuffers_hook.Register("opengl32.dll", "wglSwapLayerBuffers", + wglSwapLayerBuffers_hooked); + wglSwapMultipleBuffers_hook.Register("opengl32.dll", "wglSwapMultipleBuffers", + wglSwapMultipleBuffers_hooked); + SwapBuffers_hook.Register("gdi32.dll", "SwapBuffers", SwapBuffers_hooked); + ChangeDisplaySettingsA_hook.Register("user32.dll", "ChangeDisplaySettingsA", + ChangeDisplaySettingsA_hooked); + ChangeDisplaySettingsW_hook.Register("user32.dll", "ChangeDisplaySettingsW", + ChangeDisplaySettingsW_hooked); + ChangeDisplaySettingsExA_hook.Register("user32.dll", "ChangeDisplaySettingsExA", + ChangeDisplaySettingsExA_hooked); + ChangeDisplaySettingsExW_hook.Register("user32.dll", "ChangeDisplaySettingsExW", + ChangeDisplaySettingsExW_hooked); DLLExportHooks(); } diff --git a/renderdoc/driver/gl/gl_library_egl.cpp b/renderdoc/driver/gl/gl_library_egl.cpp index f6910fc92..4af0ae260 100644 --- a/renderdoc/driver/gl/gl_library_egl.cpp +++ b/renderdoc/driver/gl/gl_library_egl.cpp @@ -24,7 +24,7 @@ #include "gl_library_egl.h" #include -#include "os/posix/posix_hook.h" +#include "hooks/hooks.h" bool EGLPointers::LoadSymbolsFrom(void *lib_handle) { diff --git a/renderdoc/driver/vulkan/vk_layer.cpp b/renderdoc/driver/vulkan/vk_layer.cpp index 3a1f38c14..db30766e3 100644 --- a/renderdoc/driver/vulkan/vk_layer.cpp +++ b/renderdoc/driver/vulkan/vk_layer.cpp @@ -48,16 +48,16 @@ class VulkanHook : LibraryHook { VulkanHook() {} - bool CreateHooks(const char *libName) + void RegisterHooks() { + // we don't register any library or function hooks because we use the layer system + // we assume the implicit layer is registered - the UI will prompt the user about installing it. Process::RegisterEnvironmentModification(EnvironmentModification( EnvMod::Set, EnvSep::NoSep, "ENABLE_VULKAN_RENDERDOC_CAPTURE", "1")); // check options to set further variables, and apply OptionsUpdated(); - - return true; } void OptionsUpdated() diff --git a/renderdoc/hooks/hooks.cpp b/renderdoc/hooks/hooks.cpp index 146d9c586..5b9fd0609 100644 --- a/renderdoc/hooks/hooks.cpp +++ b/renderdoc/hooks/hooks.cpp @@ -26,35 +26,61 @@ #include "hooks.h" #include "common/common.h" -LibraryHooks &LibraryHooks::GetInstance() +static std::vector &LibList() { - static LibraryHooks instance; - return instance; + static std::vector libs; + return libs; } -void LibraryHooks::RegisterLibrary(LibraryHook *lib) +LibraryHook::LibraryHook() { - m_Libraries.push_back(lib); + LibList().push_back(this); } -void LibraryHooks::CreateHooks() +void LibraryHooks::RegisterHooks() { - HOOKS_BEGIN(); - for(LibraryHook *lib : m_Libraries) - lib->CreateHooks("dummy"); - HOOKS_END(); -} + BeginHookRegistration(); -void LibraryHooks::RemoveHooks() -{ - if(m_HooksRemoved) - return; - m_HooksRemoved = true; - HOOKS_REMOVE(); + for(LibraryHook *lib : LibList()) + lib->RegisterHooks(); + + EndHookRegistration(); } void LibraryHooks::OptionsUpdated() { - for(LibraryHook *lib : m_Libraries) + for(LibraryHook *lib : LibList()) lib->OptionsUpdated(); } + +//////////////////////////////////////////////////////////////////////// +// Very temporary compatibility layer with previous function interface. +// +// PosixHookFunction just calls LibraryHooks::RegisterFunctionHook and +// stores the resulting pointer in a map to look up later in +// PosixGetFunction +//////////////////////////////////////////////////////////////////////// + +static std::map origLookup; + +void PosixHookFunction(const char *name, void *hook) +{ + void **orig = origLookup[name]; + if(orig == NULL) + { + orig = origLookup[name] = new void *; + *orig = NULL; + } + + LibraryHooks::RegisterFunctionHook("", FunctionHook(name, orig, hook)); +} + +void *PosixGetFunction(void *handle, const char *name) +{ + void **orig = origLookup[name]; + if(orig && *orig) + return *orig; + + ScopedSuppressHooking suppress; + return Process::GetFunctionAddress(handle, name); +} diff --git a/renderdoc/hooks/hooks.h b/renderdoc/hooks/hooks.h index 9340b63df..53e4252d0 100644 --- a/renderdoc/hooks/hooks.h +++ b/renderdoc/hooks/hooks.h @@ -25,84 +25,197 @@ #pragma once -#include -using std::map; - #include "os/os_specific.h" -// include os-specific hooking mechanisms here +typedef std::function FunctionLoadCallback; -#if ENABLED(RDOC_WIN32) +struct FunctionHook +{ + FunctionHook() : orig(NULL), hook(NULL) {} + FunctionHook(const char *f, void **o, void *d) : function(f), orig(o), hook(d) {} + bool operator<(const FunctionHook &h) const { return function < h.function; } + std::string function; + void **orig; + void *hook; +}; -#include "os/win32/win32_hook.h" +// == Hooking workflow overview == +// +// Each subsystem that wants to hook libraries creates a LibraryHook instance. That registers with +// LibraryHooks via the singleton in global constructors, but does nothing initially. +// +// Early in init, during RenderDoc's initialisation, the last thing that happens is a call to +// LibraryHooks::RegisterHooks(). This iterates through the LibraryHook instances and calls +// RegisterHooks on each of them. +// +// Each subsystem should call LibraryHooks::RegisterLibraryHook() for the filename of each library +// it wants to hook, then LibraryHooks::RegisterFunctionHook() for each function it wants to hook +// within that library. Note that not all platforms will use all the information provided, but only +// in a way that's invisible to the user. These are lightweight calls to register the hooks, and +// don't do any work yet. +// +// A registered library hook can get an optional callback when that library is first loaded. +// +// Similarly a registered function hook can provide a function pointer location which will be filled +// out with the function pointer to call onwards. This may just be the real implementation, or a +// trampoline, depending on the platform hooking method. +// +// Once all of this is completed, these hooks will be applied and activated as necessary. If any +// libraries are already loaded, library callbacks will fire here. Similarly function hook original +// pointers will be filled out if they are already available. Library callbacks will fire precisely +// once, the first time the library is loaded. +// +// NOTE: An important result of the behaviour above is that original function pointers are not +// necessarily available until the function is actually hooked. The hooking will automatically +// propagate all functions hooked in a library once it's loaded, and since some platforms may +// trampoline-hook target functions it is *not* safe to just get the target function's pointer as +// this may then call back into hooks. The only exception to this is with a library-specific +// function for fetching pointers such as GetProcAddress on OpenGL/Vulkan. However in this case care +// must be taken to suppress any effect of function interception by calling the relevant suppression +// functions. This ensures that if the API-specific GetProcAddress calls into the platform function +// fetch, it doesn't form an infinite loop. +// +// Also in the case that a function may come from many libraries, or it has multiple aliased names, +// the order of registration is important. The hooking implementations will always follow the order +// provided as a priority list, so if you register libFoo before libBar, any functions in libFoo +// have precedence. Similarly if you register foofunc() before barfunc() but pointed to the same +// pointer location for storing the original function pointer, barfunc()'s pointer will not +// overwrite foofunc() if it exists. +// +// == Hooking details (platform-specific) == +// +// The method of hooking varies by platform but follows the same general pattern. During +// registration we build up lists of which libraries and functions are to be hooked. Once the +// registration is complete we apply all of the hooks. +// +// NOTE: The library name for function hooks is only used on windows, since on linux/android +// namespace resolution is a bit fuzzier. At the time of writing there are no cases where two +// libraries have the same function that aren't functionally equivalent. +// +// - Windows - +// On windows this involves iterating over all loaded libraries and hooking their IAT tables. We +// also hook internally any functions for dynamically loading libraries or fetching functions, so +// that we can continue to re-wrap any newly loaded libraries. +// +// Loaded libraries at startup (most likely because the exe linked against them) have their +// callbacks fired immediately. Otherwise any time a new library is found on a subsequent iteration +// from a LoadLibrary-type call we fire the callback. +// +// Whenever a library is newly found, we hook all the entry points and update any original function +// pointers that are set to NULL. +// +// - Linux - +// On linux we rely on exporting all hooked symbols, and using LD_PRELOAD to load our library first +// in resolution order. All we do is hook dlopen so that when a new library is loaded we can +// redirect the returned library handle to ourselves, as well as process any pending function hooks. +// +// - Android - +// On android the implementation varies depending on whether we're using interceptor-lib or not. +// This is optional at build time but produces more reliable results: +// +// Without interceptor-lib: +// The implementation is similar to windows. Since we don't have LD_PRELOAD we need to patch import +// tables of any loaded libraries. We also cannot reliably hook dlopen on android to redirect the +// library handle to ourselves, so instead we hook dlsym and check to see if it corresponds to a +// function we're intercepting. This is the need for the 'suppress hooking' function, since if +// eglGetProcAddress calls into dlsym we don't want to intercept that dlsym and return our own +// function. +// +// With interceptor-lib: +// Instead of patching imports we overwrite the assembly at each entry point in the *target* +// library, and patch it to call into our hooks. Then we create trampolines to restore the original +// function for onwards-calling. +// +// To ensure sanity, we always load all registered libraries in the first hook applying phase. This +// ensures that we don't end up in a weird situation where one library is loaded, not all functions +// are hooked, the user code tries to populate any missing functions and then later another library +// is loaded and we patch it after having requested function pointers. Ensuring all libraries that +// we *might* patch are loaded ASAP, everything is consistent since after that any functions that +// don't have trampolines provided will never be trampolined in the future. +// +// Sometimes interceptor-lib can fail, at which point we fall back to the path above for those +// functions and try to follow and patch any imports to them. -template -class Hook +struct LibraryHook; + +// this singleton allows you to compile in code that defines a hook for a given library +// (and it will be registered). Then when the renderdoc library is initialised in the target +// program RegisterHooks() will be called to set up the hooks. +class LibraryHooks { public: - Hook() { orig_funcptr = NULL; } - ~Hook() {} + // generic, implemented in hooks.cpp to iterate over all registered libraries + static void RegisterHooks(); + static void OptionsUpdated(); + + // platform specific implementations + + // Removes hooks (where possible) and restores everything to an un-hooked state + static void RemoveHooks(); + + // refreshes hooks, useful on android where hooking can be unreliable + static void Refresh(); + + // Ignore this library - i.e. do not hook any calls it makes. Useful in the case where a library + // might call in to hooked APIs but we want to treat it as a black box. + static void IgnoreLibrary(const char *libraryName); + + // register a library for hooking, providing an optional callback to be called the first time the + // library has been loaded and all functions in it hooked. + static void RegisterLibraryHook(const char *libraryName, FunctionLoadCallback loadedCallback); + + // registers a function to be hooked, and an optional location of where to store the original + // onward function pointer + static void RegisterFunctionHook(const char *libraryName, const FunctionHook &hook); + + // detect if an identifier is present in the current process - used as a marker to indicate + // replay-type programs. + static bool Detect(const char *identifier); + +private: + static void BeginHookRegistration(); + static void EndHookRegistration(); +}; + +// defines the interface that a library hooking class will implement. +struct LibraryHook +{ + LibraryHook(); + virtual void RegisterHooks() = 0; + virtual void OptionsUpdated() {} +private: + friend class LibraryHooks; + + static std::vector m_Libraries; +}; + +template +class HookedFunction +{ +public: + HookedFunction() { orig_funcptr = NULL; } + ~HookedFunction() {} FuncType operator()() { return (FuncType)orig_funcptr; } void SetFuncPtr(void *ptr) { orig_funcptr = ptr; } - void Initialize(const char *function, const char *module_name, void *destination_function_ptr) + void Register(const char *module_name, const char *function, void *destination_function_ptr) { - orig_funcptr = Process::GetFunctionAddress(Process::LoadModule(module_name), function); - - Win32_IAT_Hook(&orig_funcptr, module_name, function, destination_function_ptr); + LibraryHooks::RegisterFunctionHook( + module_name, FunctionHook(function, &orig_funcptr, destination_function_ptr)); } private: void *orig_funcptr; }; -#define HOOKS_BEGIN() Win32_IAT_BeginHooks() -#define HOOKS_END() Win32_IAT_EndHooks() -#define HOOKS_REMOVE() Win32_IAT_RemoveHooks() -#define HOOKS_IDENTIFY(identifier) Win32_HookDetect(identifier) - -#elif ENABLED(RDOC_POSIX) - -#include "os/posix/posix_hook.h" - -// just need this for dlsym -#include - -#define HOOKS_BEGIN() PosixHookInit() -#define HOOKS_END() PosixHookApply() -#define HOOKS_REMOVE() -#define HOOKS_IDENTIFY(identifier) PosixHookDetect(identifier) - -#else - -#error "undefined platform" - -#endif - -struct LibraryHook; - -// this singleton allows you to compile in code that defines a hook for a given library -// (and it will be registered). Then when the renderdoc library is initialised in the target -// program CreateHooks() will be called to set up the hooks. -class LibraryHooks +struct ScopedSuppressHooking { -public: - LibraryHooks() : m_HooksRemoved(false) {} - static LibraryHooks &GetInstance(); - void RegisterLibrary(LibraryHook *lib); - void CreateHooks(); - void OptionsUpdated(); - void RemoveHooks(); - -private: - bool m_HooksRemoved; - - std::vector m_Libraries; + ScopedSuppressHooking(); + ~ScopedSuppressHooking(); }; -// defines the interface that a library hooking class will implement. -struct LibraryHook -{ - LibraryHook() { LibraryHooks::GetInstance().RegisterLibrary(this); } - virtual bool CreateHooks(const char *dummy) = 0; - virtual void OptionsUpdated() {} -}; \ No newline at end of file +//////////////////////////////////////////////////////////////////////// +// Very temporary compatibility layer with previous function interface. +//////////////////////////////////////////////////////////////////////// + +void PosixHookFunction(const char *name, void *hook); +void *PosixGetFunction(void *handle, const char *name); \ No newline at end of file diff --git a/renderdoc/os/posix/android/android_hook.cpp b/renderdoc/os/posix/android/android_hook.cpp index 86f19a524..d5de0106e 100644 --- a/renderdoc/os/posix/android/android_hook.cpp +++ b/renderdoc/os/posix/android/android_hook.cpp @@ -25,7 +25,7 @@ #include "3rdparty/plthook/plthook.h" #include "common/common.h" #include "common/threading.h" -#include "os/posix/posix_hook.h" +#include "hooks/hooks.h" #include #include @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -72,37 +73,32 @@ #error unsupported OS #endif -void PosixHookInit() -{ -} - -bool PosixHookDetect(const char *identifier) -{ - return dlsym(RTLD_DEFAULT, identifier) != NULL; -} - class HookingInfo { public: - void AddFunctionHook(const std::string &name, void *hook) + void AddFunctionHook(const FunctionHook &hook) { SCOPED_LOCK(lock); - funchooks[name] = hook; + funchooks.push_back(hook); + + // add to map to speed-up lookup in GetFunctionHook + funchook_map[hook.function] = hook; } void AddLibHook(const std::string &name) { SCOPED_LOCK(lock); - libhooks.insert(name); + if(std::find(libhooks.begin(), libhooks.end(), name) == libhooks.end()) + libhooks.push_back(name); } - void AddHookCallback(const std::string &name, dlopenCallback hook) + void AddHookCallback(const std::string &name, FunctionLoadCallback callback) { SCOPED_LOCK(lock); - hookcallbacks[name] = hook; + hookcallbacks[name].push_back(callback); } - std::map GetFunctionHooks() + std::vector GetFunctionHooks() { SCOPED_LOCK(lock); return funchooks; @@ -113,24 +109,25 @@ public: SCOPED_LOCK(lock); libhooks.clear(); funchooks.clear(); + funchook_map.clear(); } - std::set GetLibHooks() + std::vector GetLibHooks() { SCOPED_LOCK(lock); return libhooks; } - std::map GetHookCallbacks() + std::map> GetHookCallbacks() { SCOPED_LOCK(lock); return hookcallbacks; } - void *GetFunctionHook(const std::string &name) + FunctionHook GetFunctionHook(const std::string &name) { SCOPED_LOCK(lock); - return funchooks[name]; + return funchook_map[name]; } bool IsLibHook(const std::string &path) @@ -196,27 +193,15 @@ public: hooked_soname_already.insert(soname); } - void SetTrampoline(const std::string &funcname, void *trampoline) - { - SCOPED_LOCK(lock); - trampolines[funcname] = trampoline; - } - - void *GetTrampoline(const std::string &funcname) - { - SCOPED_LOCK(lock); - return trampolines[funcname]; - } - private: std::set hooked_soname_already; std::set hooked_handle_already; - std::map funchooks; - std::set libhooks; + std::vector funchooks; + std::map funchook_map; + std::vector libhooks; - std::map hookcallbacks; - std::map trampolines; + std::map> hookcallbacks; Threading::CriticalSection lock; }; @@ -227,37 +212,6 @@ HookingInfo &GetHookInfo() return hookinfo; } -void PosixHookFunction(const char *name, void *hook) -{ - GetHookInfo().AddFunctionHook(name, hook); -} - -void PosixHookLibrary(const char *name, dlopenCallback cb) -{ - GetHookInfo().AddLibHook(name); - - if(cb) - { - GetHookInfo().AddHookCallback(name, cb); - dlopen(name, RTLD_NOW); - } -} - -void *PosixGetFunction(void *handle, const char *name) -{ - // when we're not using interceptor-lib, this will always return NULL - void *ret = GetHookInfo().GetTrampoline(name); - if(ret) - { - HOOK_DEBUG_PRINT("Returning trampoline %p for %s", ret, name); - return ret; - } - - HOOK_DEBUG_PRINT("No trampoline for %s, going to dlsym", name); - PosixScopedSuppressHooking suppress; - return dlsym(handle, name); -} - void *intercept_dlopen(const char *filename, int flag) { if(GetHookInfo().IsLibHook(filename)) @@ -397,8 +351,8 @@ static int dl_iterate_callback(struct dl_phdr_info *info, size_t size, void *dat HOOK_DEBUG_PRINT("[%i] %s at %p (ptr to %p)", i, importname, import, *import); - void *repl = GetHookInfo().GetFunctionHook(importname); - if(repl) + const FunctionHook repl = GetHookInfo().GetFunctionHook(importname); + if(repl.hook) { HOOK_DEBUG_PRINT("replacing %s!", importname); @@ -426,7 +380,10 @@ static int dl_iterate_callback(struct dl_phdr_info *info, size_t size, void *dat HOOK_DEBUG_PRINT("Not in relro! - %p vs %p vs %p", relro_base, import, relro_end); } - *import = repl; + // note we don't save the orig function here, since we want to apply our library priorities + // and we don't know what order these headers will be iterated in. See EndHookRegistration + // for where we iterate and fetch all the function pointers we want. + *import = repl.hook; if(pagebase) { @@ -450,11 +407,6 @@ static int dl_iterate_callback(struct dl_phdr_info *info, size_t size, void *dat return 0; } -void PosixHookReapply() -{ - dl_iterate_phdr(dl_iterate_callback, NULL); -} - // android has a special dlopen that passes the caller address in. typedef void *(*pfn__loader_dlopen)(const char *filename, int flags, const void *caller_addr); @@ -525,37 +477,16 @@ extern "C" __attribute__((visibility("default"))) void *hooked_android_dlopen_ex return ret; } -PosixScopedSuppressHooking::PosixScopedSuppressHooking() -{ - if(suppressTLS == 0) - return; - - uintptr_t old = (uintptr_t)Threading::GetTLSValue(suppressTLS); - Threading::SetTLSValue(suppressTLS, (void *)(old + 1)); -} - -PosixScopedSuppressHooking::~PosixScopedSuppressHooking() -{ - if(suppressTLS == 0) - return; - - uintptr_t old = (uintptr_t)Threading::GetTLSValue(suppressTLS); - Threading::SetTLSValue(suppressTLS, (void *)(old - 1)); -} - -bool hooks_suppressed() -{ - return (uintptr_t)Threading::GetTLSValue(suppressTLS) > 0; -} +bool hooks_suppressed(); extern "C" __attribute__((visibility("default"))) void *hooked_dlsym(void *handle, const char *symbol) { if(handle == NULL || symbol == NULL || hooks_suppressed()) return dlsym(handle, symbol); - void *repl = GetHookInfo().GetFunctionHook(symbol); + const FunctionHook repl = GetHookInfo().GetFunctionHook(symbol); - if(repl == NULL) + if(repl.hook == NULL) return dlsym(handle, symbol); if(!GetHookInfo().IsHooked(handle)) @@ -568,8 +499,8 @@ extern "C" __attribute__((visibility("default"))) void *hooked_dlsym(void *handl if(GetHookInfo().IsLibHook(handle)) { - HOOK_DEBUG_PRINT("identified dlsym(%s) we want to interpose! returning %p", symbol, repl); - return repl; + HOOK_DEBUG_PRINT("identified dlsym(%s) we want to interpose! returning %p", symbol, repl.hook); + return repl.hook; } void *ret = dlsym(handle, symbol); @@ -579,7 +510,7 @@ extern "C" __attribute__((visibility("default"))) void *hooked_dlsym(void *handl return ret; } -static void PosixHookApplyCommon() +static void InstallHooksCommon() { suppressTLS = Threading::AllocateTLSSlot(); @@ -596,15 +527,16 @@ static void PosixHookApplyCommon() if(loader_dlopen) { - PosixHookFunction("dlopen", (void *)&hooked_dlopen); + LibraryHooks::RegisterFunctionHook("", FunctionHook("dlopen", NULL, (void *)&hooked_dlopen)); } else { RDCWARN("Couldn't find __loader_dlopen, falling back to slow path for dlopen hooking"); - PosixHookFunction("dlsym", (void *)&hooked_dlsym); + LibraryHooks::RegisterFunctionHook("", FunctionHook("dlsym", NULL, (void *)&hooked_dlsym)); } - PosixHookFunction("android_dlopen_ext", (void *)&hooked_android_dlopen_ext); + LibraryHooks::RegisterFunctionHook( + "", FunctionHook("android_dlopen_ext", NULL, (void *)&hooked_android_dlopen_ext)); } #if defined(RENDERDOC_HAVE_INTERCEPTOR_LIB) @@ -616,25 +548,25 @@ void intercept_error(void *, const char *error_msg) #include "3rdparty/interceptor-lib/include/interceptor.h" -void PosixHookApply() +void PatchHookedFunctions() { RDCLOG("Applying hooks with interceptor-lib"); // see below - Huawei workaround #if defined(__LP64__) - PosixHookLibrary("/system/lib64/libhwgl.so", NULL); + LibraryHooks::RegisterLibraryHook("/system/lib64/libhwgl.so", NULL); #else - PosixHookLibrary("/system/lib/libhwgl.so", NULL); + LibraryHooks::RegisterLibraryHook("/system/lib/libhwgl.so", NULL); #endif - std::set libs = GetHookInfo().GetLibHooks(); - std::map funchooks = GetHookInfo().GetFunctionHooks(); + std::vector libs = GetHookInfo().GetLibHooks(); + std::vector funchooks = GetHookInfo().GetFunctionHooks(); // we just leak this void *intercept = InitializeInterceptor(); std::set fallbacklibs; - std::set> fallbackhooks; + std::set fallbackhooks; for(const std::string &lib : libs) { @@ -650,9 +582,11 @@ void PosixHookApply() HOOK_DEBUG_PRINT("Hooking %s = %p", lib.c_str(), handle); - for(const std::pair &hook : funchooks) + std::set foundfunctions; + + for(const FunctionHook &hook : funchooks) { - void *oldfunc = dlsym(handle, hook.first.c_str()); + void *oldfunc = dlsym(handle, hook.function.c_str()); // UNTESTED workaround taken directly from GAPID, in installer.cpp. Quoted comment: /* @@ -662,24 +596,30 @@ void PosixHookApply() // so try to intercept the internal implementation instead. */ if(huawei && oldfunc == NULL) - oldfunc = dlsym(handle, ("hw_" + hook.first).c_str()); + oldfunc = dlsym(handle, ("hw_" + hook.function).c_str()); if(GetHookInfo().IsHooked(oldfunc)) continue; if(!oldfunc) { - HOOK_DEBUG_PRINT("%s didn't have %s", lib.c_str(), hook.first.c_str()); + HOOK_DEBUG_PRINT("%s didn't have %s", lib.c_str(), hook.function.c_str()); continue; } - HOOK_DEBUG_PRINT("Hooking %s::%s = %p with %p", lib.c_str(), hook.first.c_str(), oldfunc, - hook.second); + HOOK_DEBUG_PRINT("Hooking %s::%s = %p with %p", lib.c_str(), hook.function.c_str(), oldfunc, + hook.hook); void *trampoline = NULL; - bool success = - InterceptFunction(intercept, oldfunc, hook.second, &trampoline, &intercept_error); + bool success = InterceptFunction(intercept, oldfunc, hook.hook, &trampoline, &intercept_error); + + if(!hook.orig) + RDCWARN("No original pointer for hook of '%s' - trampoline will be lost!", + hook.function.c_str()); + + if(hook.orig && *hook.orig == NULL) + *hook.orig = trampoline; if(success) { @@ -687,24 +627,15 @@ void PosixHookApply() } else { - RDCERR("Failed to hook %s::%s!", lib.c_str(), hook.first.c_str()); + RDCERR("Failed to hook %s::%s!", lib.c_str(), hook.function.c_str()); fallbacklibs.insert(lib); fallbackhooks.insert(hook); } GetHookInfo().SetHooked(oldfunc); - - GetHookInfo().SetTrampoline(hook.first, trampoline); } } - std::map callbacks = GetHookInfo().GetHookCallbacks(); - for(const std::pair &cb : callbacks) - { - HOOK_DEBUG_PRINT("Calling complete callback for %s", cb.first.c_str()); - cb.second(dlopen(cb.first.c_str(), RTLD_GLOBAL)); - } - // we still need to hook android_dlopen_ext with interceptor-lib so that we can intercept the // vulkan loader's attempts to load our library and prevent it from loading a second copy (!!) // into the process. @@ -718,34 +649,153 @@ void PosixHookApply() GetHookInfo().AddLibHook(l); } - for(const std::pair &hook : fallbackhooks) + for(const FunctionHook &hook : fallbackhooks) { - RDCLOG("Falling back to PLT hooking for %s", hook.first.c_str()); - GetHookInfo().AddFunctionHook(hook.first, hook.second); + RDCLOG("Falling back to PLT hooking for %s", hook.function.c_str()); + GetHookInfo().AddFunctionHook(hook); } - - // this already hooks dlopen (if possible) and android_dlopen_ext, which is enough - PosixHookApplyCommon(); - - PosixHookReapply(); } #else -void PosixHookApply() +void PatchHookedFunctions() { RDCLOG("Applying hooks with PLT hooks"); - - PosixHookApplyCommon(); - - PosixHookReapply(); - - std::map callbacks = GetHookInfo().GetHookCallbacks(); - for(const std::pair &cb : callbacks) - { - HOOK_DEBUG_PRINT("Calling complete callback for %s", cb.first.c_str()); - cb.second(dlopen(cb.first.c_str(), RTLD_GLOBAL)); - } } #endif + +bool LibraryHooks::Detect(const char *identifier) +{ + return dlsym(RTLD_DEFAULT, identifier) != NULL; +} + +void LibraryHooks::RemoveHooks() +{ + RDCERR("Removing hooks is not possible on this platform"); +} + +void LibraryHooks::BeginHookRegistration() +{ + // nothing to do +} + +void LibraryHooks::RegisterFunctionHook(const char *libraryName, const FunctionHook &hook) +{ + // we don't use the library name on android + (void)libraryName; + HOOK_DEBUG_PRINT("Registering function hook for %s: %p", hook.function.c_str(), hook.hook); + GetHookInfo().AddFunctionHook(hook); +} + +void LibraryHooks::RegisterLibraryHook(const char *name, FunctionLoadCallback cb) +{ + GetHookInfo().AddLibHook(name); + + HOOK_DEBUG_PRINT("Registering library hook for %s %s", name, cb ? "with callback" : ""); + + // open the library immediately if we can + dlopen(name, RTLD_NOW); + + if(cb) + GetHookInfo().AddHookCallback(name, cb); +} + +void LibraryHooks::IgnoreLibrary(const char *libraryName) +{ +} + +void LibraryHooks::EndHookRegistration() +{ + HOOK_DEBUG_PRINT("EndHookRegistration"); + + // ensure we load all libraries we can immediately, so they are immediately hooked and don't get + // loaded later. + std::vector libs = GetHookInfo().GetLibHooks(); + for(const std::string &lib : libs) + { + void *handle = dlopen(lib.c_str(), RTLD_GLOBAL); + HOOK_DEBUG_PRINT("%s: %p", lib.c_str(), handle); + } + + PatchHookedFunctions(); + + // this already hooks dlopen (if possible) and android_dlopen_ext, which is enough + InstallHooksCommon(); + + LibraryHooks::Refresh(); + + // iterate our list of libraries and look up the original pointer for any that we don't already + // have. If we have interceptor-lib this will only be for functions that failed to generate a + // trampoline and we're PLT hooking - without interceptor-lib this will be all functions, but it + // will allow us to control the order/priority. + std::vector libraryHooks = GetHookInfo().GetLibHooks(); + std::vector functionHooks = GetHookInfo().GetFunctionHooks(); + + RDCLOG("Fetching %zu original function pointers over %zu libraries", functionHooks.size(), + libraryHooks.size()); + + for(auto it = libraryHooks.begin(); it != libraryHooks.end(); ++it) + { + void *handle = dlopen(it->c_str(), RTLD_NOLOAD | RTLD_GLOBAL); + + if(handle) + { + for(FunctionHook &hook : functionHooks) + { + if(hook.orig && *hook.orig == NULL) + *hook.orig = dlsym(handle, hook.function.c_str()); + } + } + } + + RDCLOG("Finished"); + + // call the callbacks for any libraries that loaded now. If the library wasn't loaded above then + // it can't be loaded, since we only hook system libraries. + std::map> callbacks = + GetHookInfo().GetHookCallbacks(); + for(const std::pair> &cb : callbacks) + { + void *handle = dlopen(cb.first.c_str(), RTLD_GLOBAL); + if(handle) + { + HOOK_DEBUG_PRINT("Calling callbacks for %s", cb.first.c_str()); + for(FunctionLoadCallback callback : cb.second) + if(callback) + callback(handle); + } + } + + RDCLOG("Called library callbacks - hook registration complete"); +} + +void LibraryHooks::Refresh() +{ + RDCLOG("Refreshing android hooks..."); + dl_iterate_phdr(dl_iterate_callback, NULL); + RDCLOG("Refreshed"); +} + +ScopedSuppressHooking::ScopedSuppressHooking() +{ + if(suppressTLS == 0) + return; + + uintptr_t old = (uintptr_t)Threading::GetTLSValue(suppressTLS); + Threading::SetTLSValue(suppressTLS, (void *)(old + 1)); +} + +ScopedSuppressHooking::~ScopedSuppressHooking() +{ + if(suppressTLS == 0) + return; + + uintptr_t old = (uintptr_t)Threading::GetTLSValue(suppressTLS); + Threading::SetTLSValue(suppressTLS, (void *)(old - 1)); +} + +bool hooks_suppressed() +{ + return (uintptr_t)Threading::GetTLSValue(suppressTLS) > 0; +} \ No newline at end of file diff --git a/renderdoc/os/posix/apple/apple_hook.cpp b/renderdoc/os/posix/apple/apple_hook.cpp index 4ef1dcf3f..1831b0fa5 100644 --- a/renderdoc/os/posix/apple/apple_hook.cpp +++ b/renderdoc/os/posix/apple/apple_hook.cpp @@ -22,46 +22,49 @@ * THE SOFTWARE. ******************************************************************************/ -#include "os/posix/posix_hook.h" +#include "hooks/hooks.h" #include #include -void PosixHookInit() +void LibraryHooks::BeginHookRegistration() +{ + // nothing to do +} + +void LibraryHooks::RegisterLibraryHook(char const *, FunctionLoadCallback cb) +{ + if(cb) + RDCERR("Hooking on apple not complete - function load callback not implemented"); +} + +void LibraryHooks::IgnoreLibrary(const char *libraryName) { } -bool PosixHookDetect(const char *identifier) +void LibraryHooks::EndHookRegistration() +{ +} + +bool LibraryHooks::Detect(const char *identifier) { return dlsym(RTLD_DEFAULT, identifier) != NULL; } -void PosixHookLibrary(const char *name, dlopenCallback cb) +void LibraryHooks::RemoveHooks() { + RDCERR("Removing hooks is not possible on this platform"); } // android only hooking functions, not used on apple -PosixScopedSuppressHooking::PosixScopedSuppressHooking() +ScopedSuppressHooking::ScopedSuppressHooking() { } -PosixScopedSuppressHooking::~PosixScopedSuppressHooking() +ScopedSuppressHooking::~ScopedSuppressHooking() { } -void PosixHookApply() +void LibraryHooks::Refresh() { -} - -void PosixHookReapply() -{ -} - -void PosixHookFunction(char const *, void *) -{ -} - -void *PosixGetFunction(void *handle, const char *name) -{ - return dlsym(handle, name); } \ No newline at end of file diff --git a/renderdoc/os/posix/linux/linux_hook.cpp b/renderdoc/os/posix/linux/linux_hook.cpp index 627d70405..c2dca37d8 100644 --- a/renderdoc/os/posix/linux/linux_hook.cpp +++ b/renderdoc/os/posix/linux/linux_hook.cpp @@ -24,43 +24,22 @@ #include #include +#include #include #include #include "3rdparty/plthook/plthook.h" #include "common/threading.h" +#include "hooks/hooks.h" #include "os/os_specific.h" -#include "os/posix/posix_hook.h" #include "strings/string_utils.h" -// depending on symbol resolution, dlopen could get called really early. -// until we've initialised, just skip any fancy stuff -static uint32_t hookInited = 0; -#define HOOK_MAGIC_NUMBER 0xAAF00F00 - -void PosixHookInit() -{ - hookInited = HOOK_MAGIC_NUMBER; -} - -bool PosixHookDetect(const char *identifier) -{ - return dlsym(RTLD_DEFAULT, identifier) != NULL; -} - -// need to lock around use of realdlopen and libraryHooks Threading::CriticalSection libLock; -static std::map libraryHooks; - -void PosixHookLibrary(const char *name, dlopenCallback cb) -{ - if(cb == NULL) - return; - - SCOPED_LOCK(libLock); - libraryHooks[name] = cb; -} +static std::map> libraryCallbacks; +static std::vector libraryHooks; +static std::vector functionHooks; +void *intercept_dlopen(const char *filename, int flag, void *ret); void plthook_lib(void *handle); typedef void *(*DLOPENPROC)(const char *, int); @@ -68,7 +47,7 @@ DLOPENPROC realdlopen = NULL; __attribute__((visibility("default"))) void *dlopen(const char *filename, int flag) { - if(hookInited != HOOK_MAGIC_NUMBER) + if(!realdlopen) { DLOPENPROC passthru = (DLOPENPROC)dlsym(RTLD_NEXT, "dlopen"); @@ -80,28 +59,12 @@ __attribute__((visibility("default"))) void *dlopen(const char *filename, int fl return ret; } - SCOPED_LOCK(libLock); - if(realdlopen == NULL) - realdlopen = (DLOPENPROC)dlsym(RTLD_NEXT, "dlopen"); - void *ret = realdlopen(filename, flag); if(filename && ret) { - if(flag & RTLD_DEEPBIND) - plthook_lib(ret); - - for(auto it = libraryHooks.begin(); it != libraryHooks.end(); ++it) - { - if(strstr(filename, it->first.c_str())) - { - RDCDEBUG("Redirecting dlopen to ourselves for %s", filename); - - it->second(ret); - - ret = realdlopen("librenderdoc.so", flag); - } - } + SCOPED_LOCK(libLock); + ret = intercept_dlopen(filename, flag, ret); } return ret; @@ -120,28 +83,117 @@ void plthook_lib(void *handle) plthook_close(plthook); } +void *intercept_dlopen(const char *filename, int flag, void *ret) +{ + if(flag & RTLD_DEEPBIND) + plthook_lib(ret); + + std::string base = basename(filename); + + for(auto it = libraryHooks.begin(); it != libraryHooks.end(); ++it) + { + const std::string &libName = *it; + if(*it == base) + { + RDCDEBUG("Redirecting dlopen to ourselves for %s", filename); + + for(FunctionHook &hook : functionHooks) + { + if(hook.orig && *hook.orig == NULL) + *hook.orig = dlsym(ret, hook.function.c_str()); + } + + for(FunctionLoadCallback cb : libraryCallbacks[libName]) + if(cb) + cb(ret); + + // don't call the callbacks again + libraryCallbacks[libName].clear(); + + ret = realdlopen("librenderdoc.so", flag); + break; + } + } + + return ret; +} + +void LibraryHooks::BeginHookRegistration() +{ + realdlopen = (DLOPENPROC)dlsym(RTLD_NEXT, "dlopen"); +} + +bool LibraryHooks::Detect(const char *identifier) +{ + return dlsym(RTLD_DEFAULT, identifier) != NULL; +} + +void LibraryHooks::RemoveHooks() +{ + RDCERR("Removing hooks is not possible on this platform"); +} + +void LibraryHooks::EndHookRegistration() +{ + // iterate over the libraries and see which ones are already loaded, process function hooks for + // them and call callbacks. + for(auto it = libraryHooks.begin(); it != libraryHooks.end(); ++it) + { + std::string libName = *it; + void *handle = realdlopen(libName.c_str(), RTLD_NOW | RTLD_NOLOAD | RTLD_GLOBAL); + + if(handle) + { + for(FunctionHook &hook : functionHooks) + { + if(hook.orig && *hook.orig == NULL) + *hook.orig = dlsym(handle, hook.function.c_str()); + } + + for(FunctionLoadCallback cb : libraryCallbacks[libName]) + if(cb) + cb(handle); + + // don't call callbacks again if the library is dlopen'd again + libraryCallbacks[libName].clear(); + } + } +} + +void LibraryHooks::Refresh() +{ + // don't need to refresh on linux +} + +void LibraryHooks::RegisterFunctionHook(const char *libraryName, const FunctionHook &hook) +{ + // we don't use the library name + (void)libraryName; + + SCOPED_LOCK(libLock); + functionHooks.push_back(hook); +} + +void LibraryHooks::RegisterLibraryHook(char const *name, FunctionLoadCallback cb) +{ + if(cb == NULL) + return; + + SCOPED_LOCK(libLock); + if(std::find(libraryHooks.begin(), libraryHooks.end(), name) == libraryHooks.end()) + libraryHooks.push_back(name); + libraryCallbacks[name].push_back(cb); +} + +void LibraryHooks::IgnoreLibrary(const char *libraryName) +{ +} + // android only hooking functions, not used on linux -PosixScopedSuppressHooking::PosixScopedSuppressHooking() +ScopedSuppressHooking::ScopedSuppressHooking() { } -PosixScopedSuppressHooking::~PosixScopedSuppressHooking() +ScopedSuppressHooking::~ScopedSuppressHooking() { -} - -void PosixHookApply() -{ -} - -void PosixHookReapply() -{ -} - -void PosixHookFunction(char const *, void *) -{ -} - -void *PosixGetFunction(void *handle, const char *name) -{ - return dlsym(handle, name); } \ No newline at end of file diff --git a/renderdoc/os/posix/posix_hook.h b/renderdoc/os/posix/posix_hook.h deleted file mode 100644 index 8fc7e6034..000000000 --- a/renderdoc/os/posix/posix_hook.h +++ /dev/null @@ -1,51 +0,0 @@ -/****************************************************************************** - * The MIT License (MIT) - * - * Copyright (c) 2016-2018 Baldur Karlsson - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - ******************************************************************************/ - -#pragma once - -typedef void (*dlopenCallback)(void *realLib); - -void PosixHookInit(); - -// if this name is dlopen'd, the real library will be passed -// to the callback and librenderdoc.so will be returned to user code -void PosixHookLibrary(const char *name, dlopenCallback cb); - -void PosixHookFunction(const char *name, void *hook); - -void *PosixGetFunction(void *handle, const char *name); - -void PosixHookApply(); - -// this is needed on android, when we are PLT hooking to ensure hooks are applied as soon as -// possible. -void PosixHookReapply(); - -struct PosixScopedSuppressHooking -{ - PosixScopedSuppressHooking(); - ~PosixScopedSuppressHooking(); -}; - -bool PosixHookDetect(const char *identifier); \ No newline at end of file diff --git a/renderdoc/os/posix/posix_libentry.cpp b/renderdoc/os/posix/posix_libentry.cpp index 72f1c92ca..dbdd3ea10 100644 --- a/renderdoc/os/posix/posix_libentry.cpp +++ b/renderdoc/os/posix/posix_libentry.cpp @@ -34,7 +34,7 @@ void library_loaded() string curfile; FileIO::GetExecutableFilename(curfile); - if(HOOKS_IDENTIFY("renderdoc__replay__marker")) + if(LibraryHooks::Detect("renderdoc__replay__marker")) { RDCDEBUG("Not creating hooks - in replay app"); @@ -68,7 +68,7 @@ void library_loaded() RDCLOG("Loading into %s", curfile.c_str()); - LibraryHooks::GetInstance().CreateHooks(); + LibraryHooks::RegisterHooks(); } } diff --git a/renderdoc/os/win32/sys_win32_hooks.cpp b/renderdoc/os/win32/sys_win32_hooks.cpp index 7e54498fb..1d5be7440 100644 --- a/renderdoc/os/win32/sys_win32_hooks.cpp +++ b/renderdoc/os/win32/sys_win32_hooks.cpp @@ -77,54 +77,57 @@ public: m_WSARefCount = 1; } - bool CreateHooks(const char *libName) + void RegisterHooks() { + RDCLOG("Registering Win32 system hooks"); + + // register libraries that we care about. We don't need a callback when they are loaded + LibraryHooks::RegisterLibraryHook("kernel32.dll", NULL); + LibraryHooks::RegisterLibraryHook("advapi32.dll", NULL); + LibraryHooks::RegisterLibraryHook("api-ms-win-core-processthreads-l1-1-0.dll", NULL); + LibraryHooks::RegisterLibraryHook("api-ms-win-core-processthreads-l1-1-1.dll", NULL); + LibraryHooks::RegisterLibraryHook("api-ms-win-core-processthreads-l1-1-2.dll", NULL); + LibraryHooks::RegisterLibraryHook("ws2_32.dll", NULL); + // we want to hook CreateProcess purely so that we can recursively insert our hooks (if we so // wish) - CreateProcessA.Initialize("CreateProcessA", "kernel32.dll", CreateProcessA_hook); - CreateProcessW.Initialize("CreateProcessW", "kernel32.dll", CreateProcessW_hook); + CreateProcessA.Register("kernel32.dll", "CreateProcessA", CreateProcessA_hook); + CreateProcessW.Register("kernel32.dll", "CreateProcessW", CreateProcessW_hook); - CreateProcessAsUserA.Initialize("CreateProcessAsUserA", "advapi32.dll", - CreateProcessAsUserA_hook); - CreateProcessAsUserW.Initialize("CreateProcessAsUserW", "advapi32.dll", - CreateProcessAsUserW_hook); + CreateProcessAsUserA.Register("advapi32.dll", "CreateProcessAsUserA", CreateProcessAsUserA_hook); + CreateProcessAsUserW.Register("advapi32.dll", "CreateProcessAsUserW", CreateProcessAsUserW_hook); - CreateProcessWithLogonW.Initialize("CreateProcessWithLogonW", "advapi32.dll", - CreateProcessWithLogonW_hook); + CreateProcessWithLogonW.Register("advapi32.dll", "CreateProcessWithLogonW", + CreateProcessWithLogonW_hook); // handle API set exports if they exist. These don't really exist so we don't have to worry // about double hooking, and also they call into the 'real' implementation in kernelbase.dll - API110CreateProcessA.Initialize("CreateProcessA", "api-ms-win-core-processthreads-l1-1-0.dll", - API110CreateProcessA_hook); - API110CreateProcessW.Initialize("CreateProcessW", "api-ms-win-core-processthreads-l1-1-0.dll", - API110CreateProcessW_hook); - API110CreateProcessAsUserW.Initialize("CreateProcessAsUserW", - "api-ms-win-core-processthreads-l1-1-0.dll", - API110CreateProcessAsUserW_hook); + API110CreateProcessA.Register("api-ms-win-core-processthreads-l1-1-0.dll", "CreateProcessA", + API110CreateProcessA_hook); + API110CreateProcessW.Register("api-ms-win-core-processthreads-l1-1-0.dll", "CreateProcessW", + API110CreateProcessW_hook); + API110CreateProcessAsUserW.Register("api-ms-win-core-processthreads-l1-1-0.dll", + "CreateProcessAsUserW", API110CreateProcessAsUserW_hook); - API111CreateProcessA.Initialize("CreateProcessA", "api-ms-win-core-processthreads-l1-1-1.dll", - API111CreateProcessA_hook); - API111CreateProcessW.Initialize("CreateProcessW", "api-ms-win-core-processthreads-l1-1-1.dll", - API111CreateProcessW_hook); - API111CreateProcessAsUserW.Initialize("CreateProcessAsUserW", - "api-ms-win-core-processthreads-l1-1-0.dll", - API111CreateProcessAsUserW_hook); + API111CreateProcessA.Register("api-ms-win-core-processthreads-l1-1-1.dll", "CreateProcessA", + API111CreateProcessA_hook); + API111CreateProcessW.Register("api-ms-win-core-processthreads-l1-1-1.dll", "CreateProcessW", + API111CreateProcessW_hook); + API111CreateProcessAsUserW.Register("api-ms-win-core-processthreads-l1-1-0.dll", + "CreateProcessAsUserW", API111CreateProcessAsUserW_hook); - API112CreateProcessA.Initialize("CreateProcessA", "api-ms-win-core-processthreads-l1-1-2.dll", - API112CreateProcessA_hook); - API112CreateProcessW.Initialize("CreateProcessW", "api-ms-win-core-processthreads-l1-1-2.dll", - API112CreateProcessW_hook); - API112CreateProcessAsUserW.Initialize("CreateProcessAsUserW", - "api-ms-win-core-processthreads-l1-1-0.dll", - API112CreateProcessAsUserW_hook); + API112CreateProcessA.Register("api-ms-win-core-processthreads-l1-1-2.dll", "CreateProcessA", + API112CreateProcessA_hook); + API112CreateProcessW.Register("api-ms-win-core-processthreads-l1-1-2.dll", "CreateProcessW", + API112CreateProcessW_hook); + API112CreateProcessAsUserW.Register("api-ms-win-core-processthreads-l1-1-0.dll", + "CreateProcessAsUserW", API112CreateProcessAsUserW_hook); - WSAStartup.Initialize("WSAStartup", "ws2_32.dll", WSAStartup_hook); - WSACleanup.Initialize("WSACleanup", "ws2_32.dll", WSACleanup_hook); + WSAStartup.Register("ws2_32.dll", "WSAStartup", WSAStartup_hook); + WSACleanup.Register("ws2_32.dll", "WSACleanup", WSACleanup_hook); m_RecurseSlot = Threading::AllocateTLSSlot(); Threading::SetTLSValue(m_RecurseSlot, NULL); - - return true; } private: @@ -144,27 +147,27 @@ private: return true; } void EndRecurse() { Threading::SetTLSValue(m_RecurseSlot, NULL); } - Hook CreateProcessA; - Hook CreateProcessW; + HookedFunction CreateProcessA; + HookedFunction CreateProcessW; - Hook API110CreateProcessA; - Hook API110CreateProcessW; - Hook API111CreateProcessA; - Hook API111CreateProcessW; - Hook API112CreateProcessA; - Hook API112CreateProcessW; + HookedFunction API110CreateProcessA; + HookedFunction API110CreateProcessW; + HookedFunction API111CreateProcessA; + HookedFunction API111CreateProcessW; + HookedFunction API112CreateProcessA; + HookedFunction API112CreateProcessW; - Hook CreateProcessAsUserA; - Hook CreateProcessAsUserW; + HookedFunction CreateProcessAsUserA; + HookedFunction CreateProcessAsUserW; - Hook API110CreateProcessAsUserW; - Hook API111CreateProcessAsUserW; - Hook API112CreateProcessAsUserW; + HookedFunction API110CreateProcessAsUserW; + HookedFunction API111CreateProcessAsUserW; + HookedFunction API112CreateProcessAsUserW; - Hook CreateProcessWithLogonW; + HookedFunction CreateProcessWithLogonW; - Hook WSAStartup; - Hook WSACleanup; + HookedFunction WSAStartup; + HookedFunction WSACleanup; static int WSAAPI WSAStartup_hook(WORD wVersionRequested, LPWSADATA lpWSAData) { diff --git a/renderdoc/os/win32/win32_hook.cpp b/renderdoc/os/win32/win32_hook.cpp index d4df9b3b2..c66826de6 100644 --- a/renderdoc/os/win32/win32_hook.cpp +++ b/renderdoc/os/win32/win32_hook.cpp @@ -30,8 +30,10 @@ #include #include #include +#include #include #include "common/threading.h" +#include "hooks/hooks.h" #include "os/os_specific.h" #include "strings/string_utils.h" @@ -44,74 +46,58 @@ using std::map; map s_InstalledHooks; Threading::CriticalSection installedLock; -struct FunctionHook +bool ApplyHook(FunctionHook &hook, void **IATentry, bool &already) { - FunctionHook(const char *f, void **o, void *d) - : function(f), origptr(o), hookptr(d), excludeModule(NULL) + DWORD oldProtection = PAGE_EXECUTE; + + if(*IATentry == hook.hook) { - } - - bool operator<(const FunctionHook &h) { return function < h.function; } - bool ApplyHook(void **IATentry, bool &already) - { - DWORD oldProtection = PAGE_EXECUTE; - - if(*IATentry == hookptr) - { - already = true; - return true; - } - -#if ENABLED(VERBOSE_DEBUG_HOOK) - RDCDEBUG("Patching IAT for %s: %p to %p", function.c_str(), IATentry, hookptr); -#endif - - { - SCOPED_LOCK(installedLock); - if(s_InstalledHooks.find(IATentry) == s_InstalledHooks.end()) - s_InstalledHooks[IATentry] = *IATentry; - } - - BOOL success = TRUE; - - success = VirtualProtect(IATentry, sizeof(void *), PAGE_READWRITE, &oldProtection); - if(!success) - { - RDCERR("Failed to make IAT entry writeable 0x%p", IATentry); - return false; - } - - if(origptr && *origptr == NULL) - *origptr = *IATentry; - - *IATentry = hookptr; - - success = VirtualProtect(IATentry, sizeof(void *), oldProtection, &oldProtection); - if(!success) - { - RDCERR("Failed to restore IAT entry protection 0x%p", IATentry); - return false; - } - + already = true; return true; } - string function; - void **origptr; - void *hookptr; - HMODULE excludeModule; -}; +#if ENABLED(VERBOSE_DEBUG_HOOK) + RDCDEBUG("Patching IAT for %s: %p to %p", function.c_str(), IATentry, hookptr); +#endif + + { + SCOPED_LOCK(installedLock); + if(s_InstalledHooks.find(IATentry) == s_InstalledHooks.end()) + s_InstalledHooks[IATentry] = *IATentry; + } + + BOOL success = TRUE; + + success = VirtualProtect(IATentry, sizeof(void *), PAGE_READWRITE, &oldProtection); + if(!success) + { + RDCERR("Failed to make IAT entry writeable 0x%p", IATentry); + return false; + } + + *IATentry = hook.hook; + + success = VirtualProtect(IATentry, sizeof(void *), oldProtection, &oldProtection); + if(!success) + { + RDCERR("Failed to restore IAT entry protection 0x%p", IATentry); + return false; + } + + return true; +} struct DllHookset { - DllHookset() : module(NULL), OrdinalBase(0) {} - HMODULE module; + HMODULE module = NULL; + bool hooksfetched = false; // if we have multiple copies of the dll loaded (unlikely), the other module handles will be // stored here vector altmodules; vector FunctionHooks; - DWORD OrdinalBase; + DWORD OrdinalBase = 0; vector OrdinalNames; + std::vector Callbacks; void FetchOrdinalNames() { @@ -172,8 +158,12 @@ struct CachedHookData Threading::CriticalSection lock; char lowername[512]; + std::set ignores; + bool missedOrdinals; + volatile int32_t posthooking = 0; + void ApplyHooks(const char *modName, HMODULE module) { { @@ -210,6 +200,18 @@ struct CachedHookData if(it->second.module == NULL) { it->second.module = module; + + it->second.hooksfetched = true; + + // fetch all function hooks here, since we want to fill out the original function pointer + // even in case nothing imports from that function (which means it would not get filled + // out through FunctionHook::ApplyHook) + for(FunctionHook &hook : it->second.FunctionHooks) + { + if(hook.orig && *hook.orig == NULL) + *hook.orig = GetProcAddress(module, hook.function.c_str()); + } + it->second.FetchOrdinalNames(); } else if(it->second.module != module) @@ -264,6 +266,9 @@ struct CachedHookData strstr(lowername, "nvopencl") == lowername || strstr(lowername, "nvapi") == lowername) return; + if(ignores.find(lowername) != ignores.end()) + return; + byte *baseAddress = (byte *)module; // the module could have been unloaded after our toolhelp snapshot, especially if we spent a @@ -375,13 +380,13 @@ struct CachedHookData importName, hook_find()); if(found != hookset->FunctionHooks.end() && - !strcmp(found->function.c_str(), importName) && found->excludeModule != module) + !strcmp(found->function.c_str(), importName) && ownmodule != module) { bool already = false; bool applied; { SCOPED_LOCK(lock); - applied = found->ApplyHook(IATentry, already); + applied = ApplyHook(*found, IATentry, already); } // if we failed, or if it's already set and we're not doing a missedOrdinals @@ -438,13 +443,13 @@ struct CachedHookData hookset->FunctionHooks.end(), importName, hook_find()); if(found != hookset->FunctionHooks.end() && - !strcmp(found->function.c_str(), importName) && found->excludeModule != module) + !strcmp(found->function.c_str(), importName) && ownmodule != module) { bool already = false; bool applied; { SCOPED_LOCK(lock); - applied = found->ApplyHook(IATentry, already); + applied = ApplyHook(*found, IATentry, already); } // if we failed, or if it's already set and we're not doing a missedOrdinals @@ -550,6 +555,42 @@ static void HookAllModules() { ForAllModules( [](const MODULEENTRY32 &me32) { s_HookData->ApplyHooks(me32.szModule, me32.hModule); }); + + // check if we're already in this section of code, and if so don't go in again. + int32_t prev = Atomic::CmpExch32(&s_HookData->posthooking, 0, 1); + + if(prev != 0) + return; + + // for all loaded modules, call callbacks now + for(auto it = s_HookData->DllHooks.begin(); it != s_HookData->DllHooks.end(); ++it) + { + if(it->second.module == NULL) + continue; + + if(!it->second.hooksfetched) + { + it->second.hooksfetched = true; + + // fetch all function hooks here, if we didn't above (perhaps because this library was + // late-loaded) + for(FunctionHook &hook : it->second.FunctionHooks) + { + if(hook.orig && *hook.orig == NULL) + *hook.orig = GetProcAddress(it->second.module, hook.function.c_str()); + } + } + + std::vector callbacks; + // don't call callbacks next time + callbacks.swap(it->second.Callbacks); + + for(FunctionLoadCallback cb : callbacks) + if(cb) + cb(it->second.module); + } + + Atomic::CmpExch32(&s_HookData->posthooking, 1, 0); } static bool IsAPISet(const wchar_t *filename) @@ -724,8 +765,7 @@ FARPROC WINAPI Hooked_GetProcAddress(HMODULE mod, LPCSTR func) std::lower_bound(it->second.FunctionHooks.begin(), it->second.FunctionHooks.end(), search); if(found != it->second.FunctionHooks.end() && !(search < *found)) { - if(found->origptr && *found->origptr == NULL) - *found->origptr = (void *)GetProcAddress(mod, func); + FARPROC realfunc = GetProcAddress(mod, func); #if ENABLED(VERBOSE_DEBUG_HOOK) RDCDEBUG("Found hooked function, returning hook pointer %p", found->hookptr); @@ -733,10 +773,10 @@ FARPROC WINAPI Hooked_GetProcAddress(HMODULE mod, LPCSTR func) SetLastError(S_OK); - if(found->origptr && *found->origptr == NULL) + if(realfunc == NULL) return NULL; - return (FARPROC)found->hookptr; + return (FARPROC)found->hook; } } } @@ -750,7 +790,37 @@ FARPROC WINAPI Hooked_GetProcAddress(HMODULE mod, LPCSTR func) return GetProcAddress(mod, func); } -void Win32_IAT_BeginHooks() +void LibraryHooks::RegisterFunctionHook(const char *libraryName, const FunctionHook &hook) +{ + if(!_stricmp(libraryName, "kernel32.dll")) + { + if(hook.function == "LoadLibraryA" || hook.function == "LoadLibraryW" || + hook.function == "LoadLibraryExA" || hook.function == "LoadLibraryExW" || + hook.function == "GetProcAddress") + { + RDCERR("Cannot hook LoadLibrary* or GetProcAddress, as these are hooked internally"); + return; + } + } + s_HookData->DllHooks[strlower(string(libraryName))].FunctionHooks.push_back(hook); +} + +void LibraryHooks::RegisterLibraryHook(const char *libraryName, FunctionLoadCallback loadedCallback) +{ + s_HookData->DllHooks[strlower(string(libraryName))].Callbacks.push_back(loadedCallback); +} + +void LibraryHooks::IgnoreLibrary(const char *libraryName) +{ + std::string lowername = libraryName; + + for(size_t i = 0; i < lowername.size(); i++) + lowername[i] = (char)tolower(lowername[i]); + + s_HookData->ignores.insert(lowername); +} + +void LibraryHooks::BeginHookRegistration() { s_HookData = new CachedHookData; RDCASSERT(s_HookData->DllHooks.empty()); @@ -785,15 +855,11 @@ void Win32_IAT_BeginHooks() GetModuleHandleEx( GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCTSTR)&s_HookData, &s_HookData->ownmodule); - - for(auto it = s_HookData->DllHooks.begin(); it != s_HookData->DllHooks.end(); ++it) - for(size_t i = 0; i < it->second.FunctionHooks.size(); i++) - it->second.FunctionHooks[i].excludeModule = s_HookData->ownmodule; } // hook all functions for currently loaded modules. // some of these hooks (as above) will hook LoadLibrary/GetProcAddress, to protect -void Win32_IAT_EndHooks() +void LibraryHooks::EndHookRegistration() { for(auto it = s_HookData->DllHooks.begin(); it != s_HookData->DllHooks.end(); ++it) std::sort(it->second.FunctionHooks.begin(), it->second.FunctionHooks.end()); @@ -818,7 +884,12 @@ void Win32_IAT_EndHooks() } } -void Win32_IAT_RemoveHooks() +void LibraryHooks::Refresh() +{ + // don't need to refresh on windows +} + +void LibraryHooks::RemoveHooks() { for(auto it = s_InstalledHooks.begin(); it != s_InstalledHooks.end(); ++it) { @@ -845,24 +916,7 @@ void Win32_IAT_RemoveHooks() } } -void Win32_IAT_Hook(void **orig_function_ptr, const char *module_name, const char *function, - void *destination_function_ptr) -{ - if(!_stricmp(module_name, "kernel32.dll")) - { - if(!strcmp(function, "LoadLibraryA") || !strcmp(function, "LoadLibraryW") || - !strcmp(function, "LoadLibraryExA") || !strcmp(function, "LoadLibraryExW") || - !strcmp(function, "GetProcAddress")) - { - RDCERR("Cannot hook LoadLibrary* or GetProcAddress, as these are hooked internally"); - return; - } - } - s_HookData->DllHooks[strlower(string(module_name))].FunctionHooks.push_back( - FunctionHook(function, orig_function_ptr, destination_function_ptr)); -} - -bool Win32_HookDetect(const char *identifier) +bool LibraryHooks::Detect(const char *identifier) { bool ret = false; ForAllModules([&ret, identifier](const MODULEENTRY32 &me32) { @@ -870,4 +924,13 @@ bool Win32_HookDetect(const char *identifier) ret = true; }); return ret; +} + +// android only hooking functions, not used on win32 +ScopedSuppressHooking::ScopedSuppressHooking() +{ +} + +ScopedSuppressHooking::~ScopedSuppressHooking() +{ } \ No newline at end of file diff --git a/renderdoc/os/win32/win32_hook.h b/renderdoc/os/win32/win32_hook.h deleted file mode 100644 index b7a42461e..000000000 --- a/renderdoc/os/win32/win32_hook.h +++ /dev/null @@ -1,34 +0,0 @@ -/****************************************************************************** - * The MIT License (MIT) - * - * Copyright (c) 2015-2018 Baldur Karlsson - * Copyright (c) 2014 Crytek - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - ******************************************************************************/ - -#pragma once - -void Win32_IAT_Hook(void **orig_function_ptr, const char *module_name, const char *function, - void *destination_function_ptr); -void Win32_IAT_BeginHooks(); -void Win32_IAT_EndHooks(); -void Win32_IAT_RemoveHooks(); - -bool Win32_HookDetect(const char *identifier); \ No newline at end of file diff --git a/renderdoc/os/win32/win32_libentry.cpp b/renderdoc/os/win32/win32_libentry.cpp index e4405bb0b..ba232e909 100644 --- a/renderdoc/os/win32/win32_libentry.cpp +++ b/renderdoc/os/win32/win32_libentry.cpp @@ -49,7 +49,7 @@ static BOOL add_hooks() } // search for an exported symbol with this name, typically renderdoc__replay__marker - if(HOOKS_IDENTIFY(STRINGIZE(RDOC_DLL_FILE) "__replay__marker")) + if(LibraryHooks::Detect(STRINGIZE(RDOC_DLL_FILE) "__replay__marker")) { RDCDEBUG("Not creating hooks - in replay app"); @@ -64,7 +64,7 @@ static BOOL add_hooks() RDCLOG("Loading into %ls", curFile); - LibraryHooks::GetInstance().CreateHooks(); + LibraryHooks::RegisterHooks(); return TRUE; } diff --git a/renderdoc/renderdoc.vcxproj b/renderdoc/renderdoc.vcxproj index ecba2f87c..2a654702f 100644 --- a/renderdoc/renderdoc.vcxproj +++ b/renderdoc/renderdoc.vcxproj @@ -195,9 +195,6 @@ - - true - true @@ -205,7 +202,6 @@ true - diff --git a/renderdoc/renderdoc.vcxproj.filters b/renderdoc/renderdoc.vcxproj.filters index f41cad07c..653b5206e 100644 --- a/renderdoc/renderdoc.vcxproj.filters +++ b/renderdoc/renderdoc.vcxproj.filters @@ -198,9 +198,6 @@ Resources\hlsl - - OS\Win32 - API\Replay @@ -270,9 +267,6 @@ OS\Win32 - - OS\Posix - OS\Posix diff --git a/renderdoc/replay/app_api.cpp b/renderdoc/replay/app_api.cpp index 92051992c..911857115 100644 --- a/renderdoc/replay/app_api.cpp +++ b/renderdoc/replay/app_api.cpp @@ -52,7 +52,7 @@ static void MaskOverlayBits(uint32_t And, uint32_t Or) static void Shutdown() { RenderDoc::Inst().Shutdown(); - LibraryHooks::GetInstance().RemoveHooks(); + LibraryHooks::RemoveHooks(); } static void UnloadCrashHandler()