1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
3 * Copyright (c) 2006-2011 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
25 #ifndef __MACHO_LAYOUT__
26 #define __MACHO_LAYOUT__
28 #include <sys/types.h>
30 #include <sys/errno.h>
32 #include <mach/mach.h>
39 #include <mach-o/loader.h>
40 #include <mach-o/fat.h>
45 #include <unordered_map>
47 #include "MachOFileAbstraction.hpp"
48 #include "Architectures.hpp"
51 void throwf(const char* format, ...) __attribute__((format(printf, 1, 2)));
53 __attribute__((noreturn))
54 void throwf(const char* format, ...)
58 va_start(list, format);
59 vasprintf(&p, format, list);
67 class MachOLayoutAbstraction
73 Segment(uint64_t addr, uint64_t vmsize, uint64_t offset, uint64_t file_size, uint64_t sectionsSize,
74 uint64_t sectionsAlignment, uint64_t align,
75 uint32_t prot, uint32_t sectionCount, const char* segName) : fOrigAddress(addr), fOrigSize(vmsize),
76 fOrigFileOffset(offset), fOrigFileSize(file_size), fOrigPermissions(prot),
77 fSize(vmsize), fFileOffset(offset), fFileSize(file_size), fAlignment(align),
78 fPermissions(prot), fSectionCount(sectionCount), fSectionsSize(sectionsSize),
79 fSectionsAlignment(sectionsAlignment), fNewAddress(0), fMappedAddress(NULL) {
80 strlcpy(fOrigName, segName, 16);
83 uint64_t address() const { return fOrigAddress; }
84 uint64_t size() const { return fSize; }
85 uint64_t fileOffset() const { return fFileOffset; }
86 uint64_t fileSize() const { return fFileSize; }
87 uint32_t permissions() const { return fPermissions; }
88 bool readable() const { return fPermissions & VM_PROT_READ; }
89 bool writable() const { return fPermissions & VM_PROT_WRITE; }
90 bool executable() const { return fPermissions & VM_PROT_EXECUTE; }
91 uint64_t alignment() const { return fAlignment; }
92 const char* name() const { return fOrigName; }
93 uint64_t newAddress() const { return fNewAddress; }
94 uint32_t sectionCount() const{ return fSectionCount; }
95 uint64_t sectionsSize() const{ return fSectionsSize; }
96 uint64_t sectionsAlignment() const { return fSectionsAlignment; }
97 void* mappedAddress() const { return fMappedAddress; }
98 void setNewAddress(uint64_t addr) { fNewAddress = addr; }
99 void setMappedAddress(void* addr) { fMappedAddress = addr; }
100 void setSize(uint64_t new_size) { fSize = new_size; }
101 void setFileOffset(uint64_t new_off) { fFileOffset = new_off; }
102 void setFileSize(uint64_t new_size) { fFileSize = new_size; }
103 void setWritable(bool w) { if (w) fPermissions |= VM_PROT_WRITE; else fPermissions &= ~VM_PROT_WRITE; }
104 void setSectionsAlignment(uint64_t v){ fSectionsAlignment = v; }
105 void reset() { fSize=fOrigSize; fFileOffset=fOrigFileOffset; fFileSize=fOrigFileSize; fPermissions=fOrigPermissions; }
107 uint64_t fOrigAddress;
109 uint64_t fOrigFileOffset;
110 uint64_t fOrigFileSize;
111 uint32_t fOrigPermissions;
114 uint64_t fFileOffset;
117 uint32_t fPermissions;
118 uint32_t fSectionCount;
119 uint64_t fSectionsSize;
120 uint64_t fSectionsAlignment;
121 uint64_t fNewAddress;
122 void* fMappedAddress;
128 uint32_t currentVersion;
129 uint32_t compatibilityVersion;
134 virtual ArchPair getArchPair() const = 0;
135 virtual const char* getFilePath() const = 0;
136 virtual uint64_t getOffsetInUniversalFile() const = 0;
137 virtual uint32_t getFileType() const = 0;
138 virtual uint32_t getFlags() const = 0;
139 virtual Library getID() const = 0;
140 virtual bool isDylib() const = 0;
141 virtual bool isSplitSeg() const = 0;
142 virtual bool hasSplitSegInfo() const = 0;
143 virtual bool hasSplitSegInfoV2() const = 0;
144 virtual int notTrusted() const = 0;
145 virtual bool inSharableLocation() const = 0;
146 virtual bool hasDynamicLookupLinkage() const = 0;
147 virtual bool hasMainExecutableLookupLinkage() const = 0;
148 virtual bool isTwoLevelNamespace() const = 0;
149 virtual bool hasDyldInfo() const = 0;
150 virtual bool hasMultipleReadWriteSegments() const = 0;
151 virtual uint32_t getNameFileOffset() const = 0;
152 virtual time_t getLastModTime() const = 0;
153 virtual ino_t getInode() const = 0;
154 virtual std::vector<Segment>& getSegments() = 0;
155 virtual const std::vector<Segment>& getSegments() const = 0;
156 virtual const Segment* getSegment(const char* name) const = 0;
157 virtual const std::vector<Library>& getLibraries() const = 0;
158 virtual uint64_t getBaseAddress() const = 0;
159 virtual uint64_t getVMSize() const = 0;
160 virtual uint64_t getBaseExecutableAddress() const = 0;
161 virtual uint64_t getBaseWritableAddress() const = 0;
162 virtual uint64_t getBaseReadOnlyAddress() const = 0;
163 virtual uint64_t getExecutableVMSize() const = 0;
164 virtual uint64_t getWritableVMSize() const = 0;
165 virtual uint64_t getReadOnlyVMSize() const = 0;
166 // need getDyldInfoExports because export info uses ULEB encoding and size could grow
167 virtual const uint8_t* getDyldInfoExports() const = 0;
168 virtual void setDyldInfoExports(const uint8_t* newExports) const = 0;
169 virtual void uuid(uuid_t u) const = 0;
175 template <typename A>
176 class MachOLayout : public MachOLayoutAbstraction
179 MachOLayout(const void* machHeader, uint64_t offset, const char* path,
180 ino_t inode, time_t modTime, uid_t uid);
181 virtual ~MachOLayout() {}
183 virtual ArchPair getArchPair() const { return fArchPair; }
184 virtual const char* getFilePath() const { return fPath; }
185 virtual uint64_t getOffsetInUniversalFile() const { return fOffset; }
186 virtual uint32_t getFileType() const { return fFileType; }
187 virtual uint32_t getFlags() const { return fFlags; }
188 virtual Library getID() const { return fDylibID; }
189 virtual bool isDylib() const { return fIsDylib; }
190 virtual bool isSplitSeg() const;
191 virtual bool hasSplitSegInfo() const { return fSplitSegInfo != NULL; }
192 virtual bool hasSplitSegInfoV2() const{ return fHasSplitSegInfoV2; }
193 virtual int notTrusted() const { return fRootlessErrno; }
194 virtual bool inSharableLocation() const { return fShareableLocation; }
195 virtual bool hasDynamicLookupLinkage() const { return fDynamicLookupLinkage; }
196 virtual bool hasMainExecutableLookupLinkage() const { return fMainExecutableLookupLinkage; }
197 virtual bool isTwoLevelNamespace() const { return (fFlags & MH_TWOLEVEL); }
198 virtual bool hasDyldInfo() const { return fHasDyldInfo; }
199 virtual bool hasMultipleReadWriteSegments() const { return fHasTooManyWritableSegments; }
200 virtual uint32_t getNameFileOffset() const{ return fNameFileOffset; }
201 virtual time_t getLastModTime() const { return fMTime; }
202 virtual ino_t getInode() const { return fInode; }
203 virtual std::vector<Segment>& getSegments() { return fSegments; }
204 virtual const std::vector<Segment>& getSegments() const { return fSegments; }
205 virtual const Segment* getSegment(const char* name) const;
206 virtual const std::vector<Library>& getLibraries() const { return fLibraries; }
207 virtual uint64_t getBaseAddress() const { return fLowSegment->address(); }
208 virtual uint64_t getVMSize() const { return fVMSize; }
209 virtual uint64_t getBaseExecutableAddress() const { return fLowExecutableSegment->address(); }
210 virtual uint64_t getBaseWritableAddress() const { return fLowWritableSegment->address(); }
211 virtual uint64_t getBaseReadOnlyAddress() const { return fLowReadOnlySegment->address(); }
212 virtual uint64_t getExecutableVMSize() const { return fVMExecutableSize; }
213 virtual uint64_t getWritableVMSize() const { return fVMWritablSize; }
214 virtual uint64_t getReadOnlyVMSize() const { return fVMReadOnlySize; }
215 virtual const uint8_t* getDyldInfoExports() const { return fDyldInfoExports; }
216 virtual void setDyldInfoExports(const uint8_t* newExports) const { fDyldInfoExports = newExports; }
217 virtual void uuid(uuid_t u) const { memcpy(u, fUUID, 16); }
220 typedef typename A::P P;
221 typedef typename A::P::E E;
222 typedef typename A::P::uint_t pint_t;
224 uint64_t segmentSize(const macho_segment_command<typename A::P>* segCmd) const;
225 uint64_t segmentFileSize(const macho_segment_command<typename A::P>* segCmd) const;
226 uint64_t segmentAlignment(const macho_segment_command<typename A::P>* segCmd) const;
227 uint64_t sectionsSize(const macho_segment_command<typename A::P>* segCmd) const;
228 uint64_t sectionsAlignment(const macho_segment_command<typename A::P>* segCmd) const;
230 bool validReadWriteSeg(const Segment& seg) const;
232 static cpu_type_t arch();
239 std::vector<Segment> fSegments;
240 std::vector<Library> fLibraries;
241 const Segment* fLowSegment;
242 const Segment* fLowExecutableSegment;
243 const Segment* fLowWritableSegment;
244 const Segment* fLowReadOnlySegment;
246 uint32_t fNameFileOffset;
250 uint64_t fVMExecutableSize;
251 uint64_t fVMWritablSize;
252 uint64_t fVMReadOnlySize;
253 const macho_linkedit_data_command<P>* fSplitSegInfo;
254 bool fHasSplitSegInfoV2;
256 bool fShareableLocation;
257 bool fDynamicLookupLinkage;
258 bool fMainExecutableLookupLinkage;
261 bool fHasTooManyWritableSegments;
262 mutable const uint8_t* fDyldInfoExports;
268 class UniversalMachOLayout
271 UniversalMachOLayout(const char* path, const std::set<ArchPair>* onlyArchs=NULL);
272 ~UniversalMachOLayout() {}
274 static const UniversalMachOLayout& find(const char* path, const std::set<ArchPair>* onlyArchs=NULL);
275 const MachOLayoutAbstraction* getSlice(ArchPair ap) const;
276 const std::vector<MachOLayoutAbstraction*>& allLayouts() const { return fLayouts; }
281 size_t operator()(const char* __s) const {
284 __h = 5 * __h + *__s;
288 struct CStringEquals {
289 bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
291 typedef std::unordered_map<const char*, const UniversalMachOLayout*, CStringHash, CStringEquals> PathToNode;
293 static bool requestedSlice(const std::set<ArchPair>* onlyArchs, cpu_type_t cpuType, cpu_subtype_t cpuSubType);
295 static PathToNode fgLayoutCache;
297 std::vector<MachOLayoutAbstraction*> fLayouts;
300 UniversalMachOLayout::PathToNode UniversalMachOLayout::fgLayoutCache;
305 const MachOLayoutAbstraction* UniversalMachOLayout::getSlice(ArchPair ap) const
307 // use matching cputype and cpusubtype
308 for(std::vector<MachOLayoutAbstraction*>::const_iterator it=fLayouts.begin(); it != fLayouts.end(); ++it) {
309 const MachOLayoutAbstraction* layout = *it;
310 if ( layout->getArchPair().arch == ap.arch ) {
313 case CPU_TYPE_X86_64:
314 if ( (layout->getArchPair().subtype & ~CPU_SUBTYPE_MASK) == (ap.subtype & ~CPU_SUBTYPE_MASK) )
322 // if requesting x86_64h and it did not exist, try x86_64 as a fallback
323 if ((ap.arch == CPU_TYPE_X86_64) && (ap.subtype == CPU_SUBTYPE_X86_64_H)) {
324 ap.subtype = CPU_SUBTYPE_X86_64_ALL;
325 return this->getSlice(ap);
331 const UniversalMachOLayout& UniversalMachOLayout::find(const char* path, const std::set<ArchPair>* onlyArchs)
334 PathToNode::iterator pos = fgLayoutCache.find(path);
335 if ( pos != fgLayoutCache.end() )
338 // create UniversalMachOLayout
339 const UniversalMachOLayout* result = new UniversalMachOLayout(path, onlyArchs);
342 fgLayoutCache[result->fPath] = result;
348 bool UniversalMachOLayout::requestedSlice(const std::set<ArchPair>* onlyArchs, cpu_type_t cpuType, cpu_subtype_t cpuSubType)
350 if ( onlyArchs == NULL )
352 // must match cputype and cpusubtype
353 for (std::set<ArchPair>::const_iterator it = onlyArchs->begin(); it != onlyArchs->end(); ++it) {
354 ArchPair anArch = *it;
355 if ( cpuType == anArch.arch ) {
358 if ( cpuSubType == anArch.subtype )
370 UniversalMachOLayout::UniversalMachOLayout(const char* path, const std::set<ArchPair>* onlyArchs)
371 : fPath(strdup(path))
374 int fd = ::open(path, O_RDONLY, 0);
378 throwf("file not found");
380 throwf("can't open file, errno=%d", err);
382 struct stat stat_buf;
383 if ( fstat(fd, &stat_buf) == -1)
384 throwf("can't stat open file %s, errno=%d", path, errno);
385 if ( stat_buf.st_size < 20 )
386 throwf("file too small %s", path);
387 uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
388 if ( p == (uint8_t*)(-1) )
389 throwf("can't map file %s, errno=%d", path, errno);
393 // if fat file, process each architecture
394 const fat_header* fh = (fat_header*)p;
395 const mach_header* mh = (mach_header*)p;
396 if ( fh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
397 // Fat header is always big-endian
398 const struct fat_arch* slices = (struct fat_arch*)(p + sizeof(struct fat_header));
399 const uint32_t sliceCount = OSSwapBigToHostInt32(fh->nfat_arch);
400 for (uint32_t i=0; i < sliceCount; ++i) {
401 if ( requestedSlice(onlyArchs, OSSwapBigToHostInt32(slices[i].cputype), OSSwapBigToHostInt32(slices[i].cpusubtype)) ) {
402 uint32_t fileOffset = OSSwapBigToHostInt32(slices[i].offset);
403 if ( fileOffset > stat_buf.st_size ) {
404 throwf("malformed universal file, slice %u for architecture 0x%08X is beyond end of file: %s",
405 i, OSSwapBigToHostInt32(slices[i].cputype), path);
407 if ( (fileOffset+OSSwapBigToHostInt32(slices[i].size)) > stat_buf.st_size ) {
408 throwf("malformed universal file, slice %u for architecture 0x%08X is beyond end of file: %s",
409 i, OSSwapBigToHostInt32(slices[i].cputype), path);
412 switch ( OSSwapBigToHostInt32(slices[i].cputype) ) {
414 fLayouts.push_back(new MachOLayout<x86>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
416 case CPU_TYPE_X86_64:
417 fLayouts.push_back(new MachOLayout<x86_64>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
420 fLayouts.push_back(new MachOLayout<arm>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
423 fLayouts.push_back(new MachOLayout<arm64>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
426 throw "unknown slice in fat file";
429 catch (const char* msg) {
430 fprintf(stderr, "warning: %s for %s\n", msg, path);
437 if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_I386)) {
438 if ( requestedSlice(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) )
439 fLayouts.push_back(new MachOLayout<x86>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
441 else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC_64) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_X86_64)) {
442 if ( requestedSlice(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) )
443 fLayouts.push_back(new MachOLayout<x86_64>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
445 else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_ARM)) {
446 if ( requestedSlice(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) )
447 fLayouts.push_back(new MachOLayout<arm>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
449 else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC_64) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_ARM64)) {
450 if ( requestedSlice(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) )
451 fLayouts.push_back(new MachOLayout<arm64>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
454 throw "unknown file format";
457 catch (const char* msg) {
458 fprintf(stderr, "warning: %s for %s\n", msg, path);
463 ::munmap(p, stat_buf.st_size);
469 template <typename A>
470 uint64_t MachOLayout<A>::segmentSize(const macho_segment_command<typename A::P>* segCmd) const
472 // <rdar://problem/13089366> segments may have 16KB alignment padding at end, if so we can remove that in cache
473 if ( segCmd->nsects() > 0 ) {
474 const macho_section<P>* const sectionsStart = (macho_section<P>*)((uint8_t*)segCmd + sizeof(macho_segment_command<P>));
475 const macho_section<P>* const lastSection = §ionsStart[segCmd->nsects()-1];
476 uint64_t endSectAddr = lastSection->addr() + lastSection->size();
477 uint64_t endSectAddrPage = (endSectAddr + 4095) & (-4096);
478 if ( endSectAddrPage < (segCmd->vmaddr() + segCmd->vmsize()) ) {
479 uint64_t size = endSectAddrPage - segCmd->vmaddr();
480 //if ( size != segCmd->vmsize() )
481 // fprintf(stderr, "trim %s size=0x%08llX instead of 0x%08llX for %s\n",
482 // segCmd->segname(), size, segCmd->vmsize(), getFilePath());
486 return segCmd->vmsize();
489 template <typename A>
490 uint64_t MachOLayout<A>::segmentAlignment(const macho_segment_command<typename A::P>* segCmd) const
493 if ( segCmd->nsects() > 0 ) {
494 const macho_section<P>* const sectionsStart = (macho_section<P>*)((uint8_t*)segCmd + sizeof(macho_segment_command<P>));
495 const macho_section<P>* const sectionsEnd = §ionsStart[segCmd->nsects()-1];
496 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
497 if ( sect->align() > p2align )
498 p2align = sect->align();
501 return (1 << p2align);
504 template <typename A>
505 uint64_t MachOLayout<A>::segmentFileSize(const macho_segment_command<typename A::P>* segCmd) const
507 // <rdar://problem/13089366> segments may have 16KB alignment padding at end, if so we can remove that in cache
508 if ( segCmd->nsects() > 0 ) {
509 uint64_t endOffset = segCmd->fileoff();
510 const macho_section<P>* const sectionsStart = (macho_section<P>*)((uint8_t*)segCmd + sizeof(macho_segment_command<P>));
511 const macho_section<P>* const sectionsEnd = §ionsStart[segCmd->nsects()];
512 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
513 if ( sect->offset() != 0 )
514 endOffset = sect->offset() + sect->size();
516 uint64_t size = (endOffset - segCmd->fileoff() + 4095) & (-4096);
517 //if ( size != segCmd->filesize() )
518 // fprintf(stderr, "trim %s filesize=0x%08llX instead of 0x%08llX for %s\n",
519 // segCmd->segname(), size, segCmd->filesize(), getFilePath());
522 return segCmd->filesize();
525 template <typename A>
526 uint64_t MachOLayout<A>::sectionsSize(const macho_segment_command<typename A::P>* segCmd) const
528 if ( segCmd->nsects() > 0 ) {
529 const macho_section<P>* const sectionsStart = (macho_section<P>*)((uint8_t*)segCmd + sizeof(macho_segment_command<P>));
530 const macho_section<P>* const lastSection = §ionsStart[segCmd->nsects()-1];
531 uint64_t endSectAddr = lastSection->addr() + lastSection->size();
532 if ( endSectAddr < (segCmd->vmaddr() + segCmd->vmsize()) ) {
533 uint64_t size = endSectAddr - segCmd->vmaddr();
537 return segCmd->vmsize();
540 template <typename A>
541 uint64_t MachOLayout<A>::sectionsAlignment(const macho_segment_command<typename A::P>* segCmd) const
544 if ( hasSplitSegInfoV2() && (segCmd->nsects() > 0) ) {
545 const macho_section<P>* const sectionsStart = (macho_section<P>*)((uint8_t*)segCmd + sizeof(macho_segment_command<P>));
546 const macho_section<P>* const sectionsEnd = §ionsStart[segCmd->nsects()-1];
547 for (const macho_section<P>* sect=sectionsStart; sect < sectionsEnd; ++sect) {
548 if ( sect->align() > p2align )
549 p2align = sect->align();
552 return (1 << p2align);
557 template <typename A>
558 MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char* path, ino_t inode, time_t modTime, uid_t uid)
559 : fPath(path), fOffset(offset), fArchPair(0,0), fMTime(modTime), fInode(inode), fSplitSegInfo(NULL), fHasSplitSegInfoV2(false), fRootlessErrno(0),
560 fShareableLocation(false), fDynamicLookupLinkage(false), fMainExecutableLookupLinkage(false), fIsDylib(false),
561 fHasDyldInfo(false), fHasTooManyWritableSegments(false), fDyldInfoExports(NULL)
563 fDylibID.name = NULL;
564 fDylibID.currentVersion = 0;
565 fDylibID.compatibilityVersion = 0;
566 bzero(fUUID, sizeof(fUUID));
568 const macho_header<P>* mh = (const macho_header<P>*)machHeader;
569 if ( mh->cputype() != arch() )
570 throw "Layout object is wrong architecture";
571 switch ( mh->filetype() ) {
581 throw "file is not a mach-o final linked image";
583 fFlags = mh->flags();
584 fFileType = mh->filetype();
585 fArchPair.arch = mh->cputype();
586 fArchPair.subtype = mh->cpusubtype();
587 if ( rootless_check_trusted(path) != 0 && rootless_protected_volume(path) == 1)
588 fRootlessErrno = errno;
590 const macho_dyld_info_command<P>* dyldInfo = NULL;
591 const macho_symtab_command<P>* symbolTableCmd = NULL;
592 const macho_dysymtab_command<P>* dynamicSymbolTableCmd = NULL;
593 const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)mh + sizeof(macho_header<P>));
594 const uint32_t cmd_count = mh->ncmds();
595 const macho_load_command<P>* cmd = cmds;
596 for (uint32_t i = 0; i < cmd_count; ++i) {
597 switch ( cmd->cmd() ) {
600 macho_dylib_command<P>* dylib = (macho_dylib_command<P>*)cmd;
601 fDylibID.name = strdup(dylib->name());
602 fDylibID.currentVersion = dylib->current_version();
603 fDylibID.compatibilityVersion = dylib->compatibility_version();
604 fNameFileOffset = dylib->name() - (char*)machHeader;
605 fShareableLocation = ( (strncmp(fDylibID.name, "/usr/lib/", 9) == 0) || (strncmp(fDylibID.name, "/System/Library/", 16) == 0) );
609 case LC_LOAD_WEAK_DYLIB:
610 case LC_REEXPORT_DYLIB:
611 case LC_LOAD_UPWARD_DYLIB:
613 macho_dylib_command<P>* dylib = (macho_dylib_command<P>*)cmd;
615 lib.name = strdup(dylib->name());
616 lib.currentVersion = dylib->current_version();
617 lib.compatibilityVersion = dylib->compatibility_version();
618 lib.weakImport = ( cmd->cmd() == LC_LOAD_WEAK_DYLIB );
619 fLibraries.push_back(lib);
622 case LC_SEGMENT_SPLIT_INFO:
623 fSplitSegInfo = (macho_linkedit_data_command<P>*)cmd;
625 case macho_segment_command<P>::CMD:
627 const macho_segment_command<P>* segCmd = (macho_segment_command<P>*)cmd;
628 fSegments.push_back(Segment(segCmd->vmaddr(), segmentSize(segCmd), segCmd->fileoff(),
629 segmentFileSize(segCmd), sectionsSize(segCmd), sectionsAlignment(segCmd),
630 segmentAlignment(segCmd), segCmd->initprot(),
631 segCmd->nsects(), segCmd->segname()));
635 symbolTableCmd = (macho_symtab_command<P>*)cmd;
638 dynamicSymbolTableCmd = (macho_dysymtab_command<P>*)cmd;
641 case LC_DYLD_INFO_ONLY:
643 dyldInfo = (struct macho_dyld_info_command<P>*)cmd;
647 const macho_uuid_command<P>* uc = (macho_uuid_command<P>*)cmd;
648 memcpy(&fUUID, uc->uuid(), 16);
652 cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
656 fLowExecutableSegment = NULL;
657 fLowWritableSegment = NULL;
658 fLowReadOnlySegment = NULL;
659 fVMExecutableSize = 0;
663 const Segment* highSegment = NULL;
664 for(std::vector<Segment>::const_iterator it = fSegments.begin(); it != fSegments.end(); ++it) {
665 const Segment& seg = *it;
666 if ( (fLowSegment == NULL) || (seg.address() < fLowSegment->address()) )
668 if ( (highSegment == NULL) || (seg.address() > highSegment->address()) )
670 if ( seg.executable() ) {
671 if ( (fLowExecutableSegment == NULL) || (seg.address() < fLowExecutableSegment->address()) )
672 fLowExecutableSegment = &seg;
673 fVMExecutableSize += seg.size();
675 else if ( seg.writable()) {
676 if ( (fLowWritableSegment == NULL) || (seg.address() < fLowWritableSegment->address()) )
677 fLowWritableSegment = &seg;
678 fVMWritablSize += seg.size();
679 if ( !validReadWriteSeg(seg) ) {
680 fHasTooManyWritableSegments = true;
684 if ( (fLowReadOnlySegment == NULL) || (seg.address() < fLowReadOnlySegment->address()) )
685 fLowReadOnlySegment = &seg;
686 fVMReadOnlySize += seg.size();
689 if ( (highSegment != NULL) && (fLowSegment != NULL) )
690 fVMSize = (highSegment->address() + highSegment->size() - fLowSegment->address() + 4095) & (-4096);
692 // scan undefines looking, for magic ordinals
693 if ( (symbolTableCmd != NULL) && (dynamicSymbolTableCmd != NULL) ) {
694 const macho_nlist<P>* symbolTable = (macho_nlist<P>*)((uint8_t*)machHeader + symbolTableCmd->symoff());
695 const uint32_t startUndefs = dynamicSymbolTableCmd->iundefsym();
696 const uint32_t endUndefs = startUndefs + dynamicSymbolTableCmd->nundefsym();
697 for (uint32_t i=startUndefs; i < endUndefs; ++i) {
698 uint8_t ordinal = GET_LIBRARY_ORDINAL(symbolTable[i].n_desc());
699 if ( ordinal == DYNAMIC_LOOKUP_ORDINAL )
700 fDynamicLookupLinkage = true;
701 else if ( ordinal == EXECUTABLE_ORDINAL )
702 fMainExecutableLookupLinkage = true;
706 if ( dyldInfo != NULL ) {
707 if ( dyldInfo->export_off() != 0 ) {
708 fDyldInfoExports = (uint8_t*)machHeader + dyldInfo->export_off();
712 if ( fSplitSegInfo != NULL ) {
713 const uint8_t* infoStart = (uint8_t*)machHeader + fSplitSegInfo->dataoff();
714 fHasSplitSegInfoV2 = ( *infoStart == DYLD_CACHE_ADJ_V2_FORMAT );
715 if ( !fHasSplitSegInfoV2 ) {
716 // split seg version not known when segments created
717 // v1 does not support packing, so simulate that by forcing alignment
718 for (Segment& seg : fSegments) {
719 seg.setSectionsAlignment(4096);
726 template <> cpu_type_t MachOLayout<x86>::arch() { return CPU_TYPE_I386; }
727 template <> cpu_type_t MachOLayout<x86_64>::arch() { return CPU_TYPE_X86_64; }
728 template <> cpu_type_t MachOLayout<arm>::arch() { return CPU_TYPE_ARM; }
729 template <> cpu_type_t MachOLayout<arm64>::arch() { return CPU_TYPE_ARM64; }
732 bool MachOLayout<x86>::validReadWriteSeg(const Segment& seg) const
734 return (strcmp(seg.name(), "__DATA") == 0) || (strcmp(seg.name(), "__OBJC") == 0);
737 template <typename A>
738 bool MachOLayout<A>::validReadWriteSeg(const Segment& seg) const
740 return (strcmp(seg.name(), "__DATA") == 0);
745 bool MachOLayout<x86>::isSplitSeg() const
747 return ( (this->getFlags() & MH_SPLIT_SEGS) != 0 );
751 bool MachOLayout<arm>::isSplitSeg() const
753 return ( (this->getFlags() & MH_SPLIT_SEGS) != 0 );
756 template <typename A>
757 bool MachOLayout<A>::isSplitSeg() const
762 template <typename A>
763 const MachOLayoutAbstraction::Segment* MachOLayout<A>::getSegment(const char* name) const
765 for(std::vector<Segment>::const_iterator it = fSegments.begin(); it != fSegments.end(); ++it) {
766 const Segment& seg = *it;
767 if ( strcmp(seg.name(), name) == 0 )
775 #endif // __MACHO_LAYOUT__