Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/InterfaceStub/IFSHandler.cpp
35233 views
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
9
#include "llvm/InterfaceStub/IFSHandler.h"
10
#include "llvm/ADT/STLExtras.h"
11
#include "llvm/ADT/StringRef.h"
12
#include "llvm/ADT/StringSwitch.h"
13
#include "llvm/BinaryFormat/ELF.h"
14
#include "llvm/InterfaceStub/IFSStub.h"
15
#include "llvm/Support/Error.h"
16
#include "llvm/Support/GlobPattern.h"
17
#include "llvm/Support/LineIterator.h"
18
#include "llvm/Support/YAMLTraits.h"
19
#include "llvm/TargetParser/Triple.h"
20
#include <functional>
21
#include <optional>
22
23
using namespace llvm;
24
using namespace llvm::ifs;
25
26
LLVM_YAML_IS_SEQUENCE_VECTOR(IFSSymbol)
27
28
namespace llvm {
29
namespace yaml {
30
31
/// YAML traits for ELFSymbolType.
32
template <> struct ScalarEnumerationTraits<IFSSymbolType> {
33
static void enumeration(IO &IO, IFSSymbolType &SymbolType) {
34
IO.enumCase(SymbolType, "NoType", IFSSymbolType::NoType);
35
IO.enumCase(SymbolType, "Func", IFSSymbolType::Func);
36
IO.enumCase(SymbolType, "Object", IFSSymbolType::Object);
37
IO.enumCase(SymbolType, "TLS", IFSSymbolType::TLS);
38
IO.enumCase(SymbolType, "Unknown", IFSSymbolType::Unknown);
39
// Treat other symbol types as noise, and map to Unknown.
40
if (!IO.outputting() && IO.matchEnumFallback())
41
SymbolType = IFSSymbolType::Unknown;
42
}
43
};
44
45
template <> struct ScalarTraits<IFSEndiannessType> {
46
static void output(const IFSEndiannessType &Value, void *,
47
llvm::raw_ostream &Out) {
48
switch (Value) {
49
case IFSEndiannessType::Big:
50
Out << "big";
51
break;
52
case IFSEndiannessType::Little:
53
Out << "little";
54
break;
55
default:
56
llvm_unreachable("Unsupported endianness");
57
}
58
}
59
60
static StringRef input(StringRef Scalar, void *, IFSEndiannessType &Value) {
61
Value = StringSwitch<IFSEndiannessType>(Scalar)
62
.Case("big", IFSEndiannessType::Big)
63
.Case("little", IFSEndiannessType::Little)
64
.Default(IFSEndiannessType::Unknown);
65
if (Value == IFSEndiannessType::Unknown) {
66
return "Unsupported endianness";
67
}
68
return StringRef();
69
}
70
71
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
72
};
73
74
template <> struct ScalarTraits<IFSBitWidthType> {
75
static void output(const IFSBitWidthType &Value, void *,
76
llvm::raw_ostream &Out) {
77
switch (Value) {
78
case IFSBitWidthType::IFS32:
79
Out << "32";
80
break;
81
case IFSBitWidthType::IFS64:
82
Out << "64";
83
break;
84
default:
85
llvm_unreachable("Unsupported bit width");
86
}
87
}
88
89
static StringRef input(StringRef Scalar, void *, IFSBitWidthType &Value) {
90
Value = StringSwitch<IFSBitWidthType>(Scalar)
91
.Case("32", IFSBitWidthType::IFS32)
92
.Case("64", IFSBitWidthType::IFS64)
93
.Default(IFSBitWidthType::Unknown);
94
if (Value == IFSBitWidthType::Unknown) {
95
return "Unsupported bit width";
96
}
97
return StringRef();
98
}
99
100
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
101
};
102
103
template <> struct MappingTraits<IFSTarget> {
104
static void mapping(IO &IO, IFSTarget &Target) {
105
IO.mapOptional("ObjectFormat", Target.ObjectFormat);
106
IO.mapOptional("Arch", Target.ArchString);
107
IO.mapOptional("Endianness", Target.Endianness);
108
IO.mapOptional("BitWidth", Target.BitWidth);
109
}
110
111
// Compacts symbol information into a single line.
112
static const bool flow = true; // NOLINT(readability-identifier-naming)
113
};
114
115
/// YAML traits for ELFSymbol.
116
template <> struct MappingTraits<IFSSymbol> {
117
static void mapping(IO &IO, IFSSymbol &Symbol) {
118
IO.mapRequired("Name", Symbol.Name);
119
IO.mapRequired("Type", Symbol.Type);
120
// The need for symbol size depends on the symbol type.
121
if (Symbol.Type == IFSSymbolType::NoType) {
122
// Size is None, so we are reading it in, or it is non 0 so we
123
// should emit it.
124
if (!Symbol.Size || *Symbol.Size)
125
IO.mapOptional("Size", Symbol.Size);
126
} else if (Symbol.Type != IFSSymbolType::Func) {
127
IO.mapOptional("Size", Symbol.Size);
128
}
129
IO.mapOptional("Undefined", Symbol.Undefined, false);
130
IO.mapOptional("Weak", Symbol.Weak, false);
131
IO.mapOptional("Warning", Symbol.Warning);
132
}
133
134
// Compacts symbol information into a single line.
135
static const bool flow = true; // NOLINT(readability-identifier-naming)
136
};
137
138
/// YAML traits for ELFStub objects.
139
template <> struct MappingTraits<IFSStub> {
140
static void mapping(IO &IO, IFSStub &Stub) {
141
if (!IO.mapTag("!ifs-v1", true))
142
IO.setError("Not a .tbe YAML file.");
143
IO.mapRequired("IfsVersion", Stub.IfsVersion);
144
IO.mapOptional("SoName", Stub.SoName);
145
IO.mapOptional("Target", Stub.Target);
146
IO.mapOptional("NeededLibs", Stub.NeededLibs);
147
IO.mapRequired("Symbols", Stub.Symbols);
148
}
149
};
150
151
/// YAML traits for ELFStubTriple objects.
152
template <> struct MappingTraits<IFSStubTriple> {
153
static void mapping(IO &IO, IFSStubTriple &Stub) {
154
if (!IO.mapTag("!ifs-v1", true))
155
IO.setError("Not a .tbe YAML file.");
156
IO.mapRequired("IfsVersion", Stub.IfsVersion);
157
IO.mapOptional("SoName", Stub.SoName);
158
IO.mapOptional("Target", Stub.Target.Triple);
159
IO.mapOptional("NeededLibs", Stub.NeededLibs);
160
IO.mapRequired("Symbols", Stub.Symbols);
161
}
162
};
163
} // end namespace yaml
164
} // end namespace llvm
165
166
/// Attempt to determine if a Text stub uses target triple.
167
bool usesTriple(StringRef Buf) {
168
for (line_iterator I(MemoryBufferRef(Buf, "ELFStub")); !I.is_at_eof(); ++I) {
169
StringRef Line = (*I).trim();
170
if (Line.starts_with("Target:")) {
171
if (Line == "Target:" || Line.contains("{")) {
172
return false;
173
}
174
}
175
}
176
return true;
177
}
178
179
Expected<std::unique_ptr<IFSStub>> ifs::readIFSFromBuffer(StringRef Buf) {
180
yaml::Input YamlIn(Buf);
181
std::unique_ptr<IFSStubTriple> Stub(new IFSStubTriple());
182
if (usesTriple(Buf)) {
183
YamlIn >> *Stub;
184
} else {
185
YamlIn >> *static_cast<IFSStub *>(Stub.get());
186
}
187
if (std::error_code Err = YamlIn.error()) {
188
return createStringError(Err, "YAML failed reading as IFS");
189
}
190
191
if (Stub->IfsVersion > IFSVersionCurrent)
192
return make_error<StringError>(
193
"IFS version " + Stub->IfsVersion.getAsString() + " is unsupported.",
194
std::make_error_code(std::errc::invalid_argument));
195
if (Stub->Target.ArchString) {
196
uint16_t eMachine =
197
ELF::convertArchNameToEMachine(*Stub->Target.ArchString);
198
if (eMachine == ELF::EM_NONE)
199
return createStringError(
200
std::make_error_code(std::errc::invalid_argument),
201
"IFS arch '" + *Stub->Target.ArchString + "' is unsupported");
202
Stub->Target.Arch = eMachine;
203
}
204
for (const auto &Item : Stub->Symbols) {
205
if (Item.Type == IFSSymbolType::Unknown)
206
return createStringError(
207
std::make_error_code(std::errc::invalid_argument),
208
"IFS symbol type for symbol '" + Item.Name + "' is unsupported");
209
}
210
return std::move(Stub);
211
}
212
213
Error ifs::writeIFSToOutputStream(raw_ostream &OS, const IFSStub &Stub) {
214
yaml::Output YamlOut(OS, nullptr, /*WrapColumn =*/0);
215
std::unique_ptr<IFSStubTriple> CopyStub(new IFSStubTriple(Stub));
216
if (Stub.Target.Arch) {
217
CopyStub->Target.ArchString =
218
std::string(ELF::convertEMachineToArchName(*Stub.Target.Arch));
219
}
220
IFSTarget Target = Stub.Target;
221
222
if (CopyStub->Target.Triple ||
223
(!CopyStub->Target.ArchString && !CopyStub->Target.Endianness &&
224
!CopyStub->Target.BitWidth))
225
YamlOut << *CopyStub;
226
else
227
YamlOut << *static_cast<IFSStub *>(CopyStub.get());
228
return Error::success();
229
}
230
231
Error ifs::overrideIFSTarget(
232
IFSStub &Stub, std::optional<IFSArch> OverrideArch,
233
std::optional<IFSEndiannessType> OverrideEndianness,
234
std::optional<IFSBitWidthType> OverrideBitWidth,
235
std::optional<std::string> OverrideTriple) {
236
std::error_code OverrideEC(1, std::generic_category());
237
if (OverrideArch) {
238
if (Stub.Target.Arch && *Stub.Target.Arch != *OverrideArch) {
239
return make_error<StringError>(
240
"Supplied Arch conflicts with the text stub", OverrideEC);
241
}
242
Stub.Target.Arch = *OverrideArch;
243
}
244
if (OverrideEndianness) {
245
if (Stub.Target.Endianness &&
246
*Stub.Target.Endianness != *OverrideEndianness) {
247
return make_error<StringError>(
248
"Supplied Endianness conflicts with the text stub", OverrideEC);
249
}
250
Stub.Target.Endianness = *OverrideEndianness;
251
}
252
if (OverrideBitWidth) {
253
if (Stub.Target.BitWidth && *Stub.Target.BitWidth != *OverrideBitWidth) {
254
return make_error<StringError>(
255
"Supplied BitWidth conflicts with the text stub", OverrideEC);
256
}
257
Stub.Target.BitWidth = *OverrideBitWidth;
258
}
259
if (OverrideTriple) {
260
if (Stub.Target.Triple && *Stub.Target.Triple != *OverrideTriple) {
261
return make_error<StringError>(
262
"Supplied Triple conflicts with the text stub", OverrideEC);
263
}
264
Stub.Target.Triple = *OverrideTriple;
265
}
266
return Error::success();
267
}
268
269
Error ifs::validateIFSTarget(IFSStub &Stub, bool ParseTriple) {
270
std::error_code ValidationEC(1, std::generic_category());
271
if (Stub.Target.Triple) {
272
if (Stub.Target.Arch || Stub.Target.BitWidth || Stub.Target.Endianness ||
273
Stub.Target.ObjectFormat) {
274
return make_error<StringError>(
275
"Target triple cannot be used simultaneously with ELF target format",
276
ValidationEC);
277
}
278
if (ParseTriple) {
279
IFSTarget TargetFromTriple = parseTriple(*Stub.Target.Triple);
280
Stub.Target.Arch = TargetFromTriple.Arch;
281
Stub.Target.BitWidth = TargetFromTriple.BitWidth;
282
Stub.Target.Endianness = TargetFromTriple.Endianness;
283
}
284
return Error::success();
285
}
286
if (!Stub.Target.Arch || !Stub.Target.BitWidth || !Stub.Target.Endianness) {
287
// TODO: unify the error message.
288
if (!Stub.Target.Arch) {
289
return make_error<StringError>("Arch is not defined in the text stub",
290
ValidationEC);
291
}
292
if (!Stub.Target.BitWidth) {
293
return make_error<StringError>("BitWidth is not defined in the text stub",
294
ValidationEC);
295
}
296
if (!Stub.Target.Endianness) {
297
return make_error<StringError>(
298
"Endianness is not defined in the text stub", ValidationEC);
299
}
300
}
301
return Error::success();
302
}
303
304
IFSTarget ifs::parseTriple(StringRef TripleStr) {
305
Triple IFSTriple(TripleStr);
306
IFSTarget RetTarget;
307
// TODO: Implement a Triple Arch enum to e_machine map.
308
switch (IFSTriple.getArch()) {
309
case Triple::ArchType::aarch64:
310
RetTarget.Arch = (IFSArch)ELF::EM_AARCH64;
311
break;
312
case Triple::ArchType::x86_64:
313
RetTarget.Arch = (IFSArch)ELF::EM_X86_64;
314
break;
315
case Triple::ArchType::riscv64:
316
RetTarget.Arch = (IFSArch)ELF::EM_RISCV;
317
break;
318
default:
319
RetTarget.Arch = (IFSArch)ELF::EM_NONE;
320
}
321
RetTarget.Endianness = IFSTriple.isLittleEndian() ? IFSEndiannessType::Little
322
: IFSEndiannessType::Big;
323
RetTarget.BitWidth =
324
IFSTriple.isArch64Bit() ? IFSBitWidthType::IFS64 : IFSBitWidthType::IFS32;
325
return RetTarget;
326
}
327
328
void ifs::stripIFSTarget(IFSStub &Stub, bool StripTriple, bool StripArch,
329
bool StripEndianness, bool StripBitWidth) {
330
if (StripTriple || StripArch) {
331
Stub.Target.Arch.reset();
332
Stub.Target.ArchString.reset();
333
}
334
if (StripTriple || StripEndianness) {
335
Stub.Target.Endianness.reset();
336
}
337
if (StripTriple || StripBitWidth) {
338
Stub.Target.BitWidth.reset();
339
}
340
if (StripTriple) {
341
Stub.Target.Triple.reset();
342
}
343
if (!Stub.Target.Arch && !Stub.Target.BitWidth && !Stub.Target.Endianness) {
344
Stub.Target.ObjectFormat.reset();
345
}
346
}
347
348
Error ifs::filterIFSSyms(IFSStub &Stub, bool StripUndefined,
349
const std::vector<std::string> &Exclude) {
350
std::function<bool(const IFSSymbol &)> Filter = [](const IFSSymbol &) {
351
return false;
352
};
353
354
if (StripUndefined) {
355
Filter = [Filter](const IFSSymbol &Sym) {
356
return Sym.Undefined || Filter(Sym);
357
};
358
}
359
360
for (StringRef Glob : Exclude) {
361
Expected<llvm::GlobPattern> PatternOrErr = llvm::GlobPattern::create(Glob);
362
if (!PatternOrErr)
363
return PatternOrErr.takeError();
364
Filter = [Pattern = *PatternOrErr, Filter](const IFSSymbol &Sym) {
365
return Pattern.match(Sym.Name) || Filter(Sym);
366
};
367
}
368
369
llvm::erase_if(Stub.Symbols, Filter);
370
371
return Error::success();
372
}
373
374