[tools] Introduce llvm-strip
authorAlexander Shaposhnikov <shal1t712@gmail.com>
Mon, 7 May 2018 19:32:09 +0000 (19:32 +0000)
committerAlexander Shaposhnikov <shal1t712@gmail.com>
Mon, 7 May 2018 19:32:09 +0000 (19:32 +0000)
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

llvm/test/tools/llvm-objcopy/strip-all.test
llvm/test/tools/llvm-objcopy/strip-debug.test
llvm/tools/llvm-objcopy/CMakeLists.txt
llvm/tools/llvm-objcopy/ObjcopyOpts.td [moved from llvm/tools/llvm-objcopy/Opts.td with 100% similarity]
llvm/tools/llvm-objcopy/StripOpts.td [new file with mode: 0644]
llvm/tools/llvm-objcopy/llvm-objcopy.cpp

index 3e6d0d0..e4bf4e5 100644 (file)
@@ -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
index d88e238..e24843d 100644 (file)
@@ -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
index c2d2d79..b0cd66b 100644 (file)
@@ -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/llvm/tools/llvm-objcopy/StripOpts.td b/llvm/tools/llvm-objcopy/StripOpts.td
new file mode 100644 (file)
index 0000000..3266c89
--- /dev/null
@@ -0,0 +1,12 @@
+include "llvm/Option/OptParser.td"
+
+multiclass Eq<string name> {
+  def NAME: Separate<["--", "-"], name>;
+  def NAME # _eq: Joined<["--", "-"], name # "=">, Alias<!cast<Separate>(NAME)>;
+}
+
+def help : Flag<["-", "--"], "help">;
+
+def strip_debug : Flag<["-", "--"], "strip-debug">,
+                  HelpText<"Remove debugging symbols only">;
+
index 900a11d..295c9bf 100644 (file)
@@ -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 <algorithm>
 #include <cassert>
@@ -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<StringRef> SymbolsToGlobalize;
   std::vector<StringRef> SymbolsToWeaken;
   StringMap<StringRef> 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<bool(const SectionBase &Sec)>;
@@ -449,10 +475,50 @@ CopyConfig ParseObjcopyOptions(ArrayRef<const char *> 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<const char *> 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 <input> [ <output> ]", "strip tool");
+    exit(0);
+  }
+
+  SmallVector<const char *, 2> 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);
 }