X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/fb24a05017baddaa8cdc205852b134120bcc54ad..b2fa67a80bc53211e4d1ea81f23e9f953ee1dd6c:/src/other/dyldinfo.cpp diff --git a/src/other/dyldinfo.cpp b/src/other/dyldinfo.cpp index 5c42471..6a63ca1 100644 --- a/src/other/dyldinfo.cpp +++ b/src/other/dyldinfo.cpp @@ -1,6 +1,6 @@ /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*- * - * Copyright (c) 2008-2009 Apple Inc. All rights reserved. + * Copyright (c) 2008-2010 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -46,12 +46,16 @@ static bool printLazyBind = false; static bool printOpcodes = false; static bool printExport = false; static bool printExportGraph = false; -static cpu_type_t sPreferredArch = CPU_TYPE_I386; +static bool printExportNodes = false; +static bool printSharedRegion = false; +static bool printFunctionStarts = false; +static bool printDylibs = false; +static cpu_type_t sPreferredArch = 0; static cpu_type_t sPreferredSubArch = 0; - __attribute__((noreturn)) -void throwf(const char* format, ...) +__attribute__((noreturn)) +static void throwf(const char* format, ...) { va_list list; char* p; @@ -69,8 +73,8 @@ class DyldInfoPrinter { public: static bool validFile(const uint8_t* fileContent); - static DyldInfoPrinter* make(const uint8_t* fileContent, uint32_t fileLength, const char* path) - { return new DyldInfoPrinter(fileContent, fileLength, path); } + static DyldInfoPrinter* make(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool printArch) + { return new DyldInfoPrinter(fileContent, fileLength, path, printArch); } virtual ~DyldInfoPrinter() {} @@ -87,7 +91,7 @@ private: typedef __gnu_cxx::hash_set, CStringEquals> StringSet; - DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path); + DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path, bool printArch); void printRebaseInfo(); void printRebaseInfoOpcodes(); void printBindingInfo(); @@ -98,18 +102,25 @@ private: void printLazyBindingOpcodes(); void printExportInfo(); void printExportInfoGraph(); + void printExportInfoNodes(); void printRelocRebaseInfo(); void printSymbolTableExportInfo(); void printClassicLazyBindingInfo(); void printClassicBindingInfo(); + void printSharedRegionInfo(); + void printFunctionStartsInfo(); + void printDylibsInfo(); + void printFunctionStartLine(uint64_t addr); + const uint8_t* printSharedRegionInfoForEachULEB128Address(const uint8_t* p, uint8_t kind); pint_t relocBase(); const char* relocTypeName(uint8_t r_type); uint8_t segmentIndexForAddress(pint_t addr); - void processExportNode(const uint8_t* const start, const uint8_t* p, const uint8_t* const end, - char* cummulativeString, int curStrOffset); void processExportGraphNode(const uint8_t* const start, const uint8_t* const end, const uint8_t* parent, const uint8_t* p, char* cummulativeString, int curStrOffset); + void gatherNodeStarts(const uint8_t* const start, const uint8_t* const end, + const uint8_t* parent, const uint8_t* p, + std::vector& nodeStarts); const char* rebaseTypeName(uint8_t type); const char* bindTypeName(uint8_t type); pint_t segStartAddress(uint8_t segIndex); @@ -119,7 +130,7 @@ private: const char* ordinalName(int libraryOrdinal); const char* classicOrdinalName(int libraryOrdinal); pint_t* mappedAddressForVMAddress(pint_t vmaddress); - + const char* symbolNameForAddress(uint64_t); const char* fPath; @@ -130,6 +141,8 @@ private: const macho_nlist

* fSymbols; uint32_t fSymbolCount; const macho_dyld_info_command

* fInfo; + const macho_linkedit_data_command

* fSharedRegionInfo; + const macho_linkedit_data_command

* fFunctionStartsInfo; uint64_t fBaseAddress; const macho_dysymtab_command

* fDynamicSymbolTable; const macho_segment_command

