From 4a6462b63bd66da1cb8ce500d32442671c19d40f Mon Sep 17 00:00:00 2001 From: baldurk Date: Wed, 31 Jan 2018 14:50:14 +0000 Subject: [PATCH] Compile in interceptor-lib if LLVM is found, and use to hook on android * Note we still have to use PLT hooking for android_dlopen_ext that libvulkan uses to load layers, since interceptor-lib can't hook that, and otherwise libvulkan will load our library multiple times into the process instead of re-using the existing injected library. --- renderdoc/CMakeLists.txt | 19 ++ renderdoc/driver/gl/gl_hooks_egl.cpp | 83 ++--- renderdoc/driver/gl/gl_hooks_linux_shared.cpp | 222 +++++++++----- renderdoc/driver/gl/gl_hooks_vrapi.cpp | 64 ++-- renderdoc/driver/gl/gl_library_egl.cpp | 21 +- renderdoc/os/posix/android/android_hook.cpp | 290 +++++++++++++++--- renderdoc/os/posix/apple/apple_hook.cpp | 5 + renderdoc/os/posix/linux/linux_hook.cpp | 5 + renderdoc/os/posix/posix_hook.h | 2 + 9 files changed, 508 insertions(+), 203 deletions(-) diff --git a/renderdoc/CMakeLists.txt b/renderdoc/CMakeLists.txt index f3493396e..d834841e9 100644 --- a/renderdoc/CMakeLists.txt +++ b/renderdoc/CMakeLists.txt @@ -355,6 +355,25 @@ if(ENABLE_GL OR ENABLE_GLES OR ENABLE_VULKAN) list(APPEND renderdoc_objects $) endif() +find_package(LLVM CONFIG) + +# on Android, pull in interceptor-lib only if we have LLVM available +if(ANDROID AND LLVM_FOUND) + message(STATUS "LLVM found - android hooking using interceptor-lib.") + add_subdirectory(3rdparty/interceptor-lib) + list(APPEND renderdoc_objects $) + link_directories(${LLVM_DIR}/../..) + set(RDOC_DEFINITIONS ${RDOC_DEFINITIONS} PRIVATE -DRENDERDOC_HAVE_INTERCEPTOR_LIB) + + foreach(lib ${interceptor_libs}) + list(APPEND RDOC_LIBRARIES PRIVATE -l${lib}) + endforeach() +endif() + +if(ANDROID AND NOT LLVM_FOUND) + message(STATUS "LLVM not found - android hooking will use sometimes less reliable PLT-interception method.") +endif() + # always pull in the amd folder add_subdirectory(driver/ihv/amd) list(APPEND renderdoc_objects $) diff --git a/renderdoc/driver/gl/gl_hooks_egl.cpp b/renderdoc/driver/gl/gl_hooks_egl.cpp index 6858c35be..afabbfc41 100644 --- a/renderdoc/driver/gl/gl_hooks_egl.cpp +++ b/renderdoc/driver/gl/gl_hooks_egl.cpp @@ -55,35 +55,7 @@ public: } static void libHooked(void *realLib); - bool CreateHooks(const char *libName) - { - if(!m_EnabledHooks) - return false; - - if(libName) - { - // register our hooked functions for PLT hooking on android - PosixHookFunctions(); - - // 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); - } - - bool success = SetupHooks(); - - if(!success) - return false; - - m_HasHooks = true; - - return true; - } + bool CreateHooks(const char *libName); void EnableHooks(const char *libName, bool enable) { m_EnabledHooks = enable; } void OptionsUpdated(const char *libName) {} @@ -432,13 +404,45 @@ void EGLHook::libHooked(void *realLib) libGLdlsymHandle = realLib; eglhooks.CreateHooks(NULL); eglhooks.GetDriver()->SetDriverType(RDCDriver::OpenGLES); +} - PosixHookFunction("eglCreateContext", (void *)&eglCreateContext); - PosixHookFunction("eglGetDisplay", (void *)&eglGetDisplay); - PosixHookFunction("eglDestroyContext", (void *)&eglDestroyContext); - PosixHookFunction("eglMakeCurrent", (void *)&eglMakeCurrent); - PosixHookFunction("eglSwapBuffers", (void *)&eglSwapBuffers); - PosixHookFunction("eglGetProcAddress", (void *)&eglGetProcAddress); +bool EGLHook::CreateHooks(const char *libName) +{ + if(!m_EnabledHooks) + return false; + + if(libName) + { + // register our hooked functions for PLT hooking on android + PosixHookFunctions(); + + PosixHookFunction("eglCreateContext", (void *)&eglCreateContext); + PosixHookFunction("eglGetDisplay", (void *)&eglGetDisplay); + PosixHookFunction("eglDestroyContext", (void *)&eglDestroyContext); + PosixHookFunction("eglMakeCurrent", (void *)&eglMakeCurrent); + PosixHookFunction("eglSwapBuffers", (void *)&eglSwapBuffers); + 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); + + return true; + } + + bool success = SetupHooks(); + + if(!success) + return false; + + m_HasHooks = true; + + return true; } bool EGLHook::PopulateHooks() @@ -446,7 +450,14 @@ bool EGLHook::PopulateHooks() SetupHooks(); // dlsym can return GL symbols during a GLES context - return SharedPopulateHooks(false, [](const char *funcName) { + bool dlsymFirst = false; + +// however on android we want to use it to look up our trampoline map +#if ENABLED(RDOC_ANDROID) + dlsymFirst = true; +#endif + + return 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; diff --git a/renderdoc/driver/gl/gl_hooks_linux_shared.cpp b/renderdoc/driver/gl/gl_hooks_linux_shared.cpp index 498f32ceb..62f37328c 100644 --- a/renderdoc/driver/gl/gl_hooks_linux_shared.cpp +++ b/renderdoc/driver/gl/gl_hooks_linux_shared.cpp @@ -110,7 +110,7 @@ Threading::CriticalSection &GetGLLock() echo ") \\"; echo -e " { \\"; - echo -e " SCOPED_LOCK(glLock); \\"; + echo -e " SCOPED_GLCALL(glLock, function); \\"; echo -e " gl_CurChunk = GLChunk::function; \\"; if [ $ALIAS -eq 1 ]; then echo -n " return m_GLDriver->realfunc("; @@ -127,7 +127,7 @@ Threading::CriticalSection &GetGLLock() echo ") \\"; echo -e " { \\"; - echo -e " SCOPED_LOCK(glLock); \\"; + echo -e " SCOPED_GLCALL(glLock, function); \\"; echo -e " gl_CurChunk = GLChunk::function; \\"; if [ $ALIAS -eq 1 ]; then echo -n " return m_GLDriver->realfunc("; @@ -153,6 +153,41 @@ Threading::CriticalSection &GetGLLock() #undef far #endif +#if ENABLED(RDOC_DEVEL) + +struct ScopedPrinter +{ + ScopedPrinter(const char *f) : func(f) + { + // RDCLOG("Entering %s", func); + depth++; + if(depth > 100) + RDCFATAL("Infinite recursion detected!"); + } + ~ScopedPrinter() + { + // RDCLOG("Exiting %s", func); + depth--; + } + const char *func = NULL; + static int depth; +}; + +int ScopedPrinter::depth = 0; + +// This checks that we're not infinite looping by calling our own hooks from ourselves. Mostly +// useful on android where you can only debug by printf and the stack dumps are often corrupted when +// the callstack overflows. +#define SCOPED_GLCALL(lock, funcname) \ + SCOPED_LOCK(lock); \ + ScopedPrinter CONCAT(scopedprint, __LINE__)(STRINGIZE(funcname)); + +#else + +#define SCOPED_GLCALL(lock, funcname) SCOPED_LOCK(lock); + +#endif + // the _renderdoc_hooked variants are to make sure we always have a function symbol // exported that we can return from glXGetProcAddress. If another library (or the app) // creates a symbol called 'glEnable' we'll return the address of that, and break @@ -163,13 +198,13 @@ Threading::CriticalSection &GetGLLock() typedef ret (*CONCAT(function, _hooktype))(); \ extern "C" __attribute__((visibility("default"))) ret function() \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(); \ } \ ret CONCAT(function, _renderdoc_hooked)() \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(); \ } @@ -178,13 +213,13 @@ Threading::CriticalSection &GetGLLock() typedef ret (*CONCAT(function, _hooktype))(t1); \ extern "C" __attribute__((visibility("default"))) ret function(t1 p1) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1); \ } \ ret CONCAT(function, _renderdoc_hooked)(t1 p1) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1); \ } @@ -193,13 +228,13 @@ Threading::CriticalSection &GetGLLock() typedef ret (*CONCAT(function, _hooktype))(t1, t2); \ extern "C" __attribute__((visibility("default"))) ret function(t1 p1, t2 p2) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2); \ } \ ret CONCAT(function, _renderdoc_hooked)(t1 p1, t2 p2) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2); \ } @@ -208,13 +243,13 @@ Threading::CriticalSection &GetGLLock() typedef ret (*CONCAT(function, _hooktype))(t1, t2, t3); \ extern "C" __attribute__((visibility("default"))) ret function(t1 p1, t2 p2, t3 p3) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3); \ } \ ret CONCAT(function, _renderdoc_hooked)(t1 p1, t2 p2, t3 p3) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3); \ } @@ -223,13 +258,13 @@ Threading::CriticalSection &GetGLLock() typedef ret (*CONCAT(function, _hooktype))(t1, t2, t3, t4); \ extern "C" __attribute__((visibility("default"))) ret function(t1 p1, t2 p2, t3 p3, t4 p4) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4); \ } \ ret CONCAT(function, _renderdoc_hooked)(t1 p1, t2 p2, t3 p3, t4 p4) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4); \ } @@ -238,13 +273,13 @@ Threading::CriticalSection &GetGLLock() typedef ret (*CONCAT(function, _hooktype))(t1, t2, t3, t4, t5); \ extern "C" __attribute__((visibility("default"))) ret function(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4, p5); \ } \ ret CONCAT(function, _renderdoc_hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4, p5); \ } @@ -254,13 +289,13 @@ Threading::CriticalSection &GetGLLock() extern "C" __attribute__((visibility("default"))) ret function(t1 p1, t2 p2, t3 p3, t4 p4, \ t5 p5, t6 p6) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4, p5, p6); \ } \ ret CONCAT(function, _renderdoc_hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4, p5, p6); \ } @@ -270,13 +305,13 @@ Threading::CriticalSection &GetGLLock() extern "C" __attribute__((visibility("default"))) ret function(t1 p1, t2 p2, t3 p3, t4 p4, \ t5 p5, t6 p6, t7 p7) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4, p5, p6, p7); \ } \ ret CONCAT(function, _renderdoc_hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4, p5, p6, p7); \ } @@ -286,13 +321,13 @@ Threading::CriticalSection &GetGLLock() extern "C" __attribute__((visibility("default"))) ret function(t1 p1, t2 p2, t3 p3, t4 p4, \ t5 p5, t6 p6, t7 p7, t8 p8) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4, p5, p6, p7, p8); \ } \ ret CONCAT(function, _renderdoc_hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4, p5, p6, p7, p8); \ } @@ -303,14 +338,14 @@ Threading::CriticalSection &GetGLLock() extern "C" __attribute__((visibility("default"))) ret function( \ t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9 p9) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4, p5, p6, p7, p8, p9); \ } \ ret CONCAT(function, _renderdoc_hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, \ t9 p9) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4, p5, p6, p7, p8, p9); \ } @@ -321,14 +356,14 @@ Threading::CriticalSection &GetGLLock() extern "C" __attribute__((visibility("default"))) ret function( \ t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9 p9, t10 p10) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \ } \ ret CONCAT(function, _renderdoc_hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, \ t9 p9, t10 p10) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \ } @@ -339,14 +374,14 @@ Threading::CriticalSection &GetGLLock() extern "C" __attribute__((visibility("default"))) ret function( \ t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9 p9, t10 p10, t11 p11) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \ } \ ret CONCAT(function, _renderdoc_hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, \ t9 p9, t10 p10, t11 p11) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \ } @@ -357,14 +392,14 @@ Threading::CriticalSection &GetGLLock() extern "C" __attribute__((visibility("default"))) 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) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \ } \ ret CONCAT(function, _renderdoc_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); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \ } @@ -377,14 +412,14 @@ Threading::CriticalSection &GetGLLock() 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) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \ } \ ret CONCAT(function, _renderdoc_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) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \ } @@ -397,14 +432,14 @@ Threading::CriticalSection &GetGLLock() 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); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \ } \ ret CONCAT(function, _renderdoc_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); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \ } @@ -417,7 +452,7 @@ Threading::CriticalSection &GetGLLock() 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); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); \ } \ @@ -425,7 +460,7 @@ Threading::CriticalSection &GetGLLock() t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, t14 p14, \ t15 p15) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); \ } @@ -439,7 +474,7 @@ Threading::CriticalSection &GetGLLock() 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); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, \ p16); \ @@ -448,7 +483,7 @@ Threading::CriticalSection &GetGLLock() t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, t14 p14, \ t15 p15, t16 p16) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, \ p16); \ @@ -463,7 +498,7 @@ Threading::CriticalSection &GetGLLock() 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); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, \ p16, p17); \ @@ -472,7 +507,7 @@ Threading::CriticalSection &GetGLLock() t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, t14 p14, \ t15 p15, t16 p16, t17 p17) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, \ p16, p17); \ @@ -482,13 +517,13 @@ Threading::CriticalSection &GetGLLock() typedef ret (*CONCAT(function, _hooktype))(); \ extern "C" __attribute__((visibility("default"))) ret function() \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(); \ } \ ret CONCAT(function, _renderdoc_hooked)() \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(); \ } @@ -497,13 +532,13 @@ Threading::CriticalSection &GetGLLock() typedef ret (*CONCAT(function, _hooktype))(t1); \ extern "C" __attribute__((visibility("default"))) ret function(t1 p1) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1); \ } \ ret CONCAT(function, _renderdoc_hooked)(t1 p1) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1); \ } @@ -512,13 +547,13 @@ Threading::CriticalSection &GetGLLock() typedef ret (*CONCAT(function, _hooktype))(t1, t2); \ extern "C" __attribute__((visibility("default"))) ret function(t1 p1, t2 p2) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2); \ } \ ret CONCAT(function, _renderdoc_hooked)(t1 p1, t2 p2) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2); \ } @@ -527,13 +562,13 @@ Threading::CriticalSection &GetGLLock() typedef ret (*CONCAT(function, _hooktype))(t1, t2, t3); \ extern "C" __attribute__((visibility("default"))) ret function(t1 p1, t2 p2, t3 p3) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3); \ } \ ret CONCAT(function, _renderdoc_hooked)(t1 p1, t2 p2, t3 p3) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3); \ } @@ -542,13 +577,13 @@ Threading::CriticalSection &GetGLLock() typedef ret (*CONCAT(function, _hooktype))(t1, t2, t3, t4); \ extern "C" __attribute__((visibility("default"))) ret function(t1 p1, t2 p2, t3 p3, t4 p4) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4); \ } \ ret CONCAT(function, _renderdoc_hooked)(t1 p1, t2 p2, t3 p3, t4 p4) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4); \ } @@ -557,13 +592,13 @@ Threading::CriticalSection &GetGLLock() typedef ret (*CONCAT(function, _hooktype))(t1, t2, t3, t4, t5); \ extern "C" __attribute__((visibility("default"))) ret function(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4, p5); \ } \ ret CONCAT(function, _renderdoc_hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4, p5); \ } @@ -573,13 +608,13 @@ Threading::CriticalSection &GetGLLock() extern "C" __attribute__((visibility("default"))) ret function(t1 p1, t2 p2, t3 p3, t4 p4, \ t5 p5, t6 p6) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4, p5, p6); \ } \ ret CONCAT(function, _renderdoc_hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4, p5, p6); \ } @@ -590,13 +625,13 @@ Threading::CriticalSection &GetGLLock() extern "C" __attribute__((visibility("default"))) ret function(t1 p1, t2 p2, t3 p3, t4 p4, \ t5 p5, t6 p6, t7 p7) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4, p5, p6, p7); \ } \ ret CONCAT(function, _renderdoc_hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4, p5, p6, p7); \ } @@ -607,13 +642,13 @@ Threading::CriticalSection &GetGLLock() extern "C" __attribute__((visibility("default"))) ret function(t1 p1, t2 p2, t3 p3, t4 p4, \ t5 p5, t6 p6, t7 p7, t8 p8) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4, p5, p6, p7, p8); \ } \ ret CONCAT(function, _renderdoc_hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4, p5, p6, p7, p8); \ } @@ -624,14 +659,14 @@ Threading::CriticalSection &GetGLLock() extern "C" __attribute__((visibility("default"))) ret function( \ t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9 p9) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9); \ } \ ret CONCAT(function, _renderdoc_hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, \ t9 p9) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9); \ } @@ -642,14 +677,14 @@ Threading::CriticalSection &GetGLLock() extern "C" __attribute__((visibility("default"))) ret function( \ t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9 p9, t10 p10) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \ } \ ret CONCAT(function, _renderdoc_hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, \ t9 p9, t10 p10) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \ } @@ -660,14 +695,14 @@ Threading::CriticalSection &GetGLLock() extern "C" __attribute__((visibility("default"))) ret function( \ t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, t9 p9, t10 p10, t11 p11) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \ } \ ret CONCAT(function, _renderdoc_hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7, t8 p8, \ t9 p9, t10 p10, t11 p11) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \ } @@ -678,14 +713,14 @@ Threading::CriticalSection &GetGLLock() extern "C" __attribute__((visibility("default"))) 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) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \ } \ ret CONCAT(function, _renderdoc_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); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \ } @@ -698,14 +733,14 @@ Threading::CriticalSection &GetGLLock() 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) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \ } \ ret CONCAT(function, _renderdoc_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) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \ } @@ -719,14 +754,14 @@ Threading::CriticalSection &GetGLLock() 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); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \ } \ ret CONCAT(function, _renderdoc_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); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); \ } @@ -740,7 +775,7 @@ Threading::CriticalSection &GetGLLock() 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); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); \ } \ @@ -748,7 +783,7 @@ Threading::CriticalSection &GetGLLock() t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, t14 p14, \ t15 p15) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); \ } @@ -762,7 +797,7 @@ Threading::CriticalSection &GetGLLock() 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); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, \ p16); \ @@ -771,7 +806,7 @@ Threading::CriticalSection &GetGLLock() t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, t14 p14, \ t15 p15, t16 p16) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, \ p16); \ @@ -786,7 +821,7 @@ Threading::CriticalSection &GetGLLock() 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); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, \ p16, p17); \ @@ -795,7 +830,7 @@ Threading::CriticalSection &GetGLLock() t9 p9, t10 p10, t11 p11, t12 p12, t13 p13, t14 p14, \ t15 p15, t16 p16, t17 p17) \ { \ - SCOPED_LOCK(glLock); \ + SCOPED_GLCALL(glLock, function); \ gl_CurChunk = GLChunk::function; \ return m_GLDriver->realfunc(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, \ p16, p17); \ @@ -1178,20 +1213,41 @@ void *SharedLookupFuncPtr(const char *func, void *realFunc) bool SharedPopulateHooks(bool dlsymFirst, void *(*lookupFunc)(const char *)) { #undef HookInit -#define HookInit(function) \ - if(GL.function == NULL) \ - { \ - PosixScopedSuppressHooking suppress; \ - if(dlsymFirst) \ - GL.function = (CONCAT(function, _hooktype))dlsym(libGLdlsymHandle, STRINGIZE(function)); \ - lookupFunc((const char *)STRINGIZE(function)); \ +#define HookInit(function) \ + if(GL.function == NULL) \ + { \ + PosixScopedSuppressHooking suppress; \ + if(dlsymFirst && GL.function == NULL) \ + { \ + GL.function = \ + (CONCAT(function, _hooktype))PosixGetFunction(libGLdlsymHandle, STRINGIZE(function)); \ + } \ + lookupFunc((const char *)STRINGIZE(function)); \ } // cheeky #undef HookExtension -#define HookExtension(funcPtrType, function) lookupFunc((const char *)STRINGIZE(function)) +#define HookExtension(funcPtrType, function) \ + if(GL.function == NULL) \ + { \ + PosixScopedSuppressHooking suppress; \ + if(dlsymFirst && GL.function == NULL) \ + { \ + GL.function = (funcPtrType)PosixGetFunction(libGLdlsymHandle, STRINGIZE(function)); \ + } \ + lookupFunc((const char *)STRINGIZE(function)); \ + } #undef HookExtensionAlias -#define HookExtensionAlias(funcPtrType, function, alias) lookupFunc((const char *)STRINGIZE(alias)) +#define HookExtensionAlias(funcPtrType, function, alias) \ + if(GL.function == NULL) \ + { \ + PosixScopedSuppressHooking suppress; \ + if(dlsymFirst && GL.function == NULL) \ + { \ + GL.function = (funcPtrType)PosixGetFunction(libGLdlsymHandle, STRINGIZE(alias)); \ + } \ + lookupFunc((const char *)STRINGIZE(alias)); \ + } DLLExportHooks(); HookCheckGLExtensions(); diff --git a/renderdoc/driver/gl/gl_hooks_vrapi.cpp b/renderdoc/driver/gl/gl_hooks_vrapi.cpp index 94e7d9ed5..5a2fde149 100644 --- a/renderdoc/driver/gl/gl_hooks_vrapi.cpp +++ b/renderdoc/driver/gl/gl_hooks_vrapi.cpp @@ -60,23 +60,9 @@ public: m_EnabledHooks = true; } ~VRAPIHook() {} - bool CreateHooks(const char *libName) - { - if(!m_EnabledHooks) - return false; + static void libHooked(void *realLib); - if(libName) - PosixHookLibrary(libName, &libHooked); - - bool success = SetupHooks(); - - if(!success) - return false; - - m_HasHooks = true; - - return true; - } + bool CreateHooks(const char *libName); void EnableHooks(const char *libName, bool enable) { m_EnabledHooks = enable; } void OptionsUpdated(const char *libName) {} @@ -86,7 +72,6 @@ public: SetupHooks(); } - static void libHooked(void *realLib) { libvrapi_symHandle = realLib; } //--------------------------------------------------------------------------------------------------------- PFN_vrapi_CreateTextureSwapChain2 vrapi_CreateTextureSwapChain2_real; PFN_vrapi_CreateTextureSwapChain vrapi_CreateTextureSwapChain_real; @@ -103,24 +88,24 @@ public: bool SetupHooks() { if(vrapi_CreateTextureSwapChain2_real == NULL) - vrapi_CreateTextureSwapChain2_real = (PFN_vrapi_CreateTextureSwapChain2)dlsym( + vrapi_CreateTextureSwapChain2_real = (PFN_vrapi_CreateTextureSwapChain2)PosixGetFunction( libvrapi_symHandle, "vrapi_CreateTextureSwapChain2"); if(vrapi_CreateTextureSwapChain_real == NULL) - vrapi_CreateTextureSwapChain_real = (PFN_vrapi_CreateTextureSwapChain)dlsym( + vrapi_CreateTextureSwapChain_real = (PFN_vrapi_CreateTextureSwapChain)PosixGetFunction( libvrapi_symHandle, "vrapi_CreateTextureSwapChain"); if(vrapi_SubmitFrame_real == NULL) vrapi_SubmitFrame_real = - (PFN_vrapi_SubmitFrame)dlsym(libvrapi_symHandle, "vrapi_SubmitFrame"); + (PFN_vrapi_SubmitFrame)PosixGetFunction(libvrapi_symHandle, "vrapi_SubmitFrame"); if(vrapi_GetTextureSwapChainLength_real == NULL) - vrapi_GetTextureSwapChainLength_real = (PFN_vrapi_GetTextureSwapChainLength)dlsym( + vrapi_GetTextureSwapChainLength_real = (PFN_vrapi_GetTextureSwapChainLength)PosixGetFunction( libvrapi_symHandle, "vrapi_GetTextureSwapChainLength"); if(vrapi_GetTextureSwapChainHandle_real == NULL) - vrapi_GetTextureSwapChainHandle_real = (PFN_vrapi_GetTextureSwapChainHandle)dlsym( + vrapi_GetTextureSwapChainHandle_real = (PFN_vrapi_GetTextureSwapChainHandle)PosixGetFunction( libvrapi_symHandle, "vrapi_GetTextureSwapChainHandle"); if(vrapi_GetSystemPropertyInt_real == NULL) - vrapi_GetSystemPropertyInt_real = - (PFN_vrapi_GetSystemPropertyInt)dlsym(libvrapi_symHandle, "vrapi_GetSystemPropertyInt"); + vrapi_GetSystemPropertyInt_real = (PFN_vrapi_GetSystemPropertyInt)PosixGetFunction( + libvrapi_symHandle, "vrapi_GetSystemPropertyInt"); return vrapi_SubmitFrame_real != NULL; } @@ -264,4 +249,35 @@ __attribute__((visibility("default"))) void vrapi_SubmitFrame(ovrMobile *ovr, vrapi_hooks.vrapi_SubmitFrame_real(ovr, parms); } +} // extern "C" + +void VRAPIHook::libHooked(void *realLib) +{ + libvrapi_symHandle = realLib; + vrapi_hooks.CreateHooks(NULL); +} + +bool VRAPIHook::CreateHooks(const char *libName) +{ + if(!m_EnabledHooks) + return false; + + if(libName) + { + PosixHookFunction("vrapi_CreateTextureSwapChain2", (void *)&vrapi_CreateTextureSwapChain2); + PosixHookFunction("vrapi_CreateTextureSwapChain", (void *)&vrapi_CreateTextureSwapChain); + PosixHookFunction("vrapi_SubmitFrame", (void *)&vrapi_SubmitFrame); + + PosixHookLibrary(libName, &libHooked); + return true; + } + + bool success = SetupHooks(); + + if(!success) + return false; + + m_HasHooks = true; + + return true; } \ No newline at end of file diff --git a/renderdoc/driver/gl/gl_library_egl.cpp b/renderdoc/driver/gl/gl_library_egl.cpp index 729631f08..f6910fc92 100644 --- a/renderdoc/driver/gl/gl_library_egl.cpp +++ b/renderdoc/driver/gl/gl_library_egl.cpp @@ -24,6 +24,7 @@ #include "gl_library_egl.h" #include +#include "os/posix/posix_hook.h" bool EGLPointers::LoadSymbolsFrom(void *lib_handle) { @@ -33,16 +34,18 @@ bool EGLPointers::LoadSymbolsFrom(void *lib_handle) return m_initialized; } + RDCDEBUG("Initialising EGL function pointers"); + bool symbols_ok = true; -#define LOAD_SYM(SYMBOL_NAME) \ - do \ - { \ - this->SYMBOL_NAME = (PFN_egl##SYMBOL_NAME)dlsym(lib_handle, "egl" #SYMBOL_NAME); \ - if(this->SYMBOL_NAME == NULL) \ - { \ - symbols_ok = false; \ - RDCWARN("Unable to load symbol: %s", #SYMBOL_NAME); \ - } \ +#define LOAD_SYM(SYMBOL_NAME) \ + do \ + { \ + this->SYMBOL_NAME = (PFN_egl##SYMBOL_NAME)PosixGetFunction(lib_handle, "egl" #SYMBOL_NAME); \ + if(this->SYMBOL_NAME == NULL) \ + { \ + symbols_ok = false; \ + RDCWARN("Unable to load symbol: %s", #SYMBOL_NAME); \ + } \ } while(0) EGL_SYMBOLS(LOAD_SYM) diff --git a/renderdoc/os/posix/android/android_hook.cpp b/renderdoc/os/posix/android/android_hook.cpp index ad3cd9591..d2ae139cf 100644 --- a/renderdoc/os/posix/android/android_hook.cpp +++ b/renderdoc/os/posix/android/android_hook.cpp @@ -96,6 +96,37 @@ public: libhooks.insert(name); } + void AddHookCallback(const std::string &name, dlopenCallback hook) + { + SCOPED_LOCK(lock); + hookcallbacks[name] = hook; + } + + std::map GetFunctionHooks() + { + SCOPED_LOCK(lock); + return funchooks; + } + + void ClearHooks() + { + SCOPED_LOCK(lock); + libhooks.clear(); + funchooks.clear(); + } + + std::set GetLibHooks() + { + SCOPED_LOCK(lock); + return libhooks; + } + + std::map GetHookCallbacks() + { + SCOPED_LOCK(lock); + return hookcallbacks; + } + void *GetFunctionHook(const std::string &name) { SCOPED_LOCK(lock); @@ -165,6 +196,18 @@ 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; @@ -172,6 +215,9 @@ private: std::map funchooks; std::set libhooks; + std::map hookcallbacks; + std::map trampolines; + Threading::CriticalSection lock; }; @@ -191,9 +237,36 @@ void PosixHookLibrary(const char *name, dlopenCallback cb) GetHookInfo().AddLibHook(name); if(cb) - cb(dlopen(name, RTLD_NOW)); + { + 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)) + return dlopen(RENDERDOC_ANDROID_LIBRARY, flag); + + return NULL; +} + +// we need this on both paths since interceptor-lib is unable to hook dlopen in libvulkan.so static int dl_iterate_callback(struct dl_phdr_info *info, size_t size, void *data) { if(info->dlpi_name == NULL) @@ -377,60 +450,21 @@ static int dl_iterate_callback(struct dl_phdr_info *info, size_t size, void *dat return 0; } -extern "C" __attribute__((visibility("default"))) void *hooked_dlopen(const char *filename, int flag); -extern "C" __attribute__((visibility("default"))) void *hooked_dlsym(void *handle, - const char *symbol); -extern "C" __attribute__((visibility("default"))) void *hooked_android_dlopen_ext( - const char *__filename, int __flags, const android_dlextinfo *__info); - -// 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); - -pfn__loader_dlopen loader_dlopen = NULL; -uint64_t suppressTLS = 0; - -void PosixHookApply() -{ - RDCLOG("Applying hooks"); - - suppressTLS = Threading::AllocateTLSSlot(); - - // blacklist hooking certain system libraries or ourselves - GetHookInfo().SetHooked(RENDERDOC_ANDROID_LIBRARY); - GetHookInfo().SetHooked("libc.so"); - GetHookInfo().SetHooked("libvndksupport.so"); - - GetHookInfo().AddLibHook(RENDERDOC_ANDROID_LIBRARY); - - loader_dlopen = (pfn__loader_dlopen)dlsym(RTLD_NEXT, "__loader_dlopen"); - - if(loader_dlopen) - { - PosixHookFunction("dlopen", (void *)&hooked_dlopen); - } - else - { - RDCWARN("Couldn't find __loader_dlopen, falling back to slow path for dlopen hooking"); - PosixHookFunction("dlsym", (void *)&hooked_dlsym); - } - - PosixHookFunction("android_dlopen_ext", (void *)&hooked_android_dlopen_ext); - - dl_iterate_phdr(dl_iterate_callback, NULL); -} - void PosixHookReapply() { dl_iterate_phdr(dl_iterate_callback, NULL); } -void *intercept_dlopen(const char *filename, int flag) -{ - if(GetHookInfo().IsLibHook(filename)) - return dlopen(RENDERDOC_ANDROID_LIBRARY, flag); +// 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); - return NULL; -} +typedef void *(*pfnandroid_dlopen_ext)(const char *__filename, int __flags, + const android_dlextinfo *__info); + +pfnandroid_dlopen_ext real_android_dlopen_ext = NULL; + +pfn__loader_dlopen loader_dlopen = NULL; +uint64_t suppressTLS = 0; void process_dlopen(const char *filename, int flag) { @@ -478,7 +512,11 @@ extern "C" __attribute__((visibility("default"))) void *hooked_android_dlopen_ex if(ret) return ret; - ret = android_dlopen_ext(__filename, __flags, __info); + // otherwise return the 'real' result. + if(real_android_dlopen_ext == NULL) + ret = real_android_dlopen_ext(__filename, __flags, __info); + else + ret = android_dlopen_ext(__filename, __flags, __info); HOOK_DEBUG_PRINT("Got %p", ret); if(__filename && ret) @@ -539,4 +577,154 @@ extern "C" __attribute__((visibility("default"))) void *hooked_dlsym(void *handl dladdr(ret, &info); HOOK_DEBUG_PRINT("real ret is %p in %s", ret, info.dli_fname); return ret; -} \ No newline at end of file +} + +static void PosixHookApplyCommon() +{ + suppressTLS = Threading::AllocateTLSSlot(); + + // blacklist hooking certain system libraries or ourselves + GetHookInfo().SetHooked(RENDERDOC_ANDROID_LIBRARY); + GetHookInfo().SetHooked("libc.so"); + GetHookInfo().SetHooked("libvndksupport.so"); + + GetHookInfo().AddLibHook(RENDERDOC_ANDROID_LIBRARY); + + real_android_dlopen_ext = &android_dlopen_ext; + + loader_dlopen = (pfn__loader_dlopen)dlsym(RTLD_NEXT, "__loader_dlopen"); + + if(loader_dlopen) + { + PosixHookFunction("dlopen", (void *)&hooked_dlopen); + } + else + { + RDCWARN("Couldn't find __loader_dlopen, falling back to slow path for dlopen hooking"); + PosixHookFunction("dlsym", (void *)&hooked_dlsym); + } + + PosixHookFunction("android_dlopen_ext", (void *)&hooked_android_dlopen_ext); +} + +#if defined(RENDERDOC_HAVE_INTERCEPTOR_LIB) + +void intercept_error(void *, const char *error_msg) +{ + RDCERR("intercept_error: %s", error_msg); +} + +#include "3rdparty/interceptor-lib/include/interceptor.h" + +void PosixHookApply() +{ + RDCLOG("Applying hooks with interceptor-lib"); + +// see below - Huawei workaround +#if defined(__LP64__) + PosixHookLibrary("/system/lib64/libhwgl.so", NULL); +#else + PosixHookLibrary("/system/lib/libhwgl.so", NULL); +#endif + + std::set libs = GetHookInfo().GetLibHooks(); + std::map funchooks = GetHookInfo().GetFunctionHooks(); + + // we just leak this + void *intercept = InitializeInterceptor(); + + for(const std::string &lib : libs) + { + void *handle = dlopen(lib.c_str(), RTLD_NOW); + + bool huawei = lib.find("libhwgl.so") != std::string::npos; + + if(!handle) + { + HOOK_DEBUG_PRINT("Didn't get handle for %s", lib.c_str()); + continue; + } + + HOOK_DEBUG_PRINT("Hooking %s = %p", lib.c_str(), handle); + + for(const std::pair &hook : funchooks) + { + void *oldfunc = dlsym(handle, hook.first.c_str()); + + // UNTESTED workaround taken directly from GAPID, in installer.cpp. Quoted comment: + /* + // Huawei implements all functions in this library with prefix, + // all GL functions in libGLES*.so are just trampolines to his. + // However, we do not support trampoline interception for now, + // so try to intercept the internal implementation instead. + */ + if(huawei && oldfunc == NULL) + oldfunc = dlsym(handle, ("hw_" + hook.first).c_str()); + + if(GetHookInfo().IsHooked(oldfunc)) + continue; + + if(!oldfunc) + { + HOOK_DEBUG_PRINT("%s didn't have %s", lib.c_str(), hook.first.c_str()); + continue; + } + + HOOK_DEBUG_PRINT("Hooking %s::%s = %p with %p", lib.c_str(), hook.first.c_str(), oldfunc, + hook.second); + + void *trampoline = NULL; + + bool success = + InterceptFunction(intercept, oldfunc, hook.second, &trampoline, &intercept_error); + + if(success) + HOOK_DEBUG_PRINT("Hooked successfully, trampoline is %p", trampoline); + else + HOOK_DEBUG_PRINT("Failed to 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. + // Unfortunately, interceptor-lib can't hook this function so we need to set up the PLT hooking. + // This is just a minimal setup to intercept that one function. + GetHookInfo().ClearHooks(); + + // this already hooks dlopen (if possible) and android_dlopen_ext, which is enough + PosixHookApplyCommon(); + + PosixHookReapply(); +} + +#else + +void PosixHookApply() +{ + 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 diff --git a/renderdoc/os/posix/apple/apple_hook.cpp b/renderdoc/os/posix/apple/apple_hook.cpp index 0391a269e..4ef1dcf3f 100644 --- a/renderdoc/os/posix/apple/apple_hook.cpp +++ b/renderdoc/os/posix/apple/apple_hook.cpp @@ -60,3 +60,8 @@ 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 34979a403..627d70405 100644 --- a/renderdoc/os/posix/linux/linux_hook.cpp +++ b/renderdoc/os/posix/linux/linux_hook.cpp @@ -140,3 +140,8 @@ 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 index bebbb0a1d..8fc7e6034 100644 --- a/renderdoc/os/posix/posix_hook.h +++ b/renderdoc/os/posix/posix_hook.h @@ -34,6 +34,8 @@ 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