[llvm-objcopy] Add --redefine-syms

Differential revision: https://reviews.llvm.org/D57738


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@353509 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/tools/llvm-objcopy/ELF/redefine-symbol.test b/test/tools/llvm-objcopy/ELF/redefine-symbol.test
index c56621a..b8e6066 100644
--- a/test/tools/llvm-objcopy/ELF/redefine-symbol.test
+++ b/test/tools/llvm-objcopy/ELF/redefine-symbol.test
@@ -3,6 +3,16 @@
 # RUN: llvm-readobj --symbols %t2 | FileCheck %s
 # RUN: not llvm-objcopy --redefine-sym barbar %t %t2 2>&1 | FileCheck %s --check-prefix=BAD-FORMAT
 # RUN: not llvm-objcopy --redefine-sym foo=f1 --redefine-sym foo=f2 %t %t2 2>&1 | FileCheck %s --check-prefix=MULTIPLE-REDEFINITION
+# RUN: echo "  foo   oof #rename foo  " > %t.rename.txt
+# RUN: echo "empty" >> %t.rename.txt
+# RUN: not llvm-objcopy --redefine-syms %t.rename.txt %t %t3 2>&1 | FileCheck %s --check-prefix=MISSING-SYM-NAME
+# RUN: not llvm-objcopy --redefine-syms %t.rename-none.txt %t %t-none 2>&1 | FileCheck %s --check-prefix=NO-FILE
+# RUN: cmp %t2 %t3
+# RUN: echo "  bar   rab #rename bar  " > %t.rename2.txt
+# RUN: echo "  foo   oof #rename foo  " > %t.rename3.txt
+# RUN: echo "  empty   ytpme #rename empty  " >> %t.rename3.txt
+# RUN: llvm-objcopy --redefine-syms %t.rename2.txt --redefine-syms %t.rename3.txt %t %t4
+# RUN: llvm-readobj --symbols %t4 | FileCheck %s --check-prefix=MULTIPLE-FILES
 
 !ELF
 FileHeader:
@@ -79,3 +89,12 @@
 
 #BAD-FORMAT: Bad format for --redefine-sym
 #MULTIPLE-REDEFINITION: Multiple redefinition of symbol foo
+#MISSING-SYM-NAME: error: {{.*}}.rename.txt:2: missing new symbol name
+#NO-FILE: error: '{{.*}}.rename-none.txt': {{[Nn]}}o such file or directory
+
+#MULTIPLE-FILES:        Name: oof
+#MULTIPLE-FILES-NEXT:   Value: 0x1004
+#MULTIPLE-FILES:        Name: rab
+#MULTIPLE-FILES-NEXT:   Value: 0x2000
+#MULTIPLE-FILES:        Name: ytpme
+#MULTIPLE-FILES-NEXT:   Value: 0x1008
diff --git a/tools/llvm-objcopy/CopyConfig.cpp b/tools/llvm-objcopy/CopyConfig.cpp
index d013ee4..3a0e01c 100644
--- a/tools/llvm-objcopy/CopyConfig.cpp
+++ b/tools/llvm-objcopy/CopyConfig.cpp
@@ -18,6 +18,7 @@
 #include "llvm/Option/ArgList.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Compression.h"
+#include "llvm/Support/Errc.h"
 #include "llvm/Support/MemoryBuffer.h"
 #include "llvm/Support/StringSaver.h"
 #include <memory>
@@ -255,6 +256,32 @@
       ("^" + Pattern.ltrim('^').rtrim('$') + "$").toStringRef(Data));
 }
 
+static Error addSymbolsToRenameFromFile(StringMap<StringRef> &SymbolsToRename,
+                                        BumpPtrAllocator &Alloc,
+                                        StringRef Filename) {
+  StringSaver Saver(Alloc);
+  SmallVector<StringRef, 16> Lines;
+  auto BufOrErr = MemoryBuffer::getFile(Filename);
+  if (!BufOrErr)
+    return createError(Filename, BufOrErr.getError());
+
+  BufOrErr.get()->getBuffer().split(Lines, '\n');
+  size_t NumLines = Lines.size();
+  for (size_t LineNo = 0; LineNo < NumLines; ++LineNo) {
+    StringRef TrimmedLine = Lines[LineNo].split('#').first.trim();
+    if (TrimmedLine.empty())
+      continue;
+
+    std::pair<StringRef, StringRef> Pair = Saver.save(TrimmedLine).split(' ');
+    StringRef NewName = Pair.second.trim();
+    if (NewName.empty())
+      return createStringError(errc::invalid_argument,
+                               "%s:%zu: missing new symbol name",
+                               Filename.str().c_str(), LineNo + 1);
+    SymbolsToRename.insert({Pair.first, NewName});
+  }
+  return Error::success();
+}
 // ParseObjcopyOptions returns the config and sets the input arguments. If a
 // help flag is set then ParseObjcopyOptions will print the help messege and
 // exit.
