r287262 - [CrashReproducer][Darwin] Suggest attaching .crash diagnostic file

Bruno Cardoso Lopes via cfe-commits cfe-commits at lists.llvm.org
Thu Nov 17 13:41:23 PST 2016


Author: bruno
Date: Thu Nov 17 15:41:22 2016
New Revision: 287262

URL: http://llvm.org/viewvc/llvm-project?rev=287262&view=rev
Log:
[CrashReproducer][Darwin] Suggest attaching .crash diagnostic file

In addition to the preprocessed sources file and reproducer script, also
point to the .crash diagnostic files on Darwin. Example:

PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
clang-4.0: note: diagnostic msg: /var/folders/bk/1hj20g8j4xvdj5gd25ywhd3m0000gq/T/RegAllocGreedy-238f28.cpp
clang-4.0: note: diagnostic msg: /var/folders/bk/1hj20g8j4xvdj5gd25ywhd3m0000gq/T/RegAllocGreedy-238f28.cache
clang-4.0: note: diagnostic msg: /var/folders/bk/1hj20g8j4xvdj5gd25ywhd3m0000gq/T/RegAllocGreedy-238f28.sh
clang-4.0: note: diagnostic msg: /var/folders/bk/1hj20g8j4xvdj5gd25ywhd3m0000gq/T/RegAllocGreedy-238f28.crash

When no match is found for the .crash, point the user to a directory
where those can be found. Example:

clang-4.0: note: diagnostic msg: Crash backtrace is located in
clang-4.0: note: diagnostic msg: /Users/bruno/Library/Logs/DiagnosticReports/clang-4.0_<YYYY-MM-DD-HHMMSS>_<hostname>.crash
clang-4.0: note: diagnostic msg: (choose the .crash file that corresponds to your crash)

rdar://problem/27286266

Added:
    cfe/trunk/test/Driver/crash-report-crashfile.m
Modified:
    cfe/trunk/include/clang/Driver/Driver.h
    cfe/trunk/lib/Driver/Driver.cpp

Modified: cfe/trunk/include/clang/Driver/Driver.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/Driver.h?rev=287262&r1=287261&r2=287262&view=diff
==============================================================================
--- cfe/trunk/include/clang/Driver/Driver.h (original)
+++ cfe/trunk/include/clang/Driver/Driver.h Thu Nov 17 15:41:22 2016
@@ -246,6 +246,20 @@ private:
   void generatePrefixedToolNames(StringRef Tool, const ToolChain &TC,
                                  SmallVectorImpl<std::string> &Names) const;
 
