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.
This commit is contained in:
baldurk
2018-01-31 18:24:14 +00:00
parent addc95d790
commit 4a6462b63b
9 changed files with 508 additions and 203 deletions
+19
View File
@@ -355,6 +355,25 @@ if(ENABLE_GL OR ENABLE_GLES OR ENABLE_VULKAN)
list(APPEND renderdoc_objects $<TARGET_OBJECTS:rdoc_spirv>)
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 $<TARGET_OBJECTS:interceptor_lib>)
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 $<TARGET_OBJECTS:rdoc_amd>)
+47 -36
View File
@@ -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;
+139 -83
View File
@@ -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();
+40 -24
View File
@@ -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;
}
+12 -9
View File
@@ -24,6 +24,7 @@
#include "gl_library_egl.h"
#include <dlfcn.h>
#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)
+239 -51
View File
@@ -96,6 +96,37 @@ public:
libhooks.insert(name);
}
void AddHookCallback(const std::string &name, dlopenCallback hook)
{
SCOPED_LOCK(lock);
hookcallbacks[name] = hook;
}
std::map<std::string, void *> GetFunctionHooks()
{
SCOPED_LOCK(lock);
return funchooks;
}
void ClearHooks()
{
SCOPED_LOCK(lock);
libhooks.clear();
funchooks.clear();
}
std::set<std::string> GetLibHooks()
{
SCOPED_LOCK(lock);
return libhooks;
}
std::map<std::string, dlopenCallback> 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<std::string> hooked_soname_already;
std::set<void *> hooked_handle_already;
@@ -172,6 +215,9 @@ private:
std::map<std::string, void *> funchooks;
std::set<std::string> libhooks;
std::map<std::string, dlopenCallback> hookcallbacks;
std::map<std::string, void *> 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;
}
}
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<std::string> libs = GetHookInfo().GetLibHooks();
std::map<std::string, void *> 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<std::string, void *> &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<std::string, dlopenCallback> callbacks = GetHookInfo().GetHookCallbacks();
for(const std::pair<std::string, dlopenCallback> &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<std::string, dlopenCallback> callbacks = GetHookInfo().GetHookCallbacks();
for(const std::pair<std::string, dlopenCallback> &cb : callbacks)
{
HOOK_DEBUG_PRINT("Calling complete callback for %s", cb.first.c_str());
cb.second(dlopen(cb.first.c_str(), RTLD_GLOBAL));
}
}
#endif
+5
View File
@@ -60,3 +60,8 @@ void PosixHookReapply()
void PosixHookFunction(char const *, void *)
{
}
void *PosixGetFunction(void *handle, const char *name)
{
return dlsym(handle, name);
}
+5
View File
@@ -140,3 +140,8 @@ void PosixHookReapply()
void PosixHookFunction(char const *, void *)
{
}
void *PosixGetFunction(void *handle, const char *name)
{
return dlsym(handle, name);
}
+2
View File
@@ -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