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> > { 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 66 template<> 67 struct 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. 79 template<> 80 struct 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. 92 template<> 93 struct 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). 107 template<> 108 struct 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 120 template <> 121 struct 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 134 template <> 135 struct 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 149 template <> 150 struct 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 160 template <> 161 struct 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 171 template <> 172 struct 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 221 template <> 222 struct 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. 241 template <> 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 262 template <> 263 struct 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 273 template <> 274 struct 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 281 template <> 282 struct 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 293 template <> 294 struct 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 349 template <> 350 struct 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 367 template <> 368 struct 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 460 template <> 461 struct 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"). 483 template <> 484 struct 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 528 template <> 529 struct 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 539 template <> 540 struct 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 563 template <> 564 struct 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 576 template <> 577 struct 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 589 template <> 590 struct 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 601 template <> 602 struct 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 613 template <> 614 struct 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 628 template <> 629 struct 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 640 template <> 641 struct 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 653 template <> 654 struct 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 667 template <> 668 struct 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 683 template <> 684 struct 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 692 template <> 693 struct 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 711 template <> 712 struct 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 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. 754 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>> 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. 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