[llvm] r324592 - Re-land [dsymutil] Upstream update feature

Jonas Devlieghere via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 8 02:48:54 PST 2018


Author: jdevlieghere
Date: Thu Feb  8 02:48:54 2018
New Revision: 324592

URL: http://llvm.org/viewvc/llvm-project?rev=324592&view=rev
Log:
Re-land [dsymutil] Upstream update feature

This commit attempts to re-land the r324480 which was reverted in
r324493 because it broke the Windows bots. For now I disabled the two
update tests on Windows until I'm able to debug this.

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

Added:
    llvm/trunk/test/tools/dsymutil/X86/update-one-CU.test
    llvm/trunk/test/tools/dsymutil/X86/update.test
Modified:
    llvm/trunk/docs/CommandGuide/dsymutil.rst
    llvm/trunk/test/tools/dsymutil/X86/basic-linking-x86.test
    llvm/trunk/test/tools/dsymutil/cmdline.test
    llvm/trunk/tools/dsymutil/DebugMap.h
    llvm/trunk/tools/dsymutil/DwarfLinker.cpp
    llvm/trunk/tools/dsymutil/dsymutil.cpp
    llvm/trunk/tools/dsymutil/dsymutil.h

Modified: llvm/trunk/docs/CommandGuide/dsymutil.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandGuide/dsymutil.rst?rev=324592&r1=324591&r2=324592&view=diff
==============================================================================
--- llvm/trunk/docs/CommandGuide/dsymutil.rst (original)
+++ llvm/trunk/docs/CommandGuide/dsymutil.rst Thu Feb  8 02:48:54 2018
@@ -40,7 +40,9 @@ OPTIONS
 
  When used when creating a dSYM file, this option will suppress the emission of
  the .debug_inlines, .debug_pubnames, and .debug_pubtypes sections since
- dsymutil currently has better equivalents: .apple_names and .apple_types.
+ dsymutil currently has better equivalents: .apple_names and .apple_types. When
+ used in conjunction with --update option, this option will cause redundant
+ accelerator tables to be removed.
 
 .. option:: --no-odr
 
@@ -72,6 +74,12 @@ OPTIONS
 
  Dumps the symbol table found in *executable* or object file(s) and exits.
 
+.. option:: -u, --update
+
+ Update an existing dSYM file to contain the latest accelerator tables and
+ other DWARF optimizations. This option will rebuild the '.apple_names' and
+ '.apple_types' hashed accelerator tables.
+
 .. option:: -v, --verbose
 
  Display verbose information when linking.

Modified: llvm/trunk/test/tools/dsymutil/X86/basic-linking-x86.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/X86/basic-linking-x86.test?rev=324592&r1=324591&r2=324592&view=diff
==============================================================================
--- llvm/trunk/test/tools/dsymutil/X86/basic-linking-x86.test (original)
+++ llvm/trunk/test/tools/dsymutil/X86/basic-linking-x86.test Thu Feb  8 02:48:54 2018
@@ -8,6 +8,21 @@ RUN: llvm-dsymutil -f -o - -oso-prepend-
 RUN: llvm-dsymutil -dump-debug-map -oso-prepend-path=%p/.. %p/../Inputs/basic.macho.x86_64 | llvm-dsymutil -f -y -o - - | llvm-dwarfdump -a - | FileCheck %s --check-prefix=CHECK --check-prefix=BASIC
 RUN: llvm-dsymutil -dump-debug-map -oso-prepend-path=%p/.. %p/../Inputs/basic-archive.macho.x86_64 | llvm-dsymutil -f -o - -y - | llvm-dwarfdump -a - | FileCheck %s --check-prefix=CHECK --check-prefix=ARCHIVE
 
+# Update tests
+RUN: rm -rf %t.dir
+RUN: mkdir -p %t.dir
+RUN: cat %p/../Inputs/basic.macho.x86_64 > %t.dir/basic
+RUN: llvm-dsymutil -oso-prepend-path=%p/.. %t.dir/basic
+RUN: llvm-dwarfdump -a %t.dir/basic.dSYM | FileCheck %s
+RUN: llvm-dsymutil --update %t.dir/basic.dSYM
+RUN: llvm-dwarfdump -a %t.dir/basic.dSYM | FileCheck %s
+RUN: llvm-dsymutil -u %t.dir/basic.dSYM
+RUN: llvm-dwarfdump -a %t.dir/basic.dSYM | FileCheck %s
+RUN: llvm-dsymutil --update %t.dir/basic.dSYM -o %t.dir/updated.dSYM
+RUN: llvm-dwarfdump -a %t.dir/updated.dSYM | FileCheck %s
+RUN: llvm-dsymutil -f -u %t2 -o %t3
+RUN: llvm-dwarfdump -a %t3 | FileCheck %s
+
 CHECK: file format Mach-O 64-bit x86-64
 
 CHECK: debug_info contents

