]>
git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_utilities/lib/macho++.cpp
2 * Copyright (c) 2006-2014 Apple Inc. All Rights Reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 // macho++ - Mach-O object file helpers
28 #include <security_utilities/alloc.h>
29 #include <security_utilities/memutils.h>
30 #include <security_utilities/endian.h>
31 #include <mach-o/dyld.h>
38 /* Maximum number of archs a fat binary can have */
39 static const int MAX_ARCH_COUNT
= 100;
40 /* Maximum power of 2 that a mach-o can be aligned by */
41 static const int MAX_ALIGN
= 30;
44 // Architecture values
46 Architecture::Architecture(const fat_arch
&arch
)
47 : pair
<cpu_type_t
, cpu_subtype_t
>(arch
.cputype
, arch
.cpusubtype
)
51 Architecture::Architecture(const char *name
)
53 if (const NXArchInfo
*nxa
= NXGetArchInfoFromName(name
)) {
54 this->first
= nxa
->cputype
;
55 this->second
= nxa
->cpusubtype
;
57 this->first
= this->second
= none
;
63 // The local architecture.
65 // We take this from ourselves - the architecture of our main program Mach-O binary.
66 // There's the NXGetLocalArchInfo API, but it insists on saying "i386" on modern
67 // x86_64-centric systems, and lies to ppc (Rosetta) programs claiming they're native ppc.
68 // So let's not use that.
70 Architecture
Architecture::local()
72 return MainMachOImage().architecture();
77 // Translate between names and numbers
79 const char *Architecture::name() const
81 if (const NXArchInfo
*info
= NXGetArchInfoFromCpuType(cpuType(), cpuSubtype()))
87 std::string
Architecture::displayName() const
89 if (const char *s
= this->name())
92 snprintf(buf
, sizeof(buf
), "(%d:%d)", cpuType(), cpuSubtype());
98 // Compare architectures.
99 // This is asymmetrical; the second argument provides for some templating.
101 bool Architecture::matches(const Architecture
&templ
) const
103 if (first
!= templ
.first
)
104 return false; // main architecture mismatch
105 if (templ
.second
== CPU_SUBTYPE_MULTIPLE
)
106 return true; // subtype wildcard
107 // match subtypes, ignoring feature bits
108 return ((second
^ templ
.second
) & ~CPU_SUBTYPE_MASK
) == 0;
113 // MachOBase contains knowledge of the Mach-O object file format,
114 // but abstracts from any particular sourcing. It must be subclassed,
115 // and the subclass must provide the file header and commands area
116 // during its construction. Memory is owned by the subclass.
118 MachOBase::~MachOBase()
121 // provide the Mach-O file header, somehow
122 void MachOBase::initHeader(const mach_header
*header
)
125 switch (mHeader
->magic
) {
143 secinfo("macho", "%p: unrecognized header magic (%x)", this, mHeader
->magic
);
144 UnixError::throwMe(ENOEXEC
);
148 // provide the Mach-O commands section, somehow
149 void MachOBase::initCommands(const load_command
*commands
)
151 mCommands
= commands
;
152 mEndCommands
= LowLevelMemoryUtilities::increment
<load_command
>(commands
, flip(mHeader
->sizeofcmds
));
153 if (mCommands
+ 1 > mEndCommands
) // ensure initial load command core available
154 UnixError::throwMe(ENOEXEC
);
158 size_t MachOBase::headerSize() const
160 return m64
? sizeof(mach_header_64
) : sizeof(mach_header
);
163 size_t MachOBase::commandSize() const
165 return flip(mHeader
->sizeofcmds
);
170 // Create a MachO object from an open file and a starting offset.
171 // We load (only) the header and load commands into memory at that time.
172 // Note that the offset must be relative to the start of the containing file
173 // (not relative to some intermediate container).
175 MachO::MachO(FileDesc fd
, size_t offset
, size_t length
)
176 : FileDesc(fd
), mOffset(offset
), mLength(length
), mSuspicious(false)
179 mLength
= fd
.fileSize();
180 size_t size
= fd
.read(&mHeaderBuffer
, sizeof(mHeaderBuffer
), mOffset
);
181 if (size
!= sizeof(mHeaderBuffer
))
182 UnixError::throwMe(ENOEXEC
);
183 this->initHeader(&mHeaderBuffer
);
184 size_t cmdSize
= this->commandSize();
185 mCommandBuffer
= (load_command
*)malloc(cmdSize
);
187 UnixError::throwMe();
188 if (fd
.read(mCommandBuffer
, cmdSize
, this->headerSize() + mOffset
) != cmdSize
)
189 UnixError::throwMe(ENOEXEC
);
190 this->initCommands(mCommandBuffer
);
191 /* If we do not know the length, we cannot do a verification of the mach-o structure */
193 this->validateStructure();
196 void MachO::validateStructure()
198 bool isValid
= false;
200 /* There should be either an LC_SEGMENT, an LC_SEGMENT_64, or an LC_SYMTAB
201 load_command and that + size must be equal to the end of the arch */
202 for (const struct load_command
*cmd
= loadCommands(); cmd
!= NULL
; cmd
= nextCommand(cmd
)) {
203 uint32_t cmd_type
= flip(cmd
->cmd
);
204 struct segment_command
*seg
= NULL
;
205 struct segment_command_64
*seg64
= NULL
;
206 struct symtab_command
*symtab
= NULL
;
208 if (cmd_type
== LC_SEGMENT
) {
209 if(flip(cmd
->cmdsize
) < sizeof(struct segment_command
)) {
210 UnixError::throwMe(ENOEXEC
);
212 seg
= (struct segment_command
*)cmd
;
213 if (strncmp(seg
->segname
, SEG_LINKEDIT
, sizeof(seg
->segname
)) == 0) {
214 isValid
= flip(seg
->fileoff
) + flip(seg
->filesize
) == this->length();
217 } else if (cmd_type
== LC_SEGMENT_64
) {
218 if(flip(cmd
->cmdsize
) < sizeof(struct segment_command_64
)) {
219 UnixError::throwMe(ENOEXEC
);
221 seg64
= (struct segment_command_64
*)cmd
;
222 if (strncmp(seg64
->segname
, SEG_LINKEDIT
, sizeof(seg64
->segname
)) == 0) {
223 isValid
= flip(seg64
->fileoff
) + flip(seg64
->filesize
) == this->length();
226 /* PPC binaries have a SYMTAB section */
227 } else if (cmd_type
== LC_SYMTAB
) {
228 if(flip(cmd
->cmdsize
) < sizeof(struct symtab_command
)) {
229 UnixError::throwMe(ENOEXEC
);
231 symtab
= (struct symtab_command
*)cmd
;
232 isValid
= flip(symtab
->stroff
) + flip(symtab
->strsize
) == this->length();
243 ::free(mCommandBuffer
);
248 // Create a MachO object that is (entirely) mapped into memory.
249 // The caller must ensire that the underlying mapping persists
250 // at least as long as our object.
252 MachOImage::MachOImage(const void *address
)
254 this->initHeader((const mach_header
*)address
);
255 this->initCommands(LowLevelMemoryUtilities::increment
<const load_command
>(address
, this->headerSize()));
260 // Locate the Mach-O image of the main program
262 MainMachOImage::MainMachOImage()
263 : MachOImage(mainImageAddress())
267 const void *MainMachOImage::mainImageAddress()
269 return _dyld_get_image_header(0);
274 // Return various header fields
276 Architecture
MachOBase::architecture() const
278 return Architecture(flip(mHeader
->cputype
), flip(mHeader
->cpusubtype
));
281 uint32_t MachOBase::type() const
283 return flip(mHeader
->filetype
);
286 uint32_t MachOBase::flags() const
288 return flip(mHeader
->flags
);
293 // Iterate through load commands
295 const load_command
*MachOBase::nextCommand(const load_command
*command
) const
297 using LowLevelMemoryUtilities::increment
;
298 /* Do not try and increment by 0, or it will loop forever */
299 if (flip(command
->cmdsize
) == 0)
300 UnixError::throwMe(ENOEXEC
);
301 command
= increment
<const load_command
>(command
, flip(command
->cmdsize
));
302 if (command
>= mEndCommands
) // end of load commands
304 if (increment(command
, sizeof(load_command
)) > mEndCommands
305 || increment(command
, flip(command
->cmdsize
)) > mEndCommands
)
306 UnixError::throwMe(ENOEXEC
);
312 // Find a specific load command, by command number.
313 // If there are multiples, returns the first one found.
315 const load_command
*MachOBase::findCommand(uint32_t cmd
) const
317 for (const load_command
*command
= loadCommands(); command
; command
= nextCommand(command
))
318 if (flip(command
->cmd
) == cmd
)
325 // Locate a segment command, by name
327 const segment_command
*MachOBase::findSegment(const char *segname
) const
329 for (const load_command
*command
= loadCommands(); command
; command
= nextCommand(command
)) {
330 switch (flip(command
->cmd
)) {
334 if(flip(command
->cmdsize
) < sizeof(struct segment_command
)) {
335 UnixError::throwMe(ENOEXEC
);
337 const segment_command
*seg
= reinterpret_cast<const segment_command
*>(command
);
338 if (!strncmp(seg
->segname
, segname
, sizeof(seg
->segname
)))
349 const section
*MachOBase::findSection(const char *segname
, const char *sectname
) const
351 using LowLevelMemoryUtilities::increment
;
352 if (const segment_command
*seg
= findSegment(segname
)) {
354 if(flip(seg
->cmdsize
) < sizeof(segment_command_64
)) {
355 UnixError::throwMe(ENOEXEC
);
357 const segment_command_64
*seg64
= reinterpret_cast<const segment_command_64
*>(seg
);
358 if (sizeof(*seg64
) + (seg64
->nsects
* sizeof(section_64
)) > flip(seg64
->cmdsize
)) // too many segments; doesn't fit (malformed Mach-O)
360 const section_64
*sect
= increment
<const section_64
>(seg64
+ 1, 0);
361 for (unsigned n
= flip(seg64
->nsects
); n
> 0; n
--, sect
++) {
362 if (!strncmp(sect
->sectname
, sectname
, sizeof(sect
->sectname
)))
363 return reinterpret_cast<const section
*>(sect
);
366 if (sizeof(*seg
) + (seg
->nsects
* sizeof(section
)) > flip(seg
->cmdsize
)) // too many segments; doesn't fit (malformed Mach-O)
368 const section
*sect
= increment
<const section
>(seg
+ 1, 0);
369 for (unsigned n
= flip(seg
->nsects
); n
> 0; n
--, sect
++) {
370 if (!strncmp(sect
->sectname
, sectname
, sizeof(sect
->sectname
)))
380 // Translate a union lc_str into the string it denotes.
381 // Returns NULL (no exceptions) if the entry is corrupt.
383 const char *MachOBase::string(const load_command
*cmd
, const lc_str
&str
) const
385 size_t offset
= flip(str
.offset
);
386 const char *sp
= LowLevelMemoryUtilities::increment
<const char>(cmd
, offset
);
387 if (offset
+ strlen(sp
) + 1 > flip(cmd
->cmdsize
)) // corrupt string reference
394 // Figure out where the Code Signing information starts in the Mach-O binary image.
395 // The code signature is at the end of the file, and identified
396 // by a specially-named section. So its starting offset is also the end
397 // of the signable part.
398 // Note that the offset returned is relative to the start of the Mach-O image.
399 // Returns zero if not found (usually indicating that the binary was not signed).
401 const linkedit_data_command
*MachOBase::findCodeSignature() const
403 if (const load_command
*cmd
= findCommand(LC_CODE_SIGNATURE
)) {
404 if(flip(cmd
->cmdsize
) < sizeof(linkedit_data_command
)) {
405 UnixError::throwMe(ENOEXEC
);
407 return reinterpret_cast<const linkedit_data_command
*>(cmd
);
409 return NULL
; // not found
412 size_t MachOBase::signingOffset() const
414 if (const linkedit_data_command
*lec
= findCodeSignature())
415 return flip(lec
->dataoff
);
420 size_t MachOBase::signingLength() const
422 if (const linkedit_data_command
*lec
= findCodeSignature())
423 return flip(lec
->datasize
);
428 const linkedit_data_command
*MachOBase::findLibraryDependencies() const
430 if (const load_command
*cmd
= findCommand(LC_DYLIB_CODE_SIGN_DRS
)) {
431 if(flip(cmd
->cmdsize
) < sizeof(linkedit_data_command
)) {
432 UnixError::throwMe(ENOEXEC
);
434 return reinterpret_cast<const linkedit_data_command
*>(cmd
);
436 return NULL
; // not found
439 const version_min_command
*MachOBase::findMinVersion() const
441 for (const load_command
*command
= loadCommands(); command
; command
= nextCommand(command
))
442 switch (flip(command
->cmd
)) {
443 case LC_VERSION_MIN_MACOSX
:
444 case LC_VERSION_MIN_IPHONEOS
:
445 case LC_VERSION_MIN_WATCHOS
:
446 case LC_VERSION_MIN_TVOS
:
447 if(flip(command
->cmdsize
) < sizeof(version_min_command
)) {
448 UnixError::throwMe(ENOEXEC
);
450 return reinterpret_cast<const version_min_command
*>(command
);
455 const build_version_command
*MachOBase::findBuildVersion() const
457 for (const load_command
*command
= loadCommands(); command
; command
= nextCommand(command
)) {
458 if (flip(command
->cmd
) == LC_BUILD_VERSION
) {
459 if(flip(command
->cmdsize
) < sizeof(build_version_command
)) {
460 UnixError::throwMe(ENOEXEC
);
463 return reinterpret_cast<const build_version_command
*>(command
);
469 bool MachOBase::version(uint32_t *platform
, uint32_t *minVersion
, uint32_t *sdkVersion
) const
471 const build_version_command
*bc
= findBuildVersion();
474 if (platform
!= NULL
) { *platform
= flip(bc
->platform
); }
475 if (minVersion
!= NULL
) { *minVersion
= flip(bc
->minos
); }
476 if (sdkVersion
!= NULL
) { *sdkVersion
= flip(bc
->sdk
); }
480 const version_min_command
*vc
= findMinVersion();
484 switch (flip(vc
->cmd
)) {
485 case LC_VERSION_MIN_MACOSX
:
488 case LC_VERSION_MIN_IPHONEOS
:
491 case LC_VERSION_MIN_WATCHOS
:
492 pf
= PLATFORM_WATCHOS
;
494 case LC_VERSION_MIN_TVOS
:
498 // Old style load command, but we don't know what platform to map to.
502 if (platform
!= NULL
) { *platform
= pf
; }
503 if (minVersion
!= NULL
) { *minVersion
= flip(vc
->version
); }
504 if (sdkVersion
!= NULL
) { *sdkVersion
= flip(vc
->sdk
); }
512 // Return the signing-limit length for this Mach-O binary image.
513 // This is the signingOffset if present, or the full length if not.
515 size_t MachO::signingExtent() const
517 if (size_t offset
= signingOffset())
527 void MachO::seek(size_t offset
)
529 FileDesc::seek(mOffset
+ offset
);
532 CFDataRef
MachO::dataAt(size_t offset
, size_t size
)
534 CFMallocData
buffer(size
);
535 if (this->read(buffer
, size
, mOffset
+ offset
) != size
)
536 UnixError::throwMe();
541 // Fat (aka universal) file wrappers.
542 // The offset is relative to the start of the containing file.
544 Universal::Universal(FileDesc fd
, size_t offset
/* = 0 */, size_t length
/* = 0 */)
545 : FileDesc(fd
), mBase(offset
), mLength(length
), mMachType(0), mSuspicious(false)
548 fat_header header
; // if this is a fat file
549 mach_header mheader
; // if this is a thin file
552 if (fd
.read(&unionHeader
, sizeof(unionHeader
), offset
) != sizeof(unionHeader
))
553 UnixError::throwMe(ENOEXEC
);
554 switch (unionHeader
.header
.magic
) {
560 // Under certain circumstances (15001604), mArchCount under-counts the architectures
561 // by one, and special testing is required to validate the extra-curricular entry.
562 // We always read an extra entry; in the situations where this might hit end-of-file,
563 // we are content to fail.
565 mArchCount
= ntohl(unionHeader
.header
.nfat_arch
);
567 if (mArchCount
> MAX_ARCH_COUNT
)
568 UnixError::throwMe(ENOEXEC
);
570 size_t archSize
= sizeof(fat_arch
) * (mArchCount
+ 1);
571 mArchList
= (fat_arch
*)malloc(archSize
);
573 UnixError::throwMe();
574 if (fd
.read(mArchList
, archSize
, mBase
+ sizeof(unionHeader
.header
)) != archSize
) {
576 UnixError::throwMe(ENOEXEC
);
578 for (fat_arch
*arch
= mArchList
; arch
<= mArchList
+ mArchCount
; arch
++) {
580 n2hi(arch
->cpusubtype
);
585 const fat_arch
*last_arch
= mArchList
+ mArchCount
;
586 if (last_arch
->cputype
== (CPU_ARCH_ABI64
| CPU_TYPE_ARM
)) {
589 secinfo("macho", "%p is a fat file with %d architectures",
592 /* A Mach-O universal file has padding of no more than "page size"
593 * between the header and slices. This padding must be zeroed out or the file
595 std::list
<struct fat_arch
*> sortedList
;
596 for (unsigned i
= 0; i
< mArchCount
; i
++)
597 sortedList
.push_back(mArchList
+ i
);
599 sortedList
.sort(^ bool (const struct fat_arch
*arch1
, const struct fat_arch
*arch2
) { return arch1
->offset
< arch2
->offset
; });
601 const size_t universalHeaderEnd
= mBase
+ sizeof(unionHeader
.header
) + (sizeof(fat_arch
) * mArchCount
);
602 size_t prevHeaderEnd
= universalHeaderEnd
;
603 size_t prevArchSize
= 0, prevArchStart
= 0;
605 for (auto iterator
= sortedList
.begin(); iterator
!= sortedList
.end(); ++iterator
) {
606 auto ret
= mSizes
.insert(std::pair
<size_t, size_t>((*iterator
)->offset
, (*iterator
)->size
));
607 if (ret
.second
== false) {
609 MacOSError::throwMe(errSecInternalError
); // Something is wrong if the same size was encountered twice
612 size_t gapSize
= (*iterator
)->offset
- prevHeaderEnd
;
614 /* The size of the padding after the universal cannot be calculated to a fixed size */
615 if (prevHeaderEnd
!= universalHeaderEnd
) {
616 if (((*iterator
)->align
> MAX_ALIGN
) || gapSize
>= (1 << (*iterator
)->align
)) {
622 // validate gap bytes in tasty page-sized chunks
623 CssmAutoPtr
<uint8_t> gapBytes(Allocator::standard().malloc
<uint8_t>(PAGE_SIZE
));
625 while (off
< gapSize
) {
626 size_t want
= min(gapSize
- off
, (size_t)PAGE_SIZE
);
627 size_t got
= fd
.read(gapBytes
, want
, prevHeaderEnd
+ off
);
633 for (size_t x
= 0; x
< got
; x
++) {
634 if (gapBytes
[x
] != 0) {
647 prevHeaderEnd
= (*iterator
)->offset
+ (*iterator
)->size
;
648 prevArchSize
= (*iterator
)->size
;
649 prevArchStart
= (*iterator
)->offset
;
652 /* If there is anything extra at the end of the file, reject this */
653 if (!mSuspicious
&& (prevArchStart
+ prevArchSize
!= fd
.fileSize()))
662 mThinArch
= Architecture(unionHeader
.mheader
.cputype
, unionHeader
.mheader
.cpusubtype
);
663 secinfo("macho", "%p is a thin file (%s)", this, mThinArch
.name());
669 mThinArch
= Architecture(flip(unionHeader
.mheader
.cputype
), flip(unionHeader
.mheader
.cpusubtype
));
670 secinfo("macho", "%p is a thin file (%s)", this, mThinArch
.name());
673 UnixError::throwMe(ENOEXEC
);
677 Universal::~Universal()
682 size_t Universal::lengthOfSlice(size_t offset
) const
684 auto ret
= mSizes
.find(offset
);
685 if (ret
== mSizes
.end())
686 MacOSError::throwMe(errSecInternalError
);
691 // Get the "local" architecture from the fat file
692 // Throws ENOEXEC if not found.
694 MachO
*Universal::architecture() const
697 return findImage(bestNativeArch());
699 return new MachO(*this, mBase
, mLength
);
702 size_t Universal::archOffset() const
705 return mBase
+ findArch(bestNativeArch())->offset
;
712 // Get the specified architecture from the fat file
713 // Throws ENOEXEC if not found.
715 MachO
*Universal::architecture(const Architecture
&arch
) const
718 return findImage(arch
);
719 else if (mThinArch
.matches(arch
))
720 return new MachO(*this, mBase
);
722 UnixError::throwMe(ENOEXEC
);
725 size_t Universal::archOffset(const Architecture
&arch
) const
728 return mBase
+ findArch(arch
)->offset
;
729 else if (mThinArch
.matches(arch
))
732 UnixError::throwMe(ENOEXEC
);
735 size_t Universal::archLength(const Architecture
&arch
) const
738 return mBase
+ findArch(arch
)->size
;
739 else if (mThinArch
.matches(arch
))
740 return this->fileSize();
742 UnixError::throwMe(ENOEXEC
);
746 // Get the architecture at a specified offset from the fat file.
747 // Throws an exception of the offset does not point at a Mach-O image.
749 MachO
*Universal::architecture(size_t offset
) const
752 return make(new MachO(*this, offset
));
753 else if (offset
== mBase
)
754 return new MachO(*this);
756 UnixError::throwMe(ENOEXEC
);
761 // Locate an architecture from the fat file's list.
762 // Throws ENOEXEC if not found.
764 const fat_arch
*Universal::findArch(const Architecture
&target
) const
766 assert(isUniversal());
767 const fat_arch
*end
= mArchList
+ mArchCount
;
769 for (const fat_arch
*arch
= mArchList
; arch
< end
; ++arch
)
770 if (arch
->cputype
== target
.cpuType()
771 && arch
->cpusubtype
== target
.cpuSubtype())
773 // match for generic model of main architecture
774 for (const fat_arch
*arch
= mArchList
; arch
< end
; ++arch
)
775 if (arch
->cputype
== target
.cpuType() && arch
->cpusubtype
== 0)
777 // match for any subarchitecture of the main architecture (questionable)
778 for (const fat_arch
*arch
= mArchList
; arch
< end
; ++arch
)
779 if (arch
->cputype
== target
.cpuType())
782 UnixError::throwMe(ENOEXEC
); // not found
785 MachO
*Universal::findImage(const Architecture
&target
) const
787 const fat_arch
*arch
= findArch(target
);
788 return make(new MachO(*this, mBase
+ arch
->offset
, arch
->size
));
791 MachO
* Universal::make(MachO
* macho
) const
793 auto_ptr
<MachO
> mo(macho
); // safe resource
794 uint32_t type
= mo
->type();
795 if (type
== 0) // not a recognized Mach-O type
796 UnixError::throwMe(ENOEXEC
);
797 if (mMachType
&& mMachType
!= type
) // inconsistent members
798 UnixError::throwMe(ENOEXEC
);
799 mMachType
= type
; // record
805 // Find the best-matching architecture for this fat file.
806 // We pick the native architecture if it's available.
807 // If it contains exactly one architecture, we take that.
808 // Otherwise, we throw.
810 Architecture
Universal::bestNativeArch() const
813 // ask the NXArch API for our native architecture
814 const Architecture native
= Architecture::local();
815 if (fat_arch
*match
= NXFindBestFatArch(native
.cpuType(), native
.cpuSubtype(), mArchList
, mArchCount
))
817 // if the system can't figure it out, pick (arbitrarily) the first one
824 // List all architectures from the fat file's list.
826 void Universal::architectures(Architectures
&archs
) const
829 for (unsigned n
= 0; n
< mArchCount
; n
++)
830 archs
.insert(mArchList
[n
]);
832 auto_ptr
<MachO
> macho(architecture());
833 archs
.insert(macho
->architecture());
838 // Quickly guess the Mach-O type of a file.
839 // Returns type zero if the file isn't Mach-O or Universal.
840 // Always looks at the start of the file, and does not change the file pointer.
842 uint32_t Universal::typeOf(FileDesc fd
)
846 if (fd
.read(&header
, sizeof(header
), 0) != sizeof(header
))
848 while (max_tries
> 0) {
849 switch (header
.magic
) {
852 return header
.filetype
;
855 return flip(header
.filetype
);
859 const fat_arch
*arch1
=
860 LowLevelMemoryUtilities::increment
<fat_arch
>(&header
, sizeof(fat_header
));
861 if (fd
.read(&header
, sizeof(header
), ntohl(arch1
->offset
)) != sizeof(header
))
876 bool Universal::isSuspicious() const
880 Universal::Architectures archList
;
881 architectures(archList
);
882 for (Universal::Architectures::const_iterator it
= archList
.begin(); it
!= archList
.end(); ++it
) {
883 auto_ptr
<MachO
> macho(architecture(*it
));
884 if (macho
->isSuspicious())