* fFirstSegment; @@ -137,6 +150,7 @@ private: bool fWriteableSegmentWithAddrOver4G; std::vector*>fSegments; std::vector fDylibs; + std::vector*> fDylibLoadCommands; }; @@ -232,9 +246,10 @@ bool DyldInfoPrinter::validFile(const uint8_t* fileContent) } template -DyldInfoPrinter::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLength, const char* path) +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), fBaseAddress(0), fDynamicSymbolTable(NULL), fFirstSegment(NULL), fFirstWritableSegment(NULL), fWriteableSegmentWithAddrOver4G(false) { @@ -281,9 +296,11 @@ DyldInfoPrinter::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLen case LC_LOAD_DYLIB: case LC_LOAD_WEAK_DYLIB: case LC_REEXPORT_DYLIB: + case LC_LOAD_UPWARD_DYLIB: case LC_LAZY_LOAD_DYLIB: { const macho_dylib_command

* dylib = (macho_dylib_command

*)cmd; + fDylibLoadCommands.push_back(dylib); const char* lastSlash = strrchr(dylib->name(), '/'); const char* leafName = (lastSlash != NULL) ? lastSlash+1 : dylib->name(); const char* firstDot = strchr(leafName, '.'); @@ -309,10 +326,38 @@ DyldInfoPrinter::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLen fStringsEnd = fStrings + symtab->strsize(); } break; + case LC_SEGMENT_SPLIT_INFO: + fSharedRegionInfo = (macho_linkedit_data_command

*)cmd; + break; + case LC_FUNCTION_STARTS: + fFunctionStartsInfo = (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; + } + } + } + } + + if ( printRebase ) { if ( fInfo != NULL ) printRebaseInfo(); @@ -347,6 +392,14 @@ DyldInfoPrinter::DyldInfoPrinter(const uint8_t* fileContent, uint32_t fileLen } if ( printExportGraph ) printExportInfoGraph(); + if ( printExportNodes ) + printExportInfoNodes(); + if ( printSharedRegion ) + printSharedRegionInfo(); + if ( printFunctionStarts ) + printFunctionStartsInfo(); + if ( printDylibs ) + printDylibsInfo(); } static uint64_t read_uleb128(const uint8_t*& p, const uint8_t* end) @@ -522,6 +575,8 @@ const char* DyldInfoPrinter::ordinalName(int libraryOrdinal) template const char* DyldInfoPrinter::classicOrdinalName(int libraryOrdinal) { + if ( (fHeader->flags() & MH_TWOLEVEL) == 0 ) + return "flat-namespace"; switch ( libraryOrdinal) { case SELF_LIBRARY_ORDINAL: return "this-image"; @@ -811,7 +866,7 @@ void DyldInfoPrinter::printBindingInfo() } else { printf("bind information:\n"); - printf("segment section address type weak addend dylib symbol\n"); + 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()]; @@ -861,7 +916,7 @@ void DyldInfoPrinter::printBindingInfo() ++p; ++p; if ( (immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 ) - weak_import = "weak"; + weak_import = " (weak import)"; else weak_import = ""; break; @@ -882,22 +937,22 @@ void DyldInfoPrinter::printBindingInfo() segOffset += read_uleb128(p, end); break; case BIND_OPCODE_DO_BIND: - printf("%-7s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, weak_import, addend, fromDylib, symbolName ); + 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); break; case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: - printf("%-7s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, weak_import, addend, fromDylib, symbolName ); + 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 += read_uleb128(p, end) + sizeof(pint_t); break; case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: - printf("%-7s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, weak_import, addend, fromDylib, symbolName ); + 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 += 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) { - printf("%-7s %-16s 0x%08llX %10s %4s %5lld %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, typeName, weak_import, addend, fromDylib, symbolName ); + 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 += skip + sizeof(pint_t); } break; @@ -1019,6 +1074,7 @@ void DyldInfoPrinter::printLazyBindingInfo() pint_t segStartAddr = 0; const char* segName = "??"; const char* typeName = "??"; + const char* weak_import = ""; for (const uint8_t* p=start; p < end; ) { uint8_t immediate = *p & BIND_IMMEDIATE_MASK; uint8_t opcode = *p & BIND_OPCODE_MASK; @@ -1050,6 +1106,10 @@ void DyldInfoPrinter::printLazyBindingInfo() while (*p != '\0') ++p; ++p; + if ( (immediate & BIND_SYMBOL_FLAGS_WEAK_IMPORT) != 0 ) + weak_import = " (weak import)"; + else + weak_import = ""; break; case BIND_OPCODE_SET_TYPE_IMM: type = immediate; @@ -1068,7 +1128,7 @@ void DyldInfoPrinter::printLazyBindingInfo() segOffset += read_uleb128(p, end); break; case BIND_OPCODE_DO_BIND: - printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, lazy_offset, fromDylib, symbolName ); + printf("%-7s %-16s 0x%08llX 0x%04X %-16s %s%s\n", segName, sectionName(segIndex, segStartAddr+segOffset), segStartAddr+segOffset, lazy_offset, fromDylib, symbolName, weak_import); segOffset += sizeof(pint_t); break; default: @@ -1177,35 +1237,6 @@ void DyldInfoPrinter::printLazyBindingOpcodes() } - -template -void DyldInfoPrinter::processExportNode(const uint8_t* const start, const uint8_t* p, const uint8_t* const end, - char* cummulativeString, int curStrOffset) -{ - const uint8_t terminalSize = *p++; - const uint8_t* children = p + terminalSize; - if ( terminalSize != 0 ) { - uint32_t flags = read_uleb128(p, end); - uint64_t address = read_uleb128(p, end); - if ( flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION ) - fprintf(stdout, "0x%08llX [weak_def] %s\n", address, cummulativeString); - else - fprintf(stdout, "0x%08llX %s\n", address, cummulativeString); - } - const uint8_t childrenCount = *children++; - const uint8_t* s = children; - for (uint8_t i=0; i < childrenCount; ++i) { - int edgeStrLen = 0; - while (*s != '\0') { - cummulativeString[curStrOffset+edgeStrLen] = *s++; - ++edgeStrLen; - } - cummulativeString[curStrOffset+edgeStrLen] = *s++; - uint32_t childNodeOffet = read_uleb128(s, end); - processExportNode(start, start+childNodeOffet, end, cummulativeString, curStrOffset+edgeStrLen); - } -} - struct SortExportsByAddress { bool operator()(const mach_o::trie::Entry& left, const mach_o::trie::Entry& right) @@ -1228,10 +1259,26 @@ 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) { - const char* flags = ""; - if ( it->flags & EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION ) - flags = "[weak_def] "; - fprintf(stdout, "0x%08llX %s%s\n", fBaseAddress+it->address, flags, it->name); + 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); + } + else { + fprintf(stdout, "0x%08llX %s%s\n", fBaseAddress+it->address, flags, it->name); + } + } } } } @@ -1243,13 +1290,27 @@ void DyldInfoPrinter::processExportGraphNode(const uint8_t* const start, cons char* cummulativeString, int curStrOffset) { const uint8_t* const me = p; - const uint8_t terminalSize = *p++; + const uint8_t terminalSize = read_uleb128(p, end); const uint8_t* children = p + terminalSize; if ( terminalSize != 0 ) { uint32_t flags = read_uleb128(p, end); - (void)flags; // currently unused - uint64_t address = read_uleb128(p, end); - printf("\tnode%03ld [ label=%s,addr0x%08llX ];\n", (long)(me-start), cummulativeString, address); + if ( flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) { + uint64_t ordinal = read_uleb128(p, end); + const char* importName = (const char*)p; + while (*p != '\0') + ++p; + ++p; + if ( *importName == '\0' ) + printf("\tnode%03ld [ label=%s,re-export from dylib=%llu ];\n", (long)(me-start), cummulativeString, ordinal); + else + printf("\tnode%03ld [ label=%s,re-export %s from dylib=%llu ];\n", (long)(me-start), cummulativeString, importName, ordinal); + } + else { + uint64_t address = read_uleb128(p, end); + printf("\tnode%03ld [ label=%s,addr0x%08llX ];\n", (long)(me-start), cummulativeString, address); + if ( flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER ) + read_uleb128(p, end); + } } else { printf("\tnode%03ld;\n", (long)(me-start)); @@ -1286,6 +1347,276 @@ void DyldInfoPrinter::printExportInfoGraph() } } +template +void DyldInfoPrinter::gatherNodeStarts(const uint8_t* const start, const uint8_t* const end, + const uint8_t* parent, const uint8_t* p, + std::vector& nodeStarts) +{ + nodeStarts.push_back(p-start); + const uint8_t terminalSize = read_uleb128(p, end); + const uint8_t* children = p + terminalSize; + + const uint8_t childrenCount = *children++; + const uint8_t* s = children; + for (uint8_t i=0; i < childrenCount; ++i) { + // skip over edge string + while (*s != '\0') + ++s; + ++s; + uint32_t childNodeOffet = read_uleb128(s, end); + gatherNodeStarts(start, end, start, start+childNodeOffet, nodeStarts); + } +} + + +template +void DyldInfoPrinter::printExportInfoNodes() +{ + if ( (fInfo == NULL) || (fInfo->export_off() == 0) ) { + printf("no compressed export info\n"); + } + else { + const uint8_t* start = (uint8_t*)fHeader + fInfo->export_off(); + const uint8_t* end = &start[fInfo->export_size()]; + std::vector nodeStarts; + gatherNodeStarts(start, end, start, start, nodeStarts); + std::sort(nodeStarts.begin(), nodeStarts.end()); + for (std::vector::const_iterator it=nodeStarts.begin(); it != nodeStarts.end(); ++it) { + printf("0x%04X: ", *it); + const uint8_t* p = start + *it; + uint64_t exportInfoSize = read_uleb128(p, end); + if ( exportInfoSize != 0 ) { + // print terminal info + uint64_t flags = read_uleb128(p, end); + if ( flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) { + uint64_t ordinal = read_uleb128(p, end); + const char* importName = (const char*)p; + while (*p != '\0') + ++p; + ++p; + if ( strlen(importName) == 0 ) + printf("[flags=REEXPORT ordinal=%llu] ", ordinal); + else + printf("[flags=REEXPORT ordinal=%llu import=%s] ", ordinal, importName); + } + else if ( flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER ) { + uint64_t stub = read_uleb128(p, end); + uint64_t resolver = read_uleb128(p, end); + printf("[flags=STUB_AND_RESOLVER stub=0x%06llX resolver=0x%06llX] ", stub, resolver); + } + else { + uint64_t address = read_uleb128(p, end); + if ( (flags & EXPORT_SYMBOL_FLAGS_KIND_MASK) == EXPORT_SYMBOL_FLAGS_KIND_REGULAR ) + 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 + printf("[flags=0x%llX addr=0x%06llX] ", flags, address); + } + } + // print child edges + const uint8_t childrenCount = *p++; + for (uint8_t i=0; i < childrenCount; ++i) { + const char* edgeName = (const char*)p; + while (*p != '\0') + ++p; + ++p; + uint32_t childNodeOffet = read_uleb128(p, end); + printf("%s->0x%04X", edgeName, childNodeOffet); + if ( i < (childrenCount-1) ) + printf(", "); + } + printf("\n"); + } + } +} + + + +template +const uint8_t* DyldInfoPrinter::printSharedRegionInfoForEachULEB128Address(const uint8_t* p, uint8_t kind) +{ + const char* kindStr = "??"; + switch (kind) { + case 1: + kindStr = "32-bit pointer"; + break; + case 2: + 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"; + break; + case 6: + kindStr = "ARM movw"; + break; + case 0x10: + kindStr = "thumb2 movt low high 4 bits=0"; + break; + case 0x11: + kindStr = "thumb2 movt low high 4 bits=1"; + break; + case 0x12: + kindStr = "thumb2 movt low high 4 bits=2"; + break; + case 0x13: + kindStr = "thumb2 movt low high 4 bits=3"; + break; + case 0x14: + kindStr = "thumb2 movt low high 4 bits=4"; + break; + case 0x15: + kindStr = "thumb2 movt low high 4 bits=5"; + break; + case 0x16: + kindStr = "thumb2 movt low high 4 bits=6"; + break; + case 0x17: + kindStr = "thumb2 movt low high 4 bits=7"; + break; + case 0x18: + kindStr = "thumb2 movt low high 4 bits=8"; + break; + case 0x19: + kindStr = "thumb2 movt low high 4 bits=9"; + break; + case 0x1A: + kindStr = "thumb2 movt low high 4 bits=0xA"; + break; + case 0x1B: + kindStr = "thumb2 movt low high 4 bits=0xB"; + break; + case 0x1C: + kindStr = "thumb2 movt low high 4 bits=0xC"; + break; + case 0x1D: + kindStr = "thumb2 movt low high 4 bits=0xD"; + break; + case 0x1E: + kindStr = "thumb2 movt low high 4 bits=0xE"; + break; + case 0x1F: + kindStr = "thumb2 movt low high 4 bits=0xF"; + break; + } + 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); + return p; +} + +template +void DyldInfoPrinter::printSharedRegionInfo() +{ + if ( (fSharedRegionInfo == NULL) || (fSharedRegionInfo->datasize() == 0) ) { + printf("no shared region info\n"); + } + 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); + } + + } +} + +template <> +void DyldInfoPrinter::printFunctionStartLine(uint64_t addr) +{ + if ( addr & 1 ) + printf("0x%0llX [thumb] %s\n", (addr & -2), symbolNameForAddress(addr & -2)); + else + printf("0x%0llX %s\n", addr, symbolNameForAddress(addr)); +} + +template +void DyldInfoPrinter::printFunctionStartLine(uint64_t addr) +{ + printf("0x%0llX %s\n", addr, symbolNameForAddress(addr)); +} + + +template +void DyldInfoPrinter::printFunctionStartsInfo() +{ + if ( (fFunctionStartsInfo == NULL) || (fFunctionStartsInfo->datasize() == 0) ) { + printf("no function starts info\n"); + } + else { + const uint8_t* infoStart = (uint8_t*)fHeader + fFunctionStartsInfo->dataoff(); + const uint8_t* infoEnd = &infoStart[fFunctionStartsInfo->datasize()]; + uint64_t address = fBaseAddress; + for(const uint8_t* p = infoStart; (*p != 0) && (p < infoEnd); ) { + 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 ) { + address += delta; + printFunctionStartLine(address); + more = false; + } + } while (more); + } + } +} + +template +void DyldInfoPrinter::printDylibsInfo() +{ + printf("attributes dependent dylibs\n"); + for(typename std::vector*>::iterator it = fDylibLoadCommands.begin(); it != fDylibLoadCommands.end(); ++it) { + const macho_dylib_command

* dylib = *it; + const char* attribute = ""; + switch ( dylib->cmd() ) { + case LC_LOAD_WEAK_DYLIB: + attribute = "weak_import"; + break; + case LC_REEXPORT_DYLIB: + attribute = "re-export"; + break; + case LC_LOAD_UPWARD_DYLIB: + attribute = "upward"; + break; + case LC_LAZY_LOAD_DYLIB: + attribute = "lazy_load"; + break; + case LC_LOAD_DYLIB: + default: + break; + } + printf(" %-12s %s\n", attribute, dylib->name()); + } +} + template <> ppc::P::uint_t DyldInfoPrinter::relocBase() @@ -1336,8 +1667,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 "??"; } @@ -1465,6 +1794,37 @@ void DyldInfoPrinter::printSymbolTableExportInfo() } } +template +const char* DyldInfoPrinter::symbolNameForAddress(uint64_t addr) +{ + 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 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()]; + } + } + } + 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()]; + } + } + } + + return "?"; +} template void DyldInfoPrinter::printClassicBindingInfo() @@ -1613,36 +1973,37 @@ static void dump(const char* path) size_t size = OSSwapBigToHostInt32(archs[i].size); cpu_type_t cputype = OSSwapBigToHostInt32(archs[i].cputype); cpu_type_t cpusubtype = OSSwapBigToHostInt32(archs[i].cpusubtype); - if ( (cputype == sPreferredArch) - && ((sPreferredSubArch==0) || (sPreferredSubArch==cpusubtype)) ) { + if ( ((cputype == sPreferredArch) + && ((sPreferredSubArch==0) || (sPreferredSubArch==cpusubtype))) + || (sPreferredArch == 0) ) { switch(cputype) { case CPU_TYPE_POWERPC: if ( DyldInfoPrinter::validFile(p + offset) ) - DyldInfoPrinter::make(p + offset, size, path); + DyldInfoPrinter::make(p + offset, size, path, (sPreferredArch == 0)); else throw "in universal file, ppc slice does not contain ppc mach-o"; break; case CPU_TYPE_I386: if ( DyldInfoPrinter::validFile(p + offset) ) - DyldInfoPrinter::make(p + offset, size, path); + DyldInfoPrinter::make(p + offset, size, path, (sPreferredArch == 0)); else throw "in universal file, i386 slice does not contain i386 mach-o"; break; case CPU_TYPE_POWERPC64: if ( DyldInfoPrinter::validFile(p + offset) ) - DyldInfoPrinter::make(p + offset, size, path); + DyldInfoPrinter::make(p + offset, size, path, (sPreferredArch == 0)); else throw "in universal file, ppc64 slice does not contain ppc64 mach-o"; break; case CPU_TYPE_X86_64: if ( DyldInfoPrinter::validFile(p + offset) ) - DyldInfoPrinter::make(p + offset, size, path); + DyldInfoPrinter::make(p + offset, size, path, (sPreferredArch == 0)); else throw "in universal file, x86_64 slice does not contain x86_64 mach-o"; break; case CPU_TYPE_ARM: - if ( DyldInfoPrinter::validFile(p + offset) ) - DyldInfoPrinter::make(p + offset, size, path); + 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; @@ -1653,19 +2014,19 @@ static void dump(const char* path) } } else if ( DyldInfoPrinter::validFile(p) ) { - DyldInfoPrinter::make(p, length, path); + DyldInfoPrinter::make(p, length, path, false); } else if ( DyldInfoPrinter::validFile(p) ) { - DyldInfoPrinter::make(p, length, path); + DyldInfoPrinter::make(p, length, path, false); } else if ( DyldInfoPrinter::validFile(p) ) { - DyldInfoPrinter::make(p, length, path); + DyldInfoPrinter::make(p, length, path, false); } else if ( DyldInfoPrinter::validFile(p) ) { - DyldInfoPrinter::make(p, length, path); + DyldInfoPrinter::make(p, length, path, false); } else if ( DyldInfoPrinter::validFile(p) ) { - DyldInfoPrinter::make(p, length, path); + DyldInfoPrinter::make(p, length, path, false); } else { throw "not a known file type"; @@ -1679,12 +2040,14 @@ static void dump(const char* path) static void usage() { fprintf(stderr, "Usage: dyldinfo [-arch ] \n" + "\t-dylibs print dependent dylibs\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" "\t-lazy_bind print addresses dyld will lazily set on first use\n" "\t-export print addresses of all symbols this file exports\n" "\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" ); } @@ -1712,26 +2075,19 @@ int main(int argc, const char* argv[]) sPreferredArch = CPU_TYPE_I386; else if ( strcmp(arch, "x86_64") == 0 ) sPreferredArch = CPU_TYPE_X86_64; - else if ( strcmp(arch, "arm") == 0 ) - sPreferredArch = CPU_TYPE_ARM; - else if ( strcmp(arch, "armv4t") == 0 ) { - sPreferredArch = CPU_TYPE_ARM; - sPreferredSubArch = CPU_SUBTYPE_ARM_V4T; - } - else if ( strcmp(arch, "armv5") == 0 ) { - sPreferredArch = CPU_TYPE_ARM; - sPreferredSubArch = CPU_SUBTYPE_ARM_V5TEJ; - } - else if ( strcmp(arch, "armv6") == 0 ) { - sPreferredArch = CPU_TYPE_ARM; - sPreferredSubArch = CPU_SUBTYPE_ARM_V6; - } - else if ( strcmp(arch, "armv7") == 0 ) { - sPreferredArch = CPU_TYPE_ARM; - sPreferredSubArch = CPU_SUBTYPE_ARM_V7; + else { + 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; + found = true; + break; + } + } + if ( !found ) + throwf("unknown architecture %s", arch); } - else - throwf("unknown architecture %s", arch); } else if ( strcmp(arg, "-rebase") == 0 ) { printRebase = true; @@ -1754,6 +2110,18 @@ int main(int argc, const char* argv[]) else if ( strcmp(arg, "-export_dot") == 0 ) { printExportGraph = true; } + else if ( strcmp(arg, "-export_trie_nodes") == 0 ) { + printExportNodes = true; + } + else if ( strcmp(arg, "-shared_region") == 0 ) { + printSharedRegion = true; + } + else if ( strcmp(arg, "-function_starts") == 0 ) { + printFunctionStarts = true; + } + else if ( strcmp(arg, "-dylibs") == 0 ) { + printDylibs = true; + } else { throwf("unknown option: %s\n", arg); }