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