summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJose Fonseca <jfonseca@vmware.com>2016-06-30 14:51:54 +0100
committerJose Fonseca <jfonseca@vmware.com>2016-06-30 17:17:11 +0100
commit4f97da64f693607e191cd6b4cd4a8da86d7b6779 (patch)
tree6507e64022e541a7d840a28b328fe48ab8ccea6a
parent75ca211ceea3ec77bee3cdd8d91d5f0b23170ea6 (diff)
egltrace: Don't intercept dlopen calls done by EGL/GL/GLES implementation.
Certain EGL implementations do this.
-rw-r--r--wrappers/CMakeLists.txt2
-rw-r--r--wrappers/dlsym.cpp148
-rw-r--r--wrappers/egltrace.py67
-rw-r--r--wrappers/glxtrace.py50
4 files changed, 150 insertions, 117 deletions
diff --git a/wrappers/CMakeLists.txt b/wrappers/CMakeLists.txt
index 5e29b1ac..4bd3ef19 100644
--- a/wrappers/CMakeLists.txt
+++ b/wrappers/CMakeLists.txt
@@ -418,6 +418,8 @@ if (ENABLE_EGL AND NOT WIN32 AND NOT APPLE)
PREFIX ""
)
+ target_compile_definitions (egltrace PRIVATE -DEGLTRACE=1)
+
target_link_libraries (egltrace
gltrace_common
glproc_egl
diff --git a/wrappers/dlsym.cpp b/wrappers/dlsym.cpp
index 118110f2..5f34a2f0 100644
--- a/wrappers/dlsym.cpp
+++ b/wrappers/dlsym.cpp
@@ -25,6 +25,9 @@
**************************************************************************/
+#include <assert.h>
+#include <memory>
+
#include "os.hpp"
@@ -77,3 +80,148 @@ dlsym(void * handle, const char * symbol)
#endif /* __GLIBC__ */
+
+
+#include "dlopen.hpp"
+
+
+extern void * _libGlHandle;
+
+
+
+enum LibClass {
+ LIB_UNKNOWN = 0,
+ LIB_GL,
+ LIB_EGL,
+ LIB_GLES1,
+ LIB_GLES2,
+};
+
+
+inline LibClass
+classifyLibrary(const char *pathname)
+{
+ std::unique_ptr<char, decltype(std::free) *> dupname { strdup(pathname), std::free };
+
+ char *filename = basename(dupname.get());
+ assert(filename);
+
+ if (strcmp(filename, "libGL.so") == 0 ||
+ strcmp(filename, "libGL.so.1") == 0) {
+ return LIB_GL;
+ }
+
+#ifdef EGLTRACE
+ if (strcmp(filename, "libEGL.so") == 0 ||
+ strcmp(filename, "libEGL.so.1") == 0) {
+ return LIB_EGL;
+ }
+
+ if (strcmp(filename, "libGLESv1_CM.so") == 0 ||
+ strcmp(filename, "libGLESv1_CM.so.1") == 0) {
+ return LIB_GLES1;
+ }
+
+ if (strcmp(filename, "libGLESv2.so") == 0 ||
+ strcmp(filename, "libGLESv2.so.2") == 0) {
+ return LIB_GLES2;
+ }
+#endif
+
+ /*
+ * TODO: Identify driver SOs (e.g, *_dri.so), to prevent intercepting
+ * dlopen calls from them.
+ *
+ * Another alternative is to ignore dlopen calls when inside wrapped calls.
+ */
+
+ return LIB_UNKNOWN;
+}
+
+
+/*
+ * Several applications, such as Quake3, use dlopen("libGL.so.1"), but
+ * LD_PRELOAD does not intercept symbols obtained via dlopen/dlsym, therefore
+ * we need to intercept the dlopen() call here, and redirect to our wrapper
+ * shared object.
+ */
+extern "C" PUBLIC
+void * dlopen(const char *filename, int flag)
+{
+ void *handle;
+
+ if (!filename) {
+ return _dlopen(filename, flag);
+ }
+
+ LibClass libClass = classifyLibrary(filename);
+ bool intercept = libClass != LIB_UNKNOWN;
+
+ if (intercept) {
+ void *caller = __builtin_return_address(0);
+ Dl_info info;
+ const char *caller_module = "<unknown>";
+ if (dladdr(caller, &info)) {
+ caller_module = info.dli_fname;
+ intercept = classifyLibrary(caller_module) == LIB_UNKNOWN;
+ }
+
+ const char * libgl_filename = getenv("TRACE_LIBGL");
+ if (libgl_filename) {
+ // Don't intercept when using LD_LIBRARY_PATH instead of LD_PRELOAD
+ intercept = false;
+ }
+
+ os::log("apitrace: %s dlopen(\"%s\", 0x%x) from %s\n",
+ intercept ? "redirecting" : "ignoring",
+ filename, flag, caller_module);
+ }
+
+#ifdef EGLTRACE
+
+ if (intercept) {
+ /* The current dispatch implementation relies on core entry-points to be globally available, so force this.
+ *
+ * TODO: A better approach would be note down the entry points here and
+ * use them latter. Another alternative would be to reopen the library
+ * with RTLD_NOLOAD | RTLD_GLOBAL.
+ */
+ flag &= ~RTLD_LOCAL;
+ flag |= RTLD_GLOBAL;
+ }
+
+#endif
+
+ handle = _dlopen(filename, flag);
+ if (!handle) {
+ return handle;
+ }
+
+ if (intercept) {
+ if (libClass == LIB_GL) {
+ // Use the true libGL.so handle instead of RTLD_NEXT from now on
+ _libGlHandle = handle;
+ }
+
+ // Get the file path for our shared object, and use it instead
+ static int dummy = 0xdeedbeef;
+ Dl_info info;
+ if (dladdr(&dummy, &info)) {
+ handle = _dlopen(info.dli_fname, flag);
+ } else {
+ os::log("apitrace: warning: dladdr() failed\n");
+ }
+
+#ifdef EGLTRACE
+ // SDL will skip dlopen'ing libEGL.so after it spots EGL symbols on our
+ // wrapper, so force loading it here.
+ // (https://github.com/apitrace/apitrace/issues/291#issuecomment-59734022)
+ if (strcmp(filename, "libEGL.so") != 0 &&
+ strcmp(filename, "libEGL.so.1") != 0) {
+ _dlopen("libEGL.so.1", RTLD_GLOBAL | RTLD_LAZY);
+ }
+#endif
+ }
+
+ return handle;
+}
diff --git a/wrappers/egltrace.py b/wrappers/egltrace.py
index 333809b9..8e658141 100644
--- a/wrappers/egltrace.py
+++ b/wrappers/egltrace.py
@@ -113,7 +113,6 @@ if __name__ == '__main__':
print '#define GL_GLEXT_PROTOTYPES'
print '#define EGL_EGLEXT_PROTOTYPES'
print
- print '#include "dlopen.hpp"'
print '#include "glproc.hpp"'
print '#include "glsize.hpp"'
print '#include "eglsize.hpp"'
@@ -128,70 +127,6 @@ if __name__ == '__main__':
tracer.traceApi(api)
print r'''
-
-
-
-/*
- * Several applications, such as Quake3, use dlopen("libGL.so.1"), but
- * LD_PRELOAD does not intercept symbols obtained via dlopen/dlsym, therefore
- * we need to intercept the dlopen() call here, and redirect to our wrapper
- * shared object.
- */
-extern "C" PUBLIC
-void * dlopen(const char *filename, int flag)
-{
- bool intercept = false;
-
- if (filename) {
- intercept =
- strcmp(filename, "libEGL.so") == 0 ||
- strcmp(filename, "libEGL.so.1") == 0 ||
- strcmp(filename, "libGLESv1_CM.so") == 0 ||
- strcmp(filename, "libGLESv1_CM.so.1") == 0 ||
- strcmp(filename, "libGLESv2.so") == 0 ||
- strcmp(filename, "libGLESv2.so.2") == 0 ||
- strcmp(filename, "libGL.so") == 0 ||
- strcmp(filename, "libGL.so.1") == 0;
-
- if (intercept) {
- os::log("apitrace: redirecting dlopen(\"%s\", 0x%x)\n", filename, flag);
-
- /* The current dispatch implementation relies on core entry-points to be globally available, so force this.
- *
- * TODO: A better approach would be note down the entry points here and
- * use them latter. Another alternative would be to reopen the library
- * with RTLD_NOLOAD | RTLD_GLOBAL.
- */
- flag &= ~RTLD_LOCAL;
- flag |= RTLD_GLOBAL;
- }
- }
-
- void *handle = _dlopen(filename, flag);
-
- if (intercept) {
- // Get the file path for our shared object, and use it instead
- static int dummy = 0xdeedbeef;
- Dl_info info;
- if (dladdr(&dummy, &info)) {
- handle = _dlopen(info.dli_fname, flag);
- } else {
- os::log("apitrace: warning: dladdr() failed\n");
- }
-
- // SDL will skip dlopen'ing libEGL.so after it spots EGL symbols on our
- // wrapper, so force loading it here.
- // (https://github.com/apitrace/apitrace/issues/291#issuecomment-59734022)
- if (strcmp(filename, "libEGL.so") != 0 &&
- strcmp(filename, "libEGL.so.1") != 0) {
- _dlopen("libEGL.so.1", RTLD_GLOBAL | RTLD_LAZY);
- }
- }
-
- return handle;
-}
-
-
#if defined(ANDROID)
/*
@@ -251,6 +186,4 @@ void APIENTRY glWeightPointerOESBounds(GLint size, GLenum type, GLsizei stride,
*/
#endif /* ANDROID */
-
-
'''
diff --git a/wrappers/glxtrace.py b/wrappers/glxtrace.py
index e9c43a9c..d9dce953 100644
--- a/wrappers/glxtrace.py
+++ b/wrappers/glxtrace.py
@@ -166,7 +166,6 @@ if __name__ == '__main__':
print '#define GL_GLEXT_PROTOTYPES'
print '#define GLX_GLXEXT_PROTOTYPES'
print
- print '#include "dlopen.hpp"'
print '#include "glproc.hpp"'
print '#include "glsize.hpp"'
print
@@ -178,52 +177,3 @@ if __name__ == '__main__':
api.addModule(module)
tracer = GlxTracer()
tracer.traceApi(api)
-
- print r'''
-
-
-/*
- * Several applications, such as Quake3, use dlopen("libGL.so.1"), but
- * LD_PRELOAD does not intercept symbols obtained via dlopen/dlsym, therefore
- * we need to intercept the dlopen() call here, and redirect to our wrapper
- * shared object.
- */
-extern "C" PUBLIC
-void * dlopen(const char *filename, int flag)
-{
- void *handle;
-
- handle = _dlopen(filename, flag);
-
- const char * libgl_filename = getenv("TRACE_LIBGL");
-
- if (filename && handle && !libgl_filename) {
- if (0) {
- os::log("apitrace: warning: dlopen(\"%s\", 0x%x)\n", filename, flag);
- }
-
- // FIXME: handle absolute paths and other versions
- if (strcmp(filename, "libGL.so") == 0 ||
- strcmp(filename, "libGL.so.1") == 0) {
-
- // Use the true libGL.so handle instead of RTLD_NEXT from now on
- _libGlHandle = handle;
-
- // Get the file path for our shared object, and use it instead
- static int dummy = 0xdeedbeef;
- Dl_info info;
- if (dladdr(&dummy, &info)) {
- os::log("apitrace: redirecting dlopen(\"%s\", 0x%x)\n", filename, flag);
- handle = _dlopen(info.dli_fname, flag);
- } else {
- os::log("apitrace: warning: dladdr() failed\n");
- }
- }
- }
-
- return handle;
-}
-
-
-
-'''