694 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			694 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===- lib/ReaderWriter/MachO/MachONormalizedFileYAML.cpp -----------------===//
 | |
| //
 | |
| //                             The LLVM Linker
 | |
| //
 | |
| // This file is distributed under the University of Illinois Open Source
 | |
| // License. See LICENSE.TXT for details.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| ///
 | |
| /// \file For mach-o object files, this implementation uses YAML I/O to
 | |
| /// provide the convert between YAML and the normalized mach-o (NM).
 | |
| ///
 | |
| ///                  +------------+         +------+ 
 | |
| ///                  | normalized |   <->   | yaml | 
 | |
| ///                  +------------+         +------+ 
 | |
| 
 | |
| #include "MachONormalizedFile.h"
 | |
| 
 | |
| #include "lld/Core/Error.h"
 | |
| #include "lld/Core/LLVM.h"
 | |
| #include "lld/ReaderWriter/YamlContext.h"
 | |
| 
 | |
| #include "llvm/ADT/SmallString.h"
 | |
| #include "llvm/ADT/StringRef.h"
 | |
| #include "llvm/ADT/StringSwitch.h"
 | |
| #include "llvm/ADT/Twine.h"
 | |
| #include "llvm/Support/Casting.h"
 | |
| #include "llvm/Support/ErrorHandling.h"
 | |
| #include "llvm/Support/MachO.h"
 | |
| #include "llvm/Support/MemoryBuffer.h"
 | |
| #include "llvm/Support/raw_ostream.h"
 | |
| #include "llvm/Support/SourceMgr.h"
 | |
| #include "llvm/Support/system_error.h"
 | |
| #include "llvm/Support/YAMLTraits.h"
 | |
| 
 | |
| 
 | |
| using llvm::StringRef;
 | |
| using llvm::error_code;
 | |
| using llvm::dyn_cast;
 | |
| using namespace llvm::yaml;
 | |
| using namespace llvm::MachO;
 | |
| using namespace lld::mach_o::normalized;
 | |
| using lld::YamlContext;
 | |
| 
 | |
| LLVM_YAML_IS_SEQUENCE_VECTOR(Segment)
 | |
| LLVM_YAML_IS_SEQUENCE_VECTOR(DependentDylib)
 | |
| LLVM_YAML_IS_SEQUENCE_VECTOR(RebaseLocation)
 | |
| LLVM_YAML_IS_SEQUENCE_VECTOR(BindLocation)
 | |
| LLVM_YAML_IS_SEQUENCE_VECTOR(Export)
 | |
| LLVM_YAML_IS_SEQUENCE_VECTOR(StringRef)
 | |
| 
 | |
| 
 | |
| // for compatibility with gcc-4.7 in C++11 mode, add extra namespace
 | |
