1343171Sdim//===- TBEHandler.cpp -----------------------------------------------------===// 2343171Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6343171Sdim// 7343171Sdim//===-----------------------------------------------------------------------===/ 8343171Sdim 9343171Sdim#include "llvm/TextAPI/ELF/TBEHandler.h" 10343171Sdim#include "llvm/ADT/StringSwitch.h" 11343171Sdim#include "llvm/ADT/StringRef.h" 12343171Sdim#include "llvm/Support/Error.h" 13343171Sdim#include "llvm/Support/YAMLTraits.h" 14343171Sdim#include "llvm/TextAPI/ELF/ELFStub.h" 15343171Sdim 16343171Sdimusing namespace llvm; 17343171Sdimusing namespace llvm::elfabi; 18343171Sdim 19343171SdimLLVM_YAML_STRONG_TYPEDEF(ELFArch, ELFArchMapper) 20343171Sdim 21343171Sdimnamespace llvm { 22343171Sdimnamespace yaml { 23343171Sdim 24343171Sdim/// YAML traits for ELFSymbolType. 25343171Sdimtemplate <> struct ScalarEnumerationTraits<ELFSymbolType> { 26343171Sdim static void enumeration(IO &IO, ELFSymbolType &SymbolType) { 27343171Sdim IO.enumCase(SymbolType, "NoType", ELFSymbolType::NoType); 28343171Sdim IO.enumCase(SymbolType, "Func", ELFSymbolType::Func); 29343171Sdim IO.enumCase(SymbolType, "Object", ELFSymbolType::Object); 30343171Sdim IO.enumCase(SymbolType, "TLS", ELFSymbolType::TLS); 31343171Sdim IO.enumCase(SymbolType, "Unknown", ELFSymbolType::Unknown); 32343171Sdim // Treat other symbol types as noise, and map to Unknown. 33343171Sdim if (!IO.outputting() && IO.matchEnumFallback()) 34343171Sdim SymbolType = ELFSymbolType::Unknown; 35343171Sdim } 36343171Sdim}; 37343171Sdim 38343171Sdim/// YAML traits for ELFArch. 39343171Sdimtemplate <> struct ScalarTraits<ELFArchMapper> { 40343171Sdim static void output(const ELFArchMapper &Value, void *, 41343171Sdim llvm::raw_ostream &Out) { 42343171Sdim // Map from integer to architecture string. 43343171Sdim switch (Value) { 44343171Sdim case (ELFArch)ELF::EM_X86_64: 45343171Sdim Out << "x86_64"; 46343171Sdim break; 47343171Sdim case (ELFArch)ELF::EM_AARCH64: 48343171Sdim Out << "AArch64"; 49343171Sdim break; 50343171Sdim case (ELFArch)ELF::EM_NONE: 51343171Sdim default: 52343171Sdim Out << "Unknown"; 53343171Sdim } 54343171Sdim } 55343171Sdim 56343171Sdim static StringRef input(StringRef Scalar, void *, ELFArchMapper &Value) { 57343171Sdim // Map from architecture string to integer. 58343171Sdim Value = StringSwitch<ELFArch>(Scalar) 59343171Sdim .Case("x86_64", ELF::EM_X86_64) 60343171Sdim .Case("AArch64", ELF::EM_AARCH64) 61343171Sdim .Case("Unknown", ELF::EM_NONE) 62343171Sdim .Default(ELF::EM_NONE); 63343171Sdim 64343171Sdim // Returning empty StringRef indicates successful parse. 65343171Sdim return StringRef(); 66343171Sdim } 67343171Sdim 68343171Sdim // Don't place quotation marks around architecture value. 69343171Sdim static QuotingType mustQuote(StringRef) { return QuotingType::None; } 70343171Sdim}; 71343171Sdim 72343171Sdim/// YAML traits for TbeVersion. 73343171Sdimtemplate <> struct ScalarTraits<VersionTuple> { 74343171Sdim static void output(const VersionTuple &Value, void *, 75343171Sdim llvm::raw_ostream &Out) { 76343171Sdim Out << Value.getAsString(); 77343171Sdim } 78343171Sdim 79343171Sdim static StringRef input(StringRef Scalar, void *, VersionTuple &Value) { 80343171Sdim if (Value.tryParse(Scalar)) 81343171Sdim return StringRef("Can't parse version: invalid version format."); 82343171Sdim 83343171Sdim if (Value > TBEVersionCurrent) 84343171Sdim return StringRef("Unsupported TBE version."); 85343171Sdim 86343171Sdim // Returning empty StringRef indicates successful parse. 87343171Sdim return StringRef(); 88343171Sdim } 89343171Sdim 90343171Sdim // Don't place quotation marks around version value. 91343171Sdim static QuotingType mustQuote(StringRef) { return QuotingType::None; } 92343171Sdim}; 93343171Sdim 94343171Sdim/// YAML traits for ELFSymbol. 95343171Sdimtemplate <> struct MappingTraits<ELFSymbol> { 96343171Sdim static void mapping(IO &IO, ELFSymbol &Symbol) { 97343171Sdim IO.mapRequired("Type", Symbol.Type); 98343171Sdim // The need for symbol size depends on the symbol type. 99343171Sdim if (Symbol.Type == ELFSymbolType::NoType) { 100343171Sdim IO.mapOptional("Size", Symbol.Size, (uint64_t)0); 101343171Sdim } else if (Symbol.Type == ELFSymbolType::Func) { 102343171Sdim Symbol.Size = 0; 103343171Sdim } else { 104343171Sdim IO.mapRequired("Size", Symbol.Size); 105343171Sdim } 106343171Sdim IO.mapOptional("Undefined", Symbol.Undefined, false); 107343171Sdim IO.mapOptional("Weak", Symbol.Weak, false); 108343171Sdim IO.mapOptional("Warning", Symbol.Warning); 109343171Sdim } 110343171Sdim 111343171Sdim // Compacts symbol information into a single line. 112343171Sdim static const bool flow = true; 113343171Sdim}; 114343171Sdim 115343171Sdim/// YAML traits for set of ELFSymbols. 116343171Sdimtemplate <> struct CustomMappingTraits<std::set<ELFSymbol>> { 117343171Sdim static void inputOne(IO &IO, StringRef Key, std::set<ELFSymbol> &Set) { 118343171Sdim ELFSymbol Sym(Key.str()); 119343171Sdim IO.mapRequired(Key.str().c_str(), Sym); 120343171Sdim Set.insert(Sym); 121343171Sdim } 122343171Sdim 123343171Sdim static void output(IO &IO, std::set<ELFSymbol> &Set) { 124343171Sdim for (auto &Sym : Set) 125343171Sdim IO.mapRequired(Sym.Name.c_str(), const_cast<ELFSymbol &>(Sym)); 126343171Sdim } 127343171Sdim}; 128343171Sdim 129343171Sdim/// YAML traits for ELFStub objects. 130343171Sdimtemplate <> struct MappingTraits<ELFStub> { 131343171Sdim static void mapping(IO &IO, ELFStub &Stub) { 132343171Sdim if (!IO.mapTag("!tapi-tbe", true)) 133343171Sdim IO.setError("Not a .tbe YAML file."); 134343171Sdim IO.mapRequired("TbeVersion", Stub.TbeVersion); 135343171Sdim IO.mapOptional("SoName", Stub.SoName); 136343171Sdim IO.mapRequired("Arch", (ELFArchMapper &)Stub.Arch); 137343171Sdim IO.mapOptional("NeededLibs", Stub.NeededLibs); 138343171Sdim IO.mapRequired("Symbols", Stub.Symbols); 139343171Sdim } 140343171Sdim}; 141343171Sdim 142343171Sdim} // end namespace yaml 143343171Sdim} // end namespace llvm 144343171Sdim 145343171SdimExpected<std::unique_ptr<ELFStub>> elfabi::readTBEFromBuffer(StringRef Buf) { 146343171Sdim yaml::Input YamlIn(Buf); 147343171Sdim std::unique_ptr<ELFStub> Stub(new ELFStub()); 148343171Sdim YamlIn >> *Stub; 149343171Sdim if (std::error_code Err = YamlIn.error()) 150343171Sdim return createStringError(Err, "YAML failed reading as TBE"); 151343171Sdim 152343171Sdim return std::move(Stub); 153343171Sdim} 154343171Sdim 155343171SdimError elfabi::writeTBEToOutputStream(raw_ostream &OS, const ELFStub &Stub) { 156343171Sdim yaml::Output YamlOut(OS, NULL, /*WrapColumn =*/0); 157343171Sdim 158343171Sdim YamlOut << const_cast<ELFStub &>(Stub); 159343171Sdim return Error::success(); 160343171Sdim} 161