Added: llvm/trunk/test/tools/dsymutil/X86/update-one-CU.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/X86/update-one-CU.test?rev=324592&view=auto
==============================================================================
--- llvm/trunk/test/tools/dsymutil/X86/update-one-CU.test (added)
+++ llvm/trunk/test/tools/dsymutil/X86/update-one-CU.test Thu Feb  8 02:48:54 2018
@@ -0,0 +1,38 @@
+FIXME: This test should *not* fail on Windows.
+UNSUPPORTED: windows
+
+RUN: llvm-dsymutil -oso-prepend-path=%p/.. %p/../Inputs/objc.macho.x86_64 -o %t.dSYM
+RUN: llvm-dsymutil -update %t.dSYM
+RUN: llvm-dwarfdump -apple-types -apple-objc %t.dSYM | FileCheck %s
+
+CHECK: .apple_types contents:
+CHECK: Hash 0x2b5e6 [
+CHECK-NEXT:    Name at 0x145 {
+CHECK-NEXT:      String: 0x00000066 "A"
+CHECK-NEXT:      Data 0 [
+CHECK-NEXT:        Atom[0]: 0x0000012d
+CHECK-NEXT:        Atom[1]: 0x0013
+CHECK-NEXT:        Atom[2]: 0x02
+CHECK-NEXT:        Atom[3]: 0x0b87b15a
+CHECK-NEXT:      ]
+CHECK-NEXT:    }
+CHECK-NEXT:  ]
+
+CHECK: .apple_objc contents:
+CHECK: Hash 0x2b5e6
+CHECK-NEXT: Name at 0x38 {
+CHECK-NEXT:   String: 0x00000066 "A"
+CHECK-NEXT:   Data 0 [
+CHECK-NEXT:     Atom[0]: 0x00000027
+CHECK-NEXT:   ]
+CHECK-NEXT:   Data 1 [
+CHECK-NEXT:     Atom[0]: 0x0000007a
+CHECK-NEXT:   ]
+CHECK-NEXT: }
+CHECK: Hash 0x3fa0f4b5
+CHECK-NEXT: Name at 0x4c {
+CHECK-NEXT:   String: 0x0000009d "A(Category)"
+CHECK-NEXT:   Data 0 [
+CHECK-NEXT:     Atom[0]: 0x0000007a
+CHECK-NEXT:   ]
+CHECK-NEXT: }

Added: llvm/trunk/test/tools/dsymutil/X86/update.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/X86/update.test?rev=324592&view=auto
==============================================================================
--- llvm/trunk/test/tools/dsymutil/X86/update.test (added)
+++ llvm/trunk/test/tools/dsymutil/X86/update.test Thu Feb  8 02:48:54 2018
@@ -0,0 +1,18 @@
+FIXME: This test should *not* fail on Windows.
+UNSUPPORTED: windows
+
+RUN: rm -rf %t.dir
+RUN: mkdir -p %t.dir
+RUN: cat %p/../Inputs/basic.macho.x86_64 > %t.dir/basic
+RUN: llvm-dsymutil -oso-prepend-path=%p/.. %t.dir/basic
+RUN: llvm-dwarfdump -a %t.dir/basic.dSYM | FileCheck %S/basic-linking-x86.test
+RUN: llvm-dsymutil --update %t.dir/basic.dSYM
+RUN: llvm-dwarfdump -a %t.dir/basic.dSYM | FileCheck %S/basic-linking-x86.test
+RUN: llvm-dsymutil -u %t.dir/basic.dSYM
+RUN: llvm-dwarfdump -a %t.dir/basic.dSYM | FileCheck %S/basic-linking-x86.test
+RUN: llvm-dsymutil --update %t.dir/basic.dSYM -o %t.dir/updated.dSYM
+RUN: llvm-dwarfdump -a %t.dir/updated.dSYM | FileCheck %S/basic-linking-x86.test
+
+RUN: llvm-dsymutil -f -o %t2 -oso-prepend-path=%p/.. %p/../Inputs/basic.macho.x86_64
+RUN: llvm-dsymutil -f -u %t2 -o %t3
+RUN: llvm-dwarfdump -a %t3 | FileCheck %S/basic-linking-x86.test

