dll.c revision 10ca321f3be6e9e0ad484f4684cab6532bea20e2
/* 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 <string.h>
#endif
#if defined(IRIX) || defined(IRIX64) || defined(Linux) || defined(FreeBSD) || defined(AIX) || defined(DARWIN) || defined(SunOS) || defined(OSF1)
#include <dlfcn.h>
#endif
#ifdef WINDOWS
#include <Shlwapi.h>
#endif
#ifdef DARWIN
#include <Carbon/Carbon.h>
#include <mach-o/dyld.h>
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)
char szPath[MAX_PATH];
(void) resolveGlobal;
# ifndef CR_NO_GL_SYSTEM_PATH
if (PathIsRelative(dllname))
{
size_t cbName = strlen(dllname) + 1;
# ifdef IN_GUEST
UINT cchPath = GetSystemDirectoryA(szPath, sizeof(szPath));
# else
UINT cchPath = GetModuleFileNameA(NULL, szPath, sizeof(szPath));
if (cchPath != 0 && cchPath <= sizeof(szPath))
{
char * pszSlashFile = strrchr(szPath, '\\');
if (pszSlashFile)
{
cchPath = pszSlashFile - szPath;
}
}
# endif
if (cchPath + 1 + cbName > sizeof(szPath))
{
crError("invalid path specified");
SetLastError(ERROR_FILENAME_EXCED_RANGE);
return NULL;
}
szPath[cchPath] = '\\';
memcpy(&szPath[cchPath + 1], dllname, cbName);
dllname = szPath;
}
# endif // CR_NO_GL_SYSTEM_PATH
#endif
dll = (CRDLL *) crAlloc( sizeof( CRDLL ) );
dll->name = crStrdup( dllname );
#if defined(WINDOWS)
dll->hinstLib = LoadLibrary( dllname );
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 );
}