@@ -358,6 +385,11 @@
       error("Multiple redefinition of symbol " + Old2New.first);
   }
 
+  for (auto Arg : InputArgs.filtered(OBJCOPY_redefine_symbols))
+    if (Error E = addSymbolsToRenameFromFile(Config.SymbolsToRename, DC.Alloc,
+                                             Arg->getValue()))
+      error(std::move(E));
+
   for (auto Arg : InputArgs.filtered(OBJCOPY_rename_section)) {
     SectionRename SR = parseRenameSectionValue(StringRef(Arg->getValue()));
     if (!Config.SectionsToRename.try_emplace(SR.OriginalName, SR).second)
diff --git a/tools/llvm-objcopy/ObjcopyOpts.td b/tools/llvm-objcopy/ObjcopyOpts.td
index bc1ac78..ccfc542 100644
--- a/tools/llvm-objcopy/ObjcopyOpts.td
+++ b/tools/llvm-objcopy/ObjcopyOpts.td
@@ -76,6 +76,16 @@
 defm redefine_symbol
     : Eq<"redefine-sym", "Change the name of a symbol old to new">,
       MetaVarName<"old=new">;
+defm redefine_symbols
+    : Eq<"redefine-syms",
+         "Reads a list of symbol pairs from <filename> and runs as if "
+         "--redefine-sym=<old>=<new> is set for each one. <filename> "
+         "contains two symbols per line separated with whitespace and may "
+         "contain comments beginning with '#'. Leading and trailing "
+         "whitespace is stripped from each line. May be repeated to read "
+         "symbols from many files.">,         
+      MetaVarName<"filename">;
+
 defm keep_section : Eq<"keep-section", "Keep <section>">,
                     MetaVarName<"section">;
 defm only_section : Eq<"only-section", "Remove all but <section>">,
diff --git a/tools/llvm-objcopy/llvm-objcopy.cpp b/tools/llvm-objcopy/llvm-objcopy.cpp
index d8dea16..72774ec 100644
--- a/tools/llvm-objcopy/llvm-objcopy.cpp
+++ b/tools/llvm-objcopy/llvm-objcopy.cpp
@@ -52,6 +52,11 @@
 // The name this program was invoked as.
 StringRef ToolName;
 
+Error createError(StringRef File, std::error_code EC) {
+  assert(EC);  
+  return createFileError(File, make_error<StringError>(EC));
+}
+
 LLVM_ATTRIBUTE_NORETURN void error(Twine Message) {
   WithColor::error(errs(), ToolName) << Message << ".\n";
   errs().flush();
@@ -69,10 +74,7 @@
 }
 
 LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, std::error_code EC) {
-  assert(EC);
-  WithColor::error(errs(), ToolName)
-      << "'" << File << "': " << EC.message() << ".\n";
-  exit(1);
+  error(createError(File, EC));
 }
 
 LLVM_ATTRIBUTE_NORETURN void reportError(StringRef File, Error E) {
diff --git a/tools/llvm-objcopy/llvm-objcopy.h b/tools/llvm-objcopy/llvm-objcopy.h
index 18a789c..4783e78 100644
--- a/tools/llvm-objcopy/llvm-objcopy.h
+++ b/tools/llvm-objcopy/llvm-objcopy.h
@@ -18,6 +18,8 @@
 namespace llvm {
 namespace objcopy {
 
+Error createError(StringRef File, std::error_code EC);
+
 LLVM_ATTRIBUTE_NORETURN extern void error(Twine Message);
 LLVM_ATTRIBUTE_NORETURN extern void error(Error E);
 LLVM_ATTRIBUTE_NORETURN extern void reportError(StringRef File, Error E);