[ORC] Add std::tuple support to SimplePackedSerialization.
[llvm-project.git] / llvm / lib / InterfaceStub / IFSHandler.cpp
blobd3d351fa2ed45b85ae520020dc88a5058c5ed382
1 //===- IFSHandler.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 //===-----------------------------------------------------------------------===/
9 #include "llvm/InterfaceStub/IFSHandler.h"
10 #include "llvm/ADT/StringRef.h"
11 #include "llvm/ADT/StringSwitch.h"
12 #include "llvm/ADT/Triple.h"
13 #include "llvm/BinaryFormat/ELF.h"
14 #include "llvm/InterfaceStub/IFSStub.h"
15 #include "llvm/Support/Error.h"
16 #include "llvm/Support/LineIterator.h"
17 #include "llvm/Support/YAMLTraits.h"
19 using namespace llvm;
20 using namespace llvm::ifs;
22 LLVM_YAML_IS_SEQUENCE_VECTOR(IFSSymbol)
24 namespace llvm {
25 namespace yaml {
27 /// YAML traits for ELFSymbolType.
28 template <> struct ScalarEnumerationTraits<IFSSymbolType> {
29 static void enumeration(IO &IO, IFSSymbolType &SymbolType) {
30 IO.enumCase(SymbolType, "NoType", IFSSymbolType::NoType);
31 IO.enumCase(SymbolType, "Func", IFSSymbolType::Func);
32 IO.enumCase(SymbolType, "Object", IFSSymbolType::Object);
33 IO.enumCase(SymbolType, "TLS", IFSSymbolType::TLS);
34 IO.enumCase(SymbolType, "Unknown", IFSSymbolType::Unknown);
35 // Treat other symbol types as noise, and map to Unknown.
36 if (!IO.outputting() && IO.matchEnumFallback())
37 SymbolType = IFSSymbolType::Unknown;
41 template <> struct ScalarTraits<IFSEndiannessType> {
42 static void output(const IFSEndiannessType &Value, void *,
43 llvm::raw_ostream &Out) {
44 switch (Value) {
45 case IFSEndiannessType::Big:
46 Out << "big";
47 break;
48 case IFSEndiannessType::Little:
49 Out << "little";
50 break;
51 default:
52 llvm_unreachable("Unsupported endianness");
56 static StringRef input(StringRef Scalar, void *, IFSEndiannessType &Value) {
57 Value = StringSwitch<IFSEndiannessType>(Scalar)
58 .Case("big", IFSEndiannessType::Big)
59 .Case("little", IFSEndiannessType::Little)
60 .Default(IFSEndiannessType::Unknown);
61 if (Value == IFSEndiannessType::Unknown) {
62 return "Unsupported endianness";
64 return StringRef();
67 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
70 template <> struct ScalarTraits<IFSBitWidthType> {
71 static void output(const IFSBitWidthType &Value, void *,
72 llvm::raw_ostream &Out) {
73 switch (Value) {
74 case IFSBitWidthType::IFS32:
75 Out << "32";
76 break;
77 case IFSBitWidthType::IFS64:
78 Out << "64";
79 break;
80 default:
81 llvm_unreachable("Unsupported bit width");
85 static StringRef input(StringRef Scalar, void *, IFSBitWidthType &Value) {
86 Value = StringSwitch<IFSBitWidthType>(Scalar)
87 .Case("32", IFSBitWidthType::IFS32)
88 .Case("64", IFSBitWidthType::IFS64)
89 .Default(IFSBitWidthType::Unknown);
90 if (Value == IFSBitWidthType::Unknown) {
91 return "Unsupported bit width";
93 return StringRef();
96 static QuotingType mustQuote(StringRef) { return QuotingType::None; }
99 template <> struct MappingTraits<IFSTarget> {
100 static void mapping(IO &IO, IFSTarget &Target) {
101 IO.mapOptional("ObjectFormat", Target.ObjectFormat);
102 IO.mapOptional("Arch", Target.ArchString);
103 IO.mapOptional("Endianness", Target.Endianness);
104 IO.mapOptional("BitWidth", Target.BitWidth);
107 // Compacts symbol information into a single line.
108 static const bool flow = true; // NOLINT(readability-identifier-naming)
111 /// YAML traits for ELFSymbol.
112 template <> struct MappingTraits<IFSSymbol> {
113 static void mapping(IO &IO, IFSSymbol &Symbol) {
114 IO.mapRequired("Name", Symbol.Name);
115 IO.mapRequired("Type", Symbol.Type);
116 // The need for symbol size depends on the symbol type.
117 if (Symbol.Type == IFSSymbolType::NoType) {
118 IO.mapOptional("Size", Symbol.Size, (uint64_t)0);
119 } else if (Symbol.Type == IFSSymbolType::Func) {
120 Symbol.Size = 0;
121 } else {
122 IO.mapRequired("Size", Symbol.Size);
124 IO.mapOptional("Undefined", Symbol.Undefined, false);
125 IO.mapOptional("Weak", Symbol.Weak, false);
126 IO.mapOptional("Warning", Symbol.Warning);
129 // Compacts symbol information into a single line.
130 static const bool flow = true; // NOLINT(readability-identifier-naming)
133 /// YAML traits for ELFStub objects.
134 template <> struct MappingTraits<IFSStub> {
135 static void mapping(IO &IO, IFSStub &Stub) {
136 if (!IO.mapTag("!ifs-v1", true))
137 IO.setError("Not a .tbe YAML file.");
138 IO.mapRequired("IfsVersion", Stub.IfsVersion);
139 IO.mapOptional("SoName", Stub.SoName);
140 IO.mapOptional("Target", Stub.Target);
141 IO.mapOptional("NeededLibs", Stub.NeededLibs);
142 IO.mapRequired("Symbols", Stub.Symbols);
146 /// YAML traits for ELFStubTriple objects.
147 template <> struct MappingTraits<IFSStubTriple> {
148 static void mapping(IO &IO, IFSStubTriple &Stub) {
149 if (!IO.mapTag("!ifs-v1", true))
150 IO.setError("Not a .tbe YAML file.");
151 IO.mapRequired("IfsVersion", Stub.IfsVersion);
152 IO.mapOptional("SoName", Stub.SoName);
153 IO.mapOptional("Target", Stub.Target.Triple);
154 IO.mapOptional("NeededLibs", Stub.NeededLibs);
155 IO.mapRequired("Symbols", Stub.Symbols);
158 } // end namespace yaml
159 } // end namespace llvm
161 /// Attempt to determine if a Text stub uses target triple.
162 bool usesTriple(StringRef Buf) {
163 for (line_iterator I(MemoryBufferRef(Buf, "ELFStub")); !I.is_at_eof(); ++I) {
164 StringRef Line = (*I).trim();
165 if (Line.startswith("Target:")) {
166 if (Line == "Target:" || (Line.find("{") != Line.npos)) {
167 return false;
171 return true;
174 Expected<std::unique_ptr<IFSStub>> ifs::readIFSFromBuffer(StringRef Buf) {
175 yaml::Input YamlIn(Buf);
176 std::unique_ptr<IFSStubTriple> Stub(new IFSStubTriple());
177 if (usesTriple(Buf)) {
178 YamlIn >> *Stub;
179 } else {
180 YamlIn >> *static_cast<IFSStub *>(Stub.get());
182 if (std::error_code Err = YamlIn.error()) {
183 return createStringError(Err, "YAML failed reading as IFS");
186 if (Stub->IfsVersion > IFSVersionCurrent)
187 return make_error<StringError>(
188 "IFS version " + Stub->IfsVersion.getAsString() + " is unsupported.",
189 std::make_error_code(std::errc::invalid_argument));
190 if (Stub->Target.ArchString) {
191 Stub->Target.Arch =
192 ELF::convertArchNameToEMachine(Stub->Target.ArchString.getValue());
194 return std::move(Stub);
197 Error ifs::writeIFSToOutputStream(raw_ostream &OS, const IFSStub &Stub) {
198 yaml::Output YamlOut(OS, NULL, /*WrapColumn =*/0);
199 std::unique_ptr<IFSStubTriple> CopyStub(new IFSStubTriple(Stub));
200 if (Stub.Target.Arch) {
201 CopyStub->Target.ArchString = std::string(
202 ELF::convertEMachineToArchName(Stub.Target.Arch.getValue()));
204 IFSTarget Target = Stub.Target;
206 if (CopyStub->Target.Triple ||
207 (!CopyStub->Target.ArchString && !CopyStub->Target.Endianness &&
208 !CopyStub->Target.BitWidth))
209 YamlOut << *CopyStub;
210 else
211 YamlOut << *static_cast<IFSStub *>(CopyStub.get());
212 return Error::success();
215 Error ifs::overrideIFSTarget(IFSStub &Stub, Optional<IFSArch> OverrideArch,
216 Optional<IFSEndiannessType> OverrideEndianness,
217 Optional<IFSBitWidthType> OverrideBitWidth,
218 Optional<std::string> OverrideTriple) {
219 std::error_code OverrideEC(1, std::generic_category());
220 if (OverrideArch) {
221 if (Stub.Target.Arch &&
222 Stub.Target.Arch.getValue() != OverrideArch.getValue()) {
223 return make_error<StringError>(
224 "Supplied Arch conflicts with the text stub", OverrideEC);
226 Stub.Target.Arch = OverrideArch.getValue();
228 if (OverrideEndianness) {
229 if (Stub.Target.Endianness &&
230 Stub.Target.Endianness.getValue() != OverrideEndianness.getValue()) {
231 return make_error<StringError>(
232 "Supplied Endianness conflicts with the text stub", OverrideEC);
234 Stub.Target.Endianness = OverrideEndianness.getValue();
236 if (OverrideBitWidth) {
237 if (Stub.Target.BitWidth &&
238 Stub.Target.BitWidth.getValue() != OverrideBitWidth.getValue()) {
239 return make_error<StringError>(
240 "Supplied BitWidth conflicts with the text stub", OverrideEC);
242 Stub.Target.BitWidth = OverrideBitWidth.getValue();
244 if (OverrideTriple) {
245 if (Stub.Target.Triple &&
246 Stub.Target.Triple.getValue() != OverrideTriple.getValue()) {
247 return make_error<StringError>(
248 "Supplied Triple conflicts with the text stub", OverrideEC);
250 Stub.Target.Triple = OverrideTriple.getValue();
252 return Error::success();
255 Error ifs::validateIFSTarget(IFSStub &Stub, bool ParseTriple) {
256 std::error_code ValidationEC(1, std::generic_category());
257 if (Stub.Target.Triple) {
258 if (Stub.Target.Arch || Stub.Target.BitWidth || Stub.Target.Endianness ||
259 Stub.Target.ObjectFormat) {
260 return make_error<StringError>(
261 "Target triple cannot be used simultaneously with ELF target format",
262 ValidationEC);
264 if (ParseTriple) {
265 IFSTarget TargetFromTriple = parseTriple(Stub.Target.Triple.getValue());
266 Stub.Target.Arch = TargetFromTriple.Arch;
267 Stub.Target.BitWidth = TargetFromTriple.BitWidth;
268 Stub.Target.Endianness = TargetFromTriple.Endianness;
270 return Error::success();
272 if (!Stub.Target.Arch || !Stub.Target.BitWidth || !Stub.Target.Endianness) {
273 // TODO: unify the error message.
274 if (!Stub.Target.Arch) {
275 return make_error<StringError>("Arch is not defined in the text stub",
276 ValidationEC);
278 if (!Stub.Target.BitWidth) {
279 return make_error<StringError>("BitWidth is not defined in the text stub",
280 ValidationEC);
282 if (!Stub.Target.Endianness) {
283 return make_error<StringError>(
284 "Endianness is not defined in the text stub", ValidationEC);
287 return Error::success();
290 IFSTarget ifs::parseTriple(StringRef TripleStr) {
291 Triple IFSTriple(TripleStr);
292 IFSTarget RetTarget;
293 // TODO: Implement a Triple Arch enum to e_machine map.
294 switch (IFSTriple.getArch()) {
295 case Triple::ArchType::aarch64:
296 RetTarget.Arch = (IFSArch)ELF::EM_AARCH64;
297 break;
298 case Triple::ArchType::x86_64:
299 RetTarget.Arch = (IFSArch)ELF::EM_X86_64;
300 break;
301 default:
302 RetTarget.Arch = (IFSArch)ELF::EM_NONE;
304 RetTarget.Endianness = IFSTriple.isLittleEndian() ? IFSEndiannessType::Little
305 : IFSEndiannessType::Big;
306 RetTarget.BitWidth =
307 IFSTriple.isArch64Bit() ? IFSBitWidthType::IFS64 : IFSBitWidthType::IFS32;
308 return RetTarget;
311 void ifs::stripIFSTarget(IFSStub &Stub, bool StripTriple, bool StripArch,
312 bool StripEndianness, bool StripBitWidth) {
313 if (StripTriple || StripArch) {
314 Stub.Target.Arch.reset();
315 Stub.Target.ArchString.reset();
317 if (StripTriple || StripEndianness) {
318 Stub.Target.Endianness.reset();
320 if (StripTriple || StripBitWidth) {
321 Stub.Target.BitWidth.reset();
323 if (StripTriple) {
324 Stub.Target.Triple.reset();
326 if (!Stub.Target.Arch && !Stub.Target.BitWidth && !Stub.Target.Endianness) {
327 Stub.Target.ObjectFormat.reset();