summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generic/tclIOUtil.c54
-rw-r--r--generic/tclInt.h10
-rw-r--r--unix/tclConfig.h.in3
-rw-r--r--unix/tclLoadDyld.c330
4 files changed, 350 insertions, 47 deletions
diff --git a/generic/tclIOUtil.c b/generic/tclIOUtil.c
index f94a3c8..8dfd7f5 100644
--- a/generic/tclIOUtil.c
+++ b/generic/tclIOUtil.c
@@ -17,7 +17,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclIOUtil.c,v 1.118 2005/05/10 18:34:40 kennykb Exp $
+ * RCS: @(#) $Id: tclIOUtil.c,v 1.119 2005/05/23 20:19:44 das Exp $
*/
#include "tclInt.h"
@@ -3065,6 +3065,58 @@ TclLoadFile(interp, pathPtr, symc, symbols, procPtrs,
return TCL_ERROR;
}
+#ifdef TCL_LOAD_FROM_MEMORY
+ /*
+ * The platform supports loading code from memory, so ask for a
+ * buffer of the appropriate size, read the file into it and
+ * load the code from the buffer:
+ */
+ do {
+ int ret, size;
+ void *buffer;
+ Tcl_StatBuf statBuf;
+ Tcl_Channel data;
+
+ ret = Tcl_FSStat(pathPtr, &statBuf);
+ if (ret < 0) {
+ break;
+ }
+ size = (int) statBuf.st_size;
+ /* Tcl_Read takes an int: check that file size isn't wide */
+ if (size != (Tcl_WideInt)statBuf.st_size) {
+ break;
+ }
+ data = Tcl_FSOpenFileChannel(interp, pathPtr, "r", 0666);
+ if (!data) {
+ break;
+ }
+ buffer = TclpLoadMemoryGetBuffer(interp, size);
+ if (!buffer) {
+ Tcl_Close(interp, data);
+ break;
+ }
+ Tcl_SetChannelOption(interp, data, "-translation", "binary");
+ ret = Tcl_Read(data, buffer, size);
+ Tcl_Close(interp, data);
+ ret = TclpLoadMemory(interp, buffer, size, ret, handlePtr, unloadProcPtr);
+ if (ret == TCL_OK) {
+ int i;
+ if (*handlePtr == NULL) {
+ break;
+ }
+ for (i = 0;i < symc;i++) {
+ if (symbols[i] != NULL) {
+ *procPtrs[i] = TclpFindSymbol(interp, *handlePtr,
+ symbols[i]);
+ }
+ }
+ *clientDataPtr = (ClientData)*handlePtr;
+ return TCL_OK;
+ }
+ } while (0);
+ Tcl_ResetResult(interp);
+#endif
+
/*
* Get a temporary filename to use, first to
* copy the file into, and then to load.
diff --git a/generic/tclInt.h b/generic/tclInt.h
index 0aa7f5a..a739fe8 100644
--- a/generic/tclInt.h
+++ b/generic/tclInt.h
@@ -12,7 +12,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclInt.h,v 1.230 2005/05/18 15:43:36 dgp Exp $
+ * RCS: @(#) $Id: tclInt.h,v 1.231 2005/05/23 20:19:45 das Exp $
*/
#ifndef _TCLINT
@@ -2075,6 +2075,14 @@ MODULE_SCOPE int TclpDlopen _ANSI_ARGS_((Tcl_Interp *interp,
Tcl_FSUnloadFileProc **unloadProcPtr));
MODULE_SCOPE int TclpUtime _ANSI_ARGS_((Tcl_Obj *pathPtr,
struct utimbuf *tval));
+#ifdef TCL_LOAD_FROM_MEMORY
+MODULE_SCOPE void* TclpLoadMemoryGetBuffer _ANSI_ARGS_((
+ Tcl_Interp *interp, int size));
+MODULE_SCOPE int TclpLoadMemory _ANSI_ARGS_((Tcl_Interp *interp,
+ void *buffer, int size, int codeSize,
+ Tcl_LoadHandle *loadHandle,
+ Tcl_FSUnloadFileProc **unloadProcPtr));
+#endif
/*
*----------------------------------------------------------------
diff --git a/unix/tclConfig.h.in b/unix/tclConfig.h.in
index 0806e0d..0926138 100644
--- a/unix/tclConfig.h.in
+++ b/unix/tclConfig.h.in
@@ -282,6 +282,9 @@
/* Is Tcl built as a framework? */
#undef TCL_FRAMEWORK
+/* Can this platform load code from memory? */
+#undef TCL_LOAD_FROM_MEMORY
+
/* Is memory debugging enabled? */
#undef TCL_MEM_DEBUG
diff --git a/unix/tclLoadDyld.c b/unix/tclLoadDyld.c
index c131050..60ec680 100644
--- a/unix/tclLoadDyld.c
+++ b/unix/tclLoadDyld.c
@@ -11,11 +11,12 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclLoadDyld.c,v 1.16 2005/05/14 20:46:48 das Exp $
+ * RCS: @(#) $Id: tclLoadDyld.c,v 1.17 2005/05/23 20:19:47 das Exp $
*/
#include "tclInt.h"
#include <mach-o/dyld.h>
+#include <mach/mach.h>
typedef struct Tcl_DyldModuleHandle {
struct Tcl_DyldModuleHandle *nextModuleHandle;
@@ -27,6 +28,59 @@ typedef struct Tcl_DyldLoadHandle {
Tcl_DyldModuleHandle *firstModuleHandle;
} Tcl_DyldLoadHandle;
+#ifdef TCL_LOAD_FROM_MEMORY
+typedef struct ThreadSpecificData {
+ int haveLoadMemory;
+} ThreadSpecificData;
+
+static Tcl_ThreadDataKey dataKey;
+#endif
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * DyldOFIErrorMsg --
+ *
+ * Converts a numerical NSObjectFileImage error into an
+ * error message string.
+ *
+ * Results:
+ * Error message string.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static CONST char* DyldOFIErrorMsg(int err) {
+ CONST char *ofi_msg = NULL;
+
+ if (err != NSObjectFileImageSuccess) {
+ switch(err) {
+ case NSObjectFileImageFailure:
+ ofi_msg = "object file setup failure";
+ break;
+ case NSObjectFileImageInappropriateFile:
+ ofi_msg = "not a Mach-O MH_BUNDLE file";
+ break;
+ case NSObjectFileImageArch:
+ ofi_msg = "no object for this architecture";
+ break;
+ case NSObjectFileImageFormat:
+ ofi_msg = "bad object file format";
+ break;
+ case NSObjectFileImageAccess:
+ ofi_msg = "can't read object file";
+ break;
+ default:
+ ofi_msg = "unknown error";
+ break;
+ }
+ }
+ return ofi_msg;
+}
+
/*
*----------------------------------------------------------------------
*
@@ -45,7 +99,7 @@ typedef struct Tcl_DyldLoadHandle {
*----------------------------------------------------------------------
*/
-int
+MODULE_SCOPE int
TclpDlopen(interp, pathPtr, loadHandle, unloadProcPtr)
Tcl_Interp *interp; /* Used for error reporting. */
Tcl_Obj *pathPtr; /* Name of the file containing the desired
@@ -60,6 +114,8 @@ TclpDlopen(interp, pathPtr, loadHandle, unloadProcPtr)
{
Tcl_DyldLoadHandle *dyldLoadHandle;
CONST struct mach_header *dyld_lib;
+ NSObjectFileImage dyld_ofi = NULL;
+ Tcl_DyldModuleHandle *dyldModuleHandle = NULL;
CONST char *native;
/*
@@ -73,32 +129,66 @@ TclpDlopen(interp, pathPtr, loadHandle, unloadProcPtr)
NSADDIMAGE_OPTION_RETURN_ON_ERROR);
if (!dyld_lib) {
- /*
- * Let the OS loader examine the binary search path for
- * whatever string the user gave us which hopefully refers
- * to a file on the binary path
- */
- Tcl_DString ds;
- char *fileName = Tcl_GetString(pathPtr);
- native = Tcl_UtfToExternalDString(NULL, fileName, -1, &ds);
- dyld_lib = NSAddImage(native,
- NSADDIMAGE_OPTION_WITH_SEARCHING |
- NSADDIMAGE_OPTION_RETURN_ON_ERROR);
- Tcl_DStringFree(&ds);
- }
-
- if (!dyld_lib) {
NSLinkEditErrors editError;
- CONST char *name, *msg;
+ CONST char *name, *msg, *ofi_msg = NULL;
+
NSLinkEditError(&editError, &errno, &name, &msg);
- Tcl_AppendResult(interp, msg, (char *) NULL);
- return TCL_ERROR;
+ if (editError == NSLinkEditFileAccessError) {
+ /* The requested file was not found:
+ * let the OS loader examine the binary search path for
+ * whatever string the user gave us which hopefully refers
+ * to a file on the binary path
+ */
+ Tcl_DString ds;
+ char *fileName = Tcl_GetString(pathPtr);
+ CONST char *native = Tcl_UtfToExternalDString(NULL, fileName, -1, &ds);
+ dyld_lib = NSAddImage(native,
+ NSADDIMAGE_OPTION_WITH_SEARCHING |
+ NSADDIMAGE_OPTION_RETURN_ON_ERROR);
+ Tcl_DStringFree(&ds);
+ if (!dyld_lib) {
+ NSLinkEditError(&editError, &errno, &name, &msg);
+ }
+ } else if ((editError == NSLinkEditFileFormatError && errno == EBADMACHO)) {
+ /* The requested file was found but was not of type MH_DYLIB,
+ * attempt to load it as a MH_BUNDLE: */
+ NSObjectFileImageReturnCode err;
+ err = NSCreateObjectFileImageFromFile(native, &dyld_ofi);
+ ofi_msg = DyldOFIErrorMsg(err);
+ }
+ if (!dyld_lib && !dyld_ofi) {
+ Tcl_AppendResult(interp, msg, (char *) NULL);
+ if (ofi_msg) {
+ Tcl_AppendResult(interp, "NSCreateObjectFileImageFromFile() error: ",
+ ofi_msg, (char *) NULL);
+ }
+ return TCL_ERROR;
+ }
}
+ if (dyld_ofi) {
+ NSModule module;
+ module = NSLinkModule(dyld_ofi, native, NSLINKMODULE_OPTION_BINDNOW |
+ NSLINKMODULE_OPTION_RETURN_ON_ERROR);
+ NSDestroyObjectFileImage(dyld_ofi);
+ if (module) {
+ dyldModuleHandle = (Tcl_DyldModuleHandle *)
+ ckalloc(sizeof(Tcl_DyldModuleHandle));
+ if (!dyldModuleHandle) return TCL_ERROR;
+ dyldModuleHandle->module = module;
+ dyldModuleHandle->nextModuleHandle = NULL;
+ } else {
+ NSLinkEditErrors editError;
+ CONST char *name, *msg;
+ NSLinkEditError(&editError, &errno, &name, &msg);
+ Tcl_AppendResult(interp, msg, (char *) NULL);
+ return TCL_ERROR;
+ }
+ }
dyldLoadHandle = (Tcl_DyldLoadHandle *) ckalloc(sizeof(Tcl_DyldLoadHandle));
if (!dyldLoadHandle) return TCL_ERROR;
dyldLoadHandle->dyld_lib = dyld_lib;
- dyldLoadHandle->firstModuleHandle = NULL;
+ dyldLoadHandle->firstModuleHandle = dyldModuleHandle;
*loadHandle = (Tcl_LoadHandle) dyldLoadHandle;
*unloadProcPtr = &TclpUnloadFile;
return TCL_OK;
@@ -119,7 +209,7 @@ TclpDlopen(interp, pathPtr, loadHandle, unloadProcPtr)
*
*----------------------------------------------------------------------
*/
-Tcl_PackageInitProc*
+MODULE_SCOPE Tcl_PackageInitProc*
TclpFindSymbol(interp, loadHandle, symbol)
Tcl_Interp *interp;
Tcl_LoadHandle loadHandle;
@@ -133,35 +223,54 @@ TclpFindSymbol(interp, loadHandle, symbol)
/*
* dyld adds an underscore to the beginning of symbol names.
*/
-
native = Tcl_UtfToExternalDString(NULL, symbol, -1, &ds);
Tcl_DStringInit(&newName);
Tcl_DStringAppend(&newName, "_", 1);
native = Tcl_DStringAppend(&newName, native, -1);
- nsSymbol = NSLookupSymbolInImage(dyldLoadHandle->dyld_lib, native,
- NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW |
- NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
- if(nsSymbol) {
- Tcl_DyldModuleHandle *dyldModuleHandle;
- proc = NSAddressOfSymbol(nsSymbol);
- dyldModuleHandle = (Tcl_DyldModuleHandle *) ckalloc(sizeof(Tcl_DyldModuleHandle));
- if (dyldModuleHandle) {
- dyldModuleHandle->module = NSModuleForSymbol(nsSymbol);
- dyldModuleHandle->nextModuleHandle = dyldLoadHandle->firstModuleHandle;
- dyldLoadHandle->firstModuleHandle = dyldModuleHandle;
- }
+ if (dyldLoadHandle->dyld_lib) {
+ nsSymbol = NSLookupSymbolInImage(dyldLoadHandle->dyld_lib, native,
+ NSLOOKUPSYMBOLINIMAGE_OPTION_BIND_NOW |
+ NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR);
+ if(nsSymbol) {
+ /* until dyld supports unloading of MY_DYLIB binaries, the
+ * following is not needed: */
+#ifdef DYLD_SUPPORTS_DYLIB_UNLOADING
+ NSModule module = NSModuleForSymbol(nsSymbol);
+ Tcl_DyldModuleHandle *dyldModuleHandle = dyldLoadHandle->firstModuleHandle;
+ while (dyldModuleHandle) {
+ if (module == dyldModuleHandle->module) break;
+ dyldModuleHandle = dyldModuleHandle->nextModuleHandle;
+ }
+ if (!dyldModuleHandle) {
+ dyldModuleHandle = (Tcl_DyldModuleHandle *)
+ ckalloc(sizeof(Tcl_DyldModuleHandle));
+ if (dyldModuleHandle) {
+ dyldModuleHandle->module = module;
+ dyldModuleHandle->nextModuleHandle =
+ dyldLoadHandle->firstModuleHandle;
+ dyldLoadHandle->firstModuleHandle = dyldModuleHandle;
+ }
+ }
+#endif /* DYLD_SUPPORTS_DYLIB_UNLOADING */
+ } else {
+ NSLinkEditErrors editError;
+ CONST char *name, *msg;
+ NSLinkEditError(&editError, &errno, &name, &msg);
+ Tcl_AppendResult(interp, msg, (char *) NULL);
+ }
} else {
- NSLinkEditErrors editError;
- CONST char *name, *msg;
- NSLinkEditError(&editError, &errno, &name, &msg);
- Tcl_AppendResult(interp, msg, (char *) NULL);
+ nsSymbol = NSLookupSymbolInModule(dyldLoadHandle->firstModuleHandle->module,
+ native);
+ }
+ if(nsSymbol) {
+ proc = NSAddressOfSymbol(nsSymbol);
}
Tcl_DStringFree(&newName);
Tcl_DStringFree(&ds);
return proc;
}
-
+
/*
*----------------------------------------------------------------------
*
@@ -176,12 +285,13 @@ TclpFindSymbol(interp, loadHandle, symbol)
*
* Side effects:
* Code dissapears from memory.
- * Note that this is a no-op on older (OpenStep) versions of dyld.
+ * Note that dyld currently only supports unloading of binaries of
+ * type MH_BUNDLE loaded with NSLinkModule() in TclpDlopen() above.
*
*----------------------------------------------------------------------
*/
-void
+MODULE_SCOPE void
TclpUnloadFile(loadHandle)
Tcl_LoadHandle loadHandle; /* loadHandle returned by a previous call
* to TclpDlopen(). The loadHandle is
@@ -193,14 +303,15 @@ TclpUnloadFile(loadHandle)
void *ptr;
while (dyldModuleHandle) {
- NSUnLinkModule(dyldModuleHandle->module, NSUNLINKMODULE_OPTION_NONE);
+ NSUnLinkModule(dyldModuleHandle->module,
+ NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES);
ptr = dyldModuleHandle;
dyldModuleHandle = dyldModuleHandle->nextModuleHandle;
ckfree(ptr);
}
ckfree((char*) dyldLoadHandle);
}
-
+
/*
*----------------------------------------------------------------------
*
@@ -221,7 +332,7 @@ TclpUnloadFile(loadHandle)
*----------------------------------------------------------------------
*/
-int
+MODULE_SCOPE int
TclGuessPackageName(fileName, bufPtr)
CONST char *fileName; /* Name of file containing package (already
* translated to local form if needed). */
@@ -230,3 +341,132 @@ TclGuessPackageName(fileName, bufPtr)
{
return 0;
}
+
+#ifdef TCL_LOAD_FROM_MEMORY
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclpLoadMemoryGetBuffer --
+ *
+ * Allocate a buffer that can be used with TclpLoadMemory() below.
+ *
+ * Results:
+ * Pointer to allocated buffer or NULL if an error occurs.
+ *
+ * Side effects:
+ * Buffer is allocated.
+ *
+ *----------------------------------------------------------------------
+ */
+
+MODULE_SCOPE void*
+TclpLoadMemoryGetBuffer(interp, size)
+ Tcl_Interp *interp; /* Used for error reporting. */
+ int size; /* Size of desired buffer */
+{
+ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey);
+ void * buffer = NULL;
+
+ if (!tsdPtr->haveLoadMemory) {
+ /* NSCreateObjectFileImageFromMemory is available but always
+ * fails prior to Darwin 7 */
+ struct utsname name;
+ if (!uname(&name)) {
+ long release = strtol(name.release, NULL, 10);
+ tsdPtr->haveLoadMemory = (release >= 7) ? 1 : -1;
+ }
+ }
+ if (tsdPtr->haveLoadMemory > 0) {
+ /* We must allocate the buffer using vm_allocate, because
+ * NSCreateObjectFileImageFromMemory will dispose of it
+ * using vm_deallocate.
+ */
+ int err = vm_allocate(mach_task_self(),
+ (vm_address_t*)&buffer, size, 1);
+ if (err) {
+ buffer = NULL;
+ }
+ }
+ return buffer;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclpLoadMemory --
+ *
+ * Dynamically loads binary code file from memory and returns
+ * a handle to the new code.
+ *
+ * Results:
+ * A standard Tcl completion code. If an error occurs, an error
+ * message is left in the interpreter's result.
+ *
+ * Side effects:
+ * New code is loaded from memory.
+ *
+ *----------------------------------------------------------------------
+ */
+
+MODULE_SCOPE int
+TclpLoadMemory(interp, buffer, size, codeSize, loadHandle, unloadProcPtr)
+ Tcl_Interp *interp; /* Used for error reporting. */
+ void *buffer; /* Buffer containing the desired code
+ * (allocated with TclpLoadMemoryGetBuffer). */
+ int size; /* Allocation size of buffer. */
+ int codeSize; /* Size of code data read into buffer or -1 if
+ * an error occurred and the buffer should
+ * just be freed. */
+ Tcl_LoadHandle *loadHandle; /* Filled with token for dynamically loaded
+ * file which will be passed back to
+ * (*unloadProcPtr)() to unload the file. */
+ Tcl_FSUnloadFileProc **unloadProcPtr;
+ /* Filled with address of Tcl_FSUnloadFileProc
+ * function which should be used for
+ * this file. */
+{
+ Tcl_DyldLoadHandle *dyldLoadHandle;
+ NSObjectFileImage dyld_ofi = NULL;
+ Tcl_DyldModuleHandle *dyldModuleHandle;
+ CONST char *ofi_msg = NULL;
+
+ if (codeSize >= 0) {
+ NSObjectFileImageReturnCode err;
+ err = NSCreateObjectFileImageFromMemory(buffer, codeSize, &dyld_ofi);
+ ofi_msg = DyldOFIErrorMsg(err);
+ }
+ if (!dyld_ofi) {
+ vm_deallocate(mach_task_self(), (vm_address_t) buffer, size);
+ if (ofi_msg) {
+ Tcl_AppendResult(interp, "NSCreateObjectFileImageFromFile() error: ",
+ ofi_msg, (char *) NULL);
+ }
+ return TCL_ERROR;
+ } else {
+ NSModule module;
+ module = NSLinkModule(dyld_ofi, "[Memory Based Bundle]",
+ NSLINKMODULE_OPTION_BINDNOW |NSLINKMODULE_OPTION_RETURN_ON_ERROR);
+ NSDestroyObjectFileImage(dyld_ofi);
+ if (module) {
+ dyldModuleHandle = (Tcl_DyldModuleHandle *)
+ ckalloc(sizeof(Tcl_DyldModuleHandle));
+ if (!dyldModuleHandle) return TCL_ERROR;
+ dyldModuleHandle->module = module;
+ dyldModuleHandle->nextModuleHandle = NULL;
+ } else {
+ NSLinkEditErrors editError;
+ CONST char *name, *msg;
+ NSLinkEditError(&editError, &errno, &name, &msg);
+ Tcl_AppendResult(interp, msg, (char *) NULL);
+ return TCL_ERROR;
+ }
+ }
+ dyldLoadHandle = (Tcl_DyldLoadHandle *) ckalloc(sizeof(Tcl_DyldLoadHandle));
+ if (!dyldLoadHandle) return TCL_ERROR;
+ dyldLoadHandle->dyld_lib = NULL;
+ dyldLoadHandle->firstModuleHandle = dyldModuleHandle;
+ *loadHandle = (Tcl_LoadHandle) dyldLoadHandle;
+ *unloadProcPtr = &TclpUnloadFile;
+ return TCL_OK;
+}
+#endif