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> > { 57 static size_t size(IO &io, std::vector<Section> &seq) { 58 return seq.size(); 59 } 60 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> > { 69 static size_t size(IO &io, std::vector<Symbol> &seq) { 70 return seq.size(); 71 } 72 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 > { 82 static size_t size(IO &io, Relocations &seq) { 83 return seq.size(); 84 } 85 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 > { 95 static size_t size(IO &io, ContentBytes &seq) { 96 return seq.size(); 97 } 98 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 > { 110 static size_t size(IO &io, IndirectSymbols &seq) { 111 return seq.size(); 112 } 113 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> { 123 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> { 137 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> { 152 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> { 163 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> { 174 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> { 224 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> { 243 static void output(const SectionAlignment &value, void *ctxt, 244 raw_ostream &out) { 245 out << llvm::format("%d", (uint32_t)value); 246 } 247 248 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 260 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 261 }; 262 263 template <> 264 struct ScalarEnumerationTraits<NListType> { 265 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> { 276 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> { 284 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; 297 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 { 322 NormalizedContent(IO &io) : _io(io) {} 323 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 } 329 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> { 352 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> { 370 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> { 463 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> { 486 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 } 491 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 } 525 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 526 }; 527 528 529 template <> 530 struct MappingTraits<Segment> { 531 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> { 542 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> { 566 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> { 579 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> { 592 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> { 604 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> { 616 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> { 631 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> { 643 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> { 656 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> { 670 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> { 686 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> { 695 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 } 701 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 } 709 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 710 }; 711 712 template <> 713 struct MappingTraits<NormalizedFile> { 714 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 } 744 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. 757 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>> 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. 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