void dump_fat_header(FILE *obj_file, int is_swap) { int header_size = sizeof(struct fat_header); int arch_size = sizeof(struct fat_arch); struct fat_header *header = load_bytes(obj_file, 0, header_size); if (is_swap) { swap_fat_header(header, 0); } int arch_offset = header_size; for (int i = 0; i < header->nfat_arch; i++) { struct fat_arch *arch = load_bytes(obj_file, arch_offset, arch_size); if (is_swap) { swap_fat_arch(arch, 1, 0); } int mach_header_offset = arch->offset; free(arch); arch_offset += arch_size; uint32_t magic = read_magic(obj_file, mach_header_offset); int is_64 = is_magic_64(magic); int is_swap_mach = should_swap_bytes(magic); dump_mach_header(obj_file, mach_header_offset, is_64, is_swap_mach); } free(header); }
//-------------------------------------------------------------------------- bool macho_file_t::parse_fat_header() { qlseek(li, start_offset); if ( qlread(li, &fheader, sizeof(fheader)) != sizeof(fheader) ) return false; int code = (fheader.magic == FAT_MAGIC); if ( fheader.magic == FAT_CIGAM ) { swap_fat_header(&fheader); code = 2; } if ( code == 0 || fheader.nfat_arch > 16 ) return false; uint32 fsize = qlsize(li); uint32 archs_size = fheader.nfat_arch * sizeof(fat_arch); if ( sizeof(fat_header) + archs_size >= fsize ) return false; fat_archs.resize(fheader.nfat_arch); if ( qlread(li, fat_archs.begin(), archs_size) != archs_size ) { fat_archs.clear(); return false; } for ( uint32_t i=0; i < fheader.nfat_arch; i++ ) { fat_arch *parch = &fat_archs[i]; if ( code == 2 ) swap_fat_arch(parch); if ( parch->size <= sizeof(mach_header) || parch->size >= fsize || parch->offset < sizeof(fat_header) + archs_size || parch->offset + parch->size > fsize ) { fat_archs.clear(); return false; } } return true; }
static int register_libraries(int fd, const char* build, const char* project, const char* filename, int* isMachO) { ssize_t res; uint32_t magic; res = read(fd, &magic, sizeof(uint32_t)); if (res < sizeof(uint32_t)) { goto error_out; } if (magic == FAT_MAGIC || magic == FAT_CIGAM) { struct fat_header fh; int swap = 0; res = read(fd, &fh.nfat_arch, sizeof(struct fat_header) - sizeof(uint32_t)); if (res < sizeof(uint32_t)) { goto error_out; } if (magic == FAT_CIGAM) { swap = 1; swap_fat_header(&fh, NXHostByteOrder()); } int i; for (i = 0; i < fh.nfat_arch; ++i) { struct fat_arch fa; res = read(fd, &fa, sizeof(fa)); if (res < sizeof(fa)) { goto error_out; } if (swap) swap_fat_arch(&fa, 1, NXHostByteOrder()); off_t save = lseek(fd, 0, SEEK_CUR); lseek(fd, (off_t)fa.offset, SEEK_SET); register_mach_header(build, project, filename, &fa, fd, isMachO); lseek(fd, save, SEEK_SET); } } else { lseek(fd, 0, SEEK_SET); register_mach_header(build, project, filename, NULL, fd, isMachO); } error_out: return 0; }
/** * \fn moa_error_t moa_read_fat_section(struct s_mach_file* ptr_mach_file) * \brief Read the fat section of a mach_file (fat_header + fat_arch). * * \param ptr_mach_file Pointer to mach archive. * * \return MOA_SUCCESS if all succeed, else error number. */ moa_error_t moa_read_fat_section(struct s_mach_file* ptr_mach_file) { if (NULL == ptr_mach_file) return MOA_ERR_NULLPTR; /// Reset file offset lseek(ptr_mach_file->fd, (off_t)0, SEEK_SET); /// Read the fat header const size_t mach_header_size = sizeof(ptr_mach_file->fat_section.fat_header); if (read(ptr_mach_file->fd, &ptr_mach_file->fat_section.fat_header, mach_header_size) != (ssize_t)mach_header_size) return MOA_ERR_READ_FAT_HEADER; /// Check if the file is actually a mach archive if (!moa_is_mach_archive(ptr_mach_file)) return MOA_ERR_NOT_MACH_ARCHIVE; /// Get host machine byte order /// If intel CPU, we need to change the byte order to lil endian enum NXByteOrder host_byte_order = NXHostByteOrder(); if (NX_LittleEndian == host_byte_order) swap_fat_header(&ptr_mach_file->fat_section.fat_header, NX_LittleEndian); else if (NX_UnknownByteOrder == NXHostByteOrder()) return MOA_ERR_UNKNOW_ARCH; /// Read the N fat archs if (ptr_mach_file->fat_section.fat_archs != NULL) free(ptr_mach_file->fat_section.fat_archs); const size_t fat_arch_size = ptr_mach_file->fat_section.fat_header.nfat_arch * sizeof(*ptr_mach_file->fat_section.fat_archs); if (NULL == (ptr_mach_file->fat_section.fat_archs = (struct fat_arch*)malloc(fat_arch_size))) return MOA_ERR_READ_FAT_ARCH; if (read(ptr_mach_file->fd, ptr_mach_file->fat_section.fat_archs, fat_arch_size) != (ssize_t)fat_arch_size) return MOA_ERR_READ_FAT_ARCH; if (NX_LittleEndian == host_byte_order) swap_fat_arch(ptr_mach_file->fat_section.fat_archs, ptr_mach_file->fat_section.fat_header.nfat_arch, NX_LittleEndian); return MOA_SUCCESS; }
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; }
NXStream *NXGetStreamOnSection(const char *fileName, const char *segmentName, const char *sectionName) { int fd; struct stat info; NXStream *s = NULL; struct fat_header *fh; struct mach_header *mh; const struct section *sect; vm_offset_t mh_page, sect_page; unsigned long archOffset; unsigned int cnt = HOST_BASIC_INFO_COUNT; struct host_basic_info hbi; if (host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)(&hbi), &cnt) != KERN_SUCCESS) return NULL; fd = open(fileName, O_RDONLY, 0444); if (fd < 0 || fstat(fd, &info) < 0) return NULL; if (((info.st_mode & S_IFMT) != S_IFREG) || (info.st_size < sizeof(*fh))) { close(fd); return NULL; } if (map_fd(fd, 0, (vm_offset_t *)&fh, TRUE, (vm_size_t)info.st_size) != KERN_SUCCESS) { close(fd); return NULL; } #ifdef __BIG_ENDIAN__ if (fh->magic == FAT_MAGIC) { #endif __BIG_ENDIAN__ #ifdef __LITTLE_ENDIAN__ if (fh->magic == NXSwapLong(FAT_MAGIC)) { #endif __LITTLE_ENDIAN__ int i; struct fat_arch *fa = (struct fat_arch*)(fh + 1); #ifdef __LITTLE_ENDIAN__ enum NXByteOrder host_byte_sex = NXHostByteOrder(); swap_fat_header(fh, host_byte_sex); #endif __LITTLE_ENDIAN__ if ((fh->nfat_arch <= 0) || (info.st_size < sizeof(*fh)+sizeof(*fa)*fh->nfat_arch)) { vm_deallocate(mach_task_self(), (vm_offset_t)fh, info.st_size); close(fd); return NULL; } #ifdef __LITTLE_ENDIAN__ swap_fat_arch(fa, fh->nfat_arch, host_byte_sex); #endif __LITTLE_ENDIAN__ for (i = 0; i < fh->nfat_arch; i++, fa++) { if (fa->cputype == hbi.cpu_type) { //**** ** check for best cpu_subtype here ** (fa->cpusubtype == hbi.cpu_subtype) break; // for now, accept all subtypes } } if (i >= fh->nfat_arch) { vm_deallocate(mach_task_self(), (vm_offset_t)fh, info.st_size); close(fd); return NULL; } archOffset = fa->offset; mh = (struct mach_header*)((char*)fh + archOffset); } else { archOffset = 0L; mh = (struct mach_header*)fh; } if ((info.st_size < archOffset + sizeof(*mh)) || (mh->magic != MH_MAGIC) || (mh->cputype != hbi.cpu_type) || (info.st_size < archOffset + sizeof(*mh) + mh->sizeofcmds) || !check_wellformed_header(mh, info.st_size - archOffset, NO)) { // bug#21223 vm_deallocate(mach_task_self(), (vm_offset_t)fh, info.st_size); close(fd); return NULL; } /* * Get the section data. */ sect = getsectbynamefromheader(mh, segmentName, sectionName); if (sect == NULL || sect->size == 0 || (info.st_size < archOffset + sect->offset + sect->size)) { vm_deallocate(mach_task_self(), (vm_offset_t)fh, info.st_size); close(fd); return NULL; } /* * Create the stream. */ s = NXOpenMemory((char *)mh + sect->offset, sect->size, NX_READONLY); s->flags &= ~NX_USER_OWNS_BUF; /* * Through away the parts of the file not needed. Assert that all * pages that the file lives on are used only by the file. */ sect_page = round_page((vm_offset_t)mh + sect->offset + sect->size); mh_page = round_page((vm_offset_t)fh + info.st_size); if (mh_page - sect_page) vm_deallocate(mach_task_self(), sect_page, mh_page - sect_page); mh_page = trunc_page((vm_offset_t)fh); sect_page = trunc_page((vm_offset_t)mh + sect->offset); if (sect_page - mh_page) vm_deallocate(mach_task_self(), mh_page, sect_page - mh_page); if (close(fd) < 0) { NXCloseMemory(s, NX_FREEBUFFER); s = NULL; } return s; } NXStream *NXGetStreamOnSectionForBestArchitecture( const char *fileName, const char *segmentName, const char *sectionName) { int fd; struct stat info; NXStream *s = NULL; struct fat_header *fh; struct mach_header *mh; const struct section *sect; vm_offset_t mh_page, sect_page; unsigned long archOffset; unsigned int cnt = HOST_BASIC_INFO_COUNT; struct host_basic_info hbi; int fSwap = NO; if (host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)(&hbi), &cnt) != KERN_SUCCESS) return NULL; fd = open(fileName, O_RDONLY, 0444); if (fd < 0 || fstat(fd, &info) < 0) return NULL; if (((info.st_mode & S_IFMT) != S_IFREG) || (info.st_size < sizeof(*fh))) { close(fd); return NULL; } if (map_fd(fd, 0, (vm_offset_t *)&fh, TRUE, (vm_size_t)info.st_size) != KERN_SUCCESS) { close(fd); return NULL; } #ifdef __BIG_ENDIAN__ if (fh->magic == FAT_MAGIC) { #endif __BIG_ENDIAN__ #ifdef __LITTLE_ENDIAN__ if (fh->magic == NXSwapLong(FAT_MAGIC)) { #endif __LITTLE_ENDIAN__ int i; struct fat_arch *fa = (struct fat_arch*)(fh + 1); #ifdef __LITTLE_ENDIAN__ enum NXByteOrder host_byte_sex = NXHostByteOrder(); swap_fat_header(fh, host_byte_sex); #endif __LITTLE_ENDIAN__ if ((fh->nfat_arch <= 0) || (info.st_size < sizeof(*fh)+sizeof(*fa)*fh->nfat_arch)) { vm_deallocate(mach_task_self(), (vm_offset_t)fh, info.st_size); close(fd); return NULL; } #ifdef __LITTLE_ENDIAN__ swap_fat_arch(fa, fh->nfat_arch, host_byte_sex); #endif __LITTLE_ENDIAN__ for (i = 0; i < fh->nfat_arch; i++, fa++) { if (fa->cputype == hbi.cpu_type) { //**** ** check for best cpu_subtype here ** (fa->cpusubtype == hbi.cpu_subtype) break; // for now, accept all subtypes } } if (i >= fh->nfat_arch) { /* * If do not have the correct cpu_type, just use the last type * in file. * NOTE: we could have a list passed in, and choose the best * based upon that list. */ fa--; } archOffset = fa->offset; mh = (struct mach_header*)((char*)fh + archOffset); } else { archOffset = 0L; mh = (struct mach_header*)fh; } if (info.st_size < archOffset + sizeof(*mh)) { vm_deallocate(mach_task_self(), (vm_offset_t)fh, info.st_size); close(fd); return NULL; } /* * Do we need to swap the header? Header is always in byte-order of machine it * was compiled for. */ if (mh->magic == NXSwapLong(MH_MAGIC)) { fSwap = YES; #ifdef __LITTLE_ENDIAN__ swap_mach_header(mh, NX_LittleEndian); #else swap_mach_header(mh, NX_BigEndian); #endif __LITTLE_ENDIAN__ } if ((mh->magic != MH_MAGIC) || (info.st_size < archOffset + sizeof(*mh) + mh->sizeofcmds) || !check_wellformed_header(mh, info.st_size - archOffset, fSwap)) { // bug#21223 vm_deallocate(mach_task_self(), (vm_offset_t)fh, info.st_size); close(fd); return NULL; } /* * Get the section data. */ sect = getsectbynamefromheaderwithswap(mh, segmentName, sectionName, fSwap); if (sect == NULL || sect->size == 0 || (info.st_size < archOffset + sect->offset + sect->size)) { vm_deallocate(mach_task_self(), (vm_offset_t)fh, info.st_size); close(fd); return NULL; } /* * Create the stream. */ s = NXOpenMemory((char *)mh + sect->offset, sect->size, NX_READONLY); s->flags &= ~NX_USER_OWNS_BUF; /* * Through away the parts of the file not needed. Assert that all * pages that the file lives on are used only by the file. */ sect_page = round_page((vm_offset_t)mh + sect->offset + sect->size); mh_page = round_page((vm_offset_t)fh + info.st_size); if (mh_page - sect_page) vm_deallocate(mach_task_self(), sect_page, mh_page - sect_page); mh_page = trunc_page((vm_offset_t)fh); sect_page = trunc_page((vm_offset_t)mh + sect->offset); if (sect_page - mh_page) vm_deallocate(mach_task_self(), mh_page, sect_page - mh_page); if (close(fd) < 0) { NXCloseMemory(s, NX_FREEBUFFER); s = NULL; } return s; }