X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/afe874b1634377ecb27057ee76deb04915bb34d7..82b4b32b1851b4bba2473356c2208bd34561ee02:/src/other/dyldinfo.cpp diff --git a/src/other/dyldinfo.cpp b/src/other/dyldinfo.cpp index 2c86577..e271978 100644 --- a/src/other/dyldinfo.cpp +++ b/src/other/dyldinfo.cpp @@ -33,11 +33,13 @@ #include #include -#include +#include +#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 +52,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 +87,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, CStringEquals> StringSet; - DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool printArch); void printRebaseInfo(); void printRebaseInfoOpcodes(); @@ -108,10 +104,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 +136,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 +149,18 @@ private: const macho_dyld_info_command

* fInfo; const macho_linkedit_data_command

* fSharedRegionInfo; const macho_linkedit_data_command

* fFunctionStartsInfo; + const macho_linkedit_data_command

* fDataInCode; + const macho_linkedit_data_command

* fDRInfo; uint64_t fBaseAddress; const macho_dysymtab_command

* fDynamicSymbolTable; const macho_segment_command

* fFirstSegment; const macho_segment_command

* fFirstWritableSegment; bool fWriteableSegmentWithAddrOver4G; std::vector*>fSegments; + std::vector*> fSections; std::vector fDylibs; std::vector*> fDylibLoadCommands; + macho_section

fMachHeaderPseudoSection; }; @@ -166,6 +176,7 @@ 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: return true; @@ -184,6 +195,7 @@ 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: return true; @@ -202,6 +214,7 @@ 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: return true; @@ -220,13 +233,16 @@ 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; } return false; } +#if SUPPORT_ARCH_arm_any template <> bool DyldInfoPrinter::validFile(const uint8_t* fileContent) { @@ -238,18 +254,46 @@ 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; + } + return false; +} +#endif + +#if SUPPORT_ARCH_arm64 +template <> +bool DyldInfoPrinter::validFile(const uint8_t* fileContent) +{ + const macho_header

* header = (const macho_header

*)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 DyldInfoPrinter::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 +303,12 @@ DyldInfoPrinter::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLen fPath = strdup(path); fHeader = (const macho_header

*)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

) + fHeader->sizeofcmds(); @@ -291,6 +340,10 @@ DyldInfoPrinter::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLen if ( segCmd->vmaddr() > 0x100000000ULL ) fWriteableSegmentWithAddrOver4G = true; } + const macho_section

* const sectionsStart = (macho_section

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

)); + const macho_section

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

* sect = sectionsStart; sect < sectionsEnd; ++sect) + fSections.push_back(sect); } break; case LC_LOAD_DYLIB: @@ -332,32 +385,26 @@ DyldInfoPrinter::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLen case LC_FUNCTION_STARTS: fFunctionStartsInfo = (macho_linkedit_data_command

*)cmd; break; + case LC_DATA_IN_CODE: + fDataInCode = (macho_linkedit_data_command

*)cmd; + break; + case LC_DYLIB_CODE_SIGN_DRS: + fDRInfo = (macho_linkedit_data_command

*)cmd; + break; } cmd = (const macho_load_command

*)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 +447,10 @@ DyldInfoPrinter::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 +483,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 @@ -607,7 +658,7 @@ void DyldInfoPrinter::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 = "??"; @@ -679,9 +730,10 @@ void DyldInfoPrinter::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 +743,45 @@ void DyldInfoPrinter::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); @@ -1259,26 +1312,50 @@ void DyldInfoPrinter::printExportInfo() parseTrie(start, end, list); //std::sort(list.begin(), list.end(), SortExportsByAddress()); for (std::vector::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 +1367,7 @@ void DyldInfoPrinter::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 +1487,8 @@ void DyldInfoPrinter::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 +1513,126 @@ void DyldInfoPrinter::printExportInfoNodes() template -const uint8_t* DyldInfoPrinter::printSharedRegionInfoForEachULEB128Address(const uint8_t* p, uint8_t kind) +const uint8_t* DyldInfoPrinter::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"; - break; - case 4: - kindStr = "32-bit offset to IMPORT"; - break; - case 5: - kindStr = "thumb2 movw"; + case DYLD_CACHE_ADJ_V1_ADRP: + kindStr = "arm64 ADRP"; 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 = "<>"; } 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 +1645,100 @@ void DyldInfoPrinter::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 :== FromToSection+ + // FromToSection :== ToOffset+ + // ToOffset :== FromOffset+ + // FromOffset :== + 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

* fromSection = fSections[fromSectionIndex]; + const macho_section

