#if !defined(_WIN32)
#include <unistd.h> // for symlink
-#include <dlfcn.h>
+#include "dlopen.hpp"
#endif
* Handle to the true OpenGL library.
*/
#if defined(_WIN32)
-HINSTANCE __libGlHandle = NULL;
+HMODULE _libGlHandle = NULL;
#else
-void *__libGlHandle = NULL;
+void *_libGlHandle = NULL;
#endif
#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)) {
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);
}
/*
* 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
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 (resullt && result == dlsym(RTLD_SELF, symbol)) {
+#if 0
+ if (result && result == dlsym(RTLD_SELF, symbol)) {
os::log("apitrace: error: symbol lookup recursion\n");
os::abort();
return NULL;
}
+#endif
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 __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.
result = dlsym(RTLD_NEXT, symbol);
if (result) {
- __libGlHandle = RTLD_NEXT;
+ _libGlHandle = RTLD_NEXT;
return result;
}
* 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);
}