brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.2 KiB · 39dc466 Raw
364 lines · cpp
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-exception6//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 23using namespace llvm;24using namespace llvm::ifs;25 26LLVM_YAML_IS_SEQUENCE_VECTOR(IFSSymbol)27 28namespace llvm {29namespace yaml {30 31/// YAML traits for ELFSymbolType.32template <> 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 45template <> 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 74template <> 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 103template <> 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.116template <> 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 we123      // 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.139template <> 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.152template <> 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 yaml164} // end namespace llvm165 166/// Attempt to determine if a Text stub uses target triple.167bool 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 179Expected<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 213Error 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  else227    YamlOut << *static_cast<IFSStub *>(CopyStub.get());228  return Error::success();229}230 231Error 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 269Error 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 304IFSTarget ifs::parseTriple(StringRef TripleStr) {305  Triple IFSTriple(TripleStr);306  IFSTarget RetTarget;307  IFSArch TripleArch =308      ELF::convertTripleArchTypeToEMachine(IFSTriple.getArch());309  if (TripleArch != ELF::EM_NONE) {310    RetTarget.Arch = TripleArch;311  }312  RetTarget.Endianness = IFSTriple.isLittleEndian() ? IFSEndiannessType::Little313                                                    : IFSEndiannessType::Big;314  RetTarget.BitWidth =315      IFSTriple.isArch64Bit() ? IFSBitWidthType::IFS64 : IFSBitWidthType::IFS32;316  return RetTarget;317}318 319void ifs::stripIFSTarget(IFSStub &Stub, bool StripTriple, bool StripArch,320                         bool StripEndianness, bool StripBitWidth) {321  if (StripTriple || StripArch) {322    Stub.Target.Arch.reset();323    Stub.Target.ArchString.reset();324  }325  if (StripTriple || StripEndianness) {326    Stub.Target.Endianness.reset();327  }328  if (StripTriple || StripBitWidth) {329    Stub.Target.BitWidth.reset();330  }331  if (StripTriple) {332    Stub.Target.Triple.reset();333  }334  if (!Stub.Target.Arch && !Stub.Target.BitWidth && !Stub.Target.Endianness) {335    Stub.Target.ObjectFormat.reset();336  }337}338 339Error ifs::filterIFSSyms(IFSStub &Stub, bool StripUndefined,340                         const std::vector<std::string> &Exclude) {341  std::function<bool(const IFSSymbol &)> Filter = [](const IFSSymbol &) {342    return false;343  };344 345  if (StripUndefined) {346    Filter = [Filter](const IFSSymbol &Sym) {347      return Sym.Undefined || Filter(Sym);348    };349  }350 351  for (StringRef Glob : Exclude) {352    Expected<llvm::GlobPattern> PatternOrErr = llvm::GlobPattern::create(Glob);353    if (!PatternOrErr)354      return PatternOrErr.takeError();355    Filter = [Pattern = *PatternOrErr, Filter](const IFSSymbol &Sym) {356      return Pattern.match(Sym.Name) || Filter(Sym);357    };358  }359 360  llvm::erase_if(Stub.Symbols, Filter);361 362  return Error::success();363}364