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 35using llvm::StringRef; 36using namespace llvm::yaml; 37using namespace llvm::MachO; 38using namespace lld::mach_o::normalized; 39using lld::YamlContext; 40 41LLVM_YAML_IS_SEQUENCE_VECTOR(Segment) 42LLVM_YAML_IS_SEQUENCE_VECTOR(DependentDylib) 43LLVM_YAML_IS_SEQUENCE_VECTOR(RebaseLocation) 44LLVM_YAML_IS_SEQUENCE_VECTOR(BindLocation) 45LLVM_YAML_IS_SEQUENCE_VECTOR(Export) 46LLVM_YAML_IS_SEQUENCE_VECTOR(DataInCode) 47 48 49// for compatibility with gcc-4.7 in C++11 mode, add extra namespace 50namespace llvm { 51namespace yaml { 52 53// A vector of Sections is a sequence. 54template<> 55struct SequenceTraits< std::vector<Section> > { 56 static size_t size(IO &io, std::vector<Section> &seq) { 57 return seq.size(); 58 } 59 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 66template<> 67struct SequenceTraits< std::vector<Symbol> > { 68 static size_t size(IO &io, std::vector<Symbol> &seq) { 69 return seq.size(); 70 } 71 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. 79template<> 80struct SequenceTraits< Relocations > { 81 static size_t size(IO &io, Relocations &seq) { 82 return seq.size(); 83 } 84 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. 92template<> 93struct SequenceTraits< ContentBytes > { 94 static size_t size(IO &io, ContentBytes &seq) { 95 return seq.size(); 96 } 97 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). 107template<> 108struct SequenceTraits< IndirectSymbols > { 109 static size_t size(IO &io, IndirectSymbols &seq) { 110 return seq.size(); 111 } 112 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 120template <> 121struct ScalarEnumerationTraits<lld::MachOLinkingContext::Arch> { 122 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 134template <> 135struct ScalarEnumerationTraits<lld::MachOLinkingContext::OS> { 136 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 149template <> 150struct ScalarEnumerationTraits<HeaderFileType> { 151 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 160template <> 161struct ScalarBitSetTraits<FileFlags> { 162 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 171template <> 172struct ScalarEnumerationTraits<SectionType> { 173 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 221template <> 222struct ScalarBitSetTraits<SectionAttr> { 223 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. 241template <> struct ScalarTraits<SectionAlignment> { 242 static void output(const SectionAlignment &value, void *ctxt, 243 raw_ostream &out) { 244 out << llvm::format("%d", (uint32_t)value); 245 } 246 247 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 259 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 260}; 261 262template <> 263struct ScalarEnumerationTraits<NListType> { 264 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 273template <> 274struct ScalarBitSetTraits<SymbolScope> { 275 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 281template <> 282struct ScalarBitSetTraits<SymbolDesc> { 283 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 293template <> 294struct MappingTraits<Section> { 295 struct NormalizedContentBytes; 296 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 { 321 NormalizedContent(IO &io) : _io(io) {} 322 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 } 328 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 349template <> 350struct MappingTraits<Relocation> { 351 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 367template <> 368struct ScalarEnumerationTraits<RelocationInfoType> { 369 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 460template <> 461struct MappingTraits<Symbol> { 462 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"). 483template <> 484struct ScalarTraits<VMProtect> { 485 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 } 490 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 } 524 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 525}; 526 527 528template <> 529struct MappingTraits<Segment> { 530 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 539template <> 540struct ScalarEnumerationTraits<LoadCommandType> { 541 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 563template <> 564struct MappingTraits<DependentDylib> { 565 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 576template <> 577struct ScalarEnumerationTraits<RebaseType> { 578 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 589template <> 590struct MappingTraits<RebaseLocation> { 591 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 601template <> 602struct ScalarEnumerationTraits<BindType> { 603 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 613template <> 614struct MappingTraits<BindLocation> { 615 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 628template <> 629struct ScalarEnumerationTraits<ExportSymbolKind> { 630 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 640template <> 641struct ScalarBitSetTraits<ExportFlags> { 642 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 653template <> 654struct MappingTraits<Export> { 655 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 667template <> 668struct ScalarEnumerationTraits<DataRegionType> { 669 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 683template <> 684struct MappingTraits<DataInCode> { 685 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 692template <> 693struct ScalarTraits<PackedVersion> { 694 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 } 700 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 } 708 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 709}; 710 711template <> 712struct MappingTraits<NormalizedFile> { 713 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 } 743 static StringRef validate(IO &io, NormalizedFile &file) { 744 return StringRef(); 745 } 746}; 747 748} // namespace llvm 749} // namespace yaml 750 751 752namespace lld { 753namespace mach_o { 754 755/// Handles !mach-o tagged yaml documents. 756bool MachOYamlIOTaggedDocumentHandler::handledDocTag(llvm::yaml::IO &io, 757 const lld::File *&file) const { 758 if (!io.mapTag("!mach-o")) 759 return false; 760 // Step 1: parse yaml into normalized mach-o struct. 761 NormalizedFile nf; 762 YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext()); 763 assert(info != nullptr); 764 assert(info->_normalizeMachOFile == nullptr); 765 info->_normalizeMachOFile = &nf; 766 MappingTraits<NormalizedFile>::mapping(io, nf); 767 // Step 2: parse normalized mach-o struct into atoms. 768 auto fileOrError = normalizedToAtoms(nf, info->_path, true); 769 770 // Check that we parsed successfully. 771 if (!fileOrError) { 772 std::string buffer; 773 llvm::raw_string_ostream stream(buffer); 774 handleAllErrors(fileOrError.takeError(), 775 [&](const llvm::ErrorInfoBase &EI) { 776 EI.log(stream); 777 stream << "\n"; 778 }); 779 io.setError(stream.str()); 780 return false; 781 } 782 783 if (nf.arch != _arch) { 784 io.setError(Twine("file is wrong architecture. Expected (" 785 + MachOLinkingContext::nameFromArch(_arch) 786 + ") found (" 787 + MachOLinkingContext::nameFromArch(nf.arch) 788 + ")")); 789 return false; 790 } 791 info->_normalizeMachOFile = nullptr; 792 file = fileOrError->release(); 793 return true; 794} 795 796 797 798namespace normalized { 799 800/// Parses a yaml encoded mach-o file to produce an in-memory normalized view. 801llvm::Expected<std::unique_ptr<NormalizedFile>> 802readYaml(std::unique_ptr<MemoryBuffer> &mb) { 803 // Make empty NormalizedFile. 804 std::unique_ptr<NormalizedFile> f(new NormalizedFile()); 805 806 // Create YAML Input parser. 807 YamlContext yamlContext; 808 yamlContext._normalizeMachOFile = f.get(); 809 llvm::yaml::Input yin(mb->getBuffer(), &yamlContext); 810 811 // Fill NormalizedFile by parsing yaml. 812 yin >> *f; 813 814 // Return error if there were parsing problems. 815 if (auto ec = yin.error()) 816 return llvm::make_error<GenericError>(Twine("YAML parsing error: ") 817 + ec.message()); 818 819 // Hand ownership of instantiated NormalizedFile to caller. 820 return std::move(f); 821} 822 823 824/// Writes a yaml encoded mach-o files from an in-memory normalized view. 825std::error_code writeYaml(const NormalizedFile &file, raw_ostream &out) { 826 // YAML I/O is not const aware, so need to cast away ;-( 827 NormalizedFile *f = const_cast<NormalizedFile*>(&file); 828 829 // Create yaml Output writer, using yaml options for context. 830 YamlContext yamlContext; 831 yamlContext._normalizeMachOFile = f; 832 llvm::yaml::Output yout(out, &yamlContext); 833 834 // Stream out yaml. 835 yout << *f; 836 837 return std::error_code(); 838} 839 840} // namespace normalized 841} // namespace mach_o 842} // namespace lld 843