diff options
author | wtc%netscape.com <devnull@localhost> | 2003-01-14 23:27:27 +0000 |
---|---|---|
committer | wtc%netscape.com <devnull@localhost> | 2003-01-14 23:27:27 +0000 |
commit | ea443b0900a28a8063fef6f6407b84f4388fb7f6 (patch) | |
tree | a79727dfc85d7564ccf36168d7730227a10efa1d | |
parent | 56cb4035007abfcfe7d6cd1bea966d5244cdf566 (diff) | |
download | nspr-hg-ea443b0900a28a8063fef6f6407b84f4388fb7f6.tar.gz |
Bug 186599: 1. added support for relative paths to PR_LoadLibrary on
Mac OS X. 2. Reordered the Mac code in pr_LoadLibraryByPathName to try
loading various kinds of shared libraries in the order of most likely
success. The patch is contributed by Conrad Carlen <ccarlen@netscape.com>.
r=wtc. sr=sfraser.
Tag: NSPRPUB_PRE_4_2_CLIENT_BRANCH
-rw-r--r-- | pr/src/linking/prlink.c | 433 |
1 files changed, 237 insertions, 196 deletions
diff --git a/pr/src/linking/prlink.c b/pr/src/linking/prlink.c index 87a75b84..c34454e8 100644 --- a/pr/src/linking/prlink.c +++ b/pr/src/linking/prlink.c @@ -542,34 +542,21 @@ PR_LoadLibrary(const char *name) return PR_LoadLibraryWithFlags(libSpec, 0); } -#if TARGET_CARBON - -/* -** Returns a CFBundleRef if the FSSpec refers to a Mac OS X bundle directory. -** The caller is responsible for calling CFRelease() to deallocate. -*/ -static CFBundleRef getLibraryBundle(const FSSpec* spec) +#if defined(USE_MACH_DYLD) +static NSModule +pr_LoadMachDyldModule(const char *name) { - CFBundleRef bundle = NULL; - FSRef ref; - OSErr err = FSpMakeFSRef(spec, &ref); - char path[512]; - if (err == noErr && ((UInt32)(FSRefMakePath) != kUnresolvedCFragSymbolAddress)) { - err = FSRefMakePath(&ref, (UInt8*)path, sizeof(path) - 1); - if (err == noErr) { - CFStringRef pathRef = CFStringCreateWithCString(NULL, path, kCFStringEncodingUTF8); - if (pathRef) { - CFURLRef bundleURL = CFURLCreateWithFileSystemPath(NULL, pathRef, kCFURLPOSIXPathStyle, true); - if (bundleURL != NULL) { - bundle = CFBundleCreate(NULL, bundleURL); - CFRelease(bundleURL); - } - CFRelease(pathRef); - } - } + NSObjectFileImage ofi; + NSModule h = NULL; + if (NSCreateObjectFileImageFromFile(name, &ofi) + == NSObjectFileImageSuccess) { + h = NSLinkModule(ofi, name, NSLINKMODULE_OPTION_PRIVATE); } - return bundle; + return h; } +#endif + +#if defined(XP_MAC) || defined(XP_MACOSX) #ifdef XP_MACOSX static void* TV2FP(CFMutableDictionaryRef dict, const char* name, void *tvp) @@ -591,14 +578,12 @@ static void* TV2FP(CFMutableDictionaryRef dict, const char* name, void *tvp) MakeDataExecutable(newGlue, sizeof(glue)); CFDictionaryAddValue(dict, nameRef, glueData); CFRelease(glueData); -#ifdef DEBUG - printf("[TV2FP: created wrapper for CFM function %s().]\n", name); -#endif + + PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("TV2FP: created wrapper for CFM function %s().", name)); } } else { -#ifdef DEBUG - printf("[TV2FP: found wrapper for CFM function %s().]\n", name); -#endif + PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("TV2FP: found wrapper for CFM function %s().", name)); + newGlue = (uint32*) CFDataGetMutableBytePtr(glueData); } CFRelease(nameRef); @@ -609,90 +594,25 @@ static void* TV2FP(CFMutableDictionaryRef dict, const char* name, void *tvp) } #endif -#endif - /* -** Dynamically load a library. Only load libraries once, so scan the load -** map first. +** macLibraryLoadProc is a function definition for a Mac shared library +** loading method. The "name" param is the same full or partial pathname +** that was passed to pr_LoadLibraryByPathName. The function must fill +** in the fields of "lm" which apply to its library type. Returns +** PR_SUCCESS if successful. */ -static PRLibrary* -pr_LoadLibraryByPathname(const char *name, PRIntn flags) -{ - PRLibrary *lm; - PRLibrary* result; - PRInt32 oserr; - if (!_pr_initialized) _PR_ImplicitInitialization(); - - /* See if library is already loaded */ - PR_EnterMonitor(pr_linker_lock); - - result = pr_UnlockedFindLibrary(name); - if (result != NULL) goto unlock; - - lm = PR_NEWZAP(PRLibrary); - if (lm == NULL) { - oserr = _MD_ERRNO(); - goto unlock; - } - lm->staticTable = NULL; - -#ifdef XP_OS2 /* Why isn't all this stuff in MD code?! */ - { - HMODULE h; - UCHAR pszError[_MAX_PATH]; - ULONG ulRc = NO_ERROR; - - retry: - ulRc = DosLoadModule(pszError, _MAX_PATH, (PSZ) name, &h); - if (ulRc != NO_ERROR) { - oserr = ulRc; - PR_DELETE(lm); - goto unlock; - } - lm->name = strdup(name); - lm->dlh = h; - lm->next = pr_loadmap; - pr_loadmap = lm; - } -#endif /* XP_OS2 */ - -#if defined(WIN32) || defined(WIN16) - { - HINSTANCE h; - NODL_PROC *pfn; - - h = LoadLibrary(name); - if (h < (HINSTANCE)HINSTANCE_ERROR) { - oserr = _MD_ERRNO(); - PR_DELETE(lm); - goto unlock; - } - lm->name = strdup(name); - lm->dlh = h; - lm->next = pr_loadmap; - pr_loadmap = lm; - - /* - ** Try to load a table of "static functions" provided by the DLL - */ - - pfn = (NODL_PROC *)GetProcAddress(h, "NODL_TABLE"); - if (pfn != NULL) { - lm->staticTable = (*pfn)(); - } - } -#endif /* WIN32 || WIN16 */ - -#if (defined(XP_MAC) && TARGET_RT_MAC_CFM) || defined(XP_MACOSX) - { - OSErr err; - Str255 errName; - Str255 pName; - char cName[64]; - const char* libName; +typedef PRStatus (*macLibraryLoadProc)(const char *name, PRLibrary *lm); +static PRStatus +pr_LoadViaCFM(const char *name, PRLibrary *lm) +{ + OSErr err; + char cName[64]; + Str255 errName; + #if !defined(XP_MACOSX) + Str255 pName; /* * Algorithm: The "name" passed in could be either a shared * library name that we should look for in the normal library @@ -712,17 +632,20 @@ pr_LoadLibraryByPathname(const char *name, PRIntn flags) * and try to find the library. */ } else { - /* name contained a "/" which means we need to suck off the last part */ - /* of the path and pass that on the NSGetSharedLibrary */ - /* this may not be what we really want to do .. because Java could */ - /* be iterating through the whole LD path, and we'll find it if it's */ - /* anywhere on that path -- it appears that's what UNIX and the PC do */ - /* too...so we'll emulate but it could be wrong. */ + /* + * name contained a "/" which means we need to suck off + * the last part of the path and pass that on the + * NSGetSharedLibrary. this may not be what we really + * want to do .. because Java could be iterating through + * the whole LD path, and we'll find it if it's anywhere + * on that path -- it appears that's what UNIX and the + * PC do too...so we'll emulate but it could be wrong. + */ name = strrchr(name, PR_DIRECTORY_SEPARATOR) + 1; } - + PStrFromCStr(name, pName); - + /* * beard: NSGetSharedLibrary was so broken that I just decided to * use GetSharedLibrary for now. This will need to change for @@ -730,14 +653,10 @@ pr_LoadLibraryByPathname(const char *name, PRIntn flags) */ err = GetSharedLibrary(pName, kCompiledCFragArch, kReferenceCFrag, &lm->connection, &lm->main, errName); - if (err != noErr) { - oserr = err; - PR_DELETE(lm); - goto unlock; - } - - libName = name; - } else + if (err != noErr) + return PR_FAILURE; + } + else #endif { /* @@ -745,13 +664,8 @@ pr_LoadLibraryByPathname(const char *name, PRIntn flags) * Now we have to do a lot of work to convert the path name to * an FSSpec (silly, since we were probably just called from the * MacFE plug-in code that already knew the FSSpec and converted - * it to a full path just to pass to us). First we copy out the - * volume name (the text leading up to the first ":"); then we - * separate the file name (the text following the last ":") from - * rest of the path. After converting the strings to Pascal - * format we can call GetCatInfo to get the parent directory ID - * of the file, and then (finally) make an FSSpec and call - * GetDiskFragment. + * it to a full path just to pass to us). Make an FSSpec from + * the full path and call GetDiskFragment. */ FSSpec fileSpec; Boolean tempUnusedBool; @@ -762,31 +676,24 @@ pr_LoadLibraryByPathname(const char *name, PRIntn flags) FSRef ref; err = FSPathMakeRef((const UInt8*)name, &ref, NULL); if (err == noErr) - err = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, &fileSpec, NULL); + err = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, + &fileSpec, NULL); } #else PStrFromCStr(name, pName); err = FSMakeFSSpec(0, 0, pName, &fileSpec); #endif - if (err != noErr) { - oserr = _MD_ERRNO(); - PR_DELETE(lm); - goto unlock; - } + if (err != noErr) + return PR_FAILURE; /* Resolve an alias if this was one */ - err = ResolveAliasFile(&fileSpec, true, &tempUnusedBool, &tempUnusedBool); - if (err != noErr) { -#ifdef DEBUG - printf("[NSPR: oops couldn't resolve an alias.]\n"); -#endif - oserr = err; - PR_DELETE(lm); - goto unlock; - } + err = ResolveAliasFile(&fileSpec, true, &tempUnusedBool, + &tempUnusedBool); + if (err != noErr) + return PR_FAILURE; /* Finally, try to load the library */ - err = GetDiskFragment(&fileSpec, 0, kCFragGoesToEOF, fileSpec.name, + err = GetDiskFragment(&fileSpec, 0, kCFragGoesToEOF, fileSpec.name, kLoadCFrag, &lm->connection, &lm->main, errName); #if TARGET_CARBON @@ -795,61 +702,202 @@ pr_LoadLibraryByPathname(const char *name, PRIntn flags) memcpy(cName, fileSpec.name + 1, fileSpec.name[0]); cName[fileSpec.name[0]] = '\0'; #endif - libName = cName; #ifdef XP_MACOSX if (err == noErr && lm->connection) { - /* if we're a mach-o binary, need to wrap all CFM function pointers. */ - /* need a hash-table of already seen function pointers, etc. */ + /* + * if we're a mach-o binary, need to wrap all CFM function + * pointers. need a hash-table of already seen function + * pointers, etc. + */ lm->wrappers = CFDictionaryCreateMutable(NULL, 16, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); if (lm->wrappers) { lm->main = TV2FP(lm->wrappers, "main", lm->main); - } + } else + err = memFullErr; } #endif - - if (err != noErr) { + } + return (err == noErr) ? PR_SUCCESS : PR_FAILURE; +} + +/* +** Creates a CFBundleRef if the pathname refers to a Mac OS X bundle +** directory. The caller is responsible for calling CFRelease() to +** deallocate. +*/ + #if TARGET_CARBON - /* If not a CFM library, perhaps it's a CFBundle. */ - lm->bundle = getLibraryBundle(&fileSpec); -#ifdef DEBUG - if (lm->bundle) printf("[NSPR: bundle loaded succesfully: %s]\n", name); -#endif - if (lm->bundle == NULL) { -#if defined(USE_MACH_DYLD) - goto next; +static PRStatus +pr_LoadCFBundle(const char *name, PRLibrary *lm) +{ + CFURLRef bundleURL; + CFBundleRef bundle = NULL; + +#ifdef XP_MACOSX + char pathBuf[PATH_MAX]; + const char *resolvedPath; + CFStringRef pathRef; + + /* Takes care of relative paths and symlinks */ + resolvedPath = realpath(name, pathBuf); + if (!resolvedPath) + return PR_FAILURE; + + pathRef = CFStringCreateWithCString(NULL, pathBuf, kCFStringEncodingUTF8); + if (pathRef) { + bundleURL = CFURLCreateWithFileSystemPath(NULL, pathRef, + kCFURLPOSIXPathStyle, true); + if (bundleURL) { + bundle = CFBundleCreate(NULL, bundleURL); + CFRelease(bundleURL); + } + CFRelease(pathRef); + } #else - oserr = err; - PR_DELETE(lm); - goto unlock; + OSErr err; + Str255 pName; + FSSpec fsSpec; + FSRef fsRef; + + if ((UInt32)(CFURLCreateFromFSRef) == kUnresolvedCFragSymbolAddress) + return PR_FAILURE; + PStrFromCStr(name, pName); + err = FSMakeFSSpec(0, 0, pName, &fsSpec); + if (err != noErr) + return PR_FAILURE; + err = FSpMakeFSRef(&fsSpec, &fsRef); + if (err != noErr) + return PR_FAILURE; + bundleURL = CFURLCreateFromFSRef(NULL, &fsRef); + if (bundleURL) { + bundle = CFBundleCreate(NULL, bundleURL); + CFRelease(bundleURL); + } #endif - } -#else - oserr = err; - PR_DELETE(lm); - goto unlock; + + lm->bundle = bundle; + return (bundle != NULL) ? PR_SUCCESS : PR_FAILURE; +} #endif - } + +#ifdef XP_MACOSX +static PRStatus +pr_LoadViaDyld(const char *name, PRLibrary *lm) +{ + lm->dlh = pr_LoadMachDyldModule(name); + return (lm->dlh != NULL) ? PR_SUCCESS : PR_FAILURE; +} +#endif + +#endif /* defined(XP_MAC) || defined(XP_MACOSX) */ + +/* +** Dynamically load a library. Only load libraries once, so scan the load +** map first. +*/ +static PRLibrary* +pr_LoadLibraryByPathname(const char *name, PRIntn flags) +{ + PRLibrary *lm; + PRLibrary* result; + PRInt32 oserr; + + if (!_pr_initialized) _PR_ImplicitInitialization(); + + /* See if library is already loaded */ + PR_EnterMonitor(pr_linker_lock); + + result = pr_UnlockedFindLibrary(name); + if (result != NULL) goto unlock; + + lm = PR_NEWZAP(PRLibrary); + if (lm == NULL) { + oserr = _MD_ERRNO(); + goto unlock; } - - lm->name = strdup(libName); + lm->staticTable = NULL; + +#ifdef XP_OS2 /* Why isn't all this stuff in MD code?! */ + { + HMODULE h; + UCHAR pszError[_MAX_PATH]; + ULONG ulRc = NO_ERROR; + + retry: + ulRc = DosLoadModule(pszError, _MAX_PATH, (PSZ) name, &h); + if (ulRc != NO_ERROR) { + oserr = ulRc; + PR_DELETE(lm); + goto unlock; + } + lm->name = strdup(name); + lm->dlh = h; + lm->next = pr_loadmap; + pr_loadmap = lm; + } +#endif /* XP_OS2 */ + +#if defined(WIN32) || defined(WIN16) + { + HINSTANCE h; + NODL_PROC *pfn; + + h = LoadLibrary(name); + if (h < (HINSTANCE)HINSTANCE_ERROR) { + oserr = _MD_ERRNO(); + PR_DELETE(lm); + goto unlock; + } + lm->name = strdup(name); + lm->dlh = h; lm->next = pr_loadmap; pr_loadmap = lm; + /* - * we need to initalize the refCount here because the goto success skips over - * the code which would ordinarily set it below (below the #ifdef XP_UNIX - * code.) This is ugly, but there is no truly good way to deal with this - * without re-writing this function. - */ - lm->refCount = 1; - goto success; + ** Try to load a table of "static functions" provided by the DLL + */ + + pfn = (NODL_PROC *)GetProcAddress(h, "NODL_TABLE"); + if (pfn != NULL) { + lm->staticTable = (*pfn)(); + } } - next: +#endif /* WIN32 || WIN16 */ + +#if defined(XP_MAC) || defined(XP_MACOSX) + { + int i; + PRStatus status; + + static const macLibraryLoadProc loadProcs[] = { +#if defined(XP_MACOSX) + pr_LoadViaDyld, pr_LoadCFBundle, pr_LoadViaCFM +#elif TARGET_CARBON + pr_LoadViaCFM, pr_LoadCFBundle +#else + pr_LoadViaCFM #endif + }; -#ifdef XP_UNIX + for (i = 0; i < sizeof(loadProcs) / sizeof(loadProcs[0]); i++) { + if ((status = loadProcs[i](name, lm)) == PR_SUCCESS) + break; + } + if (status != PR_SUCCESS) { + oserr = cfragNoLibraryErr; + PR_DELETE(lm); + goto unlock; + } + lm->name = strdup(name); + lm->next = pr_loadmap; + pr_loadmap = lm; + } +#endif + +#if defined(XP_UNIX) && !defined(XP_MACOSX) #ifdef HAVE_DLL { #if defined(USE_DLFCN) @@ -895,12 +943,7 @@ pr_LoadLibraryByPathname(const char *name, PRIntn flags) /* No equivalent of PR_LD_GLOBAL and PR_LD_LOCAL. */ h = shl_load(name, shl_flags, 0L); #elif defined(USE_MACH_DYLD) - NSObjectFileImage ofi; - NSModule h = NULL; - if (NSCreateObjectFileImageFromFile(name, &ofi) - == NSObjectFileImageSuccess) { - h = NSLinkModule(ofi, name, NSLINKMODULE_OPTION_PRIVATE); - } + NSModule h = pr_LoadMachDyldModule(name); #else #error Configuration error #endif @@ -1009,7 +1052,6 @@ pr_LoadLibraryByPathname(const char *name, PRIntn flags) } #endif - success: result = lm; /* success */ PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Loaded library %s (load lib)", lm->name)); @@ -1213,7 +1255,7 @@ PR_UnloadLibrary(PRLibrary *lib) } #endif /* XP_PC */ -#if (defined(XP_MAC) && TARGET_RT_MAC_CFM) || defined(XP_MACOSX) +#if defined(XP_MAC) || defined(XP_MACOSX) /* Close the connection */ if (lib->connection) CloseConnection(&(lib->connection)); @@ -1322,9 +1364,8 @@ pr_FindSymbolInLib(PRLibrary *lm, const char *name) CFragSymbolClass symClass; Str255 pName; -#ifdef DEBUG - printf("[NSPR: looking up symbol: %s]\n", name + SYM_OFFSET); -#endif + PR_LOG(_pr_linker_lm, PR_LOG_MIN, ("Looking up symbol: %s", name + SYM_OFFSET)); + PStrFromCStr(name + SYM_OFFSET, pName); #if defined(XP_MACOSX) |