dll.c revision e0e0c19eefceaf5d4ec40f9466b58a771f50e799
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/* Copyright (c) 2001, Stanford University
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * All rights reserved
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * See the file LICENSE.txt for information on redistributing this software.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync#include "cr_mem.h"
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#include "cr_error.h"
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync#include "cr_dll.h"
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync#include "cr_string.h"
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync#include "stdio.h"
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync#if defined(IRIX) || defined(IRIX64) || defined(Linux) || defined(FreeBSD) || defined(AIX) || defined(DARWIN) || defined(SunOS) || defined(OSF1)
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync#include <dlfcn.h>
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync#endif
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#ifdef DARWIN
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#include <Carbon/Carbon.h>
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#include <mach-o/dyld.h>
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncchar *__frameworkErr=NULL;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncCFBundleRef LoadFramework( const char *frameworkName ) {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync CFBundleRef bundle;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync CFURLRef bundleURL;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync char fullfile[8096];
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if( frameworkName[0] != '/' ) {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* load a system framework */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* XXX \todo should this folder be retrieved from somewhere else? */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync crStrcpy( fullfile, "/System/Library/Frameworks/" );
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync crStrcat( fullfile, frameworkName );
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync } else {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* load any framework */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync crStrcpy( fullfile, frameworkName );
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync bundleURL = CFURLCreateWithString( NULL, CFStringCreateWithCStringNoCopy(NULL, fullfile, CFStringGetSystemEncoding(), NULL), NULL );
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if( !bundleURL ) {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync __frameworkErr = "Could not create OpenGL Framework bundle URL";
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync return NULL;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync bundle = CFBundleCreate( kCFAllocatorDefault, bundleURL );
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync CFRelease( bundleURL );
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if( !bundle ) {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync __frameworkErr = "Could not create OpenGL Framework bundle";
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync return NULL;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if( !CFBundleLoadExecutable(bundle) ) {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync __frameworkErr = "Could not load MachO executable";
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync return NULL;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync return bundle;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync}
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncchar *__bundleErr=NULL;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncvoid *LoadBundle( const char *filename ) {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync NSObjectFileImage fileImage;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync NSModule handle = NULL;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync char _filename[PATH_MAX];
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync __bundleErr = NULL;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if( filename[0] != '/' ) {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* default to a chromium bundle */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync crStrcpy( _filename, "/cr/lib/Darwin/" );
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync crStrcat( _filename, filename );
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync } else {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync crStrcpy( _filename, filename );
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync }
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync switch( NSCreateObjectFileImageFromFile(_filename, &fileImage) ) {
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync default:
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync case NSObjectFileImageFailure:
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync __bundleErr = "NSObjectFileImageFailure: Failure.";
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync break;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync case NSObjectFileImageInappropriateFile:
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync __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;
dll = (CRDLL *) crAlloc( sizeof( CRDLL ) );
dll->name = crStrdup( dllname );
#if defined(WINDOWS)
(void) resolveGlobal;
dll->hinstLib = LoadLibrary( 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", 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)
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 );
}