Modified: llvm/trunk/test/tools/dsymutil/cmdline.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/cmdline.test?rev=324592&r1=324591&r2=324592&view=diff
==============================================================================
--- llvm/trunk/test/tools/dsymutil/cmdline.test (original)
+++ llvm/trunk/test/tools/dsymutil/cmdline.test Thu Feb  8 02:48:54 2018
@@ -14,6 +14,7 @@ HELP: -num-threads=<n>
 HELP: -o=<filename>
 HELP: -oso-prepend-path=<path>
 HELP: -symtab
+HELP: -update
 HELP: -verbose
 HELP: -verify
 HELP: -y

Modified: llvm/trunk/tools/dsymutil/DebugMap.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/DebugMap.h?rev=324592&r1=324591&r2=324592&view=diff
==============================================================================
--- llvm/trunk/tools/dsymutil/DebugMap.h (original)
+++ llvm/trunk/tools/dsymutil/DebugMap.h Thu Feb  8 02:48:54 2018
@@ -28,6 +28,7 @@
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Triple.h"
 #include "llvm/ADT/iterator_range.h"
+#include "llvm/Object/MachO.h"
 #include "llvm/Support/Chrono.h"
 #include "llvm/Support/ErrorOr.h"
 #include "llvm/Support/YAMLTraits.h"
@@ -107,7 +108,7 @@ public:
   DebugMapObject &
   addDebugMapObject(StringRef ObjectFilePath,
                     sys::TimePoint<std::chrono::seconds> Timestamp,
-                    uint8_t Type);
+                    uint8_t Type = llvm::MachO::N_OSO);
 
   const Triple &getTriple() const { return BinaryTriple; }
 

Modified: llvm/trunk/tools/dsymutil/DwarfLinker.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/DwarfLinker.cpp?rev=324592&r1=324591&r2=324592&view=diff
==============================================================================
--- llvm/trunk/tools/dsymutil/DwarfLinker.cpp (original)
+++ llvm/trunk/tools/dsymutil/DwarfLinker.cpp Thu Feb  8 02:48:54 2018
@@ -100,6 +100,24 @@ namespace dsymutil {
 
 namespace {
 
+/// Retrieve the section named \a SecName in \a Obj.
+///
+/// To accommodate for platform discrepancies, the name passed should be
+/// (for example) 'debug_info' to match either '__debug_info' or '.debug_info'.
+/// This function will strip the initial platform-specific characters.
+static Optional<object::SectionRef>
+getSectionByName(const object::ObjectFile &Obj, StringRef SecName) {
+  for (const object::SectionRef &Section : Obj.sections()) {
+    StringRef SectionName;
+    Section.getName(SectionName);
+    SectionName = SectionName.substr(SectionName.find_first_not_of("._"));
+    if (SectionName != SecName)
+      continue;
+    return Section;
+  }
+  return None;
+}
+
 template <typename KeyT, typename ValT>
 using HalfOpenIntervalMap =
     IntervalMap<KeyT, ValT, IntervalMapImpl::NodeSizer<KeyT, ValT>::LeafSize,
@@ -491,12 +509,48 @@ private:
   std::string ClangModuleName;
 };
 
+/// Check if the DIE at \p Idx is in the scope of a function.
+static bool inFunctionScope(CompileUnit &U, unsigned Idx) {
+  while (Idx) {
+    if (U.getOrigUnit().getDIEAtIndex(Idx).getTag() == dwarf::DW_TAG_subprogram)
+      return true;
+    Idx = U.getInfo(Idx).ParentIdx;
+  }
+  return false;
+}
+
 } // end anonymous namespace
 
 void CompileUnit::markEverythingAsKept() {
-  for (auto &I : Info)
-    // Mark everything that wasn't explicity marked for pruning.
+  unsigned Idx = 0;
+
+  setHasInterestingContent();
+
+  for (auto &I : Info) {
+    // Mark everything that wasn't explicit marked for pruning.
     I.Keep = !I.Prune;
+    auto DIE = OrigUnit.getDIEAtIndex(Idx++);
+
+    // Try to guess which DIEs must go to the accelerator tables. We do that
+    // just for variables, because functions will be handled depending on
+    // whether they carry a DW_AT_low_pc attribute or not.
+    if (DIE.getTag() != dwarf::DW_TAG_variable &&
+        DIE.getTag() != dwarf::DW_TAG_constant)
+      continue;
+
+    Optional<DWARFFormValue> Value;
+    if (!(Value = DIE.find(dwarf::DW_AT_location))) {
+      if ((Value = DIE.find(dwarf::DW_AT_const_value)) &&
+          !inFunctionScope(*this, I.ParentIdx))
+        I.InDebugMap = true;
+      continue;
+    }
+    if (auto Block = Value->getAsBlock()) {
+      if (Block->size() > OrigUnit.getAddressByteSize() &&
+          (*Block)[0] == dwarf::DW_OP_addr)
+        I.InDebugMap = true;
+    }
+  }
 }
 
 uint64_t CompileUnit::computeNextUnitOffset() {
@@ -668,6 +722,9 @@ public:
                             std::vector<DWARFDebugLine::Row> &Rows,
                             unsigned AdddressSize);
 
