/*  Determines whether an executable's header matches the current architecture, ppc, and/or i386. 
*   Returns true if the header corresponds to a Mach-O, 64-bit Mach-O, or universal binary executable, false otherwise.
*   Returns by reference the result of matching against a given architecture (matches_current, matches_ppc, matches_i386).
*   Checks for a given architecture only if the corresponding return-by-reference argument is non-NULL. 
*/
static Boolean examine_header(uint8_t *bytes, ssize_t length, Boolean *matches_current, Boolean *matches_ppc, Boolean *matches_i386) {
    Boolean retval = false;
    uint32_t magic = 0, num_fat = 0, max_fat = 0;
    struct fat_arch one_fat = {0}, *fat = NULL;
    const NXArchInfo *current_arch, *ppc_arch, *i386_arch;
    
    // Look for any of the six magic numbers relevant to Mach-O executables, and swap the header if necessary.
    if (length >= sizeof(struct mach_header_64)) {
        magic = *((uint32_t *)bytes);
        max_fat = (length - sizeof(struct fat_header)) / sizeof(struct fat_arch);
        if (MH_MAGIC == magic || MH_CIGAM == magic) {
            struct mach_header *mh = (struct mach_header *)bytes;
            if (MH_CIGAM == magic) swap_header(bytes, length);
            one_fat.cputype = mh->cputype;
            one_fat.cpusubtype = mh->cpusubtype;
            fat = &one_fat;
            num_fat = 1;
        } else if (MH_MAGIC_64 == magic || MH_CIGAM_64 == magic) {
            struct mach_header_64 *mh = (struct mach_header_64 *)bytes;
            if (MH_CIGAM_64 == magic) swap_header(bytes, length);
            one_fat.cputype = mh->cputype;
            one_fat.cpusubtype = mh->cpusubtype;
            fat = &one_fat;
            num_fat = 1;
        } else if (FAT_MAGIC == magic || FAT_CIGAM == magic) {
            fat = (struct fat_arch *)(bytes + sizeof(struct fat_header));
            if (FAT_CIGAM == magic) swap_header(bytes, length);
            num_fat = ((struct fat_header *)bytes)->nfat_arch;
            if (num_fat > max_fat) num_fat = max_fat;
        }
    }
    
    // Set the return value depending on whether the header appears valid.
    retval = ((fat && num_fat > 0) ? true : false);
    
    // Check for a match against the current architecture specification, if requested.
    if (matches_current) {
        current_arch = NXGetLocalArchInfo();
        *matches_current = ((retval && current_arch && NXFindBestFatArch(current_arch->cputype, current_arch->cpusubtype, fat, num_fat)) ? true : false);
    }
    // Check for a match against the ppc architecture specification, if requested.
    if (matches_ppc) {
        ppc_arch = NXGetArchInfoFromName("ppc");
        *matches_ppc = ((retval && ppc_arch && NXFindBestFatArch(ppc_arch->cputype, ppc_arch->cpusubtype, fat, num_fat)) ? true : false);
    }
    // Check for a match against the i386 architecture specification, if requested.
    if (matches_i386) {
        i386_arch = NXGetArchInfoFromName("i386");
        *matches_i386 = ((retval && i386_arch && NXFindBestFatArch(i386_arch->cputype, i386_arch->cpusubtype, fat, num_fat)) ? true : false);
    }
    return retval;
}
Exemple #2
0
MODULE_SCOPE int
TclpLoadMemory(
    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 dyldObjFileImage = NULL;
    Tcl_DyldModuleHandle *modulePtr;
    NSModule module;
    const char *objFileImageErrMsg = NULL;

    /*
     * Try to create an object file image that we can load from.
     */

    if (codeSize >= 0) {
	NSObjectFileImageReturnCode err = NSObjectFileImageSuccess;
	const struct fat_header *fh = buffer;
	uint32_t ms = 0;
#ifndef __LP64__
	const struct mach_header *mh = NULL;
	#define mh_size  sizeof(struct mach_header)
	#define mh_magic MH_MAGIC
	#define arch_abi 0
#else
	const struct mach_header_64 *mh = NULL;
	#define mh_size  sizeof(struct mach_header_64)
	#define mh_magic MH_MAGIC_64
	#define arch_abi CPU_ARCH_ABI64
#endif

	if ((size_t) codeSize >= sizeof(struct fat_header)
		&& fh->magic == OSSwapHostToBigInt32(FAT_MAGIC)) {
	    uint32_t fh_nfat_arch = OSSwapBigToHostInt32(fh->nfat_arch);

	    /*
	     * Fat binary, try to find mach_header for our architecture
	     */

	    TclLoadDbgMsg("Fat binary, %d archs", fh_nfat_arch);
	    if ((size_t) codeSize >= sizeof(struct fat_header) +
		    fh_nfat_arch * sizeof(struct fat_arch)) {
		void *fatarchs = (char*)buffer + sizeof(struct fat_header);
		const NXArchInfo *arch = NXGetLocalArchInfo();
		struct fat_arch *fa;

		if (fh->magic != FAT_MAGIC) {
		    swap_fat_arch(fatarchs, fh_nfat_arch, arch->byteorder);
		}
		fa = NXFindBestFatArch(arch->cputype | arch_abi,
			arch->cpusubtype, fatarchs, fh_nfat_arch);
		if (fa) {
		    TclLoadDbgMsg("NXFindBestFatArch() successful: "
			    "local cputype %d subtype %d, "
			    "fat cputype %d subtype %d",
			    arch->cputype | arch_abi, arch->cpusubtype,
			    fa->cputype, fa->cpusubtype);
		    mh = (void*)((char*)buffer + fa->offset);
		    ms = fa->size;
		} else {
		    TclLoadDbgMsg("NXFindBestFatArch() failed");
		    err = NSObjectFileImageInappropriateFile;
		}
		if (fh->magic != FAT_MAGIC) {
		    swap_fat_arch(fatarchs, fh_nfat_arch, arch->byteorder);
		}
	    } else {
		TclLoadDbgMsg("Fat binary header failure");
		err = NSObjectFileImageInappropriateFile;
	    }
	} else {
	    /*
	     * Thin binary
	     */

	    TclLoadDbgMsg("Thin binary");
	    mh = buffer;
	    ms = codeSize;
	}
	if (ms && !(ms >= mh_size && mh->magic == mh_magic &&
		 mh->filetype == MH_BUNDLE)) {
	    TclLoadDbgMsg("Inappropriate file: magic %x filetype %d",
		    mh->magic, mh->filetype);
	    err = NSObjectFileImageInappropriateFile;
	}
	if (err == NSObjectFileImageSuccess) {
	    err = NSCreateObjectFileImageFromMemory(buffer, codeSize,
		    &dyldObjFileImage);
	    if (err == NSObjectFileImageSuccess) {
		TclLoadDbgMsg("NSCreateObjectFileImageFromMemory() "
			"successful");
	    } else {
		objFileImageErrMsg = DyldOFIErrorMsg(err);
		TclLoadDbgMsg("NSCreateObjectFileImageFromMemory() failed: %s",
			objFileImageErrMsg);
	    }
	} else {
	    objFileImageErrMsg = DyldOFIErrorMsg(err);
	}
    }

    /*
     * If it went wrong (or we were asked to just deallocate), get rid of the
     * memory block and create an error message.
     */

    if (dyldObjFileImage == NULL) {
	vm_deallocate(mach_task_self(), (vm_address_t) buffer, size);
	if (objFileImageErrMsg != NULL) {
	    Tcl_AppendResult(interp, "NSCreateObjectFileImageFromMemory() "
		    "error: ", objFileImageErrMsg, NULL);
	}
	return TCL_ERROR;
    }

    /*
     * Extract the module we want from the image of the object file.
     */

    module = NSLinkModule(dyldObjFileImage, "[Memory Based Bundle]",
	    NSLINKMODULE_OPTION_BINDNOW | NSLINKMODULE_OPTION_RETURN_ON_ERROR);
    NSDestroyObjectFileImage(dyldObjFileImage);
    if (module) {
	TclLoadDbgMsg("NSLinkModule() successful");
    } else {
	NSLinkEditErrors editError;
	int errorNumber;
	const char *errorName, *errMsg;

	NSLinkEditError(&editError, &errorNumber, &errorName, &errMsg);
	TclLoadDbgMsg("NSLinkModule() failed: %s", errMsg);
	Tcl_AppendResult(interp, errMsg, NULL);
	return TCL_ERROR;
    }

    /*
     * Stash the module reference within the load handle we create and return.
     */

    modulePtr = (Tcl_DyldModuleHandle *) ckalloc(sizeof(Tcl_DyldModuleHandle));
    modulePtr->module = module;
    modulePtr->nextPtr = NULL;
    dyldLoadHandle = (Tcl_DyldLoadHandle *)
	    ckalloc(sizeof(Tcl_DyldLoadHandle));
#if TCL_DYLD_USE_DLFCN
    dyldLoadHandle->dlHandle = NULL;
#endif
    dyldLoadHandle->dyldLibHeader = NULL;
    dyldLoadHandle->modulePtr = modulePtr;
    *loadHandle = (Tcl_LoadHandle) dyldLoadHandle;
    *unloadProcPtr = &TclpUnloadFile;
    return TCL_OK;
}
Exemple #3
0
int fat_iterator_find_fat_arch(
    fat_iterator iter,
    cpu_type_t cputype,
    cpu_subtype_t cpusubtype,
    struct fat_arch * fat_arch_out)
{
    int result = 0;
    uint32_t magic;

