diff options
Diffstat (limited to 'llvm/lib/InterfaceStub')
| -rw-r--r-- | llvm/lib/InterfaceStub/ELFObjHandler.cpp | 115 | ||||
| -rw-r--r-- | llvm/lib/InterfaceStub/ELFStub.cpp | 28 | ||||
| -rw-r--r-- | llvm/lib/InterfaceStub/IFSHandler.cpp | 329 | ||||
| -rw-r--r-- | llvm/lib/InterfaceStub/IFSStub.cpp | 133 | ||||
| -rw-r--r-- | llvm/lib/InterfaceStub/TBEHandler.cpp | 143 |
5 files changed, 517 insertions, 231 deletions
diff --git a/llvm/lib/InterfaceStub/ELFObjHandler.cpp b/llvm/lib/InterfaceStub/ELFObjHandler.cpp index 255d301362eb..112c1cea354a 100644 --- a/llvm/lib/InterfaceStub/ELFObjHandler.cpp +++ b/llvm/lib/InterfaceStub/ELFObjHandler.cpp @@ -7,7 +7,7 @@ //===-----------------------------------------------------------------------===/ #include "llvm/InterfaceStub/ELFObjHandler.h" -#include "llvm/InterfaceStub/ELFStub.h" +#include "llvm/InterfaceStub/IFSStub.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/Binary.h" #include "llvm/Object/ELFObjectFile.h" @@ -27,7 +27,7 @@ using namespace llvm::object; using namespace llvm::ELF; namespace llvm { -namespace elfabi { +namespace ifs { // Simple struct to hold relevant .dynamic entries. struct DynamicEntries { @@ -180,7 +180,7 @@ public: ELFStubBuilder(const ELFStubBuilder &) = delete; ELFStubBuilder(ELFStubBuilder &&) = default; - explicit ELFStubBuilder(const ELFStub &Stub) { + explicit ELFStubBuilder(const IFSStub &Stub) { DynSym.Name = ".dynsym"; DynSym.Align = sizeof(Elf_Addr); DynStr.Name = ".dynstr"; @@ -191,7 +191,7 @@ public: ShStrTab.Align = 1; // Populate string tables. - for (const ELFSymbol &Sym : Stub.Symbols) + for (const IFSSymbol &Sym : Stub.Symbols) DynStr.Content.add(Sym.Name); for (const std::string &Lib : Stub.NeededLibs) DynStr.Content.add(Lib); @@ -213,14 +213,14 @@ public: DynStr.Size = DynStr.Content.getSize(); // Populate dynamic symbol table. - for (const ELFSymbol &Sym : Stub.Symbols) { + for (const IFSSymbol &Sym : Stub.Symbols) { uint8_t Bind = Sym.Weak ? STB_WEAK : STB_GLOBAL; // For non-undefined symbols, value of the shndx is not relevant at link // time as long as it is not SHN_UNDEF. Set shndx to 1, which // points to ".dynsym". uint16_t Shndx = Sym.Undefined ? SHN_UNDEF : 1; DynSym.Content.add(DynStr.Content.getOffset(Sym.Name), Sym.Size, Bind, - (uint8_t)Sym.Type, 0, Shndx); + convertIFSSymbolTypeToELF(Sym.Type), 0, Shndx); } DynSym.Size = DynSym.Content.getSize(); @@ -250,7 +250,8 @@ public: fillStrTabShdr(ShStrTab); // Finish initializing the ELF header. - initELFHeader<ELFT>(ElfHeader, Stub.Arch); + initELFHeader<ELFT>(ElfHeader, + static_cast<uint16_t>(Stub.Target.Arch.getValue())); ElfHeader.e_shstrndx = ShStrTab.Index; ElfHeader.e_shnum = LastSection->Index + 1; ElfHeader.e_shoff = @@ -303,7 +304,10 @@ private: SymTab.Shdr.sh_flags = SHF_ALLOC; SymTab.Shdr.sh_addr = SymTab.Addr; SymTab.Shdr.sh_offset = SymTab.Offset; - SymTab.Shdr.sh_info = SymTab.Size / sizeof(Elf_Sym) > 1 ? 1 : 0; + // Only non-local symbols are included in the tbe file, so .dynsym only + // contains 1 local symbol (the undefined symbol at index 0). The sh_info + // should always be 1. + SymTab.Shdr.sh_info = 1; SymTab.Shdr.sh_size = SymTab.Size; SymTab.Shdr.sh_name = this->ShStrTab.Content.getOffset(SymTab.Name); SymTab.Shdr.sh_addralign = SymTab.Align; @@ -440,37 +444,15 @@ static Error populateDynamic(DynamicEntries &Dyn, return Error::success(); } -/// This function extracts symbol type from a symbol's st_info member and -/// maps it to an ELFSymbolType enum. -/// Currently, STT_NOTYPE, STT_OBJECT, STT_FUNC, and STT_TLS are supported. -/// Other symbol types are mapped to ELFSymbolType::Unknown. -/// -/// @param Info Binary symbol st_info to extract symbol type from. -static ELFSymbolType convertInfoToType(uint8_t Info) { - Info = Info & 0xf; - switch (Info) { - case ELF::STT_NOTYPE: - return ELFSymbolType::NoType; - case ELF::STT_OBJECT: - return ELFSymbolType::Object; - case ELF::STT_FUNC: - return ELFSymbolType::Func; - case ELF::STT_TLS: - return ELFSymbolType::TLS; - default: - return ELFSymbolType::Unknown; - } -} - -/// This function creates an ELFSymbol and populates all members using +/// This function creates an IFSSymbol and populates all members using /// information from a binary ELFT::Sym. /// -/// @param SymName The desired name of the ELFSymbol. +/// @param SymName The desired name of the IFSSymbol. /// @param RawSym ELFT::Sym to extract symbol information from. template <class ELFT> -static ELFSymbol createELFSym(StringRef SymName, +static IFSSymbol createELFSym(StringRef SymName, const typename ELFT::Sym &RawSym) { - ELFSymbol TargetSym{std::string(SymName)}; + IFSSymbol TargetSym{std::string(SymName)}; uint8_t Binding = RawSym.getBinding(); if (Binding == STB_WEAK) TargetSym.Weak = true; @@ -478,9 +460,9 @@ static ELFSymbol createELFSym(StringRef SymName, TargetSym.Weak = false; TargetSym.Undefined = RawSym.isUndefined(); - TargetSym.Type = convertInfoToType(RawSym.st_info); + TargetSym.Type = convertELFSymbolTypeToIFS(RawSym.st_info); - if (TargetSym.Type == ELFSymbolType::Func) { + if (TargetSym.Type == IFSSymbolType::Func) { TargetSym.Size = 0; } else { TargetSym.Size = RawSym.st_size; @@ -488,14 +470,14 @@ static ELFSymbol createELFSym(StringRef SymName, return TargetSym; } -/// This function populates an ELFStub with symbols using information read +/// This function populates an IFSStub with symbols using information read /// from an ELF binary. /// -/// @param TargetStub ELFStub to add symbols to. +/// @param TargetStub IFSStub to add symbols to. /// @param DynSym Range of dynamic symbols to add to TargetStub. /// @param DynStr StringRef to the dynamic string table. template <class ELFT> -static Error populateSymbols(ELFStub &TargetStub, +static Error populateSymbols(IFSStub &TargetStub, const typename ELFT::SymRange DynSym, StringRef DynStr) { // Skips the first symbol since it's the NULL symbol. @@ -508,28 +490,28 @@ static Error populateSymbols(ELFStub &TargetStub, uint8_t Visibility = RawSym.getVisibility(); if (!(Visibility == STV_DEFAULT || Visibility == STV_PROTECTED)) continue; - // Create an ELFSymbol and populate it with information from the symbol + // Create an IFSSymbol and populate it with information from the symbol // table entry. Expected<StringRef> SymName = terminatedSubstr(DynStr, RawSym.st_name); if (!SymName) return SymName.takeError(); - ELFSymbol Sym = createELFSym<ELFT>(*SymName, RawSym); - TargetStub.Symbols.insert(std::move(Sym)); + IFSSymbol Sym = createELFSym<ELFT>(*SymName, RawSym); + TargetStub.Symbols.push_back(std::move(Sym)); // TODO: Populate symbol warning. } return Error::success(); } -/// Returns a new ELFStub with all members populated from an ELFObjectFile. +/// Returns a new IFSStub with all members populated from an ELFObjectFile. /// @param ElfObj Source ELFObjectFile. template <class ELFT> -static Expected<std::unique_ptr<ELFStub>> +static Expected<std::unique_ptr<IFSStub>> buildStub(const ELFObjectFile<ELFT> &ElfObj) { using Elf_Dyn_Range = typename ELFT::DynRange; using Elf_Phdr_Range = typename ELFT::PhdrRange; using Elf_Sym_Range = typename ELFT::SymRange; using Elf_Sym = typename ELFT::Sym; - std::unique_ptr<ELFStub> DestStub = std::make_unique<ELFStub>(); + std::unique_ptr<IFSStub> DestStub = std::make_unique<IFSStub>(); const ELFFile<ELFT> &ElfFile = ElfObj.getELFFile(); // Fetch .dynamic table. Expected<Elf_Dyn_Range> DynTable = ElfFile.dynamicEntries(); @@ -558,7 +540,12 @@ buildStub(const ELFObjectFile<ELFT> &ElfObj) { DynEnt.StrSize); // Populate Arch from ELF header. - DestStub->Arch = ElfFile.getHeader().e_machine; + DestStub->Target.Arch = static_cast<IFSArch>(ElfFile.getHeader().e_machine); + DestStub->Target.BitWidth = + convertELFBitWidthToIFS(ElfFile.getHeader().e_ident[EI_CLASS]); + DestStub->Target.Endianness = + convertELFEndiannessToIFS(ElfFile.getHeader().e_ident[EI_DATA]); + DestStub->Target.ObjectFormat = "ELF"; // Populate SoName from .dynamic entries and dynamic string table. if (DynEnt.SONameOffset.hasValue()) { @@ -606,9 +593,9 @@ buildStub(const ELFObjectFile<ELFT> &ElfObj) { /// the file. /// /// @param FilePath File path for writing the ELF binary. -/// @param Stub Source ELFStub to generate a binary ELF stub from. +/// @param Stub Source InterFace Stub to generate a binary ELF stub from. template <class ELFT> -static Error writeELFBinaryToFile(StringRef FilePath, const ELFStub &Stub, +static Error writeELFBinaryToFile(StringRef FilePath, const IFSStub &Stub, bool WriteIfChanged) { ELFStubBuilder<ELFT> Builder{Stub}; // Write Stub to memory first. @@ -642,7 +629,7 @@ static Error writeELFBinaryToFile(StringRef FilePath, const ELFStub &Stub, return FileBuf->commit(); } -Expected<std::unique_ptr<ELFStub>> readELFFile(MemoryBufferRef Buf) { +Expected<std::unique_ptr<IFSStub>> readELFFile(MemoryBufferRef Buf) { Expected<std::unique_ptr<Binary>> BinOrErr = createBinary(Buf); if (!BinOrErr) { return BinOrErr.takeError(); @@ -663,18 +650,26 @@ Expected<std::unique_ptr<ELFStub>> readELFFile(MemoryBufferRef Buf) { // This function wraps the ELFT writeELFBinaryToFile() so writeBinaryStub() // can be called without having to use ELFType templates directly. -Error writeBinaryStub(StringRef FilePath, const ELFStub &Stub, - ELFTarget OutputFormat, bool WriteIfChanged) { - if (OutputFormat == ELFTarget::ELF32LE) - return writeELFBinaryToFile<ELF32LE>(FilePath, Stub, WriteIfChanged); - if (OutputFormat == ELFTarget::ELF32BE) - return writeELFBinaryToFile<ELF32BE>(FilePath, Stub, WriteIfChanged); - if (OutputFormat == ELFTarget::ELF64LE) - return writeELFBinaryToFile<ELF64LE>(FilePath, Stub, WriteIfChanged); - if (OutputFormat == ELFTarget::ELF64BE) - return writeELFBinaryToFile<ELF64BE>(FilePath, Stub, WriteIfChanged); +Error writeBinaryStub(StringRef FilePath, const IFSStub &Stub, + bool WriteIfChanged) { + assert(Stub.Target.Arch); + assert(Stub.Target.BitWidth); + assert(Stub.Target.Endianness); + if (Stub.Target.BitWidth == IFSBitWidthType::IFS32) { + if (Stub.Target.Endianness == IFSEndiannessType::Little) { + return writeELFBinaryToFile<ELF32LE>(FilePath, Stub, WriteIfChanged); + } else { + return writeELFBinaryToFile<ELF32BE>(FilePath, Stub, WriteIfChanged); + } + } else { + if (Stub.Target.Endianness == IFSEndiannessType::Little) { + return writeELFBinaryToFile<ELF64LE>(FilePath, Stub, WriteIfChanged); + } else { + return writeELFBinaryToFile<ELF64BE>(FilePath, Stub, WriteIfChanged); + } + } llvm_unreachable("invalid binary output target"); } -} // end namespace elfabi +} // end namespace ifs } // end namespace llvm diff --git a/llvm/lib/InterfaceStub/ELFStub.cpp b/llvm/lib/InterfaceStub/ELFStub.cpp deleted file mode 100644 index 3c637695d8e7..000000000000 --- a/llvm/lib/InterfaceStub/ELFStub.cpp +++ /dev/null @@ -1,28 +0,0 @@ -//===- ELFStub.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/ELFStub.h" - -using namespace llvm; -using namespace llvm::elfabi; - -ELFStub::ELFStub(ELFStub const &Stub) { - TbeVersion = Stub.TbeVersion; - Arch = Stub.Arch; - SoName = Stub.SoName; - NeededLibs = Stub.NeededLibs; - Symbols = Stub.Symbols; -} - -ELFStub::ELFStub(ELFStub &&Stub) { - TbeVersion = std::move(Stub.TbeVersion); - Arch = std::move(Stub.Arch); - SoName = std::move(Stub.SoName); - NeededLibs = std::move(Stub.NeededLibs); - Symbols = std::move(Stub.Symbols); -} diff --git a/llvm/lib/InterfaceStub/IFSHandler.cpp b/llvm/lib/InterfaceStub/IFSHandler.cpp new file mode 100644 index 000000000000..d3d351fa2ed4 --- /dev/null +++ b/llvm/lib/InterfaceStub/IFSHandler.cpp @@ -0,0 +1,329 @@ +//===- 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.find("{") != Line.npos)) { + 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, NULL, /*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(); + } +} diff --git a/llvm/lib/InterfaceStub/IFSStub.cpp b/llvm/lib/InterfaceStub/IFSStub.cpp new file mode 100644 index 000000000000..bbc91ada1ded --- /dev/null +++ b/llvm/lib/InterfaceStub/IFSStub.cpp @@ -0,0 +1,133 @@ +//===- IFSStub.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/IFSStub.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/Support/Error.h" + +using namespace llvm; +using namespace llvm::ifs; + +IFSStub::IFSStub(IFSStub const &Stub) { + IfsVersion = Stub.IfsVersion; + Target = Stub.Target; + SoName = Stub.SoName; + NeededLibs = Stub.NeededLibs; + Symbols = Stub.Symbols; +} + +IFSStub::IFSStub(IFSStub &&Stub) { + IfsVersion = std::move(Stub.IfsVersion); + Target = std::move(Stub.Target); + SoName = std::move(Stub.SoName); + NeededLibs = std::move(Stub.NeededLibs); + Symbols = std::move(Stub.Symbols); +} + +IFSStubTriple::IFSStubTriple(IFSStubTriple const &Stub) { + IfsVersion = Stub.IfsVersion; + Target = Stub.Target; + SoName = Stub.SoName; + NeededLibs = Stub.NeededLibs; + Symbols = Stub.Symbols; +} + +IFSStubTriple::IFSStubTriple(IFSStub const &Stub) { + IfsVersion = Stub.IfsVersion; + Target = Stub.Target; + SoName = Stub.SoName; + NeededLibs = Stub.NeededLibs; + Symbols = Stub.Symbols; +} + +IFSStubTriple::IFSStubTriple(IFSStubTriple &&Stub) { + IfsVersion = std::move(Stub.IfsVersion); + Target = std::move(Stub.Target); + SoName = std::move(Stub.SoName); + NeededLibs = std::move(Stub.NeededLibs); + Symbols = std::move(Stub.Symbols); +} + +bool IFSTarget::empty() { + return !Triple && !ObjectFormat && !Arch && !ArchString && !Endianness && + !BitWidth; +} + +uint8_t ifs::convertIFSBitWidthToELF(IFSBitWidthType BitWidth) { + switch (BitWidth) { + case IFSBitWidthType::IFS32: + return ELF::ELFCLASS32; + case IFSBitWidthType::IFS64: + return ELF::ELFCLASS64; + default: + llvm_unreachable("unknown bitwidth"); + } +} + +uint8_t ifs::convertIFSEndiannessToELF(IFSEndiannessType Endianness) { + switch (Endianness) { + case IFSEndiannessType::Little: + return ELF::ELFDATA2LSB; + case IFSEndiannessType::Big: + return ELF::ELFDATA2MSB; + default: + llvm_unreachable("unknown endianness"); + } +} + +uint8_t ifs::convertIFSSymbolTypeToELF(IFSSymbolType SymbolType) { + switch (SymbolType) { + case IFSSymbolType::Object: + return ELF::STT_OBJECT; + case IFSSymbolType::Func: + return ELF::STT_FUNC; + case IFSSymbolType::TLS: + return ELF::STT_TLS; + case IFSSymbolType::NoType: + default: + return ELF::STT_NOTYPE; + } +} + +IFSBitWidthType ifs::convertELFBitWidthToIFS(uint8_t BitWidth) { + switch (BitWidth) { + case ELF::ELFCLASS32: + return IFSBitWidthType::IFS32; + case ELF::ELFCLASS64: + return IFSBitWidthType::IFS64; + default: + return IFSBitWidthType::Unknown; + } +} + +IFSEndiannessType ifs::convertELFEndiannessToIFS(uint8_t Endianness) { + switch (Endianness) { + case ELF::ELFDATA2LSB: + return IFSEndiannessType::Little; + case ELF::ELFDATA2MSB: + return IFSEndiannessType::Big; + default: + return IFSEndiannessType::Unknown; + } +} + +IFSSymbolType ifs::convertELFSymbolTypeToIFS(uint8_t SymbolType) { + SymbolType = SymbolType & 0xf; + switch (SymbolType) { + case ELF::STT_OBJECT: + return IFSSymbolType::Object; + case ELF::STT_FUNC: + return IFSSymbolType::Func; + case ELF::STT_TLS: + return IFSSymbolType::TLS; + case ELF::STT_NOTYPE: + return IFSSymbolType::NoType; + default: + return IFSSymbolType::Unknown; + } +} diff --git a/llvm/lib/InterfaceStub/TBEHandler.cpp b/llvm/lib/InterfaceStub/TBEHandler.cpp deleted file mode 100644 index ee95d21ee661..000000000000 --- a/llvm/lib/InterfaceStub/TBEHandler.cpp +++ /dev/null @@ -1,143 +0,0 @@ -//===- TBEHandler.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/TBEHandler.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/InterfaceStub/ELFStub.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/YAMLTraits.h" - -using namespace llvm; -using namespace llvm::elfabi; - -LLVM_YAML_STRONG_TYPEDEF(ELFArch, ELFArchMapper) - -namespace llvm { -namespace yaml { - -/// YAML traits for ELFSymbolType. -template <> struct ScalarEnumerationTraits<ELFSymbolType> { - static void enumeration(IO &IO, ELFSymbolType &SymbolType) { - IO.enumCase(SymbolType, "NoType", ELFSymbolType::NoType); - IO.enumCase(SymbolType, "Func", ELFSymbolType::Func); - IO.enumCase(SymbolType, "Object", ELFSymbolType::Object); - IO.enumCase(SymbolType, "TLS", ELFSymbolType::TLS); - IO.enumCase(SymbolType, "Unknown", ELFSymbolType::Unknown); - // Treat other symbol types as noise, and map to Unknown. - if (!IO.outputting() && IO.matchEnumFallback()) - SymbolType = ELFSymbolType::Unknown; - } -}; - -/// YAML traits for ELFArch. -template <> struct ScalarTraits<ELFArchMapper> { - static void output(const ELFArchMapper &Value, void *, - llvm::raw_ostream &Out) { - // Map from integer to architecture string. - switch (Value) { - case (ELFArch)ELF::EM_X86_64: - Out << "x86_64"; - break; - case (ELFArch)ELF::EM_AARCH64: - Out << "AArch64"; - break; - case (ELFArch)ELF::EM_NONE: - default: - Out << "Unknown"; - } - } - - static StringRef input(StringRef Scalar, void *, ELFArchMapper &Value) { - // Map from architecture string to integer. - Value = StringSwitch<ELFArch>(Scalar) - .Case("x86_64", ELF::EM_X86_64) - .Case("AArch64", ELF::EM_AARCH64) - .Case("Unknown", ELF::EM_NONE) - .Default(ELF::EM_NONE); - - // Returning empty StringRef indicates successful parse. - return StringRef(); - } - - // Don't place quotation marks around architecture value. - static QuotingType mustQuote(StringRef) { return QuotingType::None; } -}; - -/// YAML traits for ELFSymbol. -template <> struct MappingTraits<ELFSymbol> { - static void mapping(IO &IO, ELFSymbol &Symbol) { - IO.mapRequired("Type", Symbol.Type); - // The need for symbol size depends on the symbol type. - if (Symbol.Type == ELFSymbolType::NoType) { - IO.mapOptional("Size", Symbol.Size, (uint64_t)0); - } else if (Symbol.Type == ELFSymbolType::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; -}; - -/// YAML traits for set of ELFSymbols. -template <> struct CustomMappingTraits<std::set<ELFSymbol>> { - static void inputOne(IO &IO, StringRef Key, std::set<ELFSymbol> &Set) { - ELFSymbol Sym(Key.str()); - IO.mapRequired(Key.str().c_str(), Sym); - Set.insert(Sym); - } - - static void output(IO &IO, std::set<ELFSymbol> &Set) { - for (auto &Sym : Set) - IO.mapRequired(Sym.Name.c_str(), const_cast<ELFSymbol &>(Sym)); - } -}; - -/// YAML traits for ELFStub objects. -template <> struct MappingTraits<ELFStub> { - static void mapping(IO &IO, ELFStub &Stub) { - if (!IO.mapTag("!tapi-tbe", true)) - IO.setError("Not a .tbe YAML file."); - IO.mapRequired("TbeVersion", Stub.TbeVersion); - IO.mapOptional("SoName", Stub.SoName); - IO.mapRequired("Arch", (ELFArchMapper &)Stub.Arch); - IO.mapOptional("NeededLibs", Stub.NeededLibs); - IO.mapRequired("Symbols", Stub.Symbols); - } -}; - -} // end namespace yaml -} // end namespace llvm - -Expected<std::unique_ptr<ELFStub>> elfabi::readTBEFromBuffer(StringRef Buf) { - yaml::Input YamlIn(Buf); - std::unique_ptr<ELFStub> Stub(new ELFStub()); - YamlIn >> *Stub; - if (std::error_code Err = YamlIn.error()) - return createStringError(Err, "YAML failed reading as TBE"); - - if (Stub->TbeVersion > elfabi::TBEVersionCurrent) - return make_error<StringError>( - "TBE version " + Stub->TbeVersion.getAsString() + " is unsupported.", - std::make_error_code(std::errc::invalid_argument)); - - return std::move(Stub); -} - -Error elfabi::writeTBEToOutputStream(raw_ostream &OS, const ELFStub &Stub) { - yaml::Output YamlOut(OS, NULL, /*WrapColumn =*/0); - - YamlOut << const_cast<ELFStub &>(Stub); - return Error::success(); -} |
