mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-28 04:41:07 +00:00
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:
@@ -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)); \
|
||||
|
||||
@@ -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); \
|
||||
|
||||
Reference in New Issue
Block a user