LLVM  14.0.0git
IFSHandler.cpp
Go to the documentation of this file.
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 //===-----------------------------------------------------------------------===/
8 
10 #include "llvm/ADT/StringRef.h"
11 #include "llvm/ADT/StringSwitch.h"
12 #include "llvm/ADT/Triple.h"
13 #include "llvm/BinaryFormat/ELF.h"
15 #include "llvm/Support/Error.h"
18 
19 using namespace llvm;
20 using namespace llvm::ifs;
21 
23 
24 namespace llvm {
25 namespace yaml {
26 
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())
38  }
39 };
40 
41 template <> struct ScalarTraits<IFSEndiannessType> {
42  static void output(const IFSEndiannessType &Value, void *,
43  llvm::raw_ostream &Out) {
44  switch (Value) {
46  Out << "big";
47  break;
49  Out << "little";
50  break;
51  default:
52  llvm_unreachable("Unsupported endianness");
53  }
54  }
55 
56  static StringRef input(StringRef Scalar, void *, IFSEndiannessType &Value) {
62  return "Unsupported endianness";
63  }
64  return StringRef();
65  }
66 
67  static QuotingType mustQuote(StringRef) { return QuotingType::None; }
68 };
69 
70 template <> struct ScalarTraits<IFSBitWidthType> {
71  static void output(const IFSBitWidthType &Value, void *,
72  llvm::raw_ostream &Out) {
73  switch (Value) {
75  Out << "32";
76  break;
78  Out << "64";
79  break;
80  default:
81  llvm_unreachable("Unsupported bit width");
82  }
83  }
84 
85  static StringRef input(StringRef Scalar, void *, IFSBitWidthType &Value) {
91  return "Unsupported bit width";
92  }
93  return StringRef();
94  }
95 
96  static QuotingType mustQuote(StringRef) { return QuotingType::None; }
97 };
98 
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);
105  }
106 
107  // Compacts symbol information into a single line.
108  static const bool flow = true; // NOLINT(readability-identifier-naming)
109 };
110 
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);
123  }
124  IO.mapOptional("Undefined", Symbol.Undefined, false);
125  IO.mapOptional("Weak", Symbol.Weak, false);
126  IO.mapOptional("Warning", Symbol.Warning);
127  }
128 
129  // Compacts symbol information into a single line.
130  static const bool flow = true; // NOLINT(readability-identifier-naming)
131 };
132 
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);
143  }
144 };
145 
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);
156  }
157 };
158 } // end namespace yaml
159 } // end namespace llvm
160 
161 /// Attempt to determine if a Text stub uses target triple.
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;
168  }
169  }
170  }
171  return true;
172 }
173 
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());
181  }
182  if (std::error_code Err = YamlIn.error()) {
183  return createStringError(Err, "YAML failed reading as IFS");
184  }
185 
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());
193  }
194  return std::move(Stub);
195 }
196 
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()));
203  }
204  IFSTarget Target = Stub.Target;
205 
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();
213 }
214 
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);
225  }
226  Stub.Target.Arch = OverrideArch.getValue();
227  }
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);
233  }
234  Stub.Target.Endianness = OverrideEndianness.getValue();
235  }
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);
241  }
242  Stub.Target.BitWidth = OverrideBitWidth.getValue();
243  }
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);
249  }
250  Stub.Target.Triple = OverrideTriple.getValue();
251  }
252  return Error::success();
253 }
254 
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);
263  }
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;
269  }
270  return Error::success();
271  }
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);
277  }
278  if (!Stub.Target.BitWidth) {
279  return make_error<StringError>("BitWidth is not defined in the text stub",
280  ValidationEC);
281  }
282  if (!Stub.Target.Endianness) {
283  return make_error<StringError>(
284  "Endianness is not defined in the text stub", ValidationEC);
285  }
286  }
287  return Error::success();
288 }
289 
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;
303  }
304  RetTarget.Endianness = IFSTriple.isLittleEndian() ? IFSEndiannessType::Little
306  RetTarget.BitWidth =
308  return RetTarget;
309 }
310 
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();
316  }
317  if (StripTriple || StripEndianness) {
318  Stub.Target.Endianness.reset();
319  }
320  if (StripTriple || StripBitWidth) {
321  Stub.Target.BitWidth.reset();
322  }
323  if (StripTriple) {
324  Stub.Target.Triple.reset();
325  }
326  if (!Stub.Target.Arch && !Stub.Target.BitWidth && !Stub.Target.Endianness) {
327  Stub.Target.ObjectFormat.reset();
328  }
329 }
330 
332  for (auto Iter = Stub.Symbols.begin(); Iter != Stub.Symbols.end();) {
333  if (Iter->Undefined) {
334  Iter = Stub.Symbols.erase(Iter);
335  } else {
336  Iter++;
337  }
338  }
339 }
llvm::StringSwitch::Case
StringSwitch & Case(StringLiteral S, T Value)
Definition: StringSwitch.h:67
llvm::ifs::IFSSymbolType::Unknown
@ Unknown
llvm::ifs::IFSStub::NeededLibs
std::vector< std::string > NeededLibs
Definition: IFSStub.h:95
llvm::StringRef::startswith
LLVM_NODISCARD bool startswith(StringRef Prefix) const
Check if this string starts with the given Prefix.
Definition: StringRef.h:286
llvm
---------------------— PointerInfo ------------------------------------—
Definition: AllocatorList.h:23
llvm::ifs::IFSBitWidthType
IFSBitWidthType
Definition: IFSStub.h:45
llvm::line_iterator
A forward iterator which reads text lines from a buffer.
Definition: LineIterator.h:33
llvm::yaml::ScalarTraits< IFSBitWidthType >::output
static void output(const IFSBitWidthType &Value, void *, llvm::raw_ostream &Out)
Definition: IFSHandler.cpp:71
llvm::ifs::IFSSymbol
Definition: IFSStub.h:53
llvm::ifs
Definition: ELFObjHandler.h:25
StringRef.h
llvm::StringSwitch::Default
LLVM_NODISCARD R Default(T Value)
Definition: StringSwitch.h:181
llvm::ELF::EM_AARCH64
@ EM_AARCH64
Definition: ELF.h:281
llvm::Target
Target - Wrapper for Target specific information.
Definition: TargetRegistry.h:137
llvm::StringRef::npos
static constexpr size_t npos
Definition: StringRef.h:60
llvm::StringRef::find
LLVM_NODISCARD size_t find(char C, size_t From=0) const
Search for the first character C in the string.
Definition: StringRef.h:315
llvm::ifs::IFSTarget::Arch
Optional< IFSArch > Arch
Definition: IFSStub.h:68
llvm::Error::success
static ErrorSuccess success()
Create a success value.
Definition: Error.h:331
llvm::XCOFF::SymbolType
SymbolType
Definition: XCOFF.h:183
llvm::yaml::ScalarTraits< IFSEndiannessType >::input
static StringRef input(StringRef Scalar, void *, IFSEndiannessType &Value)
Definition: IFSHandler.cpp:56
Error.h
llvm::ifs::IFSVersionCurrent
const VersionTuple IFSVersionCurrent(3, 0)
llvm::Triple
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:45
LLVM_YAML_IS_SEQUENCE_VECTOR
#define LLVM_YAML_IS_SEQUENCE_VECTOR(type)
IFSHandler.h
llvm::Optional
Definition: APInt.h:33
llvm::yaml::MappingTraits< IFSStub >::mapping
static void mapping(IO &IO, IFSStub &Stub)
Definition: IFSHandler.cpp:135
llvm::ifs::writeIFSToOutputStream
Error writeIFSToOutputStream(raw_ostream &OS, const IFSStub &Stub)
Attempts to write an IFS interface file to a raw_ostream.
Definition: IFSHandler.cpp:197
llvm::Expected
Tagged union holding either a T or a Error.
Definition: APFloat.h:42
llvm::yaml::MappingTraits
Definition: ModuleSummaryIndex.h:52
llvm::MemoryBufferRef
Definition: MemoryBufferRef.h:22
llvm::Triple::isArch64Bit
bool isArch64Bit() const
Test whether the architecture is 64-bit.
Definition: Triple.cpp:1336
llvm::ifs::IFSBitWidthType::Unknown
@ Unknown
llvm::ifs::IFSArch
uint16_t IFSArch
Definition: IFSStub.h:25
llvm::Triple::isLittleEndian
bool isLittleEndian() const
Tests whether the target triple is little endian.
Definition: Triple.cpp:1574
llvm::ELF::EM_NONE
@ EM_NONE
Definition: ELF.h:134
ELF.h
llvm::ifs::IFSSymbolType
IFSSymbolType
Definition: IFSStub.h:27
llvm::ifs::validateIFSTarget
Error validateIFSTarget(IFSStub &Stub, bool ParseTriple)
Validate the target platform inforation in the text stub.
Definition: IFSHandler.cpp:255
llvm::ifs::IFSStub
Definition: IFSStub.h:90
llvm::ifs::IFSSymbolType::TLS
@ TLS
llvm::ifs::readIFSFromBuffer
Expected< std::unique_ptr< IFSStub > > readIFSFromBuffer(StringRef Buf)
Attempts to read an IFS interface file from a StringRef buffer.
Definition: IFSHandler.cpp:174
llvm::ifs::IFSBitWidthType::IFS32
@ IFS32
LineIterator.h
llvm::raw_ostream
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:53
llvm::ifs::IFSEndiannessType::Big
@ Big
llvm::ifs::IFSStub::SoName
Optional< std::string > SoName
Definition: IFSStub.h:93
llvm::Triple::getArch
ArchType getArch() const
getArch - Get the parsed architecture type of this triple.
Definition: Triple.h:307
IFSStub.h
llvm::None
const NoneType None
Definition: None.h:23
llvm::ifs::IFSTarget::BitWidth
Optional< IFSBitWidthType > BitWidth
Definition: IFSStub.h:71
llvm::ifs::IFSEndiannessType::Unknown
@ Unknown
llvm::ifs::IFSTarget::ArchString
Optional< std::string > ArchString
Definition: IFSStub.h:69
llvm::StringRef::trim
LLVM_NODISCARD StringRef trim(char Char) const
Return string with consecutive Char characters starting from the left and right removed.
Definition: StringRef.h:870
llvm::ifs::IFSSymbolType::NoType
@ NoType
llvm::ifs::IFSTarget::Triple
Optional< std::string > Triple
Definition: IFSStub.h:66
llvm::yaml::ScalarTraits< IFSBitWidthType >::input
static StringRef input(StringRef Scalar, void *, IFSBitWidthType &Value)
Definition: IFSHandler.cpp:85
uint64_t
llvm::Optional::reset
void reset()
Definition: Optional.h:278
llvm::ifs::stripIFSTarget
void stripIFSTarget(IFSStub &Stub, bool StripTriple, bool StripArch, bool StripEndianness, bool StripBitWidth)
Strips target platform information from the text stub.
Definition: IFSHandler.cpp:311
move
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
Definition: README.txt:546
llvm::yaml::ScalarTraits< IFSEndiannessType >::output
static void output(const IFSEndiannessType &Value, void *, llvm::raw_ostream &Out)
Definition: IFSHandler.cpp:42
llvm::yaml::ScalarEnumerationTraits< IFSSymbolType >::enumeration
static void enumeration(IO &IO, IFSSymbolType &SymbolType)
Definition: IFSHandler.cpp:29
I
#define I(x, y, z)
Definition: MD5.cpp:59
llvm::ifs::IFSBitWidthType::IFS64
@ IFS64
llvm::ifs::IFSEndiannessType::Little
@ Little
llvm::ifs::IFSStubTriple
Definition: IFSStub.h:108
Triple.h
YAMLTraits.h
llvm::ifs::IFSEndiannessType
IFSEndiannessType
Definition: IFSStub.h:37
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:58
llvm_unreachable
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Definition: ErrorHandling.h:136
llvm::yaml::MappingTraits< IFSStubTriple >::mapping
static void mapping(IO &IO, IFSStubTriple &Stub)
Definition: IFSHandler.cpp:148
llvm::ifs::IFSSymbolType::Func
@ Func
llvm::make_error_code
std::error_code make_error_code(BitcodeError E)
Definition: BitcodeReader.h:270
llvm::yaml::MappingTraits< IFSTarget >::mapping
static void mapping(IO &IO, IFSTarget &Target)
Definition: IFSHandler.cpp:100
llvm::ifs::IFSTarget
Definition: IFSStub.h:65
llvm::ifs::parseTriple
IFSTarget parseTriple(StringRef TripleStr)
Parse llvm triple string into a IFSTarget struct.
Definition: IFSHandler.cpp:290
llvm::createStringError
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1231
llvm::ifs::IFSStub::Target
IFSTarget Target
Definition: IFSStub.h:94
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
llvm::ELF::convertEMachineToArchName
StringRef convertEMachineToArchName(uint16_t EMachine)
Convert an ELF's e_machine value into an architecture name.
Definition: ELF.cpp:205
llvm::ifs::IFSStub::IfsVersion
VersionTuple IfsVersion
Definition: IFSStub.h:92
llvm::ifs::stripIFSUndefinedSymbols
void stripIFSUndefinedSymbols(IFSStub &Stub)
Strips symbols from IFS symbol table that are undefined.
Definition: IFSHandler.cpp:331
StringSwitch.h
llvm::ifs::IFSSymbolType::Object
@ Object
llvm::ifs::IFSStub::Symbols
std::vector< IFSSymbol > Symbols
Definition: IFSStub.h:96
llvm::ARMBuildAttrs::Symbol
@ Symbol
Definition: ARMBuildAttributes.h:79
usesTriple
bool usesTriple(StringRef Buf)
Attempt to determine if a Text stub uses target triple.
Definition: IFSHandler.cpp:162
llvm::ELF::EM_X86_64
@ EM_X86_64
Definition: ELF.h:179
llvm::yaml::MappingTraits< IFSSymbol >::mapping
static void mapping(IO &IO, IFSSymbol &Symbol)
Definition: IFSHandler.cpp:113
llvm::yaml::ScalarTraits< IFSEndiannessType >::mustQuote
static QuotingType mustQuote(StringRef)
Definition: IFSHandler.cpp:67
llvm::yaml::ScalarTraits< IFSBitWidthType >::mustQuote
static QuotingType mustQuote(StringRef)
Definition: IFSHandler.cpp:96
llvm::StringSwitch
A switch()-like statement whose cases are string literals.
Definition: StringSwitch.h:42
llvm::ELF::convertArchNameToEMachine
uint16_t convertArchNameToEMachine(StringRef Arch)
Convert an architecture name into ELF's e_machine value.
Definition: ELF.cpp:18
llvm::ifs::IFSTarget::ObjectFormat
Optional< std::string > ObjectFormat
Definition: IFSStub.h:67
llvm::ifs::IFSTarget::Endianness
Optional< IFSEndiannessType > Endianness
Definition: IFSStub.h:70
llvm::Value
LLVM Value Representation.
Definition: Value.h:75
llvm::Optional::getValue
constexpr const T & getValue() const LLVM_LVALUE_FUNCTION
Definition: Optional.h:282
llvm::ifs::overrideIFSTarget
Error overrideIFSTarget(IFSStub &Stub, Optional< IFSArch > OverrideArch, Optional< IFSEndiannessType > OverrideEndianness, Optional< IFSBitWidthType > OverrideBitWidth, Optional< std::string > OverrideTriple)
Override the target platform inforation in the text stub.
Definition: IFSHandler.cpp:215