From 081d28357581ce0e9cb6dc852f05a892507360be Mon Sep 17 00:00:00 2001 From: baldurk Date: Tue, 25 Sep 2018 11:01:25 +0100 Subject: [PATCH] On linux don't take address of glX/egl symbols * The application could export a public glXSwapBuffers symbol that is its own function pointer, and &glXSwapBuffers looking up that symbol will get it, instead of our entry point. Follow the GL function scheme of still exporting a small stub with the proper name, but forwarding to an internal suffixed symbol that won't be overloaded. --- renderdoc/driver/gl/cgl_hooks.cpp | 7 +- renderdoc/driver/gl/egl_hooks.cpp | 106 +++++++++++++++++++++------ renderdoc/driver/gl/glx_hooks.cpp | 116 +++++++++++++++++++++++------- 3 files changed, 175 insertions(+), 54 deletions(-) diff --git a/renderdoc/driver/gl/cgl_hooks.cpp b/renderdoc/driver/gl/cgl_hooks.cpp index c7b7aba07..c8781644c 100644 --- a/renderdoc/driver/gl/cgl_hooks.cpp +++ b/renderdoc/driver/gl/cgl_hooks.cpp @@ -185,10 +185,9 @@ void CGLHook::RegisterHooks() LibraryHooks::RegisterLibraryHook("libGL.dylib", NULL); // register CGL hooks -#define CGL_REGISTER(func) \ - LibraryHooks::RegisterFunctionHook("OpenGL", \ - FunctionHook(STRINGIZE(func), (void **)&CGL.func, \ - (void *)&GL_EXPORT_NAME(CGLFlushDrawable))); +#define CGL_REGISTER(func) \ + LibraryHooks::RegisterFunctionHook( \ + "OpenGL", FunctionHook(STRINGIZE(func), (void **)&CGL.func, (void *)&GL_EXPORT_NAME(func))); CGL_HOOKED_SYMBOLS(CGL_REGISTER) #undef CGL_REGISTER } diff --git a/renderdoc/driver/gl/egl_hooks.cpp b/renderdoc/driver/gl/egl_hooks.cpp index ffd467285..93a3640c0 100644 --- a/renderdoc/driver/gl/egl_hooks.cpp +++ b/renderdoc/driver/gl/egl_hooks.cpp @@ -74,7 +74,7 @@ public: } eglhook; -HOOK_EXPORT EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display) +HOOK_EXPORT EGLDisplay EGLAPIENTRY eglGetDisplay_renderdoc_hooked(EGLNativeDisplayType display) { if(RenderDoc::Inst().IsReplayApp()) { @@ -91,8 +91,10 @@ HOOK_EXPORT EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display) return EGL.GetDisplay(display); } -HOOK_EXPORT EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay display, EGLConfig config, - EGLContext shareContext, EGLint const *attribList) +HOOK_EXPORT EGLContext EGLAPIENTRY eglCreateContext_renderdoc_hooked(EGLDisplay display, + EGLConfig config, + EGLContext shareContext, + EGLint const *attribList) { if(RenderDoc::Inst().IsReplayApp()) { @@ -200,7 +202,7 @@ HOOK_EXPORT EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay display, EGLConfi return ret; } -HOOK_EXPORT EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext ctx) +HOOK_EXPORT EGLBoolean EGLAPIENTRY eglDestroyContext_renderdoc_hooked(EGLDisplay dpy, EGLContext ctx) { if(RenderDoc::Inst().IsReplayApp()) { @@ -220,9 +222,10 @@ HOOK_EXPORT EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext return EGL.DestroyContext(dpy, ctx); } -HOOK_EXPORT EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, - EGLNativeWindowType win, - const EGLint *attrib_list) +HOOK_EXPORT EGLSurface EGLAPIENTRY eglCreateWindowSurface_renderdoc_hooked(EGLDisplay dpy, + EGLConfig config, + EGLNativeWindowType win, + const EGLint *attrib_list) { if(RenderDoc::Inst().IsReplayApp()) { @@ -244,8 +247,9 @@ HOOK_EXPORT EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLCon return ret; } -HOOK_EXPORT EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay display, EGLSurface draw, - EGLSurface read, EGLContext ctx) +HOOK_EXPORT EGLBoolean EGLAPIENTRY eglMakeCurrent_renderdoc_hooked(EGLDisplay display, + EGLSurface draw, EGLSurface read, + EGLContext ctx) { if(RenderDoc::Inst().IsReplayApp()) { @@ -320,7 +324,7 @@ HOOK_EXPORT EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay display, EGLSurface return ret; } -HOOK_EXPORT EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) +HOOK_EXPORT EGLBoolean EGLAPIENTRY eglSwapBuffers_renderdoc_hooked(EGLDisplay dpy, EGLSurface surface) { if(RenderDoc::Inst().IsReplayApp()) { @@ -339,8 +343,10 @@ HOOK_EXPORT EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface sur return EGL.SwapBuffers(dpy, surface); } -HOOK_EXPORT EGLBoolean EGLAPIENTRY eglPostSubBufferNV(EGLDisplay dpy, EGLSurface surface, EGLint x, - EGLint y, EGLint width, EGLint height) +HOOK_EXPORT EGLBoolean EGLAPIENTRY eglPostSubBufferNV_renderdoc_hooked(EGLDisplay dpy, + EGLSurface surface, EGLint x, + EGLint y, EGLint width, + EGLint height) { if(RenderDoc::Inst().IsReplayApp()) { @@ -359,7 +365,8 @@ HOOK_EXPORT EGLBoolean EGLAPIENTRY eglPostSubBufferNV(EGLDisplay dpy, EGLSurface return EGL.PostSubBufferNV(dpy, surface, x, y, width, height); } -HOOK_EXPORT __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddress(const char *func) +HOOK_EXPORT __eglMustCastToProperFunctionPointerType EGLAPIENTRY +eglGetProcAddress_renderdoc_hooked(const char *func) { if(RenderDoc::Inst().IsReplayApp()) { @@ -381,17 +388,19 @@ HOOK_EXPORT __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddre // return our egl hooks if(!strcmp(func, "eglCreateContext")) - return (__eglMustCastToProperFunctionPointerType)&eglCreateContext; + return (__eglMustCastToProperFunctionPointerType)&eglCreateContext_renderdoc_hooked; if(!strcmp(func, "eglGetDisplay")) - return (__eglMustCastToProperFunctionPointerType)&eglGetDisplay; + return (__eglMustCastToProperFunctionPointerType)&eglGetDisplay_renderdoc_hooked; if(!strcmp(func, "eglDestroyContext")) - return (__eglMustCastToProperFunctionPointerType)&eglDestroyContext; + return (__eglMustCastToProperFunctionPointerType)&eglDestroyContext_renderdoc_hooked; if(!strcmp(func, "eglMakeCurrent")) - return (__eglMustCastToProperFunctionPointerType)&eglMakeCurrent; + return (__eglMustCastToProperFunctionPointerType)&eglMakeCurrent_renderdoc_hooked; if(!strcmp(func, "eglSwapBuffers")) - return (__eglMustCastToProperFunctionPointerType)&eglSwapBuffers; + return (__eglMustCastToProperFunctionPointerType)&eglSwapBuffers_renderdoc_hooked; if(!strcmp(func, "eglPostSubBufferNV")) - return (__eglMustCastToProperFunctionPointerType)&eglPostSubBufferNV; + return (__eglMustCastToProperFunctionPointerType)&eglPostSubBufferNV_renderdoc_hooked; + if(!strcmp(func, "eglGetProcAddress")) + return (__eglMustCastToProperFunctionPointerType)&eglGetProcAddress_renderdoc_hooked; // any other egl functions are safe to pass through unchanged if(!strncmp(func, "egl", 3)) @@ -401,6 +410,57 @@ HOOK_EXPORT __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddre return (__eglMustCastToProperFunctionPointerType)HookedGetProcAddress(func, (void *)realFunc); } +// on posix systems, someone might declare a global variable with the same name as a function. When +// doing this, it might mean that our code for "&eglSwapBuffers" looking up that global symbol will +// instead find the location fo the function pointer instead of our hook function. For this reason +// we always refer to the _renderdoc_hooked name, but we still must export the functions under their +// real names and just forward to the hook implementation. + +HOOK_EXPORT EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display) +{ + return eglGetDisplay_renderdoc_hooked(display); +} + +HOOK_EXPORT EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay display, EGLConfig config, + EGLContext shareContext, EGLint const *attribList) +{ + return eglCreateContext_renderdoc_hooked(display, config, shareContext, attribList); +} + +HOOK_EXPORT EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext ctx) +{ + return eglDestroyContext_renderdoc_hooked(dpy, ctx); +} + +HOOK_EXPORT EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, + EGLNativeWindowType win, + const EGLint *attrib_list) +{ + return eglCreateWindowSurface_renderdoc_hooked(dpy, config, win, attrib_list); +} + +HOOK_EXPORT EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay display, EGLSurface draw, + EGLSurface read, EGLContext ctx) +{ + return eglMakeCurrent_renderdoc_hooked(display, draw, read, ctx); +} + +HOOK_EXPORT EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) +{ + return eglSwapBuffers_renderdoc_hooked(dpy, surface); +} + +HOOK_EXPORT EGLBoolean EGLAPIENTRY eglPostSubBufferNV(EGLDisplay dpy, EGLSurface surface, EGLint x, + EGLint y, EGLint width, EGLint height) +{ + return eglPostSubBufferNV_renderdoc_hooked(dpy, surface, x, y, width, height); +} + +HOOK_EXPORT __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddress(const char *func) +{ + return eglGetProcAddress_renderdoc_hooked(func); +} + // on posix systems we need to export the whole of the EGL API, since we will have redirected any // dlopen() for libEGL.so to ourselves, and dlsym() for any of these entry points must return a // valid function. We don't need to intercept them, so we just pass it along @@ -602,10 +662,10 @@ void EGLHook::RegisterHooks() #endif // register EGL hooks -#define EGL_REGISTER(func, isext) \ - LibraryHooks::RegisterFunctionHook( \ - "libEGL" LIBSUFFIX, \ - FunctionHook("egl" STRINGIZE(func), (void **)&EGL.func, (void *)&CONCAT(egl, func))); +#define EGL_REGISTER(func, isext) \ + LibraryHooks::RegisterFunctionHook( \ + "libEGL" LIBSUFFIX, FunctionHook("egl" STRINGIZE(func), (void **)&EGL.func, \ + (void *)&CONCAT(egl, CONCAT(func, _renderdoc_hooked)))); EGL_HOOKED_SYMBOLS(EGL_REGISTER) #undef EGL_REGISTER } diff --git a/renderdoc/driver/gl/glx_hooks.cpp b/renderdoc/driver/gl/glx_hooks.cpp index b939a51cd..60b641454 100644 --- a/renderdoc/driver/gl/glx_hooks.cpp +++ b/renderdoc/driver/gl/glx_hooks.cpp @@ -93,8 +93,8 @@ public: std::map m_GLXWindowMap; } glxhook; -HOOK_EXPORT GLXContext glXCreateContext(Display *dpy, XVisualInfo *vis, GLXContext shareList, - Bool direct) +HOOK_EXPORT GLXContext glXCreateContext_renderdoc_hooked(Display *dpy, XVisualInfo *vis, + GLXContext shareList, Bool direct) { if(RenderDoc::Inst().IsReplayApp()) { @@ -146,7 +146,7 @@ HOOK_EXPORT GLXContext glXCreateContext(Display *dpy, XVisualInfo *vis, GLXConte return ret; } -HOOK_EXPORT void glXDestroyContext(Display *dpy, GLXContext ctx) +HOOK_EXPORT void glXDestroyContext_renderdoc_hooked(Display *dpy, GLXContext ctx) { if(RenderDoc::Inst().IsReplayApp()) { @@ -165,9 +165,9 @@ HOOK_EXPORT void glXDestroyContext(Display *dpy, GLXContext ctx) GLX.glXDestroyContext(dpy, ctx); } -HOOK_EXPORT GLXContext glXCreateContextAttribsARB(Display *dpy, GLXFBConfig config, - GLXContext shareList, Bool direct, - const int *attribList) +HOOK_EXPORT GLXContext glXCreateContextAttribsARB_renderdoc_hooked(Display *dpy, GLXFBConfig config, + GLXContext shareList, Bool direct, + const int *attribList) { if(RenderDoc::Inst().IsReplayApp()) { @@ -289,7 +289,7 @@ HOOK_EXPORT GLXContext glXCreateContextAttribsARB(Display *dpy, GLXFBConfig conf return ret; } -HOOK_EXPORT Bool glXMakeCurrent(Display *dpy, GLXDrawable drawable, GLXContext ctx) +HOOK_EXPORT Bool glXMakeCurrent_renderdoc_hooked(Display *dpy, GLXDrawable drawable, GLXContext ctx) { if(RenderDoc::Inst().IsReplayApp()) { @@ -356,8 +356,8 @@ HOOK_EXPORT Bool glXMakeCurrent(Display *dpy, GLXDrawable drawable, GLXContext c return ret; } -HOOK_EXPORT Bool glXMakeContextCurrent(Display *dpy, GLXDrawable draw, GLXDrawable read, - GLXContext ctx) +HOOK_EXPORT Bool glXMakeContextCurrent_renderdoc_hooked(Display *dpy, GLXDrawable draw, + GLXDrawable read, GLXContext ctx) { if(RenderDoc::Inst().IsReplayApp()) { @@ -423,7 +423,7 @@ HOOK_EXPORT Bool glXMakeContextCurrent(Display *dpy, GLXDrawable draw, GLXDrawab return ret; } -HOOK_EXPORT void glXSwapBuffers(Display *dpy, GLXDrawable drawable) +HOOK_EXPORT void glXSwapBuffers_renderdoc_hooked(Display *dpy, GLXDrawable drawable) { if(RenderDoc::Inst().IsReplayApp()) { @@ -440,8 +440,8 @@ HOOK_EXPORT void glXSwapBuffers(Display *dpy, GLXDrawable drawable) GLX.glXSwapBuffers(dpy, drawable); } -HOOK_EXPORT GLXWindow glXCreateWindow(Display *dpy, GLXFBConfig config, Window win, - const int *attribList) +HOOK_EXPORT GLXWindow glXCreateWindow_renderdoc_hooked(Display *dpy, GLXFBConfig config, Window win, + const int *attribList) { if(RenderDoc::Inst().IsReplayApp()) { @@ -461,7 +461,7 @@ HOOK_EXPORT GLXWindow glXCreateWindow(Display *dpy, GLXFBConfig config, Window w return ret; } -HOOK_EXPORT void glXDestroyWindow(Display *dpy, GLXWindow window) +HOOK_EXPORT void glXDestroyWindow_renderdoc_hooked(Display *dpy, GLXWindow window) { if(RenderDoc::Inst().IsReplayApp()) { @@ -479,7 +479,7 @@ HOOK_EXPORT void glXDestroyWindow(Display *dpy, GLXWindow window) return GLX.glXDestroyWindow(dpy, window); } -HOOK_EXPORT __GLXextFuncPtr glXGetProcAddress(const GLubyte *f) +HOOK_EXPORT __GLXextFuncPtr glXGetProcAddress_renderdoc_hooked(const GLubyte *f) { if(RenderDoc::Inst().IsReplayApp()) { @@ -503,27 +503,27 @@ HOOK_EXPORT __GLXextFuncPtr glXGetProcAddress(const GLubyte *f) // return our glX hooks if(!strcmp(func, "glXCreateContext")) - return (__GLXextFuncPtr)&glXCreateContext; + return (__GLXextFuncPtr)&glXCreateContext_renderdoc_hooked; if(!strcmp(func, "glXDestroyContext")) - return (__GLXextFuncPtr)&glXDestroyContext; + return (__GLXextFuncPtr)&glXDestroyContext_renderdoc_hooked; if(!strcmp(func, "glXCreateContextAttribsARB")) - return (__GLXextFuncPtr)&glXCreateContextAttribsARB; + return (__GLXextFuncPtr)&glXCreateContextAttribsARB_renderdoc_hooked; if(!strcmp(func, "glXMakeCurrent")) - return (__GLXextFuncPtr)&glXMakeCurrent; + return (__GLXextFuncPtr)&glXMakeCurrent_renderdoc_hooked; if(!strcmp(func, "glXMakeContextCurrent")) - return (__GLXextFuncPtr)&glXMakeContextCurrent; + return (__GLXextFuncPtr)&glXMakeContextCurrent_renderdoc_hooked; if(!strcmp(func, "glXSwapBuffers")) - return (__GLXextFuncPtr)&glXSwapBuffers; + return (__GLXextFuncPtr)&glXSwapBuffers_renderdoc_hooked; if(!strcmp(func, "glXCreateWindow")) - return (__GLXextFuncPtr)&glXCreateWindow; + return (__GLXextFuncPtr)&glXCreateWindow_renderdoc_hooked; if(!strcmp(func, "glXDestroyWindow")) - return (__GLXextFuncPtr)&glXDestroyWindow; + return (__GLXextFuncPtr)&glXDestroyWindow_renderdoc_hooked; if(!strcmp(func, "glXGetProcAddress")) - return (__GLXextFuncPtr)&glXGetProcAddress; + return (__GLXextFuncPtr)&glXGetProcAddress_renderdoc_hooked; if(!strcmp(func, "glXGetProcAddressARB")) - return (__GLXextFuncPtr)&glXGetProcAddressARB; + return (__GLXextFuncPtr)&glXGetProcAddress_renderdoc_hooked; - // any other egl functions are safe to pass through unchanged + // any other GLX functions are safe to pass through unchanged if(!strncmp(func, "glX", 3)) return realFunc; @@ -531,9 +531,70 @@ HOOK_EXPORT __GLXextFuncPtr glXGetProcAddress(const GLubyte *f) return (__GLXextFuncPtr)HookedGetProcAddress(func, (void *)realFunc); } +HOOK_EXPORT __GLXextFuncPtr glXGetProcAddressARB_renderdoc_hooked(const GLubyte *f) +{ + return glXGetProcAddress_renderdoc_hooked(f); +} + +// on posix systems, someone might declare a global variable with the same name as a function. When +// doing this, it might mean that our code for "&glXSwapBuffers" looking up that global symbol will +// instead find the location fo the function pointer instead of our hook function. For this reason +// we always refer to the _renderdoc_hooked name, but we still must export the functions under their +// real names and just forward to the hook implementation. + +HOOK_EXPORT GLXContext glXCreateContext(Display *dpy, XVisualInfo *vis, GLXContext shareList, + Bool direct) +{ + return glXCreateContext_renderdoc_hooked(dpy, vis, shareList, direct); +} + +HOOK_EXPORT void glXDestroyContext(Display *dpy, GLXContext ctx) +{ + return glXDestroyContext_renderdoc_hooked(dpy, ctx); +} + +HOOK_EXPORT GLXContext glXCreateContextAttribsARB(Display *dpy, GLXFBConfig config, + GLXContext shareList, Bool direct, + const int *attribList) +{ + return glXCreateContextAttribsARB_renderdoc_hooked(dpy, config, shareList, direct, attribList); +} + +HOOK_EXPORT Bool glXMakeCurrent(Display *dpy, GLXDrawable drawable, GLXContext ctx) +{ + return glXMakeCurrent_renderdoc_hooked(dpy, drawable, ctx); +} + +HOOK_EXPORT Bool glXMakeContextCurrent(Display *dpy, GLXDrawable draw, GLXDrawable read, + GLXContext ctx) +{ + return glXMakeContextCurrent_renderdoc_hooked(dpy, draw, read, ctx); +} + +HOOK_EXPORT void glXSwapBuffers(Display *dpy, GLXDrawable drawable) +{ + return glXSwapBuffers_renderdoc_hooked(dpy, drawable); +} + +HOOK_EXPORT GLXWindow glXCreateWindow(Display *dpy, GLXFBConfig config, Window win, + const int *attribList) +{ + return glXCreateWindow_renderdoc_hooked(dpy, config, win, attribList); +} + +HOOK_EXPORT void glXDestroyWindow(Display *dpy, GLXWindow window) +{ + return glXDestroyWindow_renderdoc_hooked(dpy, window); +} + +HOOK_EXPORT __GLXextFuncPtr glXGetProcAddress(const GLubyte *f) +{ + return glXGetProcAddress_renderdoc_hooked(f); +} + HOOK_EXPORT __GLXextFuncPtr glXGetProcAddressARB(const GLubyte *f) { - return glXGetProcAddress(f); + return glXGetProcAddressARB_renderdoc_hooked(f); } // on posix systems we need to export the whole of the GLX API, since we will have redirected any @@ -695,7 +756,8 @@ void GLXHook::RegisterHooks() // register EGL hooks #define GLX_REGISTER(func) \ LibraryHooks::RegisterFunctionHook( \ - "libGL.so", FunctionHook(STRINGIZE(func), (void **)&GLX.func, (void *)&func)); + "libGL.so", \ + FunctionHook(STRINGIZE(func), (void **)&GLX.func, (void *)&CONCAT(func, _renderdoc_hooked))); GLX_HOOKED_SYMBOLS(GLX_REGISTER) #undef GLX_REGISTER }