diff --git a/llvm/include/llvm/BinaryFormat/MachO.h b/llvm/include/llvm/BinaryFormat/MachO.h index ac1af5dafb9e..cdc8792e7b2d 100644 --- a/llvm/include/llvm/BinaryFormat/MachO.h +++ b/llvm/include/llvm/BinaryFormat/MachO.h @@ -1015,6 +1015,29 @@ enum { DYLD_CHAINED_SYMBOL_ZLIB = 1, }; +// Values for dyld_chained_starts_in_segment::page_start. +enum { + DYLD_CHAINED_PTR_START_NONE = 0xFFFF, + DYLD_CHAINED_PTR_START_MULTI = 0x8000, + DYLD_CHAINED_PTR_START_LAST = 0x8000, +}; + +// Values for dyld_chained_starts_in_segment::pointer_format. +enum { + DYLD_CHAINED_PTR_ARM64E = 1, + DYLD_CHAINED_PTR_64 = 2, + DYLD_CHAINED_PTR_32 = 3, + DYLD_CHAINED_PTR_32_CACHE = 4, + DYLD_CHAINED_PTR_32_FIRMWARE = 5, + DYLD_CHAINED_PTR_64_OFFSET = 6, + DYLD_CHAINED_PTR_ARM64E_KERNEL = 7, + DYLD_CHAINED_PTR_64_KERNEL_CACHE = 8, + DYLD_CHAINED_PTR_ARM64E_USERLAND = 9, + DYLD_CHAINED_PTR_ARM64E_FIRMWARE = 10, + DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE = 11, + DYLD_CHAINED_PTR_ARM64E_USERLAND24 = 12, +}; + /// Structs for dyld chained fixups. /// dyld_chained_fixups_header is the data pointed to by LC_DYLD_CHAINED_FIXUPS /// load command. @@ -1032,10 +1055,21 @@ struct dyld_chained_fixups_header { /// Each each seg_info_offset entry is the offset into this struct for that /// segment followed by pool of dyld_chain_starts_in_segment data. struct dyld_chained_starts_in_image { - uint32_t seg_count; - uint32_t seg_info_offset[1]; + uint32_t seg_count; + uint32_t seg_info_offset[1]; }; - + +struct dyld_chained_starts_in_segment { + uint32_t size; ///< Size of this, including chain_starts entries + uint16_t page_size; ///< Page size in bytes (0x1000 or 0x4000) + uint16_t pointer_format; ///< DYLD_CHAINED_PTR* + uint64_t segment_offset; ///< VM offset from the __TEXT segment + uint32_t max_valid_pointer; ///< Values beyond this are not pointers on 32-bit + uint16_t page_count; ///< Length of the page_start array + uint16_t page_start[1]; ///< Page offset of first fixup on each page, or + ///< DYLD_CHAINED_PTR_START_NONE if no fixups +}; + // Byte order swapping functions for MachO structs inline void swapStruct(fat_header &mh) { @@ -2053,6 +2087,22 @@ inline void swapStruct(dyld_chained_fixups_header &C) { sys::swapByteOrder(C.symbols_format); } +inline void swapStruct(dyld_chained_starts_in_image &C) { + sys::swapByteOrder(C.seg_count); + // getStructOrErr() cannot copy the variable-length seg_info_offset array. + // Its elements must be byte swapped manually. +} + +inline void swapStruct(dyld_chained_starts_in_segment &C) { + sys::swapByteOrder(C.size); + sys::swapByteOrder(C.page_size); + sys::swapByteOrder(C.pointer_format); + sys::swapByteOrder(C.segment_offset); + sys::swapByteOrder(C.max_valid_pointer); + sys::swapByteOrder(C.page_count); + // seg_info_offset entries must be byte swapped manually. +} + /* code signing attributes of a process */ enum CodeSignAttrs { diff --git a/llvm/include/llvm/Object/MachO.h b/llvm/include/llvm/Object/MachO.h index 4ec366055db6..be44388943fa 100644 --- a/llvm/include/llvm/Object/MachO.h +++ b/llvm/include/llvm/Object/MachO.h @@ -685,10 +685,33 @@ public: ArrayRef getDyldInfoBindOpcodes() const; ArrayRef getDyldInfoWeakBindOpcodes() const; ArrayRef getDyldInfoLazyBindOpcodes() const; - /// If the optional is None, no header was found, but the object was well-formed. + /// If the optional is None, no header was found, but the object was + /// well-formed. Expected> getChainedFixupsHeader() const; Expected> getDyldChainedFixupTargets() const; + + // Note: This is a limited, temporary API, which will be removed when Apple + // upstreams their implementation. Please do not rely on this. + Expected> + getChainedFixupsLoadCommand() const; + struct ChainedFixupsSegment { + ChainedFixupsSegment(uint8_t SegIdx, uint32_t Offset, + const MachO::dyld_chained_starts_in_segment &Header, + std::vector &&PageStarts) + : SegIdx(SegIdx), Offset(Offset), Header(Header), + PageStarts(PageStarts){}; + + uint32_t SegIdx; + uint32_t Offset; // dyld_chained_starts_in_image::seg_info_offset[SegIdx] + MachO::dyld_chained_starts_in_segment Header; + std::vector PageStarts; // page_start[] entries, host endianness + }; + // Returns the number of sections listed in dyld_chained_starts_in_image, and + // a ChainedFixupsSegment for each segment that has fixups. + Expected>> + getChainedFixupsSegments() const; + ArrayRef getDyldInfoExportsTrie() const; SmallVector getFunctionStarts() const; ArrayRef getUuid() const; diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp index 2f463a1bd458..d7e9b57923b8 100644 --- a/llvm/lib/Object/MachOObjectFile.cpp +++ b/llvm/lib/Object/MachOObjectFile.cpp @@ -4756,7 +4756,7 @@ ArrayRef MachOObjectFile::getDyldInfoLazyBindOpcodes() const { return None; auto DyldInfoOrErr = - getStructOrErr(*this, DyldInfoLoadCmd); + getStructOrErr(*this, DyldInfoLoadCmd); if (!DyldInfoOrErr) return None; MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get(); @@ -4765,8 +4765,8 @@ ArrayRef MachOObjectFile::getDyldInfoLazyBindOpcodes() const { return makeArrayRef(Ptr, DyldInfo.lazy_bind_size); } -Expected> -MachOObjectFile::getChainedFixupsHeader() const { +Expected> +MachOObjectFile::getChainedFixupsLoadCommand() const { // Load the dyld chained fixups load command. if (!DyldChainedFixupsLoadCmd) return llvm::None; @@ -4774,13 +4774,28 @@ MachOObjectFile::getChainedFixupsHeader() const { *this, DyldChainedFixupsLoadCmd); if (!DyldChainedFixupsOrErr) return DyldChainedFixupsOrErr.takeError(); - MachO::linkedit_data_command DyldChainedFixups = DyldChainedFixupsOrErr.get(); + const MachO::linkedit_data_command &DyldChainedFixups = + *DyldChainedFixupsOrErr; // If the load command is present but the data offset has been zeroed out, // as is the case for dylib stubs, return None (no error). + if (!DyldChainedFixups.dataoff) + return llvm::None; + return DyldChainedFixups; +} + +Expected> +MachOObjectFile::getChainedFixupsHeader() const { + auto CFOrErr = getChainedFixupsLoadCommand(); + if (!CFOrErr) + return CFOrErr.takeError(); + if (!CFOrErr->has_value()) + return llvm::None; + + const MachO::linkedit_data_command &DyldChainedFixups = **CFOrErr; + uint64_t CFHeaderOffset = DyldChainedFixups.dataoff; - if (CFHeaderOffset == 0) - return DyldChainedFixupsOrErr.takeError(); + uint64_t CFSize = DyldChainedFixups.datasize; // Load the dyld chained fixups header. const char *CFHeaderPtr = getPtr(*this, CFHeaderOffset); @@ -4808,7 +4823,7 @@ MachOObjectFile::getChainedFixupsHeader() const { Twine(CFHeader.starts_offset) + " overlaps with chained fixups header"); } - uint32_t EndOffset = DyldChainedFixups.dataoff + DyldChainedFixups.datasize; + uint32_t EndOffset = CFHeaderOffset + CFSize; if (CFImageStartsOffset + sizeof(MachO::dyld_chained_starts_in_image) > EndOffset) { return malformedError(Twine("bad chained fixups: image starts end ") + @@ -4820,6 +4835,95 @@ MachOObjectFile::getChainedFixupsHeader() const { return CFHeader; } +Expected>> +MachOObjectFile::getChainedFixupsSegments() const { + auto CFOrErr = getChainedFixupsLoadCommand(); + if (!CFOrErr) + return CFOrErr.takeError(); + + std::vector Segments; + if (!CFOrErr->has_value()) + return std::make_pair(0, Segments); + + const MachO::linkedit_data_command &DyldChainedFixups = **CFOrErr; + + auto HeaderOrErr = getChainedFixupsHeader(); + if (!HeaderOrErr) + return HeaderOrErr.takeError(); + if (!HeaderOrErr->has_value()) + return std::make_pair(0, Segments); + const MachO::dyld_chained_fixups_header &Header = **HeaderOrErr; + + const char *Contents = getPtr(*this, DyldChainedFixups.dataoff); + + auto ImageStartsOrErr = getStructOrErr( + *this, Contents + Header.starts_offset); + if (!ImageStartsOrErr) + return ImageStartsOrErr.takeError(); + const MachO::dyld_chained_starts_in_image &ImageStarts = *ImageStartsOrErr; + + const char *SegOffsPtr = + Contents + Header.starts_offset + + offsetof(MachO::dyld_chained_starts_in_image, seg_info_offset); + const char *SegOffsEnd = + SegOffsPtr + ImageStarts.seg_count * sizeof(uint32_t); + if (SegOffsEnd > Contents + DyldChainedFixups.datasize) + return malformedError( + "bad chained fixups: seg_info_offset extends past end"); + + const char *LastSegEnd = nullptr; + for (size_t I = 0, N = ImageStarts.seg_count; I < N; ++I) { + auto OffOrErr = + getStructOrErr(*this, SegOffsPtr + I * sizeof(uint32_t)); + if (!OffOrErr) + return OffOrErr.takeError(); + // seg_info_offset == 0 means there is no associated starts_in_segment + // entry. + if (!*OffOrErr) + continue; + + auto Fail = [&](Twine Message) { + return malformedError("bad chained fixups: segment info" + Twine(I) + + " at offset " + Twine(*OffOrErr) + Message); + }; + + const char *SegPtr = Contents + Header.starts_offset + *OffOrErr; + if (LastSegEnd && SegPtr < LastSegEnd) + return Fail(" overlaps with previous segment info"); + + auto SegOrErr = + getStructOrErr(*this, SegPtr); + if (!SegOrErr) + return SegOrErr.takeError(); + const MachO::dyld_chained_starts_in_segment &Seg = *SegOrErr; + + LastSegEnd = SegPtr + Seg.size; + if (Seg.pointer_format < 1 || Seg.pointer_format > 12) + return Fail(" has unknown pointer format: " + Twine(Seg.pointer_format)); + + const char *PageStart = + SegPtr + offsetof(MachO::dyld_chained_starts_in_segment, page_start); + const char *PageEnd = PageStart + Seg.page_count * sizeof(uint16_t); + if (PageEnd > SegPtr + Seg.size) + return Fail(" : page_starts extend past seg_info size"); + + // FIXME: This does not account for multiple offsets on a single page + // (DYLD_CHAINED_PTR_START_MULTI; 32-bit only). + std::vector PageStarts; + for (size_t PageIdx = 0; PageIdx < Seg.page_count; ++PageIdx) { + uint16_t Start; + memcpy(&Start, PageStart + PageIdx * sizeof(uint16_t), sizeof(uint16_t)); + if (isLittleEndian() != sys::IsLittleEndianHost) + sys::swapByteOrder(Start); + PageStarts.push_back(Start); + } + + Segments.emplace_back(I, *OffOrErr, Seg, std::move(PageStarts)); + } + + return std::make_pair(ImageStarts.seg_count, Segments); +} + Expected> MachOObjectFile::getDyldChainedFixupTargets() const { auto CFHeaderOrErr = getChainedFixupsHeader(); diff --git a/llvm/test/tools/llvm-objdump/MachO/Inputs/chained-fixups.macho-x86_64 b/llvm/test/tools/llvm-objdump/MachO/Inputs/chained-fixups.macho-x86_64 new file mode 100755 index 000000000000..c8e0c9b13dbe Binary files /dev/null and b/llvm/test/tools/llvm-objdump/MachO/Inputs/chained-fixups.macho-x86_64 differ diff --git a/llvm/test/tools/llvm-objdump/MachO/chained-fixups.test b/llvm/test/tools/llvm-objdump/MachO/chained-fixups.test new file mode 100644 index 000000000000..72460fb8a340 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/MachO/chained-fixups.test @@ -0,0 +1,86 @@ +RUN: llvm-objdump -p %p/Inputs/chained-fixups.macho-x86_64 | FileCheck %s +RUN: llvm-otool -l %p/Inputs/chained-fixups.macho-x86_64 | FileCheck %s + +CHECK: LC_DYLD_CHAINED_FIXUPS +CHECK: LC_DYLD_EXPORTS_TRIE + +RUN: llvm-objdump --macho --chained-fixups %p/Inputs/chained-fixups.macho-x86_64 | \ +RUN: FileCheck --check-prefix=DETAILS -DNAME=%p/Inputs/chained-fixups.macho-x86_64 %s +RUN: llvm-otool -chained_fixups %p/Inputs/chained-fixups.macho-x86_64 | \ +RUN: FileCheck --check-prefix=DETAILS -DNAME=%p/Inputs/chained-fixups.macho-x86_64 %s + +DETAILS: [[NAME]]: +DETAILS-NEXT: chained fixups header (LC_DYLD_CHAINED_FIXUPS) +DETAILS-NEXT: fixups_version = 0 +DETAILS-NEXT: starts_offset = 32 +DETAILS-NEXT: imports_offset = 112 +DETAILS-NEXT: symbols_offset = 132 +DETAILS-NEXT: imports_count = 5 +DETAILS-NEXT: imports_format = 1 (DYLD_CHAINED_IMPORT) +DETAILS-NEXT: symbols_format = 0 +DETAILS-NEXT: chained starts in image +DETAILS-NEXT: seg_count = 4 +DETAILS-NEXT: seg_offset[0] = 0 (__TEXT) +DETAILS-NEXT: seg_offset[1] = 24 (__DATA_CONST) +DETAILS-NEXT: seg_offset[2] = 48 (__DATA) +DETAILS-NEXT: seg_offset[3] = 0 (__LINKEDIT) +DETAILS-NEXT: chained starts in segment 1 (__DATA_CONST) +DETAILS-NEXT: size = 24 +DETAILS-NEXT: page_size = 0x1000 +DETAILS-NEXT: pointer_format = 6 (DYLD_CHAINED_PTR_64_OFFSET) +DETAILS-NEXT: segment_offset = 0x3e0 +DETAILS-NEXT: max_valid_pointer = 0 +DETAILS-NEXT: page_count = 1 +DETAILS-NEXT: page_start[0] = 0 +DETAILS-NEXT: chained starts in segment 2 (__DATA) +DETAILS-NEXT: size = 30 +DETAILS-NEXT: page_size = 0x1000 +DETAILS-NEXT: pointer_format = 6 (DYLD_CHAINED_PTR_64_OFFSET) +DETAILS-NEXT: segment_offset = 0x3f0 +DETAILS-NEXT: max_valid_pointer = 0 +DETAILS-NEXT: page_count = 4 +DETAILS-NEXT: page_start[0] = 0 +DETAILS-NEXT: page_start[1] = 32 +DETAILS-NEXT: page_start[2] = 65535 (DYLD_CHAINED_PTR_START_NONE) +DETAILS-NEXT: page_start[3] = 32 + +## This test checks that the output is identical to that of cctools-1001.2 (XCode 14) +## The input was generated from the following files: +## +## --- dylib.s: +## .data +## .globl _weak, _dylib, _weakImport +## .weak_definition _weak +## _weak: +## _dylib: +## _weakImport: +## +## $ clang --target=x86_64-apple-macos12 -dynamiclib dylib.s -o libdylib.dylib +## +## --- chained-fixups.s: +## .global _local, _weak, _weakLocal, _dylib, _weakImport, _dynamicLookup +## .weak_definition _weakLocal +## .weak_reference _weakImport +## +## .data +## .p2align 4 +## _local: +## _weakLocal: +## .quad _local +## .space 8 +## .quad _weak +## .space 4096 +## .p2align 4 +## .quad _weakLocal +## .space 8172 +## .p2align 4 +## .quad _dylib +## .quad _dylib + 42 +## +## .section __DATA_CONST,__const +## .p2align 4 +## .quad _weakImport +## .quad _dynamicLookup +## +## $ clang --target=x86_64-apple-macos12 -dynamiclib -L. -ldylib chained-fixups.s \ +## -o chained-fixups.macho-x86_64 -Wl,-segalign,0x10 -Wl,-U,_dynamicLookup diff --git a/llvm/test/tools/llvm-objdump/MachO/chained-fixups.yaml b/llvm/test/tools/llvm-objdump/MachO/chained-fixups.yaml deleted file mode 100644 index 63f3fd54a222..000000000000 --- a/llvm/test/tools/llvm-objdump/MachO/chained-fixups.yaml +++ /dev/null @@ -1,151 +0,0 @@ -# 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 = 32 -# DETAILS-NEXT: imports_offset = 44 -# DETAILS-NEXT: symbols_offset = 44 -# DETAILS-NEXT: imports_count = 0 -# DETAILS-NEXT: imports_format = 1 (DYLD_CHAINED_IMPORT) -# DETAILS-NEXT: symbols_format = 0 - -## This yaml is from a dylib produced by ld64 -## echo ".global _foo\n_foo" > dylib.s -## clang -target=x86_64-apple-macos12 -dynamiclib -isysroot Inputs/MacOSX.sdk dylib.s -o libdylib.dylib -## obj2yaml --raw-segment=data libdylib.dylib ---- !mach-o -IsLittleEndian: true -FileHeader: - magic: 0xFEEDFACF - cputype: 0x1000007 - cpusubtype: 0x3 - filetype: 0x6 - ncmds: 13 - sizeofcmds: 568 - flags: 0x100085 - reserved: 0x0 -LoadCommands: - - cmd: LC_SEGMENT_64 - cmdsize: 152 - segname: __TEXT - vmaddr: 0 - vmsize: 16384 - fileoff: 0 - filesize: 16384 - maxprot: 5 - initprot: 5 - nsects: 1 - flags: 0 - Sections: - - sectname: __text - segname: __TEXT - addr: 0x4000 - size: 0 - offset: 0x4000 - align: 0 - reloff: 0x0 - nreloc: 0 - flags: 0x80000400 - reserved1: 0x0 - reserved2: 0x0 - reserved3: 0x0 - content: '' - - cmd: LC_SEGMENT_64 - cmdsize: 72 - segname: __LINKEDIT - vmaddr: 16384 - vmsize: 16384 - fileoff: 16384 - filesize: 96 - maxprot: 1 - initprot: 1 - nsects: 0 - flags: 0 - - cmd: LC_ID_DYLIB - cmdsize: 48 - dylib: - name: 24 - timestamp: 1 - current_version: 0 - compatibility_version: 0 - Content: libdylib.dylib - ZeroPadBytes: 3 - - cmd: LC_DYLD_CHAINED_FIXUPS - cmdsize: 16 - dataoff: 16384 - datasize: 48 - - cmd: LC_DYLD_EXPORTS_TRIE - cmdsize: 16 - dataoff: 16432 - datasize: 16 - - cmd: LC_SYMTAB - cmdsize: 24 - symoff: 16456 - nsyms: 1 - stroff: 16472 - strsize: 8 - - cmd: LC_DYSYMTAB - cmdsize: 80 - ilocalsym: 0 - nlocalsym: 0 - iextdefsym: 0 - nextdefsym: 1 - iundefsym: 1 - nundefsym: 0 - tocoff: 0 - ntoc: 0 - modtaboff: 0 - nmodtab: 0 - extrefsymoff: 0 - nextrefsyms: 0 - indirectsymoff: 0 - nindirectsyms: 0 - extreloff: 0 - nextrel: 0 - locreloff: 0 - nlocrel: 0 - - cmd: LC_UUID - cmdsize: 24 - uuid: 52409B91-DF59-346A-A63F-D4E6FFDC3E04 - - cmd: LC_BUILD_VERSION - cmdsize: 32 - platform: 1 - minos: 786432 - sdk: 851968 - ntools: 1 - Tools: - - tool: 3 - version: 53674242 - - cmd: LC_SOURCE_VERSION - cmdsize: 16 - version: 0 - - cmd: LC_LOAD_DYLIB - cmdsize: 56 - dylib: - name: 24 - timestamp: 2 - current_version: 65793 - compatibility_version: 65536 - Content: '/usr/lib/libSystem.dylib' - ZeroPadBytes: 8 - - cmd: LC_FUNCTION_STARTS - cmdsize: 16 - dataoff: 16448 - datasize: 8 - - cmd: LC_DATA_IN_CODE - cmdsize: 16 - dataoff: 16456 - datasize: 0 -__LINKEDIT: 00000000200000002C0000002C000000000000000100000000000000000000000200000000000000000000000000000000015F666F6F000804008080010000000000000000000000020000000F010000004000000000000020005F666F6F0000 -... diff --git a/llvm/tools/llvm-objdump/MachODump.cpp b/llvm/tools/llvm-objdump/MachODump.cpp index a2593cffb4d8..d95b1c4f5fd3 100644 --- a/llvm/tools/llvm-objdump/MachODump.cpp +++ b/llvm/tools/llvm-objdump/MachODump.cpp @@ -1195,6 +1195,20 @@ static void printMachOChainedFixups(object::MachOObjectFile *Obj) { reportError(std::move(Err), Obj->getFileName()); } +static SmallVector GetSegmentNames(object::MachOObjectFile *O) { + SmallVector Ret; + for (const MachOObjectFile::LoadCommandInfo &Command : O->load_commands()) { + if (Command.C.cmd == MachO::LC_SEGMENT) { + MachO::segment_command SLC = O->getSegmentLoadCommand(Command); + Ret.push_back(SLC.segname); + } else if (Command.C.cmd == MachO::LC_SEGMENT_64) { + MachO::segment_command_64 SLC = O->getSegment64LoadCommand(Command); + Ret.push_back(SLC.segname); + } + } + return Ret; +} + static void PrintChainedFixupsHeader(const MachO::dyld_chained_fixups_header &H) { outs() << "chained fixups header (LC_DYLD_CHAINED_FIXUPS)\n"; @@ -1224,6 +1238,50 @@ PrintChainedFixupsHeader(const MachO::dyld_chained_fixups_header &H) { outs() << '\n'; } +static constexpr std::array PointerFormats{ + "DYLD_CHAINED_PTR_ARM64E", + "DYLD_CHAINED_PTR_64", + "DYLD_CHAINED_PTR_32", + "DYLD_CHAINED_PTR_32_CACHE", + "DYLD_CHAINED_PTR_32_FIRMWARE", + "DYLD_CHAINED_PTR_64_OFFSET", + "DYLD_CHAINED_PTR_ARM64E_KERNEL", + "DYLD_CHAINED_PTR_64_KERNEL_CACHE", + "DYLD_CHAINED_PTR_ARM64E_USERLAND", + "DYLD_CHAINED_PTR_ARM64E_FIRMWARE", + "DYLD_CHAINED_PTR_X86_64_KERNEL_CACHE", + "DYLD_CHAINED_PTR_ARM64E_USERLAND24", +}; + +static void +PrintChainedFixupsSegment(const MachOObjectFile::ChainedFixupsSegment &Segment, + StringRef SegName) { + outs() << "chained starts in segment " << Segment.SegIdx << " (" << SegName + << ")\n"; + outs() << " size = " << Segment.Header.size << '\n'; + outs() << " page_size = " << format("0x%0" PRIx16, Segment.Header.page_size) + << '\n'; + + outs() << " pointer_format = " << Segment.Header.pointer_format; + if ((Segment.Header.pointer_format - 1) < + MachO::DYLD_CHAINED_PTR_ARM64E_USERLAND24) + outs() << " (" << PointerFormats[Segment.Header.pointer_format - 1] << ")"; + outs() << '\n'; + + outs() << " segment_offset = " + << format("0x%0" PRIx64, Segment.Header.segment_offset) << '\n'; + outs() << " max_valid_pointer = " << Segment.Header.max_valid_pointer + << '\n'; + outs() << " page_count = " << Segment.Header.page_count << '\n'; + for (auto [Index, PageStart] : enumerate(Segment.PageStarts)) { + outs() << " page_start[" << Index << "] = " << PageStart; + // FIXME: Support DYLD_CHAINED_PTR_START_MULTI (32-bit only) + if (PageStart == MachO::DYLD_CHAINED_PTR_START_NONE) + outs() << " (DYLD_CHAINED_PTR_START_NONE)"; + outs() << '\n'; + } +} + static void PrintChainedFixups(MachOObjectFile *O) { // MachOObjectFile::getChainedFixupsHeader() reads LC_DYLD_CHAINED_FIXUPS. // FIXME: Support chained fixups in __TEXT,__chain_starts section too. @@ -1234,6 +1292,28 @@ static void PrintChainedFixups(MachOObjectFile *O) { PrintChainedFixupsHeader(*ChainedFixupHeader); + auto [SegCount, Segments] = + unwrapOrError(O->getChainedFixupsSegments(), O->getFileName()); + + auto SegNames = GetSegmentNames(O); + + size_t StartsIdx = 0; + outs() << "chained starts in image\n"; + outs() << " seg_count = " << SegCount << '\n'; + for (size_t I = 0; I < SegCount; ++I) { + uint64_t SegOffset = 0; + if (StartsIdx < Segments.size() && I == Segments[StartsIdx].SegIdx) { + SegOffset = Segments[StartsIdx].Offset; + ++StartsIdx; + } + + outs() << " seg_offset[" << I << "] = " << SegOffset << " (" + << SegNames[I] << ")\n"; + } + + for (const MachOObjectFile::ChainedFixupsSegment &S : Segments) + PrintChainedFixupsSegment(S, SegNames[S.SegIdx]); + // FIXME: Print more things. }