]> git.saurik.com Git - apple/dyld.git/blobdiff - launch-cache/MachOLayout.hpp
dyld-210.2.3.tar.gz
[apple/dyld.git] / launch-cache / MachOLayout.hpp
index 1a3017f329e78b0311d1e35507c765cea234b0ea..4d6583b6bb858f1a6623d3b230e45a082a73dffc 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- 
  *
- * Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2006-2011 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
@@ -27,6 +27,7 @@
 
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/errno.h>
 #include <sys/mman.h>
 #include <mach/mach.h>
 #include <limits.h>
@@ -40,6 +41,7 @@
 
 #include <vector>
 #include <set>
+#include <ext/hash_map>
 
 #include "MachOFileAbstraction.hpp"
 #include "Architectures.hpp"
@@ -68,13 +70,14 @@ public:
        {
        public:
                                        Segment(uint64_t addr, uint64_t vmsize, uint64_t offset, uint64_t file_size, 
-                                                       uint32_t prot, const char* segName) : fAddress(addr), fSize(vmsize),
-                                                       fFileOffset(offset), fFileSize(file_size), fPermissions(prot),
+                                                       uint32_t prot, const char* segName) : fOrigAddress(addr), fOrigSize(vmsize),
+                                                       fOrigFileOffset(offset),  fOrigFileSize(file_size), fOrigPermissions(prot), 
+                                                       fSize(vmsize), fFileOffset(offset), fFileSize(file_size), fPermissions(prot),
                                                        fNewAddress(0), fMappedAddress(NULL) {
-                                                               strlcpy(fName, segName, 16);
+                                                               strlcpy(fOrigName, segName, 16);
                                                        }
                                                        
-               uint64_t        address() const         { return fAddress; }
+               uint64_t        address() const         { return fOrigAddress; }
                uint64_t        size() const            { return fSize; }
                uint64_t        fileOffset() const      { return fFileOffset; }
                uint64_t        fileSize() const        { return fFileSize; }
@@ -82,7 +85,7 @@ public:
                bool            readable() const        { return fPermissions & VM_PROT_READ; }
                bool            writable() const        { return fPermissions & VM_PROT_WRITE; }
                bool            executable() const      { return fPermissions & VM_PROT_EXECUTE; }
-               const char* name() const                { return fName; }
+               const char* name() const                { return fOrigName; }
                uint64_t        newAddress() const      { return fNewAddress; }
                void*           mappedAddress() const                   { return fMappedAddress; }
                void            setNewAddress(uint64_t addr)    { fNewAddress = addr; }
@@ -90,16 +93,21 @@ public:
                void            setSize(uint64_t new_size)              { fSize = new_size; }
                void            setFileOffset(uint64_t new_off) { fFileOffset = new_off; }
                void            setFileSize(uint64_t new_size)  { fFileSize = new_size; }
-               void            setWritable(bool writable)              { if (writable) fPermissions |= VM_PROT_WRITE; else fPermissions &= ~VM_PROT_WRITE; }
+               void            setWritable(bool w)                             { if (w) fPermissions |= VM_PROT_WRITE; else fPermissions &= ~VM_PROT_WRITE; }
+               void            reset()                                                 { fSize=fOrigSize; fFileOffset=fOrigFileOffset; fFileSize=fOrigFileSize; fPermissions=fOrigPermissions; }
        private:
-               uint64_t        fAddress;
-               uint64_t        fSize;
-               uint64_t        fFileOffset;
-               uint64_t        fFileSize;
-               uint64_t        fNewAddress;
-               void*           fMappedAddress;
-               uint32_t        fPermissions;
-               char            fName[16];
+               uint64_t                fOrigAddress;
+               uint64_t                fOrigSize;
+               uint64_t                fOrigFileOffset;
+               uint64_t                fOrigFileSize;
+               uint32_t                fOrigPermissions;
+               char                    fOrigName[16];
+               uint64_t                fSize;
+               uint64_t                fFileOffset;
+               uint64_t                fFileSize;
+               uint32_t                fPermissions;
+               uint64_t                fNewAddress;
+               void*                   fMappedAddress;
        };
 
        struct Library
