# 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:
# 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 \
# 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
# 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
# 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:
# CHECK: Name: .test
# CHECK: Name: .test3
# CHECK: Name: .shstrtab
+
+# REGEX: SectionHeaderCount: 4
+# REGEX: Name: .test2
+# REGEX: Name: .test3
+# REGEX: Name: .shstrtab
# 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:
# 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
# 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:
#CHECK-NEXT: Section: .text
#CHECK-NEXT: }
#CHECK-NEXT:]
+
+#REGEX: Symbols [
+#REGEX-NOT: foo
+#REGEX: Name: bar
+#REGEX: Name: baz
+#REGEX: ]
# 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:
--- /dev/null
+# 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
# 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
# CHECK: EntrySize: 0
# CHECK: }
# CHECK: ]
+
+# REGEX: SectionHeaderCount: 4
+# REGEX: Sections [
+# REGEX-NOT: test
# 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:
# 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:
return Iter->getValue();
}
-static void addGlobalSymbolsFromFile(std::vector<StringRef> &Symbols,
+static void addGlobalSymbolsFromFile(std::vector<NameOrRegex> &Symbols,
BumpPtrAllocator &Alloc,
- StringRef Filename) {
+ StringRef Filename, bool UseRegex) {
StringSaver Saver(Alloc);
SmallVector<StringRef, 16> Lines;
auto BufOrErr = MemoryBuffer::getFile(Filename);
// 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<char, 32> Data;
+ R = std::make_shared<Regex>(
+ ("^" + 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.
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);
}
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))
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,
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))
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())
#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 <vector>
Locals, // --discard-locals (-X)
};
+class NameOrRegex {
+ StringRef Name;
+ // Regex is shared between multiple CopyConfig instances.
+ std::shared_ptr<Regex> 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
// Repeated options
std::vector<StringRef> AddSection;
std::vector<StringRef> DumpSection;
- std::vector<StringRef> KeepSection;
- std::vector<StringRef> OnlySection;
- std::vector<StringRef> SymbolsToGlobalize;
- std::vector<StringRef> SymbolsToKeep;
- std::vector<StringRef> SymbolsToLocalize;
- std::vector<StringRef> SymbolsToRemove;
- std::vector<StringRef> SymbolsToWeaken;
- std::vector<StringRef> ToRemove;
- std::vector<StringRef> SymbolsToKeepGlobal;
+ std::vector<NameOrRegex> KeepSection;
+ std::vector<NameOrRegex> OnlySection;
+ std::vector<NameOrRegex> SymbolsToGlobalize;
+ std::vector<NameOrRegex> SymbolsToKeep;
+ std::vector<NameOrRegex> SymbolsToLocalize;
+ std::vector<NameOrRegex> SymbolsToRemove;
+ std::vector<NameOrRegex> SymbolsToWeaken;
+ std::vector<NameOrRegex> ToRemove;
+ std::vector<NameOrRegex> SymbolsToKeepGlobal;
// Map options
StringMap<SectionRename> SectionsToRename;
: Eq<"build-id-link-output", "Hard-link the output to <dir>/xx/xxx<suffix> "
"name derived from hex build ID">,
MetaVarName<"suffix">;
+
+def regex
+ : Flag<["-", "--"], "regex">,
+ HelpText<"Permit regular expressions in name comparison">;
HelpText<"Remove all local symbols except file and section symbols">;
def x : Flag<["-"], "x">, Alias<discard_all>;
+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<version>;