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