/* Copyright (c) 2001, Stanford University * All rights reserved * * See the file LICENSE.txt for information on redistributing this software. */ #include "cr_mem.h" #include "cr_error.h" #include "cr_dll.h" #include "cr_string.h" #include "stdio.h" #ifndef IN_GUEST #include #endif #if defined(IRIX) || defined(IRIX64) || defined(Linux) || defined(FreeBSD) || defined(AIX) || defined(DARWIN) || defined(SunOS) || defined(OSF1) #include #endif #ifdef WINDOWS #include #endif #ifdef DARWIN #include #include char *__frameworkErr=NULL; CFBundleRef LoadFramework( const char *frameworkName ) { CFBundleRef bundle; CFURLRef bundleURL; char fullfile[8096]; if( frameworkName[0] != '/' ) { /* load a system framework */ /* XXX \todo should this folder be retrieved from somewhere else? */ crStrcpy( fullfile, "/System/Library/Frameworks/" ); crStrcat( fullfile, frameworkName ); } else { /* load any framework */ crStrcpy( fullfile, frameworkName ); } bundleURL = CFURLCreateWithString( NULL, CFStringCreateWithCStringNoCopy(NULL, fullfile, CFStringGetSystemEncoding(), NULL), NULL ); if( !bundleURL ) { __frameworkErr = "Could not create OpenGL Framework bundle URL"; return NULL; } bundle = CFBundleCreate( kCFAllocatorDefault, bundleURL ); CFRelease( bundleURL ); if( !bundle ) { __frameworkErr = "Could not create OpenGL Framework bundle"; return NULL; } if( !CFBundleLoadExecutable(bundle) ) { __frameworkErr = "Could not load MachO executable"; return NULL; } return bundle; } char *__bundleErr=NULL; void *LoadBundle( const char *filename ) { NSObjectFileImage fileImage; NSModule handle = NULL; char _filename[PATH_MAX]; __bundleErr = NULL; if( filename[0] != '/' ) { /* default to a chromium bundle */ crStrcpy( _filename, "/cr/lib/Darwin/" ); crStrcat( _filename, filename ); } else { crStrcpy( _filename, filename ); } switch( NSCreateObjectFileImageFromFile(_filename, &fileImage) ) { default: case NSObjectFileImageFailure: __bundleErr = "NSObjectFileImageFailure: Failure."; break; case NSObjectFileImageInappropriateFile: __bundleErr = "NSObjectFileImageInappropriateFile: The specified file is not of a valid type."; break; case NSObjectFileImageArch: __bundleErr = "NSObjectFileImageArch: The specified file is for a different CPU architecture."; break; case NSObjectFileImageFormat: __bundleErr = "NSObjectFileImageFormat: The specified file does not appear to be a Mach-O file"; break; case NSObjectFileImageAccess: __bundleErr = "NSObjectFileImageAccess: Permission to create image denied."; break; case NSObjectFileImageSuccess: handle = NSLinkModule( fileImage, _filename, NSLINKMODULE_OPTION_RETURN_ON_ERROR | NSLINKMODULE_OPTION_PRIVATE ); NSDestroyObjectFileImage( fileImage ); if( !handle ) { NSLinkEditErrors c; int n; const char *name; NSLinkEditError(&c, &n, &name, (const char**)&__bundleErr); } break; } return handle; } int check_extension( const char *name, const char *extension ) { int nam_len = crStrlen( name ); int ext_len = crStrlen( extension ); char *pos = crStrstr( name, extension ); return ( pos == &(name[nam_len-ext_len]) ); } enum { CR_DLL_NONE, CR_DLL_FRAMEWORK, CR_DLL_DYLIB, CR_DLL_BUNDLE, CR_DLL_UNKNOWN }; #define NS_ADD 0 int get_dll_type( const char *name ) { if( check_extension(name, ".framework") ) return CR_DLL_FRAMEWORK; if( check_extension(name, ".bundle") ) return CR_DLL_BUNDLE; if( check_extension(name, ".dylib") ) return CR_DLL_DYLIB; return CR_DLL_DYLIB; } #endif /* * Open the named shared library. * If resolveGlobal is non-zero, unresolved symbols can be satisfied by * any matching symbol already defined globally. Otherwise, if resolveGlobal * is zero, unresolved symbols should be resolved using symbols in that * object (in preference to global symbols). * NOTE: this came about because we found that for libGL, we need the * global-resolve option but for SPU's we need the non-global option (consider * the state tracker duplicated in the array, tilesort, etc. SPUs). */ CRDLL *crDLLOpen( const char *dllname, int resolveGlobal ) { CRDLL *dll; char *dll_err; #if defined(WINDOWS) WCHAR szwPath[MAX_PATH]; UINT cwcPath = 0; (void) resolveGlobal; # ifndef CR_NO_GL_SYSTEM_PATH if (PathIsRelative(dllname)) { size_t cName = strlen(dllname) + 1; # ifdef IN_GUEST cwcPath = GetSystemDirectoryW(szwPath, RT_ELEMENTS(szwPath)); if (!cwcPath || cwcPath >= MAX_PATH) { DWORD winEr = GetLastError(); crError("GetSystemDirectoryW failed err %d", winEr); SetLastError(winEr); return NULL; } # else WCHAR * pszwSlashFile; cwcPath = GetModuleFileNameW(NULL, szwPath, RT_ELEMENTS(szwPath)); if (!cwcPath || cwcPath >= MAX_PATH) { DWORD winEr = GetLastError(); crError("GetModuleFileNameW failed err %d", winEr); SetLastError(winEr); return NULL; } pszwSlashFile = wcsrchr(szwPath, L'\\'); if (!pszwSlashFile) { crError("failed to match file name"); SetLastError(ERROR_PATH_NOT_FOUND); return NULL; } cwcPath = pszwSlashFile - szwPath; # endif if (cwcPath + 1 + cName > MAX_PATH) { crError("invalid path specified"); SetLastError(ERROR_FILENAME_EXCED_RANGE); return NULL; } szwPath[cwcPath] = '\\'; ++cwcPath; } if (!MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, dllname, -1, &szwPath[cwcPath], MAX_PATH - cwcPath)) { DWORD winEr = GetLastError(); crError("MultiByteToWideChar failed err %d", winEr); SetLastError(winEr); return NULL; } # endif // CR_NO_GL_SYSTEM_PATH #endif dll = (CRDLL *) crAlloc( sizeof( CRDLL ) ); dll->name = crStrdup( dllname ); #if defined(WINDOWS) dll->hinstLib = LoadLibraryW( szwPath ); if (!dll->hinstLib) { crError("failed to load dll %s", dllname); } dll_err = NULL; #elif defined(DARWIN) /* XXX \todo Get better error handling in here */ dll->type = get_dll_type( dllname ); dll_err = NULL; switch( dll->type ) { case CR_DLL_FRAMEWORK: dll->hinstLib = LoadFramework( dllname ); dll_err = __frameworkErr; break; case CR_DLL_BUNDLE: dll->hinstLib = LoadBundle( dllname ); dll_err = __bundleErr; break; case CR_DLL_DYLIB: #if NS_ADD dll->hinstLib = (void*)NSAddImage( dllname, NSADDIMAGE_OPTION_RETURN_ON_ERROR ); #else if( resolveGlobal ) dll->hinstLib = dlopen( dllname, RTLD_LAZY | RTLD_GLOBAL ); else dll->hinstLib = dlopen( dllname, RTLD_LAZY | RTLD_LOCAL ); dll_err = (char*) dlerror(); #endif break; default: dll->hinstLib = NULL; dll_err = "Unknown DLL type"; break; }; #elif defined(IRIX) || defined(IRIX64) || defined(Linux) || defined(FreeBSD) || defined(AIX) || defined(SunOS) || defined(OSF1) if (resolveGlobal) dll->hinstLib = dlopen( dllname, RTLD_LAZY | RTLD_GLOBAL ); else dll->hinstLib = dlopen( dllname, RTLD_LAZY ); dll_err = (char*) dlerror(); #else #error DSO #endif if (!dll->hinstLib) { if (dll_err) { crDebug( "DLL_ERROR(%s): %s", dllname, dll_err ); } crError( "DLL Loader couldn't find/open %s", dllname ); } return dll; } CRDLLFunc crDLLGetNoError( CRDLL *dll, const char *symname ) { #if defined(WINDOWS) return (CRDLLFunc) GetProcAddress( dll->hinstLib, symname ); #elif defined(DARWIN) NSSymbol nssym; if( dll->type == CR_DLL_FRAMEWORK ) return (CRDLLFunc) CFBundleGetFunctionPointerForName( (CFBundleRef) dll->hinstLib, CFStringCreateWithCStringNoCopy(NULL, symname, CFStringGetSystemEncoding(), NULL) ); if( dll->type == CR_DLL_DYLIB ) #if NS_ADD nssym = NSLookupSymbolInImage( dll->hinstLib, symname, NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR ); #else return (CRDLLFunc) dlsym( dll->hinstLib, symname ); #endif else nssym = NSLookupSymbolInModule( dll->hinstLib, symname ); if( !nssym ) { char name[PATH_MAX]; crStrcpy( name, "_" ); crStrcat( name, symname ); if( dll->type == CR_DLL_DYLIB ) nssym = NSLookupSymbolInImage( dll->hinstLib, name, NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR ); else nssym = NSLookupSymbolInModule( dll->hinstLib, name ); } return (CRDLLFunc) NSAddressOfSymbol( nssym ); #elif defined(IRIX) || defined(IRIX64) || defined(Linux) || defined(FreeBSD) || defined(AIX) || defined(SunOS) || defined(OSF1) return (CRDLLFunc) dlsym( dll->hinstLib, symname ); #else #error CR DLL ARCHITETECTURE #endif } CRDLLFunc crDLLGet( CRDLL *dll, const char *symname ) { CRDLLFunc data = crDLLGetNoError( dll, symname ); if (!data) { /* Are you sure there isn't some C++ mangling messing you up? */ crWarning( "Couldn't get symbol \"%s\" in \"%s\"", symname, dll->name ); } return data; } void crDLLClose( CRDLL *dll ) { int dll_err = 0; if (!dll) return; #if defined(WINDOWS) FreeLibrary( dll->hinstLib ); #elif defined(DARWIN) switch( dll->type ) { case CR_DLL_FRAMEWORK: CFBundleUnloadExecutable( dll->hinstLib ); CFRelease(dll->hinstLib); dll->hinstLib = NULL; break; case CR_DLL_DYLIB: #if !NS_ADD dlclose( dll->hinstLib ); #endif break; case CR_DLL_BUNDLE: NSUnLinkModule( (NSModule) dll->hinstLib, 0L ); break; } #elif defined(IRIX) || defined(IRIX64) || defined(Linux) || defined(FreeBSD) || defined(AIX) || defined(SunOS) || defined(OSF1) /* * Unloading Nvidia's libGL will crash VirtualBox later during shutdown. * Therefore we will skip unloading it. It will be unloaded later anway * because we are already freeing all resources and VirtualBox will terminate * soon. */ #ifndef IN_GUEST if (strncmp(dll->name, "libGL", 5)) #endif dll_err = dlclose( dll->hinstLib ); #else #error DSO #endif if (dll_err) crWarning("Error closing DLL %s\n",dll->name); crFree( dll->name ); crFree( dll ); }