1/* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-
2 *
3 * Copyright (c) 2006-2011 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
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
12 * file.
13 *
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.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25#ifndef __MACHO_LAYOUT__
26#define __MACHO_LAYOUT__
27
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <sys/errno.h>
31#include <sys/mman.h>
32#include <mach/mach.h>
33#include <limits.h>
34#include <stdarg.h>
35#include <stdio.h>
36#include <fcntl.h>
37#include <errno.h>
38#include <unistd.h>
39#include <mach-o/loader.h>
40#include <mach-o/fat.h>
41
42#include <vector>
43#include <set>
44#include <unordered_map>
45
46#include "MachOFileAbstraction.hpp"
47#include "Architectures.hpp"
48
49
50void throwf(const char* format, ...) __attribute__((format(printf, 1, 2)));
51
52__attribute__((noreturn))
53void throwf(const char* format, ...)
54{
55	va_list	list;
56	char*	p;
57	va_start(list, format);
58	vasprintf(&p, format, list);
59	va_end(list);
60
61	const char*	t = p;
62	throw t;
63}
64
65
66class MachOLayoutAbstraction
67{
68public:
69	struct Segment
70	{
71	public:
72					Segment(uint64_t addr, uint64_t vmsize, uint64_t offset, uint64_t file_size,
73							uint32_t prot, const char* segName) : fOrigAddress(addr), fOrigSize(vmsize),
74							fOrigFileOffset(offset),  fOrigFileSize(file_size), fOrigPermissions(prot),
75							fSize(vmsize), fFileOffset(offset), fFileSize(file_size), fPermissions(prot),
76							fNewAddress(0), fMappedAddress(NULL) {
77								strlcpy(fOrigName, segName, 16);
78							}
79
80		uint64_t	address() const		{ return fOrigAddress; }
81		uint64_t	size() const		{ return fSize; }
82		uint64_t	fileOffset() const	{ return fFileOffset; }
83		uint64_t	fileSize() const	{ return fFileSize; }
84		uint32_t	permissions() const { return fPermissions; }
85		bool		readable() const	{ return fPermissions & VM_PROT_READ; }
86		bool		writable() const	{ return fPermissions & VM_PROT_WRITE; }
87		bool		executable() const	{ return fPermissions & VM_PROT_EXECUTE; }
88		const char* name() const		{ return fOrigName; }
89		uint64_t	newAddress() const	{ return fNewAddress; }
90		void*		mappedAddress() const			{ return fMappedAddress; }
91		void		setNewAddress(uint64_t addr)	{ fNewAddress = addr; }
92		void		setMappedAddress(void* addr)	{ fMappedAddress = addr; }
93		void		setSize(uint64_t new_size)		{ fSize = new_size; }
94		void		setFileOffset(uint64_t new_off)	{ fFileOffset = new_off; }
95		void		setFileSize(uint64_t new_size)	{ fFileSize = new_size; }
96		void		setWritable(bool w)				{ if (w) fPermissions |= VM_PROT_WRITE; else fPermissions &= ~VM_PROT_WRITE; }
97		void		reset()							{ fSize=fOrigSize; fFileOffset=fOrigFileOffset; fFileSize=fOrigFileSize; fPermissions=fOrigPermissions; }
98	private:
99		uint64_t		fOrigAddress;
100		uint64_t		fOrigSize;
101		uint64_t		fOrigFileOffset;
102		uint64_t		fOrigFileSize;
103		uint32_t		fOrigPermissions;
104		char			fOrigName[16];
105		uint64_t		fSize;
106		uint64_t		fFileOffset;
107		uint64_t		fFileSize;
108		uint32_t		fPermissions;
109		uint64_t		fNewAddress;
110		void*			fMappedAddress;
111	};
112
113	struct Library
114	{
115		const char*	name;
116		uint32_t	currentVersion;
117		uint32_t	compatibilityVersion;
118		bool		weakImport;
119	};
120
121
122	virtual ArchPair							getArchPair() const = 0;
123	virtual const char*							getFilePath() const = 0;
124	virtual uint64_t							getOffsetInUniversalFile() const	= 0;
125	virtual uint32_t							getFileType() const	= 0;
126	virtual uint32_t							getFlags() const = 0;
127	virtual	Library								getID() const = 0;
128	virtual bool								isDylib() const = 0;
129	virtual bool								isSplitSeg() const = 0;
130	virtual bool								hasSplitSegInfo() const = 0;
131	virtual bool								isRootOwned() const = 0;
132	virtual bool								inSharableLocation() const = 0;
133	virtual bool								hasDynamicLookupLinkage() const = 0;
134	virtual bool								hasMainExecutableLookupLinkage() const = 0;
135	virtual bool								isTwoLevelNamespace() const	= 0;
136	virtual bool								hasDyldInfo() const	= 0;
137	virtual	uint32_t							getNameFileOffset() const = 0;
138	virtual time_t								getLastModTime() const = 0;
139	virtual ino_t								getInode() const = 0;
140	virtual std::vector<Segment>&				getSegments() = 0;
141	virtual const std::vector<Segment>&			getSegments() const = 0;
142	virtual const std::vector<Library>&			getLibraries() const = 0;
143	virtual uint64_t							getBaseAddress() const = 0;
144	virtual uint64_t							getVMSize() const = 0;
145	virtual uint64_t							getBaseExecutableAddress() const = 0;
146	virtual uint64_t							getBaseWritableAddress() const = 0;
147	virtual uint64_t							getBaseReadOnlyAddress() const = 0;
148	virtual uint64_t							getExecutableVMSize() const = 0;
149	virtual uint64_t							getWritableVMSize() const = 0;
150	virtual uint64_t							getReadOnlyVMSize() const = 0;
151	// need getDyldInfoExports because export info uses ULEB encoding and size could grow
152	virtual const uint8_t*						getDyldInfoExports() const = 0;
153	virtual void								setDyldInfoExports(const uint8_t* newExports) const = 0;
154	virtual void								uuid(uuid_t u) const = 0;
155};
156
157
158
159
160template <typename A>
161class MachOLayout : public MachOLayoutAbstraction
162{
163public:
164												MachOLayout(const void* machHeader, uint64_t offset, const char* path,
165																	ino_t inode, time_t modTime, uid_t uid);
166	virtual										~MachOLayout() {}
167
168	virtual ArchPair							getArchPair() const		{ return fArchPair; }
169	virtual const char*							getFilePath() const		{ return fPath; }
170	virtual uint64_t							getOffsetInUniversalFile() const { return fOffset; }
171	virtual uint32_t							getFileType() const		{ return fFileType; }
172	virtual uint32_t							getFlags() const		{ return fFlags; }
173	virtual	Library								getID() const			{ return fDylibID; }
174	virtual bool								isDylib() const			{ return fIsDylib; }
175	virtual bool								isSplitSeg() const;
176	virtual bool								hasSplitSegInfo() const	{ return fHasSplitSegInfo; }
177	virtual bool								isRootOwned() const		{ return fRootOwned; }
178	virtual bool								inSharableLocation() const { return fShareableLocation; }
179	virtual bool								hasDynamicLookupLinkage() const { return fDynamicLookupLinkage; }
180	virtual bool								hasMainExecutableLookupLinkage() const { return fMainExecutableLookupLinkage; }
181	virtual bool								isTwoLevelNamespace() const	{ return (fFlags & MH_TWOLEVEL); }
182	virtual bool								hasDyldInfo() const		{ return fHasDyldInfo; }
183	virtual	uint32_t							getNameFileOffset() const{ return fNameFileOffset; }
184	virtual time_t								getLastModTime() const	{ return fMTime; }
185	virtual ino_t								getInode() const		{ return fInode; }
186	virtual std::vector<Segment>&				getSegments()			{ return fSegments; }
187	virtual const std::vector<Segment>&			getSegments() const		{ return fSegments; }
188	virtual const std::vector<Library>&			getLibraries() const	{ return fLibraries; }
189	virtual uint64_t							getBaseAddress() const	{ return fLowSegment->address(); }
190	virtual uint64_t							getVMSize() const		{ return fVMSize; }
191	virtual uint64_t							getBaseExecutableAddress() const { return fLowExecutableSegment->address(); }
192	virtual uint64_t							getBaseWritableAddress() const	{ return fLowWritableSegment->address(); }
193	virtual uint64_t							getBaseReadOnlyAddress() const	{ return fLowReadOnlySegment->address(); }
194	virtual uint64_t							getExecutableVMSize() const		{ return fVMExecutableSize; }
195	virtual uint64_t							getWritableVMSize() const		{ return fVMWritablSize; }
196	virtual uint64_t							getReadOnlyVMSize() const		{ return fVMReadOnlySize; }
197	virtual const uint8_t*						getDyldInfoExports() const		{ return fDyldInfoExports; }
198	virtual void								setDyldInfoExports(const uint8_t* newExports) const { fDyldInfoExports = newExports; }
199	virtual void								uuid(uuid_t u) const { memcpy(u, fUUID, 16); }
200
201private:
202	typedef typename A::P					P;
203	typedef typename A::P::E				E;
204	typedef typename A::P::uint_t			pint_t;
205
206	static cpu_type_t							arch();
207
208	const char*									fPath;
209	uint64_t									fOffset;
210	uint32_t									fFileType;
211	ArchPair									fArchPair;
212	uint32_t									fFlags;
213	std::vector<Segment>						fSegments;
214	std::vector<Library>						fLibraries;
215	const Segment*								fLowSegment;
216	const Segment*								fLowExecutableSegment;
217	const Segment*								fLowWritableSegment;
218	const Segment*								fLowReadOnlySegment;
219	Library										fDylibID;
220	uint32_t									fNameFileOffset;
221	time_t										fMTime;
222	ino_t										fInode;
223	uint64_t									fVMSize;
224	uint64_t									fVMExecutableSize;
225	uint64_t									fVMWritablSize;
226	uint64_t									fVMReadOnlySize;
227	bool										fHasSplitSegInfo;
228	bool										fRootOwned;
229	bool										fShareableLocation;
230	bool										fDynamicLookupLinkage;
231	bool										fMainExecutableLookupLinkage;
232	bool										fIsDylib;
233	bool										fHasDyldInfo;
234	mutable const uint8_t*						fDyldInfoExports;
235	uuid_t										fUUID;
236};
237
238
239
240class UniversalMachOLayout
241{
242public:
243												UniversalMachOLayout(const char* path, const std::set<ArchPair>* onlyArchs=NULL);
244												~UniversalMachOLayout() {}
245
246	static const UniversalMachOLayout&			find(const char* path, const std::set<ArchPair>* onlyArchs=NULL);
247	const MachOLayoutAbstraction*				getSlice(ArchPair ap) const;
248	const std::vector<MachOLayoutAbstraction*>&	allLayouts() const { return fLayouts; }
249
250private:
251	class CStringHash {
252	public:
253		size_t operator()(const char* __s) const {
254			size_t __h = 0;
255			for ( ; *__s; ++__s)
256				__h = 5 * __h + *__s;
257			return __h;
258		};
259	};
260	struct CStringEquals {
261		bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
262	};
263	typedef std::unordered_map<const char*, const UniversalMachOLayout*, CStringHash, CStringEquals> PathToNode;
264
265	static bool					requestedSlice(const std::set<ArchPair>* onlyArchs, cpu_type_t cpuType, cpu_subtype_t cpuSubType);
266
267	static PathToNode							fgLayoutCache;
268	const char*									fPath;
269	std::vector<MachOLayoutAbstraction*>		fLayouts;
270};
271
272UniversalMachOLayout::PathToNode UniversalMachOLayout::fgLayoutCache;
273
274
275
276
277const MachOLayoutAbstraction* UniversalMachOLayout::getSlice(ArchPair ap) const
278{
279	// use matching cputype and cpusubtype
280	for(std::vector<MachOLayoutAbstraction*>::const_iterator it=fLayouts.begin(); it != fLayouts.end(); ++it) {
281		const MachOLayoutAbstraction* layout = *it;
282		if ( layout->getArchPair().arch == ap.arch ) {
283            switch ( ap.arch ) {
284                case CPU_TYPE_ARM:
285                    if ( layout->getArchPair().subtype == ap.subtype )
286                        return layout;
287                    break;
288                default:
289                    return layout;
290            }
291        }
292	}
293	return NULL;
294}
295
296
297const UniversalMachOLayout& UniversalMachOLayout::find(const char* path, const std::set<ArchPair>* onlyArchs)
298{
299	// look in cache
300	PathToNode::iterator pos = fgLayoutCache.find(path);
301	if ( pos != fgLayoutCache.end() )
302		return *pos->second;
303
304	// create UniversalMachOLayout
305	const UniversalMachOLayout* result = new UniversalMachOLayout(path, onlyArchs);
306
307	// add it to cache
308	fgLayoutCache[result->fPath] = result;
309
310	return *result;
311}
312
313
314bool UniversalMachOLayout::requestedSlice(const std::set<ArchPair>* onlyArchs, cpu_type_t cpuType, cpu_subtype_t cpuSubType)
315{
316	if ( onlyArchs == NULL )
317		return true;
318	// must match cputype and cpusubtype
319	for (std::set<ArchPair>::const_iterator it = onlyArchs->begin(); it != onlyArchs->end(); ++it) {
320		ArchPair anArch = *it;
321		if ( cpuType == anArch.arch ) {
322            switch ( cpuType ) {
323                case CPU_TYPE_ARM:
324                    if ( cpuSubType == anArch.subtype )
325                        return true;
326                    break;
327                default:
328                    return true;
329            }
330        }
331	}
332	return false;
333}
334
335
336UniversalMachOLayout::UniversalMachOLayout(const char* path, const std::set<ArchPair>* onlyArchs)
337 : fPath(strdup(path))
338{
339	// map in whole file
340	int fd = ::open(path, O_RDONLY, 0);
341	if ( fd == -1 ) {
342		int err = errno;
343		if  ( err == ENOENT )
344			throwf("file not found");
345		else
346			throwf("can't open file, errno=%d", err);
347	}
348	struct stat stat_buf;
349	if ( fstat(fd, &stat_buf) == -1)
350		throwf("can't stat open file %s, errno=%d", path, errno);
351	if ( stat_buf.st_size < 20 )
352		throwf("file too small %s", path);
353	uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
354	if ( p == (uint8_t*)(-1) )
355		throwf("can't map file %s, errno=%d", path, errno);
356	::close(fd);
357
358	try {
359		// if fat file, process each architecture
360		const fat_header* fh = (fat_header*)p;
361		const mach_header* mh = (mach_header*)p;
362		if ( fh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
363			// Fat header is always big-endian
364			const struct fat_arch* slices = (struct fat_arch*)(p + sizeof(struct fat_header));
365			const uint32_t sliceCount = OSSwapBigToHostInt32(fh->nfat_arch);
366			for (uint32_t i=0; i < sliceCount; ++i) {
367				if ( requestedSlice(onlyArchs, OSSwapBigToHostInt32(slices[i].cputype), OSSwapBigToHostInt32(slices[i].cpusubtype)) ) {
368					uint32_t fileOffset = OSSwapBigToHostInt32(slices[i].offset);
369					if ( fileOffset > stat_buf.st_size ) {
370						throwf("malformed universal file, slice %u for architecture 0x%08X is beyond end of file: %s",
371								i, OSSwapBigToHostInt32(slices[i].cputype), path);
372					}
373					if ( (fileOffset+OSSwapBigToHostInt32(slices[i].size)) > stat_buf.st_size ) {
374						throwf("malformed universal file, slice %u for architecture 0x%08X is beyond end of file: %s",
375								i, OSSwapBigToHostInt32(slices[i].cputype), path);
376					}
377					try {
378						switch ( OSSwapBigToHostInt32(slices[i].cputype) ) {
379							case CPU_TYPE_I386:
380								fLayouts.push_back(new MachOLayout<x86>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
381								break;
382							case CPU_TYPE_X86_64:
383								fLayouts.push_back(new MachOLayout<x86_64>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
384								break;
385							case CPU_TYPE_ARM:
386								fLayouts.push_back(new MachOLayout<arm>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
387								break;
388							default:
389								throw "unknown slice in fat file";
390						}
391					}
392					catch (const char* msg) {
393						fprintf(stderr, "warning: %s for %s\n", msg, path);
394					}
395				}
396			}
397		}
398		else {
399			try {
400if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_I386)) {
401					if ( requestedSlice(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) )
402						fLayouts.push_back(new MachOLayout<x86>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
403				}
404				else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC_64) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_X86_64)) {
405					if ( requestedSlice(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) )
406						fLayouts.push_back(new MachOLayout<x86_64>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
407				}
408				else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_ARM)) {
409					if ( requestedSlice(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) )
410						fLayouts.push_back(new MachOLayout<arm>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
411				}
412				else {
413					throw "unknown file format";
414				}
415			}
416			catch (const char* msg) {
417				fprintf(stderr, "warning: %s for %s\n", msg, path);
418			}
419		}
420	}
421	catch (...) {
422		::munmap(p, stat_buf.st_size);
423		throw;
424	}
425}
426
427
428template <typename A>
429MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char* path, ino_t inode, time_t modTime, uid_t uid)
430 : fPath(path), fOffset(offset), fArchPair(0,0), fMTime(modTime), fInode(inode), fHasSplitSegInfo(false), fRootOwned(uid==0),
431   fShareableLocation(false), fDynamicLookupLinkage(false), fMainExecutableLookupLinkage(false), fIsDylib(false),
432	fHasDyldInfo(false), fDyldInfoExports(NULL)
433{
434	fDylibID.name = NULL;
435	fDylibID.currentVersion = 0;
436	fDylibID.compatibilityVersion = 0;
437	bzero(fUUID, sizeof(fUUID));
438
439	const macho_header<P>* mh = (const macho_header<P>*)machHeader;
440	if ( mh->cputype() != arch() )
441		throw "Layout object is wrong architecture";
442	switch ( mh->filetype() ) {
443		case MH_DYLIB:
444			fIsDylib = true;
445			break;
446		case MH_BUNDLE:
447		case MH_EXECUTE:
448		case MH_DYLIB_STUB:
449		case MH_DYLINKER:
450			break;
451		default:
452			throw "file is not a mach-o final linked image";
453	}
454	fFlags = mh->flags();
455	fFileType = mh->filetype();
456	fArchPair.arch = mh->cputype();
457	fArchPair.subtype = mh->cpusubtype();
458
459	const macho_dyld_info_command<P>* dyldInfo = NULL;
460	const macho_symtab_command<P>* symbolTableCmd = NULL;
461	const macho_dysymtab_command<P>* dynamicSymbolTableCmd = NULL;
462	const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)mh + sizeof(macho_header<P>));
463	const uint32_t cmd_count = mh->ncmds();
464	const macho_load_command<P>* cmd = cmds;
465	for (uint32_t i = 0; i < cmd_count; ++i) {
466		switch ( cmd->cmd() ) {
467			case LC_ID_DYLIB:
468				{
469					macho_dylib_command<P>* dylib  = (macho_dylib_command<P>*)cmd;
470					fDylibID.name = strdup(dylib->name());
471					fDylibID.currentVersion = dylib->current_version();
472					fDylibID.compatibilityVersion = dylib->compatibility_version();
473					fNameFileOffset = dylib->name() - (char*)machHeader;
474					fShareableLocation = ( (strncmp(fDylibID.name, "/usr/lib/", 9) == 0) || (strncmp(fDylibID.name, "/System/Library/", 16) == 0) );
475				}
476				break;
477			case LC_LOAD_DYLIB:
478			case LC_LOAD_WEAK_DYLIB:
479			case LC_REEXPORT_DYLIB:
480			case LC_LOAD_UPWARD_DYLIB:
481				{
482					macho_dylib_command<P>* dylib = (macho_dylib_command<P>*)cmd;
483					Library lib;
484					lib.name = strdup(dylib->name());
485					lib.currentVersion = dylib->current_version();
486					lib.compatibilityVersion = dylib->compatibility_version();
487					lib.weakImport = ( cmd->cmd() == LC_LOAD_WEAK_DYLIB );
488					fLibraries.push_back(lib);
489				}
490				break;
491			case LC_SEGMENT_SPLIT_INFO:
492				fHasSplitSegInfo = true;
493				break;
494			case macho_segment_command<P>::CMD:
495				{
496					macho_segment_command<P>* segCmd = (macho_segment_command<P>*)cmd;
497					fSegments.push_back(Segment(segCmd->vmaddr(), segCmd->vmsize(), segCmd->fileoff(),
498								segCmd->filesize(), segCmd->initprot(), segCmd->segname()));
499				}
500				break;
501			case LC_SYMTAB:
502				symbolTableCmd = (macho_symtab_command<P>*)cmd;
503				break;
504			case LC_DYSYMTAB:
505				dynamicSymbolTableCmd = (macho_dysymtab_command<P>*)cmd;
506				break;
507			case LC_DYLD_INFO:
508			case LC_DYLD_INFO_ONLY:
509				fHasDyldInfo = true;
510				dyldInfo = (struct macho_dyld_info_command<P>*)cmd;
511				break;
512			case LC_UUID:
513				{
514					const macho_uuid_command<P>* uc = (macho_uuid_command<P>*)cmd;
515					memcpy(&fUUID, uc->uuid(), 16);
516				}
517				break;
518		}
519		cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
520	}
521
522	fLowSegment = NULL;
523	fLowExecutableSegment = NULL;
524	fLowWritableSegment = NULL;
525	fLowReadOnlySegment = NULL;
526	fVMExecutableSize = 0;
527	fVMWritablSize = 0;
528	fVMReadOnlySize = 0;
529	fVMSize = 0;
530	const Segment* highSegment = NULL;
531	for(std::vector<Segment>::const_iterator it = fSegments.begin(); it != fSegments.end(); ++it) {
532		const Segment& seg = *it;
533		if ( (fLowSegment == NULL) || (seg.address() < fLowSegment->address()) )
534			fLowSegment = &seg;
535		if ( (highSegment == NULL) || (seg.address() > highSegment->address()) )
536			highSegment = &seg;
537		if ( seg.executable() ) {
538			if ( (fLowExecutableSegment == NULL) || (seg.address() < fLowExecutableSegment->address()) )
539				fLowExecutableSegment = &seg;
540			fVMExecutableSize += seg.size();
541		}
542		else if ( seg.writable()) {
543			if ( (fLowWritableSegment == NULL) || (seg.address() < fLowWritableSegment->address()) )
544				fLowWritableSegment = &seg;
545			fVMWritablSize += seg.size();
546		}
547		else {
548			if ( (fLowReadOnlySegment == NULL) || (seg.address() < fLowReadOnlySegment->address()) )
549				fLowReadOnlySegment = &seg;
550			fVMReadOnlySize += seg.size();
551		}
552	}
553	if ( (highSegment != NULL) && (fLowSegment != NULL) )
554		fVMSize = (highSegment->address() + highSegment->size() - fLowSegment->address() + 4095) & (-4096);
555
556	// scan undefines looking, for magic ordinals
557	if ( (symbolTableCmd != NULL) && (dynamicSymbolTableCmd != NULL) ) {
558		const macho_nlist<P>* symbolTable = (macho_nlist<P>*)((uint8_t*)machHeader + symbolTableCmd->symoff());
559		const uint32_t startUndefs = dynamicSymbolTableCmd->iundefsym();
560		const uint32_t endUndefs = startUndefs + dynamicSymbolTableCmd->nundefsym();
561		for (uint32_t i=startUndefs; i < endUndefs; ++i) {
562			uint8_t ordinal = GET_LIBRARY_ORDINAL(symbolTable[i].n_desc());
563			if ( ordinal == DYNAMIC_LOOKUP_ORDINAL )
564				fDynamicLookupLinkage = true;
565			else if ( ordinal == EXECUTABLE_ORDINAL )
566				fMainExecutableLookupLinkage = true;
567		}
568	}
569
570	if ( dyldInfo != NULL ) {
571		if ( dyldInfo->export_off() != 0 ) {
572			fDyldInfoExports = (uint8_t*)machHeader + dyldInfo->export_off();
573		}
574	}
575
576}
577
578template <> cpu_type_t MachOLayout<x86>::arch()     { return CPU_TYPE_I386; }
579template <> cpu_type_t MachOLayout<x86_64>::arch()  { return CPU_TYPE_X86_64; }
580template <> cpu_type_t MachOLayout<arm>::arch()		{ return CPU_TYPE_ARM; }
581
582
583template <>
584bool MachOLayout<x86>::isSplitSeg() const
585{
586	return ( (this->getFlags() & MH_SPLIT_SEGS) != 0 );
587}
588
589template <>
590bool MachOLayout<arm>::isSplitSeg() const
591{
592	return ( (this->getFlags() & MH_SPLIT_SEGS) != 0 );
593}
594
595template <typename A>
596bool MachOLayout<A>::isSplitSeg() const
597{
598	return false;
599}
600
601
602#endif // __MACHO_LAYOUT__
603
604
605
606