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