Handle dlsym(RTLD_NEXT) without loading libGL. Closes #1463

* This also applies to libEGL - if a user calls dlsym(RTLD_NEXT) to fetch a
  libGL symbol without being linked against libGL nor ever dlopen'ing it, it
  will retrieve our hook but libGL will still not be loaded meaning we can't
  call onwards. If we get to the last second where our hook has been called but
  the real library is not loaded we need to load it manually.
This commit is contained in:
baldurk
2019-07-22 14:51:27 +01:00
parent 02e1a7a62b
commit 66869e8c69
2 changed files with 90 additions and 0 deletions
+51
View File
@@ -108,6 +108,29 @@ public:
} eglhook;
// On linux if a user doesn't link to libEGL or try to dlopen it, but just calls dlsym with
// RTLD_NEXT it might successfully one of our functions without anything ever loading libEGL. Then
// our attempts to call onwards will fail. When any of our functions are called we check to see if
// DEFAULT_HANDLE is RTLD_NEXT and if so we manually load the library. This will trigger our hook
// callback and we'll get a specific library handle.
//
// On other platforms this is not needed because we know the real library will be loaded before any
// of our hooks can be called
static void EnsureRealLibraryLoaded()
{
#if ENABLED(RDOC_LINUX)
if(eglhook.handle == DEFAULT_HANDLE)
{
RDCLOG("Loading libEGL at the last second");
void *handle = Process::LoadModule("libEGL.so");
if(!handle)
handle = Process::LoadModule("libEGL.so.1");
}
#endif
}
HOOK_EXPORT EGLDisplay EGLAPIENTRY eglGetDisplay_renderdoc_hooked(EGLNativeDisplayType display)
{
if(RenderDoc::Inst().IsReplayApp())
@@ -118,6 +141,8 @@ HOOK_EXPORT EGLDisplay EGLAPIENTRY eglGetDisplay_renderdoc_hooked(EGLNativeDispl
return EGL.GetDisplay(display);
}
EnsureRealLibraryLoaded();
#if ENABLED(RDOC_LINUX)
Keyboard::CloneDisplay(display);
#endif
@@ -135,6 +160,8 @@ HOOK_EXPORT EGLBoolean EGLAPIENTRY eglBindAPI_renderdoc_hooked(EGLenum api)
return EGL.BindAPI(api);
}
EnsureRealLibraryLoaded();
EGLBoolean ret = EGL.BindAPI(api);
if(ret)
@@ -156,6 +183,8 @@ HOOK_EXPORT EGLContext EGLAPIENTRY eglCreateContext_renderdoc_hooked(EGLDisplay
return EGL.CreateContext(display, config, shareContext, attribList);
}
EnsureRealLibraryLoaded();
LibraryHooks::Refresh();
std::vector<EGLint> attribs;
@@ -274,6 +303,8 @@ HOOK_EXPORT EGLBoolean EGLAPIENTRY eglDestroyContext_renderdoc_hooked(EGLDisplay
return EGL.DestroyContext(dpy, ctx);
}
EnsureRealLibraryLoaded();
eglhook.driver.SetDriverType(eglhook.activeAPI);
{
SCOPED_LOCK(glLock);
@@ -297,6 +328,8 @@ HOOK_EXPORT EGLSurface EGLAPIENTRY eglCreateWindowSurface_renderdoc_hooked(EGLDi
return EGL.CreateWindowSurface(dpy, config, win, attrib_list);
}
EnsureRealLibraryLoaded();
EGLSurface ret = EGL.CreateWindowSurface(dpy, config, win, attrib_list);
if(ret)
@@ -321,6 +354,8 @@ HOOK_EXPORT EGLBoolean EGLAPIENTRY eglMakeCurrent_renderdoc_hooked(EGLDisplay di
return EGL.MakeCurrent(display, draw, read, ctx);
}
EnsureRealLibraryLoaded();
EGLBoolean ret = EGL.MakeCurrent(display, draw, read, ctx);
if(ret)
@@ -377,6 +412,8 @@ HOOK_EXPORT EGLBoolean EGLAPIENTRY eglSwapBuffers_renderdoc_hooked(EGLDisplay dp
return EGL.SwapBuffers(dpy, surface);
}
EnsureRealLibraryLoaded();
SCOPED_LOCK(glLock);
eglhook.driver.SetDriverType(eglhook.activeAPI);
@@ -413,6 +450,8 @@ HOOK_EXPORT EGLBoolean EGLAPIENTRY eglPostSubBufferNV_renderdoc_hooked(EGLDispla
return EGL.PostSubBufferNV(dpy, surface, x, y, width, height);
}
EnsureRealLibraryLoaded();
SCOPED_LOCK(glLock);
eglhook.driver.SetDriverType(eglhook.activeAPI);
@@ -440,6 +479,8 @@ HOOK_EXPORT EGLBoolean EGLAPIENTRY eglSwapBuffersWithDamageEXT_renderdoc_hooked(
return EGL.SwapBuffersWithDamageEXT(dpy, surface, rects, n_rects);
}
EnsureRealLibraryLoaded();
SCOPED_LOCK(glLock);
eglhook.driver.SetDriverType(eglhook.activeAPI);
@@ -467,6 +508,8 @@ HOOK_EXPORT EGLBoolean EGLAPIENTRY eglSwapBuffersWithDamageKHR_renderdoc_hooked(
return EGL.SwapBuffersWithDamageKHR(dpy, surface, rects, n_rects);
}
EnsureRealLibraryLoaded();
SCOPED_LOCK(glLock);
eglhook.driver.SetDriverType(eglhook.activeAPI);
@@ -492,6 +535,8 @@ eglGetProcAddress_renderdoc_hooked(const char *func)
return EGL.GetProcAddress(func);
}
EnsureRealLibraryLoaded();
__eglMustCastToProperFunctionPointerType realFunc = NULL;
{
ScopedSuppressHooking suppress;
@@ -593,6 +638,7 @@ HOOK_EXPORT __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddre
typedef ret (*CONCAT(function, _hooktype))(); \
HOOK_EXPORT ret EGLAPIENTRY function() \
{ \
EnsureRealLibraryLoaded(); \
CONCAT(function, _hooktype) \
real = (CONCAT(function, _hooktype))Process::GetFunctionAddress(eglhook.handle, \
STRINGIZE(function)); \
@@ -603,6 +649,7 @@ HOOK_EXPORT __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddre
typedef ret (*CONCAT(function, _hooktype))(t1); \
HOOK_EXPORT ret EGLAPIENTRY function(t1 p1) \
{ \
EnsureRealLibraryLoaded(); \
CONCAT(function, _hooktype) \
real = (CONCAT(function, _hooktype))Process::GetFunctionAddress(eglhook.handle, \
STRINGIZE(function)); \
@@ -613,6 +660,7 @@ HOOK_EXPORT __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddre
typedef ret (*CONCAT(function, _hooktype))(t1, t2); \
HOOK_EXPORT ret EGLAPIENTRY function(t1 p1, t2 p2) \
{ \
EnsureRealLibraryLoaded(); \
CONCAT(function, _hooktype) \
real = (CONCAT(function, _hooktype))Process::GetFunctionAddress(eglhook.handle, \
STRINGIZE(function)); \
@@ -623,6 +671,7 @@ HOOK_EXPORT __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddre
typedef ret (*CONCAT(function, _hooktype))(t1, t2, t3); \
HOOK_EXPORT ret EGLAPIENTRY function(t1 p1, t2 p2, t3 p3) \
{ \
EnsureRealLibraryLoaded(); \
CONCAT(function, _hooktype) \
real = (CONCAT(function, _hooktype))Process::GetFunctionAddress(eglhook.handle, \
STRINGIZE(function)); \
@@ -633,6 +682,7 @@ HOOK_EXPORT __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddre
typedef ret (*CONCAT(function, _hooktype))(t1, t2, t3, t4); \
HOOK_EXPORT ret EGLAPIENTRY function(t1 p1, t2 p2, t3 p3, t4 p4) \
{ \
EnsureRealLibraryLoaded(); \
CONCAT(function, _hooktype) \
real = (CONCAT(function, _hooktype))Process::GetFunctionAddress(eglhook.handle, \
STRINGIZE(function)); \
@@ -643,6 +693,7 @@ HOOK_EXPORT __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddre
typedef ret (*CONCAT(function, _hooktype))(t1, t2, t3, t4, t5); \
HOOK_EXPORT ret EGLAPIENTRY function(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5) \
{ \
EnsureRealLibraryLoaded(); \
CONCAT(function, _hooktype) \
real = (CONCAT(function, _hooktype))Process::GetFunctionAddress(eglhook.handle, \
STRINGIZE(function)); \
+39
View File
@@ -58,6 +58,25 @@ public:
std::set<GLXContext> contexts;
} glxhook;
// On linux if a user doesn't link to libGL/libGLX or try to dlopen it, but just calls dlsym with
// RTLD_NEXT it might successfully one of our functions without anything ever loading libEGL. Then
// our attempts to call onwards will fail. When any of our functions are called we check to see if
// DEFAULT_HANDLE is RTLD_NEXT and if so we manually load the library. This will trigger our hook
// callback and we'll get a specific library handle.
static void EnsureRealLibraryLoaded()
{
if(glxhook.handle == RTLD_NEXT)
{
RDCLOG("Loading libGL at the last second");
void *handle = Process::LoadModule("libGL.so.1");
if(!handle)
handle = Process::LoadModule("libGL.so");
if(!handle)
handle = Process::LoadModule("libGLX.so.0");
}
}
HOOK_EXPORT GLXContext glXCreateContext_renderdoc_hooked(Display *dpy, XVisualInfo *vis,
GLXContext shareList, Bool direct)
{
@@ -69,6 +88,8 @@ HOOK_EXPORT GLXContext glXCreateContext_renderdoc_hooked(Display *dpy, XVisualIn
return GLX.glXCreateContext(dpy, vis, shareList, direct);
}
EnsureRealLibraryLoaded();
GLXContext ret = GLX.glXCreateContext(dpy, vis, shareList, direct);
// don't continue if context creation failed
@@ -121,6 +142,8 @@ HOOK_EXPORT void glXDestroyContext_renderdoc_hooked(Display *dpy, GLXContext ctx
return GLX.glXDestroyContext(dpy, ctx);
}
EnsureRealLibraryLoaded();
{
SCOPED_LOCK(glLock);
glxhook.driver.DeleteContext(ctx);
@@ -142,6 +165,8 @@ HOOK_EXPORT GLXContext glXCreateContextAttribsARB_renderdoc_hooked(Display *dpy,
return GLX.glXCreateContextAttribsARB(dpy, config, shareList, direct, attribList);
}
EnsureRealLibraryLoaded();
int defaultAttribList[] = {0};
const int *attribs = attribList ? attribList : defaultAttribList;
@@ -264,6 +289,8 @@ HOOK_EXPORT Bool glXMakeCurrent_renderdoc_hooked(Display *dpy, GLXDrawable drawa
return GLX.glXMakeCurrent(dpy, drawable, ctx);
}
EnsureRealLibraryLoaded();
Bool ret = GLX.glXMakeCurrent(dpy, drawable, ctx);
if(ret)
@@ -332,6 +359,8 @@ HOOK_EXPORT Bool glXMakeContextCurrent_renderdoc_hooked(Display *dpy, GLXDrawabl
return GLX.glXMakeContextCurrent(dpy, draw, read, ctx);
}
EnsureRealLibraryLoaded();
Bool ret = GLX.glXMakeContextCurrent(dpy, draw, read, ctx);
if(ret)
@@ -398,6 +427,8 @@ HOOK_EXPORT void glXSwapBuffers_renderdoc_hooked(Display *dpy, GLXDrawable drawa
return GLX.glXSwapBuffers(dpy, drawable);
}
EnsureRealLibraryLoaded();
SCOPED_LOCK(glLock);
{
@@ -425,6 +456,8 @@ HOOK_EXPORT __GLXextFuncPtr glXGetProcAddress_renderdoc_hooked(const GLubyte *f)
return GLX.glXGetProcAddress(f);
}
EnsureRealLibraryLoaded();
const char *func = (const char *)f;
__GLXextFuncPtr realFunc = NULL;
@@ -527,6 +560,7 @@ HOOK_EXPORT __GLXextFuncPtr glXGetProcAddressARB(const GLubyte *f)
typedef ret (*CONCAT(function, _hooktype))(); \
extern "C" __attribute__((visibility("default"))) ret function() \
{ \
EnsureRealLibraryLoaded(); \
CONCAT(function, _hooktype) \
real = (CONCAT(function, _hooktype))dlsym(glxhook.handle, STRINGIZE(function)); \
return real(); \
@@ -536,6 +570,7 @@ HOOK_EXPORT __GLXextFuncPtr glXGetProcAddressARB(const GLubyte *f)
typedef ret (*CONCAT(function, _hooktype))(t1); \
extern "C" __attribute__((visibility("default"))) ret function(t1 p1) \
{ \
EnsureRealLibraryLoaded(); \
CONCAT(function, _hooktype) \
real = (CONCAT(function, _hooktype))dlsym(glxhook.handle, STRINGIZE(function)); \
return real(p1); \
@@ -545,6 +580,7 @@ HOOK_EXPORT __GLXextFuncPtr glXGetProcAddressARB(const GLubyte *f)
typedef ret (*CONCAT(function, _hooktype))(t1, t2); \
extern "C" __attribute__((visibility("default"))) ret function(t1 p1, t2 p2) \
{ \
EnsureRealLibraryLoaded(); \
CONCAT(function, _hooktype) \
real = (CONCAT(function, _hooktype))dlsym(glxhook.handle, STRINGIZE(function)); \
return real(p1, p2); \
@@ -554,6 +590,7 @@ HOOK_EXPORT __GLXextFuncPtr glXGetProcAddressARB(const GLubyte *f)
typedef ret (*CONCAT(function, _hooktype))(t1, t2, t3); \
extern "C" __attribute__((visibility("default"))) ret function(t1 p1, t2 p2, t3 p3) \
{ \
EnsureRealLibraryLoaded(); \
CONCAT(function, _hooktype) \
real = (CONCAT(function, _hooktype))dlsym(glxhook.handle, STRINGIZE(function)); \
return real(p1, p2, p3); \
@@ -563,6 +600,7 @@ HOOK_EXPORT __GLXextFuncPtr glXGetProcAddressARB(const GLubyte *f)
typedef ret (*CONCAT(function, _hooktype))(t1, t2, t3, t4); \
extern "C" __attribute__((visibility("default"))) ret function(t1 p1, t2 p2, t3 p3, t4 p4) \
{ \
EnsureRealLibraryLoaded(); \
CONCAT(function, _hooktype) \
real = (CONCAT(function, _hooktype))dlsym(glxhook.handle, STRINGIZE(function)); \
return real(p1, p2, p3, p4); \
@@ -572,6 +610,7 @@ HOOK_EXPORT __GLXextFuncPtr glXGetProcAddressARB(const GLubyte *f)
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) \
{ \
EnsureRealLibraryLoaded(); \
CONCAT(function, _hooktype) \
real = (CONCAT(function, _hooktype))dlsym(glxhook.handle, STRINGIZE(function)); \
return real(p1, p2, p3, p4, p5); \