Index: llvm/include/llvm/BinaryFormat/MachO.h =================================================================== --- llvm/include/llvm/BinaryFormat/MachO.h +++ llvm/include/llvm/BinaryFormat/MachO.h @@ -1002,6 +1002,19 @@ uint64_t n_value; }; +// Values for dyld_chained_fixups_header::imports_format. +enum { + DYLD_CHAINED_IMPORT = 1, + DYLD_CHAINED_IMPORT_ADDEND = 2, + DYLD_CHAINED_IMPORT_ADDEND64 = 3, +}; + +// Values for dyld_chained_fixups_header::symbols_format. +enum { + DYLD_CHAINED_SYMBOL_UNCOMPRESSED = 0, + DYLD_CHAINED_SYMBOL_ZLIB = 1, +}; + /// Structs for dyld chained fixups. /// dyld_chained_fixups_header is the data pointed to by LC_DYLD_CHAINED_FIXUPS /// load command. Index: llvm/test/tools/llvm-objdump/MachO/chained-fixups.yaml =================================================================== --- llvm/test/tools/llvm-objdump/MachO/chained-fixups.yaml +++ llvm/test/tools/llvm-objdump/MachO/chained-fixups.yaml @@ -1,10 +1,25 @@ # RUN: yaml2obj %s -o %t # RUN: llvm-objdump -p %t | FileCheck %s # RUN: llvm-otool -l %t | FileCheck %s -# + # CHECK: LC_DYLD_CHAINED_FIXUPS # CHECK: LC_DYLD_EXPORTS_TRIE +# RUN: llvm-objdump --macho --chained-fixups %t | \ +# RUN: FileCheck --check-prefix=DETAILS -DNAME=%t %s +# RUN: llvm-otool -chained_fixups %t | \ +# RUN: FileCheck --check-prefix=DETAILS -DNAME=%t %s + +# DETAILS: [[NAME]]: +# DETAILS-NEXT: chained fixups header (LC_DYLD_CHAINED_FIXUPS) +# DETAILS-NEXT: fixups_version = 0 +# DETAILS-NEXT: starts_offset = 0 +# DETAILS-NEXT: imports_offset = 0 +# DETAILS-NEXT: symbols_offset = 0 +# DETAILS-NEXT: imports_count = 0 +# DETAILS-NEXT: imports_format = 0 +# DETAILS-NEXT: symbols_format = 0 + --- !mach-o FileHeader: magic: 0xFEEDFACF Index: llvm/tools/llvm-objdump/MachODump.h =================================================================== --- llvm/tools/llvm-objdump/MachODump.h +++ llvm/tools/llvm-objdump/MachODump.h @@ -36,6 +36,7 @@ extern bool Bind; extern bool DataInCode; extern std::string DisSymName; +extern bool ChainedFixups; extern bool DyldInfo; extern bool DylibId; extern bool DylibsUsed; Index: llvm/tools/llvm-objdump/MachODump.cpp =================================================================== --- llvm/tools/llvm-objdump/MachODump.cpp +++ llvm/tools/llvm-objdump/MachODump.cpp @@ -81,6 +81,7 @@ bool objdump::FunctionStarts; bool objdump::LinkOptHints; bool objdump::InfoPlist; +bool objdump::ChainedFixups; bool objdump::DyldInfo; bool objdump::DylibsUsed; bool objdump::DylibId; @@ -112,6 +113,7 @@ FunctionStarts = InputArgs.hasArg(OBJDUMP_function_starts); LinkOptHints = InputArgs.hasArg(OBJDUMP_link_opt_hints); InfoPlist = InputArgs.hasArg(OBJDUMP_info_plist); + ChainedFixups = InputArgs.hasArg(OBJDUMP_chained_fixups); DyldInfo = InputArgs.hasArg(OBJDUMP_dyld_info); DylibsUsed = InputArgs.hasArg(OBJDUMP_dylibs_used); DylibId = InputArgs.hasArg(OBJDUMP_dylib_id); @@ -1193,6 +1195,48 @@ reportError(std::move(Err), Obj->getFileName()); } +static void +PrintChainedFixupsHeader(const MachO::dyld_chained_fixups_header &H) { + outs() << "chained fixups header (LC_DYLD_CHAINED_FIXUPS)\n"; + outs() << " fixups_version = " << H.fixups_version << '\n'; + outs() << " starts_offset = " << H.starts_offset << '\n'; + outs() << " imports_offset = " << H.imports_offset << '\n'; + outs() << " symbols_offset = " << H.symbols_offset << '\n'; + outs() << " imports_count = " << H.imports_count << '\n'; + + outs() << " imports_format = " << H.imports_format; + switch (H.imports_format) { + case llvm::MachO::DYLD_CHAINED_IMPORT: + outs() << " (DYLD_CHAINED_IMPORT)"; + break; + case llvm::MachO::DYLD_CHAINED_IMPORT_ADDEND: + outs() << " (DYLD_CHAINED_IMPORT_ADDEND)"; + break; + case llvm::MachO::DYLD_CHAINED_IMPORT_ADDEND64: + outs() << " (DYLD_CHAINED_IMPORT_ADDEND64)"; + break; + } + outs() << '\n'; + + outs() << " symbols_format = " << H.symbols_format; + if (H.symbols_format == llvm::MachO::DYLD_CHAINED_SYMBOL_ZLIB) + outs() << " (zlib compressed)"; + outs() << '\n'; +} + +static void PrintChainedFixups(MachOObjectFile *O) { + // MachOObjectFile::getChainedFixupsHeader() reads LC_DYLD_CHAINED_FIXUPS. + // FIXME: Support chained fixups in __TEXT,__chain_starts section too. + auto ChainedFixupHeader = + unwrapOrError(O->getChainedFixupsHeader(), O->getFileName()); + if (!ChainedFixupHeader) + return; + + PrintChainedFixupsHeader(*ChainedFixupHeader); + + // FIXME: Print more things. +} + static void PrintDyldInfo(MachOObjectFile *O) { outs() << "dyld information:" << '\n'; printMachOChainedFixups(O); @@ -1916,8 +1960,9 @@ // UniversalHeaders or ArchiveHeaders. if (Disassemble || Relocations || PrivateHeaders || ExportsTrie || Rebase || Bind || SymbolTable || LazyBind || WeakBind || IndirectSymbols || - DataInCode || FunctionStarts || LinkOptHints || DyldInfo || DylibsUsed || - DylibId || Rpaths || ObjcMetaData || (!FilterSections.empty())) { + DataInCode || FunctionStarts || LinkOptHints || ChainedFixups || + DyldInfo || DylibsUsed || DylibId || Rpaths || ObjcMetaData || + (!FilterSections.empty())) { if (LeadingHeaders) { outs() << Name; if (!ArchiveMemberName.empty()) @@ -1986,6 +2031,8 @@ DumpSectionContents(FileName, MachOOF, Verbose); if (InfoPlist) DumpInfoPlistSectionContents(FileName, MachOOF); + if (ChainedFixups) + PrintChainedFixups(MachOOF); if (DyldInfo) PrintDyldInfo(MachOOF); if (DylibsUsed) Index: llvm/tools/llvm-objdump/ObjdumpOpts.td =================================================================== --- llvm/tools/llvm-objdump/ObjdumpOpts.td +++ llvm/tools/llvm-objdump/ObjdumpOpts.td @@ -299,11 +299,15 @@ "Mach-O objects (requires --macho)">, Group; +def chained_fixups : Flag<["--"], "chained-fixups">, + HelpText<"Print chained fixup information (requires --macho)">, + Group; + def dyld_info : Flag<["--"], "dyld_info">, - HelpText<"Print bind and rebase information used by dyld to resolve " - "external references in a final linked binary " - "(requires --macho)">, - Group; + HelpText<"Print bind and rebase information used by dyld to resolve " + "external references in a final linked binary " + "(requires --macho)">, + Group; def dylibs_used : Flag<["--"], "dylibs-used">, HelpText<"Print the shared libraries used for linked " Index: llvm/tools/llvm-objdump/OtoolOpts.td =================================================================== --- llvm/tools/llvm-objdump/OtoolOpts.td +++ llvm/tools/llvm-objdump/OtoolOpts.td @@ -37,13 +37,15 @@ def x : Flag<["-"], "x">, HelpText<"print all text sections">; def X : Flag<["-"], "X">, HelpText<"omit leading addresses or headers">; +def chained_fixups : Flag<["-"], "chained_fixups">, + HelpText<"print chained fixup information">; + // Not (yet?) implemented: // def a : Flag<["-"], "a">, HelpText<"print archive header">; // -c print argument strings of a core file // -m don't use archive(member) syntax // -dyld_info // -dyld_opcodes -// -chained_fixups // -addr_slide=arg // -function_offsets Index: llvm/tools/llvm-objdump/llvm-objdump.cpp =================================================================== --- llvm/tools/llvm-objdump/llvm-objdump.cpp +++ llvm/tools/llvm-objdump/llvm-objdump.cpp @@ -2787,6 +2787,8 @@ FilterSections.push_back(",__text"); LeadingAddr = LeadingHeaders = !InputArgs.hasArg(OTOOL_X); + ChainedFixups = InputArgs.hasArg(OTOOL_chained_fixups); + InputFilenames = InputArgs.getAllArgValues(OTOOL_INPUT); if (InputFilenames.empty()) reportCmdLineError("no input file"); @@ -2990,11 +2992,12 @@ !DynamicRelocations && !FileHeaders && !PrivateHeaders && !RawClangAST && !Relocations && !SectionHeaders && !SectionContents && !SymbolTable && !DynamicSymbolTable && !UnwindInfo && !FaultMapSection && !Offloading && - !(MachOOpt && (Bind || DataInCode || DyldInfo || DylibId || DylibsUsed || - ExportsTrie || FirstPrivateHeader || FunctionStarts || - IndirectSymbols || InfoPlist || LazyBind || LinkOptHints || - ObjcMetaData || Rebase || Rpaths || UniversalHeaders || - WeakBind || !FilterSections.empty()))) { + !(MachOOpt && + (Bind || DataInCode || ChainedFixups || DyldInfo || DylibId || + DylibsUsed || ExportsTrie || FirstPrivateHeader || FunctionStarts || + IndirectSymbols || InfoPlist || LazyBind || LinkOptHints || + ObjcMetaData || Rebase || Rpaths || UniversalHeaders || WeakBind || + !FilterSections.empty()))) { T->printHelp(ToolName); return 2; }