[llvm-objcopy][MachO] Implement --strip-all

Reviewers: alexshap, rupprecht, jdoerfert, jhenderson

Reviewed By: alexshap

Subscribers: jakehehrlich, abrachet, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D66281
diff --git a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp
index 73983a1..d14354e 100644
--- a/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp
+++ b/llvm/tools/llvm-objcopy/MachO/MachOObjcopy.cpp
@@ -23,6 +23,16 @@
 static void removeSections(const CopyConfig &Config, Object &Obj) {
   SectionPred RemovePred = [](const Section &) { return false; };
 
+  if (Config.StripAll) {
+    // Remove all debug sections.
+    RemovePred = [RemovePred](const Section &Sec) {
+      if (Sec.Segname == "__DWARF")
+        return true;
+
+      return RemovePred(Sec);
+    };
+  }
+
   if (!Config.OnlySection.empty()) {
     RemovePred = [&Config, RemovePred](const Section &Sec) {
       return !Config.OnlySection.matches(Sec.CanonicalName);
@@ -32,6 +42,23 @@
   return Obj.removeSections(RemovePred);
 }
 
+static void markSymbols(const CopyConfig &Config, Object &Obj) {
+  // Symbols referenced from the indirect symbol table must not be removed.
+  for (IndirectSymbolEntry &ISE : Obj.IndirectSymTable.Symbols)
+    if (ISE.Symbol)
+      (*ISE.Symbol)->Referenced = true;
+}
+
+static void removeSymbols(const CopyConfig &Config, Object &Obj) {
+  auto RemovePred = [Config](const std::unique_ptr<SymbolEntry> &N) {
+    if (N->Referenced)
+      return false;
+    return Config.StripAll;
+  };
+
+  Obj.SymTable.removeSymbols(RemovePred);
+}
+
 static Error handleArgs(const CopyConfig &Config, Object &Obj) {
   if (Config.AllowBrokenLinks || !Config.BuildIdLinkDir.empty() ||
       Config.BuildIdLinkInput || Config.BuildIdLinkOutput ||
@@ -45,9 +72,9 @@
       !Config.UnneededSymbolsToRemove.empty() ||
       !Config.SetSectionAlignment.empty() || !Config.SetSectionFlags.empty() ||
       !Config.ToRemove.empty() || Config.ExtractDWO || Config.KeepFileSymbols ||
-      Config.LocalizeHidden || Config.PreserveDates || Config.StripDWO ||
-      Config.StripNonAlloc || Config.StripSections || Config.Weaken ||
-      Config.DecompressDebugSections || Config.StripDebug ||
+      Config.LocalizeHidden || Config.PreserveDates || Config.StripAllGNU ||
+      Config.StripDWO || Config.StripNonAlloc || Config.StripSections ||
+      Config.Weaken || Config.DecompressDebugSections || Config.StripDebug ||
       Config.StripNonAlloc || Config.StripSections || Config.StripUnneeded ||
       Config.DiscardMode != DiscardType::None || !Config.SymbolsToAdd.empty() ||
       Config.EntryExpr) {
@@ -56,6 +83,18 @@
   }
 
   removeSections(Config, Obj);
+
+  // Mark symbols to determine which symbols are still needed.
+  if (Config.StripAll)
+    markSymbols(Config, Obj);
+
+  removeSymbols(Config, Obj);
+
+  if (Config.StripAll)
+    for (LoadCommand &LC : Obj.LoadCommands)
+      for (Section &Sec : LC.Sections)
+        Sec.Relocations.clear();
+
   return Error::success();
 }
 
diff --git a/llvm/tools/llvm-objcopy/MachO/Object.cpp b/llvm/tools/llvm-objcopy/MachO/Object.cpp
index ba3e2ef..5626782 100644
--- a/llvm/tools/llvm-objcopy/MachO/Object.cpp
+++ b/llvm/tools/llvm-objcopy/MachO/Object.cpp
@@ -10,6 +10,18 @@
   return Symbols[Index].get();
 }
 
+SymbolEntry *SymbolTable::getSymbolByIndex(uint32_t Index) {
+  return const_cast<SymbolEntry *>(
+      static_cast<const SymbolTable *>(this)->getSymbolByIndex(Index));
+}
+
+void SymbolTable::removeSymbols(
+    function_ref<bool(const std::unique_ptr<SymbolEntry> &)> ToRemove) {
+  Symbols.erase(
+      std::remove_if(std::begin(Symbols), std::end(Symbols), ToRemove),
+      std::end(Symbols));
+}
+
 void Object::removeSections(function_ref<bool(const Section &)> ToRemove) {
   for (LoadCommand &LC : LoadCommands)
     LC.Sections.erase(std::remove_if(std::begin(LC.Sections),
diff --git a/llvm/tools/llvm-objcopy/MachO/Object.h b/llvm/tools/llvm-objcopy/MachO/Object.h
index bf80253..8642ce3 100644
--- a/llvm/tools/llvm-objcopy/MachO/Object.h
+++ b/llvm/tools/llvm-objcopy/MachO/Object.h
@@ -87,6 +87,7 @@
 // nlist.
 struct SymbolEntry {
   std::string Name;
+  bool Referenced = false;
   uint32_t Index;
   uint8_t n_type;
   uint8_t n_sect;
@@ -110,6 +111,9 @@
   std::vector<std::unique_ptr<SymbolEntry>> Symbols;
 
   const SymbolEntry *getSymbolByIndex(uint32_t Index) const;
+  SymbolEntry *getSymbolByIndex(uint32_t Index);
+  void removeSymbols(
+      function_ref<bool(const std::unique_ptr<SymbolEntry> &)> ToRemove);
 };
 
 struct IndirectSymbolEntry {
@@ -118,10 +122,9 @@
   uint32_t OriginalIndex;
   /// The Symbol referenced by this entry. It's None if the index is
   /// INDIRECT_SYMBOL_LOCAL or INDIRECT_SYMBOL_ABS.
-  Optional<const SymbolEntry *> Symbol;
+  Optional<SymbolEntry *> Symbol;
 
-  IndirectSymbolEntry(uint32_t OriginalIndex,
-                      Optional<const SymbolEntry *> Symbol)
+  IndirectSymbolEntry(uint32_t OriginalIndex, Optional<SymbolEntry *> Symbol)
       : OriginalIndex(OriginalIndex), Symbol(Symbol) {}
 };