void * dlopen (const char *path, int mode) { void *(*_dlopen) (const char *path, int mode); char *new_path = NULL; void *result; _dlopen = (void *(*)(const char *path, int mode)) dlsym (RTLD_NEXT, "dlopen"); if (path && path[0] == '/') { new_path = redirect_path (path); result = _dlopen (new_path, mode); free (new_path); } else { // non-absolute library paths aren't simply relative paths, they need // a whole lookup algorithm result = _dlopen (path, mode); } return result; }
/* * 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; }