tclLoadDyld.cGo 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 1.5.1 |