[llvm] 11443ef - [llvm-objdump] Support dumping segment information with -chained_fixups

Daniel Bertalan via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 18 00:39:19 PDT 2022


Author: Daniel Bertalan
Date: 2022-08-18T09:29:27+02:00
New Revision: 11443ef85dbe4f3930f726b1be4d7f90f99d1021

URL: https://github.com/llvm/llvm-project/commit/11443ef85dbe4f3930f726b1be4d7f90f99d1021
DIFF: https://github.com/llvm/llvm-project/commit/11443ef85dbe4f3930f726b1be4d7f90f99d1021.diff

LOG: [llvm-objdump] Support dumping segment information with -chained_fixups

This commit adds the definitions for `dyld_chained_starts_in_image`,
`dyld_chained_starts_in_segment`, and related enums. Dumping their
contents is possible with the -chained_fixups flag of llvm-otool.

The chained-fixups.yaml test was changed to cover bindings/rebases, as
well as weak imports, weak symbols and flat namespace symbols. Now that
we have actual fixup entries, the __DATA segment contains data that
would need to be hexdumped in YAML. We also test empty pages (to look
for the "DYLD_CHAINED_PTR_START_NONE" annotation), so the YAML would end
up quite large. So instead, this commit includes a binary file.

When Apple's effort to upstream their chained fixups code continues,
we'll replace this code with the then-upstreamed code. But we need
something in the meantime for testing ld64.lld's chained fixups code.

Differential Revision: https://reviews.llvm.org/D131961

Added: 
    llvm/test/tools/llvm-objdump/MachO/Inputs/chained-fixups.macho-x86_64
    llvm/test/tools/llvm-objdump/MachO/chained-fixups.test

Modified: 
    llvm/include/llvm/BinaryFormat/MachO.h
    llvm/include/llvm/Object/MachO.h
    llvm/lib/Object/MachOObjectFile.cpp
    llvm/tools/llvm-objdump/MachODump.cpp

Removed: 
    llvm/test/tools/llvm-objdump/MachO/chained-fixups.yaml


################################################################################
diff  --git a/llvm/include/llvm/BinaryFormat/MachO.h b/llvm/include/llvm/BinaryFormat/MachO.h
index ac1af5dafb9ee..cdc8792e7b2d9 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 4ec366055db64..be44388943fa4 100644
--- a/llvm/include/llvm/Object/MachO.h
+++ b/llvm/include/llvm/Object/MachO.h
@@ -685,10 +685,33 @@ class MachOObjectFile : public ObjectFile {
   ArrayRef<uint8_t> getDyldInfoBindOpcodes() const;
   ArrayRef<uint8_t> getDyldInfoWeakBindOpcodes() const;
   ArrayRef<uint8_t> 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<Optional<MachO::dyld_chained_fixups_header>>
   getChainedFixupsHeader() const;
   Expected<std::vector<ChainedFixupTarget>> 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<Optional<MachO::linkedit_data_command>>
+  getChainedFixupsLoadCommand() const;
+  struct ChainedFixupsSegment {
+    ChainedFixupsSegment(uint8_t SegIdx, uint32_t Offset,
+                         const MachO::dyld_chained_starts_in_segment &Header,
+                         std::vector<uint16_t> &&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<uint16_t> 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<std::pair<size_t, std::vector<ChainedFixupsSegment>>>
+  getChainedFixupsSegments() const;
+
   ArrayRef<uint8_t> getDyldInfoExportsTrie() const;
   SmallVector<uint64_t> getFunctionStarts() const;
   ArrayRef<uint8_t> getUuid() const;

diff  --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp
index 2f463a1bd4586..d7e9b57923b8e 100644
--- a/llvm/lib/Object/MachOObjectFile.cpp
+++ b/llvm/lib/Object/MachOObjectFile.cpp
@@ -4756,7 +4756,7 @@ ArrayRef<uint8_t> MachOObjectFile::getDyldInfoLazyBindOpcodes() const {
     return None;
 
   auto DyldInfoOrErr =
-    getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd);
+      getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd);
   if (!DyldInfoOrErr)
     return None;
   MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();
@@ -4765,8 +4765,8 @@ ArrayRef<uint8_t> MachOObjectFile::getDyldInfoLazyBindOpcodes() const {
   return makeArrayRef(Ptr, DyldInfo.lazy_bind_size);
 }
 
-Expected<Optional<MachO::dyld_chained_fixups_header>>
-MachOObjectFile::getChainedFixupsHeader() const {
+Expected<Optional<MachO::linkedit_data_command>>
+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<Optional<MachO::dyld_chained_fixups_header>>
+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<std::pair<size_t, std::vector<MachOObjectFile::ChainedFixupsSegment>>>
+MachOObjectFile::getChainedFixupsSegments() const {
+  auto CFOrErr = getChainedFixupsLoadCommand();
+  if (!CFOrErr)
+    return CFOrErr.takeError();
+
+  std::vector<MachOObjectFile::ChainedFixupsSegment> 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<MachO::dyld_chained_starts_in_image>(
+      *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<uint32_t>(*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<MachO::dyld_chained_starts_in_segment>(*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<uint16_t> 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<std::vector<ChainedFixupTarget>>
 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 0000000000000..c8e0c9b13dbea
Binary files /dev/null and b/llvm/test/tools/llvm-objdump/MachO/Inputs/chained-fixups.macho-x86_64 
diff er

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 0000000000000..72460fb8a3405
--- /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 63f3fd54a2225..0000000000000
--- 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 a2593cffb4d87..d95b1c4f5fd3e 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<std::string> GetSegmentNames(object::MachOObjectFile *O) {
+  SmallVector<std::string> 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<StringRef, 13> 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.
 }
 


        


More information about the llvm-commits mailing list