[llvm-strip] Support stripping multiple input files
authorJordan Rupprecht <rupprecht@google.com>
Wed, 5 Sep 2018 13:10:03 +0000 (13:10 +0000)
committerJordan Rupprecht <rupprecht@google.com>
Wed, 5 Sep 2018 13:10:03 +0000 (13:10 +0000)
Summary:
Allow strip to be called on multiple input files, which is interpreted as stripping N files in place. Using multiple input files is incompatible with -o.

To allow this, create a `DriverConfig` struct which just wraps a list of `CopyConfigs`. objcopy will only ever have a single `CopyConfig`, but strip will have N (where N >= 1) CopyConfigs.

Reviewers: alexshap, jakehehrlich

Reviewed By: alexshap, jakehehrlich

Subscribers: MaskRay, jakehehrlich, llvm-commits

Differential Revision: https://reviews.llvm.org/D51660

llvm-svn: 341464

llvm/test/tools/llvm-objcopy/strip-multiple-files.test [new file with mode: 0644]
llvm/tools/llvm-objcopy/llvm-objcopy.cpp

diff --git a/llvm/test/tools/llvm-objcopy/strip-multiple-files.test b/llvm/test/tools/llvm-objcopy/strip-multiple-files.test
new file mode 100644 (file)
index 0000000..d1496eb
--- /dev/null
@@ -0,0 +1,75 @@
+# RUN: yaml2obj %s > %t.o
+
+# Run llvm-strip normally. This will create a stripped object file for later
+# tests so we only have to run FileCheck on it once.
+# RUN: cp %t.o %t.1.o
+# RUN: llvm-strip --keep-symbol=foo %t.1.o -o %t.stripped.o
+# RUN: llvm-readobj -symbols %t.stripped.o | FileCheck %s
+
+# llvm-strip on two files:
+# RUN: cp %t.o %t.1.o
+# RUN: cp %t.o %t.2.o
+# RUN: llvm-strip --keep-symbol=foo %t.1.o %t.2.o
+# RUN: cmp %t.1.o %t.stripped.o
+# RUN: cmp %t.2.o %t.stripped.o
+
+# llvm-strip on three files:
+# RUN: cp %t.o %t.1.o
+# RUN: cp %t.o %t.2.o
+# RUN: cp %t.o %t.3.o
+# RUN: llvm-strip --keep-symbol=foo %t.1.o %t.2.o %t.3.o
+# RUN: cmp %t.1.o %t.stripped.o
+# RUN: cmp %t.2.o %t.stripped.o
+# RUN: cmp %t.3.o %t.stripped.o
+
+# -o cannot be used with multiple input files
+# RUN: cp %t.o %t.1.o
+# RUN: cp %t.o %t.2.o
+# RUN: not llvm-strip --keep-symbol=foo -o %t.stripped.o %t.1.o %t.2.o 2>&1 \
+# RUN:   | FileCheck %s --check-prefix=BAD-O-FLAG
+
+!ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+Symbols:
+  Local:
+    - Name:     foo
+      Type:     STT_FUNC
+      Section:  .text
+      Value:    0x1234
+      Size:     8
+    - Name:     bar
+      Type:     STT_FUNC
+      Section:  .text
+      Value:    0x5678
+      Size:     8
+
+# CHECK:      Symbols [
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name:
+# CHECK-NEXT:     Value: 0x0
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Binding: Local
+# CHECK-NEXT:     Type: None
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: Undefined
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Symbol {
+# CHECK-NEXT:     Name: foo
+# CHECK-NEXT:     Value: 0x1234
+# CHECK-NEXT:     Size: 8
+# CHECK-NEXT:     Binding: Local
+# CHECK-NEXT:     Type: Function
+# CHECK-NEXT:     Other: 0
+# CHECK-NEXT:     Section: .text
+# CHECK-NEXT:   }
+# CHECK-NEXT: ]
+
+# BAD-O-FLAG: Multiple input files cannot be used in combination with -o.
index 72501f3..8ffab54 100644 (file)
@@ -128,6 +128,7 @@ struct SectionRename {
   Optional<uint64_t> NewFlags;
 };
 
+// Configuration for copying/stripping a single file.
 struct CopyConfig {
   // Main input/output options
   StringRef InputFilename;
@@ -177,6 +178,13 @@ struct CopyConfig {
   bool Weaken = false;
 };
 
+// Configuration for the overall invocation of this tool. When invoked as
+// objcopy, will always contain exactly one CopyConfig. When invoked as strip,
+// will contain one or more CopyConfigs.
+struct DriverConfig {
+  SmallVector<CopyConfig, 1> CopyConfigs;
+};
+
 using SectionPred = std::function<bool(const SectionBase &Sec)>;
 
 enum SectionFlag {
@@ -818,7 +826,7 @@ static void addGlobalSymbolsFromFile(std::vector<std::string> &Symbols,
 // ParseObjcopyOptions returns the config and sets the input arguments. If a
 // help flag is set then ParseObjcopyOptions will print the help messege and
 // exit.
-static CopyConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
+static DriverConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
   ObjcopyOptTable T;
   unsigned MissingArgumentIndex, MissingArgumentCount;
   llvm::opt::InputArgList InputArgs =
@@ -918,13 +926,15 @@ static CopyConfig parseObjcopyOptions(ArrayRef<const char *> ArgsArr) {
 
   Config.PreserveDates = InputArgs.hasArg(OBJCOPY_preserve_dates);
 
-  return Config;
+  DriverConfig DC;
+  DC.CopyConfigs.push_back(std::move(Config));
+  return DC;
 }
 
 // ParseStripOptions returns the config and sets the input arguments. If a
 // help flag is set then ParseStripOptions will print the help messege and
 // exit.
-static CopyConfig parseStripOptions(ArrayRef<const char *> ArgsArr) {
+static DriverConfig parseStripOptions(ArrayRef<const char *> ArgsArr) {
   StripOptTable T;
   unsigned MissingArgumentIndex, MissingArgumentCount;
   llvm::opt::InputArgList InputArgs =
@@ -949,14 +959,10 @@ static CopyConfig parseStripOptions(ArrayRef<const char *> ArgsArr) {
   if (Positional.empty())
     error("No input file specified");
 
-  if (Positional.size() > 1)
-    error("Support for multiple input files is not implemented yet");
+  if (Positional.size() > 1 && InputArgs.hasArg(STRIP_output))
+    error("Multiple input files cannot be used in combination with -o");
 
   CopyConfig Config;
-  Config.InputFilename = Positional[0];
-  Config.OutputFilename =
-      InputArgs.getLastArgValue(STRIP_output, Positional[0]);
-
   Config.StripDebug = InputArgs.hasArg(STRIP_strip_debug);
 
   Config.DiscardAll = InputArgs.hasArg(STRIP_discard_all);
@@ -974,16 +980,31 @@ static CopyConfig parseStripOptions(ArrayRef<const char *> ArgsArr) {
 
   Config.PreserveDates = InputArgs.hasArg(STRIP_preserve_dates);
 
-  return Config;
+  DriverConfig DC;
+  if (Positional.size() == 1) {
+    Config.InputFilename = Positional[0];
+    Config.OutputFilename =
+        InputArgs.getLastArgValue(STRIP_output, Positional[0]);
+    DC.CopyConfigs.push_back(std::move(Config));
+  } else {
+    for (const char *Filename : Positional) {
+      Config.InputFilename = Filename;
+      Config.OutputFilename = Filename;
+      DC.CopyConfigs.push_back(Config);
+    }
+  }
+
+  return DC;
 }
 
 int main(int argc, char **argv) {
   InitLLVM X(argc, argv);
   ToolName = argv[0];
-  CopyConfig Config;
+  DriverConfig DriverConfig;
   if (sys::path::stem(ToolName).endswith_lower("strip"))
-    Config = parseStripOptions(makeArrayRef(argv + 1, argc));
+    DriverConfig = parseStripOptions(makeArrayRef(argv + 1, argc));
   else
-    Config = parseObjcopyOptions(makeArrayRef(argv + 1, argc));
-  executeElfObjcopy(Config);
+    DriverConfig = parseObjcopyOptions(makeArrayRef(argv + 1, argc));
+  for (const CopyConfig &CopyConfig : DriverConfig.CopyConfigs)
+    executeElfObjcopy(CopyConfig);
 }