| namespace llvm {
 | |
| namespace yaml {
 | |
| 
 | |
| // A vector of Sections is a sequence.
 | |
| template<>
 | |
| struct SequenceTraits< std::vector<Section> > {
 | |
|   static size_t size(IO &io, std::vector<Section> &seq) {
 | |
|     return seq.size();
 | |
|   }
 | |
|   static Section& element(IO &io, std::vector<Section> &seq, size_t index) {
 | |
|     if ( index >= seq.size() )
 | |
|       seq.resize(index+1);
 | |
|     return seq[index];
 | |
|   }
 | |
| };
 | |
| 
 | |
| template<>
 | |
| struct SequenceTraits< std::vector<Symbol> > {
 | |
|   static size_t size(IO &io, std::vector<Symbol> &seq) {
 | |
|     return seq.size();
 | |
|   }
 | |
|   static Symbol& element(IO &io, std::vector<Symbol> &seq, size_t index) {
 | |
|     if ( index >= seq.size() )
 | |
|       seq.resize(index+1);
 | |
|     return seq[index];
 | |
|   }
 | |
| };
 | |
| 
 | |
| // A vector of Relocations is a sequence.
 | |
| template<>
 | |
| struct SequenceTraits< Relocations > {
 | |
|   static size_t size(IO &io, Relocations &seq) {
 | |
|     return seq.size();
 | |
|   }
 | |
|   static Relocation& element(IO &io, Relocations &seq, size_t index) {
 | |
|     if ( index >= seq.size() )
 | |
|       seq.resize(index+1);
 | |
|     return seq[index];
 | |
|   }
 | |
| };
 | |
| 
 | |
| // The content for a section is represented as a flow sequence of hex bytes.
 | |
| template<>
 | |
| struct SequenceTraits< ContentBytes > {
 | |
|   static size_t size(IO &io, ContentBytes &seq) {
 | |
|     return seq.size();
 | |
|   }
 | |
|   static Hex8& element(IO &io, ContentBytes &seq, size_t index) {
 | |
|     if ( index >= seq.size() )
 | |
|       seq.resize(index+1);
 | |
|     return seq[index];
 | |
|   }
 | |
|   static const bool flow = true;
 | |
| };
 | |
| 
 | |
| // The indirect symbols for a section is represented as a flow sequence
 | |
| // of numbers (symbol table indexes).
 | |
| template<>
 | |
| struct SequenceTraits< IndirectSymbols > {
 | |
|   static size_t size(IO &io, IndirectSymbols &seq) {
 | |
|     return seq.size();
 | |
|   }
 | |
|   static uint32_t& element(IO &io, IndirectSymbols &seq, size_t index) {
 | |
|     if ( index >= seq.size() )
 | |
|       seq.resize(index+1);
 | |
|     return seq[index];
 | |
|   }
 | |
|   static const bool flow = true;
 | |
| };
 | |
| 
 | |
| template <>
 | |
| struct ScalarEnumerationTraits<lld::MachOLinkingContext::Arch> {
 | |
|   static void enumeration(IO &io, lld::MachOLinkingContext::Arch &value) {
 | |
|     io.enumCase(value, "unknown",lld::MachOLinkingContext::arch_unknown);
 | |
|     io.enumCase(value, "ppc",    lld::MachOLinkingContext::arch_ppc);
 | |
|     io.enumCase(value, "x86",    lld::MachOLinkingContext::arch_x86);
 | |
|     io.enumCase(value, "x86_64", lld::MachOLinkingContext::arch_x86_64);
 | |
|     io.enumCase(value, "armv6",  lld::MachOLinkingContext::arch_armv6);
 | |
|     io.enumCase(value, "armv7",  lld::MachOLinkingContext::arch_armv7);
 | |
|     io.enumCase(value, "armv7s", lld::MachOLinkingContext::arch_armv7s);
 | |
|   }
 | |
| };
 | |
| 
 | |
| template <>
 | |
| struct ScalarEnumerationTraits<lld::MachOLinkingContext::OS> {
 | |
|   static void enumeration(IO &io, lld::MachOLinkingContext::OS &value) {
 | |
|     io.enumCase(value, "unknown",    
 | |
|                           lld::MachOLinkingContext::OS::unknown);
 | |
|     io.enumCase(value, "Mac OS X",    
 | |
|                           lld::MachOLinkingContext::OS::macOSX);
 | |
|     io.enumCase(value, "iOS",         
 | |
|                           lld::MachOLinkingContext::OS::iOS);
 | |
|     io.enumCase(value, "iOS Simulator", 
 | |
|                           lld::MachOLinkingContext::OS::iOS_simulator);
 | |
|   }
 | |
| };
 | |
| 
 | |
| 
 | |
| template <>
 | |
| struct ScalarEnumerationTraits<HeaderFileType> {
 | |
|   static void enumeration(IO &io, HeaderFileType &value) {
 | |
|     io.enumCase(value, "MH_OBJECT",   llvm::MachO::MH_OBJECT);
 | |
|     io.enumCase(value, "MH_DYLIB",    llvm::MachO::MH_DYLIB);
 | |
|     io.enumCase(value, "MH_EXECUTE",  llvm::MachO::MH_EXECUTE);
 | |
|     io.enumCase(value, "MH_BUNDLE",   llvm::MachO::MH_BUNDLE);
 | |
|   }
 | |
| };
 | |
| 
 | |
| 
 | |
| template <>
 | |
| struct ScalarBitSetTraits<FileFlags> {
 | |
|   static void bitset(IO &io, FileFlags &value) {
 | |
|     io.bitSetCase(value, "MH_TWOLEVEL", 
 | |
|                           llvm::MachO::MH_TWOLEVEL);
 | |
|     io.bitSetCase(value, "MH_SUBSECTIONS_VIA_SYMBOLS",  
 | |
|                           llvm::MachO::MH_SUBSECTIONS_VIA_SYMBOLS);
 | |
|   }
 | |
| };
 | |
| 
 | |
| 
 | |
| template <>
 | |
| struct ScalarEnumerationTraits<SectionType> {
 | |
|   static void enumeration(IO &io, SectionType &value) {
 | |
|     io.enumCase(value, "S_REGULAR",  
 | |
|                         llvm::MachO::S_REGULAR);
 | |
|     io.enumCase(value, "S_ZEROFILL", 
 | |
|                         llvm::MachO::S_ZEROFILL);
 | |
|     io.enumCase(value, "S_CSTRING_LITERALS", 
 | |
|                         llvm::MachO::S_CSTRING_LITERALS);
 | |
|     io.enumCase(value, "S_4BYTE_LITERALS", 
 | |
|                         llvm::MachO::S_4BYTE_LITERALS);
 | |
|     io.enumCase(value, "S_8BYTE_LITERALS", 
 | |
|                         llvm::MachO::S_8BYTE_LITERALS);
 | |
|     io.enumCase(value, "S_LITERAL_POINTERS", 
 | |
|                         llvm::MachO::S_LITERAL_POINTERS);
 | |
|     io.enumCase(value, "S_NON_LAZY_SYMBOL_POINTERS", 
 | |
|                         llvm::MachO::S_NON_LAZY_SYMBOL_POINTERS);
 | |
|     io.enumCase(value, "S_LAZY_SYMBOL_POINTERS", 
 | |
|                         llvm::MachO::S_LAZY_SYMBOL_POINTERS);
 | |
|     io.enumCase(value, "S_SYMBOL_STUBS", 
 | |
|                         llvm::MachO::S_SYMBOL_STUBS);
 | |
|     io.enumCase(value, "S_MOD_INIT_FUNC_POINTERS", 
 | |
|                         llvm::MachO::S_MOD_INIT_FUNC_POINTERS);
 | |
|     io.enumCase(value, "S_MOD_TERM_FUNC_POINTERS", 
 | |
|                         llvm::MachO::S_MOD_TERM_FUNC_POINTERS);
 | |
|     io.enumCase(value, "S_COALESCED", 
 | |
|                         llvm::MachO::S_COALESCED);
 | |
|     io.enumCase(value, "S_GB_ZEROFILL", 
 | |
|                         llvm::MachO::S_GB_ZEROFILL);
 | |
|     io.enumCase(value, "S_INTERPOSING", 
 | |
|                         llvm::MachO::S_INTERPOSING);
 | |
|     io.enumCase(value, "S_16BYTE_LITERALS", 
 | |
|                         llvm::MachO::S_16BYTE_LITERALS);
 | |
|     io.enumCase(value, "S_DTRACE_DOF", 
 | |
|                         llvm::MachO::S_DTRACE_DOF);
 | |
|     io.enumCase(value, "S_LAZY_DYLIB_SYMBOL_POINTERS", 
 | |
|                         llvm::MachO::S_LAZY_DYLIB_SYMBOL_POINTERS);
 | |
|     io.enumCase(value, "S_THREAD_LOCAL_REGULAR", 
 | |
|                         llvm::MachO::S_THREAD_LOCAL_REGULAR);
 | |
|     io.enumCase(value, "S_THREAD_LOCAL_ZEROFILL", 
 | |
|                         llvm::MachO::S_THREAD_LOCAL_ZEROFILL);
 | |
|     io.enumCase(value, "S_THREAD_LOCAL_VARIABLES", 
 | |
|                         llvm::MachO::S_THREAD_LOCAL_VARIABLES);
 | |
|     io.enumCase(value, "S_THREAD_LOCAL_VARIABLE_POINTERS", 
 | |
|                         llvm::MachO::S_THREAD_LOCAL_VARIABLE_POINTERS);
 | |
|     io.enumCase(value, "S_THREAD_LOCAL_INIT_FUNCTION_POINTERS", 
 | |
|                         llvm::MachO::S_THREAD_LOCAL_INIT_FUNCTION_POINTERS);
 | |
|   }
 | |
| };
 | |
| 
 | |
| template <>
 | |
| struct ScalarBitSetTraits<SectionAttr> {
 | |
|   static void bitset(IO &io, SectionAttr &value) {
 | |
|     io.bitSetCase(value, "S_ATTR_PURE_INSTRUCTIONS", 
 | |
|                           llvm::MachO::S_ATTR_PURE_INSTRUCTIONS);
 | |
|     io.bitSetCase(value, "S_ATTR_SOME_INSTRUCTIONS",  
 | |
|                           llvm::MachO::S_ATTR_SOME_INSTRUCTIONS);
 | |
|     io.bitSetCase(value, "S_ATTR_NO_DEAD_STRIP",  
 | |
|                           llvm::MachO::S_ATTR_NO_DEAD_STRIP);
 | |
|     io.bitSetCase(value, "S_ATTR_EXT_RELOC",  
 | |
|                           llvm::MachO::S_ATTR_EXT_RELOC);
 | |
|     io.bitSetCase(value, "S_ATTR_LOC_RELOC",  
 | |
|                           llvm::MachO::S_ATTR_LOC_RELOC);
 | |
|   }
 | |
| };
 | |
| 
 | |
| template <>
 | |
| struct ScalarEnumerationTraits<NListType> {
 | |
|   static void enumeration(IO &io, NListType &value) {
 | |
|     io.enumCase(value, "N_UNDF",  llvm::MachO::N_UNDF);
 | |
|     io.enumCase(value, "N_ABS",   llvm::MachO::N_ABS);
 | |
|     io.enumCase(value, "N_SECT",  llvm::MachO::N_SECT);
 | |
|     io.enumCase(value, "N_PBUD",  llvm::MachO::N_PBUD);
 | |
|     io.enumCase(value, "N_INDR",  llvm::MachO::N_INDR);
 | |
|   }
 | |
| };
 | |
| 
 | |
| template <>
 | |
| struct ScalarBitSetTraits<SymbolScope> {
 | |
|   static void bitset(IO &io, SymbolScope &value) {
 | |
|     io.bitSetCase(value, "N_EXT",   llvm::MachO::N_EXT);
 | |
|     io.bitSetCase(value, "N_PEXT",  llvm::MachO::N_PEXT);
 | |
|   }
 | |
| };
 | |
| 
 | |
| template <>
 | |
| struct ScalarBitSetTraits<SymbolDesc> {
 | |
|   static void bitset(IO &io, SymbolDesc &value) {
 | |
|     io.bitSetCase(value, "N_NO_DEAD_STRIP",   llvm::MachO::N_NO_DEAD_STRIP);
 | |
|     io.bitSetCase(value, "N_WEAK_REF",        llvm::MachO::N_WEAK_REF);
 | |
|     io.bitSetCase(value, "N_WEAK_DEF",        llvm::MachO::N_WEAK_DEF);
 | |
|     io.bitSetCase(value, "N_ARM_THUMB_DEF",   llvm::MachO::N_ARM_THUMB_DEF);
 | |
|     io.bitSetCase(value, "N_SYMBOL_RESOLVER", llvm::MachO::N_SYMBOL_RESOLVER);
 | |
|   }
 | |
| };
 | |
| 
 | |
| 
 | |
| template <>
 | |
| struct MappingTraits<Section> {
 | |
|   struct NormalizedContentBytes;
 | |
|   static void mapping(IO &io, Section §) {
 | |
|     io.mapRequired("segment",         sect.segmentName);
 | |
|     io.mapRequired("section",         sect.sectionName);
 | |
|     io.mapRequired("type",            sect.type);
 | |
|     io.mapOptional("attributes",      sect.attributes);
 | |
|     io.mapOptional("alignment",       sect.alignment, 0U);
 | |
|     io.mapRequired("address",         sect.address);
 | |
|     MappingNormalization<NormalizedContent, ArrayRef<uint8_t>> content(
 | |
|         io, sect.content);
 | |
|     io.mapOptional("content",         content->_normalizedContent);
 | |
|     io.mapOptional("relocations",     sect.relocations);
 | |
|     io.mapOptional("indirect-syms",   sect.indirectSymbols);
 | |
|   }
 | |
| 
 | |
|   struct NormalizedContent {
 | |
|     NormalizedContent(IO &io) : _io(io) {}
 | |
|     NormalizedContent(IO &io, ArrayRef<uint8_t> content) : _io(io) {
 | |
|       // When writing yaml, copy content byte array to Hex8 vector.
 | |
|       for (auto &c : content) {
 | |
|         _normalizedContent.push_back(c);
 | |
|       }
 | |
|     }
 | |
|     ArrayRef<uint8_t> denormalize(IO &io) {
 | |
|       // When reading yaml, allocate byte array owned by NormalizedFile and
 | |
|       // copy Hex8 vector to byte array.
 | |
|       YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
 | |
|       assert(info != nullptr);
 | |
|       NormalizedFile *file = info->_normalizeMachOFile;
 | |
|       assert(file != nullptr);
 | |
|       size_t size = _normalizedContent.size();
 | |
|       uint8_t *bytes = file->ownedAllocations.Allocate<uint8_t>(size);
 | |
|       std::copy(_normalizedContent.begin(), _normalizedContent.end(), bytes);
 | |
|       return makeArrayRef(bytes, size);
 | |
|     }
 | |
|     
 | |
|     IO                &_io;
 | |
|     ContentBytes       _normalizedContent;
 | |
|   };
 | |
| };
 | |
| 
 | |
| 
 | |
| template <>
 | |
| struct MappingTraits<Relocation> {
 | |
|   static void mapping(IO &io, Relocation &reloc) {
 | |
|     io.mapRequired("offset",    reloc.offset);
 | |
|     io.mapOptional("scattered", reloc.scattered, false);
 | |
|     io.mapRequired("type",      reloc.type);
 | |
|     io.mapRequired("length",    reloc.length);
 | |
|     io.mapRequired("pc-rel",    reloc.pcRel);
 | |
|     if ( !reloc.scattered )
 | |
|      io.mapRequired("extern",   reloc.isExtern);
 | |
|     if ( reloc.scattered )
 | |
|      io.mapRequired("value",    reloc.value);
 | |
|     if ( !reloc.scattered )
 | |
|      io.mapRequired("symbol",   reloc.symbol);
 | |
|   }
 | |
| };
 | |
| 
 | |
| 
 | |
| template <>
 | |
| struct ScalarEnumerationTraits<RelocationInfoType> {
 | |
|   static void enumeration(IO &io, RelocationInfoType &value) {
 | |
|     YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
 | |
|     assert(info != nullptr);
 | |
|     NormalizedFile *file = info->_normalizeMachOFile;
 | |
|     assert(file != nullptr);
 | |
|     switch (file->arch) {
 | |
|     case lld::MachOLinkingContext::arch_x86_64:
 | |
|       io.enumCase(value, "X86_64_RELOC_UNSIGNED",  
 | |
|                                   llvm::MachO::X86_64_RELOC_UNSIGNED);
 | |
|       io.enumCase(value, "X86_64_RELOC_SIGNED",   
 | |
|                                   llvm::MachO::X86_64_RELOC_SIGNED);
 | |
|       io.enumCase(value, "X86_64_RELOC_BRANCH",    
 | |
|                                   llvm::MachO::X86_64_RELOC_BRANCH);
 | |
|       io.enumCase(value, "X86_64_RELOC_GOT_LOAD",    
 | |
|                                   llvm::MachO::X86_64_RELOC_GOT_LOAD);
 | |
|       io.enumCase(value, "X86_64_RELOC_GOT",    
 | |
|                                   llvm::MachO::X86_64_RELOC_GOT);
 | |
|       io.enumCase(value, "X86_64_RELOC_SUBTRACTOR",   
 | |
|                                   llvm::MachO::X86_64_RELOC_SUBTRACTOR);
 | |
|       io.enumCase(value, "X86_64_RELOC_SIGNED_1",    
 | |
|                                   llvm::MachO::X86_64_RELOC_SIGNED_1);
 | |
|       io.enumCase(value, "X86_64_RELOC_SIGNED_2",    
 | |
|                                   llvm::MachO::X86_64_RELOC_SIGNED_2);
 | |
|       io.enumCase(value, "X86_64_RELOC_SIGNED_4",    
 | |
|                                   llvm::MachO::X86_64_RELOC_SIGNED_4);
 | |
|       io.enumCase(value, "X86_64_RELOC_TLV",    
 | |
|                                   llvm::MachO::X86_64_RELOC_TLV);
 | |
|       break;
 | |
|     case lld::MachOLinkingContext::arch_x86:
 | |
|       io.enumCase(value, "GENERIC_RELOC_VANILLA",  
 | |
|                                   llvm::MachO::GENERIC_RELOC_VANILLA);
 | |
|       io.enumCase(value, "GENERIC_RELOC_PAIR",   
 | |
|                                   llvm::MachO::GENERIC_RELOC_PAIR);
 | |
|       io.enumCase(value, "GENERIC_RELOC_SECTDIFF",  
 | |
|                                   llvm::MachO::GENERIC_RELOC_SECTDIFF);
 | |
|       io.enumCase(value, "GENERIC_RELOC_LOCAL_SECTDIFF",   
 | |
|                                   llvm::MachO::GENERIC_RELOC_LOCAL_SECTDIFF);
 | |
|       io.enumCase(value, "GENERIC_RELOC_TLV",   
 | |
|                                   llvm::MachO::GENERIC_RELOC_TLV);
 | |
|       break;
 | |
|     case lld::MachOLinkingContext::arch_armv6:
 | |
|     case lld::MachOLinkingContext::arch_armv7:
 | |
|     case lld::MachOLinkingContext::arch_armv7s:
 | |
|        io.enumCase(value, "ARM_RELOC_VANILLA",  
 | |
|                                   llvm::MachO::ARM_RELOC_VANILLA);
 | |
|       io.enumCase(value, "ARM_RELOC_PAIR",   
 | |
|                                   llvm::MachO::ARM_RELOC_PAIR);
 | |
|       io.enumCase(value, "ARM_RELOC_SECTDIFF",  
 | |
|                                   llvm::MachO::ARM_RELOC_SECTDIFF);
 | |
|       io.enumCase(value, "ARM_RELOC_LOCAL_SECTDIFF",   
 | |
|                                   llvm::MachO::ARM_RELOC_LOCAL_SECTDIFF);
 | |
|       io.enumCase(value, "ARM_RELOC_BR24",   
 | |
|                                   llvm::MachO::ARM_RELOC_BR24);
 | |
|       io.enumCase(value, "ARM_THUMB_RELOC_BR22",   
 | |
|                                   llvm::MachO::ARM_THUMB_RELOC_BR22);
 | |
|       io.enumCase(value, "ARM_RELOC_HALF",   
 | |
|                                   llvm::MachO::ARM_RELOC_HALF);
 | |
|       io.enumCase(value, "ARM_RELOC_HALF_SECTDIFF",   
 | |
|                                   llvm::MachO::ARM_RELOC_HALF_SECTDIFF);
 | |
|       break;
 | |
|     default:
 | |
|       llvm_unreachable("unknown architecture");
 | |
|     }
 | |
|  }
 | |
| };
 | |
| 
 | |
| 
 | |
| template <>
 | |
| struct MappingTraits<Symbol> {
 | |
|   static void mapping(IO &io, Symbol& sym) {
 | |
|     io.mapRequired("name",    sym.name);
 | |
|     io.mapRequired("type",    sym.type);
 | |
|     io.mapOptional("scope",   sym.scope, SymbolScope(0));
 | |
|     io.mapOptional("sect",    sym.sect, (uint8_t)0);
 | |
|     io.mapOptional("desc",    sym.desc, SymbolDesc(0));
 | |
|     io.mapRequired("value",   sym.value);
 | |
|   }
 | |
| };
 | |
| 
 | |
| // Custom mapping for VMProtect (e.g. "r-x").
 | |
| template <>
 | |
| struct ScalarTraits<VMProtect> {
 | |
|   static void output(const VMProtect &value, void*, raw_ostream &out) {
 | |
|     out << ( (value & llvm::MachO::VM_PROT_READ)    ? 'r' : '-');
 | |
|     out << ( (value & llvm::MachO::VM_PROT_WRITE)   ? 'w' : '-');
 | |
|     out << ( (value & llvm::MachO::VM_PROT_EXECUTE) ? 'x' : '-');
 | |
|   }
 | |
|   static StringRef input(StringRef scalar, void*, VMProtect &value) {
 | |
|     value = 0;
 | |
|     if (scalar.size() != 3)
 | |
|       return "segment access protection must be three chars (e.g. \"r-x\")";
 | |
|     switch (scalar[0]) {
 | |
|     case 'r':
 | |
|       value = llvm::MachO::VM_PROT_READ;
 | |
|       break;
 | |
|     case '-':
 | |
|       break;
 | |
|     default:
 | |
|       return "segment access protection first char must be 'r' or '-'";
 | |
|     }
 | |
|     switch (scalar[1]) {
 | |
|     case 'w':
 | |
|       value = value | llvm::MachO::VM_PROT_WRITE;
 | |
|       break;
 | |
|     case '-':
 | |
|       break;
 | |
|     default:
 | |
|       return "segment access protection second char must be 'w' or '-'";
 | |
|     }
 | |
|     switch (scalar[2]) {
 | |
|     case 'x':
 | |
|       value = value | llvm::MachO::VM_PROT_EXECUTE;
 | |
|       break;
 | |
|     case '-':
 | |
|       break;
 | |
|     default:
 | |
|       return "segment access protection third char must be 'x' or '-'";
 | |
|     }
 | |
|     // Return the empty string on success,
 | |
|     return StringRef();
 | |
|   }
 | |
| };
 | |
| 
 | |
| 
 | |
| template <>
 | |
| struct MappingTraits<Segment> {
 | |
|   static void mapping(IO &io, Segment& seg) {
 | |
|     io.mapRequired("name",      seg.name);
 | |
|     io.mapRequired("address",   seg.address);
 | |
|     io.mapRequired("size",      seg.size);
 | |
|     io.mapRequired("access",    seg.access);
 | |
|   }
 | |
| };
 | |
| 
 | |
| template <>
 | |
| struct ScalarEnumerationTraits<LoadCommandType> {
 | |
|   static void enumeration(IO &io, LoadCommandType &value) {
 | |
|     io.enumCase(value, "LC_LOAD_DYLIB",  
 | |
|                         llvm::MachO::LC_LOAD_DYLIB);
 | |
|     io.enumCase(value, "LC_LOAD_WEAK_DYLIB",  
 | |
|                         llvm::MachO::LC_LOAD_WEAK_DYLIB);
 | |
|     io.enumCase(value, "LC_REEXPORT_DYLIB",  
 | |
|                         llvm::MachO::LC_REEXPORT_DYLIB);
 | |
|     io.enumCase(value, "LC_LOAD_UPWARD_DYLIB", 
 | |
|                         llvm::MachO::LC_LOAD_UPWARD_DYLIB);
 | |
|     io.enumCase(value, "LC_LAZY_LOAD_DYLIB",  
 | |
|                         llvm::MachO::LC_LAZY_LOAD_DYLIB);
 | |
|   }
 | |
| };
 | |
| 
 | |
| template <>
 | |
| struct MappingTraits<DependentDylib> {
 | |
|   static void mapping(IO &io, DependentDylib& dylib) {
 | |
|     io.mapRequired("path",    dylib.path);
 | |
|     io.mapOptional("kind",    dylib.kind,       llvm::MachO::LC_LOAD_DYLIB);
 | |
|   }
 | |
| };
 | |
| 
 | |
| 
 | |
| template <>
 | |
| struct ScalarEnumerationTraits<RebaseType> {
 | |
|   static void enumeration(IO &io, RebaseType &value) {
 | |
|     io.enumCase(value, "REBASE_TYPE_POINTER",  
 | |
|                         llvm::MachO::REBASE_TYPE_POINTER);
 | |
|     io.enumCase(value, "REBASE_TYPE_TEXT_PCREL32",  
 | |
|                         llvm::MachO::REBASE_TYPE_TEXT_PCREL32);
 | |
|     io.enumCase(value, "REBASE_TYPE_TEXT_ABSOLUTE32",  
 | |
|                         llvm::MachO::REBASE_TYPE_TEXT_ABSOLUTE32);
 | |
|   }
 | |
| };
 | |
| 
 | |
| 
 | |
| template <>
 | |
| struct MappingTraits<RebaseLocation> {
 | |
|   static void mapping(IO &io, RebaseLocation& rebase) {
 | |
|     io.mapRequired("segment-index",   rebase.segIndex);
 | |
|     io.mapRequired("segment-offset",  rebase.segOffset);
 | |
|     io.mapOptional("kind",            rebase.kind, 
 | |
|                                       llvm::MachO::REBASE_TYPE_POINTER);
 | |
|   }
 | |
| };
 | |
| 
 | |
| 
 | |
| 
 | |
| template <>
 | |
| struct ScalarEnumerationTraits<BindType> {
 | |
|   static void enumeration(IO &io, BindType &value) {
 | |
|     io.enumCase(value, "BIND_TYPE_POINTER",  
 | |
|                         llvm::MachO::BIND_TYPE_POINTER);
 | |
|     io.enumCase(value, "BIND_TYPE_TEXT_ABSOLUTE32",  
 | |
|                         llvm::MachO::BIND_TYPE_TEXT_ABSOLUTE32);
 | |
|     io.enumCase(value, "BIND_TYPE_TEXT_PCREL32",  
 | |
|                         llvm::MachO::BIND_TYPE_TEXT_PCREL32);
 | |
|   }
 | |
| };
 | |
| 
 | |
| template <>
 | |
| struct MappingTraits<BindLocation> {
 | |
|   static void mapping(IO &io, BindLocation &bind) {
 | |
|     io.mapRequired("segment-index",   bind.segIndex);
 | |
|     io.mapRequired("segment-offset",  bind.segOffset);
 | |
|     io.mapOptional("kind",            bind.kind, 
 | |
|                                       llvm::MachO::BIND_TYPE_POINTER);
 | |
|     io.mapOptional("can-be-null",     bind.canBeNull, false);
 | |
|     io.mapRequired("ordinal",         bind.ordinal);
 | |
|     io.mapRequired("symbol-name",     bind.symbolName);
 | |
|     io.mapOptional("addend",          bind.addend, Hex64(0));
 | |
|   }
 | |
| };
 | |
| 
 | |
| 
 | |
| template <>
 | |
| struct ScalarEnumerationTraits<ExportSymbolKind> {
 | |
|   static void enumeration(IO &io, ExportSymbolKind &value) {
 | |
|     io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_REGULAR",       
 | |
|                         llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR);
 | |
|     io.enumCase(value, "EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCALl",  
 | |
|                         llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL);
 | |
|   }
 | |
| };
 | |
| 
 | |
| template <>
 | |
| struct ScalarBitSetTraits<ExportFlags> {
 | |
|   static void bitset(IO &io, ExportFlags &value) {
 | |
|     io.bitSetCase(value, "EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION",   
 | |
|                           llvm::MachO::EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION);
 | |
|     io.bitSetCase(value, "EXPORT_SYMBOL_FLAGS_REEXPORT",         
 | |
|                           llvm::MachO::EXPORT_SYMBOL_FLAGS_REEXPORT);
 | |
|     io.bitSetCase(value, "EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER",    
 | |
|                           llvm::MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER);
 | |
|   }
 | |
| };
 | |
| 
 | |
| 
 | |
| template <>
 | |
| struct MappingTraits<Export> {
 | |
|   static void mapping(IO &io, Export &exp) {
 | |
|     io.mapRequired("name",         exp.name);
 | |
|     io.mapRequired("offset",       exp.offset);
 | |
|     io.mapOptional("kind",         exp.kind, 
 | |
|                                 llvm::MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR);
 | |
|     io.mapOptional("flags",        exp.flags);
 | |
|     io.mapOptional("other-offset", exp.otherOffset, Hex32(0));
 | |
|     io.mapOptional("other-name",   exp.otherName, StringRef());
 | |
|   }
 | |
| };
 | |
| 
 | |
| 
 | |
| template <>
 | |
| struct MappingTraits<NormalizedFile> {
 | |
|   static void mapping(IO &io, NormalizedFile &file) {
 | |
|     io.mapRequired("arch",             file.arch);
 | |
|     io.mapRequired("file-type",        file.fileType);
 | |
|     io.mapOptional("flags",            file.flags);
 | |
|     io.mapOptional("dependents",       file.dependentDylibs);
 | |
|     io.mapOptional("install-name",     file.installName,    StringRef());
 | |
|     io.mapOptional("has-UUID",         file.hasUUID,        true);
 | |
|     io.mapOptional("rpaths",           file.rpaths);
 | |
|     io.mapOptional("entry-point",      file.entryAddress,   Hex64(0));
 | |
|     io.mapOptional("source-version",   file.sourceVersion,  Hex64(0));
 | |
|     io.mapOptional("OS",               file.os);
 | |
|     io.mapOptional("min-os-version",   file.minOSverson,    Hex32(0));
 | |
|     io.mapOptional("sdk-version",      file.sdkVersion,     Hex32(0));
 | |
|     io.mapOptional("segments",         file.segments);
 | |
|     io.mapOptional("sections",         file.sections);
 | |
|     io.mapOptional("local-symbols",    file.localSymbols);
 | |
|     io.mapOptional("global-symbols",   file.globalSymbols);
 | |
|     io.mapOptional("undefined-symbols",file.undefinedSymbols);
 | |
|     io.mapOptional("rebasings",        file.rebasingInfo);
 | |
|     io.mapOptional("bindings",         file.bindingInfo);
 | |
|     io.mapOptional("weak-bindings",    file.weakBindingInfo);
 | |
|     io.mapOptional("lazy-bindings",    file.lazyBindingInfo);
 | |
|     io.mapOptional("exports",          file.exportInfo);
 | |
|   }
 | |
|   static StringRef validate(IO &io, NormalizedFile &file) {
 | |
|     return StringRef();
 | |
|   }
 | |
| };
 | |
| 
 | |
| } // namespace llvm
 | |
