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/Error.h"
15 #include "llvm/Support/ErrorHandling.h"
16 #include "llvm/Support/LEB128.h"
18 #include <string.h> // for memcpy
24 template <typename StructType
>
25 Expected
<const char *> processLoadCommandData(
26 MachOYAML::LoadCommand
&LC
,
27 const llvm::object::MachOObjectFile::LoadCommandInfo
&LoadCmd
,
28 MachOYAML::Object
&Y
);
30 const object::MachOObjectFile
&Obj
;
31 std::unique_ptr
<DWARFContext
> DWARFCtx
;
33 void dumpHeader(std::unique_ptr
<MachOYAML::Object
> &Y
);
34 Error
dumpLoadCommands(std::unique_ptr
<MachOYAML::Object
> &Y
);
35 void dumpLinkEdit(std::unique_ptr
<MachOYAML::Object
> &Y
);
36 void dumpRebaseOpcodes(std::unique_ptr
<MachOYAML::Object
> &Y
);
37 void dumpBindOpcodes(std::vector
<MachOYAML::BindOpcode
> &BindOpcodes
,
38 ArrayRef
<uint8_t> OpcodeBuffer
, bool Lazy
= false);
39 void dumpExportTrie(std::unique_ptr
<MachOYAML::Object
> &Y
);
40 void dumpSymbols(std::unique_ptr
<MachOYAML::Object
> &Y
);
41 void dumpIndirectSymbols(std::unique_ptr
<MachOYAML::Object
> &Y
);
43 template <typename SectionType
>
44 Expected
<MachOYAML::Section
> constructSectionCommon(SectionType Sec
,
46 template <typename SectionType
>
47 Expected
<MachOYAML::Section
> constructSection(SectionType Sec
,
49 template <typename SectionType
, typename SegmentType
>
50 Expected
<const char *>
51 extractSections(const llvm::object::MachOObjectFile::LoadCommandInfo
&LoadCmd
,
52 std::vector
<MachOYAML::Section
> &Sections
,
53 MachOYAML::Object
&Y
);
56 MachODumper(const object::MachOObjectFile
&O
,
57 std::unique_ptr
<DWARFContext
> DCtx
, unsigned RawSegments
)
58 : Obj(O
), DWARFCtx(std::move(DCtx
)), RawSegment(RawSegments
) {}
59 Expected
<std::unique_ptr
<MachOYAML::Object
>> dump();
62 #define HANDLE_LOAD_COMMAND(LCName, LCValue, LCStruct) \
64 memcpy((void *)&(LC.Data.LCStruct##_data), LoadCmd.Ptr, \
65 sizeof(MachO::LCStruct)); \
66 if (Obj.isLittleEndian() != sys::IsLittleEndianHost) \
67 MachO::swapStruct(LC.Data.LCStruct##_data); \
68 if (Expected<const char *> ExpectedEndPtr = \
69 processLoadCommandData<MachO::LCStruct>(LC, LoadCmd, *Y.get())) \
70 EndPtr = *ExpectedEndPtr; \
72 return ExpectedEndPtr.takeError(); \
75 template <typename SectionType
>
76 Expected
<MachOYAML::Section
>
77 MachODumper::constructSectionCommon(SectionType Sec
, size_t SecIndex
) {
78 MachOYAML::Section TempSec
;
79 memcpy(reinterpret_cast<void *>(&TempSec
.sectname
[0]), &Sec
.sectname
[0], 16);
80 memcpy(reinterpret_cast<void *>(&TempSec
.segname
[0]), &Sec
.segname
[0], 16);
81 TempSec
.addr
= Sec
.addr
;
82 TempSec
.size
= Sec
.size
;
83 TempSec
.offset
= Sec
.offset
;
84 TempSec
.align
= Sec
.align
;
85 TempSec
.reloff
= Sec
.reloff
;
86 TempSec
.nreloc
= Sec
.nreloc
;
87 TempSec
.flags
= Sec
.flags
;
88 TempSec
.reserved1
= Sec
.reserved1
;
89 TempSec
.reserved2
= Sec
.reserved2
;
90 TempSec
.reserved3
= 0;
91 if (!MachO::isVirtualSection(Sec
.flags
& MachO::SECTION_TYPE
))
93 yaml::BinaryRef(Obj
.getSectionContents(Sec
.offset
, Sec
.size
));
95 if (Expected
<object::SectionRef
> SecRef
= Obj
.getSection(SecIndex
)) {
96 TempSec
.relocations
.reserve(TempSec
.nreloc
);
97 for (const object::RelocationRef
&Reloc
: SecRef
->relocations()) {
98 const object::DataRefImpl Rel
= Reloc
.getRawDataRefImpl();
99 const MachO::any_relocation_info RE
= Obj
.getRelocation(Rel
);
100 MachOYAML::Relocation R
;
101 R
.address
= Obj
.getAnyRelocationAddress(RE
);
102 R
.is_pcrel
= Obj
.getAnyRelocationPCRel(RE
);
103 R
.length
= Obj
.getAnyRelocationLength(RE
);
104 R
.type
= Obj
.getAnyRelocationType(RE
);
105 R
.is_scattered
= Obj
.isRelocationScattered(RE
);
106 R
.symbolnum
= (R
.is_scattered
? 0 : Obj
.getPlainRelocationSymbolNum(RE
));
108 (R
.is_scattered
? false : Obj
.getPlainRelocationExternal(RE
));
109 R
.value
= (R
.is_scattered
? Obj
.getScatteredRelocationValue(RE
) : 0);
110 TempSec
.relocations
.push_back(R
);
113 return SecRef
.takeError();
119 Expected
<MachOYAML::Section
> MachODumper::constructSection(MachO::section Sec
,
121 Expected
<MachOYAML::Section
> TempSec
= constructSectionCommon(Sec
, SecIndex
);
123 TempSec
->reserved3
= 0;
128 Expected
<MachOYAML::Section
>
129 MachODumper::constructSection(MachO::section_64 Sec
, size_t SecIndex
) {
130 Expected
<MachOYAML::Section
> TempSec
= constructSectionCommon(Sec
, SecIndex
);
132 TempSec
->reserved3
= Sec
.reserved3
;
136 static Error
dumpDebugSection(StringRef SecName
, DWARFContext
&DCtx
,
137 DWARFYAML::Data
&DWARF
) {
138 if (SecName
== "__debug_abbrev") {
139 dumpDebugAbbrev(DCtx
, DWARF
);
140 return Error::success();
142 if (SecName
== "__debug_aranges")
143 return dumpDebugARanges(DCtx
, DWARF
);
144 if (SecName
== "__debug_info") {
145 dumpDebugInfo(DCtx
, DWARF
);
146 return Error::success();
148 if (SecName
== "__debug_line") {
149 dumpDebugLines(DCtx
, DWARF
);
150 return Error::success();
152 if (SecName
.startswith("__debug_pub")) {
153 // FIXME: We should extract pub-section dumpers from this function.
154 dumpDebugPubSections(DCtx
, DWARF
);
155 return Error::success();
157 if (SecName
== "__debug_ranges")
158 return dumpDebugRanges(DCtx
, DWARF
);
159 if (SecName
== "__debug_str")
160 return dumpDebugStrings(DCtx
, DWARF
);
161 return createStringError(errc::not_supported
,
162 "dumping " + SecName
+ " section is not supported");
165 template <typename SectionType
, typename SegmentType
>
166 Expected
<const char *> MachODumper::extractSections(
167 const llvm::object::MachOObjectFile::LoadCommandInfo
&LoadCmd
,
168 std::vector
<MachOYAML::Section
> &Sections
, MachOYAML::Object
&Y
) {
169 auto End
= LoadCmd
.Ptr
+ LoadCmd
.C
.cmdsize
;
170 const SectionType
*Curr
=
171 reinterpret_cast<const SectionType
*>(LoadCmd
.Ptr
+ sizeof(SegmentType
));
172 for (; reinterpret_cast<const void *>(Curr
) < End
; Curr
++) {
174 memcpy((void *)&Sec
, Curr
, sizeof(SectionType
));
175 if (Obj
.isLittleEndian() != sys::IsLittleEndianHost
)
176 MachO::swapStruct(Sec
);
177 // For MachO section indices start from 1.
178 if (Expected
<MachOYAML::Section
> S
=
179 constructSection(Sec
, Sections
.size() + 1)) {
180 StringRef
SecName(S
->sectname
);
182 // Copy data sections if requested.
183 if ((RawSegment
& ::RawSegments::data
) &&
184 StringRef(S
->segname
).startswith("__DATA"))
186 yaml::BinaryRef(Obj
.getSectionContents(Sec
.offset
, Sec
.size
));
188 if (SecName
.startswith("__debug_")) {
189 // If the DWARF section cannot be successfully parsed, emit raw content
190 // instead of an entry in the DWARF section of the YAML.
191 if (Error Err
= dumpDebugSection(SecName
, *DWARFCtx
.get(), Y
.DWARF
))
192 consumeError(std::move(Err
));
196 Sections
.push_back(std::move(*S
));
198 return S
.takeError();
200 return reinterpret_cast<const char *>(Curr
);
203 template <typename StructType
>
204 Expected
<const char *> MachODumper::processLoadCommandData(
205 MachOYAML::LoadCommand
&LC
,
206 const llvm::object::MachOObjectFile::LoadCommandInfo
&LoadCmd
,
207 MachOYAML::Object
&Y
) {
208 return LoadCmd
.Ptr
+ sizeof(StructType
);
212 Expected
<const char *>
213 MachODumper::processLoadCommandData
<MachO::segment_command
>(
214 MachOYAML::LoadCommand
&LC
,
215 const llvm::object::MachOObjectFile::LoadCommandInfo
&LoadCmd
,
216 MachOYAML::Object
&Y
) {
217 return extractSections
<MachO::section
, MachO::segment_command
>(
218 LoadCmd
, LC
.Sections
, Y
);
222 Expected
<const char *>
223 MachODumper::processLoadCommandData
<MachO::segment_command_64
>(
224 MachOYAML::LoadCommand
&LC
,
225 const llvm::object::MachOObjectFile::LoadCommandInfo
&LoadCmd
,
226 MachOYAML::Object
&Y
) {
227 return extractSections
<MachO::section_64
, MachO::segment_command_64
>(
228 LoadCmd
, LC
.Sections
, Y
);
231 template <typename StructType
>
233 readString(MachOYAML::LoadCommand
&LC
,
234 const llvm::object::MachOObjectFile::LoadCommandInfo
&LoadCmd
) {
235 auto Start
= LoadCmd
.Ptr
+ sizeof(StructType
);
236 auto MaxSize
= LoadCmd
.C
.cmdsize
- sizeof(StructType
);
237 auto Size
= strnlen(Start
, MaxSize
);
238 LC
.Content
= StringRef(Start
, Size
).str();
243 Expected
<const char *>
244 MachODumper::processLoadCommandData
<MachO::dylib_command
>(
245 MachOYAML::LoadCommand
&LC
,
246 const llvm::object::MachOObjectFile::LoadCommandInfo
&LoadCmd
,
247 MachOYAML::Object
&Y
) {
248 return readString
<MachO::dylib_command
>(LC
, LoadCmd
);
252 Expected
<const char *>
253 MachODumper::processLoadCommandData
<MachO::dylinker_command
>(
254 MachOYAML::LoadCommand
&LC
,
255 const llvm::object::MachOObjectFile::LoadCommandInfo
&LoadCmd
,
256 MachOYAML::Object
&Y
) {
257 return readString
<MachO::dylinker_command
>(LC
, LoadCmd
);
261 Expected
<const char *>
262 MachODumper::processLoadCommandData
<MachO::rpath_command
>(
263 MachOYAML::LoadCommand
&LC
,
264 const llvm::object::MachOObjectFile::LoadCommandInfo
&LoadCmd
,
265 MachOYAML::Object
&Y
) {
266 return readString
<MachO::rpath_command
>(LC
, LoadCmd
);
270 Expected
<const char *>
271 MachODumper::processLoadCommandData
<MachO::build_version_command
>(
272 MachOYAML::LoadCommand
&LC
,
273 const llvm::object::MachOObjectFile::LoadCommandInfo
&LoadCmd
,
274 MachOYAML::Object
&Y
) {
275 auto Start
= LoadCmd
.Ptr
+ sizeof(MachO::build_version_command
);
276 auto NTools
= LC
.Data
.build_version_command_data
.ntools
;
277 for (unsigned i
= 0; i
< NTools
; ++i
) {
278 auto Curr
= Start
+ i
* sizeof(MachO::build_tool_version
);
279 MachO::build_tool_version BV
;
280 memcpy((void *)&BV
, Curr
, sizeof(MachO::build_tool_version
));
281 if (Obj
.isLittleEndian() != sys::IsLittleEndianHost
)
282 MachO::swapStruct(BV
);
283 LC
.Tools
.push_back(BV
);
285 return Start
+ NTools
* sizeof(MachO::build_tool_version
);
288 Expected
<std::unique_ptr
<MachOYAML::Object
>> MachODumper::dump() {
289 auto Y
= std::make_unique
<MachOYAML::Object
>();
290 Y
->IsLittleEndian
= Obj
.isLittleEndian();
292 if (Error Err
= dumpLoadCommands(Y
))
293 return std::move(Err
);
294 if (RawSegment
& ::RawSegments::linkedit
)
295 Y
->RawLinkEditSegment
=
296 yaml::BinaryRef(Obj
.getSegmentContents("__LINKEDIT"));
303 void MachODumper::dumpHeader(std::unique_ptr
<MachOYAML::Object
> &Y
) {
304 Y
->Header
.magic
= Obj
.getHeader().magic
;
305 Y
->Header
.cputype
= Obj
.getHeader().cputype
;
306 Y
->Header
.cpusubtype
= Obj
.getHeader().cpusubtype
;
307 Y
->Header
.filetype
= Obj
.getHeader().filetype
;
308 Y
->Header
.ncmds
= Obj
.getHeader().ncmds
;
309 Y
->Header
.sizeofcmds
= Obj
.getHeader().sizeofcmds
;
310 Y
->Header
.flags
= Obj
.getHeader().flags
;
311 Y
->Header
.reserved
= 0;
314 Error
MachODumper::dumpLoadCommands(std::unique_ptr
<MachOYAML::Object
> &Y
) {
315 for (auto LoadCmd
: Obj
.load_commands()) {
316 MachOYAML::LoadCommand LC
;
317 const char *EndPtr
= LoadCmd
.Ptr
;
318 switch (LoadCmd
.C
.cmd
) {
320 memcpy((void *)&(LC
.Data
.load_command_data
), LoadCmd
.Ptr
,
321 sizeof(MachO::load_command
));
322 if (Obj
.isLittleEndian() != sys::IsLittleEndianHost
)
323 MachO::swapStruct(LC
.Data
.load_command_data
);
324 if (Expected
<const char *> ExpectedEndPtr
=
325 processLoadCommandData
<MachO::load_command
>(LC
, LoadCmd
,
327 EndPtr
= *ExpectedEndPtr
;
329 return ExpectedEndPtr
.takeError();
331 #include "llvm/BinaryFormat/MachO.def"
333 auto RemainingBytes
= LoadCmd
.C
.cmdsize
- (EndPtr
- LoadCmd
.Ptr
);
334 if (!std::all_of(EndPtr
, &EndPtr
[RemainingBytes
],
335 [](const char C
) { return C
== 0; })) {
336 LC
.PayloadBytes
.insert(LC
.PayloadBytes
.end(), EndPtr
,
337 &EndPtr
[RemainingBytes
]);
340 LC
.ZeroPadBytes
= RemainingBytes
;
341 Y
->LoadCommands
.push_back(std::move(LC
));
343 return Error::success();
346 void MachODumper::dumpLinkEdit(std::unique_ptr
<MachOYAML::Object
> &Y
) {
347 dumpRebaseOpcodes(Y
);
348 dumpBindOpcodes(Y
->LinkEdit
.BindOpcodes
, Obj
.getDyldInfoBindOpcodes());
349 dumpBindOpcodes(Y
->LinkEdit
.WeakBindOpcodes
,
350 Obj
.getDyldInfoWeakBindOpcodes());
351 dumpBindOpcodes(Y
->LinkEdit
.LazyBindOpcodes
, Obj
.getDyldInfoLazyBindOpcodes(),
355 dumpIndirectSymbols(Y
);
358 void MachODumper::dumpRebaseOpcodes(std::unique_ptr
<MachOYAML::Object
> &Y
) {
359 MachOYAML::LinkEditData
&LEData
= Y
->LinkEdit
;
361 auto RebaseOpcodes
= Obj
.getDyldInfoRebaseOpcodes();
362 for (auto OpCode
= RebaseOpcodes
.begin(); OpCode
!= RebaseOpcodes
.end();
364 MachOYAML::RebaseOpcode RebaseOp
;
366 static_cast<MachO::RebaseOpcode
>(*OpCode
& MachO::REBASE_OPCODE_MASK
);
367 RebaseOp
.Imm
= *OpCode
& MachO::REBASE_IMMEDIATE_MASK
;
372 switch (RebaseOp
.Opcode
) {
373 case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB
:
375 ULEB
= decodeULEB128(OpCode
+ 1, &Count
);
376 RebaseOp
.ExtraData
.push_back(ULEB
);
379 // Intentionally no break here -- This opcode has two ULEB values
380 case MachO::REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
381 case MachO::REBASE_OPCODE_ADD_ADDR_ULEB
:
382 case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES
:
383 case MachO::REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB
:
385 ULEB
= decodeULEB128(OpCode
+ 1, &Count
);
386 RebaseOp
.ExtraData
.push_back(ULEB
);
393 LEData
.RebaseOpcodes
.push_back(RebaseOp
);
395 if (RebaseOp
.Opcode
== MachO::REBASE_OPCODE_DONE
)
400 StringRef
ReadStringRef(const uint8_t *Start
) {
401 const uint8_t *Itr
= Start
;
404 return StringRef(reinterpret_cast<const char *>(Start
), Itr
- Start
);
407 void MachODumper::dumpBindOpcodes(
408 std::vector
<MachOYAML::BindOpcode
> &BindOpcodes
,
409 ArrayRef
<uint8_t> OpcodeBuffer
, bool Lazy
) {
410 for (auto OpCode
= OpcodeBuffer
.begin(); OpCode
!= OpcodeBuffer
.end();
412 MachOYAML::BindOpcode BindOp
;
414 static_cast<MachO::BindOpcode
>(*OpCode
& MachO::BIND_OPCODE_MASK
);
415 BindOp
.Imm
= *OpCode
& MachO::BIND_IMMEDIATE_MASK
;
421 switch (BindOp
.Opcode
) {
422 case MachO::BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB
:
423 ULEB
= decodeULEB128(OpCode
+ 1, &Count
);
424 BindOp
.ULEBExtraData
.push_back(ULEB
);
427 // Intentionally no break here -- this opcode has two ULEB values
429 case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB
:
430 case MachO::BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB
:
431 case MachO::BIND_OPCODE_ADD_ADDR_ULEB
:
432 case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB
:
433 ULEB
= decodeULEB128(OpCode
+ 1, &Count
);
434 BindOp
.ULEBExtraData
.push_back(ULEB
);
438 case MachO::BIND_OPCODE_SET_ADDEND_SLEB
:
439 SLEB
= decodeSLEB128(OpCode
+ 1, &Count
);
440 BindOp
.SLEBExtraData
.push_back(SLEB
);
444 case MachO::BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM
:
445 BindOp
.Symbol
= ReadStringRef(OpCode
+ 1);
446 OpCode
+= BindOp
.Symbol
.size() + 1;
452 BindOpcodes
.push_back(BindOp
);
454 // Lazy bindings have DONE opcodes between operations, so we need to keep
455 // processing after a DONE.
456 if (!Lazy
&& BindOp
.Opcode
== MachO::BIND_OPCODE_DONE
)
462 * /brief processes a node from the export trie, and its children.
464 * To my knowledge there is no documentation of the encoded format of this data
465 * other than in the heads of the Apple linker engineers. To that end hopefully
466 * this comment and the implementation below can serve to light the way for
467 * anyone crazy enough to come down this path in the future.
469 * This function reads and preserves the trie structure of the export trie. To
470 * my knowledge there is no code anywhere else that reads the data and preserves
471 * the Trie. LD64 (sources available at opensource.apple.com) has a similar
472 * implementation that parses the export trie into a vector. That code as well
473 * as LLVM's libObject MachO implementation were the basis for this.
475 * The export trie is an encoded trie. The node serialization is a bit awkward.
476 * The below pseudo-code is the best description I've come up with for it.
478 * struct SerializedNode {
479 * ULEB128 TerminalSize;
480 * struct TerminalData { <-- This is only present if TerminalSize > 0
482 * ULEB128 Address; <-- Present if (! Flags & REEXPORT )
483 * ULEB128 Other; <-- Present if ( Flags & REEXPORT ||
484 * Flags & STUB_AND_RESOLVER )
485 * char[] ImportName; <-- Present if ( Flags & REEXPORT )
487 * uint8_t ChildrenCount;
488 * Pair<char[], ULEB128> ChildNameOffsetPair[ChildrenCount];
489 * SerializedNode Children[ChildrenCount]
492 * Terminal nodes are nodes that represent actual exports. They can appear
493 * anywhere in the tree other than at the root; they do not need to be leaf
494 * nodes. When reading the data out of the trie this routine reads it in-order,
495 * but it puts the child names and offsets directly into the child nodes. This
496 * results in looping over the children twice during serialization and
497 * de-serialization, but it makes the YAML representation more human readable.
499 * Below is an example of the graph from a "Hello World" executable:
509 * |----------------------------------------|
511 * ------------------------ ---------------------
512 * | '_mh_execute_header' | | 'main' |
513 * | Flags: 0x00000000 | | Flags: 0x00000000 |
514 * | Addr: 0x00000000 | | Addr: 0x00001160 |
515 * ------------------------ ---------------------
517 * This graph represents the trie for the exports "__mh_execute_header" and
518 * "_main". In the graph only the "_main" and "__mh_execute_header" nodes are
522 const uint8_t *processExportNode(const uint8_t *CurrPtr
,
523 const uint8_t *const End
,
524 MachOYAML::ExportEntry
&Entry
) {
528 Entry
.TerminalSize
= decodeULEB128(CurrPtr
, &Count
);
530 if (Entry
.TerminalSize
!= 0) {
531 Entry
.Flags
= decodeULEB128(CurrPtr
, &Count
);
533 if (Entry
.Flags
& MachO::EXPORT_SYMBOL_FLAGS_REEXPORT
) {
535 Entry
.Other
= decodeULEB128(CurrPtr
, &Count
);
537 Entry
.ImportName
= std::string(reinterpret_cast<const char *>(CurrPtr
));
539 Entry
.Address
= decodeULEB128(CurrPtr
, &Count
);
541 if (Entry
.Flags
& MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER
) {
542 Entry
.Other
= decodeULEB128(CurrPtr
, &Count
);
548 uint8_t childrenCount
= *CurrPtr
++;
549 if (childrenCount
== 0)
552 Entry
.Children
.insert(Entry
.Children
.begin(), (size_t)childrenCount
,
553 MachOYAML::ExportEntry());
554 for (auto &Child
: Entry
.Children
) {
555 Child
.Name
= std::string(reinterpret_cast<const char *>(CurrPtr
));
556 CurrPtr
+= Child
.Name
.length() + 1;
557 Child
.NodeOffset
= decodeULEB128(CurrPtr
, &Count
);
560 for (auto &Child
: Entry
.Children
) {
561 CurrPtr
= processExportNode(CurrPtr
, End
, Child
);
566 void MachODumper::dumpExportTrie(std::unique_ptr
<MachOYAML::Object
> &Y
) {
567 MachOYAML::LinkEditData
&LEData
= Y
->LinkEdit
;
568 auto ExportsTrie
= Obj
.getDyldInfoExportsTrie();
569 processExportNode(ExportsTrie
.begin(), ExportsTrie
.end(), LEData
.ExportTrie
);
572 template <typename nlist_t
>
573 MachOYAML::NListEntry
constructNameList(const nlist_t
&nlist
) {
574 MachOYAML::NListEntry NL
;
575 NL
.n_strx
= nlist
.n_strx
;
576 NL
.n_type
= nlist
.n_type
;
577 NL
.n_sect
= nlist
.n_sect
;
578 NL
.n_desc
= nlist
.n_desc
;
579 NL
.n_value
= nlist
.n_value
;
583 void MachODumper::dumpSymbols(std::unique_ptr
<MachOYAML::Object
> &Y
) {
584 MachOYAML::LinkEditData
&LEData
= Y
->LinkEdit
;
586 for (auto Symbol
: Obj
.symbols()) {
587 MachOYAML::NListEntry NLE
=
589 ? constructNameList
<MachO::nlist_64
>(
590 Obj
.getSymbol64TableEntry(Symbol
.getRawDataRefImpl()))
591 : constructNameList
<MachO::nlist
>(
592 Obj
.getSymbolTableEntry(Symbol
.getRawDataRefImpl()));
593 LEData
.NameList
.push_back(NLE
);
596 StringRef RemainingTable
= Obj
.getStringTableData();
597 while (RemainingTable
.size() > 0) {
598 auto SymbolPair
= RemainingTable
.split('\0');
599 RemainingTable
= SymbolPair
.second
;
600 LEData
.StringTable
.push_back(SymbolPair
.first
);
604 void MachODumper::dumpIndirectSymbols(std::unique_ptr
<MachOYAML::Object
> &Y
) {
605 MachOYAML::LinkEditData
&LEData
= Y
->LinkEdit
;
607 MachO::dysymtab_command DLC
= Obj
.getDysymtabLoadCommand();
608 for (unsigned i
= 0; i
< DLC
.nindirectsyms
; ++i
)
609 LEData
.IndirectSymbols
.push_back(Obj
.getIndirectSymbolTableEntry(DLC
, i
));
612 Error
macho2yaml(raw_ostream
&Out
, const object::MachOObjectFile
&Obj
,
613 unsigned RawSegments
) {
614 std::unique_ptr
<DWARFContext
> DCtx
= DWARFContext::create(Obj
);
615 MachODumper
Dumper(Obj
, std::move(DCtx
), RawSegments
);
616 Expected
<std::unique_ptr
<MachOYAML::Object
>> YAML
= Dumper
.dump();
618 return YAML
.takeError();
620 yaml::YamlObjectFile YAMLFile
;
621 YAMLFile
.MachO
= std::move(YAML
.get());
623 yaml::Output
Yout(Out
);
625 return Error::success();
628 Error
macho2yaml(raw_ostream
&Out
, const object::MachOUniversalBinary
&Obj
,
629 unsigned RawSegments
) {
630 yaml::YamlObjectFile YAMLFile
;
631 YAMLFile
.FatMachO
.reset(new MachOYAML::UniversalBinary());
632 MachOYAML::UniversalBinary
&YAML
= *YAMLFile
.FatMachO
;
633 YAML
.Header
.magic
= Obj
.getMagic();
634 YAML
.Header
.nfat_arch
= Obj
.getNumberOfObjects();
636 for (auto Slice
: Obj
.objects()) {
637 MachOYAML::FatArch arch
;
638 arch
.cputype
= Slice
.getCPUType();
639 arch
.cpusubtype
= Slice
.getCPUSubType();
640 arch
.offset
= Slice
.getOffset();
641 arch
.size
= Slice
.getSize();
642 arch
.align
= Slice
.getAlign();
643 arch
.reserved
= Slice
.getReserved();
644 YAML
.FatArchs
.push_back(arch
);
646 auto SliceObj
= Slice
.getAsObjectFile();
648 return SliceObj
.takeError();
650 std::unique_ptr
<DWARFContext
> DCtx
= DWARFContext::create(*SliceObj
.get());
651 MachODumper
Dumper(*SliceObj
.get(), std::move(DCtx
), RawSegments
);
652 Expected
<std::unique_ptr
<MachOYAML::Object
>> YAMLObj
= Dumper
.dump();
654 return YAMLObj
.takeError();
655 YAML
.Slices
.push_back(*YAMLObj
.get());
658 yaml::Output
Yout(Out
);
660 return Error::success();
663 Error
macho2yaml(raw_ostream
&Out
, const object::Binary
&Binary
,
664 unsigned RawSegments
) {
665 if (const auto *MachOObj
= dyn_cast
<object::MachOUniversalBinary
>(&Binary
))
666 return macho2yaml(Out
, *MachOObj
, RawSegments
);
668 if (const auto *MachOObj
= dyn_cast
<object::MachOObjectFile
>(&Binary
))
669 return macho2yaml(Out
, *MachOObj
, RawSegments
);
671 llvm_unreachable("unexpected Mach-O file format");