[dsymutil] Upstream emitting of papertrail warnings.
authorJonas Devlieghere <jonas@devlieghere.com>
Mon, 2 Apr 2018 10:40:43 +0000 (10:40 +0000)
committerJonas Devlieghere <jonas@devlieghere.com>
Mon, 2 Apr 2018 10:40:43 +0000 (10:40 +0000)
When running dsymutil as part of your build system, it can be desirable
for warnings to be part of the end product, rather than just being
emitted to the output stream. This patch upstreams that functionality.

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

llvm-svn: 328965

llvm/docs/CommandGuide/dsymutil.rst
llvm/lib/CodeGen/AsmPrinter/DIE.cpp
llvm/test/tools/dsymutil/X86/papertrail-warnings.test [new file with mode: 0644]
llvm/test/tools/dsymutil/cmdline.test
llvm/test/tools/dsymutil/debug-map-parsing.test
llvm/tools/dsymutil/DebugMap.h
llvm/tools/dsymutil/DwarfLinker.cpp
llvm/tools/dsymutil/MachODebugMapParser.cpp
llvm/tools/dsymutil/dsymutil.cpp
llvm/tools/dsymutil/dsymutil.h

index a89ee18..ceaa540 100644 (file)
@@ -70,6 +70,13 @@ OPTIONS
 
  Specifies a ``path`` to prepend to all debug symbol object file paths.
 
+.. option:: --papertrail
+
+ When running dsymutil as part of your build system, it can be desirable for
+ warnings to be part of the end product, rather than just being emitted to the
+ output stream. When enabled warnings are embedded in the linked DWARF debug
+ information.
+
 .. option:: -s, --symtab
 
  Dumps the symbol table found in *executable* or object file(s) and exits.
index 6c9969d..b4ab6fa 100644 (file)
@@ -746,6 +746,7 @@ void DIEBlock::EmitValue(const AsmPrinter *Asm, dwarf::Form Form) const {
   case dwarf::DW_FORM_block2: Asm->emitInt16(Size);   break;
   case dwarf::DW_FORM_block4: Asm->emitInt32(Size);   break;
   case dwarf::DW_FORM_block:  Asm->EmitULEB128(Size); break;
+  case dwarf::DW_FORM_string: break;
   case dwarf::DW_FORM_data16: break;
   }
 
diff --git a/llvm/test/tools/dsymutil/X86/papertrail-warnings.test b/llvm/test/tools/dsymutil/X86/papertrail-warnings.test
new file mode 100644 (file)
index 0000000..c2dbabe
--- /dev/null
@@ -0,0 +1,30 @@
+RUN: RC_DEBUG_OPTIONS=1 dsymutil -f %p/../Inputs/basic.macho.x86_64 -o - | llvm-dwarfdump -v - | FileCheck %s
+
+CHECK: .debug_info contents:
+CHECK:  Compile Unit:
+CHECK:  DW_TAG_compile_unit [1] *
+CHECK:    DW_AT_producer {{.*}}"dsymutil
+CHECK:    DW_AT_name {{.*}}"/Inputs/basic1.macho.x86_64.o"
+CHECK:    DW_TAG_constant [2]
+CHECK:      DW_AT_name {{.*}}"dsymutil_warning"
+CHECK:      DW_AT_artificial [DW_FORM_flag]    (0x01)
+CHECK:      DW_AT_const_value {{.*}}"unable to open object file: No such file or directory"
+CHECK:    NULL
+CHECK:  Compile Unit:
+CHECK:  DW_TAG_compile_unit [1] *
+CHECK:    DW_AT_producer {{.*}}"dsymutil
+CHECK:    DW_AT_name {{.*}}"/Inputs/basic2.macho.x86_64.o"
+CHECK:    DW_TAG_constant [2]
+CHECK:      DW_AT_name {{.*}}"dsymutil_warning"
+CHECK:      DW_AT_artificial [DW_FORM_flag]    (0x01)
+CHECK:      DW_AT_const_value {{.*}}"unable to open object file: No such file or directory"
+CHECK:    NULL
+CHECK:  Compile Unit:
+CHECK:  DW_TAG_compile_unit [1] *
+CHECK:    DW_AT_producer {{.*}}"dsymutil
+CHECK:    DW_AT_name {{.*}}"/Inputs/basic3.macho.x86_64.o"
+CHECK:    DW_TAG_constant [2]
+CHECK:      DW_AT_name {{.*}}"dsymutil_warning"
+CHECK:      DW_AT_artificial [DW_FORM_flag]    (0x01)
+CHECK:      DW_AT_const_value {{.*}}"unable to open object file: No such file or directory"
+CHECK:    NULL
\ No newline at end of file
index ff1fc71..c9b5b2c 100644 (file)
@@ -13,6 +13,7 @@ HELP: -no-swiftmodule-timestamp
 HELP: -num-threads=<n>
 HELP: -o=<filename>
 HELP: -oso-prepend-path=<path>