@@ -107,17 +115,25 @@ public:
                const char*     name;
                uint32_t        currentVersion;
                uint32_t        compatibilityVersion;
+               bool            weakImport;
        };
        
        
-       virtual cpu_type_t                                                      getArchitecture() const = 0;
+       virtual ArchPair                                                        getArchPair() const = 0;
        virtual const char*                                                     getFilePath() const = 0;
        virtual uint64_t                                                        getOffsetInUniversalFile() const        = 0;
        virtual uint32_t                                                        getFileType() const     = 0;
        virtual uint32_t                                                        getFlags() const = 0;
        virtual Library                                                         getID() const = 0;
+       virtual bool                                                            isDylib() const = 0;
        virtual bool                                                            isSplitSeg() const = 0;
        virtual bool                                                            hasSplitSegInfo() const = 0;
+       virtual bool                                                            isRootOwned() const = 0;
+       virtual bool                                                            inSharableLocation() const = 0;
+       virtual bool                                                            hasDynamicLookupLinkage() const = 0;
+       virtual bool                                                            hasMainExecutableLookupLinkage() const = 0;
+       virtual bool                                                            isTwoLevelNamespace() const     = 0;
+       virtual bool                                                            hasDyldInfo() const     = 0;
        virtual uint32_t                                                        getNameFileOffset() const = 0;
        virtual time_t                                                          getLastModTime() const = 0;
        virtual ino_t                                                           getInode() const = 0;
@@ -132,6 +148,9 @@ public:
        virtual uint64_t                                                        getExecutableVMSize() const = 0;
        virtual uint64_t                                                        getWritableVMSize() const = 0;
        virtual uint64_t                                                        getReadOnlyVMSize() const = 0;
+       // need getDyldInfoExports because export info uses ULEB encoding and size could grow
+       virtual const uint8_t*                                          getDyldInfoExports() const = 0;
+       virtual void                                                            setDyldInfoExports(const uint8_t* newExports) const = 0;
 };
 
 
