Index: llvm/trunk/test/tools/llvm-objcopy/ELF/globalize.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/ELF/globalize.test +++ llvm/trunk/test/tools/llvm-objcopy/ELF/globalize.test @@ -4,6 +4,8 @@ # RUN: --globalize-symbol Weak \ # RUN: --globalize-symbol WeakUndef %t %t2 # RUN: llvm-readobj --symbols %t2 | FileCheck %s +# RUN: llvm-objcopy --regex --globalize-symbol '.*' %t %t3 +# RUN: cmp %t2 %t3 !ELF FileHeader: Index: llvm/trunk/test/tools/llvm-objcopy/ELF/keep-global-symbols.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/ELF/keep-global-symbols.test +++ llvm/trunk/test/tools/llvm-objcopy/ELF/keep-global-symbols.test @@ -28,6 +28,7 @@ # RUN: echo "Unknown" >> %t-globals2.txt # RUN: echo " " >> %t-globals2.txt # RUN: echo "# File with no symbols" > %t-globals3.txt +# RUN: echo "^Global[0-9]+([[:space:]]Global6)*$" > %t-globals-regexp.txt # RUN: llvm-objcopy \ # RUN: -G Global1 \ @@ -41,6 +42,9 @@ # RUN: %t.o %t.2.o # RUN: llvm-readobj --elf-output-style=GNU --symbols %t.2.o | FileCheck %s +# RUN: llvm-objcopy --regex --keep-global-symbols %t-globals-regexp.txt %t.o %t.3.o +# RUN: llvm-readobj --elf-output-style=GNU --symbols %t.3.o | FileCheck %s --check-prefix=REGEXP + !ELF FileHeader: Class: ELFCLASS64 @@ -97,3 +101,12 @@ # CHECK-NEXT: 11: {{.*}} GLOBAL {{.*}} UND Global7 # CHECK-NEXT: 12: {{.*}} WEAK {{.*}} Weak1 # CHECK-NEXT: 13: {{.*}} GLOBAL {{.*}} Weak2 + +# REGEXP: 6: {{.*}} GLOBAL {{.*}} Global1 +# REGEXP-NEXT: 7: {{.*}} GLOBAL {{.*}} Global2 +# REGEXP-NEXT: 8: {{.*}} GLOBAL {{.*}} Global3 +# REGEXP-NEXT: 9: {{.*}} GLOBAL {{.*}} Global4 +# REGEXP-NEXT: 10: {{.*}} GLOBAL {{.*}} Global5 +# REGEXP-NEXT: 11: {{.*}} GLOBAL {{.*}} Global6 +# REGEXP-NEXT: 12: {{.*}} GLOBAL {{.*}} Global5 Global6 +# REGEXP-NEXT: 13: {{.*}} GLOBAL {{.*}} UND Global7 Index: llvm/trunk/test/tools/llvm-objcopy/ELF/keep-many.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/ELF/keep-many.test +++ llvm/trunk/test/tools/llvm-objcopy/ELF/keep-many.test @@ -1,6 +1,8 @@ # RUN: yaml2obj %s > %t # RUN: llvm-objcopy --strip-non-alloc --keep-section=.test --keep-section=.test3 %t %t2 +# RUN: llvm-objcopy --strip-non-alloc --regex --keep-section='^.test[0-9]+$' %t %t3 # RUN: llvm-readobj --file-headers --sections %t2 | FileCheck %s +# RUN: llvm-readobj --file-headers --sections %t3 | FileCheck %s --check-prefix=REGEX !ELF FileHeader: @@ -25,3 +27,8 @@ # CHECK: Name: .test # CHECK: Name: .test3 # CHECK: Name: .shstrtab + +# REGEX: SectionHeaderCount: 4 +# REGEX: Name: .test2 +# REGEX: Name: .test3 +# REGEX: Name: .shstrtab Index: llvm/trunk/test/tools/llvm-objcopy/ELF/keep-only-section.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/ELF/keep-only-section.test +++ llvm/trunk/test/tools/llvm-objcopy/ELF/keep-only-section.test @@ -3,6 +3,8 @@ # RUN: llvm-objcopy -j .test --keep-section=.test2 %t %t3 # RUN: llvm-readobj --file-headers --sections %t2 | FileCheck %s # RUN: diff %t2 %t3 +# RUN: llvm-objcopy --regex --keep-section='^.test$' --only-section='^.test[2-3]+$' %t %t4 +# RUN: llvm-readobj --file-headers --sections %t4 | FileCheck %s --check-prefix=REGEX !ELF FileHeader: @@ -25,3 +27,12 @@ # CHECK: Name: .symtab # CHECK: Name: .strtab # CHECK: Name: .shstrtab + +# REGEX: SectionHeaderCount: 7 + +# REGEX: Name: .test +# REGEX: Name: .test2 +# REGEX: Name: .test3 +# REGEX: Name: .symtab +# REGEX: Name: .strtab +# REGEX: Name: .shstrtab Index: llvm/trunk/test/tools/llvm-objcopy/ELF/keep-symbol.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/ELF/keep-symbol.test +++ llvm/trunk/test/tools/llvm-objcopy/ELF/keep-symbol.test @@ -1,8 +1,10 @@ # RUN: yaml2obj %s > %t # RUN: llvm-objcopy --discard-all -K foo --keep-symbol bar %t %t2 # RUN: llvm-objcopy -K foo -N foo -N bar --keep-symbol bar -N baz %t %t3 +# RUN: llvm-objcopy --discard-all --regex -K '^ba.*' %t %t4 # RUN: llvm-readobj --symbols %t2 | FileCheck %s # RUN: llvm-readobj --symbols %t3 | FileCheck %s +# RUN: llvm-readobj --symbols %t4 | FileCheck %s --check-prefix=REGEX !ELF FileHeader: @@ -64,3 +66,9 @@ #CHECK-NEXT: Section: .text #CHECK-NEXT: } #CHECK-NEXT:] + +#REGEX: Symbols [ +#REGEX-NOT: foo +#REGEX: Name: bar +#REGEX: Name: baz +#REGEX: ] Index: llvm/trunk/test/tools/llvm-objcopy/ELF/localize.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/ELF/localize.test +++ llvm/trunk/test/tools/llvm-objcopy/ELF/localize.test @@ -7,6 +7,8 @@ # RUN: -L GlobalCommon \ # RUN: %t %t2 # RUN: llvm-readobj --symbols %t2 | FileCheck %s +# RUN: llvm-objcopy --regex -L '.*' %t %t3 +# RUN: cmp %t2 %t3 !ELF FileHeader: Index: llvm/trunk/test/tools/llvm-objcopy/ELF/regex.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/ELF/regex.test +++ llvm/trunk/test/tools/llvm-objcopy/ELF/regex.test @@ -0,0 +1,60 @@ +# RUN: yaml2obj %s > %t + +# No symbol matches, because pattern is implicitly enveloped in '^$' +# RUN: llvm-objcopy --discard-all --regex -K 'ba' %t %t2 +# RUN: llvm-readobj --symbols %t2 | FileCheck %s --check-prefix=REGEX1 + +# Symbol 'bar' matches +# RUN: llvm-objcopy --discard-all --regex -K 'ba.*' %t %t3 +# RUN: llvm-readobj --symbols %t3 | FileCheck %s --check-prefix=REGEX2 + +# All symbols match +# RUN: llvm-objcopy --discard-all --regex -K '.*ba.*' %t %t4 +# RUN: llvm-readobj --symbols %t4 | FileCheck %s --check-prefix=REGEX3 + +# All symbols match +# RUN: llvm-objcopy --discard-all --regex -K '^([a-z]+)*ba.*$' %t %t5 +# RUN: cmp %t4 %t5 + +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_REL + Machine: EM_X86_64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x1000 + AddressAlign: 0x0000000000000010 + Size: 64 +Symbols: + Local: + - Name: foobaz + Type: STT_FUNC + Section: .text + Value: 0x1000 + Size: 8 + - Name: bar + Type: STT_FUNC + Section: .text + Value: 0x1008 + Size: 8 + - Name: rebar + Type: STT_FUNC + Section: .text + Value: 0x1010 + Size: 8 + +#REGEX1-NOT: foobaz +#REGEX1-NOT: bar +#REGEX1-NOT: rebar + +#REGEX2-NOT: foobaz +#REGEX2: bar +#REGEX2-NOT: rebar + +#REGEX3: foobaz +#REGEX3: bar +#REGEX3: rebar Index: llvm/trunk/test/tools/llvm-objcopy/ELF/remove-section.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/ELF/remove-section.test +++ llvm/trunk/test/tools/llvm-objcopy/ELF/remove-section.test @@ -11,6 +11,10 @@ # RUN: llvm-objcopy --remove-section=.test2 %t1 %t3 # RUN: cmp %t2 %t3 +# RUN: llvm-objcopy --regex --remove-section='.test[0-9]+' %t %t4 +# RUN: llvm-readobj --file-headers --sections %t4 | FileCheck %s --check-prefix=REGEX + + !ELF FileHeader: Class: ELFCLASS64 @@ -116,3 +120,7 @@ # CHECK: EntrySize: 0 # CHECK: } # CHECK: ] + +# REGEX: SectionHeaderCount: 4 +# REGEX: Sections [ +# REGEX-NOT: test Index: llvm/trunk/test/tools/llvm-objcopy/ELF/strip-symbol.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/ELF/strip-symbol.test +++ llvm/trunk/test/tools/llvm-objcopy/ELF/strip-symbol.test @@ -2,7 +2,9 @@ # RUN: llvm-objcopy --strip-symbol baz -N bar %t %t2 # RUN: llvm-readobj --symbols --sections %t2 | FileCheck %s # RUN: llvm-strip --strip-symbol baz -N bar %t -o %t3 -# RUN: llvm-readobj --symbols --sections %t3 | FileCheck %s +# RUN: cmp %t2 %t3 +# RUN: llvm-strip --regex --strip-symbol '^b.*' -N bar %t -o %t4 +# RUN: cmp %t3 %t4 !ELF FileHeader: Index: llvm/trunk/test/tools/llvm-objcopy/ELF/weaken.test =================================================================== --- llvm/trunk/test/tools/llvm-objcopy/ELF/weaken.test +++ llvm/trunk/test/tools/llvm-objcopy/ELF/weaken.test @@ -1,6 +1,8 @@ # RUN: yaml2obj %s > %t # RUN: llvm-objcopy --weaken-symbol Global -W Local -W Weak %t %t2 # RUN: llvm-readobj --symbols %t2 | FileCheck %s +# RUN: llvm-objcopy --regex --weaken-symbol '.*' %t %t3 +# RUN: cmp %t2 %t3 !ELF FileHeader: Index: llvm/trunk/tools/llvm-objcopy/CopyConfig.h =================================================================== --- llvm/trunk/tools/llvm-objcopy/CopyConfig.h +++ llvm/trunk/tools/llvm-objcopy/CopyConfig.h @@ -15,6 +15,7 @@ #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Allocator.h" +#include "llvm/Support/Regex.h" // Necessary for llvm::DebugCompressionType::None #include "llvm/Target/TargetOptions.h" #include @@ -48,6 +49,17 @@ Locals, // --discard-locals (-X) }; +class NameOrRegex { + StringRef Name; + // Regex is shared between multiple CopyConfig instances. + std::shared_ptr R; + +public: + NameOrRegex(StringRef Pattern, bool IsRegex); + bool operator==(StringRef S) const { return R ? R->match(S) : Name == S; } + bool operator!=(StringRef S) const { return !operator==(S); } +}; + // Configuration for copying/stripping a single file. struct CopyConfig { // Main input/output options @@ -73,15 +85,15 @@ // Repeated options std::vector AddSection; std::vector DumpSection; - std::vector KeepSection; - std::vector OnlySection; - std::vector SymbolsToGlobalize; - std::vector SymbolsToKeep; - std::vector SymbolsToLocalize; - std::vector SymbolsToRemove; - std::vector SymbolsToWeaken; - std::vector ToRemove; - std::vector SymbolsToKeepGlobal; + std::vector KeepSection; + std::vector OnlySection; + std::vector SymbolsToGlobalize; + std::vector SymbolsToKeep; + std::vector SymbolsToLocalize; + std::vector SymbolsToRemove; + std::vector SymbolsToWeaken; + std::vector ToRemove; + std::vector SymbolsToKeepGlobal; // Map options StringMap SectionsToRename; Index: llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp =================================================================== --- llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp +++ llvm/trunk/tools/llvm-objcopy/CopyConfig.cpp @@ -225,9 +225,9 @@ return Iter->getValue(); } -static void addGlobalSymbolsFromFile(std::vector &Symbols, +static void addGlobalSymbolsFromFile(std::vector &Symbols, BumpPtrAllocator &Alloc, - StringRef Filename) { + StringRef Filename, bool UseRegex) { StringSaver Saver(Alloc); SmallVector Lines; auto BufOrErr = MemoryBuffer::getFile(Filename); @@ -240,10 +240,21 @@ // it's not empty. auto TrimmedLine = Line.split('#').first.trim(); if (!TrimmedLine.empty()) - Symbols.push_back(Saver.save(TrimmedLine)); + Symbols.emplace_back(Saver.save(TrimmedLine), UseRegex); } } +NameOrRegex::NameOrRegex(StringRef Pattern, bool IsRegex) { + if (!IsRegex) { + Name = Pattern; + return; + } + + SmallVector Data; + R = std::make_shared( + ("^" + Pattern.ltrim('^').rtrim('$') + "$").toStringRef(Data)); +} + // ParseObjcopyOptions returns the config and sets the input arguments. If a // help flag is set then ParseObjcopyOptions will print the help messege and // exit. @@ -292,6 +303,7 @@ InputArgs.hasArg(OBJCOPY_output_target))) error("--target cannot be used with --input-target or --output-target"); + bool UseRegex = InputArgs.hasArg(OBJCOPY_regex); if (InputArgs.hasArg(OBJCOPY_target)) { Config.InputFormat = InputArgs.getLastArgValue(OBJCOPY_target); Config.OutputFormat = InputArgs.getLastArgValue(OBJCOPY_target); @@ -371,11 +383,11 @@ } for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section)) - Config.ToRemove.push_back(Arg->getValue()); + Config.ToRemove.emplace_back(Arg->getValue(), UseRegex); for (auto Arg : InputArgs.filtered(OBJCOPY_keep_section)) - Config.KeepSection.push_back(Arg->getValue()); + Config.KeepSection.emplace_back(Arg->getValue(), UseRegex); for (auto Arg : InputArgs.filtered(OBJCOPY_only_section)) - Config.OnlySection.push_back(Arg->getValue()); + Config.OnlySection.emplace_back(Arg->getValue(), UseRegex); for (auto Arg : InputArgs.filtered(OBJCOPY_add_section)) Config.AddSection.push_back(Arg->getValue()); for (auto Arg : InputArgs.filtered(OBJCOPY_dump_section)) @@ -400,20 +412,20 @@ Config.DecompressDebugSections = InputArgs.hasArg(OBJCOPY_decompress_debug_sections); for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol)) - Config.SymbolsToLocalize.push_back(Arg->getValue()); + Config.SymbolsToLocalize.emplace_back(Arg->getValue(), UseRegex); for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol)) - Config.SymbolsToKeepGlobal.push_back(Arg->getValue()); + Config.SymbolsToKeepGlobal.emplace_back(Arg->getValue(), UseRegex); for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols)) addGlobalSymbolsFromFile(Config.SymbolsToKeepGlobal, DC.Alloc, - Arg->getValue()); + Arg->getValue(), UseRegex); for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol)) - Config.SymbolsToGlobalize.push_back(Arg->getValue()); + Config.SymbolsToGlobalize.emplace_back(Arg->getValue(), UseRegex); for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol)) - Config.SymbolsToWeaken.push_back(Arg->getValue()); + Config.SymbolsToWeaken.emplace_back(Arg->getValue(), UseRegex); for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol)) - Config.SymbolsToRemove.push_back(Arg->getValue()); + Config.SymbolsToRemove.emplace_back(Arg->getValue(), UseRegex); for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol)) - Config.SymbolsToKeep.push_back(Arg->getValue()); + Config.SymbolsToKeep.emplace_back(Arg->getValue(), UseRegex); Config.DeterministicArchives = InputArgs.hasFlag( OBJCOPY_enable_deterministic_archives, @@ -472,6 +484,7 @@ error("Multiple input files cannot be used in combination with -o"); CopyConfig Config; + bool UseRegexp = InputArgs.hasArg(STRIP_regex); Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug); if (InputArgs.hasArg(STRIP_discard_all, STRIP_discard_locals)) @@ -485,16 +498,16 @@ Config.KeepFileSymbols = InputArgs.hasArg(STRIP_keep_file_symbols); for (auto Arg : InputArgs.filtered(STRIP_keep_section)) - Config.KeepSection.push_back(Arg->getValue()); + Config.KeepSection.emplace_back(Arg->getValue(), UseRegexp); for (auto Arg : InputArgs.filtered(STRIP_remove_section)) - Config.ToRemove.push_back(Arg->getValue()); + Config.ToRemove.emplace_back(Arg->getValue(), UseRegexp); for (auto Arg : InputArgs.filtered(STRIP_strip_symbol)) - Config.SymbolsToRemove.push_back(Arg->getValue()); + Config.SymbolsToRemove.emplace_back(Arg->getValue(), UseRegexp); for (auto Arg : InputArgs.filtered(STRIP_keep_symbol)) - Config.SymbolsToKeep.push_back(Arg->getValue()); + Config.SymbolsToKeep.emplace_back(Arg->getValue(), UseRegexp); if (!Config.StripDebug && !Config.StripUnneeded && Config.DiscardMode == DiscardType::None && !Config.StripAllGNU && Config.SymbolsToRemove.empty()) Index: llvm/trunk/tools/llvm-objcopy/ObjcopyOpts.td =================================================================== --- llvm/trunk/tools/llvm-objcopy/ObjcopyOpts.td +++ llvm/trunk/tools/llvm-objcopy/ObjcopyOpts.td @@ -193,3 +193,7 @@ : Eq<"build-id-link-output", "Hard-link the output to /xx/xxx " "name derived from hex build ID">, MetaVarName<"suffix">; + +def regex + : Flag<["-", "--"], "regex">, + HelpText<"Permit regular expressions in name comparison">; Index: llvm/trunk/tools/llvm-objcopy/StripOpts.td =================================================================== --- llvm/trunk/tools/llvm-objcopy/StripOpts.td +++ llvm/trunk/tools/llvm-objcopy/StripOpts.td @@ -74,6 +74,10 @@ HelpText<"Remove all local symbols except file and section symbols">; def x : Flag<["-"], "x">, Alias; +def regex + : Flag<["-", "--"], "regex">, + HelpText<"Permit regular expressions in name comparison">; + def version : Flag<["-", "--"], "version">, HelpText<"Print the version and exit.">; def V : Flag<["-"], "V">, Alias;