| } // namespace yaml
 | |
| 
 | |
| 
 | |
| namespace lld {
 | |
| namespace mach_o {
 | |
| 
 | |
| /// Handles !mach-o tagged yaml documents.  
 | |
| bool MachOYamlIOTaggedDocumentHandler::handledDocTag(llvm::yaml::IO &io,
 | |
|                                                  const lld::File *&file) const {
 | |
|   if (!io.mapTag("!mach-o"))
 | |
|     return false;
 | |
|   // Step 1: parse yaml into normalized mach-o struct.
 | |
|   NormalizedFile nf;
 | |
|   YamlContext *info = reinterpret_cast<YamlContext *>(io.getContext());
 | |
|   assert(info != nullptr);
 | |
|   assert(info->_normalizeMachOFile == nullptr);
 | |
|   info->_normalizeMachOFile = &nf;
 | |
|   MappingTraits<NormalizedFile>::mapping(io, nf);
 | |
|   // Step 2: parse normalized mach-o struct into atoms.
 | |
|   ErrorOr<std::unique_ptr<lld::File>> foe = normalizedToAtoms(nf, info->_path,
 | |
|                                                               true);
 | |
|   if (foe) {
 | |
|     // Transfer ownership to "out" File parameter.
 | |
|     std::unique_ptr<lld::File> f = std::move(foe.get());
 | |
|     file = f.release();
 | |
|     return true;
 | |
|   }
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| namespace normalized {
 | |
| 
 | |
| /// Parses a yaml encoded mach-o file to produce an in-memory normalized view.
 | |
| ErrorOr<std::unique_ptr<NormalizedFile>>
 | |
| readYaml(std::unique_ptr<MemoryBuffer> &mb) {
 | |
|   // Make empty NormalizedFile.
 | |
|   std::unique_ptr<NormalizedFile> f(new NormalizedFile());
 | |
| 
 | |
|   // Create YAML Input parser.
 | |
|   YamlContext yamlContext;
 | |
|   yamlContext._normalizeMachOFile = f.get();
 | |
|   llvm::yaml::Input yin(mb->getBuffer(), &yamlContext);
 | |
| 
 | |
|   // Fill NormalizedFile by parsing yaml.
 | |
|   yin >> *f;
 | |
| 
 | |
|   // Return error if there were parsing problems.
 | |
|   if (yin.error())
 | |
|     return make_error_code(lld::YamlReaderError::illegal_value);
 | |
| 
 | |
|   // Hand ownership of instantiated NormalizedFile to caller.
 | |
|   return std::move(f);
 | |
| }
 | |
| 
 | |
| 
 | |
| /// Writes a yaml encoded mach-o files from an in-memory normalized view.
 | |
| error_code
 | |
| writeYaml(const NormalizedFile &file, raw_ostream &out) {
 | |
|   // YAML I/O is not const aware, so need to cast away ;-(
 | |
|   NormalizedFile *f = const_cast<NormalizedFile*>(&file);
 | |
| 
 | |
|   // Create yaml Output writer, using yaml options for context.
 | |
|   YamlContext yamlContext;
 | |
|   yamlContext._normalizeMachOFile = f;
 | |
|   llvm::yaml::Output yout(out, &yamlContext);
 | |
| 
 | |
|   // Stream out yaml.
 | |
|   yout << *f;
 | |
| 
 | |
|   return error_code::success();
 | |
| }
 | |
| 
 | |
| } // namespace normalized
 | |
| } // namespace mach_o
 | |
| } // namespace lld
 | |
| 
 |