]> git.saurik.com Git - apple/ld64.git/blobdiff - src/other/dyldinfo.cpp
ld64-409.12.tar.gz
[apple/ld64.git] / src / other / dyldinfo.cpp
index 2c86577133aaa4d0f3dab601eb9e4f261574433f..45fcb0f508bf6876323a5168fc397b28963a5f3f 100644 (file)
 #include <errno.h>
 
 #include <vector>
+#include <tuple>
 #include <set>
-#include <ext/hash_set>
+#include <unordered_set>
 
+#include "configure.h"
 #include "MachOFileAbstraction.hpp"
 #include "Architectures.hpp"
 #include "MachOTrie.hpp"
+#include "../ld/code-sign-blobs/superblob.h"
 
 static bool printRebase = false;
 static bool printBind = false;
@@ -50,6 +53,8 @@ static bool printExportNodes = false;
 static bool printSharedRegion = false;
 static bool printFunctionStarts = false;
 static bool printDylibs = false;
+static bool printDRs = false;
+static bool printDataCode = false;
 static cpu_type_t      sPreferredArch = 0;
 static cpu_type_t      sPreferredSubArch = 0;
 
@@ -83,14 +88,6 @@ private:
        typedef typename A::P::E                                E;
        typedef typename A::P::uint_t                   pint_t;
        
-       class CStringEquals
-       {
-       public:
-               bool operator()(const char* left, const char* right) const { return (strcmp(left, right) == 0); }
-       };
-
-       typedef __gnu_cxx::hash_set<const char*, __gnu_cxx::hash<const char*>, CStringEquals>  StringSet;
-
                                                                                                DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool printArch);
        void                                                                            printRebaseInfo();
        void                                                                            printRebaseInfoOpcodes();
@@ -108,10 +105,19 @@ private:
        void                                                                            printClassicLazyBindingInfo();
        void                                                                            printClassicBindingInfo();
        void                                                                            printSharedRegionInfo();
+       const char*                                                                     sharedRegionKindName(uint8_t kind);
        void                                                                            printFunctionStartsInfo();
        void                                                                            printDylibsInfo();
+       void                                                                            printDRInfo();
+       void                                                                            printDataInCode();
        void                                                                            printFunctionStartLine(uint64_t addr);
-       const uint8_t*                                                          printSharedRegionInfoForEachULEB128Address(const uint8_t* p, uint8_t kind);
+       const uint8_t*                                                          printSharedRegionV1InfoForEachULEB128Address(const uint8_t* p, const uint8_t* end, uint8_t kind);
+       const uint8_t*                                                          printSharedRegionV2InfoForEachULEB128Address(const uint8_t* p, const uint8_t* end);
+       const uint8_t*                                                          printSharedRegionV2InfoForEachULEB128AddressAndAdj(const uint8_t* p, const uint8_t* end);
+       const uint8_t*                                                          printSharedRegionV2SectionPair(const uint8_t* p, const uint8_t* end);
+       const uint8_t*                                                          printSharedRegionV2ToSectionOffset(const uint8_t* p, const uint8_t* end);
+       const uint8_t*                                                          printSharedRegionV2Kind(const uint8_t* p, const uint8_t* end);
+
        pint_t                                                                          relocBase();
        const char*                                                                     relocTypeName(uint8_t r_type);
        uint8_t                                                                         segmentIndexForAddress(pint_t addr);
@@ -131,6 +137,7 @@ private:
        const char*                                                                     classicOrdinalName(int libraryOrdinal);
        pint_t*                                                                         mappedAddressForVMAddress(pint_t vmaddress);
        const char*                                                                     symbolNameForAddress(uint64_t);
+       const char*                                                                     closestSymbolNameForAddress(uint64_t addr, uint64_t* offset, uint8_t sectIndex=0);
 
                
        const char*                                                                     fPath;
@@ -143,14 +150,18 @@ private:
        const macho_dyld_info_command<P>*                       fInfo;
        const macho_linkedit_data_command<P>*           fSharedRegionInfo;
        const macho_linkedit_data_command<P>*           fFunctionStartsInfo;
+       const macho_linkedit_data_command<P>*           fDataInCode;
+       const macho_linkedit_data_command<P>*           fDRInfo;
        uint64_t                                                                        fBaseAddress;
        const macho_dysymtab_command<P>*                        fDynamicSymbolTable;
        const macho_segment_command<P>*                         fFirstSegment;
        const macho_segment_command<P>*                         fFirstWritableSegment;
        bool                                                                            fWriteableSegmentWithAddrOver4G;
        std::vector<const macho_segment_command<P>*>fSegments;
+       std::vector<const macho_section<P>*>            fSections;
        std::vector<const char*>                                        fDylibs;
        std::vector<const macho_dylib_command<P>*>      fDylibLoadCommands;
+       macho_section<P>                                                        fMachHeaderPseudoSection;
 };
 
 
@@ -166,6 +177,7 @@ bool DyldInfoPrinter<ppc>::validFile(const uint8_t* fileContent)
        switch (header->filetype()) {
                case MH_EXECUTE:
                case MH_DYLIB:
+               case MH_DYLIB_STUB:
                case MH_BUNDLE:
                case MH_DYLINKER:
                        return true;
@@ -184,6 +196,7 @@ bool DyldInfoPrinter<ppc64>::validFile(const uint8_t* fileContent)
        switch (header->filetype()) {
                case MH_EXECUTE:
                case MH_DYLIB:
+               case MH_DYLIB_STUB:
                case MH_BUNDLE:
                case MH_DYLINKER:
                        return true;
@@ -202,6 +215,7 @@ bool DyldInfoPrinter<x86>::validFile(const uint8_t* fileContent)
        switch (header->filetype()) {
                case MH_EXECUTE:
                case MH_DYLIB:
+               case MH_DYLIB_STUB:
                case MH_BUNDLE:
                case MH_DYLINKER:
                        return true;
@@ -220,13 +234,16 @@ bool DyldInfoPrinter<x86_64>::validFile(const uint8_t* fileContent)
        switch (header->filetype()) {
                case MH_EXECUTE:
                case MH_DYLIB:
+               case MH_DYLIB_STUB:
                case MH_BUNDLE:
                case MH_DYLINKER:
+               case MH_KEXT_BUNDLE:
                        return true;
        }
        return false;
 }
 
+#if SUPPORT_ARCH_arm_any
 template <>
 bool DyldInfoPrinter<arm>::validFile(const uint8_t* fileContent)
 {      
@@ -238,18 +255,46 @@ bool DyldInfoPrinter<arm>::validFile(const uint8_t* fileContent)
        switch (header->filetype()) {
                case MH_EXECUTE:
                case MH_DYLIB:
+               case MH_DYLIB_STUB:
                case MH_BUNDLE:
                case MH_DYLINKER:
+               case MH_KEXT_BUNDLE:
                        return true;
        }
        return false;
 }
+#endif
+
+#if SUPPORT_ARCH_arm64
+template <>
+bool DyldInfoPrinter<arm64>::validFile(const uint8_t* fileContent)
+{      
+       const macho_header<P>* header = (const macho_header<P>*)fileContent;
+       if ( header->magic() != MH_MAGIC_64 )
+               return false;
+       if ( header->cputype() != CPU_TYPE_ARM64 )
+               return false;
+       switch (header->filetype()) {
+               case MH_EXECUTE:
+               case MH_DYLIB:
+               case MH_DYLIB_STUB:
+               case MH_BUNDLE:
+               case MH_DYLINKER:
+               case MH_KEXT_BUNDLE:
+                       return true;
+               default:
+                       return false;
+       }
+       return false;
+}
+#endif
+
 
 template <typename A>
 DyldInfoPrinter<A>::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool printArch)
  : fHeader(NULL), fLength(fileLength), 
    fStrings(NULL), fStringsEnd(NULL), fSymbols(NULL), fSymbolCount(0), fInfo(NULL), 
-   fSharedRegionInfo(NULL), fFunctionStartsInfo(NULL), 
+   fSharedRegionInfo(NULL), fFunctionStartsInfo(NULL), fDataInCode(NULL), fDRInfo(NULL), 
    fBaseAddress(0), fDynamicSymbolTable(NULL), fFirstSegment(NULL), fFirstWritableSegment(NULL),
    fWriteableSegmentWithAddrOver4G(false)
 {
@@ -259,7 +304,12 @@ DyldInfoPrinter<A>::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLen
 
        fPath = strdup(path);
        fHeader = (const macho_header<P>*)fileContent;
-       
+
+       fMachHeaderPseudoSection.set_segname("__TEXT");
+       fMachHeaderPseudoSection.set_sectname("");
+       fMachHeaderPseudoSection.set_addr(0);
+       fSections.push_back(&fMachHeaderPseudoSection);
+
        // get LC_DYLD_INFO
        const uint8_t* const endOfFile = (uint8_t*)fHeader + fLength;
        const uint8_t* const endOfLoadCommands = (uint8_t*)fHeader + sizeof(macho_header<P>) + fHeader->sizeofcmds();
@@ -291,6 +341,10 @@ DyldInfoPrinter<A>::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLen
                                        if ( segCmd->vmaddr() > 0x100000000ULL )
                                                fWriteableSegmentWithAddrOver4G = true;
                                }
+                               const macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
+                               const macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
+                               for(const macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect)
+                                       fSections.push_back(sect);
                                }
                                break;
                        case LC_LOAD_DYLIB:
