1 //===- lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp -----------------===//
2 //
3 // The LLVM Linker
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 ///
11 /// \file For mach-o object files, this implementation uses YAML I/O to
12 /// provide the convert between YAML and the normalized mach-o (NM).
13 ///
14 /// +------------+ +------+
15 /// | normalized | <-> | yaml |
16 /// +------------+ +------+
17
18 #include "MachONormalizedFile.h"
19 #include "lld/Common/LLVM.h"
20 #include "lld/Core/Error.h"
21 #include "lld/ReaderWriter/YamlContext.h"
22 #include "llvm/ADT/SmallString.h"
23 #include "llvm/ADT/StringRef.h"
24 #include "llvm/ADT/StringSwitch.h"
25 #include "llvm/ADT/Twine.h"
26 #include "llvm/BinaryFormat/MachO.h"
27 #include "llvm/Support/Casting.h"
28 #include "llvm/Support/ErrorHandling.h"
29 #include "llvm/Support/Format.h"
30 #include "llvm/Support/MemoryBuffer.h"
31 #include "llvm/Support/SourceMgr.h"
32 #include "llvm/Support/YAMLTraits.h"
33 #include "llvm/Support/raw_ostream.h"
34 #include <system_error>
35
36 using llvm::StringRef;
37 using namespace llvm::yaml;
38 using namespace llvm::MachO;
39 using namespace lld::mach_o::normalized;
40 using lld::YamlContext;
41
42 LLVM_YAML_IS_SEQUENCE_VECTOR(Segment)
43 LLVM_YAML_IS_SEQUENCE_VECTOR(DependentDylib)
44 LLVM_YAML_IS_SEQUENCE_VECTOR(RebaseLocation)
45 LLVM_YAML_IS_SEQUENCE_VECTOR(BindLocation)
46 LLVM_YAML_IS_SEQUENCE_VECTOR(Export)
47 LLVM_YAML_IS_SEQUENCE_VECTOR(DataInCode)
48
49
50 // for compatibility with gcc-4.7 in C++11 mode, add extra namespace
51 namespace llvm {
52 namespace yaml {
53
54 // A vector of Sections is a sequence.
55 template<>
56 struct SequenceTraits< std::vector<Section> > {
sizellvm::yaml::SequenceTraits57 static size_t size(IO &io, std::vector<Section> &seq) {
58 return seq.size();
59 }
elementllvm::yaml::SequenceTraits60 static Section& element(IO &io, std::vector<Section> &seq, size_t index) {
61 if ( index >= seq.size() )
62 seq.resize(index+1);
63 return seq[index];
64 }
65 };
66
67 template<>
68 struct SequenceTraits< std::vector<Symbol> > {
sizellvm::yaml::SequenceTraits69 static size_t size(IO &io, std::vector<Symbol> &seq) {
70 return seq.size();
71 }
elementllvm::yaml::SequenceTraits72 static Symbol& element(IO &io, std::vector<Symbol> &seq, size_t index) {
73 if ( index >= seq.size() )
74 seq.resize(index+1);
75 return seq[index];
76 }
77 };
78
79 // A vector of Relocations is a sequence.
80 template<>
81 struct SequenceTraits< Relocations > {
sizellvm::yaml::SequenceTraits82 static size_t size(IO &io, Relocations &seq) {
83 return seq.size();
84 }
elementllvm::yaml::SequenceTraits85 static Relocation& element(IO &io, Relocations &seq, size_t index) {
86 if ( index >= seq.size() )
87 seq.resize(index+1);
88 return seq[index];
89 }
90 };
91
92 // The content for a section is represented as a flow sequence of hex bytes.
93 template<>
94 struct SequenceTraits< ContentBytes > {
sizellvm::yaml::SequenceTraits95 static size_t size(IO &io, ContentBytes &seq) {
96 return seq.size();
97 }
elementllvm::yaml::SequenceTraits98 static Hex8& element(IO &io, ContentBytes &seq, size_t index) {
99 if ( index >= seq.size() )
100 seq.resize(index+1);
101 return seq[index];
102 }
103 static const bool flow = true;
104 };
105
106 // The indirect symbols for a section is represented as a flow sequence
107 // of numbers (symbol table indexes).
108 template<>
109 struct SequenceTraits< IndirectSymbols > {
sizellvm::yaml::SequenceTraits110 static size_t size(IO &io, IndirectSymbols &seq) {
111 return seq.size();
112 }
elementllvm::yaml::SequenceTraits113 static uint32_t& element(IO &io, IndirectSymbols &seq, size_t index) {
114 if ( index >= seq.size() )
115 seq.resize(index+1);
116 return seq[index];
117 }
118 static const bool flow = true;
119 };
120
121 template <>
122 struct ScalarEnumerationTraits<lld::MachOLinkingContext::Arch> {
enumerationllvm::yaml::ScalarEnumerationTraits123 static void enumeration(IO &io, lld::MachOLinkingContext::Arch &value) {
124 io.enumCase(value, "unknown",lld::MachOLinkingContext::arch_unknown);
125 io.enumCase(value, "ppc", lld::MachOLinkingContext::arch_ppc);
126 io.enumCase(value, "x86", lld::MachOLinkingContext::arch_x86);
127 io.enumCase(value, "x86_64", lld::MachOLinkingContext::arch_x86_64);
128 io.enumCase(value, "armv6", lld::MachOLinkingContext::arch_armv6);
129 io.enumCase(value, "armv7", lld::MachOLinkingContext::arch_armv7);
130 io.enumCase(value, "armv7s", lld::MachOLinkingContext::arch_armv7s);
131 io.enumCase(value, "arm64", lld::MachOLinkingContext::arch_arm64);
132 }
133 };
134
135 template <>
136 struct ScalarEnumerationTraits<lld::MachOLinkingContext::OS> {
enumerationllvm::yaml::ScalarEnumerationTraits137 static void enumeration(IO &io, lld::MachOLinkingContext::OS &value) {
138 io.enumCase(value, "unknown",
139 lld::MachOLinkingContext::OS::unknown);
140 io.enumCase(value, "Mac OS X",
141 lld::MachOLinkingContext::OS::macOSX);
142 io.enumCase(value, "iOS",
143 lld::MachOLinkingContext::OS::iOS);
144 io.enumCase(value, "iOS Simulator",
145 lld::MachOLinkingContext::OS::iOS_simulator);
146 }
147 };
148
149
150 template <>
151 struct ScalarEnumerationTraits<HeaderFileType> {
enumerationllvm::yaml::ScalarEnumerationTraits152 static void enumeration(IO &io, HeaderFileType &value) {
153 io.enumCase(value, "MH_OBJECT", llvm::MachO::MH_OBJECT);
154 io.enumCase(value, "MH_DYLIB", llvm::MachO::MH_DYLIB);
155 io.enumCase(value, "MH_EXECUTE", llvm::MachO::MH_EXECUTE);
156 io.enumCase(value, "MH_BUNDLE", llvm::MachO::MH_BUNDLE);
157 }
158 };
159
160
161 template <>
162 struct ScalarBitSetTraits<FileFlags> {
bitsetllvm::yaml::ScalarBitSetTraits163 static void bitset(IO &io, FileFlags &value) {
164 io.bitSetCase(value, "MH_TWOLEVEL",
165 llvm::MachO::MH_TWOLEVEL);
166 io.bitSetCase(value, "MH_SUBSECTIONS_VIA_SYMBOLS",
167 llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
168 }
169 };
170
171
172 template <>
173 struct ScalarEnumerationTraits<SectionType> {
enumerationllvm::yaml::ScalarEnumerationTraits174 static void enumeration(IO &io, SectionType &value) {
175 io.enumCase(value, "S_REGULAR",
176 llvm::MachO::S_REGULAR);
177 io.enumCase(value, "S_ZEROFILL",
178 llvm::MachO::S_ZEROFILL);
179 io.enumCase(value, "S_CSTRING_LITERALS",
180 llvm::MachO::S_CSTRING_LITERALS);
181 io.enumCase(value, "S_4BYTE_LITERALS",
182 llvm::MachO::S_4BYTE_LITERALS);
183 io.enumCase(value, "S_8BYTE_LITERALS",
184 llvm::MachO::S_8BYTE_LITERALS);
185 io.enumCase(value, "S_LITERAL_POINTERS",
186 llvm::MachO::S_LITERAL_POINTERS);
187 io.enumCase(value, "S_NON_LAZY_SYMBOL_POINTERS",
188 llvm::MachO::S_NON_LAZY_SYMBOL_POINTERS);
189 io.enumCase(value, "S_LAZY_SYMBOL_POINTERS",
190 llvm::MachO::S_LAZY_SYMBOL_POINTERS);
191 io.enumCase(value, "S_SYMBOL_STUBS",
192 llvm::MachO::S_SYMBOL_STUBS);
193 io.enumCase(value, "S_MOD_INIT_FUNC_POINTERS",
194 llvm::MachO::S_MOD_INIT_FUNC_POINTERS);
195 io.enumCase(value, "S_MOD_TERM_FUNC_POINTERS",
196 llvm::MachO::S_MOD_TERM_FUNC_POINTERS);
197 io.enumCase(value, "S_COALESCED",
198 llvm::MachO::S_COALESCED);
199 io.enumCase(value, "S_GB_ZEROFILL",
200 llvm::MachO::S_GB_ZEROFILL);
201 io.enumCase(value, "S_INTERPOSING",
202 llvm::MachO::S_INTERPOSING);
203 io.enumCase(value, "S_16BYTE_LITERALS",
204 llvm::MachO::S_16BYTE_LITERALS);
205 io.enumCase(value, "S_DTRACE_DOF",
206 llvm::MachO::S_DTRACE_DOF);
207 io.enumCase(value, "S_LAZY_DYLIB_SYMBOL_POINTERS",
208 llvm::MachO::S_LAZY_DYLIB_SYMBOL_POINTERS);
209 io.enumCase(value, "S_THREAD_LOCAL_REGULAR",
210 llvm::MachO::S_THREAD_LOCAL_REGULAR);
211 io.enumCase(value, "S_THREAD_LOCAL_ZEROFILL",
212 llvm::MachO::S_THREAD_LOCAL_ZEROFILL);
213 io.enumCase(value, "S_THREAD_LOCAL_VARIABLES",
214 llvm::MachO::S_THREAD_LOCAL_VARIABLES);
215 io.enumCase(value, "S_THREAD_LOCAL_VARIABLE_POINTERS",
216 llvm::MachO::S_THREAD_LOCAL_VARIABLE_POINTERS);
217 io.enumCase(value, "S_THREAD_LOCAL_INIT_FUNCTION_POINTERS",
218 llvm::MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS);
219 }
220 };
221
222 template <>
223 struct ScalarBitSetTraits<SectionAttr> {
bitsetllvm::yaml::ScalarBitSetTraits224 static void bitset(IO &io, SectionAttr &value) {
225 io.bitSetCase(value, "S_ATTR_PURE_INSTRUCTIONS",
226 llvm::MachO::S_ATTR_PURE_INSTRUCTIONS);
227 io.bitSetCase(value, "S_ATTR_SOME_INSTRUCTIONS",
228 llvm::MachO::S_ATTR_SOME_INSTRUCTIONS);
229 io.bitSetCase(value, "S_ATTR_NO_DEAD_STRIP",
230 llvm::MachO::S_ATTR_NO_DEAD_STRIP);
231 io.bitSetCase(value, "S_ATTR_EXT_RELOC",
232 llvm::MachO::S_ATTR_EXT_RELOC);
233 io.bitSetCase(value, "S_ATTR_LOC_RELOC",
234 llvm::MachO::S_ATTR_LOC_RELOC);
235 io.bitSetCase(value, "S_ATTR_DEBUG",
236 llvm::MachO::S_ATTR_DEBUG);
237 }
238 };
239
240 /// This is a custom formatter for SectionAlignment. Values are
241 /// the power to raise by, ie, the n in 2^n.
242 template <> struct ScalarTraits<SectionAlignment> {
outputllvm::yaml::ScalarTraits243 static void output(const SectionAlignment &value, void *ctxt,
244 raw_ostream &out) {
245 out << llvm::format("%d", (uint32_t)value);
246 }
247
inputllvm::yaml::ScalarTraits248 static StringRef input(StringRef scalar, void *ctxt,
249 SectionAlignment &value) {
250 uint32_t alignment;
251 if (scalar.getAsInteger(0, alignment)) {
252 return "malformed alignment value";
253 }
254 if (!llvm::isPowerOf2_32(alignment))
255 return "alignment must be a power of 2";
256 value = alignment;
257 return StringRef(); // returning empty string means success
258 }
259
mustQuotellvm::yaml::ScalarTraits260 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
261 };
262
263 template <>
264 struct ScalarEnumerationTraits<NListType> {
enumerationllvm::yaml::ScalarEnumerationTraits265 static void enumeration(IO &io, NListType &value) {
266 io.enumCase(value, "N_UNDF", llvm::MachO::N_UNDF);
267 io.enumCase(value, "N_ABS", llvm::MachO::N_ABS);
268 io.enumCase(value, "N_SECT", llvm::MachO::N_SECT);
269 io.enumCase(value, "N_PBUD", llvm::MachO::N_PBUD);
270 io.enumCase(value, "N_INDR", llvm::MachO::N_INDR);
271 }
272 };
273
274 template <>
275 struct ScalarBitSetTraits<SymbolScope> {
bitsetllvm::yaml::ScalarBitSetTraits276 static void bitset(IO &io, SymbolScope &value) {
277 io.bitSetCase(value, "N_EXT", llvm::MachO::N_EXT);
278 io.bitSetCase(value, "N_PEXT", llvm::MachO::N_PEXT);
279 }
280 };
281
282 template <>
283 struct ScalarBitSetTraits<SymbolDesc> {
bitsetllvm::yaml::ScalarBitSetTraits284 static void bitset(IO &io, SymbolDesc &value) {
285 io.bitSetCase(value, "N_NO_DEAD_STRIP", llvm::MachO::N_NO_DEAD_STRIP);
286 io.bitSetCase(value, "N_WEAK_REF", llvm::MachO::N_WEAK_REF);
287 io.bitSetCase(value, "N_WEAK_DEF", llvm::MachO::N_WEAK_DEF);
288 io.bitSetCase(value, "N_ARM_THUMB_DEF", llvm::MachO::N_ARM_THUMB_DEF);
289 io.bitSetCase(value, "N_SYMBOL_RESOLVER", llvm::MachO::N_SYMBOL_RESOLVER);
290 }
291 };
292
293
294 template <>
295 struct MappingTraits<Section> {
296 struct NormalizedContentBytes;
mappingllvm::yaml::MappingTraits297 static void mapping(IO &io, Section §) {
298 io.mapRequired("segment", sect.segmentName);
299 io.mapRequired("section", sect.sectionName);
300 io.mapRequired("type", sect.type);
301 io.mapOptional("attributes", sect.attributes);
302 io.mapOptional("alignment", sect.alignment, (SectionAlignment)1);
303 io.mapRequired("address", sect.address);
304 if (isZeroFillSection(sect.type)) {
305 // S_ZEROFILL sections use "size:" instead of "content:"
306 uint64_t size = sect.content.size();
307 io.mapOptional("size", size);
308 if (!io.outputting()) {
309 uint8_t *bytes = nullptr;
310 sect.content = makeArrayRef(bytes, size);
311 }
312 } else {
313 MappingNormalization<NormalizedContent, ArrayRef<uint8_t>> content(
314 io, sect.content);
315 io.mapOptional("content", content->_normalizedContent);
316 }
317 io.mapOptional("relocations", sect.relocations);
318 io.mapOptional("indirect-syms", sect.indirectSymbols);
319 }
320
321 struct NormalizedContent {
NormalizedContentllvm::yaml::MappingTraits::NormalizedContent322 NormalizedContent(IO &io) : _io(io) {}
NormalizedContentllvm::yaml::MappingTraits::NormalizedContent323 NormalizedContent(IO &io, ArrayRef<uint8_t> content) : _io(io) {
324 // When writing yaml, copy content byte array to Hex8 vector.
325 for (auto &c : content) {
326 _normalizedContent.push_back(c);
327 }
328 }
denormalizellvm::yaml::MappingTraits::NormalizedContent329 ArrayRef<uint8_t> denormalize(IO &io) {
330 // When reading yaml, allocate byte array owned by NormalizedFile and
331 // copy Hex8 vector to byte array.
332 YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
333 assert(info != nullptr);
334 NormalizedFile *file = info->_normalizeMachOFile;
335 assert(file != nullptr);
336 size_t size = _normalizedContent.size();
337 if (!size)
338 return None;
339 uint8_t *bytes = file->ownedAllocations.Allocate<uint8_t>(size);
340 std::copy(_normalizedContent.begin(), _normalizedContent.end(), bytes);
341 return makeArrayRef(bytes, size);
342 }
343
344 IO &_io;
345 ContentBytes _normalizedContent;
346 };
347 };
348
349
350 template <>
351 struct MappingTraits<Relocation> {
mappingllvm::yaml::MappingTraits352 static void mapping(IO &io, Relocation &reloc) {
353 io.mapRequired("offset", reloc.offset);
354 io.mapOptional("scattered", reloc.scattered, false);
355 io.mapRequired("type", reloc.type);
356 io.mapRequired("length", reloc.length);
357 io.mapRequired("pc-rel", reloc.pcRel);
358 if ( !reloc.scattered )
359 io.mapRequired("extern", reloc.isExtern);
360 if ( reloc.scattered )
361 io.mapRequired("value", reloc.value);
362 if ( !reloc.scattered )
363 io.mapRequired("symbol", reloc.symbol);
364 }
365 };
366
367
368 template <>
369 struct ScalarEnumerationTraits<RelocationInfoType> {
enumerationllvm::yaml::ScalarEnumerationTraits370 static void enumeration(IO &io, RelocationInfoType &value) {
371 YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
372 assert(info != nullptr);
373 NormalizedFile *file = info->_normalizeMachOFile;
374 assert(file != nullptr);
375 switch (file->arch) {
376 case lld::MachOLinkingContext::arch_x86_64:
377 io.enumCase(value, "X86_64_RELOC_UNSIGNED",
378 llvm::MachO::X86_64_RELOC_UNSIGNED);
379 io.enumCase(value, "X86_64_RELOC_SIGNED",
380 llvm::MachO::X86_64_RELOC_SIGNED);
381 io.enumCase(value, "X86_64_RELOC_BRANCH",
382 llvm::MachO::X86_64_RELOC_BRANCH);
383 io.enumCase(value, "X86_64_RELOC_GOT_LOAD",
384 llvm::MachO::X86_64_RELOC_GOT_LOAD);
385 io.enumCase(value, "X86_64_RELOC_GOT",
386 llvm::MachO::X86_64_RELOC_GOT);
387 io.enumCase(value, "X86_64_RELOC_SUBTRACTOR",
388 llvm::MachO::X86_64_RELOC_SUBTRACTOR);
389 io.enumCase(value, "X86_64_RELOC_SIGNED_1",
390 llvm::MachO::X86_64_RELOC_SIGNED_1);
391 io.enumCase(value, "X86_64_RELOC_SIGNED_2",
392 llvm::MachO::X86_64_RELOC_SIGNED_2);
393 io.enumCase(value, "X86_64_RELOC_SIGNED_4",
394 llvm::MachO::X86_64_RELOC_SIGNED_4);
395 io.enumCase(value, "X86_64_RELOC_TLV",
396 llvm::MachO::X86_64_RELOC_TLV);
397 break;
398 case lld::MachOLinkingContext::arch_x86:
399 io.enumCase(value, "GENERIC_RELOC_VANILLA",
400 llvm::MachO::GENERIC_RELOC_VANILLA);
401 io.enumCase(value, "GENERIC_RELOC_PAIR",
402 llvm::MachO::GENERIC_RELOC_PAIR);
403 io.enumCase(value, "GENERIC_RELOC_SECTDIFF",
404 llvm::MachO::GENERIC_RELOC_SECTDIFF);
405 io.enumCase(value, "GENERIC_RELOC_LOCAL_SECTDIFF",
406 llvm::MachO::GENERIC_RELOC_LOCAL_SECTDIFF);
407 io.enumCase(value, "GENERIC_RELOC_TLV",
408 llvm::MachO::GENERIC_RELOC_TLV);
409 break;
410 case lld::MachOLinkingContext::arch_armv6:
411 case lld::MachOLinkingContext::arch_armv7:
412 case lld::MachOLinkingContext::arch_armv7s:
413 io.enumCase(value, "ARM_RELOC_VANILLA",
414 llvm::MachO::ARM_RELOC_VANILLA);
415 io.enumCase(value, "ARM_RELOC_PAIR",
416 llvm::MachO::ARM_RELOC_PAIR);
417 io.enumCase(value, "ARM_RELOC_SECTDIFF",
418 llvm::MachO::ARM_RELOC_SECTDIFF);
419 io.enumCase(value, "ARM_RELOC_LOCAL_SECTDIFF",
420 llvm::MachO::ARM_RELOC_LOCAL_SECTDIFF);
421 io.enumCase(value, "ARM_RELOC_BR24",
422 llvm::MachO::ARM_RELOC_BR24);
423 io.enumCase(value, "ARM_THUMB_RELOC_BR22",
424 llvm::MachO::ARM_THUMB_RELOC_BR22);
425 io.enumCase(value, "ARM_RELOC_HALF",
426 llvm::MachO::ARM_RELOC_HALF);
427 io.enumCase(value, "ARM_RELOC_HALF_SECTDIFF",
428 llvm::MachO::ARM_RELOC_HALF_SECTDIFF);
429 break;
430 case lld::MachOLinkingContext::arch_arm64:
431 io.enumCase(value, "ARM64_RELOC_UNSIGNED",
432 llvm::MachO::ARM64_RELOC_UNSIGNED);
433 io.enumCase(value, "ARM64_RELOC_SUBTRACTOR",
434 llvm::MachO::ARM64_RELOC_SUBTRACTOR);
435 io.enumCase(value, "ARM64_RELOC_BRANCH26",
436 llvm::MachO::ARM64_RELOC_BRANCH26);
437 io.enumCase(value, "ARM64_RELOC_PAGE21",
438 llvm::MachO::ARM64_RELOC_PAGE21);
439 io.enumCase(value, "ARM64_RELOC_PAGEOFF12",
440 llvm::MachO::ARM64_RELOC_PAGEOFF12);
441 io.enumCase(value, "ARM64_RELOC_GOT_LOAD_PAGE21",
442 llvm::MachO::ARM64_RELOC_GOT_LOAD_PAGE21);
443 io.enumCase(value, "ARM64_RELOC_GOT_LOAD_PAGEOFF12",
444 llvm::MachO::ARM64_RELOC_GOT_LOAD_PAGEOFF12);
445 io.enumCase(value, "ARM64_RELOC_POINTER_TO_GOT",
446 llvm::MachO::ARM64_RELOC_POINTER_TO_GOT);
447 io.enumCase(value, "ARM64_RELOC_TLVP_LOAD_PAGE21",
448 llvm::MachO::ARM64_RELOC_TLVP_LOAD_PAGE21);
449 io.enumCase(value, "ARM64_RELOC_TLVP_LOAD_PAGEOFF12",
450 llvm::MachO::ARM64_RELOC_TLVP_LOAD_PAGEOFF12);
451 io.enumCase(value, "ARM64_RELOC_ADDEND",
452 llvm::MachO::ARM64_RELOC_ADDEND);
453 break;
454 default:
455 llvm_unreachable("unknown architecture");
456 }
457 }
458 };
459
460
461 template <>
462 struct MappingTraits<Symbol> {
mappingllvm::yaml::MappingTraits463 static void mapping(IO &io, Symbol& sym) {
464 io.mapRequired("name", sym.name);
465 io.mapRequired("type", sym.type);
466 io.mapOptional("scope", sym.scope, SymbolScope(0));
467 io.mapOptional("sect", sym.sect, (uint8_t)0);
468 if (sym.type == llvm::MachO::N_UNDF) {
469 // In undef symbols, desc field contains alignment/ordinal info
470 // which is better represented as a hex vaule.
471 uint16_t t1 = sym.desc;
472 Hex16 t2 = t1;
473 io.mapOptional("desc", t2, Hex16(0));
474 sym.desc = t2;
475 } else {
476 // In defined symbols, desc fit is a set of option bits.
477 io.mapOptional("desc", sym.desc, SymbolDesc(0));
478 }
479 io.mapRequired("value", sym.value);
480 }
481 };
482
483 // Custom mapping for VMProtect (e.g. "r-x").
484 template <>
485 struct ScalarTraits<VMProtect> {
outputllvm::yaml::ScalarTraits486 static void output(const VMProtect &value, void*, raw_ostream &out) {
487 out << ( (value & llvm::MachO::VM_PROT_READ) ? 'r' : '-');
488 out << ( (value & llvm::MachO::VM_PROT_WRITE) ? 'w' : '-');
489 out << ( (value & llvm::MachO::VM_PROT_EXECUTE) ? 'x' : '-');
490 }
inputllvm::yaml::ScalarTraits491 static StringRef input(StringRef scalar, void*, VMProtect &value) {
492 value = 0;
493 if (scalar.size() != 3)
494 return "segment access protection must be three chars (e.g. \"r-x\")";
495 switch (scalar[0]) {
496 case 'r':
497 value = llvm::MachO::VM_PROT_READ;
498 break;
499 case '-':
500 break;
501 default:
502 return "segment access protection first char must be 'r' or '-'";
503 }
504 switch (scalar[1]) {
505 case 'w':
506 value = value | llvm::MachO::VM_PROT_WRITE;
507 break;
508 case '-':
509 break;
510 default:
511 return "segment access protection second char must be 'w' or '-'";
512 }
513 switch (scalar[2]) {
514 case 'x':
515 value = value | llvm::MachO::VM_PROT_EXECUTE;
516 break;
517 case '-':
518 break;
519 default:
520 return "segment access protection third char must be 'x' or '-'";
521 }
522 // Return the empty string on success,
523 return StringRef();
524 }
mustQuotellvm::yaml::ScalarTraits525 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
526 };
527
528
529 template <>
530 struct MappingTraits<Segment> {
mappingllvm::yaml::MappingTraits531 static void mapping(IO &io, Segment& seg) {
532 io.mapRequired("name", seg.name);
533 io.mapRequired("address", seg.address);
534 io.mapRequired("size", seg.size);
535 io.mapRequired("init-access", seg.init_access);
536 io.mapRequired("max-access", seg.max_access);
537 }
538 };
539
540 template <>
541 struct ScalarEnumerationTraits<LoadCommandType> {
enumerationllvm::yaml::ScalarEnumerationTraits542 static void enumeration(IO &io, LoadCommandType &value) {
543 io.enumCase(value, "LC_LOAD_DYLIB",
544 llvm::MachO::LC_LOAD_DYLIB);
545 io.enumCase(value, "LC_LOAD_WEAK_DYLIB",
546 llvm::MachO::LC_LOAD_WEAK_DYLIB);
547 io.enumCase(value, "LC_REEXPORT_DYLIB",
548 llvm::MachO::LC_REEXPORT_DYLIB);
549 io.enumCase(value, "LC_LOAD_UPWARD_DYLIB",
550 llvm::MachO::LC_LOAD_UPWARD_DYLIB);
551 io.enumCase(value, "LC_LAZY_LOAD_DYLIB",
552 llvm::MachO::LC_LAZY_LOAD_DYLIB);
553 io.enumCase(value, "LC_VERSION_MIN_MACOSX",
554 llvm::MachO::LC_VERSION_MIN_MACOSX);
555 io.enumCase(value, "LC_VERSION_MIN_IPHONEOS",
556 llvm::MachO::LC_VERSION_MIN_IPHONEOS);
557 io.enumCase(value, "LC_VERSION_MIN_TVOS",
558 llvm::MachO::LC_VERSION_MIN_TVOS);
559 io.enumCase(value, "LC_VERSION_MIN_WATCHOS",
560 llvm::MachO::LC_VERSION_MIN_WATCHOS);
561 }
562 };
563
564 template <>
565 struct MappingTraits<DependentDylib> {
mappingllvm::yaml::MappingTraits566 static void mapping(IO &io, DependentDylib& dylib) {
567 io.mapRequired("path", dylib.path);
568 io.mapOptional("kind", dylib.kind,
569 llvm::MachO::LC_LOAD_DYLIB);
570 io.mapOptional("compat-version", dylib.compatVersion,
571 PackedVersion(0x10000));
572 io.mapOptional("current-version", dylib.currentVersion,
573 PackedVersion(0x10000));
574 }
575 };
576
577 template <>
578 struct ScalarEnumerationTraits<RebaseType> {
enumerationllvm::yaml::ScalarEnumerationTraits579 static void enumeration(IO &io, RebaseType &value) {
580 io.enumCase(value, "REBASE_TYPE_POINTER",
581 llvm::MachO::REBASE_TYPE_POINTER);
582 io.enumCase(value, "REBASE_TYPE_TEXT_PCREL32",
583 llvm::MachO::REBASE_TYPE_TEXT_PCREL32);
584 io.enumCase(value, "REBASE_TYPE_TEXT_ABSOLUTE32",
585 llvm::MachO::REBASE_TYPE_TEXT_ABSOLUTE32);
586 }
587 };
588
589
590 template <>
591 struct MappingTraits<RebaseLocation> {
mappingllvm::yaml::MappingTraits592 static void mapping(IO &io, RebaseLocation& rebase) {
593 io.mapRequired("segment-index", rebase.segIndex);
594 io.mapRequired("segment-offset", rebase.segOffset);
595 io.mapOptional("kind", rebase.kind,
596 llvm::MachO::REBASE_TYPE_POINTER);
597 }
598 };
599
600
601
602 template <>
603 struct ScalarEnumerationTraits<BindType> {
enumerationllvm::yaml::ScalarEnumerationTraits604 static void enumeration(IO &io, BindType &value) {
605 io.enumCase(value, "BIND_TYPE_POINTER",
606 llvm::MachO::BIND_TYPE_POINTER);
607 io.enumCase(value, "BIND_TYPE_TEXT_ABSOLUTE32",
608 llvm::MachO::BIND_TYPE_TEXT_ABSOLUTE32);
609 io.enumCase(value, "BIND_TYPE_TEXT_PCREL32",
610 llvm::MachO::BIND_TYPE_TEXT_PCREL32);
611 }
612 };
613
614 template <>
615 struct MappingTraits<BindLocation> {
mappingllvm::yaml::MappingTraits616 static void mapping(IO &io, BindLocation &bind) {
617 io.mapRequired("segment-index", bind.segIndex);
618 io.mapRequired("segment-offset", bind.segOffset);
619 io.mapOptional("kind", bind.kind,
620 llvm::MachO::BIND_TYPE_POINTER);
621 io.mapOptional("can-be-null", bind.canBeNull, false);
622 io.mapRequired("ordinal", bind.ordinal);
623 io.mapRequired("symbol-name", bind.symbolName);
624 io.mapOptional("addend", bind.addend, Hex64(0));
625 }
626 };
627
628
629 template <>
630 struct ScalarEnumerationTraits<ExportSymbolKind> {
enumerationllvm::yaml::ScalarEnumerationTraits631 static void enumeration(IO &io, ExportSymbolKind &value) {
632 io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_REGULAR",
633 llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR);
634 io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL",
635 llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL);
636 io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE",
637 llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE);
638 }
639 };
640
641 template <>
642 struct ScalarBitSetTraits<ExportFlags> {
bitsetllvm::yaml::ScalarBitSetTraits643 static void bitset(IO &io, ExportFlags &value) {
644 io.bitSetCase(value, "EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION",
645 llvm::MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
646 io.bitSetCase(value, "EXPORT_SYMBOL_FLAGS_REEXPORT",
647 llvm::MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);
648 io.bitSetCase(value, "EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER",
649 llvm::MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
650 }
651 };
652
653
654 template <>
655 struct MappingTraits<Export> {
mappingllvm::yaml::MappingTraits656 static void mapping(IO &io, Export &exp) {
657 io.mapRequired("name", exp.name);
658 io.mapOptional("offset", exp.offset);
659 io.mapOptional("kind", exp.kind,
660 llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR);
661 if (!io.outputting() || exp.flags)
662 io.mapOptional("flags", exp.flags);
663 io.mapOptional("other", exp.otherOffset, Hex32(0));
664 io.mapOptional("other-name", exp.otherName, StringRef());
665 }
666 };
667
668 template <>
669 struct ScalarEnumerationTraits<DataRegionType> {
enumerationllvm::yaml::ScalarEnumerationTraits670 static void enumeration(IO &io, DataRegionType &value) {
671 io.enumCase(value, "DICE_KIND_DATA",
672 llvm::MachO::DICE_KIND_DATA);
673 io.enumCase(value, "DICE_KIND_JUMP_TABLE8",
674 llvm::MachO::DICE_KIND_JUMP_TABLE8);
675 io.enumCase(value, "DICE_KIND_JUMP_TABLE16",
676 llvm::MachO::DICE_KIND_JUMP_TABLE16);
677 io.enumCase(value, "DICE_KIND_JUMP_TABLE32",
678 llvm::MachO::DICE_KIND_JUMP_TABLE32);
679 io.enumCase(value, "DICE_KIND_ABS_JUMP_TABLE32",
680 llvm::MachO::DICE_KIND_ABS_JUMP_TABLE32);
681 }
682 };
683
684 template <>
685 struct MappingTraits<DataInCode> {
mappingllvm::yaml::MappingTraits686 static void mapping(IO &io, DataInCode &entry) {
687 io.mapRequired("offset", entry.offset);
688 io.mapRequired("length", entry.length);
689 io.mapRequired("kind", entry.kind);
690 }
691 };
692
693 template <>
694 struct ScalarTraits<PackedVersion> {
outputllvm::yaml::ScalarTraits695 static void output(const PackedVersion &value, void*, raw_ostream &out) {
696 out << llvm::format("%d.%d", (value >> 16), (value >> 8) & 0xFF);
697 if (value & 0xFF) {
698 out << llvm::format(".%d", (value & 0xFF));
699 }
700 }
inputllvm::yaml::ScalarTraits701 static StringRef input(StringRef scalar, void*, PackedVersion &result) {
702 uint32_t value;
703 if (lld::MachOLinkingContext::parsePackedVersion(scalar, value))
704 return "malformed version number";
705 result = value;
706 // Return the empty string on success,
707 return StringRef();
708 }
mustQuotellvm::yaml::ScalarTraits709 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
710 };
711
712 template <>
713 struct MappingTraits<NormalizedFile> {
mappingllvm::yaml::MappingTraits714 static void mapping(IO &io, NormalizedFile &file) {
715 io.mapRequired("arch", file.arch);
716 io.mapRequired("file-type", file.fileType);
717 io.mapOptional("flags", file.flags);
718 io.mapOptional("dependents", file.dependentDylibs);
719 io.mapOptional("install-name", file.installName, StringRef());
720 io.mapOptional("compat-version", file.compatVersion, PackedVersion(0x10000));
721 io.mapOptional("current-version", file.currentVersion, PackedVersion(0x10000));
722 io.mapOptional("has-UUID", file.hasUUID, true);
723 io.mapOptional("rpaths", file.rpaths);
724 io.mapOptional("entry-point", file.entryAddress, Hex64(0));
725 io.mapOptional("stack-size", file.stackSize, Hex64(0));
726 io.mapOptional("source-version", file.sourceVersion, Hex64(0));
727 io.mapOptional("OS", file.os);
728 io.mapOptional("min-os-version", file.minOSverson, PackedVersion(0));
729 io.mapOptional("min-os-version-kind", file.minOSVersionKind, (LoadCommandType)0);
730 io.mapOptional("sdk-version", file.sdkVersion, PackedVersion(0));
731 io.mapOptional("segments", file.segments);
732 io.mapOptional("sections", file.sections);
733 io.mapOptional("local-symbols", file.localSymbols);
734 io.mapOptional("global-symbols", file.globalSymbols);
735 io.mapOptional("undefined-symbols",file.undefinedSymbols);
736 io.mapOptional("page-size", file.pageSize, Hex32(4096));
737 io.mapOptional("rebasings", file.rebasingInfo);
738 io.mapOptional("bindings", file.bindingInfo);
739 io.mapOptional("weak-bindings", file.weakBindingInfo);
740 io.mapOptional("lazy-bindings", file.lazyBindingInfo);
741 io.mapOptional("exports", file.exportInfo);
742 io.mapOptional("dataInCode", file.dataInCode);
743 }
validatellvm::yaml::MappingTraits744 static StringRef validate(IO &io, NormalizedFile &file) {
745 return StringRef();
746 }
747 };
748
749 } // namespace llvm
750 } // namespace yaml
751
752
753 namespace lld {
754 namespace mach_o {
755
756 /// Handles !mach-o tagged yaml documents.
handledDocTag(llvm::yaml::IO & io,const lld::File * & file) const757 bool MachOYamlIOTaggedDocumentHandler::handledDocTag(llvm::yaml::IO &io,
758 const lld::File *&file) const {
759 if (!io.mapTag("!mach-o"))
760 return false;
761 // Step 1: parse yaml into normalized mach-o struct.
762 NormalizedFile nf;
763 YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
764 assert(info != nullptr);
765 assert(info->_normalizeMachOFile == nullptr);
766 info->_normalizeMachOFile = &nf;
767 MappingTraits<NormalizedFile>::mapping(io, nf);
768 // Step 2: parse normalized mach-o struct into atoms.
769 auto fileOrError = normalizedToAtoms(nf, info->_path, true);
770
771 // Check that we parsed successfully.
772 if (!fileOrError) {
773 std::string buffer;
774 llvm::raw_string_ostream stream(buffer);
775 handleAllErrors(fileOrError.takeError(),
776 [&](const llvm::ErrorInfoBase &EI) {
777 EI.log(stream);
778 stream << "\n";
779 });
780 io.setError(stream.str());
781 return false;
782 }
783
784 if (nf.arch != _arch) {
785 io.setError(Twine("file is wrong architecture. Expected ("
786 + MachOLinkingContext::nameFromArch(_arch)
787 + ") found ("
788 + MachOLinkingContext::nameFromArch(nf.arch)
789 + ")"));
790 return false;
791 }
792 info->_normalizeMachOFile = nullptr;
793 file = fileOrError->release();
794 return true;
795 }
796
797
798
799 namespace normalized {
800
801 /// Parses a yaml encoded mach-o file to produce an in-memory normalized view.
802 llvm::Expected<std::unique_ptr<NormalizedFile>>
readYaml(std::unique_ptr<MemoryBuffer> & mb)803 readYaml(std::unique_ptr<MemoryBuffer> &mb) {
804 // Make empty NormalizedFile.
805 std::unique_ptr<NormalizedFile> f(new NormalizedFile());
806
807 // Create YAML Input parser.
808 YamlContext yamlContext;
809 yamlContext._normalizeMachOFile = f.get();
810 llvm::yaml::Input yin(mb->getBuffer(), &yamlContext);
811
812 // Fill NormalizedFile by parsing yaml.
813 yin >> *f;
814
815 // Return error if there were parsing problems.
816 if (auto ec = yin.error())
817 return llvm::make_error<GenericError>(Twine("YAML parsing error: ")
818 + ec.message());
819
820 // Hand ownership of instantiated NormalizedFile to caller.
821 return std::move(f);
822 }
823
824
825 /// Writes a yaml encoded mach-o files from an in-memory normalized view.
writeYaml(const NormalizedFile & file,raw_ostream & out)826 std::error_code writeYaml(const NormalizedFile &file, raw_ostream &out) {
827 // YAML I/O is not const aware, so need to cast away ;-(
828 NormalizedFile *f = const_cast<NormalizedFile*>(&file);
829
830 // Create yaml Output writer, using yaml options for context.
831 YamlContext yamlContext;
832 yamlContext._normalizeMachOFile = f;
833 llvm::yaml::Output yout(out, &yamlContext);
834
835 // Stream out yaml.
836 yout << *f;
837
838 return std::error_code();
839 }
840
841 } // namespace normalized
842 } // namespace mach_o
843 } // namespace lld
844