tclLoadDyld.c

Go to the documentation of this file.
00001 /*
00002  * tclLoadDyld.c --
00003  *
00004  *      This procedure provides a version of the TclLoadFile that works with
00005  *      Apple's dyld dynamic loading.
00006  *      Original version of his file (superseded long ago) provided by
00007  *      Wilfredo Sanchez (wsanchez@apple.com).
00008  *
00009  * Copyright (c) 1995 Apple Computer, Inc.
00010  * Copyright (c) 2001-2007 Daniel A. Steffen <das@users.sourceforge.net>
00011  *
00012  * See the file "license.terms" for information on usage and redistribution of
00013  * this file, and for a DISCLAIMER OF ALL WARRANTIES.
00014  *
00015  * RCS: @(#) $Id: tclLoadDyld.c,v 1.29 2007/12/13 15:28:42 dgp Exp $
00016  */
00017 
00018 #include "tclInt.h"
00019 
00020 #ifndef MODULE_SCOPE
00021 #define MODULE_SCOPE extern
00022 #endif
00023 
00024 #ifndef TCL_DYLD_USE_DLFCN
00025 /*
00026  * Use preferred dlfcn API on 10.4 and later
00027  */
00028 #   if !defined(NO_DLFCN_H) && MAC_OS_X_VERSION_MAX_ALLOWED >= 1040
00029 #       define TCL_DYLD_USE_DLFCN 1
00030 #   else
00031 #       define TCL_DYLD_USE_DLFCN 0
00032 #   endif
00033 #endif
00034 #ifndef TCL_DYLD_USE_NSMODULE
00035 /*
00036  * Use deprecated NSModule API only to support 10.3 and earlier:
00037  */
00038 #   if MAC_OS_X_VERSION_MIN_REQUIRED < 1040
00039 #       define TCL_DYLD_USE_NSMODULE 1
00040 #   else
00041 #       define TCL_DYLD_USE_NSMODULE 0
00042 #   endif
00043 #endif
00044 
00045 #if TCL_DYLD_USE_DLFCN
00046 #include <dlfcn.h>
00047 #if defined(HAVE_WEAK_IMPORT) && MAC_OS_X_VERSION_MIN_REQUIRED < 1040
00048 /*
00049  * Support for weakly importing dlfcn API.
00050  */
00051 extern void *dlopen(const char *path, int mode) WEAK_IMPORT_ATTRIBUTE;
00052 extern void *dlsym(void *handle, const char *symbol) WEAK_IMPORT_ATTRIBUTE;
00053 extern int dlclose(void *handle) WEAK_IMPORT_ATTRIBUTE;
00054 extern char *dlerror(void) WEAK_IMPORT_ATTRIBUTE;
00055 #endif
00056 #endif
00057 
00058 #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY)
00059 #include <mach-o/dyld.h>
00060 #include <mach-o/fat.h>
00061 #include <mach-o/swap.h>
00062 #include <mach-o/arch.h>
00063 #include <libkern/OSByteOrder.h>
00064 #include <mach/mach.h>
00065 #include <stdbool.h>
00066 
00067 typedef struct Tcl_DyldModuleHandle {
00068     struct Tcl_DyldModuleHandle *nextPtr;
00069     NSModule module;
00070 } Tcl_DyldModuleHandle;
00071 #endif /* TCL_DYLD_USE_NSMODULE */
00072 
00073 typedef struct Tcl_DyldLoadHandle {
00074 #if TCL_DYLD_USE_DLFCN
00075     void *dlHandle;
00076 #endif
00077 #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY)
00078     const struct mach_header *dyldLibHeader;
00079     Tcl_DyldModuleHandle *modulePtr;
00080 #endif
00081 } Tcl_DyldLoadHandle;
00082 
00083 #if (TCL_DYLD_USE_DLFCN && MAC_OS_X_VERSION_MIN_REQUIRED < 1040) || \
00084         defined(TCL_LOAD_FROM_MEMORY)
00085 MODULE_SCOPE long tclMacOSXDarwinRelease;
00086 #endif
00087 
00088 #ifdef TCL_DEBUG_LOAD
00089 #define TclLoadDbgMsg(m, ...) do { \
00090             fprintf(stderr, "%s:%d: %s(): " m ".\n", \
00091             strrchr(__FILE__, '/')+1, __LINE__, __func__, ##__VA_ARGS__); \
00092         } while (0)
00093 #else
00094 #define TclLoadDbgMsg(m, ...)
00095 #endif
00096 
00097 #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY)
00098 /*
00099  *----------------------------------------------------------------------
00100  *
00101  * DyldOFIErrorMsg --
00102  *
00103  *      Converts a numerical NSObjectFileImage error into an error message
00104  *      string.
00105  *
00106  * Results:
00107  *      Error message string.
00108  *
00109  * Side effects:
00110  *      None.
00111  *
00112  *----------------------------------------------------------------------
00113  */
00114 
00115 static CONST char*
00116 DyldOFIErrorMsg(
00117     int err)
00118 {
00119     switch(err) {
00120     case NSObjectFileImageSuccess:
00121         return NULL;
00122     case NSObjectFileImageFailure:
00123         return "object file setup failure";
00124     case NSObjectFileImageInappropriateFile:
00125         return "not a Mach-O MH_BUNDLE file";
00126     case NSObjectFileImageArch:
00127         return "no object for this architecture";
00128     case NSObjectFileImageFormat:
00129         return "bad object file format";
00130     case NSObjectFileImageAccess:
00131         return "can't read object file";
00132     default:
00133         return "unknown error";
00134     }
00135 }
00136 #endif /* TCL_DYLD_USE_NSMODULE */
00137 
00138 /*
00139  *----------------------------------------------------------------------
00140  *
00141  * TclpDlopen --
00142  *
00143  *      Dynamically loads a binary code file into memory and returns a handle
00144  *      to the new code.
00145  *
00146  * Results:
00147  *      A standard Tcl completion code. If an error occurs, an error message
00148  *      is left in the interpreter's result.
00149  *
00150  * Side effects:
00151  *      New code suddenly appears in memory.
00152  *
00153  *----------------------------------------------------------------------
00154  */
00155 
00156 MODULE_SCOPE int
00157 TclpDlopen(
00158     Tcl_Interp *interp,         /* Used for error reporting. */
00159     Tcl_Obj *pathPtr,           /* Name of the file containing the desired
00160                                  * code (UTF-8). */
00161     Tcl_LoadHandle *loadHandle, /* Filled with token for dynamically loaded
00162                                  * file which will be passed back to
00163                                  * (*unloadProcPtr)() to unload the file. */
00164     Tcl_FSUnloadFileProc **unloadProcPtr)
00165                                 /* Filled with address of Tcl_FSUnloadFileProc
00166                                  * function which should be used for this
00167                                  * file. */
00168 {
00169     Tcl_DyldLoadHandle *dyldLoadHandle;
00170 #if TCL_DYLD_USE_DLFCN
00171     void *dlHandle = NULL;
00172 #endif
00173 #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY)
00174     const struct mach_header *dyldLibHeader = NULL;
00175     Tcl_DyldModuleHandle *modulePtr = NULL;
00176 #endif
00177 #if TCL_DYLD_USE_NSMODULE
00178     NSLinkEditErrors editError;
00179     int errorNumber;
00180     const char *errorName, *objFileImageErrMsg = NULL;
00181 #endif
00182     const char *errMsg = NULL;
00183     int result;
00184     Tcl_DString ds;
00185     char *fileName = NULL;
00186     const char *nativePath, *nativeFileName = NULL;
00187 
00188     /*
00189      * First try the full path the user gave us. This is particularly
00190      * important if the cwd is inside a vfs, and we are trying to load using a
00191      * relative path.
00192      */
00193 
00194     nativePath = Tcl_FSGetNativePath(pathPtr);
00195 
00196 #if TCL_DYLD_USE_DLFCN
00197 #if MAC_OS_X_VERSION_MIN_REQUIRED < 1040
00198     if (tclMacOSXDarwinRelease >= 8)
00199 #endif
00200     {
00201         dlHandle = dlopen(nativePath, RTLD_NOW | RTLD_LOCAL);
00202         if (!dlHandle) {
00203             /*
00204              * Let the OS loader examine the binary search path for whatever
00205              * string the user gave us which hopefully refers to a file on the
00206              * binary path.
00207              */
00208 
00209             fileName = Tcl_GetString(pathPtr);
00210             nativeFileName = Tcl_UtfToExternalDString(NULL, fileName, -1, &ds);
00211             dlHandle = dlopen(nativeFileName, RTLD_NOW | RTLD_LOCAL);
00212         }
00213         if (dlHandle) {
00214             TclLoadDbgMsg("dlopen() successful");
00215         } else {
00216             errMsg = dlerror();
00217             TclLoadDbgMsg("dlopen() failed: %s", errMsg);
00218         }
00219     }
00220     if (!dlHandle)
00221 #endif /* TCL_DYLD_USE_DLFCN */
00222     {
00223 #if TCL_DYLD_USE_NSMODULE
00224         dyldLibHeader = NSAddImage(nativePath,
00225                 NSADDIMAGE_OPTION_RETURN_ON_ERROR);
00226         if (dyldLibHeader) {
00227             TclLoadDbgMsg("NSAddImage() successful");
00228         } else {
00229             NSLinkEditError(&editError, &errorNumber, &errorName, &errMsg);
00230             if (editError == NSLinkEditFileAccessError) {
00231                 /*
00232                  * The requested file was not found. Let the OS loader examine
00233                  * the binary search path for whatever string the user gave us
00234                  * which hopefully refers to a file on the binary path.
00235                  */
00236 
00237                 if (!fileName) {
00238                     fileName = Tcl_GetString(pathPtr);
00239                     nativeFileName = Tcl_UtfToExternalDString(NULL, fileName,
00240                             -1, &ds);
00241                 }
00242                 dyldLibHeader = NSAddImage(nativeFileName,
00243                         NSADDIMAGE_OPTION_WITH_SEARCHING |
00244                         NSADDIMAGE_OPTION_RETURN_ON_ERROR);
00245                 if (dyldLibHeader) {
00246                     TclLoadDbgMsg("NSAddImage() successful");
00247                 } else {
00248                     NSLinkEditError(&editError, &errorNumber, &errorName,
00249                             &errMsg);
00250                     TclLoadDbgMsg("NSAddImage() failed: %s", errMsg);
00251                 }
00252             } else if ((editError == NSLinkEditFileFormatError
00253                     && errorNumber == EBADMACHO)
00254                     || editError == NSLinkEditOtherError){
00255                 NSObjectFileImageReturnCode err;
00256                 NSObjectFileImage dyldObjFileImage;
00257                 NSModule module;
00258 
00259                 /*
00260                  * The requested file was found but was not of type MH_DYLIB,
00261                  * attempt to load it as a MH_BUNDLE.
00262                  */
00263 
00264                 err = NSCreateObjectFileImageFromFile(nativePath,
00265                         &dyldObjFileImage);
00266                 if (err == NSObjectFileImageSuccess && dyldObjFileImage) {
00267                     TclLoadDbgMsg("NSCreateObjectFileImageFromFile() "
00268                             "successful");
00269                     module = NSLinkModule(dyldObjFileImage, nativePath,
00270                             NSLINKMODULE_OPTION_BINDNOW
00271                             | NSLINKMODULE_OPTION_RETURN_ON_ERROR);
00272                     NSDestroyObjectFileImage(dyldObjFileImage);
00273                     if (module) {
00274                         modulePtr = (Tcl_DyldModuleHandle *)
00275                                 ckalloc(sizeof(Tcl_DyldModuleHandle));
00276                         modulePtr->module = module;
00277                         modulePtr->nextPtr = NULL;
00278                         TclLoadDbgMsg("NSLinkModule() successful");
00279                     } else {
00280                         NSLinkEditError(&editError, &errorNumber, &errorName,
00281                                 &errMsg);
00282                         TclLoadDbgMsg("NSLinkModule() failed: %s", errMsg);
00283                     }
00284                 } else {
00285                     objFileImageErrMsg = DyldOFIErrorMsg(err);
00286                     TclLoadDbgMsg("NSCreateObjectFileImageFromFile() failed: "
00287                             "%s", objFileImageErrMsg);
00288                 }
00289             }
00290         }
00291 #endif /* TCL_DYLD_USE_NSMODULE */
00292     }
00293     if (0
00294 #if TCL_DYLD_USE_DLFCN
00295             || dlHandle
00296 #endif
00297 #if TCL_DYLD_USE_NSMODULE
00298             || dyldLibHeader || modulePtr
00299 #endif
00300     ) {
00301         dyldLoadHandle = (Tcl_DyldLoadHandle *)
00302                 ckalloc(sizeof(Tcl_DyldLoadHandle));
00303 #if TCL_DYLD_USE_DLFCN
00304         dyldLoadHandle->dlHandle = dlHandle;
00305 #endif
00306 #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY)
00307         dyldLoadHandle->dyldLibHeader = dyldLibHeader;
00308         dyldLoadHandle->modulePtr = modulePtr;
00309 #endif
00310         *loadHandle = (Tcl_LoadHandle) dyldLoadHandle;
00311         *unloadProcPtr = &TclpUnloadFile;
00312         result = TCL_OK;
00313     } else {
00314         Tcl_AppendResult(interp, errMsg, NULL);
00315 #if TCL_DYLD_USE_NSMODULE
00316         if (objFileImageErrMsg) {
00317             Tcl_AppendResult(interp, "\nNSCreateObjectFileImageFromFile() "
00318                     "error: ", objFileImageErrMsg, NULL);
00319         }
00320 #endif
00321         result = TCL_ERROR;
00322     }
00323     if(fileName) {
00324         Tcl_DStringFree(&ds);
00325     }
00326     return result;
00327 }
00328 
00329 /*
00330  *----------------------------------------------------------------------
00331  *
00332  * TclpFindSymbol --
00333  *
00334  *      Looks up a symbol, by name, through a handle associated with a
00335  *      previously loaded piece of code (shared library).
00336  *
00337  * Results:
00338  *      Returns a pointer to the function associated with 'symbol' if it is
00339  *      found. Otherwise returns NULL and may leave an error message in the
00340  *      interp's result.
00341  *
00342  *----------------------------------------------------------------------
00343  */
00344 
00345 MODULE_SCOPE Tcl_PackageInitProc *
00346 TclpFindSymbol(
00347     Tcl_Interp *interp,         /* For error reporting. */
00348     Tcl_LoadHandle loadHandle,  /* Handle from TclpDlopen. */
00349     CONST char *symbol)         /* Symbol name to look up. */
00350 {
00351     Tcl_DyldLoadHandle *dyldLoadHandle = (Tcl_DyldLoadHandle *) loadHandle;
00352     Tcl_PackageInitProc *proc = NULL;
00353     const char *errMsg = NULL;
00354     Tcl_DString ds;
00355     const char *native;
00356 
00357     native = Tcl_UtfToExternalDString(NULL, symbol, -1, &ds);
00358 #if TCL_DYLD_USE_DLFCN
00359     if (dyldLoadHandle->dlHandle) {
00360         proc = dlsym(dyldLoadHandle->dlHandle, native);
00361         if (proc) {
00362             TclLoadDbgMsg("dlsym() successful");
00363         } else {
00364             errMsg = dlerror();
00365             TclLoadDbgMsg("dlsym() failed: %s", errMsg);
00366         }
00367     } else
00368 #endif /* TCL_DYLD_USE_DLFCN */
00369     {
00370 #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY)
00371         NSSymbol nsSymbol = NULL;
00372         Tcl_DString newName;
00373 
00374         /*
00375          * dyld adds an underscore to the beginning of symbol names.
00376          */
00377 
00378         Tcl_DStringInit(&newName);
00379         Tcl_DStringAppend(&newName, "_", 1);
00380         native = Tcl_DStringAppend(&newName, native, -1);
00381         if (dyldLoadHandle->dyldLibHeader) {
00382             nsSymbol = NSLookupSymbolInImage(dyldLoadHandle->dyldLibHeader,
00383                     native, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW |
00384                     NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
00385             if (nsSymbol) {
00386                 TclLoadDbgMsg("NSLookupSymbolInImage() successful");
00387 #ifdef DYLD_SUPPORTS_DYLIB_UNLOADING
00388                 /*
00389                  * Until dyld supports unloading of MY_DYLIB binaries, the
00390                  * following is not needed.
00391                  */
00392 
00393                 NSModule module = NSModuleForSymbol(nsSymbol);
00394                 Tcl_DyldModuleHandle *modulePtr = dyldLoadHandle->modulePtr;
00395 
00396                 while (modulePtr != NULL) {
00397                     if (module == modulePtr->module) {
00398                         break;
00399                     }
00400                     modulePtr = modulePtr->nextPtr;
00401                 }
00402                 if (modulePtr == NULL) {
00403                     modulePtr = (Tcl_DyldModuleHandle *)
00404                             ckalloc(sizeof(Tcl_DyldModuleHandle));
00405                     modulePtr->module = module;
00406                     modulePtr->nextPtr = dyldLoadHandle->modulePtr;
00407                     dyldLoadHandle->modulePtr = modulePtr;
00408                 }
00409 #endif /* DYLD_SUPPORTS_DYLIB_UNLOADING */
00410             } else {
00411                 NSLinkEditErrors editError;
00412                 int errorNumber;
00413                 const char *errorName;
00414 
00415                 NSLinkEditError(&editError, &errorNumber, &errorName, &errMsg);
00416                 TclLoadDbgMsg("NSLookupSymbolInImage() failed: %s", errMsg);
00417             }
00418         } else if (dyldLoadHandle->modulePtr) {
00419             nsSymbol = NSLookupSymbolInModule(
00420                     dyldLoadHandle->modulePtr->module, native);
00421             if (nsSymbol) {
00422                 TclLoadDbgMsg("NSLookupSymbolInModule() successful");
00423             } else {
00424                 TclLoadDbgMsg("NSLookupSymbolInModule() failed");
00425             }
00426         }
00427         if (nsSymbol) {
00428             proc = NSAddressOfSymbol(nsSymbol);
00429             if (proc) {
00430                 TclLoadDbgMsg("NSAddressOfSymbol() successful");
00431             } else {
00432                 TclLoadDbgMsg("NSAddressOfSymbol() failed");
00433             }
00434         }
00435         Tcl_DStringFree(&newName);
00436 #endif /* TCL_DYLD_USE_NSMODULE */
00437     }
00438     Tcl_DStringFree(&ds);
00439     if (errMsg) {
00440         Tcl_AppendResult(interp, errMsg, NULL);
00441     }
00442     return proc;
00443 }
00444 
00445 /*
00446  *----------------------------------------------------------------------
00447  *
00448  * TclpUnloadFile --
00449  *
00450  *      Unloads a dynamically loaded binary code file from memory. Code
00451  *      pointers in the formerly loaded file are no longer valid after calling
00452  *      this function.
00453  *
00454  * Results:
00455  *      None.
00456  *
00457  * Side effects:
00458  *      Code dissapears from memory. Note that dyld currently only supports
00459  *      unloading of binaries of type MH_BUNDLE loaded with NSLinkModule() in
00460  *      TclpDlopen() above.
00461  *
00462  *----------------------------------------------------------------------
00463  */
00464 
00465 MODULE_SCOPE void
00466 TclpUnloadFile(
00467     Tcl_LoadHandle loadHandle)  /* loadHandle returned by a previous call to
00468                                  * TclpDlopen(). The loadHandle is a token
00469                                  * that represents the loaded file. */
00470 {
00471     Tcl_DyldLoadHandle *dyldLoadHandle = (Tcl_DyldLoadHandle *) loadHandle;
00472 
00473 #if TCL_DYLD_USE_DLFCN
00474     if (dyldLoadHandle->dlHandle) {
00475         int result;
00476 
00477         result = dlclose(dyldLoadHandle->dlHandle);
00478         if (!result) {
00479             TclLoadDbgMsg("dlclose() successful");
00480         } else {
00481             TclLoadDbgMsg("dlclose() failed: %s", dlerror());
00482         }
00483     } else
00484 #endif /* TCL_DYLD_USE_DLFCN */
00485     {
00486 #if TCL_DYLD_USE_NSMODULE || defined(TCL_LOAD_FROM_MEMORY)
00487         Tcl_DyldModuleHandle *modulePtr = dyldLoadHandle->modulePtr;
00488 
00489         while (modulePtr != NULL) {
00490             void *ptr;
00491             bool result;
00492 
00493             result = NSUnLinkModule(modulePtr->module,
00494                     NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES);
00495             if (result) {
00496                 TclLoadDbgMsg("NSUnLinkModule() successful");
00497             } else {
00498                 TclLoadDbgMsg("NSUnLinkModule() failed");
00499             }
00500             ptr = modulePtr;
00501             modulePtr = modulePtr->nextPtr;
00502             ckfree(ptr);
00503         }
00504 #endif /* TCL_DYLD_USE_NSMODULE */
00505     }
00506     ckfree((char*) dyldLoadHandle);
00507 }
00508 
00509 /*
00510  *----------------------------------------------------------------------
00511  *
00512  * TclGuessPackageName --
00513  *
00514  *      If the "load" command is invoked without providing a package name,
00515  *      this procedure is invoked to try to figure it out.
00516  *
00517  * Results:
00518  *      Always returns 0 to indicate that we couldn't figure out a package
00519  *      name; generic code will then try to guess the package from the file
00520  *      name. A return value of 1 would have meant that we figured out the
00521  *      package name and put it in bufPtr.
00522  *
00523  * Side effects:
00524  *      None.
00525  *
00526  *----------------------------------------------------------------------
00527  */
00528 
00529 int
00530 TclGuessPackageName(
00531     CONST char *fileName,       /* Name of file containing package (already
00532                                  * translated to local form if needed). */
00533     Tcl_DString *bufPtr)        /* Initialized empty dstring. Append package
00534                                  * name to this if possible. */
00535 {
00536     return 0;
00537 }
00538 
00539 #ifdef TCL_LOAD_FROM_MEMORY
00540 /*
00541  *----------------------------------------------------------------------
00542  *
00543  * TclpLoadMemoryGetBuffer --
00544  *
00545  *      Allocate a buffer that can be used with TclpLoadMemory() below.
00546  *
00547  * Results:
00548  *      Pointer to allocated buffer or NULL if an error occurs.
00549  *
00550  * Side effects:
00551  *      Buffer is allocated.
00552  *
00553  *----------------------------------------------------------------------
00554  */
00555 
00556 MODULE_SCOPE void *
00557 TclpLoadMemoryGetBuffer(
00558     Tcl_Interp *interp,         /* Used for error reporting. */
00559     int size)                   /* Size of desired buffer. */
00560 {
00561     void *buffer = NULL;
00562 
00563     /*
00564      * NSCreateObjectFileImageFromMemory is available but always fails
00565      * prior to Darwin 7.
00566      */
00567     if (tclMacOSXDarwinRelease >= 7) {
00568         /*
00569          * We must allocate the buffer using vm_allocate, because
00570          * NSCreateObjectFileImageFromMemory will dispose of it using
00571          * vm_deallocate.
00572          */
00573 
00574         if (vm_allocate(mach_task_self(), (vm_address_t *) &buffer, size, 1)) {
00575             buffer = NULL;
00576         }
00577     }
00578     return buffer;
00579 }
00580 
00581 /*
00582  *----------------------------------------------------------------------
00583  *
00584  * TclpLoadMemory --
00585  *
00586  *      Dynamically loads binary code file from memory and returns a handle to
00587  *      the new code.
00588  *
00589  * Results:
00590  *      A standard Tcl completion code. If an error occurs, an error message
00591  *      is left in the interpreter's result.
00592  *
00593  * Side effects:
00594  *      New code is loaded from memory.
00595  *
00596  *----------------------------------------------------------------------
00597  */
00598 
00599 MODULE_SCOPE int
00600 TclpLoadMemory(
00601     Tcl_Interp *interp,         /* Used for error reporting. */
00602     void *buffer,               /* Buffer containing the desired code
00603                                  * (allocated with TclpLoadMemoryGetBuffer). */
00604     int size,                   /* Allocation size of buffer. */
00605     int codeSize,               /* Size of code data read into buffer or -1 if
00606                                  * an error occurred and the buffer should
00607                                  * just be freed. */
00608     Tcl_LoadHandle *loadHandle, /* Filled with token for dynamically loaded
00609                                  * file which will be passed back to
00610                                  * (*unloadProcPtr)() to unload the file. */
00611     Tcl_FSUnloadFileProc **unloadProcPtr)
00612                                 /* Filled with address of Tcl_FSUnloadFileProc
00613                                  * function which should be used for this
00614                                  * file. */
00615 {
00616     Tcl_DyldLoadHandle *dyldLoadHandle;
00617     NSObjectFileImage dyldObjFileImage = NULL;
00618     Tcl_DyldModuleHandle *modulePtr;
00619     NSModule module;
00620     const char *objFileImageErrMsg = NULL;
00621 
00622     /*
00623      * Try to create an object file image that we can load from.
00624      */
00625 
00626     if (codeSize >= 0) {
00627         NSObjectFileImageReturnCode err = NSObjectFileImageSuccess;
00628         const struct fat_header *fh = buffer;
00629         uint32_t ms = 0;
00630 #ifndef __LP64__
00631         const struct mach_header *mh = NULL;
00632         #define mh_size  sizeof(struct mach_header)
00633         #define mh_magic MH_MAGIC
00634         #define arch_abi 0
00635 #else
00636         const struct mach_header_64 *mh = NULL;
00637         #define mh_size  sizeof(struct mach_header_64)
00638         #define mh_magic MH_MAGIC_64
00639         #define arch_abi CPU_ARCH_ABI64
00640 #endif
00641 
00642         if ((size_t) codeSize >= sizeof(struct fat_header)
00643                 && fh->magic == OSSwapHostToBigInt32(FAT_MAGIC)) {
00644             uint32_t fh_nfat_arch = OSSwapBigToHostInt32(fh->nfat_arch);
00645 
00646             /*
00647              * Fat binary, try to find mach_header for our architecture
00648              */
00649 
00650             TclLoadDbgMsg("Fat binary, %d archs", fh_nfat_arch);
00651             if ((size_t) codeSize >= sizeof(struct fat_header) +
00652                     fh_nfat_arch * sizeof(struct fat_arch)) {
00653                 void *fatarchs = (char*)buffer + sizeof(struct fat_header);
00654                 const NXArchInfo *arch = NXGetLocalArchInfo();
00655                 struct fat_arch *fa;
00656 
00657                 if (fh->magic != FAT_MAGIC) {
00658                     swap_fat_arch(fatarchs, fh_nfat_arch, arch->byteorder);
00659                 }
00660                 fa = NXFindBestFatArch(arch->cputype | arch_abi,
00661                         arch->cpusubtype, fatarchs, fh_nfat_arch);
00662                 if (fa) {
00663                     TclLoadDbgMsg("NXFindBestFatArch() successful: "
00664                             "local cputype %d subtype %d, "
00665                             "fat cputype %d subtype %d",
00666                             arch->cputype | arch_abi, arch->cpusubtype,
00667                             fa->cputype, fa->cpusubtype);
00668                     mh = (void*)((char*)buffer + fa->offset);
00669                     ms = fa->size;
00670                 } else {
00671                     TclLoadDbgMsg("NXFindBestFatArch() failed");
00672                     err = NSObjectFileImageInappropriateFile;
00673                 }
00674                 if (fh->magic != FAT_MAGIC) {
00675                     swap_fat_arch(fatarchs, fh_nfat_arch, arch->byteorder);
00676                 }
00677             } else {
00678                 TclLoadDbgMsg("Fat binary header failure");
00679                 err = NSObjectFileImageInappropriateFile;
00680             }
00681         } else {
00682             /*
00683              * Thin binary
00684              */
00685 
00686             TclLoadDbgMsg("Thin binary");
00687             mh = buffer;
00688             ms = codeSize;
00689         }
00690         if (ms && !(ms >= mh_size && mh->magic == mh_magic &&
00691                  mh->filetype == MH_BUNDLE)) {
00692             TclLoadDbgMsg("Inappropriate file: magic %x filetype %d",
00693                     mh->magic, mh->filetype);
00694             err = NSObjectFileImageInappropriateFile;
00695         }
00696         if (err == NSObjectFileImageSuccess) {
00697             err = NSCreateObjectFileImageFromMemory(buffer, codeSize,
00698                     &dyldObjFileImage);
00699             if (err == NSObjectFileImageSuccess) {
00700                 TclLoadDbgMsg("NSCreateObjectFileImageFromMemory() "
00701                         "successful");
00702             } else {
00703                 objFileImageErrMsg = DyldOFIErrorMsg(err);
00704                 TclLoadDbgMsg("NSCreateObjectFileImageFromMemory() failed: %s",
00705                         objFileImageErrMsg);
00706             }
00707         } else {
00708             objFileImageErrMsg = DyldOFIErrorMsg(err);
00709         }
00710     }
00711 
00712     /*
00713      * If it went wrong (or we were asked to just deallocate), get rid of the
00714      * memory block and create an error message.
00715      */
00716 
00717     if (dyldObjFileImage == NULL) {
00718         vm_deallocate(mach_task_self(), (vm_address_t) buffer, size);
00719         if (objFileImageErrMsg != NULL) {
00720             Tcl_AppendResult(interp, "NSCreateObjectFileImageFromMemory() "
00721                     "error: ", objFileImageErrMsg, NULL);
00722         }
00723         return TCL_ERROR;
00724     }
00725 
00726     /*
00727      * Extract the module we want from the image of the object file.
00728      */
00729 
00730     module = NSLinkModule(dyldObjFileImage, "[Memory Based Bundle]",
00731             NSLINKMODULE_OPTION_BINDNOW | NSLINKMODULE_OPTION_RETURN_ON_ERROR);
00732     NSDestroyObjectFileImage(dyldObjFileImage);
00733     if (module) {
00734         TclLoadDbgMsg("NSLinkModule() successful");
00735     } else {
00736         NSLinkEditErrors editError;
00737         int errorNumber;
00738         const char *errorName, *errMsg;
00739 
00740         NSLinkEditError(&editError, &errorNumber, &errorName, &errMsg);
00741         TclLoadDbgMsg("NSLinkModule() failed: %s", errMsg);
00742         Tcl_AppendResult(interp, errMsg, NULL);
00743         return TCL_ERROR;
00744     }
00745 
00746     /*
00747      * Stash the module reference within the load handle we create and return.
00748      */
00749 
00750     modulePtr = (Tcl_DyldModuleHandle *) ckalloc(sizeof(Tcl_DyldModuleHandle));
00751     modulePtr->module = module;
00752     modulePtr->nextPtr = NULL;
00753     dyldLoadHandle = (Tcl_DyldLoadHandle *)
00754             ckalloc(sizeof(Tcl_DyldLoadHandle));
00755 #if TCL_DYLD_USE_DLFCN
00756     dyldLoadHandle->dlHandle = NULL;
00757 #endif
00758     dyldLoadHandle->dyldLibHeader = NULL;
00759     dyldLoadHandle->modulePtr = modulePtr;
00760     *loadHandle = (Tcl_LoadHandle) dyldLoadHandle;
00761     *unloadProcPtr = &TclpUnloadFile;
00762     return TCL_OK;
00763 }
00764 #endif /* TCL_LOAD_FROM_MEMORY */
00765 
00766 /*
00767  * Local Variables:
00768  * mode: c
00769  * c-basic-offset: 4
00770  * fill-column: 79
00771  * End:
00772  */



Generated on Wed Mar 12 12:18:25 2008 by  doxygen 1.5.1