os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/unix/tclLoadDyld.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 /*
     2  * tclLoadDyld.c --
     3  *
     4  *	This procedure provides a version of the TclLoadFile that works with
     5  *	Apple's dyld dynamic loading.
     6  *	Original version of his file (now superseded long ago) provided by
     7  *	Wilfredo Sanchez (wsanchez@apple.com).
     8  *
     9  * Copyright (c) 1995 Apple Computer, Inc.
    10  * Copyright (c) 2001-2007 Daniel A. Steffen <das@users.sourceforge.net>
    11  *
    12  * See the file "license.terms" for information on usage and redistribution of
    13  * this file, and for a DISCLAIMER OF ALL WARRANTIES.
    14  *
    15  * RCS: @(#) $Id: tclLoadDyld.c,v 1.14.2.9 2007/04/29 02:20:16 das Exp $
    16  */
    17 
    18 #include "tclInt.h"
    19 #include "tclPort.h"
    20 #include <mach-o/dyld.h>
    21 #include <mach-o/fat.h>
    22 #include <mach-o/swap.h>
    23 #include <mach-o/arch.h>
    24 #include <libkern/OSByteOrder.h>
    25 #undef panic
    26 #include <mach/mach.h>
    27 
    28 #ifndef MODULE_SCOPE
    29 #define MODULE_SCOPE extern
    30 #endif
    31 
    32 typedef struct Tcl_DyldModuleHandle {
    33     struct Tcl_DyldModuleHandle *nextPtr;
    34     NSModule module;
    35 } Tcl_DyldModuleHandle;
    36 
    37 typedef struct Tcl_DyldLoadHandle {
    38     CONST struct mach_header *dyldLibHeader;
    39     Tcl_DyldModuleHandle *modulePtr;
    40 } Tcl_DyldLoadHandle;
    41 
    42 #ifdef TCL_LOAD_FROM_MEMORY
    43 MODULE_SCOPE long tclMacOSXDarwinRelease;
    44 #endif
    45 
    46 /*
    47  *----------------------------------------------------------------------
    48  *
    49  * DyldOFIErrorMsg --
    50  *
    51  *	Converts a numerical NSObjectFileImage error into an error message
    52  *	string.
    53  *
    54  * Results:
    55  *	Error message string.
    56  *
    57  * Side effects:
    58  *	None.
    59  *
    60  *----------------------------------------------------------------------
    61  */
    62 
    63 static CONST char*
    64 DyldOFIErrorMsg(
    65     int err)
    66 {
    67     switch(err) {
    68     case NSObjectFileImageSuccess:
    69 	return NULL;
    70     case NSObjectFileImageFailure:
    71 	return "object file setup failure";
    72     case NSObjectFileImageInappropriateFile:
    73 	return "not a Mach-O MH_BUNDLE file";
    74     case NSObjectFileImageArch:
    75 	return "no object for this architecture";
    76     case NSObjectFileImageFormat:
    77 	return "bad object file format";
    78     case NSObjectFileImageAccess:
    79 	return "can't read object file";
    80     default:
    81 	return "unknown error";
    82     }
    83 }
    84 
    85 /*
    86  *----------------------------------------------------------------------
    87  *
    88  * TclpDlopen --
    89  *
    90  *	Dynamically loads a binary code file into memory and returns a handle
    91  *	to the new code.
    92  *
    93  * Results:
    94  *	A standard Tcl completion code. If an error occurs, an error message
    95  *	is left in the interpreter's result.
    96  *
    97  * Side effects:
    98  *	New code suddenly appears in memory.
    99  *
   100  *----------------------------------------------------------------------
   101  */
   102 
   103 MODULE_SCOPE int
   104 TclpDlopen(
   105     Tcl_Interp *interp,		/* Used for error reporting. */
   106     Tcl_Obj *pathPtr,		/* Name of the file containing the desired
   107 				 * code (UTF-8). */
   108     Tcl_LoadHandle *loadHandle,	/* Filled with token for dynamically loaded
   109 				 * file which will be passed back to
   110 				 * (*unloadProcPtr)() to unload the file. */
   111     Tcl_FSUnloadFileProc **unloadProcPtr)
   112 				/* Filled with address of Tcl_FSUnloadFileProc
   113 				 * function which should be used for this
   114 				 * file. */
   115 {
   116     Tcl_DyldLoadHandle *dyldLoadHandle;
   117     CONST struct mach_header *dyldLibHeader;
   118     NSObjectFileImage dyldObjFileImage = NULL;
   119     Tcl_DyldModuleHandle *modulePtr = NULL;
   120     CONST char *native;
   121 
   122     /*
   123      * First try the full path the user gave us. This is particularly
   124      * important if the cwd is inside a vfs, and we are trying to load using a
   125      * relative path.
   126      */
   127 
   128     native = Tcl_FSGetNativePath(pathPtr);
   129     dyldLibHeader = NSAddImage(native, NSADDIMAGE_OPTION_RETURN_ON_ERROR);
   130 
   131     if (!dyldLibHeader) {
   132 	NSLinkEditErrors editError;
   133 	int errorNumber;
   134 	CONST char *name, *msg, *objFileImageErrMsg = NULL;
   135 
   136 	NSLinkEditError(&editError, &errorNumber, &name, &msg);
   137 
   138 	if (editError == NSLinkEditFileAccessError) {
   139 	    /*
   140 	     * The requested file was not found. Let the OS loader examine the
   141 	     * binary search path for whatever string the user gave us which
   142 	     * hopefully refers to a file on the binary path.
   143 	     */
   144 
   145 	    Tcl_DString ds;
   146 	    char *fileName = Tcl_GetString(pathPtr);
   147 	    CONST char *native =
   148 		    Tcl_UtfToExternalDString(NULL, fileName, -1, &ds);
   149 
   150 	    dyldLibHeader = NSAddImage(native, NSADDIMAGE_OPTION_WITH_SEARCHING
   151 		    | NSADDIMAGE_OPTION_RETURN_ON_ERROR);
   152 	    Tcl_DStringFree(&ds);
   153 	    if (!dyldLibHeader) {
   154 		NSLinkEditError(&editError, &errorNumber, &name, &msg);
   155 	    }
   156 	} else if ((editError == NSLinkEditFileFormatError
   157 		&& errorNumber == EBADMACHO)
   158 		|| editError == NSLinkEditOtherError){
   159 	    /*
   160 	     * The requested file was found but was not of type MH_DYLIB,
   161 	     * attempt to load it as a MH_BUNDLE.
   162 	     */
   163 
   164 	    NSObjectFileImageReturnCode err =
   165 		    NSCreateObjectFileImageFromFile(native, &dyldObjFileImage);
   166 	    objFileImageErrMsg = DyldOFIErrorMsg(err);
   167 	}
   168 
   169 	if (!dyldLibHeader && !dyldObjFileImage) {
   170 	    Tcl_AppendResult(interp, msg, NULL);
   171 	    if (msg && *msg) {
   172 		Tcl_AppendResult(interp, "\n", NULL);
   173 	    }
   174 	    if (objFileImageErrMsg) {
   175 		Tcl_AppendResult(interp,
   176 			"NSCreateObjectFileImageFromFile() error: ",
   177 			objFileImageErrMsg, NULL);
   178 	    }
   179 	    return TCL_ERROR;
   180 	}
   181     }
   182 
   183     if (dyldObjFileImage) {
   184 	NSModule module;
   185 
   186 	module = NSLinkModule(dyldObjFileImage, native,
   187 		NSLINKMODULE_OPTION_BINDNOW
   188 		| NSLINKMODULE_OPTION_RETURN_ON_ERROR);
   189 	NSDestroyObjectFileImage(dyldObjFileImage);
   190 
   191 	if (!module) {
   192 	    NSLinkEditErrors editError;
   193 	    int errorNumber;
   194 	    CONST char *name, *msg;
   195 
   196 	    NSLinkEditError(&editError, &errorNumber, &name, &msg);
   197 	    Tcl_AppendResult(interp, msg, NULL);
   198 	    return TCL_ERROR;
   199 	}
   200 
   201 	modulePtr = (Tcl_DyldModuleHandle *)
   202 		ckalloc(sizeof(Tcl_DyldModuleHandle));
   203 	modulePtr->module = module;
   204 	modulePtr->nextPtr = NULL;
   205     }
   206 
   207     dyldLoadHandle = (Tcl_DyldLoadHandle *)
   208 	    ckalloc(sizeof(Tcl_DyldLoadHandle));
   209     dyldLoadHandle->dyldLibHeader = dyldLibHeader;
   210     dyldLoadHandle->modulePtr = modulePtr;
   211     *loadHandle = (Tcl_LoadHandle) dyldLoadHandle;
   212     *unloadProcPtr = &TclpUnloadFile;
   213     return TCL_OK;
   214 }
   215 
   216 /*
   217  *----------------------------------------------------------------------
   218  *
   219  * TclpFindSymbol --
   220  *
   221  *	Looks up a symbol, by name, through a handle associated with a
   222  *	previously loaded piece of code (shared library).
   223  *
   224  * Results:
   225  *	Returns a pointer to the function associated with 'symbol' if it is
   226  *	found. Otherwise returns NULL and may leave an error message in the
   227  *	interp's result.
   228  *
   229  *----------------------------------------------------------------------
   230  */
   231 
   232 MODULE_SCOPE Tcl_PackageInitProc *
   233 TclpFindSymbol(
   234     Tcl_Interp *interp,		/* For error reporting. */
   235     Tcl_LoadHandle loadHandle,	/* Handle from TclpDlopen. */
   236     CONST char *symbol)		/* Symbol name to look up. */
   237 {
   238     NSSymbol nsSymbol;
   239     CONST char *native;
   240     Tcl_DString newName, ds;
   241     Tcl_PackageInitProc *proc = NULL;
   242     Tcl_DyldLoadHandle *dyldLoadHandle = (Tcl_DyldLoadHandle *) loadHandle;
   243 
   244     /*
   245      * dyld adds an underscore to the beginning of symbol names.
   246      */
   247 
   248     native = Tcl_UtfToExternalDString(NULL, symbol, -1, &ds);
   249     Tcl_DStringInit(&newName);
   250     Tcl_DStringAppend(&newName, "_", 1);
   251     native = Tcl_DStringAppend(&newName, native, -1);
   252 
   253     if (dyldLoadHandle->dyldLibHeader) {
   254 	nsSymbol = NSLookupSymbolInImage(dyldLoadHandle->dyldLibHeader, native,
   255 		NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW |
   256 		NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
   257 	if (nsSymbol) {
   258 	    /*
   259 	     * Until dyld supports unloading of MY_DYLIB binaries, the
   260 	     * following is not needed.
   261 	     */
   262 
   263 #ifdef DYLD_SUPPORTS_DYLIB_UNLOADING
   264 	    NSModule module = NSModuleForSymbol(nsSymbol);
   265 	    Tcl_DyldModuleHandle *modulePtr = dyldLoadHandle->modulePtr;
   266 
   267 	    while (modulePtr != NULL) {
   268 		if (module == modulePtr->module) {
   269 		    break;
   270 		}
   271 		modulePtr = modulePtr->nextPtr;
   272 	    }
   273 	    if (modulePtr == NULL) {
   274 		modulePtr = (Tcl_DyldModuleHandle *)
   275 			ckalloc(sizeof(Tcl_DyldModuleHandle));
   276 		modulePtr->module = module;
   277 		modulePtr->nextPtr = dyldLoadHandle->modulePtr;
   278 		dyldLoadHandle->modulePtr = modulePtr;
   279 	    }
   280 #endif /* DYLD_SUPPORTS_DYLIB_UNLOADING */
   281 
   282 	} else {
   283 	    NSLinkEditErrors editError;
   284 	    int errorNumber;
   285 	    CONST char *name, *msg;
   286 
   287 	    NSLinkEditError(&editError, &errorNumber, &name, &msg);
   288 	    Tcl_AppendResult(interp, msg, NULL);
   289 	}
   290     } else {
   291 	nsSymbol = NSLookupSymbolInModule(dyldLoadHandle->modulePtr->module,
   292 		native);
   293     }
   294     if (nsSymbol) {
   295 	proc = NSAddressOfSymbol(nsSymbol);
   296     }
   297     Tcl_DStringFree(&newName);
   298     Tcl_DStringFree(&ds);
   299 
   300     return proc;
   301 }
   302 
   303 /*
   304  *----------------------------------------------------------------------
   305  *
   306  * TclpUnloadFile --
   307  *
   308  *	Unloads a dynamically loaded binary code file from memory. Code
   309  *	pointers in the formerly loaded file are no longer valid after calling
   310  *	this function.
   311  *
   312  * Results:
   313  *	None.
   314  *
   315  * Side effects:
   316  *	Code dissapears from memory. Note that dyld currently only supports
   317  *	unloading of binaries of type MH_BUNDLE loaded with NSLinkModule() in
   318  *	TclpDlopen() above.
   319  *
   320  *----------------------------------------------------------------------
   321  */
   322 
   323 MODULE_SCOPE void
   324 TclpUnloadFile(
   325     Tcl_LoadHandle loadHandle)	/* loadHandle returned by a previous call to
   326 				 * TclpDlopen(). The loadHandle is a token
   327 				 * that represents the loaded file. */
   328 {
   329     Tcl_DyldLoadHandle *dyldLoadHandle = (Tcl_DyldLoadHandle *) loadHandle;
   330     Tcl_DyldModuleHandle *modulePtr = dyldLoadHandle->modulePtr;
   331 
   332     while (modulePtr != NULL) {
   333 	void *ptr;
   334 
   335 	NSUnLinkModule(modulePtr->module,
   336 		NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES);
   337 	ptr = modulePtr;
   338 	modulePtr = modulePtr->nextPtr;
   339 	ckfree(ptr);
   340     }
   341     ckfree((char*) dyldLoadHandle);
   342 }
   343 
   344 /*
   345  *----------------------------------------------------------------------
   346  *
   347  * TclGuessPackageName --
   348  *
   349  *	If the "load" command is invoked without providing a package name,
   350  *	this procedure is invoked to try to figure it out.
   351  *
   352  * Results:
   353  *	Always returns 0 to indicate that we couldn't figure out a package
   354  *	name; generic code will then try to guess the package from the file
   355  *	name. A return value of 1 would have meant that we figured out the
   356  *	package name and put it in bufPtr.
   357  *
   358  * Side effects:
   359  *	None.
   360  *
   361  *----------------------------------------------------------------------
   362  */
   363 
   364 int
   365 TclGuessPackageName(
   366     CONST char *fileName,	/* Name of file containing package (already
   367 				 * translated to local form if needed). */
   368     Tcl_DString *bufPtr)	/* Initialized empty dstring. Append package
   369 				 * name to this if possible. */
   370 {
   371     return 0;
   372 }
   373 
   374 #ifdef TCL_LOAD_FROM_MEMORY
   375 /*
   376  *----------------------------------------------------------------------
   377  *
   378  * TclpLoadMemoryGetBuffer --
   379  *
   380  *	Allocate a buffer that can be used with TclpLoadMemory() below.
   381  *
   382  * Results:
   383  *	Pointer to allocated buffer or NULL if an error occurs.
   384  *
   385  * Side effects:
   386  *	Buffer is allocated.
   387  *
   388  *----------------------------------------------------------------------
   389  */
   390 
   391 MODULE_SCOPE void *
   392 TclpLoadMemoryGetBuffer(
   393     Tcl_Interp *interp,		/* Used for error reporting. */
   394     int size)			/* Size of desired buffer. */
   395 {
   396     void *buffer = NULL;
   397 
   398     /*
   399      * NSCreateObjectFileImageFromMemory is available but always fails
   400      * prior to Darwin 7.
   401      */
   402     if (tclMacOSXDarwinRelease >= 7) {
   403 	/*
   404 	 * We must allocate the buffer using vm_allocate, because
   405 	 * NSCreateObjectFileImageFromMemory will dispose of it using
   406 	 * vm_deallocate.
   407 	 */
   408 
   409 	if (vm_allocate(mach_task_self(), (vm_address_t *) &buffer, size, 1)) {
   410 	    buffer = NULL;
   411 	}
   412     }
   413     return buffer;
   414 }
   415 
   416 /*
   417  *----------------------------------------------------------------------
   418  *
   419  * TclpLoadMemory --
   420  *
   421  *	Dynamically loads binary code file from memory and returns a handle to
   422  *	the new code.
   423  *
   424  * Results:
   425  *	A standard Tcl completion code. If an error occurs, an error message
   426  *	is left in the interpreter's result.
   427  *
   428  * Side effects:
   429  *	New code is loaded from memory.
   430  *
   431  *----------------------------------------------------------------------
   432  */
   433 
   434 MODULE_SCOPE int
   435 TclpLoadMemory(
   436     Tcl_Interp *interp,		/* Used for error reporting. */
   437     void *buffer,		/* Buffer containing the desired code
   438 				 * (allocated with TclpLoadMemoryGetBuffer). */
   439     int size,			/* Allocation size of buffer. */
   440     int codeSize,		/* Size of code data read into buffer or -1 if
   441 				 * an error occurred and the buffer should
   442 				 * just be freed. */
   443     Tcl_LoadHandle *loadHandle,	/* Filled with token for dynamically loaded
   444 				 * file which will be passed back to
   445 				 * (*unloadProcPtr)() to unload the file. */
   446     Tcl_FSUnloadFileProc **unloadProcPtr)
   447 				/* Filled with address of Tcl_FSUnloadFileProc
   448 				 * function which should be used for this
   449 				 * file. */
   450 {
   451     Tcl_DyldLoadHandle *dyldLoadHandle;
   452     NSObjectFileImage dyldObjFileImage = NULL;
   453     Tcl_DyldModuleHandle *modulePtr;
   454     NSModule module;
   455     CONST char *objFileImageErrMsg = NULL;
   456 
   457     /*
   458      * Try to create an object file image that we can load from.
   459      */
   460 
   461     if (codeSize >= 0) {
   462 	NSObjectFileImageReturnCode err = NSObjectFileImageSuccess;
   463 	CONST struct fat_header *fh = buffer;
   464 	uint32_t ms = 0;
   465 #ifndef __LP64__
   466 	CONST struct mach_header *mh = NULL;
   467 	#define mh_magic OSSwapHostToBigInt32(MH_MAGIC)
   468 	#define mh_size  sizeof(struct mach_header)
   469 #else
   470 	CONST struct mach_header_64 *mh = NULL;
   471 	#define mh_magic OSSwapHostToBigInt32(MH_MAGIC_64)
   472 	#define mh_size  sizeof(struct mach_header_64)
   473 #endif
   474 	
   475 	if ((size_t) codeSize >= sizeof(struct fat_header)
   476 		&& fh->magic == OSSwapHostToBigInt32(FAT_MAGIC)) {
   477 	    /*
   478 	     * Fat binary, try to find mach_header for our architecture
   479 	     */
   480 	    uint32_t fh_nfat_arch = OSSwapBigToHostInt32(fh->nfat_arch);
   481 	    
   482 	    if ((size_t) codeSize >= sizeof(struct fat_header) + 
   483 		    fh_nfat_arch * sizeof(struct fat_arch)) {
   484 		void *fatarchs = (char*)buffer + sizeof(struct fat_header);
   485 		CONST NXArchInfo *arch = NXGetLocalArchInfo();
   486 		struct fat_arch *fa;
   487 		
   488 		if (fh->magic != FAT_MAGIC) {
   489 		    swap_fat_arch(fatarchs, fh_nfat_arch, arch->byteorder);
   490 		}
   491 		fa = NXFindBestFatArch(arch->cputype, arch->cpusubtype,
   492 			fatarchs, fh_nfat_arch);
   493 		if (fa) {
   494 		    mh = (void*)((char*)buffer + fa->offset);
   495 		    ms = fa->size;
   496 		} else {
   497 		    err = NSObjectFileImageInappropriateFile;
   498 		}
   499 		if (fh->magic != FAT_MAGIC) {
   500 		    swap_fat_arch(fatarchs, fh_nfat_arch, arch->byteorder);
   501 		}
   502 	    } else {
   503 		err = NSObjectFileImageInappropriateFile;
   504 	    }
   505 	} else {
   506 	    /*
   507 	     * Thin binary
   508 	     */
   509 	    mh = buffer;
   510 	    ms = codeSize;
   511 	}
   512 	if (ms && !(ms >= mh_size && mh->magic == mh_magic &&
   513 		 mh->filetype == OSSwapHostToBigInt32(MH_BUNDLE))) {
   514 	    err = NSObjectFileImageInappropriateFile;
   515 	}
   516 	if (err == NSObjectFileImageSuccess) {
   517 	    err = NSCreateObjectFileImageFromMemory(buffer, codeSize,
   518 		    &dyldObjFileImage);
   519 	}
   520 	objFileImageErrMsg = DyldOFIErrorMsg(err);
   521     }
   522 
   523     /*
   524      * If it went wrong (or we were asked to just deallocate), get rid of the
   525      * memory block and create an error message.
   526      */
   527 
   528     if (dyldObjFileImage == NULL) {
   529 	vm_deallocate(mach_task_self(), (vm_address_t) buffer, size);
   530 	if (objFileImageErrMsg != NULL) {
   531 	    Tcl_AppendResult(interp,
   532 		    "NSCreateObjectFileImageFromMemory() error: ",
   533 		    objFileImageErrMsg, NULL);
   534 	}
   535 	return TCL_ERROR;
   536     }
   537 
   538     /*
   539      * Extract the module we want from the image of the object file.
   540      */
   541 
   542     module = NSLinkModule(dyldObjFileImage, "[Memory Based Bundle]",
   543 	    NSLINKMODULE_OPTION_BINDNOW | NSLINKMODULE_OPTION_RETURN_ON_ERROR);
   544     NSDestroyObjectFileImage(dyldObjFileImage);
   545 
   546     if (!module) {
   547 	NSLinkEditErrors editError;
   548 	int errorNumber;
   549 	CONST char *name, *msg;
   550 
   551 	NSLinkEditError(&editError, &errorNumber, &name, &msg);
   552 	Tcl_AppendResult(interp, msg, NULL);
   553 	return TCL_ERROR;
   554     }
   555 
   556     /*
   557      * Stash the module reference within the load handle we create and return.
   558      */
   559 
   560     modulePtr = (Tcl_DyldModuleHandle *) ckalloc(sizeof(Tcl_DyldModuleHandle));
   561     modulePtr->module = module;
   562     modulePtr->nextPtr = NULL;
   563 
   564     dyldLoadHandle = (Tcl_DyldLoadHandle *)
   565 	    ckalloc(sizeof(Tcl_DyldLoadHandle));
   566     dyldLoadHandle->dyldLibHeader = NULL;
   567     dyldLoadHandle->modulePtr = modulePtr;
   568     *loadHandle = (Tcl_LoadHandle) dyldLoadHandle;
   569     *unloadProcPtr = &TclpUnloadFile;
   570     return TCL_OK;
   571 }
   572 #endif
   573 
   574 /*
   575  * Local Variables:
   576  * mode: c
   577  * c-basic-offset: 4
   578  * fill-column: 78
   579  * End:
   580  */