+HELP: -papertrail
 HELP: -symtab
 HELP: -toolchain
 HELP: -update
index 7cdfdea..928323c 100644 (file)
@@ -80,7 +80,7 @@ NOT-FOUND-NEXT: triple: 'x86_64-apple-darwin'
 NOT-FOUND-NEXT: binary-path:{{.*}}/Inputs/basic.macho.x86_64
 NOT-FOUND-NEXT: ...
 
-Check that we correctly error out on invalid executatble.
+Check that we correctly error out on invalid executable.
 
 NO-EXECUTABLE: cannot parse{{.*}}/inexistant': {{[Nn]o}} such file
 NO-EXECUTABLE-NOT: ---
index 2173ba6..4b80bf0 100644 (file)
@@ -176,6 +176,11 @@ public:
     return make_range(Symbols.begin(), Symbols.end());
   }
 
+  bool empty() const { return Symbols.empty(); }
+
+  void addWarning(StringRef Warning) { Warnings.push_back(Warning); }
+  const std::vector<std::string> &getWarnings() const { return Warnings; }
+
   void print(raw_ostream &OS) const;
 #ifndef NDEBUG
   void dump() const;
@@ -194,6 +199,8 @@ private:
   DenseMap<uint64_t, DebugMapEntry *> AddressToMapping;
   uint8_t Type;
 
+  std::vector<std::string> Warnings;
+
   /// For YAMLIO support.
   ///@{
   friend yaml::MappingTraits<dsymutil::DebugMapObject>;
index 41f52e7..8b9a4b9 100644 (file)
@@ -1481,6 +1481,10 @@ private:
       MaxDwarfVersion = Version;
   }
 
