1 //===------ macho2yaml.cpp - obj2yaml conversion tool -----------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
10 #include "llvm/DebugInfo/DWARF/DWARFContext.h"
11 #include "llvm/Object/MachOUniversal.h"
12 #include "llvm/ObjectYAML/DWARFYAML.h"
13 #include "llvm/ObjectYAML/ObjectYAML.h"
14 #include "llvm/Support/Errc.h"
15 #include "llvm/Support/Error.h"
16 #include "llvm/Support/ErrorHandling.h"
17 #include "llvm/Support/LEB128.h"
19 #include <string.h> // for memcpy
25 template <typename StructType
>
26 Expected
<const char *> processLoadCommandData(
27 MachOYAML::LoadCommand
&LC
,
28 const llvm::object::MachOObjectFile::LoadCommandInfo
&LoadCmd
,
29 MachOYAML::Object
&Y
);
31 const object::MachOObjectFile
&Obj
;
32 std::unique_ptr
<DWARFContext
> DWARFCtx
;
34 void dumpHeader(std::unique_ptr
<MachOYAML::Object
> &Y
);
35 Error
dumpLoadCommands(std::unique_ptr
<MachOYAML::Object
> &Y
);
36 void dumpLinkEdit(std::unique_ptr
<MachOYAML::Object
> &Y
);
37 void dumpRebaseOpcodes(std::unique_ptr
<MachOYAML::Object
> &Y
);
38 void dumpFunctionStarts(std::unique_ptr
<MachOYAML::Object
> &Y
);
39 void dumpBindOpcodes(std::vector
<MachOYAML::BindOpcode
> &BindOpcodes
,
40 ArrayRef
<uint8_t> OpcodeBuffer
, bool Lazy
= false);
41 void dumpExportTrie(std::unique_ptr
<MachOYAML::Object
> &Y
);
42 void dumpSymbols(std::unique_ptr
<MachOYAML::Object
> &Y
);
43 void dumpIndirectSymbols(std::unique_ptr
<MachOYAML::Object
> &Y
);
44 void dumpChainedFixups(std::unique_ptr
<MachOYAML::Object
> &Y
);
45 void dumpDataInCode(std::unique_ptr
<MachOYAML::Object
> &Y
);
47 template <typename SectionType
>
48 Expected
<MachOYAML::Section
> constructSectionCommon(SectionType Sec
,
50 template <typename SectionType
>
51 Expected
<MachOYAML::Section
> constructSection(SectionType Sec
,
53 template <typename SectionType
, typename SegmentType
>
54 Expected
<const char *>
55 extractSections(const llvm::object::MachOObjectFile::LoadCommandInfo
&LoadCmd
,
56 std::vector
<MachOYAML::Section
> &Sections
,
57 MachOYAML::Object
&Y
);
60 MachODumper(const object::MachOObjectFile
&O
,
61 std::unique_ptr
<DWARFContext
> DCtx
, unsigned RawSegments
)
62 : Obj(O
), DWARFCtx(std::move(DCtx
)), RawSegment(RawSegments
) {}
63 Expected
<std::unique_ptr
<MachOYAML::Object
>> dump();
66 #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
68 memcpy((void *)&(LC.Data.LCStruct##_data), LoadCmd.Ptr, \
69 sizeof(MachO::LCStruct)); \
70 if (Obj.isLittleEndian() != sys::IsLittleEndianHost) \
71 MachO::swapStruct(LC.Data.LCStruct##_data); \
72 if (Expected<const char *> ExpectedEndPtr = \
73 processLoadCommandData<MachO::LCStruct>(LC, LoadCmd, *Y.get())) \
74 EndPtr = *ExpectedEndPtr; \
76 return ExpectedEndPtr.takeError(); \
79 template <typename SectionType
>
80 Expected
<MachOYAML::Section
>
81 MachODumper::constructSectionCommon(SectionType Sec
, size_t SecIndex
) {
82 MachOYAML::Section TempSec
;
83 memcpy(reinterpret_cast<void *>(&TempSec
.sectname
[0]), &Sec
.sectname
[0], 16);
84 memcpy(reinterpret_cast<void *>(&TempSec
.segname
[0]), &Sec
.segname
[0], 16);
85 TempSec
.addr
= Sec
.addr
;
86 TempSec
.size
= Sec
.size
;
87 TempSec
.offset
= Sec
.offset
;
88 TempSec
.align
= Sec
.align
;
89 TempSec
.reloff
= Sec
.reloff
;
90 TempSec
.nreloc
= Sec
.nreloc
;
91 TempSec
.flags
= Sec
.flags
;
92 TempSec
.reserved1
= Sec
.reserved1
;
93 TempSec
.reserved2
= Sec
.reserved2
;
94 TempSec
.reserved3
= 0;
95 if (!MachO::isVirtualSection(Sec
.flags
& MachO::SECTION_TYPE
))
97 yaml::BinaryRef(Obj
.getSectionContents(Sec
.offset
, Sec
.size
));
99 if (Expected
<object::SectionRef
> SecRef
= Obj
.getSection(SecIndex
)) {
100 TempSec
.relocations
.reserve(TempSec
.nreloc
);
101 for (const object::RelocationRef
&Reloc
: SecRef
->relocations()) {
102 const object::DataRefImpl Rel
= Reloc
.getRawDataRefImpl();
103 const MachO::any_relocation_info RE
= Obj
.getRelocation(Rel
);
104 MachOYAML::Relocation R
;
105 R
.address
= Obj
.getAnyRelocationAddress(RE
);
106 R
.is_pcrel
= Obj
.getAnyRelocationPCRel(RE
);
107 R
.length
= Obj
.getAnyRelocationLength(RE
);
108 R
.type
= Obj
.getAnyRelocationType(RE
);
109 R
.is_scattered
= Obj
.isRelocationScattered(RE
);
110 R
.symbolnum
= (R
.is_scattered
? 0 : Obj
.getPlainRelocationSymbolNum(RE
));
112 (R
.is_scattered
? false : Obj
.getPlainRelocationExternal(RE
));
113 R
.value
= (R
.is_scattered
? Obj
.getScatteredRelocationValue(RE
) : 0);
114 TempSec
.relocations
.push_back(R
);
117 return SecRef
.takeError();
123 Expected
<MachOYAML::Section
> MachODumper::constructSection(MachO::section Sec
,
125 Expected
<MachOYAML::Section
> TempSec
= constructSectionCommon(Sec
, SecIndex
);
127 TempSec
->reserved3
= 0;
132 Expected
<MachOYAML::Section
>
133 MachODumper::constructSection(MachO::section_64 Sec
, size_t SecIndex
) {
134 Expected
<MachOYAML::Section
> TempSec
= constructSectionCommon(Sec
, SecIndex
);
136 TempSec
->reserved3
= Sec
.reserved3
;
140 static Error
dumpDebugSection(StringRef SecName
, DWARFContext
&DCtx
,
141 DWARFYAML::Data
&DWARF
) {
142 if (SecName
== "__debug_abbrev")
143 return dumpDebugAbbrev(DCtx
, DWARF
);
144 if (SecName
== "__debug_aranges")
145 return dumpDebugARanges(DCtx
, DWARF
);
146 if (SecName
== "__debug_info") {
147 dumpDebugInfo(DCtx
, DWARF
);
148 return Error::success();
150 if (SecName
== "__debug_line") {
151 dumpDebugLines(DCtx
, DWARF
);
152 return Error::success();
154 if (SecName
.startswith("__debug_pub")) {
155 // FIXME: We should extract pub-section dumpers from this function.
156 dumpDebugPubSections(DCtx
, DWARF
);
157 return Error::success();
159 if (SecName
== "__debug_ranges")
160 return dumpDebugRanges(DCtx
, DWARF
);
161 if (SecName
== "__debug_str")
162 return dumpDebugStrings(DCtx
, DWARF
);
163 return createStringError(errc::not_supported
,
164 "dumping " + SecName
+ " section is not supported");
167 template <typename SectionType
, typename SegmentType
>
168 Expected
<const char *> MachODumper::extractSections(
169 const llvm::object::MachOObjectFile::LoadCommandInfo
&LoadCmd
,
170 std::vector
<MachOYAML::Section
> &Sections
, MachOYAML::Object
&Y
) {
171 auto End
= LoadCmd
.Ptr
+ LoadCmd
.C
.cmdsize
;
172 const SectionType
*Curr
=
173 reinterpret_cast<const SectionType
*>(LoadCmd
.Ptr
+ sizeof(SegmentType
));
174 for (; reinterpret_cast<const void *>(Curr
) < End
; Curr
++) {
176 memcpy((void *)&Sec
, Curr
, sizeof(SectionType
));
177 if (Obj
.isLittleEndian() != sys::IsLittleEndianHost
)
178 MachO::swapStruct(Sec
);
179 // For MachO section indices start from 1.
180 if (Expected
<MachOYAML::Section
> S
=
181 constructSection(Sec
, Sections
.size() + 1)) {
182 StringRef
SecName(S
->sectname
);
184 // Copy data sections if requested.
185 if ((RawSegment
& ::RawSegments::data
) &&
186 StringRef(S
->segname
).startswith("__DATA"))
188 yaml::BinaryRef(Obj
.getSectionContents(Sec
.offset
, Sec
.size
));
190 if (SecName
.startswith("__debug_")) {
191 // If the DWARF section cannot be successfully parsed, emit raw content
192 // instead of an entry in the DWARF section of the YAML.
193 if (Error Err
= dumpDebugSection(SecName
, *DWARFCtx
, Y
.DWARF
))
194 consumeError(std::move(Err
));
198 Sections
.push_back(std::move(*S
));
200 return S
.takeError();
202 return reinterpret_cast<const char *>(Curr
);
205 template <typename StructType
>
206 Expected
<const char *> MachODumper::processLoadCommandData(
207 MachOYAML::LoadCommand
&LC
,
208 const llvm::object::MachOObjectFile::LoadCommandInfo
&LoadCmd
,
209 MachOYAML::Object
&Y
) {
210 return LoadCmd
.Ptr
+ sizeof(StructType
);
214 Expected
<const char *>
215 MachODumper::processLoadCommandData
<MachO::segment_command
>(
216 MachOYAML::LoadCommand
&LC
,
217 const llvm::object::MachOObjectFile::LoadCommandInfo
&LoadCmd
,
218 MachOYAML::Object
&Y
) {
219 return extractSections
<MachO::section
, MachO::segment_command
>(
220 LoadCmd
, LC
.Sections
, Y
);
224 Expected
<const char *>
225 MachODumper::processLoadCommandData
<MachO::segment_command_64
>(
226 MachOYAML::LoadCommand
&LC
,
227 const llvm::object::MachOObjectFile::LoadCommandInfo
&LoadCmd
,
228 MachOYAML::Object
&Y
) {
229 return extractSections
<MachO::section_64
, MachO::segment_command_64
>(
230 LoadCmd
, LC
.Sections
, Y
);
233 template <typename StructType
>
235 readString(MachOYAML::LoadCommand
&LC
,
236 const llvm::object::MachOObjectFile::LoadCommandInfo
&LoadCmd
) {
237 auto Start
= LoadCmd
.Ptr
+ sizeof(StructType
);
238 auto MaxSize
= LoadCmd
.C
.cmdsize
- sizeof(StructType
);
239 auto Size
= strnlen(Start
, MaxSize
);
240 LC
.Content
= StringRef(Start
, Size
).str();
245 Expected
<const char *>
246 MachODumper::processLoadCommandData
<MachO::dylib_command
>(
247 MachOYAML::LoadCommand
&LC
,
248 const llvm::object::MachOObjectFile::LoadCommandInfo
&LoadCmd
,
249 MachOYAML::Object
&Y
) {
250 return readString
<MachO::dylib_command
>(LC
, LoadCmd
);
254 Expected
<const char *>
255 MachODumper::processLoadCommandData
<MachO::dylinker_command
>(
256 MachOYAML::LoadCommand
&LC
,
257 const llvm::object::MachOObjectFile::LoadCommandInfo
&LoadCmd
,
258 MachOYAML::Object
&Y
) {
259 return readString
<MachO::dylinker_command
>(LC
, LoadCmd
);
263 Expected
<const char *>
264 MachODumper::processLoadCommandData
<MachO::rpath_command
>(
265 MachOYAML::LoadCommand
&LC
,
266 const llvm::object::MachOObjectFile::LoadCommandInfo
&LoadCmd
,
267 MachOYAML::Object
&Y
) {
268 return readString
<MachO::rpath_command
>(LC
, LoadCmd
);
272 Expected
<const char *>
273 MachODumper::processLoadCommandData
<MachO::build_version_command
>(
274 MachOYAML::LoadCommand
&LC
,
275 const llvm::object::MachOObjectFile::LoadCommandInfo
&LoadCmd
,
276 MachOYAML::Object
&Y
) {
277 auto Start
= LoadCmd
.Ptr
+ sizeof(MachO::build_version_command
);
278 auto NTools
= LC
.Data
.build_version_command_data
.ntools
;
279 for (unsigned i
= 0; i
< NTools
; ++i
) {
280 auto Curr
= Start
+ i
* sizeof(MachO::build_tool_version
);
281 MachO::build_tool_version BV
;
282 memcpy((void *)&BV
, Curr
, sizeof(MachO::build_tool_version
));
283 if (Obj
.isLittleEndian() != sys::IsLittleEndianHost
)
284 MachO::swapStruct(BV
);
285 LC
.Tools
.push_back(BV
);
287 return Start
+ NTools
* sizeof(MachO::build_tool_version
);
290 Expected
<std::unique_ptr
<MachOYAML::Object
>> MachODumper::dump() {
291 auto Y
= std::make_unique
<MachOYAML::Object
>();
292 Y
->IsLittleEndian
= Obj
.isLittleEndian();
294 if (Error Err
= dumpLoadCommands(Y
))
295 return std::move(Err
);
296 if (RawSegment
& ::RawSegments::linkedit
)
297 Y
->RawLinkEditSegment
=
298 yaml::BinaryRef(Obj
.getSegmentContents("__LINKEDIT"));
305 void MachODumper::dumpHeader(std::unique_ptr
<MachOYAML::Object
> &Y
) {
306 Y
->Header
.magic
= Obj
.getHeader().magic
;
307 Y
->Header
.cputype
= Obj
.getHeader().cputype
;
308 Y
->Header
.cpusubtype
= Obj
.getHeader().cpusubtype
;
309 Y
->Header
.filetype
= Obj
.getHeader().filetype
;
310 Y
->Header
.ncmds
= Obj
.getHeader().ncmds
;
311 Y
->Header
.sizeofcmds
= Obj
.getHeader().sizeofcmds
;
312 Y
->Header
.flags
= Obj
.getHeader().flags
;
313 Y
->Header
.reserved
= 0;
316 Error
MachODumper::dumpLoadCommands(std::unique_ptr
<MachOYAML::Object
> &Y
) {
317 for (auto LoadCmd
: Obj
.load_commands()) {
318 MachOYAML::LoadCommand LC
;
319 const char *EndPtr
= LoadCmd
.Ptr
;
320 switch (LoadCmd
.C
.cmd
) {
322 memcpy((void *)&(LC
.Data
.load_command_data
), LoadCmd
.Ptr
,
323 sizeof(MachO::load_command
));
324 if (Obj
.isLittleEndian() != sys::IsLittleEndianHost
)
325 MachO::swapStruct(LC
.Data
.load_command_data
);
326 if (Expected
<const char *> ExpectedEndPtr
=
327 processLoadCommandData
<MachO::load_command
>(LC
, LoadCmd
, *Y
))
328 EndPtr
= *ExpectedEndPtr
;
330 return ExpectedEndPtr
.takeError();
332 #include "llvm/BinaryFormat/MachO.def"
334 auto RemainingBytes
= LoadCmd
.C
.cmdsize
- (EndPtr
- LoadCmd
.Ptr
);
335 if (!std::all_of(EndPtr
, &EndPtr
[RemainingBytes
],
336 [](const char C
) { return C
== 0; })) {
337 LC
.PayloadBytes
.insert(LC
.PayloadBytes
.end(), EndPtr
,
338 &EndPtr
[RemainingBytes
]);
341 LC
.ZeroPadBytes
= RemainingBytes
;
342 Y
->LoadCommands
.push_back(std::move(LC
));
344 return Error::success();
347 void MachODumper::dumpLinkEdit(std::unique_ptr
<MachOYAML::Object
> &Y
) {
348 dumpRebaseOpcodes(Y
);
349 dumpBindOpcodes(Y
->LinkEdit
.BindOpcodes
, Obj
.getDyldInfoBindOpcodes());
350 dumpBindOpcodes(Y
->LinkEdit
.WeakBindOpcodes
,
351 Obj
.getDyldInfoWeakBindOpcodes());
352 dumpBindOpcodes(Y
->LinkEdit
.LazyBindOpcodes
, Obj
.getDyldInfoLazyBindOpcodes(),
356 dumpIndirectSymbols(Y
);
357 dumpFunctionStarts(Y
);
358 dumpChainedFixups(Y
);
362 void MachODumper::dumpFunctionStarts(std::unique_ptr
<MachOYAML::Object
> &Y
) {
363 MachOYAML::LinkEditData
&LEData
= Y
->LinkEdit
;
365 auto FunctionStarts
= Obj
.getFunctionStarts();
366 for (auto Addr
: FunctionStarts
)
367 LEData
.FunctionStarts
.push_back(Addr
);
370 void MachODumper::dumpRebaseOpcodes(std::unique_ptr
<MachOYAML::Object
> &Y
) {
371 MachOYAML::LinkEditData
&LEData
= Y
->LinkEdit
;
373 auto RebaseOpcodes
= Obj
.getDyldInfoRebaseOpcodes();
374 for (auto OpCode
= RebaseOpcodes
.begin(); OpCode
!= RebaseOpcodes
.end();
376 MachOYAML::RebaseOpcode RebaseOp
;
378 static_cast<MachO::RebaseOpcode
>(*OpCode
& MachO::REBASE_OPCODE_MASK
);
379 RebaseOp
.Imm
= *OpCode
& MachO::REBASE_IMMEDIATE_MASK
;
384 switch (RebaseOp
.Opcode
) {
385 case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
:
387 ULEB
= decodeULEB128(OpCode
+ 1, &Count
);
388 RebaseOp
.ExtraData
.push_back(ULEB
);
391 // Intentionally no break here -- This opcode has two ULEB values
392 case MachO::REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
393 case MachO::REBASE_OPCODE_ADD_ADDR_ULEB
:
394 case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES
:
395 case MachO::REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
:
397 ULEB
= decodeULEB128(OpCode
+ 1, &Count
);
398 RebaseOp
.ExtraData
.push_back(ULEB
);
405 LEData
.RebaseOpcodes
.push_back(RebaseOp
);
407 if (RebaseOp
.Opcode
== MachO::REBASE_OPCODE_DONE
)
412 StringRef
ReadStringRef(const uint8_t *Start
) {
413 const uint8_t *Itr
= Start
;
416 return StringRef(reinterpret_cast<const char *>(Start
), Itr
- Start
);
419 void MachODumper::dumpBindOpcodes(
420 std::vector
<MachOYAML::BindOpcode
> &BindOpcodes
,
421 ArrayRef
<uint8_t> OpcodeBuffer
, bool Lazy
) {
422 for (auto OpCode
= OpcodeBuffer
.begin(); OpCode
!= OpcodeBuffer
.end();
424 MachOYAML::BindOpcode BindOp
;
426 static_cast<MachO::BindOpcode
>(*OpCode
& MachO::BIND_OPCODE_MASK
);
427 BindOp
.Imm
= *OpCode
& MachO::BIND_IMMEDIATE_MASK
;
433 switch (BindOp
.Opcode
) {
434 case MachO::BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
435 ULEB
= decodeULEB128(OpCode
+ 1, &Count
);
436 BindOp
.ULEBExtraData
.push_back(ULEB
);
439 // Intentionally no break here -- this opcode has two ULEB values
441 case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
442 case MachO::BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
443 case MachO::BIND_OPCODE_ADD_ADDR_ULEB
:
444 case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
445 ULEB
= decodeULEB128(OpCode
+ 1, &Count
);
446 BindOp
.ULEBExtraData
.push_back(ULEB
);
450 case MachO::BIND_OPCODE_SET_ADDEND_SLEB
:
451 SLEB
= decodeSLEB128(OpCode
+ 1, &Count
);
452 BindOp
.SLEBExtraData
.push_back(SLEB
);
456 case MachO::BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
457 BindOp
.Symbol
= ReadStringRef(OpCode
+ 1);
458 OpCode
+= BindOp
.Symbol
.size() + 1;
464 BindOpcodes
.push_back(BindOp
);
466 // Lazy bindings have DONE opcodes between operations, so we need to keep
467 // processing after a DONE.
468 if (!Lazy
&& BindOp
.Opcode
== MachO::BIND_OPCODE_DONE
)
474 * /brief processes a node from the export trie, and its children.
476 * To my knowledge there is no documentation of the encoded format of this data
477 * other than in the heads of the Apple linker engineers. To that end hopefully
478 * this comment and the implementation below can serve to light the way for
479 * anyone crazy enough to come down this path in the future.
481 * This function reads and preserves the trie structure of the export trie. To
482 * my knowledge there is no code anywhere else that reads the data and preserves
483 * the Trie. LD64 (sources available at opensource.apple.com) has a similar
484 * implementation that parses the export trie into a vector. That code as well
485 * as LLVM's libObject MachO implementation were the basis for this.
487 * The export trie is an encoded trie. The node serialization is a bit awkward.
488 * The below pseudo-code is the best description I've come up with for it.
490 * struct SerializedNode {
491 * ULEB128 TerminalSize;
492 * struct TerminalData { <-- This is only present if TerminalSize > 0
494 * ULEB128 Address; <-- Present if (! Flags & REEXPORT )
495 * ULEB128 Other; <-- Present if ( Flags & REEXPORT ||
496 * Flags & STUB_AND_RESOLVER )
497 * char[] ImportName; <-- Present if ( Flags & REEXPORT )
499 * uint8_t ChildrenCount;
500 * Pair<char[], ULEB128> ChildNameOffsetPair[ChildrenCount];
501 * SerializedNode Children[ChildrenCount]
504 * Terminal nodes are nodes that represent actual exports. They can appear
505 * anywhere in the tree other than at the root; they do not need to be leaf
506 * nodes. When reading the data out of the trie this routine reads it in-order,
507 * but it puts the child names and offsets directly into the child nodes. This
508 * results in looping over the children twice during serialization and
509 * de-serialization, but it makes the YAML representation more human readable.
511 * Below is an example of the graph from a "Hello World" executable:
521 * |----------------------------------------|
523 * ------------------------ ---------------------
524 * | '_mh_execute_header' | | 'main' |
525 * | Flags: 0x00000000 | | Flags: 0x00000000 |
526 * | Addr: 0x00000000 | | Addr: 0x00001160 |
527 * ------------------------ ---------------------
529 * This graph represents the trie for the exports "__mh_execute_header" and
530 * "_main". In the graph only the "_main" and "__mh_execute_header" nodes are
534 const uint8_t *processExportNode(const uint8_t *Start
, const uint8_t *CurrPtr
,
535 const uint8_t *const End
,
536 MachOYAML::ExportEntry
&Entry
) {
540 Entry
.TerminalSize
= decodeULEB128(CurrPtr
, &Count
);
542 if (Entry
.TerminalSize
!= 0) {
543 Entry
.Flags
= decodeULEB128(CurrPtr
, &Count
);
545 if (Entry
.Flags
& MachO::EXPORT_SYMBOL_FLAGS_REEXPORT
) {
547 Entry
.Other
= decodeULEB128(CurrPtr
, &Count
);
549 Entry
.ImportName
= std::string(reinterpret_cast<const char *>(CurrPtr
));
551 Entry
.Address
= decodeULEB128(CurrPtr
, &Count
);
553 if (Entry
.Flags
& MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
) {
554 Entry
.Other
= decodeULEB128(CurrPtr
, &Count
);
560 uint8_t childrenCount
= *CurrPtr
++;
561 if (childrenCount
== 0)
564 Entry
.Children
.insert(Entry
.Children
.begin(), (size_t)childrenCount
,
565 MachOYAML::ExportEntry());
566 for (auto &Child
: Entry
.Children
) {
567 Child
.Name
= std::string(reinterpret_cast<const char *>(CurrPtr
));
568 CurrPtr
+= Child
.Name
.length() + 1;
569 Child
.NodeOffset
= decodeULEB128(CurrPtr
, &Count
);
572 for (auto &Child
: Entry
.Children
) {
573 CurrPtr
= processExportNode(Start
, Start
+ Child
.NodeOffset
, End
, Child
);
578 void MachODumper::dumpExportTrie(std::unique_ptr
<MachOYAML::Object
> &Y
) {
579 MachOYAML::LinkEditData
&LEData
= Y
->LinkEdit
;
580 // The exports trie can be in LC_DYLD_INFO or LC_DYLD_EXPORTS_TRIE
581 auto ExportsTrie
= Obj
.getDyldInfoExportsTrie();
582 if (ExportsTrie
.empty())
583 ExportsTrie
= Obj
.getDyldExportsTrie();
584 processExportNode(ExportsTrie
.begin(), ExportsTrie
.begin(), ExportsTrie
.end(),
588 template <typename nlist_t
>
589 MachOYAML::NListEntry
constructNameList(const nlist_t
&nlist
) {
590 MachOYAML::NListEntry NL
;
591 NL
.n_strx
= nlist
.n_strx
;
592 NL
.n_type
= nlist
.n_type
;
593 NL
.n_sect
= nlist
.n_sect
;
594 NL
.n_desc
= nlist
.n_desc
;
595 NL
.n_value
= nlist
.n_value
;
599 void MachODumper::dumpSymbols(std::unique_ptr
<MachOYAML::Object
> &Y
) {
600 MachOYAML::LinkEditData
&LEData
= Y
->LinkEdit
;
602 for (auto Symbol
: Obj
.symbols()) {
603 MachOYAML::NListEntry NLE
=
605 ? constructNameList
<MachO::nlist_64
>(
606 Obj
.getSymbol64TableEntry(Symbol
.getRawDataRefImpl()))
607 : constructNameList
<MachO::nlist
>(
608 Obj
.getSymbolTableEntry(Symbol
.getRawDataRefImpl()));
609 LEData
.NameList
.push_back(NLE
);
612 StringRef RemainingTable
= Obj
.getStringTableData();
613 while (RemainingTable
.size() > 0) {
614 auto SymbolPair
= RemainingTable
.split('\0');
615 RemainingTable
= SymbolPair
.second
;
616 LEData
.StringTable
.push_back(SymbolPair
.first
);
620 void MachODumper::dumpIndirectSymbols(std::unique_ptr
<MachOYAML::Object
> &Y
) {
621 MachOYAML::LinkEditData
&LEData
= Y
->LinkEdit
;
623 MachO::dysymtab_command DLC
= Obj
.getDysymtabLoadCommand();
624 for (unsigned i
= 0; i
< DLC
.nindirectsyms
; ++i
)
625 LEData
.IndirectSymbols
.push_back(Obj
.getIndirectSymbolTableEntry(DLC
, i
));
628 void MachODumper::dumpChainedFixups(std::unique_ptr
<MachOYAML::Object
> &Y
) {
629 MachOYAML::LinkEditData
&LEData
= Y
->LinkEdit
;
631 for (const auto &LC
: Y
->LoadCommands
) {
632 if (LC
.Data
.load_command_data
.cmd
== llvm::MachO::LC_DYLD_CHAINED_FIXUPS
) {
633 const MachO::linkedit_data_command
&DC
=
634 LC
.Data
.linkedit_data_command_data
;
636 assert(DC
.dataoff
< Obj
.getData().size());
637 assert(DC
.dataoff
+ DC
.datasize
<= Obj
.getData().size());
638 const char *Bytes
= Obj
.getData().data() + DC
.dataoff
;
639 for (size_t Idx
= 0; Idx
< DC
.datasize
; Idx
++) {
640 LEData
.ChainedFixups
.push_back(Bytes
[Idx
]);
648 void MachODumper::dumpDataInCode(std::unique_ptr
<MachOYAML::Object
> &Y
) {
649 MachOYAML::LinkEditData
&LEData
= Y
->LinkEdit
;
651 MachO::linkedit_data_command DIC
= Obj
.getDataInCodeLoadCommand();
652 uint32_t NumEntries
= DIC
.datasize
/ sizeof(MachO::data_in_code_entry
);
653 for (uint32_t Idx
= 0; Idx
< NumEntries
; ++Idx
) {
654 MachO::data_in_code_entry DICE
=
655 Obj
.getDataInCodeTableEntry(DIC
.dataoff
, Idx
);
656 MachOYAML::DataInCodeEntry Entry
{DICE
.offset
, DICE
.length
, DICE
.kind
};
657 LEData
.DataInCode
.emplace_back(Entry
);
661 Error
macho2yaml(raw_ostream
&Out
, const object::MachOObjectFile
&Obj
,
662 unsigned RawSegments
) {
663 std::unique_ptr
<DWARFContext
> DCtx
= DWARFContext::create(Obj
);
664 MachODumper
Dumper(Obj
, std::move(DCtx
), RawSegments
);
665 Expected
<std::unique_ptr
<MachOYAML::Object
>> YAML
= Dumper
.dump();
667 return YAML
.takeError();
669 yaml::YamlObjectFile YAMLFile
;
670 YAMLFile
.MachO
= std::move(YAML
.get());
672 yaml::Output
Yout(Out
);
674 return Error::success();
677 Error
macho2yaml(raw_ostream
&Out
, const object::MachOUniversalBinary
&Obj
,
678 unsigned RawSegments
) {
679 yaml::YamlObjectFile YAMLFile
;
680 YAMLFile
.FatMachO
.reset(new MachOYAML::UniversalBinary());
681 MachOYAML::UniversalBinary
&YAML
= *YAMLFile
.FatMachO
;
682 YAML
.Header
.magic
= Obj
.getMagic();
683 YAML
.Header
.nfat_arch
= Obj
.getNumberOfObjects();
685 for (auto Slice
: Obj
.objects()) {
686 MachOYAML::FatArch arch
;
687 arch
.cputype
= Slice
.getCPUType();
688 arch
.cpusubtype
= Slice
.getCPUSubType();
689 arch
.offset
= Slice
.getOffset();
690 arch
.size
= Slice
.getSize();
691 arch
.align
= Slice
.getAlign();
692 arch
.reserved
= Slice
.getReserved();
693 YAML
.FatArchs
.push_back(arch
);
695 auto SliceObj
= Slice
.getAsObjectFile();
697 return SliceObj
.takeError();
699 std::unique_ptr
<DWARFContext
> DCtx
= DWARFContext::create(*SliceObj
.get());
700 MachODumper
Dumper(*SliceObj
.get(), std::move(DCtx
), RawSegments
);
701 Expected
<std::unique_ptr
<MachOYAML::Object
>> YAMLObj
= Dumper
.dump();
703 return YAMLObj
.takeError();
704 YAML
.Slices
.push_back(*YAMLObj
.get());
707 yaml::Output
Yout(Out
);
709 return Error::success();
712 Error
macho2yaml(raw_ostream
&Out
, const object::Binary
&Binary
,
713 unsigned RawSegments
) {
714 if (const auto *MachOObj
= dyn_cast
<object::MachOUniversalBinary
>(&Binary
))
715 return macho2yaml(Out
, *MachOObj
, RawSegments
);
717 if (const auto *MachOObj
= dyn_cast
<object::MachOObjectFile
>(&Binary
))
718 return macho2yaml(Out
, *MachOObj
, RawSegments
);
720 llvm_unreachable("unexpected Mach-O file format");