##########################################################################
#
-# Copyright 2008-2009 VMware, Inc.
+# Copyright 2008-2010 VMware, Inc.
# All Rights Reserved.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
##########################################################################/
-from base import *
-from glapi import glapi
-import trace
-
-
-glxapi = API("GLX")
+"""GLX tracing generator."""
-PROC = Opaque("__GLXextFuncPtr")
-glxapi.add_functions(glapi.functions)
-glxapi.add_functions([
- Function(PROC, "glXGetProcAddressARB", [(Alias("const GLubyte *", String), "procName")]),
- Function(PROC, "glXGetProcAddress", [(Alias("const GLubyte *", String), "procName")]),
-])
+from stdapi import API
+from glapi import glapi
+from glxapi import glxapi
+from gltrace import GlTracer
+from dispatch import function_pointer_type, function_pointer_value
-class GlxTracer(trace.Tracer):
+class GlxTracer(GlTracer):
def get_function_address(self, function):
- if function.name.startswith("glXGetProcAddress"):
- return 'dlsym(RTLD_NEXT, "%s")' % (function.name,)
- else:
- print ' if (!pglXGetProcAddress) {'
- print ' pglXGetProcAddress = (PglXGetProcAddress)dlsym(RTLD_NEXT, "glXGetProcAddress");'
- print ' if (!pglXGetProcAddress)'
- print ' Log::Abort();'
- print ' }'
- return 'pglXGetProcAddress((const GLubyte *)"%s")' % (function.name,)
+ return '__%s' % (function.name,)
def wrap_ret(self, function, instance):
- if function.name.startswith("glXGetProcAddress"):
- print ' if (%s) {' % instance
- for f in glxapi.functions:
- ptype = self.function_pointer_type(f)
- pvalue = self.function_pointer_value(f)
- print ' if(!strcmp("%s", (const char *)procName)) {' % f.name
- print ' %s = (%s)%s;' % (pvalue, ptype, instance)
- print ' %s = (%s)&%s;' % (instance, function.type, f.name);
- print ' }'
- print ' }'
+ if function.name in ("glXGetProcAddress", "glXGetProcAddressARB"):
+ print ' %s = __unwrap_proc_addr(procName, %s);' % (instance, instance)
if __name__ == '__main__':
print
print '#include <stdlib.h>'
print '#include <string.h>'
+ print
+ print '#ifndef _GNU_SOURCE'
+ print '#define _GNU_SOURCE // for dladdr'
+ print '#endif'
print '#include <dlfcn.h>'
- print '#include <X11/Xlib.h>'
- print '#include <GL/gl.h>'
- print '#include <GL/glext.h>'
- print '#include <GL/glx.h>'
- print '#include <GL/glxext.h>'
print
- print '#include "log.hpp"'
- print '#include "glhelpers.hpp"'
+ print '#include "trace_write.hpp"'
+ print
+ print '#include "glproc.hpp"'
+ print '#include "glsize.hpp"'
print
print 'extern "C" {'
print
+ print 'static __GLXextFuncPtr __unwrap_proc_addr(const GLubyte * procName, __GLXextFuncPtr procPtr);'
+ print
+
+ api = API()
+ api.add_api(glxapi)
+ api.add_api(glapi)
tracer = GlxTracer()
- tracer.trace_api(glxapi)
+ tracer.trace_api(api)
+
+ print 'static __GLXextFuncPtr __unwrap_proc_addr(const GLubyte * procName, __GLXextFuncPtr procPtr) {'
+ print ' if (!procPtr) {'
+ print ' return procPtr;'
+ print ' }'
+ 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 ' %s = (%s)procPtr;' % (pvalue, ptype)
+ print ' return (__GLXextFuncPtr)&%s;' % (f.name,)
+ print ' }'
+ 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.
+ */
+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");
+ return NULL;
+ }
+ }
+
+ handle = dlopen_ptr(filename, flag);
+
+ if (filename && handle) {
+ if (0) {
+ OS::DebugMessage("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;
+
+ // Get the file path for our shared object, and use it instead
+ static int dummy = 0xdeedbeef;
+ 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);
+ } else {
+ OS::DebugMessage("warning: dladdr() failed\n");
+ }
+ }
+ }
+
+ return handle;
+}
+
+'''
print '} /* extern "C" */'