aboutsummaryrefslogtreecommitdiff
path: root/llvm/tools
diff options
context:
space:
mode:
authorJordan Rupprecht <rupprecht@google.com>2019-10-17 20:51:00 +0000
committerJordan Rupprecht <rupprecht@google.com>2019-10-17 20:51:00 +0000
commitedeebad7715774b8481103733dc5d52dac43bdf3 (patch)
treec84c0c304f7142e3ecef79ccd5120179a6dc1e60 /llvm/tools
parent9c5d76ff4d15e2cabf976911bd150302ae5fdeea (diff)
downloadllvm-edeebad7715774b8481103733dc5d52dac43bdf3.zip
llvm-edeebad7715774b8481103733dc5d52dac43bdf3.tar.gz
llvm-edeebad7715774b8481103733dc5d52dac43bdf3.tar.bz2
[llvm-objcopy] Add support for shell wildcards
Summary: GNU objcopy accepts the --wildcard flag to allow wildcard matching on symbol-related flags. (Note: it's implicitly true for section flags). The basic syntax is to allow *, ?, \, and [] which work similarly to how they work in a shell. Additionally, starting a wildcard with ! causes that wildcard to prevent it from matching a flag. Use an updated GlobPattern in libSupport to handle these patterns. It does not fully match the `fnmatch` used by GNU objcopy since named character classes (e.g. `[[:digit:]]`) are not supported, but this should support most existing use cases (mostly just `*` is what's used anyway). Reviewers: jhenderson, MaskRay, evgeny777, espindola, alexshap Reviewed By: MaskRay Subscribers: nickdesaulniers, emaste, arichardson, hiraditya, jakehehrlich, abrachet, seiya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D66613 llvm-svn: 375169
Diffstat (limited to 'llvm/tools')
-rw-r--r--llvm/tools/llvm-objcopy/CommonOpts.td10
-rw-r--r--llvm/tools/llvm-objcopy/CopyConfig.cpp160
-rw-r--r--llvm/tools/llvm-objcopy/CopyConfig.h56
-rw-r--r--llvm/tools/llvm-objcopy/llvm-objcopy.cpp2
4 files changed, 179 insertions, 49 deletions
diff --git a/llvm/tools/llvm-objcopy/CommonOpts.td b/llvm/tools/llvm-objcopy/CommonOpts.td
index 597163e..e8c092b4 100644
--- a/llvm/tools/llvm-objcopy/CommonOpts.td
+++ b/llvm/tools/llvm-objcopy/CommonOpts.td
@@ -111,3 +111,13 @@ def version : Flag<["--"], "version">,
def V : Flag<["-"], "V">,
Alias<version>,
HelpText<"Alias for --version">;
+
+def wildcard
+ : Flag<["--"], "wildcard">,
+ HelpText<"Allow wildcard syntax for symbol-related flags. Incompatible "
+ "with --regex. Allows using '*' to match any number of "
+ "characters, '?' to match any single character, '\' to escape "
+ "special characters, and '[]' to define character classes. "
+ "Wildcards beginning with '!' will prevent a match, for example "
+ "\"-N '*' -N '!x'\" will strip all symbols except for \"x\".">;
+def w : Flag<["-"], "w">, Alias<wildcard>, HelpText<"Alias for --wildcard">;
diff --git a/llvm/tools/llvm-objcopy/CopyConfig.cpp b/llvm/tools/llvm-objcopy/CopyConfig.cpp
index 952b3a7..c805631 100644
--- a/llvm/tools/llvm-objcopy/CopyConfig.cpp
+++ b/llvm/tools/llvm-objcopy/CopyConfig.cpp
@@ -260,8 +260,10 @@ getOutputTargetInfoByTargetName(StringRef TargetName) {
return {TargetInfo{Format, MI}};
}
-static Error addSymbolsFromFile(NameMatcher &Symbols, BumpPtrAllocator &Alloc,
- StringRef Filename, bool UseRegex) {
+static Error
+addSymbolsFromFile(NameMatcher &Symbols, BumpPtrAllocator &Alloc,
+ StringRef Filename, MatchStyle MS,
+ llvm::function_ref<Error(Error)> ErrorCallback) {
StringSaver Saver(Alloc);
SmallVector<StringRef, 16> Lines;
auto BufOrErr = MemoryBuffer::getFile(Filename);
@@ -274,21 +276,46 @@ static Error addSymbolsFromFile(NameMatcher &Symbols, BumpPtrAllocator &Alloc,
// it's not empty.
auto TrimmedLine = Line.split('#').first.trim();
if (!TrimmedLine.empty())
- Symbols.addMatcher({Saver.save(TrimmedLine), UseRegex});
+ if (Error E = Symbols.addMatcher(NameOrPattern::create(
+ Saver.save(TrimmedLine), MS, ErrorCallback)))
+ return E;
}
return Error::success();
}
-NameOrRegex::NameOrRegex(StringRef Pattern, bool IsRegex) {
- if (!IsRegex) {
- Name = Pattern;
- return;
- }
+Expected<NameOrPattern>
+NameOrPattern::create(StringRef Pattern, MatchStyle MS,
+ llvm::function_ref<Error(Error)> ErrorCallback) {
+ switch (MS) {
+ case MatchStyle::Literal:
+ return NameOrPattern(Pattern);
+ case MatchStyle::Wildcard: {
+ SmallVector<char, 32> Data;
+ bool IsPositiveMatch = true;
+ if (Pattern[0] == '!') {
+ IsPositiveMatch = false;
+ Pattern = Pattern.drop_front();
+ }
+ Expected<GlobPattern> GlobOrErr = GlobPattern::create(Pattern);
+
+ // If we couldn't create it as a glob, report the error, but try again with
+ // a literal if the error reporting is non-fatal.
+ if (!GlobOrErr) {
+ if (Error E = ErrorCallback(GlobOrErr.takeError()))
+ return std::move(E);
+ return create(Pattern, MatchStyle::Literal, ErrorCallback);
+ }
- SmallVector<char, 32> Data;
- R = std::make_shared<Regex>(
- ("^" + Pattern.ltrim('^').rtrim('$') + "$").toStringRef(Data));
+ return NameOrPattern(std::make_shared<GlobPattern>(*GlobOrErr),
+ IsPositiveMatch);
+ }
+ case MatchStyle::Regex: {
+ SmallVector<char, 32> Data;
+ return NameOrPattern(std::make_shared<Regex>(
+ ("^" + Pattern.ltrim('^').rtrim('$') + "$").toStringRef(Data)));
+ }
+ }
}
static Error addSymbolsToRenameFromFile(StringMap<StringRef> &SymbolsToRename,
@@ -338,7 +365,9 @@ static void printHelp(const opt::OptTable &OptTable, raw_ostream &OS,
// ParseObjcopyOptions returns the config and sets the input arguments. If a
// help flag is set then ParseObjcopyOptions will print the help messege and
// exit.
-Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
+Expected<DriverConfig>
+parseObjcopyOptions(ArrayRef<const char *> ArgsArr,
+ llvm::function_ref<Error(Error)> ErrorCallback) {
DriverConfig DC;
ObjcopyOptTable T;
unsigned MissingArgumentIndex, MissingArgumentCount;
@@ -387,7 +416,18 @@ Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
errc::invalid_argument,
"--target cannot be used with --input-target or --output-target");
- bool UseRegex = InputArgs.hasArg(OBJCOPY_regex);
+ if (InputArgs.hasArg(OBJCOPY_regex) && InputArgs.hasArg(OBJCOPY_wildcard))
+ return createStringError(errc::invalid_argument,
+ "--regex and --wildcard are incompatible");
+
+ MatchStyle SectionMatchStyle = InputArgs.hasArg(OBJCOPY_regex)
+ ? MatchStyle::Regex
+ : MatchStyle::Wildcard;
+ MatchStyle SymbolMatchStyle = InputArgs.hasArg(OBJCOPY_regex)
+ ? MatchStyle::Regex
+ : InputArgs.hasArg(OBJCOPY_wildcard)
+ ? MatchStyle::Wildcard
+ : MatchStyle::Literal;
StringRef InputFormat, OutputFormat;
if (InputArgs.hasArg(OBJCOPY_target)) {
InputFormat = InputArgs.getLastArgValue(OBJCOPY_target);
@@ -541,11 +581,17 @@ Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
}
for (auto Arg : InputArgs.filtered(OBJCOPY_remove_section))
- Config.ToRemove.addMatcher({Arg->getValue(), UseRegex});
+ if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SectionMatchStyle, ErrorCallback)))
+ return std::move(E);
for (auto Arg : InputArgs.filtered(OBJCOPY_keep_section))
- Config.KeepSection.addMatcher({Arg->getValue(), UseRegex});
+ if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SectionMatchStyle, ErrorCallback)))
+ return std::move(E);
for (auto Arg : InputArgs.filtered(OBJCOPY_only_section))
- Config.OnlySection.addMatcher({Arg->getValue(), UseRegex});
+ if (Error E = Config.OnlySection.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SectionMatchStyle, ErrorCallback)))
+ return std::move(E);
for (auto Arg : InputArgs.filtered(OBJCOPY_add_section)) {
StringRef ArgValue(Arg->getValue());
if (!ArgValue.contains('='))
@@ -583,46 +629,68 @@ Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
if (Config.DiscardMode == DiscardType::All)
Config.StripDebug = true;
for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbol))
- Config.SymbolsToLocalize.addMatcher({Arg->getValue(), UseRegex});
+ if (Error E = Config.SymbolsToLocalize.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
+ return std::move(E);
for (auto Arg : InputArgs.filtered(OBJCOPY_localize_symbols))
if (Error E = addSymbolsFromFile(Config.SymbolsToLocalize, DC.Alloc,
- Arg->getValue(), UseRegex))
+ Arg->getValue(), SymbolMatchStyle,
+ ErrorCallback))
return std::move(E);
for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbol))
- Config.SymbolsToKeepGlobal.addMatcher({Arg->getValue(), UseRegex});
+ if (Error E = Config.SymbolsToKeepGlobal.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
+ return std::move(E);
for (auto Arg : InputArgs.filtered(OBJCOPY_keep_global_symbols))
if (Error E = addSymbolsFromFile(Config.SymbolsToKeepGlobal, DC.Alloc,
- Arg->getValue(), UseRegex))
+ Arg->getValue(), SymbolMatchStyle,
+ ErrorCallback))
return std::move(E);
for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbol))
- Config.SymbolsToGlobalize.addMatcher({Arg->getValue(), UseRegex});
+ if (Error E = Config.SymbolsToGlobalize.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
+ return std::move(E);
for (auto Arg : InputArgs.filtered(OBJCOPY_globalize_symbols))
if (Error E = addSymbolsFromFile(Config.SymbolsToGlobalize, DC.Alloc,
- Arg->getValue(), UseRegex))
+ Arg->getValue(), SymbolMatchStyle,
+ ErrorCallback))
return std::move(E);
for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbol))
- Config.SymbolsToWeaken.addMatcher({Arg->getValue(), UseRegex});
+ if (Error E = Config.SymbolsToWeaken.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
+ return std::move(E);
for (auto Arg : InputArgs.filtered(OBJCOPY_weaken_symbols))
if (Error E = addSymbolsFromFile(Config.SymbolsToWeaken, DC.Alloc,
- Arg->getValue(), UseRegex))
+ Arg->getValue(), SymbolMatchStyle,
+ ErrorCallback))
return std::move(E);
for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbol))
- Config.SymbolsToRemove.addMatcher({Arg->getValue(), UseRegex});
+ if (Error E = Config.SymbolsToRemove.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
+ return std::move(E);
for (auto Arg : InputArgs.filtered(OBJCOPY_strip_symbols))
if (Error E = addSymbolsFromFile(Config.SymbolsToRemove, DC.Alloc,
- Arg->getValue(), UseRegex))
+ Arg->getValue(), SymbolMatchStyle,
+ ErrorCallback))
return std::move(E);
for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbol))
- Config.UnneededSymbolsToRemove.addMatcher({Arg->getValue(), UseRegex});
+ if (Error E =
+ Config.UnneededSymbolsToRemove.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
+ return std::move(E);
for (auto Arg : InputArgs.filtered(OBJCOPY_strip_unneeded_symbols))
if (Error E = addSymbolsFromFile(Config.UnneededSymbolsToRemove, DC.Alloc,
- Arg->getValue(), UseRegex))
+ Arg->getValue(), SymbolMatchStyle,
+ ErrorCallback))
return std::move(E);
for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbol))
- Config.SymbolsToKeep.addMatcher({Arg->getValue(), UseRegex});
+ if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
+ return std::move(E);
for (auto Arg : InputArgs.filtered(OBJCOPY_keep_symbols))
- if (Error E = addSymbolsFromFile(Config.SymbolsToKeep, DC.Alloc,
- Arg->getValue(), UseRegex))
+ if (Error E =
+ addSymbolsFromFile(Config.SymbolsToKeep, DC.Alloc, Arg->getValue(),
+ SymbolMatchStyle, ErrorCallback))
return std::move(E);
for (auto Arg : InputArgs.filtered(OBJCOPY_add_symbol))
Config.SymbolsToAdd.push_back(Arg->getValue());
@@ -688,7 +756,7 @@ Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
// exit.
Expected<DriverConfig>
parseStripOptions(ArrayRef<const char *> ArgsArr,
- std::function<Error(Error)> ErrorCallback) {
+ llvm::function_ref<Error(Error)> ErrorCallback) {
StripOptTable T;
unsigned MissingArgumentIndex, MissingArgumentCount;
llvm::opt::InputArgList InputArgs =
@@ -726,7 +794,17 @@ parseStripOptions(ArrayRef<const char *> ArgsArr,
"multiple input files cannot be used in combination with -o");
CopyConfig Config;
- bool UseRegexp = InputArgs.hasArg(STRIP_regex);
+
+ if (InputArgs.hasArg(STRIP_regex) && InputArgs.hasArg(STRIP_wildcard))
+ return createStringError(errc::invalid_argument,
+ "--regex and --wildcard are incompatible");
+ MatchStyle SectionMatchStyle =
+ InputArgs.hasArg(STRIP_regex) ? MatchStyle::Regex : MatchStyle::Wildcard;
+ MatchStyle SymbolMatchStyle = InputArgs.hasArg(STRIP_regex)
+ ? MatchStyle::Regex
+ : InputArgs.hasArg(STRIP_wildcard)
+ ? MatchStyle::Wildcard
+ : MatchStyle::Literal;
Config.AllowBrokenLinks = InputArgs.hasArg(STRIP_allow_broken_links);
Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug);
@@ -744,16 +822,24 @@ parseStripOptions(ArrayRef<const char *> ArgsArr,
Config.KeepFileSymbols = InputArgs.hasArg(STRIP_keep_file_symbols);
for (auto Arg : InputArgs.filtered(STRIP_keep_section))
- Config.KeepSection.addMatcher({Arg->getValue(), UseRegexp});
+ if (Error E = Config.KeepSection.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SectionMatchStyle, ErrorCallback)))
+ return std::move(E);
for (auto Arg : InputArgs.filtered(STRIP_remove_section))
- Config.ToRemove.addMatcher({Arg->getValue(), UseRegexp});
+ if (Error E = Config.ToRemove.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SectionMatchStyle, ErrorCallback)))
+ return std::move(E);
for (auto Arg : InputArgs.filtered(STRIP_strip_symbol))
- Config.SymbolsToRemove.addMatcher({Arg->getValue(), UseRegexp});
+ if (Error E = Config.SymbolsToRemove.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
+ return std::move(E);
for (auto Arg : InputArgs.filtered(STRIP_keep_symbol))
- Config.SymbolsToKeep.addMatcher({Arg->getValue(), UseRegexp});
+ if (Error E = Config.SymbolsToKeep.addMatcher(NameOrPattern::create(
+ Arg->getValue(), SymbolMatchStyle, ErrorCallback)))
+ return std::move(E);
if (!InputArgs.hasArg(STRIP_no_strip_all) && !Config.StripDebug &&
!Config.StripUnneeded && Config.DiscardMode == DiscardType::None &&
diff --git a/llvm/tools/llvm-objcopy/CopyConfig.h b/llvm/tools/llvm-objcopy/CopyConfig.h
index 745af0ce..55a55d3 100644
--- a/llvm/tools/llvm-objcopy/CopyConfig.h
+++ b/llvm/tools/llvm-objcopy/CopyConfig.h
@@ -19,6 +19,7 @@
#include "llvm/Object/ELFTypes.h"
#include "llvm/Support/Allocator.h"
#include "llvm/Support/Error.h"
+#include "llvm/Support/GlobPattern.h"
#include "llvm/Support/Regex.h"
// Necessary for llvm::DebugCompressionType::None
#include "llvm/Target/TargetOptions.h"
@@ -88,28 +89,58 @@ enum class DiscardType {
Locals, // --discard-locals (-X)
};
-class NameOrRegex {
+enum class MatchStyle {
+ Literal, // Default for symbols.
+ Wildcard, // Default for sections, or enabled with --wildcard (-w).
+ Regex, // Enabled with --regex.
+};
+
+class NameOrPattern {
StringRef Name;
// Regex is shared between multiple CopyConfig instances.
std::shared_ptr<Regex> R;
+ std::shared_ptr<GlobPattern> G;
+ bool IsPositiveMatch = true;
+
+ NameOrPattern(StringRef N) : Name(N) {}
+ NameOrPattern(std::shared_ptr<Regex> R) : R(R) {}
+ NameOrPattern(std::shared_ptr<GlobPattern> G, bool IsPositiveMatch)
+ : G(G), IsPositiveMatch(IsPositiveMatch) {}
public:
- NameOrRegex(StringRef Pattern, bool IsRegex);
- bool operator==(StringRef S) const { return R ? R->match(S) : Name == S; }
+ // ErrorCallback is used to handle recoverable errors. An Error returned
+ // by the callback aborts the parsing and is then returned by this function.
+ static Expected<NameOrPattern>
+ create(StringRef Pattern, MatchStyle MS,
+ llvm::function_ref<Error(Error)> ErrorCallback);
+
+ bool isPositiveMatch() const { return IsPositiveMatch; }
+ bool operator==(StringRef S) const {
+ return R ? R->match(S) : G ? G->match(S) : Name == S;
+ }
bool operator!=(StringRef S) const { return !operator==(S); }
};
// Matcher that checks symbol or section names against the command line flags
// provided for that option.
class NameMatcher {
- std::vector<NameOrRegex> Matchers;
+ std::vector<NameOrPattern> PosMatchers;
+ std::vector<NameOrPattern> NegMatchers;
public:
- void addMatcher(NameOrRegex Matcher) {
- Matchers.push_back(std::move(Matcher));
+ Error addMatcher(Expected<NameOrPattern> Matcher) {
+ if (!Matcher)
+ return Matcher.takeError();
+ if (Matcher->isPositiveMatch())
+ PosMatchers.push_back(std::move(*Matcher));
+ else
+ NegMatchers.push_back(std::move(*Matcher));
+ return Error::success();
+ }
+ bool matches(StringRef S) const {
+ return is_contained(PosMatchers, S) && !is_contained(NegMatchers, S);
}
- bool matches(StringRef S) const { return is_contained(Matchers, S); }
- bool empty() const { return Matchers.empty(); }
+ bool empty() const { return PosMatchers.empty() && NegMatchers.empty(); }
};
// Configuration for copying/stripping a single file.
@@ -214,8 +245,11 @@ struct DriverConfig {
// ParseObjcopyOptions returns the config and sets the input arguments. If a
// help flag is set then ParseObjcopyOptions will print the help messege and
-// exit.
-Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr);
+// exit. ErrorCallback is used to handle recoverable errors. An Error returned
+// by the callback aborts the parsing and is then returned by this function.
+Expected<DriverConfig>
+parseObjcopyOptions(ArrayRef<const char *> ArgsArr,
+ llvm::function_ref<Error(Error)> ErrorCallback);
// ParseStripOptions returns the config and sets the input arguments. If a
// help flag is set then ParseStripOptions will print the help messege and
@@ -223,7 +257,7 @@ Expected<DriverConfig> parseObjcopyOptions(ArrayRef<const char *> ArgsArr);
// by the callback aborts the parsing and is then returned by this function.
Expected<DriverConfig>
parseStripOptions(ArrayRef<const char *> ArgsArr,
- std::function<Error(Error)> ErrorCallback);
+ llvm::function_ref<Error(Error)> ErrorCallback);
} // namespace objcopy
} // namespace llvm
diff --git a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
index db6d751..a68210f 100644
--- a/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
+++ b/llvm/tools/llvm-objcopy/llvm-objcopy.cpp
@@ -335,7 +335,7 @@ int main(int argc, char **argv) {
Expected<DriverConfig> DriverConfig =
IsStrip ? parseStripOptions(Args, reportWarning)
- : parseObjcopyOptions(Args);
+ : parseObjcopyOptions(Args, reportWarning);
if (!DriverConfig) {
logAllUnhandledErrors(DriverConfig.takeError(),
WithColor::error(errs(), ToolName));