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