@@ -332,32 +386,26 @@ DyldInfoPrinter<A>::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLen
                        case LC_FUNCTION_STARTS:
                                fFunctionStartsInfo = (macho_linkedit_data_command<P>*)cmd;
                                break;
+                       case LC_DATA_IN_CODE:
+                               fDataInCode = (macho_linkedit_data_command<P>*)cmd;
+                               break;
+                       case LC_DYLIB_CODE_SIGN_DRS:
+                               fDRInfo = (macho_linkedit_data_command<P>*)cmd;
+                               break;
                }
                cmd = (const macho_load_command<P>*)endOfCmd;
        }
        
        if ( printArch ) {
-               switch ( fHeader->cputype() ) {
-                       case CPU_TYPE_I386:
-                               printf("for arch i386:\n");
-                               break;
-                       case CPU_TYPE_X86_64:
-                               printf("for arch x86_64:\n");
-                               break;
-                       case CPU_TYPE_POWERPC:                  
-                               printf("for arch ppc:\n");
-                               break;
-                       case CPU_TYPE_ARM:
-                               for (const ARMSubType* t=ARMSubTypes; t->subTypeName != NULL; ++t) {
-                                       if ( (cpu_subtype_t)fHeader->cpusubtype() == t->subType) {
-                                               printf("for arch %s:\n", t->subTypeName);
-                                               break;
-                                       }
-                               }
+               for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+                       if ( (cpu_type_t)fHeader->cputype() == t->cpuType ) {
+                               if ( t->isSubType && ((cpu_subtype_t)fHeader->cpusubtype() != t->cpuSubType) )
+                                       continue;
+                               printf("for arch %s:\n", t->archName);
+                       }
                }
        }
        
-       
        if ( printRebase ) {
                if ( fInfo != NULL )
                        printRebaseInfo();
@@ -400,6 +448,10 @@ DyldInfoPrinter<A>::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLen
                printFunctionStartsInfo();
        if ( printDylibs )
                printDylibsInfo();
+       if ( printDRs )
+               printDRInfo();
+       if ( printDataCode )
+               printDataInCode();
 }
 
 static uint64_t read_uleb128(const uint8_t*& p, const uint8_t* end)
@@ -432,7 +484,7 @@ static int64_t read_sleb128(const uint8_t*& p, const uint8_t* end)
                if (p == end)
                        throwf("malformed sleb128");
                byte = *p++;
-               result |= ((byte & 0x7f) << bit);
+               result |= (((int64_t)(byte & 0x7f)) << bit);
                bit += 7;
        } while (byte & 0x80);
        // sign extend negative numbers
@@ -564,6 +616,8 @@ const char* DyldInfoPrinter<A>::ordinalName(int libraryOrdinal)
                        return "main-executable";
                case BIND_SPECIAL_DYLIB_FLAT_LOOKUP:
                        return "flat-namespace";
+               case BIND_SPECIAL_DYLIB_WEAK_LOOKUP:
+                       return "weak";
        }
        if ( libraryOrdinal < BIND_SPECIAL_DYLIB_FLAT_LOOKUP )
                throw "unknown special ordinal";
