1//===- TBEHandler.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#include "llvm/TextAPI/ELF/TBEHandler.h" 10#include "llvm/ADT/StringSwitch.h" 11#include "llvm/ADT/StringRef.h" 12#include "llvm/Support/Error.h" 13#include "llvm/Support/YAMLTraits.h" 14#include "llvm/TextAPI/ELF/ELFStub.h" 15 16using namespace llvm; 17using namespace llvm::elfabi; 18 19LLVM_YAML_STRONG_TYPEDEF(ELFArch, ELFArchMapper) 20 21namespace llvm { 22namespace yaml { 23 24/// YAML traits for ELFSymbolType. 25template <> struct ScalarEnumerationTraits<ELFSymbolType> { 26 static void enumeration(IO &IO, ELFSymbolType &SymbolType) { 27 IO.enumCase(SymbolType, "NoType", ELFSymbolType::NoType); 28 IO.enumCase(SymbolType, "Func", ELFSymbolType::Func); 29 IO.enumCase(SymbolType, "Object", ELFSymbolType::Object); 30 IO.enumCase(SymbolType, "TLS", ELFSymbolType::TLS); 31 IO.enumCase(SymbolType, "Unknown", ELFSymbolType::Unknown); 32 // Treat other symbol types as noise, and map to Unknown. 33 if (!IO.outputting() && IO.matchEnumFallback()) 34 SymbolType = ELFSymbolType::Unknown; 35 } 36}; 37 38/// YAML traits for ELFArch. 39template <> struct ScalarTraits<ELFArchMapper> { 40 static void output(const ELFArchMapper &Value, void *, 41 llvm::raw_ostream &Out) { 42 // Map from integer to architecture string. 43 switch (Value) { 44 case (ELFArch)ELF::EM_X86_64: 45 Out << "x86_64"; 46 break; 47 case (ELFArch)ELF::EM_AARCH64: 48 Out << "AArch64"; 49 break; 50 case (ELFArch)ELF::EM_NONE: 51 default: 52 Out << "Unknown"; 53 } 54 } 55 56 static StringRef input(StringRef Scalar, void *, ELFArchMapper &Value) { 57 // Map from architecture string to integer. 58 Value = StringSwitch<ELFArch>(Scalar) 59 .Case("x86_64", ELF::EM_X86_64) 60 .Case("AArch64", ELF::EM_AARCH64) 61 .Case("Unknown", ELF::EM_NONE) 62 .Default(ELF::EM_NONE); 63 64 // Returning empty StringRef indicates successful parse. 65 return StringRef(); 66 } 67 68 // Don't place quotation marks around architecture value. 69 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 70}; 71 72/// YAML traits for TbeVersion. 73template <> struct ScalarTraits<VersionTuple> { 74 static void output(const VersionTuple &Value, void *, 75 llvm::raw_ostream &Out) { 76 Out << Value.getAsString(); 77 } 78 79 static StringRef input(StringRef Scalar, void *, VersionTuple &Value) { 80 if (Value.tryParse(Scalar)) 81 return StringRef("Can't parse version: invalid version format."); 82 83 if (Value > TBEVersionCurrent) 84 return StringRef("Unsupported TBE version."); 85 86 // Returning empty StringRef indicates successful parse. 87 return StringRef(); 88 } 89 90 // Don't place quotation marks around version value. 91 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 92}; 93 94/// YAML traits for ELFSymbol. 95template <> struct MappingTraits<ELFSymbol> { 96 static void mapping(IO &IO, ELFSymbol &Symbol) { 97 IO.mapRequired("Type", Symbol.Type); 98 // The need for symbol size depends on the symbol type. 99 if (Symbol.Type == ELFSymbolType::NoType) { 100 IO.mapOptional("Size", Symbol.Size, (uint64_t)0); 101 } else if (Symbol.Type == ELFSymbolType::Func) { 102 Symbol.Size = 0; 103 } else { 104 IO.mapRequired("Size", Symbol.Size); 105 } 106 IO.mapOptional("Undefined", Symbol.Undefined, false); 107 IO.mapOptional("Weak", Symbol.Weak, false); 108 IO.mapOptional("Warning", Symbol.Warning); 109 } 110 111 // Compacts symbol information into a single line. 112 static const bool flow = true; 113}; 114 115/// YAML traits for set of ELFSymbols. 116template <> struct CustomMappingTraits<std::set<ELFSymbol>> { 117 static void inputOne(IO &IO, StringRef Key, std::set<ELFSymbol> &Set) { 118 ELFSymbol Sym(Key.str()); 119 IO.mapRequired(Key.str().c_str(), Sym); 120 Set.insert(Sym); 121 } 122 123 static void output(IO &IO, std::set<ELFSymbol> &Set) { 124 for (auto &Sym : Set) 125 IO.mapRequired(Sym.Name.c_str(), const_cast<ELFSymbol &>(Sym)); 126 } 127}; 128 129/// YAML traits for ELFStub objects. 130template <> struct MappingTraits<ELFStub> { 131 static void mapping(IO &IO, ELFStub &Stub) { 132 if (!IO.mapTag("!tapi-tbe", true)) 133 IO.setError("Not a .tbe YAML file."); 134 IO.mapRequired("TbeVersion", Stub.TbeVersion); 135 IO.mapOptional("SoName", Stub.SoName); 136 IO.mapRequired("Arch", (ELFArchMapper &)Stub.Arch); 137 IO.mapOptional("NeededLibs", Stub.NeededLibs); 138 IO.mapRequired("Symbols", Stub.Symbols); 139 } 140}; 141 142} // end namespace yaml 143} // end namespace llvm 144 145Expected<std::unique_ptr<ELFStub>> elfabi::readTBEFromBuffer(StringRef Buf) { 146 yaml::Input YamlIn(Buf); 147 std::unique_ptr<ELFStub> Stub(new ELFStub()); 148 YamlIn >> *Stub; 149 if (std::error_code Err = YamlIn.error()) 150 return createStringError(Err, "YAML failed reading as TBE"); 151 152 return std::move(Stub); 153} 154 155Error elfabi::writeTBEToOutputStream(raw_ostream &OS, const ELFStub &Stub) { 156 yaml::Output YamlOut(OS, NULL, /*WrapColumn =*/0); 157 158 YamlOut << const_cast<ELFStub &>(Stub); 159 return Error::success(); 160} 161