| //===- 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/TextAPI/ELF/TBEHandler.h" | |
| #include "llvm/ADT/StringSwitch.h" | |
| #include "llvm/ADT/StringRef.h" | |
| #include "llvm/Support/Error.h" | |
| #include "llvm/Support/YAMLTraits.h" | |
| #include "llvm/TextAPI/ELF/ELFStub.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<ELFSymbolType> { | |
| 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<ELFArchMapper> { | |
| 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<ELFArch>(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 TbeVersion. | |
| template <> struct ScalarTraits<VersionTuple> { | |
| static void output(const VersionTuple &Value, void *, | |
| llvm::raw_ostream &Out) { | |
| Out << Value.getAsString(); | |
| } | |
| static StringRef input(StringRef Scalar, void *, VersionTuple &Value) { | |
| if (Value.tryParse(Scalar)) | |
| return StringRef("Can't parse version: invalid version format."); | |
| if (Value > TBEVersionCurrent) | |
| return StringRef("Unsupported TBE version."); | |
| // Returning empty StringRef indicates successful parse. | |
| return StringRef(); | |
| } | |
| // Don't place quotation marks around version value. | |
| static QuotingType mustQuote(StringRef) { return QuotingType::None; } | |
| }; | |
| /// YAML traits for ELFSymbol. | |
| template <> struct MappingTraits<ELFSymbol> { | |
| 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<std::set<ELFSymbol>> { | |
| static void inputOne(IO &IO, StringRef Key, std::set<ELFSymbol> &Set) { | |
| ELFSymbol Sym(Key.str()); | |
| IO.mapRequired(Key.str().c_str(), Sym); | |
| Set.insert(Sym); | |
| } | |
| static void output(IO &IO, std::set<ELFSymbol> &Set) { | |
| for (auto &Sym : Set) | |
| IO.mapRequired(Sym.Name.c_str(), const_cast<ELFSymbol &>(Sym)); | |
| } | |
| }; | |
| /// YAML traits for ELFStub objects. | |
| template <> struct MappingTraits<ELFStub> { | |
| 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<std::unique_ptr<ELFStub>> elfabi::readTBEFromBuffer(StringRef Buf) { | |
| yaml::Input YamlIn(Buf); | |
| std::unique_ptr<ELFStub> Stub(new ELFStub()); | |
| YamlIn >> *Stub; | |
| if (std::error_code Err = YamlIn.error()) | |
| return createStringError(Err, "YAML failed reading as TBE"); | |
| return std::move(Stub); | |
| } | |
| Error elfabi::writeTBEToOutputStream(raw_ostream &OS, const ELFStub &Stub) { | |
| yaml::Output YamlOut(OS, NULL, /*WrapColumn =*/0); | |
| YamlOut << const_cast<ELFStub &>(Stub); | |
| return Error::success(); | |
| } |