* 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 +const char* DyldInfoPrinter::sharedRegionKindName(uint8_t kind) +{ + switch (kind) { + default: + return "<>"; + 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"; } } + +#if SUPPORT_ARCH_arm_any template <> void DyldInfoPrinter::printFunctionStartLine(uint64_t addr) { @@ -1553,6 +1747,7 @@ void DyldInfoPrinter::printFunctionStartLine(uint64_t addr) else printf("0x%0llX %s\n", addr, symbolNameForAddress(addr)); } +#endif template void DyldInfoPrinter::printFunctionStartLine(uint64_t addr) @@ -1617,6 +1812,84 @@ void DyldInfoPrinter::printDylibsInfo() } } +template +void DyldInfoPrinter::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 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 +void DyldInfoPrinter::printDataInCode() +{ + if ( fDataInCode == NULL ) { + printf("no data-in-code info\n"); + } + else { + printf("offset length data-kind\n"); + const macho_data_in_code_entry

* start = (macho_data_in_code_entry

*)((uint8_t*)fHeader + fDataInCode->dataoff()); + const macho_data_in_code_entry

* end = (macho_data_in_code_entry

*)((uint8_t*)fHeader + fDataInCode->dataoff() + fDataInCode->datasize()); + for (const macho_data_in_code_entry

* 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::relocBase() @@ -1648,10 +1921,10 @@ x86::P::uint_t DyldInfoPrinter::relocBase() template <> x86_64::P::uint_t DyldInfoPrinter::relocBase() { - // check for split-seg return fFirstWritableSegment->vmaddr(); } +#if SUPPORT_ARCH_arm_any template <> arm::P::uint_t DyldInfoPrinter::relocBase() { @@ -1660,6 +1933,15 @@ arm::P::uint_t DyldInfoPrinter::relocBase() else return fFirstSegment->vmaddr(); } +#endif + +#if SUPPORT_ARCH_arm64 +template <> +arm64::P::uint_t DyldInfoPrinter::relocBase() +{ + return fFirstWritableSegment->vmaddr(); +} +#endif template <> @@ -1667,8 +1949,6 @@ const char* DyldInfoPrinter::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 +1982,7 @@ const char* DyldInfoPrinter::relocTypeName(uint8_t r_type) return "??"; } +#if SUPPORT_ARCH_arm_any template <> const char* DyldInfoPrinter::relocTypeName(uint8_t r_type) { @@ -1712,7 +1993,18 @@ const char* DyldInfoPrinter::relocTypeName(uint8_t r_type) else return "??"; } - +#endif + +#if SUPPORT_ARCH_arm64 +template <> +const char* DyldInfoPrinter::relocTypeName(uint8_t r_type) +{ + if ( r_type == ARM64_RELOC_UNSIGNED ) + return "pointer"; + return "??"; +} +#endif + template void DyldInfoPrinter::printRelocRebaseInfo() @@ -1797,37 +2089,65 @@ void DyldInfoPrinter::printSymbolTableExportInfo() } template -const char* DyldInfoPrinter::symbolNameForAddress(uint64_t addr) +const char* DyldInfoPrinter::closestSymbolNameForAddress(uint64_t addr, uint64_t* offset, uint8_t sectIndex) { + const macho_nlist

* bestSymbol = NULL; if ( fDynamicSymbolTable != NULL ) { - // find exact match in globals - const macho_nlist

* lastExport = &fSymbols[fDynamicSymbolTable->iextdefsym()+fDynamicSymbolTable->nextdefsym()]; - for (const macho_nlist

* 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

* const globalsStart = &fSymbols[fDynamicSymbolTable->iextdefsym()]; + const macho_nlist

* const globalsEnd = &globalsStart[fDynamicSymbolTable->nextdefsym()]; + for (const macho_nlist

* 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

* lastLocal = &fSymbols[fDynamicSymbolTable->ilocalsym()+fDynamicSymbolTable->nlocalsym()]; - for (const macho_nlist

* 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

* const localsStart = &fSymbols[fDynamicSymbolTable->ilocalsym()]; + const macho_nlist

* const localsEnd = &localsStart[fDynamicSymbolTable->nlocalsym()]; + for (const macho_nlist

* 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

* lastSym = &fSymbols[fSymbolCount]; - for (const macho_nlist

* 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

* const allStart = &fSymbols[0]; + const macho_nlist

* const allEnd = &fSymbols[fSymbolCount]; + for (const macho_nlist

* 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 +const char* DyldInfoPrinter::symbolNameForAddress(uint64_t addr) +{ + uint64_t offset; + const char* s = closestSymbolNameForAddress(addr, &offset); + if ( (offset == 0) && (s != NULL) ) + return s; return "?"; } - + template void DyldInfoPrinter::printClassicBindingInfo() { @@ -2003,12 +2323,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::validFile(p + offset) ) DyldInfoPrinter::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::validFile(p + offset) ) + DyldInfoPrinter::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 +2357,16 @@ static void dump(const char* path) else if ( DyldInfoPrinter::validFile(p) ) { DyldInfoPrinter::make(p, length, path, false); } +#if SUPPORT_ARCH_arm_any else if ( DyldInfoPrinter::validFile(p) ) { DyldInfoPrinter::make(p, length, path, false); } +#endif +#if SUPPORT_ARCH_arm64 + else if ( DyldInfoPrinter::validFile(p) ) { + DyldInfoPrinter::make(p, length, path, false); + } +#endif else { throw "not a known file type"; } @@ -2043,6 +2380,7 @@ static void usage() { fprintf(stderr, "Usage: dyldinfo [-arch ] \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 +2389,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" ); } @@ -2077,12 +2416,19 @@ int main(int argc, const char* argv[]) 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"; 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 +2470,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); }