[llvm] r324480 - [dsymutil] Upstream update feature.

Jonas Devlieghere via llvm-commits llvm-commits at lists.llvm.org
Wed Feb 7 05:51:29 PST 2018


Author: jdevlieghere
Date: Wed Feb  7 05:51:29 2018
New Revision: 324480

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

Now that dsymutil can generate accelerator tables, we can upstream the
update logic that, as the name implies, updates the accelerator tables
in an existing dSYM bundle. In combination with `-minimize` this can be
used to remove redundant .debug_(inlines|pubtypes|pubnames).

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

Added:
    llvm/trunk/test/tools/dsymutil/X86/update-one-CU.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=324480&r1=324479&r2=324480&view=diff
==============================================================================
--- llvm/trunk/docs/CommandGuide/dsymutil.rst (original)
+++ llvm/trunk/docs/CommandGuide/dsymutil.rst Wed Feb  7 05:51:29 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=324480&r1=324479&r2=324480&view=diff
==============================================================================
--- llvm/trunk/test/tools/dsymutil/X86/basic-linking-x86.test (original)
+++ llvm/trunk/test/tools/dsymutil/X86/basic-linking-x86.test Wed Feb  7 05:51:29 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/Contents/Resources/DWARF/basic | FileCheck %s
+RUN: llvm-dsymutil --update %t.dir/basic.dSYM
+RUN: llvm-dwarfdump -a %t.dir/basic.dSYM/Contents/Resources/DWARF/basic | FileCheck %s
+RUN: llvm-dsymutil -u %t.dir/basic.dSYM
+RUN: llvm-dwarfdump -a %t.dir/basic.dSYM/Contents/Resources/DWARF/basic | FileCheck %s
+RUN: llvm-dsymutil --update %t.dir/basic.dSYM -o %t.dir/updated.dSYM
+RUN: llvm-dwarfdump -a %t.dir/updated.dSYM/Contents/Resources/DWARF/basic | 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=324480&view=auto
==============================================================================
--- llvm/trunk/test/tools/dsymutil/X86/update-one-CU.test (added)
+++ llvm/trunk/test/tools/dsymutil/X86/update-one-CU.test Wed Feb  7 05:51:29 2018
@@ -0,0 +1,35 @@
+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/Contents/Resources/DWARF/objc.macho.x86_64 | 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: }

Modified: llvm/trunk/test/tools/dsymutil/cmdline.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/dsymutil/cmdline.test?rev=324480&r1=324479&r2=324480&view=diff
==============================================================================
--- llvm/trunk/test/tools/dsymutil/cmdline.test (original)
+++ llvm/trunk/test/tools/dsymutil/cmdline.test Wed Feb  7 05:51:29 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=324480&r1=324479&r2=324480&view=diff
==============================================================================
--- llvm/trunk/tools/dsymutil/DebugMap.h (original)
+++ llvm/trunk/tools/dsymutil/DebugMap.h Wed Feb  7 05:51:29 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=324480&r1=324479&r2=324480&view=diff
==============================================================================
--- llvm/trunk/tools/dsymutil/DwarfLinker.cpp (original)
+++ llvm/trunk/tools/dsymutil/DwarfLinker.cpp Wed Feb  7 05:51:29 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=324480&r1=324479&r2=324480&view=diff
==============================================================================
--- llvm/trunk/tools/dsymutil/dsymutil.cpp (original)
+++ llvm/trunk/tools/dsymutil/dsymutil.cpp Wed Feb  7 05:51:29 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=324480&r1=324479&r2=324480&view=diff
==============================================================================
--- llvm/trunk/tools/dsymutil/dsymutil.h (original)
+++ llvm/trunk/tools/dsymutil/dsymutil.h Wed Feb  7 05:51:29 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