@@ -141,17 +160,25 @@ template <typename A>
 class MachOLayout : public MachOLayoutAbstraction
 {
 public:
-                                                                                               MachOLayout(const void* machHeader, uint64_t offset, const char* path, ino_t inode, time_t modTime);
+                                                                                               MachOLayout(const void* machHeader, uint64_t offset, const char* path,
+                                                                                                                                       ino_t inode, time_t modTime, uid_t uid);
        virtual                                                                         ~MachOLayout() {}
 
-       virtual cpu_type_t                                                      getArchitecture() const;
+       virtual ArchPair                                                        getArchPair() const             { return fArchPair; }
        virtual const char*                                                     getFilePath() const             { return fPath; }
        virtual uint64_t                                                        getOffsetInUniversalFile() const { return fOffset; }
        virtual uint32_t                                                        getFileType() const             { return fFileType; }
        virtual uint32_t                                                        getFlags() const                { return fFlags; }
        virtual Library                                                         getID() const                   { return fDylibID; }
+       virtual bool                                                            isDylib() const                 { return fIsDylib; }
        virtual bool                                                            isSplitSeg() const;
        virtual bool                                                            hasSplitSegInfo() const { return fHasSplitSegInfo; }
+       virtual bool                                                            isRootOwned() const             { return fRootOwned; }
+       virtual bool                                                            inSharableLocation() const { return fShareableLocation; }
+       virtual bool                                                            hasDynamicLookupLinkage() const { return fDynamicLookupLinkage; }
+       virtual bool                                                            hasMainExecutableLookupLinkage() const { return fMainExecutableLookupLinkage; }
+       virtual bool                                                            isTwoLevelNamespace() const     { return (fFlags & MH_TWOLEVEL); }
+       virtual bool                                                            hasDyldInfo() const             { return fHasDyldInfo; }
        virtual uint32_t                                                        getNameFileOffset() const{ return fNameFileOffset; }
        virtual time_t                                                          getLastModTime() const  { return fMTime; }
        virtual ino_t                                                           getInode() const                { return fInode; }
@@ -166,15 +193,20 @@ public:
        virtual uint64_t                                                        getExecutableVMSize() const             { return fVMExecutableSize; }
        virtual uint64_t                                                        getWritableVMSize() const               { return fVMWritablSize; }
        virtual uint64_t                                                        getReadOnlyVMSize() const               { return fVMReadOnlySize; }
-
+       virtual const uint8_t*                                          getDyldInfoExports() const              { return fDyldInfoExports; }
+       virtual void                                                            setDyldInfoExports(const uint8_t* newExports) const { fDyldInfoExports = newExports; }
+       
 private:
        typedef typename A::P                                   P;
        typedef typename A::P::E                                E;
        typedef typename A::P::uint_t                   pint_t;
        
+       static cpu_type_t                                                       arch();
+
        const char*                                                                     fPath;
        uint64_t                                                                        fOffset;
        uint32_t                                                                        fFileType;
+       ArchPair                                                                        fArchPair;
        uint32_t                                                                        fFlags;
        std::vector<Segment>                                            fSegments;
        std::vector<Library>                                            fLibraries;
@@ -191,6 +223,13 @@ private:
        uint64_t                                                                        fVMWritablSize;
        uint64_t                                                                        fVMReadOnlySize;
        bool                                                                            fHasSplitSegInfo;
+       bool                                                                            fRootOwned;
+       bool                                                                            fShareableLocation;
+       bool                                                                            fDynamicLookupLinkage;
+       bool                                                                            fMainExecutableLookupLinkage;
+       bool                                                                            fIsDylib;
+       bool                                                                            fHasDyldInfo;
+       mutable const uint8_t*                                          fDyldInfoExports;
 };
 
 
