/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- * * Copyright (c) 2006-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ #ifndef __MACHO_LAYOUT__ #define __MACHO_LAYOUT__ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "MachOFileAbstraction.hpp" #include "Architectures.hpp" void throwf(const char* format, ...) __attribute__((format(printf, 1, 2))); __attribute__((noreturn)) void throwf(const char* format, ...) { va_list list; char* p; va_start(list, format); vasprintf(&p, format, list); va_end(list); const char* t = p; throw t; } class MachOLayoutAbstraction { public: struct Segment { public: Segment(uint64_t addr, uint64_t vmsize, uint64_t offset, uint64_t file_size, uint64_t align, uint32_t prot, const char* segName) : fOrigAddress(addr), fOrigSize(vmsize), fOrigFileOffset(offset), fOrigFileSize(file_size), fOrigPermissions(prot), fSize(vmsize), fFileOffset(offset), fFileSize(file_size), fAlignment(align), fPermissions(prot), fNewAddress(0), fMappedAddress(NULL) { strlcpy(fOrigName, segName, 16); } uint64_t address() const { return fOrigAddress; } uint64_t size() const { return fSize; } uint64_t fileOffset() const { return fFileOffset; } uint64_t fileSize() const { return fFileSize; } uint32_t permissions() const { return fPermissions; } bool readable() const { return fPermissions & VM_PROT_READ; } bool writable() const { return fPermissions & VM_PROT_WRITE; } bool executable() const { return fPermissions & VM_PROT_EXECUTE; } uint64_t alignment() const { return fAlignment; } const char* name() const { return fOrigName; } uint64_t newAddress() const { return fNewAddress; } void* mappedAddress() const { return fMappedAddress; } void setNewAddress(uint64_t addr) { fNewAddress = addr; } void setMappedAddress(void* addr) { fMappedAddress = addr; } void setSize(uint64_t new_size) { fSize = new_size; } void setFileOffset(uint64_t new_off) { fFileOffset = new_off; } void setFileSize(uint64_t new_size) { fFileSize = new_size; } void setWritable(bool w) { if (w) fPermissions |= VM_PROT_WRITE; else fPermissions &= ~VM_PROT_WRITE; } void reset() { fSize=fOrigSize; fFileOffset=fOrigFileOffset; fFileSize=fOrigFileSize; fPermissions=fOrigPermissions; } private: uint64_t fOrigAddress; uint64_t fOrigSize; uint64_t fOrigFileOffset; uint64_t fOrigFileSize; uint32_t fOrigPermissions; char fOrigName[16]; uint64_t fSize; uint64_t fFileOffset; uint64_t fFileSize; uint64_t fAlignment; uint32_t fPermissions; uint64_t fNewAddress; void* fMappedAddress; }; struct Library { const char* name; uint32_t currentVersion; uint32_t compatibilityVersion; bool weakImport; }; virtual ArchPair getArchPair() const = 0; virtual const char* getFilePath() const = 0; virtual uint64_t getOffsetInUniversalFile() const = 0; virtual uint32_t getFileType() const = 0; virtual uint32_t getFlags() const = 0; virtual Library getID() const = 0; virtual bool isDylib() const = 0; virtual bool isSplitSeg() const = 0; virtual bool hasSplitSegInfo() const = 0; virtual bool isRootOwned() const = 0; virtual bool inSharableLocation() const = 0; virtual bool hasDynamicLookupLinkage() const = 0; virtual bool hasMainExecutableLookupLinkage() const = 0; virtual bool isTwoLevelNamespace() const = 0; virtual bool hasDyldInfo() const = 0; virtual bool hasMultipleReadWriteSegments() const = 0; virtual uint32_t getNameFileOffset() const = 0; virtual time_t getLastModTime() const = 0; virtual ino_t getInode() const = 0; virtual std::vector& getSegments() = 0; virtual const std::vector& getSegments() const = 0; virtual const Segment* getSegment(const char* name) const = 0; virtual const std::vector& getLibraries() const = 0; virtual uint64_t getBaseAddress() const = 0; virtual uint64_t getVMSize() const = 0; virtual uint64_t getBaseExecutableAddress() const = 0; virtual uint64_t getBaseWritableAddress() const = 0; virtual uint64_t getBaseReadOnlyAddress() const = 0; virtual uint64_t getExecutableVMSize() const = 0; virtual uint64_t getWritableVMSize() const = 0; virtual uint64_t getReadOnlyVMSize() const = 0; // need getDyldInfoExports because export info uses ULEB encoding and size could grow virtual const uint8_t* getDyldInfoExports() const = 0; virtual void setDyldInfoExports(const uint8_t* newExports) const = 0; virtual void uuid(uuid_t u) const = 0; }; template class MachOLayout : public MachOLayoutAbstraction { public: MachOLayout(const void* machHeader, uint64_t offset, const char* path, ino_t inode, time_t modTime, uid_t uid); virtual ~MachOLayout() {} virtual ArchPair getArchPair() const { return fArchPair; } virtual const char* getFilePath() const { return fPath; } virtual uint64_t getOffsetInUniversalFile() const { return fOffset; } virtual uint32_t getFileType() const { return fFileType; } virtual uint32_t getFlags() const { return fFlags; } virtual Library getID() const { return fDylibID; } virtual bool isDylib() const { return fIsDylib; } virtual bool isSplitSeg() const; virtual bool hasSplitSegInfo() const { return fHasSplitSegInfo; } virtual bool isRootOwned() const { return fRootOwned; } virtual bool inSharableLocation() const { return fShareableLocation; } virtual bool hasDynamicLookupLinkage() const { return fDynamicLookupLinkage; } virtual bool hasMainExecutableLookupLinkage() const { return fMainExecutableLookupLinkage; } virtual bool isTwoLevelNamespace() const { return (fFlags & MH_TWOLEVEL); } virtual bool hasDyldInfo() const { return fHasDyldInfo; } virtual bool hasMultipleReadWriteSegments() const { return fHasTooManyWritableSegments; } virtual uint32_t getNameFileOffset() const{ return fNameFileOffset; } virtual time_t getLastModTime() const { return fMTime; } virtual ino_t getInode() const { return fInode; } virtual std::vector& getSegments() { return fSegments; } virtual const std::vector& getSegments() const { return fSegments; } virtual const Segment* getSegment(const char* name) const; virtual const std::vector& getLibraries() const { return fLibraries; } virtual uint64_t getBaseAddress() const { return fLowSegment->address(); } virtual uint64_t getVMSize() const { return fVMSize; } virtual uint64_t getBaseExecutableAddress() const { return fLowExecutableSegment->address(); } virtual uint64_t getBaseWritableAddress() const { return fLowWritableSegment->address(); } virtual uint64_t getBaseReadOnlyAddress() const { return fLowReadOnlySegment->address(); } virtual uint64_t getExecutableVMSize() const { return fVMExecutableSize; } virtual uint64_t getWritableVMSize() const { return fVMWritablSize; } virtual uint64_t getReadOnlyVMSize() const { return fVMReadOnlySize; } virtual const uint8_t* getDyldInfoExports() const { return fDyldInfoExports; } virtual void setDyldInfoExports(const uint8_t* newExports) const { fDyldInfoExports = newExports; } virtual void uuid(uuid_t u) const { memcpy(u, fUUID, 16); } private: typedef typename A::P P; typedef typename A::P::E E; typedef typename A::P::uint_t pint_t; uint64_t segmentSize(const macho_segment_command* segCmd) const; uint64_t segmentFileSize(const macho_segment_command* segCmd) const; uint64_t segmentAlignment(const macho_segment_command* segCmd) const; bool validReadWriteSeg(const Segment& seg) const; static cpu_type_t arch(); const char* fPath; uint64_t fOffset; uint32_t fFileType; ArchPair fArchPair; uint32_t fFlags; std::vector fSegments; std::vector fLibraries; const Segment* fLowSegment; const Segment* fLowExecutableSegment; const Segment* fLowWritableSegment; const Segment* fLowReadOnlySegment; Library fDylibID; uint32_t fNameFileOffset; time_t fMTime; ino_t fInode; uint64_t fVMSize; uint64_t fVMExecutableSize; uint64_t fVMWritablSize; uint64_t fVMReadOnlySize; bool fHasSplitSegInfo; bool fRootOwned; bool fShareableLocation; bool fDynamicLookupLinkage; bool fMainExecutableLookupLinkage; bool fIsDylib; bool fHasDyldInfo; bool fHasTooManyWritableSegments; mutable const uint8_t* fDyldInfoExports; uuid_t fUUID; }; class UniversalMachOLayout { public: UniversalMachOLayout(const char* path, const std::set* onlyArchs=NULL); ~UniversalMachOLayout() {} static const UniversalMachOLayout& find(const char* path, const std::set* onlyArchs=NULL); const MachOLayoutAbstraction* getSlice(ArchPair ap) const; const std::vector& allLayouts() const { return fLayouts; } private: class CStringHash { public: size_t operator()(const char* __s) const { size_t __h = 0; for ( ; *__s; ++__s) __h = 5 * __h + *__s; return __h; }; }; struct CStringEquals { bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); } }; typedef std::unordered_map PathToNode; static bool requestedSlice(const std::set* onlyArchs, cpu_type_t cpuType, cpu_subtype_t cpuSubType); static PathToNode fgLayoutCache; const char* fPath; std::vector fLayouts; }; UniversalMachOLayout::PathToNode UniversalMachOLayout::fgLayoutCache; const MachOLayoutAbstraction* UniversalMachOLayout::getSlice(ArchPair ap) const { // use matching cputype and cpusubtype for(std::vector::const_iterator it=fLayouts.begin(); it != fLayouts.end(); ++it) { const MachOLayoutAbstraction* layout = *it; if ( layout->getArchPair().arch == ap.arch ) { switch ( ap.arch ) { case CPU_TYPE_ARM: case CPU_TYPE_X86_64: if ( (layout->getArchPair().subtype & ~CPU_SUBTYPE_MASK) == (ap.subtype & ~CPU_SUBTYPE_MASK) ) return layout; break; default: return layout; } } } // if requesting x86_64h and it did not exist, try x86_64 as a fallback if ((ap.arch == CPU_TYPE_X86_64) && (ap.subtype == CPU_SUBTYPE_X86_64_H)) { ap.subtype = CPU_SUBTYPE_X86_64_ALL; return this->getSlice(ap); } return NULL; } const UniversalMachOLayout& UniversalMachOLayout::find(const char* path, const std::set* onlyArchs) { // look in cache PathToNode::iterator pos = fgLayoutCache.find(path); if ( pos != fgLayoutCache.end() ) return *pos->second; // create UniversalMachOLayout const UniversalMachOLayout* result = new UniversalMachOLayout(path, onlyArchs); // add it to cache fgLayoutCache[result->fPath] = result; return *result; } bool UniversalMachOLayout::requestedSlice(const std::set* onlyArchs, cpu_type_t cpuType, cpu_subtype_t cpuSubType) { if ( onlyArchs == NULL ) return true; // must match cputype and cpusubtype for (std::set::const_iterator it = onlyArchs->begin(); it != onlyArchs->end(); ++it) { ArchPair anArch = *it; if ( cpuType == anArch.arch ) { switch ( cpuType ) { case CPU_TYPE_ARM: if ( cpuSubType == anArch.subtype ) return true; break; default: return true; } } } return false; } UniversalMachOLayout::UniversalMachOLayout(const char* path, const std::set* onlyArchs) : fPath(strdup(path)) { // map in whole file int fd = ::open(path, O_RDONLY, 0); if ( fd == -1 ) { int err = errno; if ( err == ENOENT ) throwf("file not found"); else throwf("can't open file, errno=%d", err); } struct stat stat_buf; if ( fstat(fd, &stat_buf) == -1) throwf("can't stat open file %s, errno=%d", path, errno); if ( stat_buf.st_size < 20 ) throwf("file too small %s", path); uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0); if ( p == (uint8_t*)(-1) ) throwf("can't map file %s, errno=%d", path, errno); ::close(fd); try { // if fat file, process each architecture const fat_header* fh = (fat_header*)p; const mach_header* mh = (mach_header*)p; if ( fh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) { // Fat header is always big-endian const struct fat_arch* slices = (struct fat_arch*)(p + sizeof(struct fat_header)); const uint32_t sliceCount = OSSwapBigToHostInt32(fh->nfat_arch); for (uint32_t i=0; i < sliceCount; ++i) { if ( requestedSlice(onlyArchs, OSSwapBigToHostInt32(slices[i].cputype), OSSwapBigToHostInt32(slices[i].cpusubtype)) ) { uint32_t fileOffset = OSSwapBigToHostInt32(slices[i].offset); if ( fileOffset > stat_buf.st_size ) { throwf("malformed universal file, slice %u for architecture 0x%08X is beyond end of file: %s", i, OSSwapBigToHostInt32(slices[i].cputype), path); } if ( (fileOffset+OSSwapBigToHostInt32(slices[i].size)) > stat_buf.st_size ) { throwf("malformed universal file, slice %u for architecture 0x%08X is beyond end of file: %s", i, OSSwapBigToHostInt32(slices[i].cputype), path); } try { switch ( OSSwapBigToHostInt32(slices[i].cputype) ) { case CPU_TYPE_I386: fLayouts.push_back(new MachOLayout(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid)); break; case CPU_TYPE_X86_64: fLayouts.push_back(new MachOLayout(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid)); break; case CPU_TYPE_ARM: fLayouts.push_back(new MachOLayout(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid)); break; case CPU_TYPE_ARM64: fLayouts.push_back(new MachOLayout(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid)); break; default: throw "unknown slice in fat file"; } } catch (const char* msg) { fprintf(stderr, "warning: %s for %s\n", msg, path); } } } } else { try { if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_I386)) { if ( requestedSlice(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) ) fLayouts.push_back(new MachOLayout(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid)); } else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC_64) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_X86_64)) { if ( requestedSlice(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) ) fLayouts.push_back(new MachOLayout(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid)); } else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_ARM)) { if ( requestedSlice(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) ) fLayouts.push_back(new MachOLayout(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid)); } else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC_64) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_ARM64)) { if ( requestedSlice(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) ) fLayouts.push_back(new MachOLayout(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid)); } else { throw "unknown file format"; } } catch (const char* msg) { fprintf(stderr, "warning: %s for %s\n", msg, path); } } } catch (...) { ::munmap(p, stat_buf.st_size); throw; } } template uint64_t MachOLayout::segmentSize(const macho_segment_command* segCmd) const { // segments may have 16KB alignment padding at end, if so we can remove that in cache if ( segCmd->nsects() > 0 ) { const macho_section

