[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