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