@@ -198,12 +237,12 @@ private:
 class UniversalMachOLayout
 {
 public:
-                                                                                               UniversalMachOLayout(const char* path, const std::set<cpu_type_t>* onlyArchs=NULL);
+                                                                                               UniversalMachOLayout(const char* path, const std::set<ArchPair>* onlyArchs=NULL);
                                                                                                ~UniversalMachOLayout() {}
 
-       static const UniversalMachOLayout*                      find(const char* path, const std::set<cpu_type_t>* onlyArchs=NULL);
-       const MachOLayoutAbstraction*                           getArch(cpu_type_t) const;
-       const std::vector<MachOLayoutAbstraction*>&     getArchs() const { return fLayouts; }
+       static const UniversalMachOLayout&                      find(const char* path, const std::set<ArchPair>* onlyArchs=NULL);
+       const MachOLayoutAbstraction*                           getSlice(ArchPair ap) const;
+       const std::vector<MachOLayoutAbstraction*>&     allLayouts() const { return fLayouts; }
 
 private:
        struct CStringEquals {
@@ -211,6 +250,8 @@ private:
        };
        typedef __gnu_cxx::hash_map<const char*, const UniversalMachOLayout*, __gnu_cxx::hash<const char*>, CStringEquals> PathToNode;
 
+       static bool                                     requestedSlice(const std::set<ArchPair>* onlyArchs, cpu_type_t cpuType, cpu_subtype_t cpuSubType);
+
        static PathToNode                                                       fgLayoutCache;
        const char*                                                                     fPath;
        std::vector<MachOLayoutAbstraction*>            fLayouts;
@@ -219,23 +260,34 @@ private:
 UniversalMachOLayout::PathToNode UniversalMachOLayout::fgLayoutCache;
 
 
-const MachOLayoutAbstraction* UniversalMachOLayout::getArch(cpu_type_t arch) const
+
+
+const MachOLayoutAbstraction* UniversalMachOLayout::getSlice(ArchPair ap) const
 {
+       // use matching cputype and cpusubtype
        for(std::vector<MachOLayoutAbstraction*>::const_iterator it=fLayouts.begin(); it != fLayouts.end(); ++it) {
                const MachOLayoutAbstraction* layout = *it;
-               if ( layout->getArchitecture() == arch ) 
-                       return layout;
+               if ( layout->getArchPair().arch == ap.arch ) {
+            switch ( ap.arch ) {
+                case CPU_TYPE_ARM:
+                    if ( layout->getArchPair().subtype == ap.subtype ) 
+                        return layout;
+                    break;
+                default:
+                    return layout;
+            }
+        }
        }
        return NULL;
 }
 
-const UniversalMachOLayout* UniversalMachOLayout::find(const char* path, const std::set<cpu_type_t>* onlyArchs)
+
+const UniversalMachOLayout& UniversalMachOLayout::find(const char* path, const std::set<ArchPair>* onlyArchs)
 {
        // look in cache
        PathToNode::iterator pos = fgLayoutCache.find(path);
        if ( pos != fgLayoutCache.end() )
-               return pos->second;
+               return *pos->second;
                
        // create UniversalMachOLayout
        const UniversalMachOLayout* result = new UniversalMachOLayout(path, onlyArchs);
@@ -243,17 +295,44 @@ const UniversalMachOLayout* UniversalMachOLayout::find(const char* path, const s
        // add it to cache
        fgLayoutCache[result->fPath] = result;
        
-       return result;
+       return *result;
 }
 
 
-UniversalMachOLayout::UniversalMachOLayout(const char* path, const std::set<cpu_type_t>* onlyArchs)
+bool UniversalMachOLayout::requestedSlice(const std::set<ArchPair>* onlyArchs, cpu_type_t cpuType, cpu_subtype_t cpuSubType)
+{
+       if ( onlyArchs == NULL )
+               return true;
+       // must match cputype and cpusubtype
+       for (std::set<ArchPair>::const_iterator it = onlyArchs->begin(); it != onlyArchs->end(); ++it) {
+               ArchPair anArch = *it;
+               if ( cpuType == anArch.arch ) {
+            switch ( cpuType ) {
+                case CPU_TYPE_ARM:
+                    if ( cpuSubType == anArch.subtype ) 
+                        return true;
+                    break;
+                default:
+                    return true;
+            }
+        }
+       }
+       return false;
+}
+
+
+UniversalMachOLayout::UniversalMachOLayout(const char* path, const std::set<ArchPair>* onlyArchs)
  : fPath(strdup(path))
 {
        // map in whole file
        int fd = ::open(path, O_RDONLY, 0);
-       if ( fd == -1 )
-               throwf("can't open file, errno=%d", errno);
+       if ( fd == -1 ) {
+               int err = errno;
+               if  ( err == ENOENT )
+                       throwf("file not found");
+               else
+                       throwf("can't open file, errno=%d", err);
+       }
        struct stat stat_buf;
        if ( fstat(fd, &stat_buf) == -1)
                throwf("can't stat open file %s, errno=%d", path, errno);
@@ -270,52 +349,53 @@ UniversalMachOLayout::UniversalMachOLayout(const char* path, const std::set<cpu_
                const mach_header* mh = (mach_header*)p;
                if ( fh->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) {
                        // Fat header is always big-endian
-                       const struct fat_arch* archs = (struct fat_arch*)(p + sizeof(struct fat_header));
-                       for (unsigned long i=0; i < OSSwapBigToHostInt32(fh->nfat_arch); ++i) {
-                               uint32_t fileOffset = OSSwapBigToHostInt32(archs[i].offset);
-                               cpu_type_t curArch =  OSSwapBigToHostInt32(archs[i].cputype);
-                               try {
-                                       if ( (onlyArchs == NULL) || (onlyArchs->count(curArch) != 0) ) {
-                                               switch ( curArch ) {
-                                                       case CPU_TYPE_POWERPC:
-                                                               fLayouts.push_back(new MachOLayout<ppc>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime));
-                                                               break;
-                                                       case CPU_TYPE_POWERPC64:
-                                                               fLayouts.push_back(new MachOLayout<ppc64>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime));
-                                                               break;
+                       const struct fat_arch* slices = (struct fat_arch*)(p + sizeof(struct fat_header));
+                       const uint32_t sliceCount = OSSwapBigToHostInt32(fh->nfat_arch);
+                       for (uint32_t i=0; i < sliceCount; ++i) {
+                               if ( requestedSlice(onlyArchs, OSSwapBigToHostInt32(slices[i].cputype), OSSwapBigToHostInt32(slices[i].cpusubtype)) ) {
+                                       uint32_t fileOffset = OSSwapBigToHostInt32(slices[i].offset);
+                                       if ( fileOffset > stat_buf.st_size ) {
+                                               throwf("malformed universal file, slice %u for architecture 0x%08X is beyond end of file: %s", 
+                                                               i, OSSwapBigToHostInt32(slices[i].cputype), path);
+                                       }
+                                       if ( (fileOffset+OSSwapBigToHostInt32(slices[i].size)) > stat_buf.st_size ) {
+                                               throwf("malformed universal file, slice %u for architecture 0x%08X is beyond end of file: %s", 
+                                                               i, OSSwapBigToHostInt32(slices[i].cputype), path);
+                                       }
+                                       try {
+                                               switch ( OSSwapBigToHostInt32(slices[i].cputype) ) {
                                                        case CPU_TYPE_I386:
-                                                               fLayouts.push_back(new MachOLayout<x86>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime));
+                                                               fLayouts.push_back(new MachOLayout<x86>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
                                                                break;
                                                        case CPU_TYPE_X86_64:
-                                                               fLayouts.push_back(new MachOLayout<x86_64>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime));
+                                                               fLayouts.push_back(new MachOLayout<x86_64>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
+                                                               break;
+                                                       case CPU_TYPE_ARM:
+                                                               fLayouts.push_back(new MachOLayout<arm>(&p[fileOffset], fileOffset, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
                                                                break;
                                                        default:
-                                                               throw "unknown file format";
+                                                               throw "unknown slice in fat file";
                                                }
                                        }
-                               }
-                               catch (const char* msg) {
-                                       fprintf(stderr, "warning: %s for %s\n", msg, path);
+                                       catch (const char* msg) {
+                                               fprintf(stderr, "warning: %s for %s\n", msg, path);
+                                       }
                                }
                        }
                }
                else {
                        try {
-                               if ( (OSSwapBigToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapBigToHostInt32(mh->cputype) == CPU_TYPE_POWERPC)) {
-                                       if ( (onlyArchs == NULL) || (onlyArchs->count(CPU_TYPE_POWERPC) != 0) ) 
-                                               fLayouts.push_back(new MachOLayout<ppc>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime));
-                               }
-                               else if ( (OSSwapBigToHostInt32(mh->magic) == MH_MAGIC_64) && (OSSwapBigToHostInt32(mh->cputype) == CPU_TYPE_POWERPC64)) {
-                                       if ( (onlyArchs == NULL) || (onlyArchs->count(CPU_TYPE_POWERPC64) != 0) ) 
-                                               fLayouts.push_back(new MachOLayout<ppc64>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime));
-                               }
-                               else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_I386)) {
-                                       if ( (onlyArchs == NULL) || (onlyArchs->count(CPU_TYPE_I386) != 0) ) 
-                                               fLayouts.push_back(new MachOLayout<x86>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime));
+if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_I386)) {
+                                       if ( requestedSlice(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) ) 
+                                               fLayouts.push_back(new MachOLayout<x86>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
                                }
                                else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC_64) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_X86_64)) {
-                                       if ( (onlyArchs == NULL) || (onlyArchs->count(CPU_TYPE_X86_64) != 0) ) 
-                                               fLayouts.push_back(new MachOLayout<x86_64>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime));
+                                       if ( requestedSlice(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) ) 
+                                               fLayouts.push_back(new MachOLayout<x86_64>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
+                               }
+                               else if ( (OSSwapLittleToHostInt32(mh->magic) == MH_MAGIC) && (OSSwapLittleToHostInt32(mh->cputype) == CPU_TYPE_ARM)) {
+                                       if ( requestedSlice(onlyArchs, OSSwapLittleToHostInt32(mh->cputype), OSSwapLittleToHostInt32(mh->cpusubtype)) ) 
+                                               fLayouts.push_back(new MachOLayout<arm>(mh, 0, fPath, stat_buf.st_ino, stat_buf.st_mtime, stat_buf.st_uid));
                                }
                                else {
                                        throw "unknown file format";
@@ -333,20 +413,23 @@ UniversalMachOLayout::UniversalMachOLayout(const char* path, const std::set<cpu_
 }
 
 
-
 template <typename A>
-MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char* path, ino_t inode, time_t modTime)
- : fPath(path), fOffset(offset), fMTime(modTime), fInode(inode), fHasSplitSegInfo(false)
+MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char* path, ino_t inode, time_t modTime, uid_t uid)
+ : fPath(path), fOffset(offset), fArchPair(0,0), fMTime(modTime), fInode(inode), fHasSplitSegInfo(false), fRootOwned(uid==0),
+   fShareableLocation(false), fDynamicLookupLinkage(false), fMainExecutableLookupLinkage(false), fIsDylib(false), 
+       fHasDyldInfo(false), fDyldInfoExports(NULL)
 {
        fDylibID.name = NULL;
        fDylibID.currentVersion = 0;
        fDylibID.compatibilityVersion = 0;
-       
+
        const macho_header<P>* mh = (const macho_header<P>*)machHeader;
-       if ( mh->cputype() != getArchitecture() )
-               throw "wrong architecture";
+       if ( mh->cputype() != arch() )
+               throw "Layout object is wrong architecture";
        switch ( mh->filetype() ) {
                case MH_DYLIB:
+                       fIsDylib = true;
+                       break;
                case MH_BUNDLE:
                case MH_EXECUTE:
                case MH_DYLIB_STUB:
@@ -357,7 +440,12 @@ MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char*
        }
        fFlags = mh->flags();
        fFileType = mh->filetype();
+       fArchPair.arch = mh->cputype();
+       fArchPair.subtype = mh->cpusubtype();
        
+       const macho_dyld_info_command<P>* dyldInfo = NULL;
+       const macho_symtab_command<P>* symbolTableCmd = NULL;
+       const macho_dysymtab_command<P>* dynamicSymbolTableCmd = NULL;
        const macho_load_command<P>* const cmds = (macho_load_command<P>*)((uint8_t*)mh + sizeof(macho_header<P>));
        const uint32_t cmd_count = mh->ncmds();
        const macho_load_command<P>* cmd = cmds;
@@ -370,17 +458,20 @@ MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char*
                                        fDylibID.currentVersion = dylib->current_version();
                                        fDylibID.compatibilityVersion = dylib->compatibility_version();
                                        fNameFileOffset = dylib->name() - (char*)machHeader;
+                                       fShareableLocation = ( (strncmp(fDylibID.name, "/usr/lib/", 9) == 0) || (strncmp(fDylibID.name, "/System/Library/", 16) == 0) );
                                }
                                break;
                        case LC_LOAD_DYLIB:
                        case LC_LOAD_WEAK_DYLIB:
                        case LC_REEXPORT_DYLIB:
+                       case LC_LOAD_UPWARD_DYLIB:
                                {
                                        macho_dylib_command<P>* dylib = (macho_dylib_command<P>*)cmd;
                                        Library lib;
                                        lib.name = strdup(dylib->name());
                                        lib.currentVersion = dylib->current_version();
                                        lib.compatibilityVersion = dylib->compatibility_version();
+                                       lib.weakImport = ( cmd->cmd() == LC_LOAD_WEAK_DYLIB );
                                        fLibraries.push_back(lib);
                                }
                                break;
@@ -394,6 +485,17 @@ MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char*
                                                                segCmd->filesize(), segCmd->initprot(), segCmd->segname()));
                                }
                                break;