    uint32_t nfat_arch;

    struct fat_arch * fat_arches;
    struct fat_arch * fat_arches_copy = NULL;  // must free

    struct fat_arch * found_arch;

    magic = MAGIC32(iter->file_start);

    if (iter->fat_header) {
        uint32_t fat_arches_size;
        uint32_t index;

        nfat_arch = iter->num_arches;
        fat_arches_size = nfat_arch * sizeof(struct fat_arch);

        fat_arches_copy = (struct fat_arch *)(malloc(fat_arches_size));
        if (!fat_arches_copy) {
            goto finish;
        }

        fat_arches = fat_arches_copy;

        memcpy(fat_arches, iter->fat_arches, fat_arches_size);

        /* NXFindBestFatArch() requires all the fat info to be in host
         * byte order.
         */
        for (index = 0; index < nfat_arch; index++) {
            fat_arches[index].cputype =
                OSSwapBigToHostInt32(fat_arches[index].cputype);
            fat_arches[index].cpusubtype =
                OSSwapBigToHostInt32(fat_arches[index].cpusubtype);
            fat_arches[index].offset =
                OSSwapBigToHostInt32(fat_arches[index].offset);
            fat_arches[index].size =
                OSSwapBigToHostInt32(fat_arches[index].size);
            fat_arches[index].align =
                OSSwapBigToHostInt32(fat_arches[index].align);
        }
    } else {
        struct fat_arch fake_fat_arches;
        uint8_t  swap;
        struct mach_header * mach_hdr;

        nfat_arch = 1;

        bzero(&fake_fat_arches, sizeof(fake_fat_arches));

        fat_arches = &fake_fat_arches;

        swap = ISSWAPPEDMACHO(magic);
        mach_hdr = (struct mach_header *)iter->file_start;
        fat_arches[0].cputype = CondSwapInt32(swap, mach_hdr->cputype);
        fat_arches[0].cpusubtype = CondSwapInt32(swap, mach_hdr->cpusubtype);

        fat_arches[0].offset = 0;
        fat_arches[0].size = iter->file_end - iter->file_start;
        fat_arches[0].align = 1;  // not used anyhow
    }

    found_arch = NXFindBestFatArch(cputype, cpusubtype, fat_arches, nfat_arch);
    if (found_arch) {
        result = 1;
        if (fat_arch_out) {
            memcpy(fat_arch_out, found_arch, sizeof(*fat_arch_out));
        }
    }

finish:
    if (fat_arches_copy) {
        free(fat_arches_copy);
    }

    return result;
}