@@ -593,12 +647,164 @@ const char* DyldInfoPrinter<A>::classicOrdinalName(int libraryOrdinal)
 template <typename A>
 void DyldInfoPrinter<A>::printRebaseInfo()
 {
+       bool seenThreadedRebase = false;
        if ( (fInfo == NULL) || (fInfo->rebase_off() == 0) ) {
-               printf("no compressed rebase info\n");
+               // If we have no rebase opcodes, then we may be using the threaded rebase/bind combined
+               // format and need to parse the bind opcodes instead.
+               if ( (fInfo->rebase_size() == 0) && (fInfo->bind_size() != 0) ) {
+                       const uint8_t* p = (uint8_t*)fHeader + fInfo->bind_off();
+                       const uint8_t* end = &p[fInfo->bind_size()];
+
+                       uint8_t type = 0;
+                       uint8_t flags = 0;
+                       uint8_t segIndex = 0;
+                       uint64_t segOffset = 0;
+                       const char* symbolName = NULL;
+                       const char* fromDylib = "??";
+                       int libraryOrdinal = 0;
+                       int64_t addend = 0;
+                       uint32_t count;
+                       uint32_t skip;
+                       pint_t segStartAddr = 0;
+                       const char* segName = "??";
+                       const char* typeName = "??";
+                       const char* weak_import = "";
+                       bool done = false;
+                       while ( !done && (p < end) ) {
+                               uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
+                               uint8_t opcode = *p & BIND_OPCODE_MASK;
+                               ++p;
+                               switch (opcode) {
+                                       case BIND_OPCODE_DONE:
+                                               done = true;
+                                               break;
+                                       case BIND_OPCODE_SET_DYLIB_ORDINAL_IMM:
+                                               libraryOrdinal = immediate;
+                                               fromDylib = ordinalName(libraryOrdinal);
+                                               break;
+                                       case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
+                                               libraryOrdinal = read_uleb128(p, end);
+                                               fromDylib = ordinalName(libraryOrdinal);
+                                               break;
+                                       case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
+                                               // the special ordinals are negative numbers
+                                               if ( immediate == 0 )
+                                                       libraryOrdinal = 0;
+                                               else {
+                                                       int8_t signExtended = BIND_OPCODE_MASK | immediate;
+                                                       libraryOrdinal = signExtended;
+                                               }
+                                               fromDylib = ordinalName(libraryOrdinal);
+                                               break;
+                                       case BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+                                               symbolName = (char*)p;
+                                               while (*p != '\0')
+                                                       ++p;
+                                               ++p;
+                                               flags = immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT;
+                                               if ( flags != 0 )
+                                                       weak_import = " (weak import)";
+                                               else
+                                                       weak_import = "";
+                                               break;
+                                       case BIND_OPCODE_SET_TYPE_IMM:
+                                               type = immediate;
+                                               typeName = bindTypeName(type);
+                                               break;
+                                       case BIND_OPCODE_SET_ADDEND_SLEB:
+                                               addend = read_sleb128(p, end);
+                                               break;
+                                       case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+                                               segIndex = immediate;
+                                               segStartAddr = segStartAddress(segIndex);
+                                               segName = segmentName(segIndex);
+                                               segOffset = read_uleb128(p, end);
+                                               break;
+                                       case BIND_OPCODE_ADD_ADDR_ULEB:
+                                               segOffset += read_uleb128(p, end);
+                                               break;
+                                       case BIND_OPCODE_DO_BIND:
+                                               break;
+                                       case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
+                                               segOffset += read_uleb128(p, end) + sizeof(pint_t);
+                                               break;
+                                       case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
+                                               segOffset += immediate*sizeof(pint_t) + sizeof(pint_t);
+                                               break;
+                                       case BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB:
+                                               count = read_uleb128(p, end);
+                                               skip = read_uleb128(p, end);
+                                               for (uint32_t i=0; i < count; ++i) {
+                                                       segOffset += skip + sizeof(pint_t);
+                                               }
+                                               break;
+                                       case BIND_OPCODE_THREADED:
+                                               // Note the immediate is a sub opcode
+                                               switch (immediate) {
+                                                       case BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB:
+                                                               printf("rebase information (from compressed dyld info):\n");
+                                                               printf("segment section          address     type         value\n");
+                                                               count = read_uleb128(p, end);
+                                                               seenThreadedRebase = true;
+                                                               break;
+                                                       case BIND_SUBOPCODE_THREADED_APPLY: {
+                                                               uint64_t delta = 0;
+                                                               do {
+                                                                       const uint8_t* pointerLocation = (uint8_t*)fHeader + fSegments[segIndex]->fileoff() + segOffset;
+                                                                       uint64_t value = P::getP(*(uint64_t*)pointerLocation);
+#if SUPPORT_ARCH_arm64e
+                                                                       uint16_t diversity = (uint16_t)(value >> 32);
+                                                                       bool hasAddressDiversity = (value & (1ULL << 48)) != 0;
+                                                                       ptrauth_key key = (ptrauth_key)((value >> 49) & 0x3);
+                                                                       bool isAuthenticated = (value & (1ULL << 63)) != 0;
+#endif
+                                                                       bool isRebase = (value & (1ULL << 62)) == 0;
+                                                                       if (isRebase) {
+
+#if SUPPORT_ARCH_arm64e
+                                                                               static const char* keyNames[] = {
+                                                                                       "IA", "IB", "DA", "DB"
+                                                                               };
+                                                                               if (isAuthenticated) {
+                                                                                       uint64_t targetValue = value & 0xFFFFFFFFULL;
+                                                                                       targetValue += fBaseAddress;
+                                                                                       printf("%-7s %-16s 0x%08llX  %s  0x%08llX (JOP: diversity %d, address %s, %s)\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, targetValue, diversity, hasAddressDiversity ? "true" : "false", keyNames[key]);
+                                                                               } else
+#endif
+                                                                               {
+                                                                                       // Regular pointer which needs to fit in 51-bits of value.
+                                                                                       // C++ RTTI uses the top bit, so we'll allow the whole top-byte
+                                                                                       // and the signed-extended bottom 43-bits to be fit in to 51-bits.
+                                                                                       uint64_t top8Bits = value & 0x0007F80000000000ULL;
+                                                                                       uint64_t bottom43Bits = value & 0x000007FFFFFFFFFFULL;
+                                                                                       uint64_t targetValue = ( top8Bits << 13 ) | (((intptr_t)(bottom43Bits << 21) >> 21) & 0x00FFFFFFFFFFFFFF);
+                                                                                       printf("%-7s %-16s 0x%08llX  %s  0x%08llX\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, targetValue);
+                                                                               }
+                                                                       }
+                                                                       // The delta is bits [51..61]
+                                                                       // And bit 62 is to tell us if we are a rebase (0) or bind (1)
+                                                                       value &= ~(1ULL << 62);
+                                                                       delta = ( value & 0x3FF8000000000000 ) >> 51;
+                                                                       segOffset += delta * sizeof(pint_t);
+                                                               } while ( delta != 0);
+                                                               break;
+                                                       }
+                                                       default:
+                                                               throwf("unknown threaded bind subopcode %d", immediate);
+                                               }
+                                               break;
+                                       default:
+                                               throwf("bad bind opcode %d", *p);
+                               }
+                       }
+               }
+
+               if (!seenThreadedRebase)
+                       printf("no compressed rebase info\n");
        }
        else {
                printf("rebase information (from compressed dyld info):\n");
-               printf("segment section          address     type\n");
+               printf("segment section          address     type         value\n");
 
                const uint8_t* p = (uint8_t*)fHeader + fInfo->rebase_off();
                const uint8_t* end = &p[fInfo->rebase_size()];
@@ -607,10 +813,12 @@ void DyldInfoPrinter<A>::printRebaseInfo()
                uint64_t segOffset = 0;
                uint32_t count;
                uint32_t skip;
-               int segIndex;
+               int segIndex = 0;
                pint_t segStartAddr = 0;
                const char* segName = "??";
                const char* typeName = "??";
+               const uint8_t* pointerLocation = nullptr;
+               uint64_t value = 0;
                bool done = false;
                while ( !done && (p < end) ) {
                        uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
@@ -638,35 +846,42 @@ void DyldInfoPrinter<A>::printRebaseInfo()
                                        break;
                                case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
                                        for (int i=0; i < immediate; ++i) {
-                                               printf("%-7s %-16s 0x%08llX  %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+                                               pointerLocation = (uint8_t*)fHeader + fSegments[segIndex]->fileoff() + segOffset;
+                                               value = P::getP(*(uint64_t*)pointerLocation);
+                                               printf("%-7s %-16s 0x%08llX  %s  0x%08llX\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, value);
                                                segOffset += sizeof(pint_t);
                                        }
                                        break;
                                case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
                                        count = read_uleb128(p, end);
                                        for (uint32_t i=0; i < count; ++i) {
-                                               printf("%-7s %-16s 0x%08llX  %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+                                               pointerLocation = (uint8_t*)fHeader + fSegments[segIndex]->fileoff() + segOffset;
+                                               value = P::getP(*(uint64_t*)pointerLocation);
+                                               printf("%-7s %-16s 0x%08llX  %s  0x%08llX\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, value);
                                                segOffset += sizeof(pint_t);
                                        }
                                        break;
                                case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
-                                       printf("%-7s %-16s 0x%08llX  %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+                                       pointerLocation = (uint8_t*)fHeader + fSegments[segIndex]->fileoff() + segOffset;
+                                       value = P::getP(*(uint64_t*)pointerLocation);
+                                       printf("%-7s %-16s 0x%08llX  %s  0x%08llX\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, value);
                                        segOffset += read_uleb128(p, end) + sizeof(pint_t);
                                        break;
                                case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
                                        count = read_uleb128(p, end);
                                        skip = read_uleb128(p, end);
                                        for (uint32_t i=0; i < count; ++i) {
-                                               printf("%-7s %-16s 0x%08llX  %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+                                               pointerLocation = (uint8_t*)fHeader + fSegments[segIndex]->fileoff() + segOffset;
+                                               value = P::getP(*(uint64_t*)pointerLocation);
+                                               printf("%-7s %-16s 0x%08llX  %s  0x%08llX\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, value);
                                                segOffset += skip + sizeof(pint_t);
                                        }
                                        break;
                                default:
                                        throwf("bad rebase opcode %d", *p);
                        }
-               }       
+               }
        }
-
 }
 
 
@@ -679,9 +894,10 @@ void DyldInfoPrinter<A>::printRebaseInfoOpcodes()
        }
        else {
                printf("rebase opcodes:\n");
-               const uint8_t* p = (uint8_t*)fHeader + fInfo->rebase_off();
-               const uint8_t* end = &p[fInfo->rebase_size()];
-               
+               const uint8_t* start = (uint8_t*)fHeader + fInfo->rebase_off();
+               const uint8_t* end = &start[fInfo->rebase_size()];
+               const uint8_t* p = start;
+
                uint8_t type = 0;
                uint64_t address = fBaseAddress;
                uint32_t count;
@@ -691,44 +907,45 @@ void DyldInfoPrinter<A>::printRebaseInfoOpcodes()
                while ( !done && (p < end) ) {
                        uint8_t immediate = *p & REBASE_IMMEDIATE_MASK;
                        uint8_t opcode = *p & REBASE_OPCODE_MASK;
+                       uint32_t opcodeOffset = p-start;
                        ++p;
                        switch (opcode) {
                                case REBASE_OPCODE_DONE:
                                        done = true;
-                                       printf("REBASE_OPCODE_DONE()\n");
+                                       printf("0x%04X REBASE_OPCODE_DONE()\n", opcodeOffset);
                                        break;
                                case REBASE_OPCODE_SET_TYPE_IMM:
                                        type = immediate;
-                                       printf("REBASE_OPCODE_SET_TYPE_IMM(%d)\n", type);
+                                       printf("0x%04X REBASE_OPCODE_SET_TYPE_IMM(%d)\n", opcodeOffset, type);
                                        break;
                                case REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
                                        segmentIndex = immediate;
                                        address = read_uleb128(p, end);
-                                       printf("REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%d, 0x%08llX)\n", segmentIndex, address);
+                                       printf("0x%04X REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(%d, 0x%08llX)\n", opcodeOffset, segmentIndex, address);
                                        break;
                                case REBASE_OPCODE_ADD_ADDR_ULEB:
                                        address = read_uleb128(p, end);
-                                       printf("REBASE_OPCODE_ADD_ADDR_ULEB(0x%0llX)\n", address);
+                                       printf("0x%04X REBASE_OPCODE_ADD_ADDR_ULEB(0x%0llX)\n", opcodeOffset, address);
                                        break;
                                case REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
                                        address = immediate*sizeof(pint_t);
-                                       printf("REBASE_OPCODE_ADD_ADDR_IMM_SCALED(0x%0llX)\n", address);
+                                       printf("0x%04X REBASE_OPCODE_ADD_ADDR_IMM_SCALED(0x%0llX)\n", opcodeOffset, address);
                                        break;
                                case REBASE_OPCODE_DO_REBASE_IMM_TIMES:
-                                       printf("REBASE_OPCODE_DO_REBASE_IMM_TIMES(%d)\n", immediate);
+                                       printf("0x%04X REBASE_OPCODE_DO_REBASE_IMM_TIMES(%d)\n", opcodeOffset, immediate);
                                        break;
                                case REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
                                        count = read_uleb128(p, end);
-                                       printf("REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%d)\n", count);
+                                       printf("0x%04X REBASE_OPCODE_DO_REBASE_ULEB_TIMES(%d)\n", opcodeOffset, count);
                                        break;
                                case REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
                                        skip = read_uleb128(p, end) + sizeof(pint_t);
-                                       printf("REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(%d)\n", skip);
+                                       printf("0x%04X REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB(%d)\n", opcodeOffset, skip);
                                        break;
                                case REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
                                        count = read_uleb128(p, end);
                                        skip = read_uleb128(p, end);
-                                       printf("REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%d, %d)\n", count, skip);
+                                       printf("0x%04X REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB(%d, %d)\n", opcodeOffset, count, skip);
                                        break;
                                default:
                                        throwf("bad rebase opcode %d", *p);
@@ -738,11 +955,6 @@ void DyldInfoPrinter<A>::printRebaseInfoOpcodes()
 
 }
 
-
-
-
-
-
 template <typename A>
 void DyldInfoPrinter<A>::printBindingInfoOpcodes(bool weakbinding)
 {
@@ -848,6 +1060,20 @@ void DyldInfoPrinter<A>::printBindingInfoOpcodes(bool weakbinding)
                                        skip = read_uleb128(p, end);
                                        printf("0x%04X BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB(%d, 0x%08X)\n", opcodeOffset, count, skip);
                                        break;
+                               case BIND_OPCODE_THREADED:
+                                       // Note the immediate is a sub opcode
+                                       switch (immediate) {
+                                               case BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB:
+                                                       count = read_uleb128(p, end);
+                                                       printf("0x%04X BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB(%d)\n", opcodeOffset, count);
+                                                       break;
+                                               case BIND_SUBOPCODE_THREADED_APPLY:
+                                                       printf("0x%04X BIND_SUBOPCODE_THREADED_APPLY\n", opcodeOffset);
+                                                       break;
+                                               default:
+                                                       throwf("unknown threaded bind subopcode %d", immediate);
+                                       }
+                                       break;
                                default:
                                        throwf("unknown bind opcode %d", *p);
                        }
@@ -856,7 +1082,20 @@ void DyldInfoPrinter<A>::printBindingInfoOpcodes(bool weakbinding)
 
 }
 
+struct ThreadedBindData {
+       ThreadedBindData(const char* symbolName, int64_t addend, int libraryOrdinal, uint8_t flags, uint8_t type)
+               : symbolName(symbolName), addend(addend), libraryOrdinal(libraryOrdinal), flags(flags), type(type) { }
 
+       std::tuple<const char*, int64_t, int, uint8_t, uint8_t> pack() const {
+               return std::make_tuple(symbolName, addend, libraryOrdinal, flags, type);
+       }
+
+       const char* symbolName  = nullptr;
+       int64_t addend                  = 0;
+       int libraryOrdinal              = 0;
+       uint8_t flags                   = 0;
+       uint8_t type                    = 0;
+};
 
 template <typename A>
 void DyldInfoPrinter<A>::printBindingInfo()
@@ -869,8 +1108,9 @@ void DyldInfoPrinter<A>::printBindingInfo()
                printf("segment section          address        type    addend dylib            symbol\n");
                const uint8_t* p = (uint8_t*)fHeader + fInfo->bind_off();
                const uint8_t* end = &p[fInfo->bind_size()];
-               
+
                uint8_t type = 0;
+               uint8_t flags = 0;
                uint8_t segIndex = 0;
                uint64_t segOffset = 0;
                const char* symbolName = NULL;
@@ -883,6 +1123,8 @@ void DyldInfoPrinter<A>::printBindingInfo()
                const char* segName = "??";
                const char* typeName = "??";
                const char* weak_import = "";
+               std::vector<ThreadedBindData> ordinalTable;
+               bool useThreadedRebaseBind = false;
                bool done = false;
                while ( !done && (p < end) ) {
                        uint8_t immediate = *p & BIND_IMMEDIATE_MASK;
@@ -915,7 +1157,8 @@ void DyldInfoPrinter<A>::printBindingInfo()
                                        while (*p != '\0')
                                                ++p;
                                        ++p;
-                                       if ( (immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 )
+                                       flags = immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT;
+                                       if ( flags != 0 )
                                                weak_import = " (weak import)";
                                        else
                                                weak_import = "";
@@ -937,8 +1180,12 @@ void DyldInfoPrinter<A>::printBindingInfo()
                                        segOffset += read_uleb128(p, end);
                                        break;
                                case BIND_OPCODE_DO_BIND:
-                                       printf("%-7s %-16s 0x%08llX %10s  %5lld %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import );
-                                       segOffset += sizeof(pint_t);
+                                       if (!useThreadedRebaseBind) {
+                                               printf("%-7s %-16s 0x%08llX %10s  %5lld %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import );
+                                               segOffset += sizeof(pint_t);
+                                       } else {
+                                               ordinalTable.push_back(ThreadedBindData(symbolName, addend, libraryOrdinal, flags, type));
+                                       }
                                        break;
                                case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
                                        printf("%-7s %-16s 0x%08llX %10s  %5lld %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import );
@@ -956,6 +1203,68 @@ void DyldInfoPrinter<A>::printBindingInfo()
                                                segOffset += skip + sizeof(pint_t);
                                        }
                                        break;
+                               case BIND_OPCODE_THREADED:
+                                       // Note the immediate is a sub opcode
+                                       switch (immediate) {
+                                               case BIND_SUBOPCODE_THREADED_SET_BIND_ORDINAL_TABLE_SIZE_ULEB:
+                                                       count = read_uleb128(p, end);
+                                                       ordinalTable.clear();
+                                                       ordinalTable.reserve(count);
+                                                       useThreadedRebaseBind = true;
+                                                       break;
+                                               case BIND_SUBOPCODE_THREADED_APPLY: {
+                                                       uint64_t delta = 0;
+                                                       do {
+                                                               const uint8_t* pointerLocation = (uint8_t*)fHeader + fSegments[segIndex]->fileoff() + segOffset;
+                                                               uint64_t value = P::getP(*(uint64_t*)pointerLocation);
+#if SUPPORT_ARCH_arm64e
+                                                               uint16_t diversity = (uint16_t)(value >> 32);
+                                                               bool hasAddressDiversity = (value & (1ULL << 48)) != 0;
+                                                               ptrauth_key key = (ptrauth_key)((value >> 49) & 0x3);
+                                                               bool isAuthenticated = (value & (1ULL << 63)) != 0;
+#endif
+                                                               bool isRebase = (value & (1ULL << 62)) == 0;
+
+                                                               if (isRebase) {
+                                                                       //printf("(rebase): %-7s %-16s 0x%08llX  %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName);
+                                                               } else {
+                                                                       // the ordinal is bits [0..15]
+                                                                       uint16_t ordinal = value & 0xFFFF;
+                                                                       if (ordinal >= ordinalTable.size()) {
+                                                                               fprintf(stderr, "bind ordinal is out of range\n");
+                                                                               break;
+                                                                       }
+                                                                       std::tie(symbolName, addend, libraryOrdinal, flags, type) = ordinalTable[ordinal].pack();
+                                                                       if ( (flags & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 )
+                                                                               weak_import = " (weak import)";
+                                                                       else
+                                                                               weak_import = "";
+                                                                       fromDylib = ordinalName(libraryOrdinal);
+#if SUPPORT_ARCH_arm64e
+                                                                       if (isAuthenticated) {
+                                                                               static const char* keyNames[] = {
+                                                                                       "IA", "IB", "DA", "DB"
+                                                                               };
+                                                                               printf("%-7s %-16s 0x%08llX %10s  %5lld %-16s %s%s with value 0x%016llX (JOP: diversity %d, address %s, %s)\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import, value, diversity, hasAddressDiversity ? "true" : "false", keyNames[key]);
+                                                                       } else
+#endif
+                                                                       {
+                                                                               printf("%-7s %-16s 0x%08llX %10s  %5lld %-16s %s%s with value 0x%016llX\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, addend, fromDylib, symbolName, weak_import, value );
+                                                                       }
+                                                               }
+
+                                                               // The delta is bits [51..61]
+                                                               // And bit 62 is to tell us if we are a rebase (0) or bind (1)
+                                                               value &= ~(1ULL << 62);
+                                                               delta = ( value & 0x3FF8000000000000 ) >> 51;
+                                                               segOffset += delta * sizeof(pint_t);
+                                                       } while ( delta != 0);
+                                                       break;
+                                               }
+                                               default:
+                                                       throwf("unknown threaded bind subopcode %d", immediate);
+                                       }
+                                       break;
                                default:
                                        throwf("bad bind opcode %d", *p);
                        }
@@ -1259,26 +1568,50 @@ void DyldInfoPrinter<A>::printExportInfo()
                parseTrie(start, end, list);
                //std::sort(list.begin(), list.end(), SortExportsByAddress());
                for (std::vector<mach_o::trie::Entry>::iterator it=list.begin(); it != list.end(); ++it) {
-                       if ( it->flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
-                               if ( it->importName[0] == '\0' )
-                                       fprintf(stdout, "[re-export] %s from dylib=%llu\n", it->name, it->other);
-                               else
-                                       fprintf(stdout, "[re-export] %s from dylib=%llu named=%s\n", it->name, it->other, it->importName);
-                       }
-                       else {
-                               const char* flags = "";
-                               if ( it->flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION )
-                                       flags = "[weak_def] ";
-                               else if ( (it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL )
-                                       flags = "[per-thread] ";
-                               if ( it->flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER ) {
-                                       flags = "[resolver] ";
-                                       fprintf(stdout, "0x%08llX  %s%s (resolver=0x%08llX)\n", fBaseAddress+it->address, flags, it->name, it->other);
+                       const bool reExport = (it->flags & EXPORT_SYMBOL_FLAGS_REEXPORT);
+                       const bool weakDef = (it->flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
+                       const bool threadLocal = ((it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL);
+                       const bool abs = ((it->flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
+                       const bool resolver = (it->flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
+                       if ( reExport )
+                               printf("[re-export] ");
+                       else
+                               printf("0x%08llX  ", fBaseAddress+it->address);
+                       printf("%s", it->name);
+                       if ( weakDef || threadLocal || resolver || abs ) {
+                               bool needComma = false;
+                               printf(" [");
+                               if ( weakDef ) {
+                                       printf("weak_def");
+                                       needComma = true;
                                }
-                               else {
-                                       fprintf(stdout, "0x%08llX  %s%s\n", fBaseAddress+it->address, flags, it->name);
+                               if ( threadLocal ) {
+                                       if ( needComma ) 
+                                               printf(", ");
+                                       printf("per-thread");
+                                       needComma = true;
+                               }
+                               if ( abs ) {
+                                       if ( needComma )
+                                               printf(", ");
+                                       printf("absolute");
+                                       needComma = true;
                                }
+                               if ( resolver ) {
+                                       if ( needComma ) 
+                                               printf(", ");
+                                       printf("resolver=0x%08llX", it->other);
+                                       needComma = true;
+                               }
+                               printf("]");
+                       }
+                       if ( reExport ) {
+                               if ( it->importName[0] == '\0' )
+                                       printf(" (from %s)", fDylibs[it->other - 1]);
+                               else
+                                       printf(" (%s from %s)", it->importName, fDylibs[it->other - 1]);
                        }
+                       printf("\n");
                }
        }
 }
@@ -1290,7 +1623,7 @@ void DyldInfoPrinter<A>::processExportGraphNode(const uint8_t* const start, cons
                                                                                        char* cummulativeString, int curStrOffset) 
 {
        const uint8_t* const me = p;
-       const uint8_t terminalSize = read_uleb128(p, end);
+       const uint64_t terminalSize = read_uleb128(p, end);
        const uint8_t* children = p + terminalSize;
        if ( terminalSize != 0 ) {
                uint32_t flags = read_uleb128(p, end);
@@ -1410,6 +1743,8 @@ void DyldInfoPrinter<A>::printExportInfoNodes()
                                                printf("[addr=0x%06llX] ", address);
                                        else if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL)
                                                printf("[flags=THREAD_LOCAL addr=0x%06llX] ", address);
+                                       else if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE)
+                                               printf("[flags=ABSOLUTE addr=0x%06llX] ", address);
                                        else
                                                printf("[flags=0x%llX addr=0x%06llX] ", flags, address);
                                }
@@ -1434,97 +1769,126 @@ void DyldInfoPrinter<A>::printExportInfoNodes()
 
 
 template <typename A>
-const uint8_t* DyldInfoPrinter<A>::printSharedRegionInfoForEachULEB128Address(const uint8_t* p, uint8_t kind)
+const uint8_t* DyldInfoPrinter<A>::printSharedRegionV1InfoForEachULEB128Address(const uint8_t* p, const uint8_t* end, uint8_t kind)
 {
        const char* kindStr =  "??";
-       switch (kind) {
-               case 1:
+       switch (kind ) {
+               case DYLD_CACHE_ADJ_V1_POINTER_32:
                        kindStr = "32-bit pointer";
                        break;
-               case 2:
+               case DYLD_CACHE_ADJ_V1_POINTER_64:
                        kindStr = "64-bit pointer";
                        break;
-               case 3:
-                       kindStr = "ppc hi16";
+               case DYLD_CACHE_ADJ_V1_ADRP:
+                       kindStr = "arm64 ADRP";
                        break;
-               case 4:
-                       kindStr = "32-bit offset to IMPORT";
-                       break;
-               case 5:
-                       kindStr = "thumb2 movw";
-                       break;
-               case 6:
-                       kindStr = "ARM movw";
-                       break;
-               case 0x10:
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+0:
                        kindStr = "thumb2 movt low high 4 bits=0";
                        break;
-               case 0x11:
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+1:
                        kindStr = "thumb2 movt low high 4 bits=1";
                        break;
-               case 0x12:
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+2:
                        kindStr = "thumb2 movt low high 4 bits=2";
                        break;
-               case 0x13:
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+3:
                        kindStr = "thumb2 movt low high 4 bits=3";
                        break;
-               case 0x14:
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+4:
                        kindStr = "thumb2 movt low high 4 bits=4";
                        break;
-               case 0x15:
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+5:
                        kindStr = "thumb2 movt low high 4 bits=5";
                        break;
-               case 0x16:
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+6:
                        kindStr = "thumb2 movt low high 4 bits=6";
                        break;
-               case 0x17:
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+7:
                        kindStr = "thumb2 movt low high 4 bits=7";
                        break;
-               case 0x18:
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+8:
                        kindStr = "thumb2 movt low high 4 bits=8";
                        break;
-               case 0x19:
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+9:
                        kindStr = "thumb2 movt low high 4 bits=9";
                        break;
-               case 0x1A:
-                       kindStr = "thumb2 movt low high 4 bits=0xA";
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+10:
+                       kindStr = "thumb2 movt low high 4 bits=10";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+11:
+                       kindStr = "thumb2 movt low high 4 bits=11";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+12:
+                       kindStr = "thumb2 movt low high 4 bits=12";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+13:
+                       kindStr = "thumb2 movt low high 4 bits=13";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+14:
+                       kindStr = "thumb2 movt low high 4 bits=14";
                        break;
-               case 0x1B:
-                       kindStr = "thumb2 movt low high 4 bits=0xB";
+               case DYLD_CACHE_ADJ_V1_ARM_THUMB_MOVT+15:
+                       kindStr = "thumb2 movt low high 4 bits=15";
                        break;
-               case 0x1C:
-                       kindStr = "thumb2 movt low high 4 bits=0xC";
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+0:
+                       kindStr = "arm movt low high 4 bits=0";
                        break;
-               case 0x1D:
-                       kindStr = "thumb2 movt low high 4 bits=0xD";
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+1:
+                       kindStr = "arm movt low high 4 bits=1";
                        break;
-               case 0x1E:
-                       kindStr = "thumb2 movt low high 4 bits=0xE";
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+2:
+                       kindStr = "arm movt low high 4 bits=2";
                        break;
-               case 0x1F:
-                       kindStr = "thumb2 movt low high 4 bits=0xF";
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+3:
+                       kindStr = "arm movt low high 4 bits=3";
                        break;
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+4:
+                       kindStr = "arm movt low high 4 bits=4";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+5:
+                       kindStr = "arm movt low high 4 bits=5";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+6:
+                       kindStr = "arm movt low high 4 bits=6";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+7:
+                       kindStr = "arm movt low high 4 bits=7";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+8:
+                       kindStr = "arm movt low high 4 bits=8";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+9:
+                       kindStr = "arm movt low high 4 bits=9";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+10:
+                       kindStr = "arm movt low high 4 bits=10";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+11:
+                       kindStr = "arm movt low high 4 bits=11";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+12:
+                       kindStr = "arm movt low high 4 bits=12";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+13:
+                       kindStr = "arm movt low high 4 bits=13";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+14:
+                       kindStr = "arm movt low high 4 bits=14";
+                       break;
+               case DYLD_CACHE_ADJ_V1_ARM_MOVT+15:
+                       kindStr = "arm movt low high 4 bits=15";
+                       break;
+               default:
+                       kindStr = "<<unknown>>";
        }
        uint64_t address = 0;
        uint64_t delta = 0;
-       uint32_t shift = 0;
-       bool more = true;
        do {
-               uint8_t byte = *p++;
-               delta |= ((byte & 0x7F) << shift);
-               shift += 7;
-               if ( byte < 0x80 ) {
-                       if ( delta != 0 ) {
-                               address += delta;
-                               printf("0x%0llX   %s\n", address+fBaseAddress, kindStr); 
-                               delta = 0;
-                               shift = 0;
-                       }
-                       else {
-                               more = false;
-                       }
-               }
-       } while (more);
+               delta = read_uleb128(p, end);
+               address += delta;
+               printf("0x%0llX   %s\n", address+fBaseAddress, kindStr); 
+       } while (delta);
+
        return p;
 }
 
@@ -1537,14 +1901,102 @@ void DyldInfoPrinter<A>::printSharedRegionInfo()
        else {
                const uint8_t* infoStart = (uint8_t*)fHeader + fSharedRegionInfo->dataoff();
                const uint8_t* infoEnd = &infoStart[fSharedRegionInfo->datasize()];
-               for(const uint8_t* p = infoStart; (*p != 0) && (p < infoEnd);) {
-                       uint8_t kind = *p++;
-                       p = this->printSharedRegionInfoForEachULEB128Address(p, kind);
+               if ( *infoStart == DYLD_CACHE_ADJ_V2_FORMAT ) {
+                       ++infoStart;
+                       // Whole                 :== <count> FromToSection+
+                       // FromToSection :== <from-sect-index> <to-sect-index> <count> ToOffset+
+                       // ToOffset              :== <to-sect-offset-delta> <count> FromOffset+
+                       // FromOffset    :== <kind> <count> <from-sect-offset-delta>
+                       const uint8_t* p = infoStart;
+                       uint64_t sectionCount = read_uleb128(p, infoEnd);
+                       for (uint64_t i=0; i < sectionCount; ++i) {
+                               uint64_t fromSectionIndex = read_uleb128(p, infoEnd);
+                               uint64_t toSectionIndex = read_uleb128(p, infoEnd);
+                               uint64_t toOffsetCount = read_uleb128(p, infoEnd);
+                               const macho_section<P>* fromSection = fSections[fromSectionIndex];
+                               const macho_section<P>* toSection = fSections[toSectionIndex];
+                               char fromSectionName[20];
+                               strncpy(fromSectionName, fromSection->sectname(), 16);
+                               fromSectionName[16] = '\0';
+                               printf("from sect=%s/%s, to sect=%s/%s, count=%lld:\n", fromSection->segname(), fromSectionName, toSection->segname(), toSection->sectname(), toOffsetCount);
+                               uint64_t toSectionOffset = 0;
+                               const char* lastFromSymbol = NULL;
+                               for (uint64_t j=0; j < toOffsetCount; ++j) {
+                                       uint64_t toSectionDelta = read_uleb128(p, infoEnd);
+                                       uint64_t fromOffsetCount = read_uleb128(p, infoEnd);
+                                       toSectionOffset += toSectionDelta;
+                                       for (uint64_t k=0; k < fromOffsetCount; ++k) {
+                                               uint64_t kind = read_uleb128(p, infoEnd);
+                                               uint64_t fromSectDeltaCount = read_uleb128(p, infoEnd);
+                                               uint64_t fromSectionOffset = 0;
+                                               for (uint64_t l=0; l < fromSectDeltaCount; ++l) {
+                                                       uint64_t delta = read_uleb128(p, infoEnd);
+                                                       fromSectionOffset += delta;
+                                                       uint64_t symbolOffset;
+                                                       const char* s = closestSymbolNameForAddress(fromSection->addr()+fromSectionOffset, &symbolOffset, fromSectionIndex);
+                                                       if ( (s != lastFromSymbol) && (s != NULL) )
+                                                               printf("  %s:\n", s);
+                                                       const char* toSymbol = closestSymbolNameForAddress(toSection->addr()+toSectionOffset, &symbolOffset, toSectionIndex);
+                                                       printf("       from addr=0x%0llX %s to addr=0x%0llX", fromSection->addr()+fromSectionOffset, sharedRegionKindName(kind), toSection->addr()+toSectionOffset);
+                                                       if ( toSymbol != NULL ) {
+                                                               if ( symbolOffset == 0 )
+                                                                       printf(" (%s)", toSymbol);
+                                                               else
+                                                                       printf(" (%s + %lld)", toSymbol, symbolOffset);
+                                                       }
+                                                       printf("\n");
+                                                       lastFromSymbol = s;
+                                               }
+                                       }
+                               }
+                       }
                }
+               else {
+                       for(const uint8_t* p = infoStart; (*p != 0) && (p < infoEnd);) {
+                               uint8_t kind = *p++;
+                               p = this->printSharedRegionV1InfoForEachULEB128Address(p, infoEnd, kind);
+                       }
+               }
+       }
+}
 
+template <typename A>
+const char* DyldInfoPrinter<A>::sharedRegionKindName(uint8_t kind)
+{
+       switch (kind) {
+               default:
+                       return "<<unknown>>";
+               case DYLD_CACHE_ADJ_V2_POINTER_32:
+                       return "pointer32";
+               case DYLD_CACHE_ADJ_V2_POINTER_64:
+                       return "pointer64";
+               case DYLD_CACHE_ADJ_V2_DELTA_32:
+                       return "delta32";
+               case DYLD_CACHE_ADJ_V2_DELTA_64:
+                       return "delta64";
+               case DYLD_CACHE_ADJ_V2_ARM64_ADRP:
+                       return "adrp";
+               case DYLD_CACHE_ADJ_V2_ARM64_OFF12:
+                       return "off12";
+               case DYLD_CACHE_ADJ_V2_ARM64_BR26:
+                       return "br26";
+               case DYLD_CACHE_ADJ_V2_ARM_MOVW_MOVT:
+                       return "movw/movt";
+               case DYLD_CACHE_ADJ_V2_ARM_BR24:
+                       return "br24";
+               case DYLD_CACHE_ADJ_V2_THUMB_MOVW_MOVT:
+                       return "movw/movt";
+               case DYLD_CACHE_ADJ_V2_THUMB_BR22:
+                       return "br22";
+               case DYLD_CACHE_ADJ_V2_IMAGE_OFF_32:
+                       return "off32";
+               case DYLD_CACHE_ADJ_V2_THREADED_POINTER_64:
+                       return "theaded-pointer64";
        }
 }
 
+
+#if SUPPORT_ARCH_arm_any
 template <>
 void DyldInfoPrinter<arm>::printFunctionStartLine(uint64_t addr)
 {
@@ -1553,6 +2005,7 @@ void DyldInfoPrinter<arm>::printFunctionStartLine(uint64_t addr)
        else
                printf("0x%0llX         %s\n", addr, symbolNameForAddress(addr)); 
 }
+#endif
 
 template <typename A>
 void DyldInfoPrinter<A>::printFunctionStartLine(uint64_t addr)
@@ -1617,6 +2070,84 @@ void DyldInfoPrinter<A>::printDylibsInfo()
        }
 }
 
+template <typename A>
+void DyldInfoPrinter<A>::printDRInfo()
+{
+       if ( fDRInfo == NULL ) {
+               printf("no Designated Requirements info\n");
+       }
+       else {
+               printf("dylibs                 DRs\n");
+               const uint8_t* start = ((uint8_t*)fHeader + fDRInfo->dataoff());
+               //const uint8_t* end   = ((uint8_t*)fHeader + fDRInfo->dataoff() + fDRInfo->datasize());
+               typedef Security::SuperBlob<Security::kSecCodeMagicDRList> DRListSuperBlob;
+               const DRListSuperBlob* topBlob = (DRListSuperBlob*)start;
+               if ( topBlob->validateBlob(fDRInfo->datasize()) ) {
+                       if ( topBlob->count() == fDylibLoadCommands.size() ) {
+                               for(unsigned i=0; i < topBlob->count(); ++i) {
+                                       printf(" %-20s   ", fDylibs[i]);
+                                       const Security::BlobCore* item = topBlob->find(i);
+                                       if ( item != NULL ) {
+                                               const uint8_t* itemStart = (uint8_t*)item;
+                                               const uint8_t* itemEnd = itemStart + item->length();
+                                               for(const uint8_t* p=itemStart; p < itemEnd; ++p)
+                                                       printf("%02X ", *p);
+                                       }
+                                       else {
+                                               printf("no DR info");
+                                       }
+                                       printf("\n");
+                               }
+                       }
+                       else {
+                               fprintf(stderr, "superblob of DRs has a different number of elements than dylib load commands\n");
+                       }
+               }
+               else {
+                       fprintf(stderr, "superblob of DRs invalid\n");
+               }
+       }
+}
+
+
+
+
+
+template <typename A>
+void DyldInfoPrinter<A>::printDataInCode()
+{
+       if ( fDataInCode == NULL ) {
+               printf("no data-in-code info\n");
+       }
+       else {
+               printf("offset      length  data-kind\n");
+               const macho_data_in_code_entry<P>* start = (macho_data_in_code_entry<P>*)((uint8_t*)fHeader + fDataInCode->dataoff());
+               const macho_data_in_code_entry<P>* end = (macho_data_in_code_entry<P>*)((uint8_t*)fHeader + fDataInCode->dataoff() + fDataInCode->datasize());
+               for (const macho_data_in_code_entry<P>* p=start; p < end; ++p) {
+                       const char* kindStr = "???";
+                       switch ( p->kind() ) {
+                               case 1:
+                                       kindStr = "data";
+                                       break;
+                               case 2:
+                                       kindStr = "jumptable8";
+                                       break;
+                               case 3:
+                                       kindStr = "jumptable16";
+                                       break;
+                               case 4:
+                                       kindStr = "jumptable32";
+                                       break;
+                               case 5:
+                                       kindStr = "jumptable32absolute";
+                                       break;
+                       }
+                       printf("0x%08X  0x%04X  %s\n", p->offset(), p->length(), kindStr);
+               }
+       }
+}
+
+
 
 template <>
 ppc::P::uint_t DyldInfoPrinter<ppc>::relocBase()
@@ -1648,10 +2179,10 @@ x86::P::uint_t DyldInfoPrinter<x86>::relocBase()
 template <>
 x86_64::P::uint_t DyldInfoPrinter<x86_64>::relocBase()
 {
-       // check for split-seg
        return fFirstWritableSegment->vmaddr();
 }
 
+#if SUPPORT_ARCH_arm_any
 template <>
 arm::P::uint_t DyldInfoPrinter<arm>::relocBase()
 {
@@ -1660,6 +2191,15 @@ arm::P::uint_t DyldInfoPrinter<arm>::relocBase()
        else
                return fFirstSegment->vmaddr();
 }
+#endif
+
+#if SUPPORT_ARCH_arm64
+template <>
+arm64::P::uint_t DyldInfoPrinter<arm64>::relocBase()
+{
+       return fFirstWritableSegment->vmaddr();
+}
+#endif
 
 
 template <>
@@ -1667,8 +2207,6 @@ const char*       DyldInfoPrinter<ppc>::relocTypeName(uint8_t r_type)
 {
        if ( r_type == GENERIC_RELOC_VANILLA )
                return "pointer";
-       else if ( r_type == PPC_RELOC_PB_LA_PTR )
-               return "pb pointer";
        else
                return "??";
 }
@@ -1702,6 +2240,7 @@ const char*       DyldInfoPrinter<x86_64>::relocTypeName(uint8_t r_type)
                return "??";
 }
        
+#if SUPPORT_ARCH_arm_any
 template <>
 const char*    DyldInfoPrinter<arm>::relocTypeName(uint8_t r_type)
 {
@@ -1712,11 +2251,109 @@ const char*    DyldInfoPrinter<arm>::relocTypeName(uint8_t r_type)
        else
                return "??";
 }
-       
+#endif
+
+#if SUPPORT_ARCH_arm64 
+template <>
+const char*    DyldInfoPrinter<arm64>::relocTypeName(uint8_t r_type)
+{
+       if ( r_type == ARM64_RELOC_UNSIGNED )
+               return "pointer";
+       return "??";
+}
+#endif
+
 
 template <typename A>
 void DyldInfoPrinter<A>::printRelocRebaseInfo()
 {
+       // First check if we can find a magic section for threaded rebase
+       {
+               auto rebaseChain = [this](uintptr_t chainStartMappedAddress, uintptr_t chainStartVMAddress, uint64_t stepMultiplier, uintptr_t baseAddress) {
+                       uint64_t delta = 0;
+                       uintptr_t mappedAddress = chainStartMappedAddress;
+                       uintptr_t vmAddress = chainStartVMAddress;
+                       do {
+                               uint64_t value = *(uint64_t*)mappedAddress;
+
+                               uint8_t segIndex = segmentIndexForAddress(vmAddress);
+                               const char* segName = segmentName(segIndex);
+                               const char* sectName = sectionName(segIndex, vmAddress);
+
+#if SUPPORT_ARCH_arm64e
+                               uint16_t diversity = (uint16_t)(value >> 32);
+                               bool hasAddressDiversity = (value & (1ULL << 48)) != 0;
+                               ptrauth_key key = (ptrauth_key)((value >> 49) & 0x3);
+                               bool isAuthenticated = (value & (1ULL << 63)) != 0;
+#endif
+                               bool isRebase = (value & (1ULL << 62)) == 0;
+                               if (isRebase) {
+
+#if SUPPORT_ARCH_arm64e
+                                       if (isAuthenticated) {
+                                               uint64_t slide = 0;
+                                               static const char* keyNames[] = {
+                                                       "IA", "IB", "DA", "DB"
+                                               };
+                                               // The new value for a rebase is the low 32-bits of the threaded value plus the slide.
+                                               uint64_t newValue = (value & 0xFFFFFFFF) + slide;
+                                               // Add in the offset from the mach_header
+                                               newValue += baseAddress;
+                                               // We have bits to merge in to the discriminator
+                                               printf("%-7s %-16s 0x%08llX  %s  0x%08llX (JOP: diversity %d, address %s, %s)\n",
+                                                          segName, sectName, (uint64_t)vmAddress, "pointer", newValue,
+                                                          diversity, hasAddressDiversity ? "true" : "false", keyNames[key]);
+                                       } else
+#endif
+                                       {
+                                               // Regular pointer which needs to fit in 51-bits of value.
+                                               // C++ RTTI uses the top bit, so we'll allow the whole top-byte
+                                               // and the bottom 43-bits to be fit in to 51-bits.
+                                               uint64_t top8Bits = value & 0x0007F80000000000ULL;
+                                               uint64_t bottom43Bits = value & 0x000007FFFFFFFFFFULL;
+                                               uint64_t targetValue = ( top8Bits << 13 ) | (((intptr_t)(bottom43Bits << 21) >> 21) & 0x00FFFFFFFFFFFFFF);
+                                               printf("%-7s %-16s 0x%08llX  %s  0x%08llX\n", segName, sectName, (uint64_t)vmAddress, "pointer", targetValue);
+                                       }
+                               }
+
+                               // The delta is bits [51..61]
+                               // And bit 62 is to tell us if we are a rebase (0) or bind (1)
+                               value &= ~(1ULL << 62);
+                               delta = ( value & 0x3FF8000000000000 ) >> 51;
+                               mappedAddress += delta * stepMultiplier;
+                               vmAddress += delta * stepMultiplier;
+                       } while ( delta != 0 );
+               };
+               for(const macho_segment_command<P>* segCmd : fSegments) {
+                       if (strcmp(segCmd->segname(), "__TEXT") != 0)
+                               continue;
+                       macho_section<P>* const sectionsStart = (macho_section<P>*)((char*)segCmd + sizeof(macho_segment_command<P>));
+                       macho_section<P>* const sectionsEnd = &sectionsStart[segCmd->nsects()];
+                       for(macho_section<P>* sect = sectionsStart; sect < sectionsEnd; ++sect) {
+                               if (strcmp(sect->sectname(), "__thread_starts") != 0)
+                                       continue;
+                               printf("rebase information (from __TEXT,__thread_starts):\n");
+                               printf("segment  section          address     type\n");
+                               const uint8_t* sectionContent = (uint8_t*)fHeader + segCmd->fileoff() + sect->offset();
+                               uint32_t *threadStarts = (uint32_t*)sectionContent;
+                               uint32_t *threadEnds = (uint32_t*)(sectionContent + sect->size());
+                               uint32_t threadStartsHeader = threadStarts[0];
+                               uint64_t stepMultiplier = (threadStartsHeader & 1) == 1 ? 8 : 4;
+                               for (uint32_t* threadOffset = threadStarts + 1; threadOffset != threadEnds; ++threadOffset) {
+                                       //printf("Thread start offset: 0x%016X\n", *threadOffset);
+                                       // If we get a 0xFFFFFFFF offset then ld64 overestimated the size required.  So skip the remainder
+                                       // of the entries.
+                                       if (*threadOffset == 0xFFFFFFFF)
+                                               break;
+                                       uint64_t chainStartVMAddr = fBaseAddress + *threadOffset;
+                                       uintptr_t chainStartMappedAddress = (uintptr_t)mappedAddressForVMAddress(chainStartVMAddr);
+                                       rebaseChain(chainStartMappedAddress, chainStartVMAddr, stepMultiplier, fBaseAddress);
+                               }
+                               return;
+                       }
+               }
+       }
+
        if ( fDynamicSymbolTable == NULL ) {
                printf("no classic dynamic symbol table");
        }
@@ -1797,37 +2434,65 @@ void DyldInfoPrinter<A>::printSymbolTableExportInfo()
 }
 
 template <typename A>
-const char* DyldInfoPrinter<A>::symbolNameForAddress(uint64_t addr)
+const char* DyldInfoPrinter<A>::closestSymbolNameForAddress(uint64_t addr, uint64_t* offset, uint8_t sectIndex)
 {
+       const macho_nlist<P>* bestSymbol = NULL;
        if ( fDynamicSymbolTable != NULL ) {
-               // find exact match in globals
-               const macho_nlist<P>* lastExport = &fSymbols[fDynamicSymbolTable->iextdefsym()+fDynamicSymbolTable->nextdefsym()];
-               for (const macho_nlist<P>* sym = &fSymbols[fDynamicSymbolTable->iextdefsym()]; sym < lastExport; ++sym) {
-                       if ( (sym->n_value() == addr) && ((sym->n_type() & N_TYPE) == N_SECT) && ((sym->n_type() & N_STAB) == 0) ) {
-                               return &fStrings[sym->n_strx()];
+               // find closest match in globals
+               const macho_nlist<P>* const globalsStart = &fSymbols[fDynamicSymbolTable->iextdefsym()];
+               const macho_nlist<P>* const globalsEnd   = &globalsStart[fDynamicSymbolTable->nextdefsym()];
+               for (const macho_nlist<P>* s = globalsStart; s < globalsEnd; ++s) {
+                       if ( (s->n_type() & N_TYPE) == N_SECT ) {
+                               if ( (s->n_value() <= addr) && ((s->n_sect() == sectIndex) || (sectIndex ==0)) ) {
+                                       if ( (bestSymbol == NULL) || (bestSymbol->n_value() < s->n_value()) )
+                                               bestSymbol = s;
+                               }
                        }
                }
-               // find exact match in local symbols
-               const macho_nlist<P>* lastLocal = &fSymbols[fDynamicSymbolTable->ilocalsym()+fDynamicSymbolTable->nlocalsym()];
-               for (const macho_nlist<P>* sym = &fSymbols[fDynamicSymbolTable->ilocalsym()]; sym < lastLocal; ++sym) {
-                       if ( (sym->n_value() == addr) && ((sym->n_type() & N_TYPE) == N_SECT) && ((sym->n_type() & N_STAB) == 0) ) {
-                               return &fStrings[sym->n_strx()];
+
+               // find closest match in locals
+               const macho_nlist<P>* const localsStart = &fSymbols[fDynamicSymbolTable->ilocalsym()];
+               const macho_nlist<P>* const localsEnd   = &localsStart[fDynamicSymbolTable->nlocalsym()];
+               for (const macho_nlist<P>* s = localsStart; s < localsEnd; ++s) {
+                       if ( ((s->n_type() & N_TYPE) == N_SECT) && ((s->n_type() & N_STAB) == 0) ) {
+                               if ( (s->n_value() <= addr) && ((s->n_sect() == sectIndex) || (sectIndex ==0)) ) {
+                                       if ( (bestSymbol == NULL) || (bestSymbol->n_value() < s->n_value()) )
+                                               bestSymbol = s;
+                               }
                        }
                }
        }
        else {
-               // find exact match in all symbols
-               const macho_nlist<P>* lastSym = &fSymbols[fSymbolCount];
-               for (const macho_nlist<P>* sym = &fSymbols[0]; sym < lastSym; ++sym) {
-                       if ( (sym->n_value() == addr) && ((sym->n_type() & N_TYPE) == N_SECT) && ((sym->n_type() & N_STAB) == 0) ) {
-                               return &fStrings[sym->n_strx()];
+               // find closest match in locals
+               const macho_nlist<P>* const allStart = &fSymbols[0];
+               const macho_nlist<P>* const allEnd   = &fSymbols[fSymbolCount];
+               for (const macho_nlist<P>* s = allStart; s < allEnd; ++s) {
+                       if ( ((s->n_type() & N_TYPE) == N_SECT) && ((s->n_type() & N_STAB) == 0) ) {
+                               if ( (s->n_value() <= addr) && ((s->n_sect() == sectIndex) || (sectIndex ==0)) ) {
+                                       if ( (bestSymbol == NULL) || (bestSymbol->n_value() < s->n_value()) )
+                                               bestSymbol = s;
+                               }
                        }
                }
        }
+       if ( bestSymbol != NULL ) {
+               *offset = addr - bestSymbol->n_value();
+               return &fStrings[bestSymbol->n_strx()];
+       }
+       *offset = 0;
+       return NULL;
+}
 
+template <typename A>
+const char* DyldInfoPrinter<A>::symbolNameForAddress(uint64_t addr)
+{
+       uint64_t offset;
+       const char* s = closestSymbolNameForAddress(addr, &offset);
+       if ( (offset == 0) && (s != NULL) )
+               return s;
        return "?";
 }
+
 template <typename A>
 void DyldInfoPrinter<A>::printClassicBindingInfo()
 {
@@ -2003,12 +2668,22 @@ static void dump(const char* path)
                                                else
                                                        throw "in universal file, x86_64 slice does not contain x86_64 mach-o";
                                                break;
+#if SUPPORT_ARCH_arm_any
                                        case CPU_TYPE_ARM:
                                                if ( DyldInfoPrinter<arm>::validFile(p + offset) ) 
                                                        DyldInfoPrinter<arm>::make(p + offset, size, path, (sPreferredArch == 0));
                                                else
                                                        throw "in universal file, arm slice does not contain arm mach-o";
                                                break;
+#endif
+#if SUPPORT_ARCH_arm64
+                                       case CPU_TYPE_ARM64:
+                                               if ( DyldInfoPrinter<arm64>::validFile(p + offset) )
+                                                       DyldInfoPrinter<arm64>::make(p + offset, size, path, (sPreferredArch == 0));
+                                               else
+                                                       throw "in universal file, arm64 slice does not contain arm64 mach-o";
+                                               break;
+#endif
                                        default:
                                                        throwf("in universal file, unknown architecture slice 0x%x\n", cputype);
                                        }
@@ -2027,9 +2702,16 @@ static void dump(const char* path)
                else if ( DyldInfoPrinter<x86_64>::validFile(p) ) {
                        DyldInfoPrinter<x86_64>::make(p, length, path, false);
                }
+#if SUPPORT_ARCH_arm_any
                else if ( DyldInfoPrinter<arm>::validFile(p) ) {
                        DyldInfoPrinter<arm>::make(p, length, path, false);
                }
+#endif
+#if SUPPORT_ARCH_arm64
+               else if ( DyldInfoPrinter<arm64>::validFile(p) ) {
+                       DyldInfoPrinter<arm64>::make(p, length, path, false);
+               }
+#endif
                else {
                        throw "not a known file type";
                }
@@ -2043,6 +2725,7 @@ static void usage()
 {
        fprintf(stderr, "Usage: dyldinfo [-arch <arch>] <options> <mach-o file>\n"
                        "\t-dylibs           print dependent dylibs\n"
+                       "\t-dr               print dependent dylibs and show any recorded DR info\n"
                        "\t-rebase           print addresses dyld will adjust if file not loaded at preferred address\n"
                        "\t-bind             print addresses dyld will set based on symbolic lookups\n"
                        "\t-weak_bind        print symbols which dyld must coalesce\n"
@@ -2051,6 +2734,7 @@ static void usage()
                        "\t-opcodes          print opcodes used to generate the rebase and binding information\n"
                        "\t-function_starts  print table of function start addresses\n"
                        "\t-export_dot       print a GraphViz .dot file of the exported symbols trie\n"
+                       "\t-data_in_code     print any data-in-code information\n"
                );
 }
 
@@ -2073,16 +2757,15 @@ int main(int argc, const char* argv[])
                                                sPreferredArch = CPU_TYPE_POWERPC64;
                                        else if ( strcmp(arch, "ppc") == 0 )
                                                sPreferredArch = CPU_TYPE_POWERPC;
-                                       else if ( strcmp(arch, "i386") == 0 )
-                                               sPreferredArch = CPU_TYPE_I386;
-                                       else if ( strcmp(arch, "x86_64") == 0 )
-                                               sPreferredArch = CPU_TYPE_X86_64;
                                        else {
+                                               if ( arch == NULL )
+                                                       throw "-arch missing architecture name";
                                                bool found = false;
-                                               for (const ARMSubType* t=ARMSubTypes; t->subTypeName != NULL; ++t) {
-                                                       if ( strcmp(t->subTypeName,arch) == 0 ) {
-                                                               sPreferredArch = CPU_TYPE_ARM;
-                                                               sPreferredSubArch = t->subType;
+                                               for (const ArchInfo* t=archInfoArray; t->archName != NULL; ++t) {
+                                                       if ( strcmp(t->archName,arch) == 0 ) {
+                                                               sPreferredArch = t->cpuType;
+                                                               if ( t->isSubType )
+                                                                       sPreferredSubArch = t->cpuSubType;
                                                                found = true;
                                                                break;
                                                        }
@@ -2124,6 +2807,12 @@ int main(int argc, const char* argv[])
                                else if ( strcmp(arg, "-dylibs") == 0 ) {
                                        printDylibs = true;
                                }
+                               else if ( strcmp(arg, "-dr") == 0 ) {
+                                       printDRs = true;
+                               }
+                               else if ( strcmp(arg, "-data_in_code") == 0 ) {
+                                       printDataCode = true;
+                               }
                                else {
                                        throwf("unknown option: %s\n", arg);
                                }