X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/eaf282aaf65b222563e6b3db98e12d720fb161bf..e456bf1059cf7e6b8b71545d1b2f2092b55a9684:/src/other/dyldinfo.cpp diff --git a/src/other/dyldinfo.cpp b/src/other/dyldinfo.cpp index f19538f..45fcb0f 100644 --- a/src/other/dyldinfo.cpp +++ b/src/other/dyldinfo.cpp @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -236,6 +237,7 @@ bool DyldInfoPrinter::validFile(const uint8_t* fileContent) case MH_DYLIB_STUB: case MH_BUNDLE: case MH_DYLINKER: + case MH_KEXT_BUNDLE: return true; } return false; @@ -256,6 +258,7 @@ bool DyldInfoPrinter::validFile(const uint8_t* fileContent) case MH_DYLIB_STUB: case MH_BUNDLE: case MH_DYLINKER: + case MH_KEXT_BUNDLE: return true; } return false; @@ -274,14 +277,19 @@ bool DyldInfoPrinter::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; + default: + return false; } return false; } #endif + template DyldInfoPrinter::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool printArch) : fHeader(NULL), fLength(fileLength), @@ -608,6 +616,8 @@ const char* DyldInfoPrinter::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"; @@ -637,12 +647,164 @@ const char* DyldInfoPrinter::classicOrdinalName(int libraryOrdinal) template void DyldInfoPrinter::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()]; @@ -655,6 +817,8 @@ void DyldInfoPrinter::printRebaseInfo() 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; @@ -682,35 +846,42 @@ void DyldInfoPrinter::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); } - } + } } - } @@ -784,11 +955,6 @@ void DyldInfoPrinter::printRebaseInfoOpcodes() } - - - - - template void DyldInfoPrinter::printBindingInfoOpcodes(bool weakbinding) { @@ -894,6 +1060,20 @@ void DyldInfoPrinter::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); } @@ -902,7 +1082,20 @@ void DyldInfoPrinter::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 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 void DyldInfoPrinter::printBindingInfo() @@ -915,8 +1108,9 @@ void DyldInfoPrinter::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; @@ -929,6 +1123,8 @@ void DyldInfoPrinter::printBindingInfo() const char* segName = "??"; const char* typeName = "??"; const char* weak_import = ""; + std::vector ordinalTable; + bool useThreadedRebaseBind = false; bool done = false; while ( !done && (p < end) ) { uint8_t immediate = *p & BIND_IMMEDIATE_MASK; @@ -961,7 +1157,8 @@ void DyldInfoPrinter::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 = ""; @@ -983,8 +1180,12 @@ void DyldInfoPrinter::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 ); @@ -1002,6 +1203,68 @@ void DyldInfoPrinter::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); } @@ -1652,7 +1915,10 @@ void DyldInfoPrinter::printSharedRegionInfo() uint64_t toOffsetCount = read_uleb128(p, infoEnd); const macho_section

* fromSection = fSections[fromSectionIndex]; const macho_section

* toSection = fSections[toSectionIndex]; - printf("from sect=%s, to sect=%s, count=%lld:\n", fromSection->sectname(), toSection->sectname(), toOffsetCount); + 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) { @@ -1724,6 +1990,8 @@ const char* DyldInfoPrinter::sharedRegionKindName(uint8_t kind) return "br22"; case DYLD_CACHE_ADJ_V2_IMAGE_OFF_32: return "off32"; + case DYLD_CACHE_ADJ_V2_THREADED_POINTER_64: + return "theaded-pointer64"; } } @@ -1933,6 +2201,7 @@ arm64::P::uint_t DyldInfoPrinter::relocBase() } #endif + template <> const char* DyldInfoPrinter::relocTypeName(uint8_t r_type) { @@ -1994,9 +2263,97 @@ const char* DyldInfoPrinter::relocTypeName(uint8_t r_type) } #endif + template void DyldInfoPrinter::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

* segCmd : fSegments) { + if (strcmp(segCmd->segname(), "__TEXT") != 0) + continue; + macho_section

* const sectionsStart = (macho_section

*)((char*)segCmd + sizeof(macho_segment_command

)); + macho_section

* const sectionsEnd = §ionsStart[segCmd->nsects()]; + for(macho_section

* 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"); } @@ -2324,7 +2681,7 @@ static void dump(const char* path) if ( DyldInfoPrinter::validFile(p + offset) ) DyldInfoPrinter::make(p + offset, size, path, (sPreferredArch == 0)); else - throw "in universal file, arm64 slice does not contain arm mach-o"; + throw "in universal file, arm64 slice does not contain arm64 mach-o"; break; #endif default: @@ -2400,14 +2757,6 @@ 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; -#if SUPPORT_ARCH_arm64 - else if ( strcmp(arch, "arm64") == 0 ) - sPreferredArch = CPU_TYPE_ARM64; -#endif else { if ( arch == NULL ) throw "-arch missing architecture name";