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