123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339 |
- //===- IFSHandler.cpp -----------------------------------------------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===-----------------------------------------------------------------------===/
- #include "llvm/InterfaceStub/IFSHandler.h"
- #include "llvm/ADT/StringRef.h"
- #include "llvm/ADT/StringSwitch.h"
- #include "llvm/ADT/Triple.h"
- #include "llvm/BinaryFormat/ELF.h"
- #include "llvm/InterfaceStub/IFSStub.h"
- #include "llvm/Support/Error.h"
- #include "llvm/Support/LineIterator.h"
- #include "llvm/Support/YAMLTraits.h"
- using namespace llvm;
- using namespace llvm::ifs;
- LLVM_YAML_IS_SEQUENCE_VECTOR(IFSSymbol)
- namespace llvm {
- namespace yaml {
- /// YAML traits for ELFSymbolType.
- template <> struct ScalarEnumerationTraits<IFSSymbolType> {
- static void enumeration(IO &IO, IFSSymbolType &SymbolType) {
- IO.enumCase(SymbolType, "NoType", IFSSymbolType::NoType);
- IO.enumCase(SymbolType, "Func", IFSSymbolType::Func);
- IO.enumCase(SymbolType, "Object", IFSSymbolType::Object);
- IO.enumCase(SymbolType, "TLS", IFSSymbolType::TLS);
- IO.enumCase(SymbolType, "Unknown", IFSSymbolType::Unknown);
- // Treat other symbol types as noise, and map to Unknown.
- if (!IO.outputting() && IO.matchEnumFallback())
- SymbolType = IFSSymbolType::Unknown;
- }
- };
- template <> struct ScalarTraits<IFSEndiannessType> {
- static void output(const IFSEndiannessType &Value, void *,
- llvm::raw_ostream &Out) {
- switch (Value) {
- case IFSEndiannessType::Big:
- Out << "big";
- break;
- case IFSEndiannessType::Little:
- Out << "little";
- break;
- default:
- llvm_unreachable("Unsupported endianness");
- }
- }
- static StringRef input(StringRef Scalar, void *, IFSEndiannessType &Value) {
- Value = StringSwitch<IFSEndiannessType>(Scalar)
- .Case("big", IFSEndiannessType::Big)
- .Case("little", IFSEndiannessType::Little)
- .Default(IFSEndiannessType::Unknown);
- if (Value == IFSEndiannessType::Unknown) {
- return "Unsupported endianness";
- }
- return StringRef();
- }
- static QuotingType mustQuote(StringRef) { return QuotingType::None; }
- };
- template <> struct ScalarTraits<IFSBitWidthType> {
- static void output(const IFSBitWidthType &Value, void *,
- llvm::raw_ostream &Out) {
- switch (Value) {
- case IFSBitWidthType::IFS32:
- Out << "32";
- break;
- case IFSBitWidthType::IFS64:
- Out << "64";
- break;
- default:
- llvm_unreachable("Unsupported bit width");
- }
- }
- static StringRef input(StringRef Scalar, void *, IFSBitWidthType &Value) {
- Value = StringSwitch<IFSBitWidthType>(Scalar)
- .Case("32", IFSBitWidthType::IFS32)
- .Case("64", IFSBitWidthType::IFS64)
- .Default(IFSBitWidthType::Unknown);
- if (Value == IFSBitWidthType::Unknown) {
- return "Unsupported bit width";
- }
- return StringRef();
- }
- static QuotingType mustQuote(StringRef) { return QuotingType::None; }
- };
- template <> struct MappingTraits<IFSTarget> {
- static void mapping(IO &IO, IFSTarget &Target) {
- IO.mapOptional("ObjectFormat", Target.ObjectFormat);
- IO.mapOptional("Arch", Target.ArchString);
- IO.mapOptional("Endianness", Target.Endianness);
- IO.mapOptional("BitWidth", Target.BitWidth);
- }
- // Compacts symbol information into a single line.
- static const bool flow = true; // NOLINT(readability-identifier-naming)
- };
- /// YAML traits for ELFSymbol.
- template <> struct MappingTraits<IFSSymbol> {
- static void mapping(IO &IO, IFSSymbol &Symbol) {
- IO.mapRequired("Name", Symbol.Name);
- IO.mapRequired("Type", Symbol.Type);
- // The need for symbol size depends on the symbol type.
- if (Symbol.Type == IFSSymbolType::NoType) {
- IO.mapOptional("Size", Symbol.Size, (uint64_t)0);
- } else if (Symbol.Type == IFSSymbolType::Func) {
- Symbol.Size = 0;
- } else {
- IO.mapRequired("Size", Symbol.Size);
- }
- IO.mapOptional("Undefined", Symbol.Undefined, false);
- IO.mapOptional("Weak", Symbol.Weak, false);
- IO.mapOptional("Warning", Symbol.Warning);
- }
- // Compacts symbol information into a single line.
- static const bool flow = true; // NOLINT(readability-identifier-naming)
- };
- /// YAML traits for ELFStub objects.
- template <> struct MappingTraits<IFSStub> {
- static void mapping(IO &IO, IFSStub &Stub) {
- if (!IO.mapTag("!ifs-v1", true))
- IO.setError("Not a .tbe YAML file.");
- IO.mapRequired("IfsVersion", Stub.IfsVersion);
- IO.mapOptional("SoName", Stub.SoName);
- IO.mapOptional("Target", Stub.Target);
- IO.mapOptional("NeededLibs", Stub.NeededLibs);
- IO.mapRequired("Symbols", Stub.Symbols);
- }
- };
- /// YAML traits for ELFStubTriple objects.
- template <> struct MappingTraits<IFSStubTriple> {
- static void mapping(IO &IO, IFSStubTriple &Stub) {
- if (!IO.mapTag("!ifs-v1", true))
- IO.setError("Not a .tbe YAML file.");
- IO.mapRequired("IfsVersion", Stub.IfsVersion);
- IO.mapOptional("SoName", Stub.SoName);
- IO.mapOptional("Target", Stub.Target.Triple);
- IO.mapOptional("NeededLibs", Stub.NeededLibs);
- IO.mapRequired("Symbols", Stub.Symbols);
- }
- };
- } // end namespace yaml
- } // end namespace llvm
- /// Attempt to determine if a Text stub uses target triple.
- bool usesTriple(StringRef Buf) {
- for (line_iterator I(MemoryBufferRef(Buf, "ELFStub")); !I.is_at_eof(); ++I) {
- StringRef Line = (*I).trim();
- if (Line.startswith("Target:")) {
- if (Line == "Target:" || Line.contains("{")) {
- return false;
- }
- }
- }
- return true;
- }
- Expected<std::unique_ptr<IFSStub>> ifs::readIFSFromBuffer(StringRef Buf) {
- yaml::Input YamlIn(Buf);
- std::unique_ptr<IFSStubTriple> Stub(new IFSStubTriple());
- if (usesTriple(Buf)) {
- YamlIn >> *Stub;
- } else {
- YamlIn >> *static_cast<IFSStub *>(Stub.get());
- }
- if (std::error_code Err = YamlIn.error()) {
- return createStringError(Err, "YAML failed reading as IFS");
- }
- if (Stub->IfsVersion > IFSVersionCurrent)
- return make_error<StringError>(
- "IFS version " + Stub->IfsVersion.getAsString() + " is unsupported.",
- std::make_error_code(std::errc::invalid_argument));
- if (Stub->Target.ArchString) {
- Stub->Target.Arch =
- ELF::convertArchNameToEMachine(Stub->Target.ArchString.getValue());
- }
- return std::move(Stub);
- }
- Error ifs::writeIFSToOutputStream(raw_ostream &OS, const IFSStub &Stub) {
- yaml::Output YamlOut(OS, nullptr, /*WrapColumn =*/0);
- std::unique_ptr<IFSStubTriple> CopyStub(new IFSStubTriple(Stub));
- if (Stub.Target.Arch) {
- CopyStub->Target.ArchString = std::string(
- ELF::convertEMachineToArchName(Stub.Target.Arch.getValue()));
- }
- IFSTarget Target = Stub.Target;
- if (CopyStub->Target.Triple ||
- (!CopyStub->Target.ArchString && !CopyStub->Target.Endianness &&
- !CopyStub->Target.BitWidth))
- YamlOut << *CopyStub;
- else
- YamlOut << *static_cast<IFSStub *>(CopyStub.get());
- return Error::success();
- }
- Error ifs::overrideIFSTarget(IFSStub &Stub, Optional<IFSArch> OverrideArch,
- Optional<IFSEndiannessType> OverrideEndianness,
- Optional<IFSBitWidthType> OverrideBitWidth,
- Optional<std::string> OverrideTriple) {
- std::error_code OverrideEC(1, std::generic_category());
- if (OverrideArch) {
- if (Stub.Target.Arch &&
- Stub.Target.Arch.getValue() != OverrideArch.getValue()) {
- return make_error<StringError>(
- "Supplied Arch conflicts with the text stub", OverrideEC);
- }
- Stub.Target.Arch = OverrideArch.getValue();
- }
- if (OverrideEndianness) {
- if (Stub.Target.Endianness &&
- Stub.Target.Endianness.getValue() != OverrideEndianness.getValue()) {
- return make_error<StringError>(
- "Supplied Endianness conflicts with the text stub", OverrideEC);
- }
- Stub.Target.Endianness = OverrideEndianness.getValue();
- }
- if (OverrideBitWidth) {
- if (Stub.Target.BitWidth &&
- Stub.Target.BitWidth.getValue() != OverrideBitWidth.getValue()) {
- return make_error<StringError>(
- "Supplied BitWidth conflicts with the text stub", OverrideEC);
- }
- Stub.Target.BitWidth = OverrideBitWidth.getValue();
- }
- if (OverrideTriple) {
- if (Stub.Target.Triple &&
- Stub.Target.Triple.getValue() != OverrideTriple.getValue()) {
- return make_error<StringError>(
- "Supplied Triple conflicts with the text stub", OverrideEC);
- }
- Stub.Target.Triple = OverrideTriple.getValue();
- }
- return Error::success();
- }
- Error ifs::validateIFSTarget(IFSStub &Stub, bool ParseTriple) {
- std::error_code ValidationEC(1, std::generic_category());
- if (Stub.Target.Triple) {
- if (Stub.Target.Arch || Stub.Target.BitWidth || Stub.Target.Endianness ||
- Stub.Target.ObjectFormat) {
- return make_error<StringError>(
- "Target triple cannot be used simultaneously with ELF target format",
- ValidationEC);
- }
- if (ParseTriple) {
- IFSTarget TargetFromTriple = parseTriple(Stub.Target.Triple.getValue());
- Stub.Target.Arch = TargetFromTriple.Arch;
- Stub.Target.BitWidth = TargetFromTriple.BitWidth;
- Stub.Target.Endianness = TargetFromTriple.Endianness;
- }
- return Error::success();
- }
- if (!Stub.Target.Arch || !Stub.Target.BitWidth || !Stub.Target.Endianness) {
- // TODO: unify the error message.
- if (!Stub.Target.Arch) {
- return make_error<StringError>("Arch is not defined in the text stub",
- ValidationEC);
- }
- if (!Stub.Target.BitWidth) {
- return make_error<StringError>("BitWidth is not defined in the text stub",
- ValidationEC);
- }
- if (!Stub.Target.Endianness) {
- return make_error<StringError>(
- "Endianness is not defined in the text stub", ValidationEC);
- }
- }
- return Error::success();
- }
- IFSTarget ifs::parseTriple(StringRef TripleStr) {
- Triple IFSTriple(TripleStr);
- IFSTarget RetTarget;
- // TODO: Implement a Triple Arch enum to e_machine map.
- switch (IFSTriple.getArch()) {
- case Triple::ArchType::aarch64:
- RetTarget.Arch = (IFSArch)ELF::EM_AARCH64;
- break;
- case Triple::ArchType::x86_64:
- RetTarget.Arch = (IFSArch)ELF::EM_X86_64;
- break;
- default:
- RetTarget.Arch = (IFSArch)ELF::EM_NONE;
- }
- RetTarget.Endianness = IFSTriple.isLittleEndian() ? IFSEndiannessType::Little
- : IFSEndiannessType::Big;
- RetTarget.BitWidth =
- IFSTriple.isArch64Bit() ? IFSBitWidthType::IFS64 : IFSBitWidthType::IFS32;
- return RetTarget;
- }
- void ifs::stripIFSTarget(IFSStub &Stub, bool StripTriple, bool StripArch,
- bool StripEndianness, bool StripBitWidth) {
- if (StripTriple || StripArch) {
- Stub.Target.Arch.reset();
- Stub.Target.ArchString.reset();
- }
- if (StripTriple || StripEndianness) {
- Stub.Target.Endianness.reset();
- }
- if (StripTriple || StripBitWidth) {
- Stub.Target.BitWidth.reset();
- }
- if (StripTriple) {
- Stub.Target.Triple.reset();
- }
- if (!Stub.Target.Arch && !Stub.Target.BitWidth && !Stub.Target.Endianness) {
- Stub.Target.ObjectFormat.reset();
- }
- }
- void ifs::stripIFSUndefinedSymbols(IFSStub &Stub) {
- for (auto Iter = Stub.Symbols.begin(); Iter != Stub.Symbols.end();) {
- if (Iter->Undefined) {
- Iter = Stub.Symbols.erase(Iter);
- } else {
- Iter++;
- }
- }
- }
|