forked from OSchip/llvm-project
[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
This commit is contained in:
parent
ed342d9d29
commit
11443ef85d
|
@ -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 {
|
||||
|
|
|
@ -685,10 +685,33 @@ public:
|
|||
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;
|
||||
|
|
|
@ -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();
|
||||
|
|
Binary file not shown.
|
@ -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
|
|
@ -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
|
||||
...
|
|
@ -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.
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue