From ebcba7c93cc0b4167be0a8a7df24da4c00676f47 Mon Sep 17 00:00:00 2001 From: Alexander Shaposhnikov Date: Mon, 7 May 2018 19:32:09 +0000 Subject: [PATCH] [tools] Introduce llvm-strip llvm-strip is supposed to be a drop-in replacement for binutils strip. To start the ball rolling this diff adds the initial bits for llvm-strip, more features will be added incrementally over time. Test plan: make check-all Differential revision: https://reviews.llvm.org/D46407 llvm-svn: 331663 --- test/tools/llvm-objcopy/strip-all.test | 8 ++ test/tools/llvm-objcopy/strip-debug.test | 12 +++ tools/llvm-objcopy/CMakeLists.txt | 15 ++- .../llvm-objcopy/{Opts.td => ObjcopyOpts.td} | 0 tools/llvm-objcopy/StripOpts.td | 12 +++ tools/llvm-objcopy/llvm-objcopy.cpp | 98 ++++++++++++++++--- 6 files changed, 125 insertions(+), 20 deletions(-) rename tools/llvm-objcopy/{Opts.td => ObjcopyOpts.td} (100%) create mode 100644 tools/llvm-objcopy/StripOpts.td diff --git a/test/tools/llvm-objcopy/strip-all.test b/test/tools/llvm-objcopy/strip-all.test index 3e6d0d0222f..e4bf4e5e654 100644 --- a/test/tools/llvm-objcopy/strip-all.test +++ b/test/tools/llvm-objcopy/strip-all.test @@ -2,6 +2,14 @@ # RUN: llvm-objcopy --strip-all %t %t2 # RUN: llvm-readobj -file-headers -sections %t2 | FileCheck %s +# We run yaml2obj again rather than copy %t to avoid interfering +# with llvm-objcopy's test (which potentially could have corrupted/updated the binary). + +# RUN: yaml2obj %s > %t3 +# RUN: llvm-strip %t3 +# RUN: llvm-readobj -file-headers -sections %t3 | FileCheck %s +# RUN: cmp %t2 %t3 + !ELF FileHeader: Class: ELFCLASS64 diff --git a/test/tools/llvm-objcopy/strip-debug.test b/test/tools/llvm-objcopy/strip-debug.test index d88e238f6a9..e24843d46b0 100644 --- a/test/tools/llvm-objcopy/strip-debug.test +++ b/test/tools/llvm-objcopy/strip-debug.test @@ -2,6 +2,16 @@ # RUN: llvm-objcopy -strip-debug %t %t2 # RUN: llvm-readobj -file-headers -sections -symbols %t2 | FileCheck %s +# We run yaml2obj again rather than copy %t to avoid interfering +# with llvm-objcopy's test (which potentially could have corrupted/updated the binary). + +# RUN: yaml2obj %s > %t3 +# RUN: llvm-strip -strip-debug %t3 +# RUN: llvm-readobj -file-headers -sections -symbols %t3 | FileCheck %s +# RUN: cmp %t2 %t3 + +# RUN: not llvm-strip -strip-debug 2>&1 | FileCheck %s --check-prefix=NO-INPUT-FILES + !ELF FileHeader: Class: ELFCLASS64 @@ -52,3 +62,5 @@ Symbols: # CHECK-NEXT: Section: .text # CHECK-NEXT: } # CHECK-NEXT: ] + +# NO-INPUT-FILES: No input file specified diff --git a/tools/llvm-objcopy/CMakeLists.txt b/tools/llvm-objcopy/CMakeLists.txt index c2d2d798b38..b0cd66be5b3 100644 --- a/tools/llvm-objcopy/CMakeLists.txt +++ b/tools/llvm-objcopy/CMakeLists.txt @@ -5,18 +5,25 @@ set(LLVM_LINK_COMPONENTS MC ) -set(LLVM_TARGET_DEFINITIONS Opts.td) +set(LLVM_TARGET_DEFINITIONS ObjcopyOpts.td) +tablegen(LLVM ObjcopyOpts.inc -gen-opt-parser-defs) +add_public_tablegen_target(ObjcopyOptsTableGen) -tablegen(LLVM Opts.inc -gen-opt-parser-defs) -add_public_tablegen_target(ObjcopyTableGen) +set(LLVM_TARGET_DEFINITIONS StripOpts.td) +tablegen(LLVM StripOpts.inc -gen-opt-parser-defs) +add_public_tablegen_target(StripOptsTableGen) add_llvm_tool(llvm-objcopy llvm-objcopy.cpp Object.cpp DEPENDS - ObjcopyTableGen + ObjcopyOptsTableGen + StripOptsTableGen ) +add_llvm_tool_symlink(llvm-strip llvm-objcopy) + if(LLVM_INSTALL_BINUTILS_SYMLINKS) add_llvm_tool_symlink(objcopy llvm-objcopy) + add_llvm_tool_symlink(strip llvm-objcopy) endif() diff --git a/tools/llvm-objcopy/Opts.td b/tools/llvm-objcopy/ObjcopyOpts.td similarity index 100% rename from tools/llvm-objcopy/Opts.td rename to tools/llvm-objcopy/ObjcopyOpts.td diff --git a/tools/llvm-objcopy/StripOpts.td b/tools/llvm-objcopy/StripOpts.td new file mode 100644 index 00000000000..3266c89bda0 --- /dev/null +++ b/tools/llvm-objcopy/StripOpts.td @@ -0,0 +1,12 @@ +include "llvm/Option/OptParser.td" + +multiclass Eq { + def NAME: Separate<["--", "-"], name>; + def NAME # _eq: Joined<["--", "-"], name # "=">, Alias(NAME)>; +} + +def help : Flag<["-", "--"], "help">; + +def strip_debug : Flag<["-", "--"], "strip-debug">, + HelpText<"Remove debugging symbols only">; + diff --git a/tools/llvm-objcopy/llvm-objcopy.cpp b/tools/llvm-objcopy/llvm-objcopy.cpp index 900a11d04a1..295c9bf9285 100644 --- a/tools/llvm-objcopy/llvm-objcopy.cpp +++ b/tools/llvm-objcopy/llvm-objcopy.cpp @@ -28,6 +28,7 @@ #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/InitLLVM.h" +#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -45,17 +46,17 @@ using namespace ELF; namespace { -enum ID { +enum ObjcopyID { OBJCOPY_INVALID = 0, // This is not an option ID. #define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ HELPTEXT, METAVAR, VALUES) \ OBJCOPY_##ID, -#include "Opts.inc" +#include "ObjcopyOpts.inc" #undef OPTION }; #define PREFIX(NAME, VALUE) const char *const NAME[] = VALUE; -#include "Opts.inc" +#include "ObjcopyOpts.inc" #undef PREFIX static const opt::OptTable::Info ObjcopyInfoTable[] = { @@ -65,7 +66,7 @@ static const opt::OptTable::Info ObjcopyInfoTable[] = { METAVAR, OBJCOPY_##ID, opt::Option::KIND##Class, \ PARAM, FLAGS, OBJCOPY_##GROUP, \ OBJCOPY_##ALIAS, ALIASARGS, VALUES}, -#include "Opts.inc" +#include "ObjcopyOpts.inc" #undef OPTION }; @@ -74,6 +75,31 @@ public: ObjcopyOptTable() : OptTable(ObjcopyInfoTable, true) {} }; +enum StripID { + STRIP_INVALID = 0, // This is not an option ID. +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + STRIP_##ID, +#include "StripOpts.inc" +#undef OPTION +}; + +static const opt::OptTable::Info StripInfoTable[] = { +#define OPTION(PREFIX, NAME, ID, KIND, GROUP, ALIAS, ALIASARGS, FLAGS, PARAM, \ + HELPTEXT, METAVAR, VALUES) \ + {PREFIX, NAME, HELPTEXT, \ + METAVAR, STRIP_##ID, opt::Option::KIND##Class, \ + PARAM, FLAGS, STRIP_##GROUP, \ + STRIP_##ALIAS, ALIASARGS, VALUES}, +#include "StripOpts.inc" +#undef OPTION +}; + +class StripOptTable : public opt::OptTable { +public: + StripOptTable() : OptTable(StripInfoTable, true) {} +}; + } // namespace // The name this program was invoked as. @@ -122,16 +148,16 @@ struct CopyConfig { std::vector SymbolsToGlobalize; std::vector SymbolsToWeaken; StringMap SymbolsToRename; - bool StripAll; - bool StripAllGNU; - bool StripDebug; - bool StripSections; - bool StripNonAlloc; - bool StripDWO; - bool ExtractDWO; - bool LocalizeHidden; - bool Weaken; - bool DiscardAll; + bool StripAll = false; + bool StripAllGNU = false; + bool StripDebug = false; + bool StripSections = false; + bool StripNonAlloc = false; + bool StripDWO = false; + bool ExtractDWO = false; + bool LocalizeHidden = false; + bool Weaken = false; + bool DiscardAll = false; }; using SectionPred = std::function; @@ -449,10 +475,50 @@ CopyConfig ParseObjcopyOptions(ArrayRef ArgsArr) { return Config; } +// ParseStripOptions returns the config and sets the input arguments. If a +// help flag is set then ParseStripOptions will print the help messege and +// exit. +CopyConfig ParseStripOptions(ArrayRef ArgsArr) { + StripOptTable T; + unsigned MissingArgumentIndex, MissingArgumentCount; + llvm::opt::InputArgList InputArgs = + T.ParseArgs(ArgsArr, MissingArgumentIndex, MissingArgumentCount); + + if (InputArgs.size() == 0 || InputArgs.hasArg(STRIP_help)) { + T.PrintHelp(outs(), "llvm-strip [ ]", "strip tool"); + exit(0); + } + + SmallVector Positional; + for (auto Arg : InputArgs.filtered(STRIP_UNKNOWN)) + error("unknown argument '" + Arg->getAsString(InputArgs) + "'"); + for (auto Arg : InputArgs.filtered(STRIP_INPUT)) + Positional.push_back(Arg->getValue()); + + if (Positional.empty()) + error("No input file specified"); + + if (Positional.size() > 2) + error("Support for multiple input files is not implemented yet"); + + CopyConfig Config; + Config.InputFilename = Positional[0]; + Config.OutputFilename = Positional[0]; + + // Strip debug info only. + Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug); + if (!Config.StripDebug) + Config.StripAll = true; + return Config; +} + int main(int argc, char **argv) { InitLLVM X(argc, argv); ToolName = argv[0]; - - CopyConfig Config = ParseObjcopyOptions(makeArrayRef(argv + 1, argc)); + CopyConfig Config; + if (sys::path::stem(ToolName).endswith_lower("strip")) + Config = ParseStripOptions(makeArrayRef(argv + 1, argc)); + else + Config = ParseObjcopyOptions(makeArrayRef(argv + 1, argc)); ExecuteElfObjcopy(Config); }