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()