Index: llvm/include/llvm/InterfaceStub/IFSHandler.h =================================================================== --- llvm/include/llvm/InterfaceStub/IFSHandler.h +++ llvm/include/llvm/InterfaceStub/IFSHandler.h @@ -19,6 +19,8 @@ #include "llvm/Support/Error.h" #include "llvm/Support/VersionTuple.h" #include +#include +#include namespace llvm { @@ -51,8 +53,9 @@ void stripIFSTarget(IFSStub &Stub, bool StripTriple, bool StripArch, bool StripEndianness, bool StripBitWidth); -/// Strips symbols from IFS symbol table that are undefined. -void stripIFSUndefinedSymbols(IFSStub &Stub); +Error filterIFSSyms(IFSStub &Stub, bool StripUndefined, + const std::vector &Exclude = {}, + const std::vector &Preserve = {}); /// Parse llvm triple string into a IFSTarget struct. IFSTarget parseTriple(StringRef TripleStr); Index: llvm/lib/InterfaceStub/IFSHandler.cpp =================================================================== --- llvm/lib/InterfaceStub/IFSHandler.cpp +++ llvm/lib/InterfaceStub/IFSHandler.cpp @@ -7,14 +7,17 @@ //===-----------------------------------------------------------------------===/ #include "llvm/InterfaceStub/IFSHandler.h" +#include "llvm/ADT/STLExtras.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/GlobPattern.h" #include "llvm/Support/LineIterator.h" #include "llvm/Support/YAMLTraits.h" +#include using namespace llvm; using namespace llvm::ifs; @@ -328,12 +331,38 @@ } } -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++; - } +Error ifs::filterIFSSyms(IFSStub &Stub, bool StripUndefined, + const std::vector &Exclude, + const std::vector &Preserve) { + std::function Filter = [](const IFSSymbol &) { + return false; + }; + + if (StripUndefined) { + Filter = [Filter](const IFSSymbol &Sym) { + return Sym.Undefined || Filter(Sym); + }; + } + + for (StringRef Glob : Exclude) { + Expected PatternOrErr = llvm::GlobPattern::create(Glob); + if (!PatternOrErr) + return PatternOrErr.takeError(); + Filter = [Pattern = *PatternOrErr, Filter](const IFSSymbol &Sym) { + return Pattern.match(Sym.Name) || Filter(Sym); + }; } + + for (StringRef Glob : Preserve) { + Expected PatternOrErr = llvm::GlobPattern::create(Glob); + if (!PatternOrErr) + return PatternOrErr.takeError(); + Filter = [Pattern = *PatternOrErr, Filter](const IFSSymbol &Sym) { + return !Pattern.match(Sym.Name) && Filter(Sym); + }; + } + + llvm::erase_if(Stub.Symbols, Filter); + + return Error::success(); } Index: llvm/test/tools/llvm-ifs/preserve-and-exclude.test =================================================================== --- /dev/null +++ llvm/test/tools/llvm-ifs/preserve-and-exclude.test @@ -0,0 +1,34 @@ +## Test --preserve and --exclude flags + +# RUN: llvm-ifs --input-format=IFS --output-ifs=- --strip-undefined \ +# RUN: --preserve='keep_*' --preserve='diff_pattern_keep' \ +# RUN: --preserve='*_preserved' --exclude='exclude*' %s | FileCheck %s + +# RUN: not llvm-ifs --input-format=IFS --output-ifs=- --preserve='[' %s 2>&1 | \ +# RUN: FileCheck %s --check-prefix=BAD-GLOB + +# RUN: not llvm-ifs --input-format=IFS --output-ifs=- --exclude='[' %s 2>&1 | \ +# RUN: FileCheck %s --check-prefix=BAD-GLOB + +# BAD-GLOB: error: invalid glob pattern: [ + +--- !ifs-v1 +SoName: somelib.so +IfsVersion: 3.0 +Symbols: + - { Name: diff_pattern_keep, Type: Func, Undefined: true } + - { Name: dont_keep, Type: Func, Undefined: true } + - { Name: exclude_no_preserve, Type: Func } + - { Name: exclude_preserved, Type: Func, Undefined: true } + - { Name: keep_1, Type: Func, Undefined: true } + - { Name: keep_2, Type: Func, Undefined: true } + - { Name: no_match_not_undef, Type: Func } +... + +# CHECK: - { Name: diff_pattern_keep, Type: Func, Undefined: true } +# CHECK-NOT: - { Name: dont_keep, Type: Func, Undefined: true } +# CHECK-NOT: - { Name: exclude_no_preserve, Type: Func } +# CHECK-NEXT: - { Name: exclude_preserved, Type: Func, Undefined: true } +# CHECK-NEXT: - { Name: keep_1, Type: Func, Undefined: true } +# CHECK-NEXT: - { Name: keep_2, Type: Func, Undefined: true } +# CHECK-NEXT: - { Name: no_match_not_undef, Type: Func } Index: llvm/tools/llvm-ifs/llvm-ifs.cpp =================================================================== --- llvm/tools/llvm-ifs/llvm-ifs.cpp +++ llvm/tools/llvm-ifs/llvm-ifs.cpp @@ -103,6 +103,17 @@ StripUndefined("strip-undefined", cl::desc("Strip undefined symbols from IFS output"), cl::cat(IfsCategory)); +cl::list PreserveSyms( + "preserve", + cl::desc("Specify a pattern forsymbols which might otherwise be removed by " + "--strip-undefined or --exclude. Can be specified multiple times"), + cl::cat(IfsCategory)); +cl::list + ExcludeSyms("exclude", + cl::desc("Remove symbols which match the pattern. Symbols " + "matching a pattern specified by a --preserve will " + "not be removed. Can be specified multiple times"), + cl::cat(IfsCategory)); cl::opt SoName("soname", @@ -473,8 +484,9 @@ stripIFSTarget(Stub, StripIFSTarget, StripIFSArch, StripIFSEndiannessWidth, StripIFSBitWidth); } - if (StripUndefined) - stripIFSUndefinedSymbols(Stub); + if (Error E = + filterIFSSyms(Stub, StripUndefined, ExcludeSyms, PreserveSyms)) + fatalError(std::move(E)); Error IFSWriteError = writeIFS(OutputFilePath.getValue(), Stub); if (IFSWriteError) fatalError(std::move(IFSWriteError)); @@ -525,8 +537,9 @@ stripIFSTarget(Stub, StripIFSTarget, StripIFSArch, StripIFSEndiannessWidth, StripIFSBitWidth); } - if (StripUndefined) - stripIFSUndefinedSymbols(Stub); + if (Error E = + filterIFSSyms(Stub, StripUndefined, ExcludeSyms, PreserveSyms)) + fatalError(std::move(E)); Error IFSWriteError = writeIFS(OutputIFSFilePath.getValue(), Stub); if (IFSWriteError) fatalError(std::move(IFSWriteError));