173471bf0Spatrick //===- IFSHandler.cpp -----------------------------------------------------===//
273471bf0Spatrick //
373471bf0Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
473471bf0Spatrick // See https://llvm.org/LICENSE.txt for license information.
573471bf0Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
673471bf0Spatrick //
773471bf0Spatrick //===-----------------------------------------------------------------------===/
873471bf0Spatrick
973471bf0Spatrick #include "llvm/InterfaceStub/IFSHandler.h"
10*d415bd75Srobert #include "llvm/ADT/STLExtras.h"
1173471bf0Spatrick #include "llvm/ADT/StringRef.h"
1273471bf0Spatrick #include "llvm/ADT/StringSwitch.h"
1373471bf0Spatrick #include "llvm/ADT/Triple.h"
1473471bf0Spatrick #include "llvm/BinaryFormat/ELF.h"
1573471bf0Spatrick #include "llvm/InterfaceStub/IFSStub.h"
1673471bf0Spatrick #include "llvm/Support/Error.h"
17*d415bd75Srobert #include "llvm/Support/GlobPattern.h"
1873471bf0Spatrick #include "llvm/Support/LineIterator.h"
1973471bf0Spatrick #include "llvm/Support/YAMLTraits.h"
20*d415bd75Srobert #include <functional>
21*d415bd75Srobert #include <optional>
2273471bf0Spatrick
2373471bf0Spatrick using namespace llvm;
2473471bf0Spatrick using namespace llvm::ifs;
2573471bf0Spatrick
2673471bf0Spatrick LLVM_YAML_IS_SEQUENCE_VECTOR(IFSSymbol)
2773471bf0Spatrick
2873471bf0Spatrick namespace llvm {
2973471bf0Spatrick namespace yaml {
3073471bf0Spatrick
3173471bf0Spatrick /// YAML traits for ELFSymbolType.
3273471bf0Spatrick template <> struct ScalarEnumerationTraits<IFSSymbolType> {
enumerationllvm::yaml::ScalarEnumerationTraits3373471bf0Spatrick static void enumeration(IO &IO, IFSSymbolType &SymbolType) {
3473471bf0Spatrick IO.enumCase(SymbolType, "NoType", IFSSymbolType::NoType);
3573471bf0Spatrick IO.enumCase(SymbolType, "Func", IFSSymbolType::Func);
3673471bf0Spatrick IO.enumCase(SymbolType, "Object", IFSSymbolType::Object);
3773471bf0Spatrick IO.enumCase(SymbolType, "TLS", IFSSymbolType::TLS);
3873471bf0Spatrick IO.enumCase(SymbolType, "Unknown", IFSSymbolType::Unknown);
3973471bf0Spatrick // Treat other symbol types as noise, and map to Unknown.
4073471bf0Spatrick if (!IO.outputting() && IO.matchEnumFallback())
4173471bf0Spatrick SymbolType = IFSSymbolType::Unknown;
4273471bf0Spatrick }
4373471bf0Spatrick };
4473471bf0Spatrick
4573471bf0Spatrick template <> struct ScalarTraits<IFSEndiannessType> {
outputllvm::yaml::ScalarTraits4673471bf0Spatrick static void output(const IFSEndiannessType &Value, void *,
4773471bf0Spatrick llvm::raw_ostream &Out) {
4873471bf0Spatrick switch (Value) {
4973471bf0Spatrick case IFSEndiannessType::Big:
5073471bf0Spatrick Out << "big";
5173471bf0Spatrick break;
5273471bf0Spatrick case IFSEndiannessType::Little:
5373471bf0Spatrick Out << "little";
5473471bf0Spatrick break;
5573471bf0Spatrick default:
5673471bf0Spatrick llvm_unreachable("Unsupported endianness");
5773471bf0Spatrick }
5873471bf0Spatrick }
5973471bf0Spatrick
inputllvm::yaml::ScalarTraits6073471bf0Spatrick static StringRef input(StringRef Scalar, void *, IFSEndiannessType &Value) {
6173471bf0Spatrick Value = StringSwitch<IFSEndiannessType>(Scalar)
6273471bf0Spatrick .Case("big", IFSEndiannessType::Big)
6373471bf0Spatrick .Case("little", IFSEndiannessType::Little)
6473471bf0Spatrick .Default(IFSEndiannessType::Unknown);
6573471bf0Spatrick if (Value == IFSEndiannessType::Unknown) {
6673471bf0Spatrick return "Unsupported endianness";
6773471bf0Spatrick }
6873471bf0Spatrick return StringRef();
6973471bf0Spatrick }
7073471bf0Spatrick
mustQuotellvm::yaml::ScalarTraits7173471bf0Spatrick static QuotingType mustQuote(StringRef) { return QuotingType::None; }
7273471bf0Spatrick };
7373471bf0Spatrick
7473471bf0Spatrick template <> struct ScalarTraits<IFSBitWidthType> {
outputllvm::yaml::ScalarTraits7573471bf0Spatrick static void output(const IFSBitWidthType &Value, void *,
7673471bf0Spatrick llvm::raw_ostream &Out) {
7773471bf0Spatrick switch (Value) {
7873471bf0Spatrick case IFSBitWidthType::IFS32:
7973471bf0Spatrick Out << "32";
8073471bf0Spatrick break;
8173471bf0Spatrick case IFSBitWidthType::IFS64:
8273471bf0Spatrick Out << "64";
8373471bf0Spatrick break;
8473471bf0Spatrick default:
8573471bf0Spatrick llvm_unreachable("Unsupported bit width");
8673471bf0Spatrick }
8773471bf0Spatrick }
8873471bf0Spatrick
inputllvm::yaml::ScalarTraits8973471bf0Spatrick static StringRef input(StringRef Scalar, void *, IFSBitWidthType &Value) {
9073471bf0Spatrick Value = StringSwitch<IFSBitWidthType>(Scalar)
9173471bf0Spatrick .Case("32", IFSBitWidthType::IFS32)
9273471bf0Spatrick .Case("64", IFSBitWidthType::IFS64)
9373471bf0Spatrick .Default(IFSBitWidthType::Unknown);
9473471bf0Spatrick if (Value == IFSBitWidthType::Unknown) {
9573471bf0Spatrick return "Unsupported bit width";
9673471bf0Spatrick }
9773471bf0Spatrick return StringRef();
9873471bf0Spatrick }
9973471bf0Spatrick
mustQuotellvm::yaml::ScalarTraits10073471bf0Spatrick static QuotingType mustQuote(StringRef) { return QuotingType::None; }
10173471bf0Spatrick };
10273471bf0Spatrick
10373471bf0Spatrick template <> struct MappingTraits<IFSTarget> {
mappingllvm::yaml::MappingTraits10473471bf0Spatrick static void mapping(IO &IO, IFSTarget &Target) {
10573471bf0Spatrick IO.mapOptional("ObjectFormat", Target.ObjectFormat);
10673471bf0Spatrick IO.mapOptional("Arch", Target.ArchString);
10773471bf0Spatrick IO.mapOptional("Endianness", Target.Endianness);
10873471bf0Spatrick IO.mapOptional("BitWidth", Target.BitWidth);
10973471bf0Spatrick }
11073471bf0Spatrick
11173471bf0Spatrick // Compacts symbol information into a single line.
11273471bf0Spatrick static const bool flow = true; // NOLINT(readability-identifier-naming)
11373471bf0Spatrick };
11473471bf0Spatrick
11573471bf0Spatrick /// YAML traits for ELFSymbol.
11673471bf0Spatrick template <> struct MappingTraits<IFSSymbol> {
mappingllvm::yaml::MappingTraits11773471bf0Spatrick static void mapping(IO &IO, IFSSymbol &Symbol) {
11873471bf0Spatrick IO.mapRequired("Name", Symbol.Name);
11973471bf0Spatrick IO.mapRequired("Type", Symbol.Type);
12073471bf0Spatrick // The need for symbol size depends on the symbol type.
12173471bf0Spatrick if (Symbol.Type == IFSSymbolType::NoType) {
122*d415bd75Srobert // Size is None, so we are reading it in, or it is non 0 so we
123*d415bd75Srobert // should emit it.
124*d415bd75Srobert if (!Symbol.Size || *Symbol.Size)
125*d415bd75Srobert IO.mapOptional("Size", Symbol.Size);
126*d415bd75Srobert } else if (Symbol.Type != IFSSymbolType::Func) {
127*d415bd75Srobert IO.mapOptional("Size", Symbol.Size);
12873471bf0Spatrick }
12973471bf0Spatrick IO.mapOptional("Undefined", Symbol.Undefined, false);
13073471bf0Spatrick IO.mapOptional("Weak", Symbol.Weak, false);
13173471bf0Spatrick IO.mapOptional("Warning", Symbol.Warning);
13273471bf0Spatrick }
13373471bf0Spatrick
13473471bf0Spatrick // Compacts symbol information into a single line.
13573471bf0Spatrick static const bool flow = true; // NOLINT(readability-identifier-naming)
13673471bf0Spatrick };
13773471bf0Spatrick
13873471bf0Spatrick /// YAML traits for ELFStub objects.
13973471bf0Spatrick template <> struct MappingTraits<IFSStub> {
mappingllvm::yaml::MappingTraits14073471bf0Spatrick static void mapping(IO &IO, IFSStub &Stub) {
14173471bf0Spatrick if (!IO.mapTag("!ifs-v1", true))
14273471bf0Spatrick IO.setError("Not a .tbe YAML file.");
14373471bf0Spatrick IO.mapRequired("IfsVersion", Stub.IfsVersion);
14473471bf0Spatrick IO.mapOptional("SoName", Stub.SoName);
14573471bf0Spatrick IO.mapOptional("Target", Stub.Target);
14673471bf0Spatrick IO.mapOptional("NeededLibs", Stub.NeededLibs);
14773471bf0Spatrick IO.mapRequired("Symbols", Stub.Symbols);
14873471bf0Spatrick }
14973471bf0Spatrick };
15073471bf0Spatrick
15173471bf0Spatrick /// YAML traits for ELFStubTriple objects.
15273471bf0Spatrick template <> struct MappingTraits<IFSStubTriple> {
mappingllvm::yaml::MappingTraits15373471bf0Spatrick static void mapping(IO &IO, IFSStubTriple &Stub) {
15473471bf0Spatrick if (!IO.mapTag("!ifs-v1", true))
15573471bf0Spatrick IO.setError("Not a .tbe YAML file.");
15673471bf0Spatrick IO.mapRequired("IfsVersion", Stub.IfsVersion);
15773471bf0Spatrick IO.mapOptional("SoName", Stub.SoName);
15873471bf0Spatrick IO.mapOptional("Target", Stub.Target.Triple);
15973471bf0Spatrick IO.mapOptional("NeededLibs", Stub.NeededLibs);
16073471bf0Spatrick IO.mapRequired("Symbols", Stub.Symbols);
16173471bf0Spatrick }
16273471bf0Spatrick };
16373471bf0Spatrick } // end namespace yaml
16473471bf0Spatrick } // end namespace llvm
16573471bf0Spatrick
16673471bf0Spatrick /// Attempt to determine if a Text stub uses target triple.
usesTriple(StringRef Buf)16773471bf0Spatrick bool usesTriple(StringRef Buf) {
16873471bf0Spatrick for (line_iterator I(MemoryBufferRef(Buf, "ELFStub")); !I.is_at_eof(); ++I) {
16973471bf0Spatrick StringRef Line = (*I).trim();
17073471bf0Spatrick if (Line.startswith("Target:")) {
171*d415bd75Srobert if (Line == "Target:" || Line.contains("{")) {
17273471bf0Spatrick return false;
17373471bf0Spatrick }
17473471bf0Spatrick }
17573471bf0Spatrick }
17673471bf0Spatrick return true;
17773471bf0Spatrick }
17873471bf0Spatrick
readIFSFromBuffer(StringRef Buf)17973471bf0Spatrick Expected<std::unique_ptr<IFSStub>> ifs::readIFSFromBuffer(StringRef Buf) {
18073471bf0Spatrick yaml::Input YamlIn(Buf);
18173471bf0Spatrick std::unique_ptr<IFSStubTriple> Stub(new IFSStubTriple());
18273471bf0Spatrick if (usesTriple(Buf)) {
18373471bf0Spatrick YamlIn >> *Stub;
18473471bf0Spatrick } else {
18573471bf0Spatrick YamlIn >> *static_cast<IFSStub *>(Stub.get());
18673471bf0Spatrick }
18773471bf0Spatrick if (std::error_code Err = YamlIn.error()) {
18873471bf0Spatrick return createStringError(Err, "YAML failed reading as IFS");
18973471bf0Spatrick }
19073471bf0Spatrick
19173471bf0Spatrick if (Stub->IfsVersion > IFSVersionCurrent)
19273471bf0Spatrick return make_error<StringError>(
19373471bf0Spatrick "IFS version " + Stub->IfsVersion.getAsString() + " is unsupported.",
19473471bf0Spatrick std::make_error_code(std::errc::invalid_argument));
19573471bf0Spatrick if (Stub->Target.ArchString) {
19673471bf0Spatrick Stub->Target.Arch =
197*d415bd75Srobert ELF::convertArchNameToEMachine(*Stub->Target.ArchString);
19873471bf0Spatrick }
19973471bf0Spatrick return std::move(Stub);
20073471bf0Spatrick }
20173471bf0Spatrick
writeIFSToOutputStream(raw_ostream & OS,const IFSStub & Stub)20273471bf0Spatrick Error ifs::writeIFSToOutputStream(raw_ostream &OS, const IFSStub &Stub) {
203*d415bd75Srobert yaml::Output YamlOut(OS, nullptr, /*WrapColumn =*/0);
20473471bf0Spatrick std::unique_ptr<IFSStubTriple> CopyStub(new IFSStubTriple(Stub));
20573471bf0Spatrick if (Stub.Target.Arch) {
206*d415bd75Srobert CopyStub->Target.ArchString =
207*d415bd75Srobert std::string(ELF::convertEMachineToArchName(*Stub.Target.Arch));
20873471bf0Spatrick }
20973471bf0Spatrick IFSTarget Target = Stub.Target;
21073471bf0Spatrick
21173471bf0Spatrick if (CopyStub->Target.Triple ||
21273471bf0Spatrick (!CopyStub->Target.ArchString && !CopyStub->Target.Endianness &&
21373471bf0Spatrick !CopyStub->Target.BitWidth))
21473471bf0Spatrick YamlOut << *CopyStub;
21573471bf0Spatrick else
21673471bf0Spatrick YamlOut << *static_cast<IFSStub *>(CopyStub.get());
21773471bf0Spatrick return Error::success();
21873471bf0Spatrick }
21973471bf0Spatrick
overrideIFSTarget(IFSStub & Stub,std::optional<IFSArch> OverrideArch,std::optional<IFSEndiannessType> OverrideEndianness,std::optional<IFSBitWidthType> OverrideBitWidth,std::optional<std::string> OverrideTriple)220*d415bd75Srobert Error ifs::overrideIFSTarget(
221*d415bd75Srobert IFSStub &Stub, std::optional<IFSArch> OverrideArch,
222*d415bd75Srobert std::optional<IFSEndiannessType> OverrideEndianness,
223*d415bd75Srobert std::optional<IFSBitWidthType> OverrideBitWidth,
224*d415bd75Srobert std::optional<std::string> OverrideTriple) {
22573471bf0Spatrick std::error_code OverrideEC(1, std::generic_category());
22673471bf0Spatrick if (OverrideArch) {
227*d415bd75Srobert if (Stub.Target.Arch && *Stub.Target.Arch != *OverrideArch) {
22873471bf0Spatrick return make_error<StringError>(
22973471bf0Spatrick "Supplied Arch conflicts with the text stub", OverrideEC);
23073471bf0Spatrick }
231*d415bd75Srobert Stub.Target.Arch = *OverrideArch;
23273471bf0Spatrick }
23373471bf0Spatrick if (OverrideEndianness) {
23473471bf0Spatrick if (Stub.Target.Endianness &&
235*d415bd75Srobert *Stub.Target.Endianness != *OverrideEndianness) {
23673471bf0Spatrick return make_error<StringError>(
23773471bf0Spatrick "Supplied Endianness conflicts with the text stub", OverrideEC);
23873471bf0Spatrick }
239*d415bd75Srobert Stub.Target.Endianness = *OverrideEndianness;
24073471bf0Spatrick }
24173471bf0Spatrick if (OverrideBitWidth) {
242*d415bd75Srobert if (Stub.Target.BitWidth && *Stub.Target.BitWidth != *OverrideBitWidth) {
24373471bf0Spatrick return make_error<StringError>(
24473471bf0Spatrick "Supplied BitWidth conflicts with the text stub", OverrideEC);
24573471bf0Spatrick }
246*d415bd75Srobert Stub.Target.BitWidth = *OverrideBitWidth;
24773471bf0Spatrick }
24873471bf0Spatrick if (OverrideTriple) {
249*d415bd75Srobert if (Stub.Target.Triple && *Stub.Target.Triple != *OverrideTriple) {
25073471bf0Spatrick return make_error<StringError>(
25173471bf0Spatrick "Supplied Triple conflicts with the text stub", OverrideEC);
25273471bf0Spatrick }
253*d415bd75Srobert Stub.Target.Triple = *OverrideTriple;
25473471bf0Spatrick }
25573471bf0Spatrick return Error::success();
25673471bf0Spatrick }
25773471bf0Spatrick
validateIFSTarget(IFSStub & Stub,bool ParseTriple)25873471bf0Spatrick Error ifs::validateIFSTarget(IFSStub &Stub, bool ParseTriple) {
25973471bf0Spatrick std::error_code ValidationEC(1, std::generic_category());
26073471bf0Spatrick if (Stub.Target.Triple) {
26173471bf0Spatrick if (Stub.Target.Arch || Stub.Target.BitWidth || Stub.Target.Endianness ||
26273471bf0Spatrick Stub.Target.ObjectFormat) {
26373471bf0Spatrick return make_error<StringError>(
26473471bf0Spatrick "Target triple cannot be used simultaneously with ELF target format",
26573471bf0Spatrick ValidationEC);
26673471bf0Spatrick }
26773471bf0Spatrick if (ParseTriple) {
268*d415bd75Srobert IFSTarget TargetFromTriple = parseTriple(*Stub.Target.Triple);
26973471bf0Spatrick Stub.Target.Arch = TargetFromTriple.Arch;
27073471bf0Spatrick Stub.Target.BitWidth = TargetFromTriple.BitWidth;
27173471bf0Spatrick Stub.Target.Endianness = TargetFromTriple.Endianness;
27273471bf0Spatrick }
27373471bf0Spatrick return Error::success();
27473471bf0Spatrick }
27573471bf0Spatrick if (!Stub.Target.Arch || !Stub.Target.BitWidth || !Stub.Target.Endianness) {
27673471bf0Spatrick // TODO: unify the error message.
27773471bf0Spatrick if (!Stub.Target.Arch) {
27873471bf0Spatrick return make_error<StringError>("Arch is not defined in the text stub",
27973471bf0Spatrick ValidationEC);
28073471bf0Spatrick }
28173471bf0Spatrick if (!Stub.Target.BitWidth) {
28273471bf0Spatrick return make_error<StringError>("BitWidth is not defined in the text stub",
28373471bf0Spatrick ValidationEC);
28473471bf0Spatrick }
28573471bf0Spatrick if (!Stub.Target.Endianness) {
28673471bf0Spatrick return make_error<StringError>(
28773471bf0Spatrick "Endianness is not defined in the text stub", ValidationEC);
28873471bf0Spatrick }
28973471bf0Spatrick }
29073471bf0Spatrick return Error::success();
29173471bf0Spatrick }
29273471bf0Spatrick
parseTriple(StringRef TripleStr)29373471bf0Spatrick IFSTarget ifs::parseTriple(StringRef TripleStr) {
29473471bf0Spatrick Triple IFSTriple(TripleStr);
29573471bf0Spatrick IFSTarget RetTarget;
29673471bf0Spatrick // TODO: Implement a Triple Arch enum to e_machine map.
29773471bf0Spatrick switch (IFSTriple.getArch()) {
29873471bf0Spatrick case Triple::ArchType::aarch64:
29973471bf0Spatrick RetTarget.Arch = (IFSArch)ELF::EM_AARCH64;
30073471bf0Spatrick break;
30173471bf0Spatrick case Triple::ArchType::x86_64:
30273471bf0Spatrick RetTarget.Arch = (IFSArch)ELF::EM_X86_64;
30373471bf0Spatrick break;
30473471bf0Spatrick default:
30573471bf0Spatrick RetTarget.Arch = (IFSArch)ELF::EM_NONE;
30673471bf0Spatrick }
30773471bf0Spatrick RetTarget.Endianness = IFSTriple.isLittleEndian() ? IFSEndiannessType::Little
30873471bf0Spatrick : IFSEndiannessType::Big;
30973471bf0Spatrick RetTarget.BitWidth =
31073471bf0Spatrick IFSTriple.isArch64Bit() ? IFSBitWidthType::IFS64 : IFSBitWidthType::IFS32;
31173471bf0Spatrick return RetTarget;
31273471bf0Spatrick }
31373471bf0Spatrick
stripIFSTarget(IFSStub & Stub,bool StripTriple,bool StripArch,bool StripEndianness,bool StripBitWidth)31473471bf0Spatrick void ifs::stripIFSTarget(IFSStub &Stub, bool StripTriple, bool StripArch,
31573471bf0Spatrick bool StripEndianness, bool StripBitWidth) {
31673471bf0Spatrick if (StripTriple || StripArch) {
31773471bf0Spatrick Stub.Target.Arch.reset();
31873471bf0Spatrick Stub.Target.ArchString.reset();
31973471bf0Spatrick }
32073471bf0Spatrick if (StripTriple || StripEndianness) {
32173471bf0Spatrick Stub.Target.Endianness.reset();
32273471bf0Spatrick }
32373471bf0Spatrick if (StripTriple || StripBitWidth) {
32473471bf0Spatrick Stub.Target.BitWidth.reset();
32573471bf0Spatrick }
32673471bf0Spatrick if (StripTriple) {
32773471bf0Spatrick Stub.Target.Triple.reset();
32873471bf0Spatrick }
32973471bf0Spatrick if (!Stub.Target.Arch && !Stub.Target.BitWidth && !Stub.Target.Endianness) {
33073471bf0Spatrick Stub.Target.ObjectFormat.reset();
33173471bf0Spatrick }
33273471bf0Spatrick }
333*d415bd75Srobert
filterIFSSyms(IFSStub & Stub,bool StripUndefined,const std::vector<std::string> & Exclude)334*d415bd75Srobert Error ifs::filterIFSSyms(IFSStub &Stub, bool StripUndefined,
335*d415bd75Srobert const std::vector<std::string> &Exclude) {
336*d415bd75Srobert std::function<bool(const IFSSymbol &)> Filter = [](const IFSSymbol &) {
337*d415bd75Srobert return false;
338*d415bd75Srobert };
339*d415bd75Srobert
340*d415bd75Srobert if (StripUndefined) {
341*d415bd75Srobert Filter = [Filter](const IFSSymbol &Sym) {
342*d415bd75Srobert return Sym.Undefined || Filter(Sym);
343*d415bd75Srobert };
344*d415bd75Srobert }
345*d415bd75Srobert
346*d415bd75Srobert for (StringRef Glob : Exclude) {
347*d415bd75Srobert Expected<llvm::GlobPattern> PatternOrErr = llvm::GlobPattern::create(Glob);
348*d415bd75Srobert if (!PatternOrErr)
349*d415bd75Srobert return PatternOrErr.takeError();
350*d415bd75Srobert Filter = [Pattern = *PatternOrErr, Filter](const IFSSymbol &Sym) {
351*d415bd75Srobert return Pattern.match(Sym.Name) || Filter(Sym);
352*d415bd75Srobert };
353*d415bd75Srobert }
354*d415bd75Srobert
355*d415bd75Srobert llvm::erase_if(Stub.Symbols, Filter);
356*d415bd75Srobert
357*d415bd75Srobert return Error::success();
358*d415bd75Srobert }
359