+  /// Emit warnings as Dwarf compile units to leave a trail after linking.
+  bool emitPaperTrailWarnings(const DebugMapObject &DMO, const DebugMap &Map,
+                              OffsetsStringPool &StringPool);
+
   /// Keeps track of relocations.
   class RelocationManager {
     struct ValidReloc {
@@ -4118,6 +4122,64 @@ void DwarfLinker::DIECloner::cloneAllCompileUnits(
   }
 }
 
+bool DwarfLinker::emitPaperTrailWarnings(const DebugMapObject &DMO,
+                                         const DebugMap &Map,
+                                         OffsetsStringPool &StringPool) {
+  if (DMO.getWarnings().empty() || !DMO.empty())
+    return false;
+
+  Streamer->switchToDebugInfoSection(/* Version */ 2);
+  DIE *CUDie = DIE::get(DIEAlloc, dwarf::DW_TAG_compile_unit);
+  CUDie->setOffset(11);
+  StringRef Producer = StringPool.internString("dsymutil");
+  StringRef File = StringPool.internString(DMO.getObjectFilename());
+  CUDie->addValue(DIEAlloc, dwarf::DW_AT_producer, dwarf::DW_FORM_strp,
+                  DIEInteger(StringPool.getStringOffset(Producer)));
+  DIEBlock *String = new (DIEAlloc) DIEBlock();
+  DIEBlocks.push_back(String);
+  for (auto &C : File)
+    String->addValue(DIEAlloc, dwarf::Attribute(0), dwarf::DW_FORM_data1,
+                     DIEInteger(C));
+  String->addValue(DIEAlloc, dwarf::Attribute(0), dwarf::DW_FORM_data1,
+                   DIEInteger(0));
+
+  CUDie->addValue(DIEAlloc, dwarf::DW_AT_name, dwarf::DW_FORM_string, String);
+  for (const auto &Warning : DMO.getWarnings()) {
+    DIE &ConstDie = CUDie->addChild(DIE::get(DIEAlloc, dwarf::DW_TAG_constant));
+    ConstDie.addValue(
+        DIEAlloc, dwarf::DW_AT_name, dwarf::DW_FORM_strp,
+        DIEInteger(StringPool.getStringOffset("dsymutil_warning")));
+    ConstDie.addValue(DIEAlloc, dwarf::DW_AT_artificial, dwarf::DW_FORM_flag,
+                      DIEInteger(1));
+    ConstDie.addValue(DIEAlloc, dwarf::DW_AT_const_value, dwarf::DW_FORM_strp,
+                      DIEInteger(StringPool.getStringOffset(Warning)));
+  }
+  unsigned Size = 4 /* FORM_strp */ + File.size() + 1 +
+                  DMO.getWarnings().size() * (4 + 1 + 4) +
+                  1 /* End of children */;
+  DIEAbbrev Abbrev = CUDie->generateAbbrev();
+  AssignAbbrev(Abbrev);
+  CUDie->setAbbrevNumber(Abbrev.getNumber());
+  Size += getULEB128Size(Abbrev.getNumber());
+  // Abbreviation ordering needed for classic compatibility.
+  for (auto &Child : CUDie->children()) {
+    Abbrev = Child.generateAbbrev();
+    AssignAbbrev(Abbrev);
+    Child.setAbbrevNumber(Abbrev.getNumber());
+    Size += getULEB128Size(Abbrev.getNumber());
+  }
+  CUDie->setSize(Size);
+  auto &Asm = Streamer->getAsmPrinter();
+  Asm.emitInt32(11 + CUDie->getSize() - 4);
+  Asm.emitInt16(2);
+  Asm.emitInt32(0);
+  Asm.emitInt8(Map.getTriple().isArch64Bit() ? 8 : 4);
+  Streamer->emitDIE(*CUDie);
+  OutputDebugInfoSize += 11 /* Header */ + Size;
+
+  return true;
+}
+
 bool DwarfLinker::link(const DebugMap &Map) {
   if (!createStreamer(Map.getTriple(), OutFile))
     return false;
@@ -4184,8 +4246,10 @@ bool DwarfLinker::link(const DebugMap &Map) {
       continue;
     }
 
-    if (!LinkContext.ObjectFile)
+    if (emitPaperTrailWarnings(LinkContext.DMO, Map, OffsetsStringPool))
+      continue;
 
+    if (!LinkContext.ObjectFile)
       continue;
 
     // Look for relocations that correspond to debug map entries.
@@ -4232,6 +4296,11 @@ bool DwarfLinker::link(const DebugMap &Map) {
     }
   }
 
+  // If we haven't seen any CUs, pick an arbitrary valid Dwarf version anyway,
+  // to be able to emit papertrail warnings.
+  if (MaxDwarfVersion == 0)
+    MaxDwarfVersion = 3;
+
   ThreadPool pool(2);
 
   // These variables manage the list of processed object files.
index 88b8011..2ec0e62 100644 (file)
@@ -24,10 +24,12 @@ using namespace llvm::object;
 class MachODebugMapParser {
 public:
   MachODebugMapParser(StringRef BinaryPath, ArrayRef<std::string> Archs,
-                      StringRef PathPrefix = "", bool Verbose = false)
+                      StringRef PathPrefix = "",
+                      bool PaperTrailWarnings = false, bool Verbose = false)
       : BinaryPath(BinaryPath), Archs(Archs.begin(), Archs.end()),
-        PathPrefix(PathPrefix), MainBinaryHolder(Verbose),
-        CurrentObjectHolder(Verbose), CurrentDebugMapObject(nullptr) {}
+        PathPrefix(PathPrefix), PaperTrailWarnings(PaperTrailWarnings),
+        MainBinaryHolder(Verbose), CurrentObjectHolder(Verbose),
+        CurrentDebugMapObject(nullptr) {}
 
   /// Parses and returns the DebugMaps of the input binary. The binary contains
   /// multiple maps in case it is a universal binary.
@@ -42,6 +44,7 @@ private:
   std::string BinaryPath;
   SmallVector<StringRef, 1> Archs;
   std::string PathPrefix;
+  bool PaperTrailWarnings;
 
   /// Owns the MemoryBuffer for the main binary.
   BinaryHolder MainBinaryHolder;
@@ -102,6 +105,13 @@ private:
     warn_ostream() << "("
                    << MachOUtils::getArchName(Result->getTriple().getArchName())
                    << ") " << File << " " << Msg << "\n";
+
+    if (PaperTrailWarnings) {
+      if (!File.empty())
+        Result->addDebugMapObject(File, sys::TimePoint<std::chrono::seconds>());
+      if (Result->end() != Result->begin())
+        (*--Result->end())->addWarning(Msg.str());
+    }
   }
 };
 
