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