+  /// Copy over the debug sections that are not modified when updating.
+  void copyInvariantDebugSection(const object::ObjectFile &Obj, LinkOptions &);
+
   uint32_t getLineSectionSize() const { return LineSectionSize; }
 
   /// Emit the .debug_pubnames contribution for \p Unit.
@@ -1200,6 +1257,32 @@ void DwarfStreamer::emitLineTableForUnit
   MS->EmitLabel(LineEndSym);
 }
 
+static void emitSectionContents(const object::ObjectFile &Obj,
+                                StringRef SecName, MCStreamer *MS) {
+  StringRef Contents;
+  if (auto Sec = getSectionByName(Obj, SecName))
+    if (!Sec->getContents(Contents))
+      MS->EmitBytes(Contents);
+}
+
+void DwarfStreamer::copyInvariantDebugSection(const object::ObjectFile &Obj,
+                                              LinkOptions &Options) {
+  MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLineSection());
+  emitSectionContents(Obj, "debug_line", MS);
+
+  MS->SwitchSection(MC->getObjectFileInfo()->getDwarfLocSection());
+  emitSectionContents(Obj, "debug_loc", MS);
+
+  MS->SwitchSection(MC->getObjectFileInfo()->getDwarfRangesSection());
+  emitSectionContents(Obj, "debug_ranges", MS);
+
+  MS->SwitchSection(MC->getObjectFileInfo()->getDwarfFrameSection());
+  emitSectionContents(Obj, "debug_frame", MS);
+
+  MS->SwitchSection(MC->getObjectFileInfo()->getDwarfARangesSection());
+  emitSectionContents(Obj, "debug_aranges", MS);
+}
+
 /// Emit the pubnames or pubtypes section contribution for \p
 /// Unit into \p Sec. The data is provided in \p Names.
 void DwarfStreamer::emitPubSectionForUnit(
@@ -1529,8 +1612,8 @@ private:
     /// it to \p Die.
     /// \returns the size of the new attribute.
     unsigned cloneStringAttribute(DIE &Die, AttributeSpec AttrSpec,
-                                  const DWARFFormValue &Val,
-                                  const DWARFUnit &U);
+                                  const DWARFFormValue &Val, const DWARFUnit &U,
+                                  AttributesInfo &Info);
 
     /// Clone an attribute referencing another DIE and add
     /// it to \p Die.
@@ -2621,12 +2704,18 @@ void DwarfLinker::AssignAbbrev(DIEAbbrev
 unsigned DwarfLinker::DIECloner::cloneStringAttribute(DIE &Die,
                                                       AttributeSpec AttrSpec,
                                                       const DWARFFormValue &Val,
-                                                      const DWARFUnit &U) {
+                                                      const DWARFUnit &U,
+                                                      AttributesInfo &Info) {
   // Switch everything to out of line strings.
   const char *String = *Val.getAsCString();
-  unsigned Offset = Linker.StringPool.getStringOffset(String);
+  auto StringEntry = Linker.StringPool.getEntry(String);
+  if (AttrSpec.Attr == dwarf::DW_AT_name)
+    Info.Name = StringEntry;
+  else if (AttrSpec.Attr == dwarf::DW_AT_MIPS_linkage_name ||
+           AttrSpec.Attr == dwarf::DW_AT_linkage_name)
+    Info.MangledName = StringEntry;
   Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr), dwarf::DW_FORM_strp,
-               DIEInteger(Offset));
+               DIEInteger(StringEntry.getOffset()));
   return 4;
 }
 