@@ -522,13 +532,14 @@ namespace llvm {
 namespace dsymutil {
 llvm::ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
 parseDebugMap(StringRef InputFile, ArrayRef<std::string> Archs,
-              StringRef PrependPath, bool Verbose, bool InputIsYAML) {
-  if (!InputIsYAML) {
-    MachODebugMapParser Parser(InputFile, Archs, PrependPath, Verbose);
-    return Parser.parse();
-  } else {
+              StringRef PrependPath, bool PaperTrailWarnings, bool Verbose,
+              bool InputIsYAML) {
+  if (InputIsYAML)
     return DebugMap::parseYAMLDebugMap(InputFile, PrependPath, Verbose);
-  }
+
+  MachODebugMapParser Parser(InputFile, Archs, PrependPath, PaperTrailWarnings,
+                             Verbose);
+  return Parser.parse();
 }
 
 bool dumpStab(StringRef InputFile, ArrayRef<std::string> Archs,
index 533ff89..51118d3 100644 (file)
@@ -147,6 +147,11 @@ static opt<std::string>
     Toolchain("toolchain", desc("Embed toolchain information in dSYM bundle."),
               cat(DsymCategory));
 
+static opt<bool>
+    PaperTrailWarnings("papertrail",
+                       desc("Embed warnings in the linked DWARF debug info."),
+                       cat(DsymCategory));
+
 static bool createPlistFile(llvm::StringRef Bin, llvm::StringRef BundleRoot) {
   if (NoOutput)
     return true;
@@ -430,6 +435,12 @@ int main(int argc, char **argv) {
     return 1;
   }
 
+  if (getenv("RC_DEBUG_OPTIONS"))
+    PaperTrailWarnings = true;
+
+  if (PaperTrailWarnings && InputIsYAMLDebugMap)
+    warn_ostream() << "Paper trail warnings are not supported for YAML input";
+
   for (const auto &Arch : ArchFlags)
     if (Arch != "*" && Arch != "all" &&
         !llvm::object::MachOObjectFile::isValidArch(Arch)) {
@@ -445,8 +456,9 @@ int main(int argc, char **argv) {
       continue;
     }
 
-    auto DebugMapPtrsOrErr = parseDebugMap(InputFile, ArchFlags, OsoPrependPath,
-                                           Verbose, InputIsYAMLDebugMap);
+    auto DebugMapPtrsOrErr =
+        parseDebugMap(InputFile, ArchFlags, OsoPrependPath, PaperTrailWarnings,
+                      Verbose, InputIsYAMLDebugMap);
 
     if (auto EC = DebugMapPtrsOrErr.getError()) {
       error_ostream() << "cannot parse the debug map for '" << InputFile
index 4d7ea47..deaf332 100644 (file)
@@ -59,7 +59,8 @@ struct LinkOptions {
 /// returned when the file is universal (aka fat) binary.
 ErrorOr<std::vector<std::unique_ptr<DebugMap>>>
 parseDebugMap(StringRef InputFile, ArrayRef<std::string> Archs,
-              StringRef PrependPath, bool Verbose, bool InputIsYAML);
+              StringRef PrependPath, bool PaperTrailWarnings, bool Verbose,
+              bool InputIsYAML);
 
 /// Dump the symbol table
 bool dumpStab(StringRef InputFile, ArrayRef<std::string> Archs,