1 //===- IFSHandler.cpp -----------------------------------------------------===//
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
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"
20 using namespace llvm::ifs
;
22 LLVM_YAML_IS_SEQUENCE_VECTOR(IFSSymbol
)
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
) {
45 case IFSEndiannessType::Big
:
48 case IFSEndiannessType::Little
:
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";
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
) {
74 case IFSBitWidthType::IFS32
:
77 case IFSBitWidthType::IFS64
:
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";
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
) {
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
)) {
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
)) {
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
) {
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
;
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());
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",
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",
278 if (!Stub
.Target
.BitWidth
) {
279 return make_error
<StringError
>("BitWidth is not defined in the text stub",
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
);
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
;
298 case Triple::ArchType::x86_64
:
299 RetTarget
.Arch
= (IFSArch
)ELF::EM_X86_64
;
302 RetTarget
.Arch
= (IFSArch
)ELF::EM_NONE
;
304 RetTarget
.Endianness
= IFSTriple
.isLittleEndian() ? IFSEndiannessType::Little
305 : IFSEndiannessType::Big
;
307 IFSTriple
.isArch64Bit() ? IFSBitWidthType::IFS64
: IFSBitWidthType::IFS32
;
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();
324 Stub
.Target
.Triple
.reset();
326 if (!Stub
.Target
.Arch
&& !Stub
.Target
.BitWidth
&& !Stub
.Target
.Endianness
) {
327 Stub
.Target
.ObjectFormat
.reset();