@@ -2749,6 +2838,14 @@ unsigned DwarfLinker::DIECloner::cloneAd
     const CompileUnit &Unit, AttributesInfo &Info) {
   uint64_t Addr = *Val.getAsAddress();
 
+  if (LLVM_UNLIKELY(Linker.Options.Update)) {
+    if (AttrSpec.Attr == dwarf::DW_AT_low_pc)
+      Info.HasLowPc = true;
+    Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),
+                 dwarf::Form(AttrSpec.Form), DIEInteger(Addr));
+    return Unit.getOrigUnit().getAddressByteSize();
+  }
+
   if (AttrSpec.Attr == dwarf::DW_AT_low_pc) {
     if (Die.getTag() == dwarf::DW_TAG_inlined_subroutine ||
         Die.getTag() == dwarf::DW_TAG_lexical_block)
@@ -2789,6 +2886,26 @@ unsigned DwarfLinker::DIECloner::cloneSc
     AttributeSpec AttrSpec, const DWARFFormValue &Val, unsigned AttrSize,
     AttributesInfo &Info) {
   uint64_t Value;
+
+  if (LLVM_UNLIKELY(Linker.Options.Update)) {
+    if (auto OptionalValue = Val.getAsUnsignedConstant())
+      Value = *OptionalValue;
+    else if (auto OptionalValue = Val.getAsSignedConstant())
+      Value = *OptionalValue;
+    else if (auto OptionalValue = Val.getAsSectionOffset())
+      Value = *OptionalValue;
+    else {
+      Linker.reportWarning(
+          "Unsupported scalar attribute form. Dropping attribute.", &InputDIE);
+      return 0;
+    }
+    if (AttrSpec.Attr == dwarf::DW_AT_declaration && Value)
+      Info.IsDeclaration = true;
+    Die.addValue(DIEAlloc, dwarf::Attribute(AttrSpec.Attr),
+                 dwarf::Form(AttrSpec.Form), DIEInteger(Value));
+    return AttrSize;
+  }
+
   if (AttrSpec.Attr == dwarf::DW_AT_high_pc &&
       Die.getTag() == dwarf::DW_TAG_compile_unit) {
     if (Unit.getLowPc() == -1ULL)
@@ -2839,7 +2956,7 @@ unsigned DwarfLinker::DIECloner::cloneAt
   switch (AttrSpec.Form) {
   case dwarf::DW_FORM_strp:
   case dwarf::DW_FORM_string:
-    return cloneStringAttribute(Die, AttrSpec, Val, U);
+    return cloneStringAttribute(Die, AttrSpec, Val, U, Info);
   case dwarf::DW_FORM_ref_addr:
   case dwarf::DW_FORM_ref1:
   case dwarf::DW_FORM_ref2:
@@ -3108,13 +3225,14 @@ DIE *DwarfLinker::DIECloner::cloneDIE(
 
   if (Abbrev->getTag() == dwarf::DW_TAG_subprogram) {
     Flags |= TF_InFunctionScope;
-    if (!Info.InDebugMap)
+    if (!Info.InDebugMap && LLVM_LIKELY(!Options.Update))
       Flags |= TF_SkipPC;
   }
 
   bool Copied = false;
   for (const auto &AttrSpec : Abbrev->attributes()) {
-    if (shouldSkipAttribute(AttrSpec, Die->getTag(), Info.InDebugMap,
+    if (LLVM_LIKELY(!Options.Update) &&
+        shouldSkipAttribute(AttrSpec, Die->getTag(), Info.InDebugMap,
                             Flags & TF_SkipPC, Flags & TF_InFunctionScope)) {
       DWARFFormValue::skipValue(AttrSpec.Form, Data, &Offset,
                                 U.getFormParams());
@@ -3827,13 +3945,18 @@ void DwarfLinker::DIECloner::cloneAllCom
     Linker.OutputDebugInfoSize = CurrentUnit->computeNextUnitOffset();
     if (Linker.Options.NoOutput)
       continue;
-    // FIXME: for compatibility with the classic dsymutil, we emit
-    // an empty line table for the unit, even if the unit doesn't
-    // actually exist in the DIE tree.
-    Linker.patchLineTableForUnit(*CurrentUnit, DwarfContext);
-    Linker.emitAcceleratorEntriesForUnit(*CurrentUnit);
-    Linker.patchRangesForUnit(*CurrentUnit, DwarfContext);
-    Linker.Streamer->emitLocationsForUnit(*CurrentUnit, DwarfContext);
+
+    if (LLVM_LIKELY(!Linker.Options.Update)) {
+      // FIXME: for compatibility with the classic dsymutil, we emit an empty
+      // line table for the unit, even if the unit doesn't actually exist in
+      // the DIE tree.
+      Linker.patchLineTableForUnit(*CurrentUnit, DwarfContext);
+      Linker.emitAcceleratorEntriesForUnit(*CurrentUnit);
+      Linker.patchRangesForUnit(*CurrentUnit, DwarfContext);
+      Linker.Streamer->emitLocationsForUnit(*CurrentUnit, DwarfContext);
+    } else {
+      Linker.emitAcceleratorEntriesForUnit(*CurrentUnit);
+    }
   }
 
   if (Linker.Options.NoOutput)
@@ -3841,7 +3964,8 @@ void DwarfLinker::DIECloner::cloneAllCom
 
   // Emit all the compile unit's debug information.
   for (auto &CurrentUnit : CompileUnits) {
-    Linker.generateUnitRanges(*CurrentUnit);
+    if (LLVM_LIKELY(!Linker.Options.Update))
+      Linker.generateUnitRanges(*CurrentUnit);
     CurrentUnit->fixupForwardReferences();
     Linker.Streamer->emitCompileUnitHeader(*CurrentUnit);
     if (!CurrentUnit->getOutputUnitDIE())
@@ -3900,7 +4024,8 @@ bool DwarfLinker::link(const DebugMap &M
 
     // Look for relocations that correspond to debug map entries.
     RelocationManager RelocMgr(*this);
-    if (!RelocMgr.findValidRelocsInDebugInfo(*ErrOrObj, *Obj)) {
+    if (LLVM_LIKELY(!Options.Update) &&
+        !RelocMgr.findValidRelocsInDebugInfo(*ErrOrObj, *Obj)) {
       if (Options.Verbose)
         outs() << "No valid relocations found. Skipping.\n";
       continue;
@@ -3921,9 +4046,10 @@ bool DwarfLinker::link(const DebugMap &M
         CUDie.dump(outs(), 0, DumpOpts);
       }
 
-      if (!registerModuleReference(CUDie, *CU, ModuleMap)) {
-        Units.push_back(llvm::make_unique<CompileUnit>(*CU, UnitID++,
-                                                       !Options.NoODR, ""));
+      if (!CUDie || LLVM_UNLIKELY(Options.Update) ||
+          !registerModuleReference(CUDie, *CU, ModuleMap)) {
+        Units.push_back(llvm::make_unique<CompileUnit>(
+            *CU, UnitID++, !Options.NoODR && !Options.Update, ""));
         maybeUpdateMaxDwarfVersion(CU->getVersion());
       }
     }
@@ -3935,21 +4061,27 @@ bool DwarfLinker::link(const DebugMap &M
 
     // Then mark all the DIEs that need to be present in the linked
     // output and collect some information about them. Note that this
-    // loop can not be merged with the previous one becaue cross-cu
+    // loop can not be merged with the previous one because cross-CU
     // references require the ParentIdx to be setup for every CU in
     // the object file before calling this.
-    for (auto &CurrentUnit : Units)
-      lookForDIEsToKeep(RelocMgr, CurrentUnit->getOrigUnit().getUnitDIE(), *Obj,
-                        *CurrentUnit, 0);
+    if (LLVM_UNLIKELY(Options.Update)) {
+      for (auto &CurrentUnit : Units)
+        CurrentUnit->markEverythingAsKept();
+      Streamer->copyInvariantDebugSection(*ErrOrObj, Options);
+    } else {
+      for (auto &CurrentUnit : Units)
+        lookForDIEsToKeep(RelocMgr, CurrentUnit->getOrigUnit().getUnitDIE(),
+                          *Obj, *CurrentUnit, 0);
+    }
 
     // The calls to applyValidRelocs inside cloneDIE will walk the
     // reloc array again (in the same way findValidRelocsInDebugInfo()
     // did). We need to reset the NextValidReloc index to the beginning.
     RelocMgr.resetValidRelocs();
-    if (RelocMgr.hasValidRelocs())
+    if (RelocMgr.hasValidRelocs() || LLVM_UNLIKELY(Options.Update))
       DIECloner(*this, RelocMgr, DIEAlloc, Units, Options)
           .cloneAllCompileUnits(*DwarfContext);
-    if (!Options.NoOutput && !Units.empty())
+    if (!Options.NoOutput && !Units.empty() && LLVM_LIKELY(!Options.Update))
       patchFrameInfoForObject(*Obj, *DwarfContext,
                               Units[0]->getOrigUnit().getAddressByteSize());
 

Modified: llvm/trunk/tools/dsymutil/dsymutil.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/dsymutil.cpp?rev=324592&r1=324591&r2=324592&view=diff
==============================================================================
--- llvm/trunk/tools/dsymutil/dsymutil.cpp (original)
+++ llvm/trunk/tools/dsymutil/dsymutil.cpp Thu Feb  8 02:48:54 2018
@@ -80,10 +80,21 @@ static opt<bool> Minimize(
     desc("When used when creating a dSYM file, this option will suppress\n"
          "the emission of the .debug_inlines, .debug_pubnames, and\n"
          ".debug_pubtypes sections since dsymutil currently has better\n"
-         "equivalents: .apple_names and .apple_types."),
+         "equivalents: .apple_names and .apple_types. When used in\n"
+         "conjunction with --update option, this option will cause redundant\n"
+         "accelerator tables to be removed."),
     init(false), cat(DsymCategory));
 static alias MinimizeA("z", desc("Alias for --minimize"), aliasopt(Minimize));
 
+static opt<bool> Update(
+    "update",
+    desc("Updates existing dSYM files to contain the latest accelerator\n"
+         "tables and other DWARF optimizations. This option will currently\n"
+         "add the new .apple_names and .apple_types hashed accelerator\n"
+         "tables."),
+    init(false), cat(DsymCategory));
+static alias UpdateA("u", desc("Alias for --update"), aliasopt(Update));
+
 static opt<unsigned> NumThreads(
     "num-threads",
     desc("Specifies the maximum number (n) of simultaneous threads to use\n"
@@ -230,8 +241,12 @@ static bool verify(llvm::StringRef Outpu
 }
 
 static std::string getOutputFileName(llvm::StringRef InputFile) {
+  // When updating, do in place replacement.
+  if (OutputFileOpt.empty() && Update)
+    return InputFile;
+
+  // If a flat dSYM has been requested, things are pretty simple.
   if (FlatOut) {
-    // If a flat dSYM has been requested, things are pretty simple.
     if (OutputFileOpt.empty()) {
       if (InputFile == "-")
         return "a.out.dwarf";
@@ -269,6 +284,76 @@ static Expected<sys::fs::TempFile> creat
   return sys::fs::TempFile::create(TmpModel);
 }
 
+/// Parses the command line options into the LinkOptions struct and performs
+/// some sanity checking. Returns an error in case the latter fails.
+static Expected<LinkOptions> getOptions() {
+  LinkOptions Options;
+
+  Options.Verbose = Verbose;
+  Options.NoOutput = NoOutput;
+  Options.NoODR = NoODR;
+  Options.Minimize = Minimize;
+  Options.Update = Update;
+  Options.NoTimestamp = NoTimestamp;
+  Options.PrependPath = OsoPrependPath;
+
+  if (Options.Update && std::find(InputFiles.begin(), InputFiles.end(), "-") !=
+                            InputFiles.end()) {
+    // FIXME: We cannot use stdin for an update because stdin will be
+    // consumed by the BinaryHolder during the debugmap parsing, and
+    // then we will want to consume it again in DwarfLinker. If we
+    // used a unique BinaryHolder object that could cache multiple
+    // binaries this restriction would go away.
+    return make_error<StringError>(
+        "error: standard input cannot be used as input for a dSYM update.",
+        inconvertibleErrorCode());
+  }
+
+  return Options;
+}
+
+/// Return a list of input files. This function has logic for dealing with the
+/// special case where we might have dSYM bundles as input. The function
+/// returns an error when the directory structure doesn't match that of a dSYM
+/// bundle.
+static Expected<std::vector<std::string>> getInputs(bool DsymAsInput) {
+  if (!DsymAsInput)
+    return InputFiles;
+
+  // If we are updating, we might get dSYM bundles as input.
+  std::vector<std::string> Inputs;
+  for (const auto &Input : InputFiles) {
+    if (!llvm::sys::fs::is_directory(Input)) {
+      Inputs.push_back(Input);
+      continue;
+    }
+
+    // Make sure that we're dealing with a dSYM bundle.
+    std::string dSYMDir = Input + "/Contents/Resources/DWARF";
+    if (!llvm::sys::fs::is_directory(dSYMDir))
+      return make_error<StringError>(
+          Input + " is a directory, but doesn't look like a dSYM bundle.",
+          inconvertibleErrorCode());
+
+    // Create a directory iterator to iterate over all the entries in the
+    // bundle.
+    std::error_code EC;
+    llvm::sys::fs::directory_iterator DirIt(dSYMDir, EC);
+    llvm::sys::fs::directory_iterator DirEnd;
+    if (EC)
+      return errorCodeToError(EC);
+
+    // Add each entry to the list of inputs.
+    while (DirIt != DirEnd) {
+      Inputs.push_back(DirIt->path());
+      DirIt.increment(EC);
+      if (EC)
+        return errorCodeToError(EC);
+    }
+  }
+  return Inputs;
+}
+
 namespace {
 struct TempFileVector {
   std::vector<sys::fs::TempFile> Files;
@@ -285,7 +370,6 @@ int main(int argc, char **argv) {
   llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
   llvm::PrettyStackTraceProgram StackPrinter(argc, argv);
   llvm::llvm_shutdown_obj Shutdown;
-  LinkOptions Options;
   void *P = (void *)(intptr_t)getOutputFileName;
   std::string SDKPath = llvm::sys::fs::getMainExecutable(argv[0], P);
   SDKPath = llvm::sys::path::parent_path(SDKPath);
@@ -308,24 +392,29 @@ int main(int argc, char **argv) {
     return 0;
   }
 
-  Options.Verbose = Verbose;
-  Options.NoOutput = NoOutput;
-  Options.NoODR = NoODR;
-  Options.Minimize = Minimize;
-  Options.NoTimestamp = NoTimestamp;
-  Options.PrependPath = OsoPrependPath;
+  auto OptionsOrErr = getOptions();
+  if (!OptionsOrErr) {
+    errs() << "error: " << toString(OptionsOrErr.takeError());
+    return 1;
+  }
 
   llvm::InitializeAllTargetInfos();
   llvm::InitializeAllTargetMCs();
   llvm::InitializeAllTargets();
   llvm::InitializeAllAsmPrinters();
 
+  auto InputsOrErr = getInputs(OptionsOrErr->Update);
+  if (!InputsOrErr) {
+    errs() << "error: " << toString(InputsOrErr.takeError()) << '\n';
+    return 1;
+  }
+
   if (!FlatOut && OutputFileOpt == "-") {
     llvm::errs() << "error: cannot emit to standard output without --flat\n";
     return 1;
   }
 
-  if (InputFiles.size() > 1 && FlatOut && !OutputFileOpt.empty()) {
+  if (InputsOrErr->size() > 1 && FlatOut && !OutputFileOpt.empty()) {
     llvm::errs() << "error: cannot use -o with multiple inputs in flat mode\n";
     return 1;
   }
@@ -337,7 +426,7 @@ int main(int argc, char **argv) {
       return 1;
     }
 
-  for (auto &InputFile : InputFiles) {
+  for (auto &InputFile : *InputsOrErr) {
     // Dump the symbol table for each input file and requested arch
     if (DumpStab) {
       if (!dumpStab(InputFile, ArchFlags, OsoPrependPath))
@@ -354,6 +443,15 @@ int main(int argc, char **argv) {
       return 1;
     }
 
+    if (OptionsOrErr->Update) {
+      // The debug map should be empty. Add one object file corresponding to
+      // the input file.
+      for (auto &Map : *DebugMapPtrsOrErr)
+        Map->addDebugMapObject(InputFile,
+                               llvm::sys::TimePoint<std::chrono::seconds>());
+    }
+
+    // Ensure that the debug map is not empty (anymore).
     if (DebugMapPtrsOrErr->empty()) {
       llvm::errs() << "error: no architecture to link\n";
       return 1;
@@ -369,7 +467,10 @@ int main(int argc, char **argv) {
 
     // If there is more than one link to execute, we need to generate
     // temporary files.
-    bool NeedsTempFiles = !DumpDebugMap && (*DebugMapPtrsOrErr).size() != 1;
+    bool NeedsTempFiles =
+        !DumpDebugMap && (OutputFileOpt != "-") &&
+        (DebugMapPtrsOrErr->size() != 1 || OptionsOrErr->Update);
+
     llvm::SmallVector<MachOUtils::ArchAndFilename, 4> TempFiles;
     TempFileVector TempFileStore;
     std::atomic_char AllOK(1);
@@ -412,7 +513,7 @@ int main(int argc, char **argv) {
 
       auto LinkLambda = [&,
                          OutputFile](std::shared_ptr<raw_fd_ostream> Stream) {
-        AllOK.fetch_and(linkDwarf(*Stream, *Map, Options));
+        AllOK.fetch_and(linkDwarf(*Stream, *Map, *OptionsOrErr));
         Stream->flush();
         if (Verify && !NoOutput)
           AllOK.fetch_and(verify(OutputFile, Map->getTriple().getArchName()));
@@ -434,7 +535,7 @@ int main(int argc, char **argv) {
 
     if (NeedsTempFiles &&
         !MachOUtils::generateUniversalBinary(
-            TempFiles, getOutputFileName(InputFile), Options, SDKPath))
+            TempFiles, getOutputFileName(InputFile), *OptionsOrErr, SDKPath))
       return 1;
   }
 

Modified: llvm/trunk/tools/dsymutil/dsymutil.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/dsymutil/dsymutil.h?rev=324592&r1=324591&r2=324592&view=diff
==============================================================================
--- llvm/trunk/tools/dsymutil/dsymutil.h (original)
+++ llvm/trunk/tools/dsymutil/dsymutil.h Thu Feb  8 02:48:54 2018
@@ -37,7 +37,10 @@ struct LinkOptions {
   bool NoOutput = false;
 
   /// Do not unique types according to ODR
-  bool NoODR;
+  bool NoODR = false;
+
+  /// Update
+  bool Update = false;
 
   /// Minimize
   bool Minimize = false;




More information about the llvm-commits mailing list