//===- TBEHandler.cpp -----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===-----------------------------------------------------------------------===/ #include "llvm/InterfaceStub/TBEHandler.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/InterfaceStub/ELFStub.h" #include "llvm/Support/Error.h" #include "llvm/Support/YAMLTraits.h" using namespace llvm; using namespace llvm::elfabi; LLVM_YAML_STRONG_TYPEDEF(ELFArch, ELFArchMapper) namespace llvm { namespace yaml { /// YAML traits for ELFSymbolType. template <> struct ScalarEnumerationTraits { static void enumeration(IO &IO, ELFSymbolType &SymbolType) { IO.enumCase(SymbolType, "NoType", ELFSymbolType::NoType); IO.enumCase(SymbolType, "Func", ELFSymbolType::Func); IO.enumCase(SymbolType, "Object", ELFSymbolType::Object); IO.enumCase(SymbolType, "TLS", ELFSymbolType::TLS); IO.enumCase(SymbolType, "Unknown", ELFSymbolType::Unknown); // Treat other symbol types as noise, and map to Unknown. if (!IO.outputting() && IO.matchEnumFallback()) SymbolType = ELFSymbolType::Unknown; } }; /// YAML traits for ELFArch. template <> struct ScalarTraits { static void output(const ELFArchMapper &Value, void *, llvm::raw_ostream &Out) { // Map from integer to architecture string. switch (Value) { case (ELFArch)ELF::EM_X86_64: Out << "x86_64"; break; case (ELFArch)ELF::EM_AARCH64: Out << "AArch64"; break; case (ELFArch)ELF::EM_NONE: default: Out << "Unknown"; } } static StringRef input(StringRef Scalar, void *, ELFArchMapper &Value) { // Map from architecture string to integer. Value = StringSwitch(Scalar) .Case("x86_64", ELF::EM_X86_64) .Case("AArch64", ELF::EM_AARCH64) .Case("Unknown", ELF::EM_NONE) .Default(ELF::EM_NONE); // Returning empty StringRef indicates successful parse. return StringRef(); } // Don't place quotation marks around architecture value. static QuotingType mustQuote(StringRef) { return QuotingType::None; } }; /// YAML traits for ELFSymbol. template <> struct MappingTraits { static void mapping(IO &IO, ELFSymbol &Symbol) { IO.mapRequired("Type", Symbol.Type); // The need for symbol size depends on the symbol type. if (Symbol.Type == ELFSymbolType::NoType) { IO.mapOptional("Size", Symbol.Size, (uint64_t)0); } else if (Symbol.Type == ELFSymbolType::Func) { Symbol.Size = 0; } else { IO.mapRequired("Size", Symbol.Size); } IO.mapOptional("Undefined", Symbol.Undefined, false); IO.mapOptional("Weak", Symbol.Weak, false); IO.mapOptional("Warning", Symbol.Warning); } // Compacts symbol information into a single line. static const bool flow = true; }; /// YAML traits for set of ELFSymbols. template <> struct CustomMappingTraits> { static void inputOne(IO &IO, StringRef Key, std::set &Set) { ELFSymbol Sym(Key.str()); IO.mapRequired(Key.str().c_str(), Sym); Set.insert(Sym); } static void output(IO &IO, std::set &Set) { for (auto &Sym : Set) IO.mapRequired(Sym.Name.c_str(), const_cast(Sym)); } }; /// YAML traits for ELFStub objects. template <> struct MappingTraits { static void mapping(IO &IO, ELFStub &Stub) { if (!IO.mapTag("!tapi-tbe", true)) IO.setError("Not a .tbe YAML file."); IO.mapRequired("TbeVersion", Stub.TbeVersion); IO.mapOptional("SoName", Stub.SoName); IO.mapRequired("Arch", (ELFArchMapper &)Stub.Arch); IO.mapOptional("NeededLibs", Stub.NeededLibs); IO.mapRequired("Symbols", Stub.Symbols); } }; } // end namespace yaml } // end namespace llvm Expected> elfabi::readTBEFromBuffer(StringRef Buf) { yaml::Input YamlIn(Buf); std::unique_ptr Stub(new ELFStub()); YamlIn >> *Stub; if (std::error_code Err = YamlIn.error()) return createStringError(Err, "YAML failed reading as TBE"); if (Stub->TbeVersion > elfabi::TBEVersionCurrent) return make_error( "TBE version " + Stub->TbeVersion.getAsString() + " is unsupported.", std::make_error_code(std::errc::invalid_argument)); return std::move(Stub); } Error elfabi::writeTBEToOutputStream(raw_ostream &OS, const ELFStub &Stub) { yaml::Output YamlOut(OS, NULL, /*WrapColumn =*/0); YamlOut << const_cast(Stub); return Error::success(); }