diff options
Diffstat (limited to 'src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macdll.c')
-rw-r--r-- | src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macdll.c | 587 |
1 files changed, 587 insertions, 0 deletions
diff --git a/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macdll.c b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macdll.c new file mode 100644 index 00000000..a5ecce78 --- /dev/null +++ b/src/libs/xpcom18a4/nsprpub/pr/src/md/mac/macdll.c @@ -0,0 +1,587 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998-2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include <string.h> + +#include <Files.h> +#include <Errors.h> +#include <Folders.h> +#include <CodeFragments.h> +#include <Aliases.h> +#include <Resources.h> + +#include "IterateDirectory.h" /* MoreFiles */ + +#include "MacErrorHandling.h" +#include "macdll.h" +#include "mdmac.h" +#include "macio.h" + +#include "primpl.h" +#include "plstr.h" + +/* + turds used to iterate through the directories looking + for the desired library. +*/ + +struct GetSharedLibraryFilterProcData +{ + Boolean inRecursive; + StringPtr inName; + + Boolean outFound; + CFragConnectionID outID; + Ptr outAddress; + OSErr outError; +}; +typedef struct GetSharedLibraryFilterProcData GetSharedLibraryFilterProcData; + +static pascal void +GetSharedLibraryFilterProc(const CInfoPBRec* const inCpb, Boolean* inWantQuit, void *inFilterData); + + +/* + NSGetSharedLibrary + + Unfortunately CFM doesn't support user specified loader paths, + so we emulate the behavior. Effectively this is a GetSharedLibrary + where the loader path is user defined. +*/ + +OSErr +NSGetSharedLibrary(Str255 inLibName, CFragConnectionID* outID, Ptr* outMainAddr) +{ + char* curLibPath; + char* freeCurLibPath; + OSErr tempErr; + Boolean recursive; + FSSpec curFolder; + GetSharedLibraryFilterProcData filterData; + char *endCurLibPath; + Boolean done; + + filterData.outFound = false; + filterData.outID = (CFragConnectionID)(-1); + filterData.outAddress = NULL; + filterData.inName = inLibName; + + freeCurLibPath = curLibPath = PR_GetLibraryPath(); + + if (curLibPath == NULL) + return (cfragNoLibraryErr); + + tempErr = cfragNoLibraryErr; + + do + { + endCurLibPath = PL_strchr(curLibPath, PR_PATH_SEPARATOR); + done = (endCurLibPath == NULL); + +#if 0 + // we overload the first character of a path if it's : + // then we want to recursively search that path + // see if path should be recursive + if (*curLibPath == ':') + { + // ':' is an illegal character in the name of a file + // if we start any path with this, we want to allow + // search recursively + curLibPath++; + recursive = true; + } + else +#endif + { + recursive = false; + } + + if (!done) + *endCurLibPath = '\0'; // NULL terminate the string + + // convert to FSSpec + tempErr = ConvertUnixPathToFSSpec(curLibPath, &curFolder); + + // now look in this directory + if (noErr == tempErr) + { + filterData.inRecursive = recursive; + FSpIterateDirectory(&curFolder, recursive ? 0 : 1, &GetSharedLibraryFilterProc, &filterData); + + if (filterData.outFound) + { + *outID = filterData.outID; + *outMainAddr = filterData.outAddress; + tempErr = noErr; + break; + } + else + { + tempErr = cfragNoLibraryErr; + } + } + + curLibPath = endCurLibPath + 1; // skip to next path (past the '\0'); + } while (!done); + + free(freeCurLibPath); + return (tempErr); +} + + +static Boolean +LibInPefContainer(const FSSpec* inSpec, StringPtr inName, UInt32* outCodeOffset, UInt32* outCodeLength); + + +/* + GetSharedLibraryFilterProc + + Callback to FSpIterateDirectory, finds a library with the name matching the + data in inFilterData (of type GetSharedLibraryFilterProcData). Forces a quit + when a match is found. +*/ + +static pascal void +GetSharedLibraryFilterProc(const CInfoPBRec* const inCpb, Boolean* inWantQuit, void *inFilterData) +{ + GetSharedLibraryFilterProcData* pFilterData = (GetSharedLibraryFilterProcData*) inFilterData; + + if ((inCpb->hFileInfo.ioFlAttrib & (1 << ioDirFlg)) == 0) + { + FSSpec fragSpec; + OSErr tempErr; + Str255 errName; + Boolean crap; + UInt32 codeOffset; + UInt32 codeLength; + + // it's a file + + // ¥ fix-me do we really want to allow all 'APPL's' for in which to find this library? + switch (inCpb->hFileInfo.ioFlFndrInfo.fdType) + { + case kCFragLibraryFileType: + case 'APPL': + tempErr = FSMakeFSSpec(inCpb->hFileInfo.ioVRefNum, inCpb->hFileInfo.ioFlParID, inCpb->hFileInfo.ioNamePtr, &fragSpec); + + // this shouldn't fail + if (noErr != tempErr) + { + return; + } + + // resolve an alias if this was one + tempErr = ResolveAliasFile(&fragSpec, true, &crap, &crap); + + // if got here we have a shlb (or app-like shlb) + if (noErr != tempErr) + { + // probably couldn't resolve an alias + return; + } + + break; + default: + return; + } + + // see if this symbol is in this fragment + if (LibInPefContainer(&fragSpec, pFilterData->inName, &codeOffset, &codeLength)) + tempErr = GetDiskFragment(&fragSpec, codeOffset, codeLength, fragSpec.name, kLoadCFrag, &pFilterData->outID, &pFilterData->outAddress, errName); + else + return; + + // stop if we found a library by that name + if (noErr == tempErr) + { + *inWantQuit = true; + pFilterData->outFound = true; + pFilterData->outError = tempErr; + } + } + // FSpIterateDirectory will automagically call us for subsequent sub-dirs if necessary +} + + +/* + LibInPefContainer + + Tell whether library inName is contained it the file pointed to by inSpec. + Return the codeOffset and codeLength information, for a subsequent + call to GetDiskFragment. +*/ + +static Boolean +LibInPefContainer(const FSSpec* inSpec, StringPtr inName, UInt32* outCodeOffset, UInt32* outCodeLength) +{ + short refNum; + CFragResourceHandle hCfrg; + CFragResourceMember* pCurItem; + UInt32 curLibIndex; + Boolean found; + + // asume we didn't find it + found = false; + + // open the resource fork, if we can't bail + refNum = FSpOpenResFile(inSpec, fsRdPerm); + require(-1 != refNum, Exit); + + // grab out the alias record, if it's not there bail + hCfrg = (CFragResourceHandle) Get1Resource(kCFragResourceType, kCFragResourceID); + require(NULL != hCfrg, CloseResourceAndExit); + + HLock((Handle)hCfrg); + + // get ptr to first item + pCurItem = &(*hCfrg)->firstMember; + for (curLibIndex = 0; curLibIndex < (*hCfrg)->memberCount; curLibIndex++) + { + // is this our library? + if ((pCurItem->name[0] == inName[0]) && + (strncmp((char*) inName + 1, (char*) pCurItem->name + 1, PR_MIN(pCurItem->name[0], inName[0])) == 0)) + { + *outCodeOffset = pCurItem->offset; + *outCodeLength = pCurItem->length; + found = true; + } + + // skip to next one + pCurItem = (CFragResourceMember*) ((char*) pCurItem + pCurItem->memberSize); + } + + HUnlock((Handle)hCfrg); + +CloseResourceAndExit: + CloseResFile(refNum); +Exit: + return (found); + +} + + +/* + NSFindSymbol + + Workaround bug in CFM FindSymbol (in at least 7.5.5) where symbols with lengths + greater than 63 chars cause a "paramErr". We iterate through all symbols + in the library to find the desired symbol. +*/ + +OSErr +NSFindSymbol(CFragConnectionID inID, Str255 inSymName, Ptr* outMainAddr, CFragSymbolClass *outSymClass) +{ + OSErr err; + + if (inSymName[0] > 63) + { + /* + if there are greater than 63 characters in the + name, CFM FindSymbol fails, so let's iterate through all + of the symbols in the fragment and grab it + that way. + */ + long symbolCount; + Str255 curSymName; + long curIndex; + Boolean found; + + found = false; + err = CountSymbols(inID, &symbolCount); + if (noErr == err) + { + /* now iterate through all the symbols in the library */ + /* per DTS the indices apparently go 0 to n-1 */ + for (curIndex = 0; (curIndex <= symbolCount - 1 && !found); curIndex++) + { + err = GetIndSymbol(inID, curIndex, curSymName, outMainAddr, outSymClass); + if (noErr == err && curSymName[0] == inSymName[0] && !strncmp((char*)curSymName + 1, (char*)inSymName + 1, curSymName[0])) + { + /* found our symbol */ + found = true; + } + } + + /* if we didn't find it set the error code so below it won't take this symbol */ + if (!found) + err = cfragNoSymbolErr; + } + } + else + { + err = FindSymbol(inID, inSymName, outMainAddr, outSymClass); + } + + return (err); +} + + +#pragma mark - + + +/*----------------------------------------------------------------- + + GetNamedFragmentOffsets + + Get the offsets into the data fork of the named fragment, + by reading the 'cfrg' resoruce. + +-----------------------------------------------------------------*/ +OSErr GetNamedFragmentOffsets(const FSSpec *fileSpec, const char* fragmentName, + UInt32 *outOffset, UInt32 *outLength) +{ + CFragResourceHandle cFragHandle; + short fileRefNum; + OSErr err = noErr; + + fileRefNum = FSpOpenResFile(fileSpec, fsRdPerm); + err = ResError(); + if (err != noErr) return err; + + cFragHandle = (CFragResourceHandle)Get1Resource(kCFragResourceType, kCFragResourceID); + if (!cFragHandle) + { + err = resNotFound; + goto done; + } + + /* nothing here moves memory, so no need to lock the handle */ + + err = cfragNoLibraryErr; /* in case of failure */ + *outOffset = 0; + *outLength = 0; + + /* Now look for the named fragment */ + if ((**cFragHandle).memberCount > 0) + { + CFragResourceMemberPtr memberPtr; + UInt16 i; + + for ( i = 0, memberPtr = &(**cFragHandle).firstMember; + i < (**cFragHandle).memberCount; + i ++, memberPtr = (CFragResourceMemberPtr)((char *)memberPtr + memberPtr->memberSize)) + { + char memberName[256]; + UInt16 nameLen = PR_MIN(memberPtr->name[0], 255); + + // avoid malloc here for speed + strncpy(memberName, (char *)&memberPtr->name[1], nameLen); + memberName[nameLen] = '\0'; + + // fragment names are case insensitive, so act like the system + if (PL_strcasecmp(memberName, fragmentName) == 0) + { + *outOffset = memberPtr->offset; + *outLength = memberPtr->length; + err = noErr; + break; + } + } + } + + /* Resource handle will go away when the res fork is closed */ + +done: + CloseResFile(fileRefNum); + return err; +} + + +/*----------------------------------------------------------------- + + GetIndexedFragmentOffsets + + Get the offsets into the data fork of the indexed fragment, + by reading the 'cfrg' resoruce. + +-----------------------------------------------------------------*/ +OSErr GetIndexedFragmentOffsets(const FSSpec *fileSpec, UInt32 fragmentIndex, + UInt32 *outOffset, UInt32 *outLength, char **outFragmentName) +{ + CFragResourceHandle cFragHandle; + short fileRefNum; + OSErr err = noErr; + + fileRefNum = FSpOpenResFile(fileSpec, fsRdPerm); + err = ResError(); + if (err != noErr) return err; + + cFragHandle = (CFragResourceHandle)Get1Resource(kCFragResourceType, kCFragResourceID); + if (!cFragHandle) + { + err = resNotFound; + goto done; + } + + err = cfragNoLibraryErr; /* in case of failure */ + *outOffset = 0; + *outLength = 0; + *outFragmentName = NULL; + + /* the CStrFromPStr mallocs, so might move memory */ + HLock((Handle)cFragHandle); + + /* Now look for the named fragment */ + if ((**cFragHandle).memberCount > 0) + { + CFragResourceMemberPtr memberPtr; + UInt16 i; + + for ( i = 0, memberPtr = &(**cFragHandle).firstMember; + i < (**cFragHandle).memberCount; + i ++, memberPtr = (CFragResourceMemberPtr)((char *)memberPtr + memberPtr->memberSize)) + { + + if (i == fragmentIndex) + { + char *fragmentStr; + CStrFromPStr(memberPtr->name, &fragmentStr); + if (!fragmentStr) /* test for allocation failure */ + { + err = memFullErr; + break; + } + + *outFragmentName = fragmentStr; + *outOffset = memberPtr->offset; + *outLength = memberPtr->length; + err = noErr; + break; + } + } + } + + HUnlock((Handle)cFragHandle); + + /* Resource handle will go away when the res fork is closed */ + +done: + CloseResFile(fileRefNum); + return err; +} + + +/*----------------------------------------------------------------- + + NSLoadNamedFragment + + Load the named fragment from the specified file. Aliases must + have been resolved by this point. + +-----------------------------------------------------------------*/ + +OSErr NSLoadNamedFragment(const FSSpec *fileSpec, const char* fragmentName, CFragConnectionID *outConnectionID) +{ + UInt32 fragOffset, fragLength; + short fragNameLength; + Ptr main; + Str255 fragName; + Str255 errName; + OSErr err; + + err = GetNamedFragmentOffsets(fileSpec, fragmentName, &fragOffset, &fragLength); + if (err != noErr) return err; + + // convert fragment name to pascal string + fragNameLength = strlen(fragmentName); + if (fragNameLength > 255) + fragNameLength = 255; + BlockMoveData(fragmentName, &fragName[1], fragNameLength); + fragName[0] = fragNameLength; + + // Note that we pass the fragment name as the 4th param to GetDiskFragment. + // This value affects the ability of debuggers, and the Talkback system, + // to match code fragments with symbol files + err = GetDiskFragment(fileSpec, fragOffset, fragLength, fragName, + kLoadCFrag, outConnectionID, &main, errName); + + return err; +} + + +/*----------------------------------------------------------------- + + NSLoadIndexedFragment + + Load the indexed fragment from the specified file. Aliases must + have been resolved by this point. + + *outFragName is a malloc'd block containing the fragment name, + if returning noErr. + +-----------------------------------------------------------------*/ + +OSErr NSLoadIndexedFragment(const FSSpec *fileSpec, PRUint32 fragmentIndex, + char** outFragName, CFragConnectionID *outConnectionID) +{ + UInt32 fragOffset, fragLength; + char *fragNameBlock = NULL; + Ptr main; + Str255 fragName = "\p"; + Str255 errName; + OSErr err; + + *outFragName = NULL; + + err = GetIndexedFragmentOffsets(fileSpec, fragmentIndex, &fragOffset, &fragLength, &fragNameBlock); + if (err != noErr) return err; + + if (fragNameBlock) + { + UInt32 nameLen = strlen(fragNameBlock); + if (nameLen > 63) + nameLen = 63; + BlockMoveData(fragNameBlock, &fragName[1], nameLen); + fragName[0] = nameLen; + } + + // Note that we pass the fragment name as the 4th param to GetDiskFragment. + // This value affects the ability of debuggers, and the Talkback system, + // to match code fragments with symbol files + err = GetDiskFragment(fileSpec, fragOffset, fragLength, fragName, + kLoadCFrag, outConnectionID, &main, errName); + if (err != noErr) + { + free(fragNameBlock); + return err; + } + + *outFragName = fragNameBlock; + return noErr; +} + + |