From 29b4c65162570a164a2c2b83235da257c966d0f0 Mon Sep 17 00:00:00 2001 From: baldurk Date: Sat, 15 Nov 2014 00:13:44 +0000 Subject: [PATCH] Work around issue where application 'exports' gl symbols * This is a bit complex. If an application has a global symbol e.g. GLENABLE glEnable; as their function pointers that they fill out from glXGetProcAddress, then OUR glEnable global function gets replaced with that symbol. It's weird. But it means crashes if we try and return the address of that symbol as a function pointer. * However it's also possible to get the reverse problem - if an application has a shared library that has those symbols expecting them to be function pointers, those symbols will get overridden with our global functions and it will mean an instant crash when they try to assign to those func ptrs. * I'm not sure if there is an ideal fix to this Catch-22, as we also need to export these bare functions in case someone just plain links against libGL and expects them to be there, with no GetProcAddress/dlsym funny business. --- renderdoc/hooks/gl_linux_hooks.cpp | 73 +++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 21 deletions(-) diff --git a/renderdoc/hooks/gl_linux_hooks.cpp b/renderdoc/hooks/gl_linux_hooks.cpp index 865c5ab59..5fec9290f 100644 --- a/renderdoc/hooks/gl_linux_hooks.cpp +++ b/renderdoc/hooks/gl_linux_hooks.cpp @@ -55,14 +55,14 @@ void *libGLdlsymHandle = RTLD_NEXT; // default to RTLD_NEXT, but overwritten if if(!strcmp(func, STRINGIZE(function))) \ { \ OpenGLHook::glhooks.GL.function = (funcPtrType)realFunc; \ - return (__GLXextFuncPtr)&function; \ + return (__GLXextFuncPtr)&CONCAT(function, _renderdoc_hooked); \ } #define HookExtensionAlias(funcPtrType, function, alias) \ if(!strcmp(func, STRINGIZE(alias))) \ { \ OpenGLHook::glhooks.GL.function = (funcPtrType)realFunc; \ - return (__GLXextFuncPtr)&function; \ + return (__GLXextFuncPtr)&CONCAT(function, _renderdoc_hooked); \ } /* @@ -78,13 +78,21 @@ void *libGLdlsymHandle = RTLD_NEXT; // default to RTLD_NEXT, but overwritten if echo -en "\ttypedef ret (*CONCAT(function, _hooktype)) ("; for I in `seq 1 $N`; do echo -n "t$I"; if [ $I -ne $N ]; then echo -n ", "; fi; done; echo "); \\"; - - echo -e "\textern \"C\" __attribute__ ((visibility (\"default\"))) \\"; - + + echo -e "\textern \"C\" __attribute__ ((visibility (\"default\"))) \\"; + echo -en "\tret function("; for I in `seq 1 $N`; do echo -n "t$I p$I"; if [ $I -ne $N ]; then echo -n ", "; fi; done; echo ") \\"; - + + echo -en "\t{ SCOPED_LOCK(glLock); return OpenGLHook::glhooks.GetDriver()->function("; + for I in `seq 1 $N`; do echo -n "p$I"; if [ $I -ne $N ]; then echo -n ", "; fi; done; + echo "); }"; + + echo -en "\tret CONCAT(function,_renderdoc_hooked)("; + for I in `seq 1 $N`; do echo -n "t$I p$I"; if [ $I -ne $N ]; then echo -n ", "; fi; done; + echo ") \\"; + echo -en "\t{ SCOPED_LOCK(glLock); return OpenGLHook::glhooks.GetDriver()->function("; for I in `seq 1 $N`; do echo -n "p$I"; if [ $I -ne $N ]; then echo -n ", "; fi; done; echo -n "); }"; @@ -103,101 +111,124 @@ void *libGLdlsymHandle = RTLD_NEXT; // default to RTLD_NEXT, but overwritten if #undef far #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 +// badly. Instead we leave the 'naked' versions for applications trying to import those +// symbols, and declare the _renderdoc_hooked for returning as a func pointer. + #define HookWrapper0(ret, function) \ typedef ret (*CONCAT(function, _hooktype)) (); \ extern "C" __attribute__ ((visibility ("default"))) \ ret function() \ { SCOPED_LOCK(glLock); return OpenGLHook::glhooks.GetDriver()->function(); } - + ret CONCAT(function,_renderdoc_hooked)() \ + { SCOPED_LOCK(glLock); return OpenGLHook::glhooks.GetDriver()->function(); } #define HookWrapper1(ret, function, t1, p1) \ typedef ret (*CONCAT(function, _hooktype)) (t1); \ extern "C" __attribute__ ((visibility ("default"))) \ ret function(t1 p1) \ { SCOPED_LOCK(glLock); return OpenGLHook::glhooks.GetDriver()->function(p1); } - + ret CONCAT(function,_renderdoc_hooked)(t1 p1) \ + { SCOPED_LOCK(glLock); return OpenGLHook::glhooks.GetDriver()->function(p1); } #define HookWrapper2(ret, function, t1, p1, t2, p2) \ typedef ret (*CONCAT(function, _hooktype)) (t1, t2); \ extern "C" __attribute__ ((visibility ("default"))) \ ret function(t1 p1, t2 p2) \ { SCOPED_LOCK(glLock); return OpenGLHook::glhooks.GetDriver()->function(p1, p2); } - + ret CONCAT(function,_renderdoc_hooked)(t1 p1, t2 p2) \ + { SCOPED_LOCK(glLock); return OpenGLHook::glhooks.GetDriver()->function(p1, p2); } #define HookWrapper3(ret, function, t1, p1, t2, p2, t3, p3) \ typedef ret (*CONCAT(function, _hooktype)) (t1, t2, t3); \ extern "C" __attribute__ ((visibility ("default"))) \ ret function(t1 p1, t2 p2, t3 p3) \ { SCOPED_LOCK(glLock); return OpenGLHook::glhooks.GetDriver()->function(p1, p2, p3); } - + ret CONCAT(function,_renderdoc_hooked)(t1 p1, t2 p2, t3 p3) \ + { SCOPED_LOCK(glLock); return OpenGLHook::glhooks.GetDriver()->function(p1, p2, p3); } #define HookWrapper4(ret, function, t1, p1, t2, p2, t3, p3, t4, p4) \ 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); return OpenGLHook::glhooks.GetDriver()->function(p1, p2, p3, p4); } - + ret CONCAT(function,_renderdoc_hooked)(t1 p1, t2 p2, t3 p3, t4 p4) \ + { SCOPED_LOCK(glLock); return OpenGLHook::glhooks.GetDriver()->function(p1, p2, p3, p4); } #define HookWrapper5(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5) \ 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); return OpenGLHook::glhooks.GetDriver()->function(p1, p2, p3, p4, p5); } - + ret CONCAT(function,_renderdoc_hooked)(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5) \ + { SCOPED_LOCK(glLock); return OpenGLHook::glhooks.GetDriver()->function(p1, p2, p3, p4, p5); } #define HookWrapper6(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6) \ typedef ret (*CONCAT(function, _hooktype)) (t1, t2, t3, t4, t5, t6); \ extern "C" __attribute__ ((visibility ("default"))) \ ret function(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6) \ { SCOPED_LOCK(glLock); return OpenGLHook::glhooks.GetDriver()->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); return OpenGLHook::glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6); } #define HookWrapper7(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7) \ typedef ret (*CONCAT(function, _hooktype)) (t1, t2, t3, t4, t5, t6, t7); \ extern "C" __attribute__ ((visibility ("default"))) \ ret function(t1 p1, t2 p2, t3 p3, t4 p4, t5 p5, t6 p6, t7 p7) \ { SCOPED_LOCK(glLock); return OpenGLHook::glhooks.GetDriver()->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); return OpenGLHook::glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7); } #define HookWrapper8(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, p8) \ typedef ret (*CONCAT(function, _hooktype)) (t1, t2, t3, t4, t5, t6, t7, t8); \ 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); return OpenGLHook::glhooks.GetDriver()->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); return OpenGLHook::glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8); } #define HookWrapper9(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, p8, t9, p9) \ typedef ret (*CONCAT(function, _hooktype)) (t1, t2, t3, t4, t5, t6, t7, t8, t9); \ 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); return OpenGLHook::glhooks.GetDriver()->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); return OpenGLHook::glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9); } #define HookWrapper10(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, p8, t9, p9, t10, p10) \ typedef ret (*CONCAT(function, _hooktype)) (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10); \ 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); return OpenGLHook::glhooks.GetDriver()->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); return OpenGLHook::glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); } #define HookWrapper11(ret, function, t1, p1, t2, p2, t3, p3, t4, p4, t5, p5, t6, p6, t7, p7, t8, p8, t9, p9, t10, p10, t11, p11) \ typedef ret (*CONCAT(function, _hooktype)) (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11); \ 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); return OpenGLHook::glhooks.GetDriver()->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); return OpenGLHook::glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); } #define HookWrapper12(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) \ typedef ret (*CONCAT(function, _hooktype)) (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12); \ 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); return OpenGLHook::glhooks.GetDriver()->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); return OpenGLHook::glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); } #define HookWrapper13(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, t13, p13) \ typedef ret (*CONCAT(function, _hooktype)) (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13); \ 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, t13 p13) \ { SCOPED_LOCK(glLock); return OpenGLHook::glhooks.GetDriver()->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); return OpenGLHook::glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); } #define HookWrapper14(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, t13, p13, t14, p14) \ typedef ret (*CONCAT(function, _hooktype)) (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14); \ 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, t13 p13, t14 p14) \ { SCOPED_LOCK(glLock); return OpenGLHook::glhooks.GetDriver()->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); return OpenGLHook::glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14); } #define HookWrapper15(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, t13, p13, t14, p14, t15, p15) \ typedef ret (*CONCAT(function, _hooktype)) (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15); \ 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, t13 p13, t14 p14, t15 p15) \ { SCOPED_LOCK(glLock); return OpenGLHook::glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); } + 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, t15 p15) \ + { SCOPED_LOCK(glLock); return OpenGLHook::glhooks.GetDriver()->function(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); } Threading::CriticalSection glLock;