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