]> git.cworth.org Git - apitrace/blobdiff - dispatch/glproc_gl.cpp
retrace: Implement glxCopySubBufferMESA
[apitrace] / dispatch / glproc_gl.cpp
index 5adbebbb799417d93546f0b936bab0ee137a0299..2516dab81c441e685a5797096a53c032056567b7 100644 (file)
@@ -29,7 +29,7 @@
 
 #if !defined(_WIN32)
 #include <unistd.h> // for symlink
-#include <dlfcn.h>
+#include "dlopen.hpp"
 #endif
 
 
@@ -37,9 +37,9 @@
  * Handle to the true OpenGL library.
  */
 #if defined(_WIN32)
-HINSTANCE __libGlHandle = NULL;
+HMODULE _libGlHandle = NULL;
 #else
-void *__libGlHandle = NULL;
+void *_libGlHandle = NULL;
 #endif
 
 
@@ -47,9 +47,9 @@ void *__libGlHandle = NULL;
 #if defined(_WIN32)
 
 void *
-__getPublicProcAddress(const char *procName)
+_getPublicProcAddress(const char *procName)
 {
-    if (!__libGlHandle) {
+    if (!_libGlHandle) {
         char szDll[MAX_PATH] = {0};
         
         if (!GetSystemDirectoryA(szDll, MAX_PATH)) {
@@ -58,20 +58,20 @@ __getPublicProcAddress(const char *procName)
         
         strcat(szDll, "\\\\opengl32.dll");
         
-        __libGlHandle = LoadLibraryA(szDll);
-        if (!__libGlHandle) {
+        _libGlHandle = LoadLibraryA(szDll);
+        if (!_libGlHandle) {
             os::log("apitrace: error: couldn't load %s\n", szDll);
             return NULL;
         }
     }
         
-    return (void *)GetProcAddress(__libGlHandle, procName);
+    return (void *)GetProcAddress(_libGlHandle, procName);
 }
 
 
 void *
-__getPrivateProcAddress(const char *procName) {
-    return (void *)__wglGetProcAddress(procName);
+_getPrivateProcAddress(const char *procName) {
+    return (void *)_wglGetProcAddress(procName);
 }
 
 
@@ -87,11 +87,11 @@ static const char *libgl_filename = "/System/Library/Frameworks/OpenGL.framework
 /*
  * Lookup a libGL symbol
  */
-void * __libgl_sym(const char *symbol)
+void * _libgl_sym(const char *symbol)
 {
     void *result;
 
-    if (!__libGlHandle) {
+    if (!_libGlHandle) {
         /* 
          * Unfortunately we can't just dlopen the true dynamic library because
          * DYLD_LIBRARY_PATH/DYLD_FRAMEWORK_PATH take precedence, even for
@@ -103,19 +103,19 @@ void * __libgl_sym(const char *symbol)
 
         if (mktemp(temp_filename) != NULL) {
             if (symlink(libgl_filename, temp_filename) == 0) {
-                __libGlHandle = dlopen(temp_filename, RTLD_LOCAL | RTLD_NOW | RTLD_FIRST);
+                _libGlHandle = dlopen(temp_filename, RTLD_LOCAL | RTLD_NOW | RTLD_FIRST);
                 remove(temp_filename);
             }
         }
 
-        if (!__libGlHandle) {
+        if (!_libGlHandle) {
             os::log("apitrace: error: couldn't load %s\n", libgl_filename);
             os::abort();
             return NULL;
         }
     }
 
-    result = dlsym(__libGlHandle, symbol);
+    result = dlsym(_libGlHandle, symbol);
 
 #if 0
     if (result && result == dlsym(RTLD_SELF, symbol)) {
@@ -130,50 +130,96 @@ void * __libgl_sym(const char *symbol)
 
 
 void *
-__getPublicProcAddress(const char *procName)
+_getPublicProcAddress(const char *procName)
 {
-    return __libgl_sym(procName);
+    return _libgl_sym(procName);
 }
 
 void *
-__getPrivateProcAddress(const char *procName)
+_getPrivateProcAddress(const char *procName)
 {
-    return __libgl_sym(procName);
+    return _libgl_sym(procName);
 }
 
 
 #else
 
 
+static inline void
+logSymbol(const char *name, void *ptr) {
+    if (0) {
+        if (ptr) {
+            Dl_info info;
+            if (ptr && dladdr(ptr, &info)) {
+                os::log("apitrace: %s -> \"%s\"\n", name, info.dli_fname);
+            }
+        } else {
+            os::log("apitrace: %s -> NULL\n", name);
+        }
+    }
+}
+
+
+#ifdef __GLIBC__
+extern "C" void * __libc_dlsym(void *, const char *);
+#endif
+
+
 /*
- * Invoke the true dlopen() function.
+ * Protect against dlsym interception.
+ *
+ * We implement the whole API, so we don't need to intercept dlsym -- dlopen is
+ * enough. However we need to protect against other dynamic libraries
+ * intercepting dlsym, to prevent infinite recursion,
+ *
+ * In particular the Steam Community Overlay advertises dlsym. See also
+ * http://lists.freedesktop.org/archives/apitrace/2013-March/000573.html
  */
-static void *
-__dlopen(const char *filename, int flag)
+static inline void *
+_dlsym(void *handle, const char *symbol)
 {
-    typedef void * (*PFNDLOPEN)(const char *, int);
-    static PFNDLOPEN dlopen_ptr = NULL;
+    void *result;
 
-    if (!dlopen_ptr) {
-        dlopen_ptr = (PFNDLOPEN)dlsym(RTLD_NEXT, "dlopen");
-        if (!dlopen_ptr) {
-            os::log("apitrace: error: dlsym(RTLD_NEXT, \"dlopen\") failed\n");
+#ifdef __GLIBC__
+    /*
+     * We rely on glibc's internal __libc_dlsym.  See also
+     * http://www.linuxforu.com/2011/08/lets-hook-a-library-function/
+     *
+     * Use use it to obtain the true dlsym.  We don't use __libc_dlsym directly
+     * because it does not support things such as RTLD_NEXT.
+     */
+    typedef void * (*PFN_DLSYM)(void *, const char *);
+    static PFN_DLSYM dlsym_ptr = NULL;
+    if (!dlsym_ptr) {
+        void *libdl_handle = _dlopen("libdl.so.2", RTLD_LOCAL | RTLD_NOW);
+        if (libdl_handle) {
+            dlsym_ptr = (PFN_DLSYM)__libc_dlsym(libdl_handle, "dlsym");
+        }
+        if (!dlsym_ptr) {
+            os::log("apitrace: error: failed to look up real dlsym\n");
             return NULL;
         }
+
+        logSymbol("dlsym", (void*)dlsym_ptr);
     }
 
-    return dlopen_ptr(filename, flag);
+    result = dlsym_ptr(handle, symbol);
+#else
+    result = dlsym(handle, symbol);
+#endif
+
+    return result;
 }
 
 
 /*
  * Lookup a libGL symbol
  */
-void * __libgl_sym(const char *symbol)
+void * _libgl_sym(const char *symbol)
 {
     void *result;
 
-    if (!__libGlHandle) {
+    if (!_libGlHandle) {
         /*
          * The app doesn't directly link against libGL.so, nor does it directly
          * dlopen it.  So we have to load it ourselves.
@@ -188,7 +234,7 @@ void * __libgl_sym(const char *symbol)
 
             result = dlsym(RTLD_NEXT, symbol);
             if (result) {
-                __libGlHandle = RTLD_NEXT;
+                _libGlHandle = RTLD_NEXT;
                 return result;
             }
 
@@ -202,27 +248,31 @@ void * __libgl_sym(const char *symbol)
          * exposes symbols to it.
          */
 
-        __libGlHandle = __dlopen(libgl_filename, RTLD_GLOBAL | RTLD_LAZY);
-        if (!__libGlHandle) {
+        _libGlHandle = _dlopen(libgl_filename, RTLD_GLOBAL | RTLD_LAZY);
+        if (!_libGlHandle) {
             os::log("apitrace: error: couldn't find libGL.so\n");
             return NULL;
         }
     }
 
-    return dlsym(__libGlHandle, symbol);
+    result = _dlsym(_libGlHandle, symbol);
+
+    logSymbol(symbol, result);
+
+    return result;
 }
 
 
 void *
-__getPublicProcAddress(const char *procName)
+_getPublicProcAddress(const char *procName)
 {
-    return __libgl_sym(procName);
+    return _libgl_sym(procName);
 }
 
 void *
-__getPrivateProcAddress(const char *procName)
+_getPrivateProcAddress(const char *procName)
 {
-    return (void *)__glXGetProcAddressARB((const GLubyte *)procName);
+    return (void *)_glXGetProcAddressARB((const GLubyte *)procName);
 }