+  /// \brief Find the appropriate .crash diagonostic file for the child crash
+  /// under this driver and copy it out to a temporary destination with the
+  /// other reproducer related files (.sh, .cache, etc). If not found, suggest a
+  /// directory for the user to look at.
+  ///
+  /// \param The file path to copy the .crash to.
+  /// \param The suggested directory for the user to look at in case the search
+  /// or copy fails.
+  ///
+  /// \returns If the .crash is found and successfully copied return true,
+  /// otherwise false and return the suggested directory in \p CrashDiagDir.
+  bool getCrashDiagnosticFile(StringRef ReproCrashFilename,
+                              SmallString<128> &CrashDiagDir);
+
 public:
   Driver(StringRef ClangExecutable, StringRef DefaultTargetTriple,
          DiagnosticsEngine &Diags,

Modified: cfe/trunk/lib/Driver/Driver.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Driver.cpp?rev=287262&r1=287261&r2=287262&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/Driver.cpp (original)
+++ cfe/trunk/lib/Driver/Driver.cpp Thu Nov 17 15:41:22 2016
@@ -42,6 +42,9 @@
 #include <map>
 #include <memory>
 #include <utility>
+#if LLVM_ON_UNIX
+#include <unistd.h> // getpid
+#endif
 
 using namespace clang::driver;
 using namespace clang;
@@ -695,6 +698,95 @@ static void printArgList(raw_ostream &OS
   OS << '\n';
 }
 
+bool Driver::getCrashDiagnosticFile(StringRef ReproCrashFilename,
+                                    SmallString<128> &CrashDiagDir) {
+  using namespace llvm::sys;
+  assert(llvm::Triple(llvm::sys::getProcessTriple()).isOSDarwin() &&
+         "Only knows about .crash files on Darwin");
+
+  // The .crash file can be found on at ~/Library/Logs/DiagnosticReports/
+  // (or /Library/Logs/DiagnosticReports for root) and has the filename pattern
+  // clang-<VERSION>_<YYYY-MM-DD-HHMMSS>_<hostname>.crash.
+  path::home_directory(CrashDiagDir);
+  if (CrashDiagDir.startswith("/var/root"))
+    CrashDiagDir = "/";
+  path::append(CrashDiagDir, "Library/Logs/DiagnosticReports");
+  int PID =
+#if LLVM_ON_UNIX
+      getpid();
+#else
+      0;
+#endif
+  std::error_code EC;
+  fs::file_status FileStatus;
+  TimePoint<> LastAccessTime;
+  SmallString<128> CrashFilePath;
+  // Lookup the .crash files and get the one generated by a subprocess spawned
+  // by this driver invocation.
+  for (fs::directory_iterator File(CrashDiagDir, EC), FileEnd;
+       File != FileEnd && !EC; File.increment(EC)) {
+    StringRef FileName = path::filename(File->path());
+    if (!FileName.startswith(Name))
+      continue;
+    if (fs::status(File->path(), FileStatus))
+      continue;
+    llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> CrashFile =
+        llvm::MemoryBuffer::getFile(File->path());
+    if (!CrashFile)
+      continue;
+    // The first line should start with "Process:", otherwise this isn't a real
+    // .crash file.
+    StringRef Data = CrashFile.get()->getBuffer();
+    if (!Data.startswith("Process:"))
+      continue;
+    // Parse parent process pid line, e.g: "Parent Process: clang-4.0 [79141]"
+    size_t ParentProcPos = Data.find("Parent Process:");
+    if (ParentProcPos == StringRef::npos)
+      continue;
+    size_t LineEnd = Data.find_first_of("\n", ParentProcPos);
+    if (LineEnd == StringRef::npos)
+      continue;
+    StringRef ParentProcess = Data.slice(ParentProcPos+15, LineEnd).trim();
+    int OpenBracket = -1, CloseBracket = -1;
+    for (size_t i = 0, e = ParentProcess.size(); i < e; ++i) {
+      if (ParentProcess[i] == '[')
+        OpenBracket = i;
+      if (ParentProcess[i] == ']')
+        CloseBracket = i;
+    }
+    // Extract the parent process PID from the .crash file and check whether
+    // it matches this driver invocation pid.
+    int CrashPID;
+    if (OpenBracket < 0 || CloseBracket < 0 ||
+        ParentProcess.slice(OpenBracket + 1, CloseBracket)
+            .getAsInteger(10, CrashPID) || CrashPID != PID) {
+      continue;
+    }
+
+    // Found a .crash file matching the driver pid. To avoid getting an older
+    // and misleading crash file, continue looking for the most recent.
+    // FIXME: the driver can dispatch multiple cc1 invocations, leading to
+    // multiple crashes poiting to the same parent process. Since the driver
+    // does not collect pid information for the dispatched invocation there's
+    // currently no way to distinguish among them.
+    const auto FileAccessTime = FileStatus.getLastModificationTime();
+    if (FileAccessTime > LastAccessTime) {
+      CrashFilePath.assign(File->path());
+      LastAccessTime = FileAccessTime;
+    }
+  }
+
+  // If found, copy it over to the location of other reproducer files.
+  if (!CrashFilePath.empty()) {
+    EC = fs::copy_file(CrashFilePath, ReproCrashFilename);
+    if (EC)
+      return false;
+    return true;
+  }
+
+  return false;
+}
+
 // When clang crashes, produce diagnostic information including the fully
 // preprocessed source file(s).  Request that the developer attach the
 // diagnostic information to a bug report.
@@ -822,8 +914,13 @@ void Driver::generateCompilationDiagnost
          "Preprocessed source(s) and associated run script(s) are located at:";
 
   SmallString<128> VFS;
+  SmallString<128> ReproCrashFilename;
   for (const char *TempFile : TempFiles) {
     Diag(clang::diag::note_drv_command_failed_diag_msg) << TempFile;
+    if (ReproCrashFilename.empty()) {
+      ReproCrashFilename = TempFile;
+      llvm::sys::path::replace_extension(ReproCrashFilename, ".crash");
+    }
     if (StringRef(TempFile).endswith(".cache")) {
       // In some cases (modules) we'll dump extra data to help with reproducing
       // the crash into a directory next to the output.
@@ -851,6 +948,24 @@ void Driver::generateCompilationDiagnost
     Diag(clang::diag::note_drv_command_failed_diag_msg) << Script;
   }
 
+  // On darwin, provide information about the .crash diagnostic report.
+  if (llvm::Triple(llvm::sys::getProcessTriple()).isOSDarwin()) {
+    SmallString<128> CrashDiagDir;
+    if (getCrashDiagnosticFile(ReproCrashFilename, CrashDiagDir)) {
+      Diag(clang::diag::note_drv_command_failed_diag_msg)
+          << ReproCrashFilename.str();
+    } else { // Suggest a directory for the user to look for .crash files.
+      llvm::sys::path::append(CrashDiagDir, Name);
+      CrashDiagDir += "_<YYYY-MM-DD-HHMMSS>_<hostname>.crash";
+      Diag(clang::diag::note_drv_command_failed_diag_msg)
+          << "Crash backtrace is located in";
+      Diag(clang::diag::note_drv_command_failed_diag_msg)
+          << CrashDiagDir.str();
+      Diag(clang::diag::note_drv_command_failed_diag_msg)
+          << "(choose the .crash file that corresponds to your crash)";
+    }
+  }
+
   for (const auto &A : C.getArgs().filtered(options::OPT_frewrite_map_file,
                                             options::OPT_frewrite_map_file_EQ))
     Diag(clang::diag::note_drv_command_failed_diag_msg) << A->getValue();

Added: cfe/trunk/test/Driver/crash-report-crashfile.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Driver/crash-report-crashfile.m?rev=287262&view=auto
==============================================================================
--- cfe/trunk/test/Driver/crash-report-crashfile.m (added)
+++ cfe/trunk/test/Driver/crash-report-crashfile.m Thu Nov 17 15:41:22 2016
@@ -0,0 +1,17 @@
+// REQUIRES: crash-recovery, shell, system-darwin
+// RUN: rm -rf %t
+// RUN: mkdir -p %t/i %t/m %t
+
+// RUN: not env FORCE_CLANG_DIAGNOSTICS_CRASH= TMPDIR=%t TEMP=%t TMP=%t \
+// RUN: %clang -fsyntax-only %s -I %S/Inputs/module -isysroot %/t/i/    \
+// RUN: -fmodules -fmodules-cache-path=%t/m/ -DFOO=BAR 2>&1 | FileCheck %s
+
+ at import simple;
+const int x = MODULE_MACRO;
+
+// CHECK: Preprocessed source(s) and associated run script(s) are located at:
+// CHECK-NEXT: note: diagnostic msg: {{.*}}.m
+// CHECK-NEXT: note: diagnostic msg: {{.*}}.cache
+// CHECK-NEXT: note: diagnostic msg: {{.*}}.sh
+// CHECK-NEXT: note: diagnostic msg: Crash backtrace is located in
+// CHECK-NEXT: note: diagnostic msg: {{.*}}Library/Logs/DiagnosticReports{{.*}}




More information about the cfe-commits mailing list