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