xref: /openbsd-src/gnu/llvm/llvm/lib/InterfaceStub/IFSHandler.cpp (revision d415bd752c734aee168c4ee86ff32e8cc249eb16)
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