X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=glxtrace.py;h=6b5d786b6d91ff16f1562ceb9790f544481d51ed;hb=b5f2ee344ef2914ca141608107c571ec0c28c6a6;hp=a5317a4b74888f56c89142b29501a3c5832e3347;hpb=0ad49cbe3446dfe8404516852c904b40cf909c7c;p=apitrace diff --git a/glxtrace.py b/glxtrace.py index a5317a4..6b5d786 100644 --- a/glxtrace.py +++ b/glxtrace.py @@ -1,5 +1,6 @@ ########################################################################## # +# Copyright 2011 Jose Fonseca # Copyright 2008-2010 VMware, Inc. # All Rights Reserved. # @@ -36,10 +37,30 @@ from dispatch import function_pointer_type, function_pointer_value class GlxTracer(GlTracer): - def get_function_address(self, function): - return '__%s' % (function.name,) + def is_public_function(self, function): + # The symbols visible in libGL.so can vary, so expose them all + return True + + def trace_function_impl_body(self, function): + GlTracer.trace_function_impl_body(self, function) + + # Take snapshots + if function.name == 'glXSwapBuffers': + print ' glsnapshot::snapshot(__call);' + if function.name in ('glFinish', 'glFlush'): + print ' GLint __draw_framebuffer = 0;' + print ' __glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &__draw_framebuffer);' + print ' if (__draw_framebuffer == 0) {' + print ' GLint __draw_buffer = GL_NONE;' + print ' __glGetIntegerv(GL_DRAW_BUFFER, &__draw_buffer);' + print ' if (__draw_buffer == GL_FRONT) {' + print ' glsnapshot::snapshot(__call);' + print ' }' + print ' }' def wrap_ret(self, function, instance): + GlTracer.wrap_ret(self, function, instance) + if function.name in ("glXGetProcAddress", "glXGetProcAddressARB"): print ' %s = __unwrap_proc_addr(procName, %s);' % (instance, instance) @@ -54,12 +75,15 @@ if __name__ == '__main__': print '#endif' print '#include ' print - print '#include "trace_write.hpp"' + print '#include "trace_writer.hpp"' + print + print '// To validate our prototypes' + print '#define GL_GLEXT_PROTOTYPES' + print '#define GLX_GLXEXT_PROTOTYPES' print print '#include "glproc.hpp"' print '#include "glsize.hpp"' - print - print 'extern "C" {' + print '#include "glsnapshot.hpp"' print print 'static __GLXextFuncPtr __unwrap_proc_addr(const GLubyte * procName, __GLXextFuncPtr procPtr);' print @@ -77,45 +101,67 @@ if __name__ == '__main__': for f in api.functions: ptype = function_pointer_type(f) pvalue = function_pointer_value(f) - print ' if(!strcmp("%s", (const char *)procName)) {' % f.name + print ' if (strcmp("%s", (const char *)procName) == 0) {' % f.name print ' %s = (%s)procPtr;' % (pvalue, ptype) print ' return (__GLXextFuncPtr)&%s;' % (f.name,) print ' }' + print ' OS::DebugMessage("apitrace: warning: unknown function \\"%s\\"\\n", (const char *)procName);' print ' return procPtr;' print '}' print 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. + * Handle to the true libGL.so + */ +static void *libgl_handle = NULL; + + +/* + * Invoke the true dlopen() function. */ -void *dlopen(const char *filename, int flag) +static void *__dlopen(const char *filename, int flag) { typedef void * (*PFNDLOPEN)(const char *, int); static PFNDLOPEN dlopen_ptr = NULL; - void *handle; if (!dlopen_ptr) { dlopen_ptr = (PFNDLOPEN)dlsym(RTLD_NEXT, "dlopen"); if (!dlopen_ptr) { - OS::DebugMessage("error: dlsym(RTLD_NEXT, \"dlopen\") failed\n"); + OS::DebugMessage("apitrace: error: dlsym(RTLD_NEXT, \"dlopen\") failed\n"); return NULL; } } - handle = dlopen_ptr(filename, flag); + return dlopen_ptr(filename, flag); +} + + +/* + * 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 && handle) { + handle = __dlopen(filename, flag); + + const char * libgl_filename = getenv("TRACE_LIBGL"); + + if (filename && handle && !libgl_filename) { if (0) { - OS::DebugMessage("warning: dlopen(\"%s\", 0x%x)\n", filename, flag); + OS::DebugMessage("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 libgl_handle = handle; @@ -124,9 +170,9 @@ void *dlopen(const char *filename, int flag) Dl_info info; if (dladdr(&dummy, &info)) { OS::DebugMessage("apitrace: redirecting dlopen(\"%s\", 0x%x)\n", filename, flag); - handle = dlopen_ptr(info.dli_fname, flag); + handle = __dlopen(info.dli_fname, flag); } else { - OS::DebugMessage("warning: dladdr() failed\n"); + OS::DebugMessage("apitrace: warning: dladdr() failed\n"); } } } @@ -134,5 +180,52 @@ void *dlopen(const char *filename, int flag) return handle; } + +/* + * Lookup a libGL symbol + */ +void * __libgl_sym(const char *symbol) +{ + void *result; + + if (!libgl_handle) { + /* + * The app doesn't directly link against libGL.so, nor does it directly + * dlopen it. So we have to load it ourselves. + */ + + const char * libgl_filename = getenv("TRACE_LIBGL"); + + if (!libgl_filename) { + /* + * Try to use whatever libGL.so the library is linked against. + */ + + result = dlsym(RTLD_NEXT, symbol); + if (result) { + libgl_handle = RTLD_NEXT; + return result; + } + + libgl_filename = "libGL.so.1"; + } + + /* + * It would have been preferable to use RTLD_LOCAL to ensure that the + * application can never access libGL.so symbols directly, but this + * won't work, given libGL.so often loads a driver specific SO and + * exposes symbols to it. + */ + + libgl_handle = __dlopen(libgl_filename, RTLD_GLOBAL | RTLD_LAZY); + if (!libgl_handle) { + OS::DebugMessage("apitrace: error: couldn't find libGL.so\n"); + return NULL; + } + } + + return dlsym(libgl_handle, symbol); +} + + ''' - print '} /* extern "C" */'