* const sectionsStart = (macho_section

*)((uint8_t*)segCmd + sizeof(macho_segment_command

)); const macho_section

* const lastSection = §ionsStart[segCmd->nsects()-1]; uint64_t endSectAddr = lastSection->addr() + lastSection->size(); uint64_t endSectAddrPage = (endSectAddr + 4095) & (-4096); if ( endSectAddrPage < (segCmd->vmaddr() + segCmd->vmsize()) ) { uint64_t size = endSectAddrPage - segCmd->vmaddr(); //if ( size != segCmd->vmsize() ) // fprintf(stderr, "trim %s size=0x%08llX instead of 0x%08llX for %s\n", // segCmd->segname(), size, segCmd->vmsize(), getFilePath()); return size; } } return segCmd->vmsize(); } template uint64_t MachOLayout::segmentAlignment(const macho_segment_command* segCmd) const { int p2align = 12; if ( segCmd->nsects() > 0 ) { const macho_section

* const sectionsStart = (macho_section

*)((uint8_t*)segCmd + sizeof(macho_segment_command

)); const macho_section

* const sectionsEnd = §ionsStart[segCmd->nsects()-1]; for (const macho_section

* sect=sectionsStart; sect < sectionsEnd; ++sect) { if ( sect->align() > p2align ) p2align = sect->align(); } } return (1 << p2align); } template uint64_t MachOLayout::segmentFileSize(const macho_segment_command* segCmd) const { // segments may have 16KB alignment padding at end, if so we can remove that in cache if ( segCmd->nsects() > 0 ) { uint64_t endOffset = segCmd->fileoff(); const macho_section

* const sectionsStart = (macho_section

*)((uint8_t*)segCmd + sizeof(macho_segment_command

)); const macho_section

* const sectionsEnd = §ionsStart[segCmd->nsects()]; for (const macho_section

* sect=sectionsStart; sect < sectionsEnd; ++sect) { if ( sect->offset() != 0 ) endOffset = sect->offset() + sect->size(); } uint64_t size = (endOffset - segCmd->fileoff() + 4095) & (-4096); //if ( size != segCmd->filesize() ) // fprintf(stderr, "trim %s filesize=0x%08llX instead of 0x%08llX for %s\n", // segCmd->segname(), size, segCmd->filesize(), getFilePath()); return size; } return segCmd->filesize(); } template MachOLayout::MachOLayout(const void* machHeader, uint64_t offset, const char* path, ino_t inode, time_t modTime, uid_t uid) : fPath(path), fOffset(offset), fArchPair(0,0), fMTime(modTime), fInode(inode), fHasSplitSegInfo(false), fRootOwned(uid==0), fShareableLocation(false), fDynamicLookupLinkage(false), fMainExecutableLookupLinkage(false), fIsDylib(false), fHasDyldInfo(false), fHasTooManyWritableSegments(false), fDyldInfoExports(NULL) { fDylibID.name = NULL; fDylibID.currentVersion = 0; fDylibID.compatibilityVersion = 0; bzero(fUUID, sizeof(fUUID)); const macho_header

* mh = (const macho_header

*)machHeader; if ( mh->cputype() != arch() ) throw "Layout object is wrong architecture"; switch ( mh->filetype() ) { case MH_DYLIB: fIsDylib = true; break; case MH_BUNDLE: case MH_EXECUTE: case MH_DYLIB_STUB: case MH_DYLINKER: break; default: throw "file is not a mach-o final linked image"; } fFlags = mh->flags(); fFileType = mh->filetype(); fArchPair.arch = mh->cputype(); fArchPair.subtype = mh->cpusubtype(); const macho_dyld_info_command

* dyldInfo = NULL; const macho_symtab_command

* symbolTableCmd = NULL; const macho_dysymtab_command

* dynamicSymbolTableCmd = NULL; const macho_load_command

* const cmds = (macho_load_command

*)((uint8_t*)mh + sizeof(macho_header

)); const uint32_t cmd_count = mh->ncmds(); const macho_load_command

* cmd = cmds; for (uint32_t i = 0; i < cmd_count; ++i) { switch ( cmd->cmd() ) { case LC_ID_DYLIB: { macho_dylib_command

* dylib = (macho_dylib_command

*)cmd; fDylibID.name = strdup(dylib->name()); fDylibID.currentVersion = dylib->current_version(); fDylibID.compatibilityVersion = dylib->compatibility_version(); fNameFileOffset = dylib->name() - (char*)machHeader; fShareableLocation = ( (strncmp(fDylibID.name, "/usr/lib/", 9) == 0) || (strncmp(fDylibID.name, "/System/Library/", 16) == 0) ); } break; case LC_LOAD_DYLIB: case LC_LOAD_WEAK_DYLIB: case LC_REEXPORT_DYLIB: case LC_LOAD_UPWARD_DYLIB: { macho_dylib_command

* dylib = (macho_dylib_command

*)cmd; Library lib; lib.name = strdup(dylib->name()); lib.currentVersion = dylib->current_version(); lib.compatibilityVersion = dylib->compatibility_version(); lib.weakImport = ( cmd->cmd() == LC_LOAD_WEAK_DYLIB ); fLibraries.push_back(lib); } break; case LC_SEGMENT_SPLIT_INFO: fHasSplitSegInfo = true; break; case macho_segment_command

::CMD: { const macho_segment_command

* segCmd = (macho_segment_command

*)cmd; fSegments.push_back(Segment(segCmd->vmaddr(), segmentSize(segCmd), segCmd->fileoff(), segmentFileSize(segCmd), segmentAlignment(segCmd), segCmd->initprot(), segCmd->segname())); } break; case LC_SYMTAB: symbolTableCmd = (macho_symtab_command

*)cmd; break; case LC_DYSYMTAB: dynamicSymbolTableCmd = (macho_dysymtab_command

*)cmd; break; case LC_DYLD_INFO: case LC_DYLD_INFO_ONLY: fHasDyldInfo = true; dyldInfo = (struct macho_dyld_info_command

*)cmd; break; case LC_UUID: { const macho_uuid_command

* uc = (macho_uuid_command

*)cmd; memcpy(&fUUID, uc->uuid(), 16); } break; } cmd = (const macho_load_command

*)(((uint8_t*)cmd)+cmd->cmdsize()); } fLowSegment = NULL; fLowExecutableSegment = NULL; fLowWritableSegment = NULL; fLowReadOnlySegment = NULL; fVMExecutableSize = 0; fVMWritablSize = 0; fVMReadOnlySize = 0; fVMSize = 0; const Segment* highSegment = NULL; for(std::vector::const_iterator it = fSegments.begin(); it != fSegments.end(); ++it) { const Segment& seg = *it; if ( (fLowSegment == NULL) || (seg.address() < fLowSegment->address()) ) fLowSegment = &seg; if ( (highSegment == NULL) || (seg.address() > highSegment->address()) ) highSegment = &seg; if ( seg.executable() ) { if ( (fLowExecutableSegment == NULL) || (seg.address() < fLowExecutableSegment->address()) ) fLowExecutableSegment = &seg; fVMExecutableSize += seg.size(); } else if ( seg.writable()) { if ( (fLowWritableSegment == NULL) || (seg.address() < fLowWritableSegment->address()) ) fLowWritableSegment = &seg; fVMWritablSize += seg.size(); if ( !validReadWriteSeg(seg) ) { fHasTooManyWritableSegments = true; } } else { if ( (fLowReadOnlySegment == NULL) || (seg.address() < fLowReadOnlySegment->address()) ) fLowReadOnlySegment = &seg; fVMReadOnlySize += seg.size(); } } if ( (highSegment != NULL) && (fLowSegment != NULL) ) fVMSize = (highSegment->address() + highSegment->size() - fLowSegment->address() + 4095) & (-4096); // scan undefines looking, for magic ordinals if ( (symbolTableCmd != NULL) && (dynamicSymbolTableCmd != NULL) ) { const macho_nlist

* symbolTable = (macho_nlist

*)((uint8_t*)machHeader + symbolTableCmd->symoff()); const uint32_t startUndefs = dynamicSymbolTableCmd->iundefsym(); const uint32_t endUndefs = startUndefs + dynamicSymbolTableCmd->nundefsym(); for (uint32_t i=startUndefs; i < endUndefs; ++i) { uint8_t ordinal = GET_LIBRARY_ORDINAL(symbolTable[i].n_desc()); if ( ordinal == DYNAMIC_LOOKUP_ORDINAL ) fDynamicLookupLinkage = true; else if ( ordinal == EXECUTABLE_ORDINAL ) fMainExecutableLookupLinkage = true; } } if ( dyldInfo != NULL ) { if ( dyldInfo->export_off() != 0 ) { fDyldInfoExports = (uint8_t*)machHeader + dyldInfo->export_off(); } } } template <> cpu_type_t MachOLayout::arch() { return CPU_TYPE_I386; } template <> cpu_type_t MachOLayout::arch() { return CPU_TYPE_X86_64; } template <> cpu_type_t MachOLayout::arch() { return CPU_TYPE_ARM; } template <> cpu_type_t MachOLayout::arch() { return CPU_TYPE_ARM64; } template <> bool MachOLayout::validReadWriteSeg(const Segment& seg) const { return (strcmp(seg.name(), "__DATA") == 0) || (strcmp(seg.name(), "__OBJC") == 0); } template bool MachOLayout::validReadWriteSeg(const Segment& seg) const { return (strcmp(seg.name(), "__DATA") == 0); } template <> bool MachOLayout::isSplitSeg() const { return ( (this->getFlags() & MH_SPLIT_SEGS) != 0 ); } template <> bool MachOLayout::isSplitSeg() const { return ( (this->getFlags() & MH_SPLIT_SEGS) != 0 ); } template bool MachOLayout::isSplitSeg() const { return false; } template const MachOLayoutAbstraction::Segment* MachOLayout::getSegment(const char* name) const { for(std::vector::const_iterator it = fSegments.begin(); it != fSegments.end(); ++it) { const Segment& seg = *it; if ( strcmp(seg.name(), name) == 0 ) return &seg; } return NULL; } #endif // __MACHO_LAYOUT__