+                       case LC_SYMTAB:
+                               symbolTableCmd = (macho_symtab_command<P>*)cmd;
+                               break;
+                       case LC_DYSYMTAB:
+                               dynamicSymbolTableCmd = (macho_dysymtab_command<P>*)cmd;
+                               break;
+                       case LC_DYLD_INFO:
+                       case LC_DYLD_INFO_ONLY:
+                               fHasDyldInfo = true;
+                               dyldInfo = (struct macho_dyld_info_command<P>*)cmd;
+                               break;
                }
                cmd = (const macho_load_command<P>*)(((uint8_t*)cmd)+cmd->cmdsize());
        }
@@ -427,25 +529,46 @@ MachOLayout<A>::MachOLayout(const void* machHeader, uint64_t offset, const char*
                        if ( (fLowReadOnlySegment == NULL) || (seg.address() < fLowReadOnlySegment->address()) )
                                fLowReadOnlySegment = &seg;
                        fVMReadOnlySize += seg.size();
-               }
+               }               
        }
        if ( (highSegment != NULL) && (fLowSegment != NULL) )
                fVMSize = (highSegment->address() + highSegment->size() - fLowSegment->address() + 4095) & (-4096);                     
+       
+       // scan undefines looking, for magic ordinals
+       if ( (symbolTableCmd != NULL) && (dynamicSymbolTableCmd != NULL) ) {
+               const macho_nlist<P>* symbolTable = (macho_nlist<P>*)((uint8_t*)machHeader + symbolTableCmd->symoff());
+               const uint32_t startUndefs = dynamicSymbolTableCmd->iundefsym();
+               const uint32_t endUndefs = startUndefs + dynamicSymbolTableCmd->nundefsym();
+               for (uint32_t i=startUndefs; i < endUndefs; ++i) {
+                       uint8_t ordinal = GET_LIBRARY_ORDINAL(symbolTable[i].n_desc());
+                       if ( ordinal == DYNAMIC_LOOKUP_ORDINAL )
+                               fDynamicLookupLinkage = true;
+                       else if ( ordinal == EXECUTABLE_ORDINAL )
+                               fMainExecutableLookupLinkage = true;
+               }
+       }
+       
+       if ( dyldInfo != NULL ) {
+               if ( dyldInfo->export_off() != 0 ) {
+                       fDyldInfoExports = (uint8_t*)machHeader + dyldInfo->export_off();
+               }
+       }
+
 }
 
-template <> cpu_type_t MachOLayout<ppc>::getArchitecture()    const { return CPU_TYPE_POWERPC; }
-template <> cpu_type_t MachOLayout<ppc64>::getArchitecture()  const { return CPU_TYPE_POWERPC64; }
-template <> cpu_type_t MachOLayout<x86>::getArchitecture()    const { return CPU_TYPE_I386; }
-template <> cpu_type_t MachOLayout<x86_64>::getArchitecture() const { return CPU_TYPE_X86_64; }
+template <> cpu_type_t MachOLayout<x86>::arch()     { return CPU_TYPE_I386; }
+template <> cpu_type_t MachOLayout<x86_64>::arch()  { return CPU_TYPE_X86_64; }
+template <> cpu_type_t MachOLayout<arm>::arch()                { return CPU_TYPE_ARM; }
+
 
 template <>
-bool MachOLayout<ppc>::isSplitSeg() const
+bool MachOLayout<x86>::isSplitSeg() const
 {
        return ( (this->getFlags() & MH_SPLIT_SEGS) != 0 );
 }
 
 template <>
-bool MachOLayout<x86>::isSplitSeg() const
+bool MachOLayout<arm>::isSplitSeg() const
 {
        return ( (this->getFlags() & MH_SPLIT_SEGS) != 0 );
 }