Bug 1160142 - Updates for exception handler apis to allow the pairing of a passed in minidump. r=ted
authorJim Mathies <jmathies@mozilla.com>
Thu, 11 Jun 2015 12:25:45 -0500
changeset 248369 0413e4515c7df5bd89606ba2b7882d4c3a09ca12
parent 248368 ce6dbefadccd5264c887f965b01c5b8fb4d98c2d
child 248370 bcfa99bc90fa6046a46b0055086aa911d9e4179f
push id28893
push userkwierso@gmail.com
push dateFri, 12 Jun 2015 00:02:58 +0000
treeherderautoland@8cf9d3e497f9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersted
bugs1160142
milestone41.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1160142 - Updates for exception handler apis to allow the pairing of a passed in minidump. r=ted
toolkit/crashreporter/nsExceptionHandler.cpp
toolkit/crashreporter/nsExceptionHandler.h
--- a/toolkit/crashreporter/nsExceptionHandler.cpp
+++ b/toolkit/crashreporter/nsExceptionHandler.cpp
@@ -2409,29 +2409,45 @@ GetMinidumpLimboDir(nsIFile** dir)
 #else
     CreateFileFromPath(gExceptionHandler->minidump_descriptor().directory(),
                        dir);
 #endif
     return nullptr != *dir;
   }
 }
 
+void
+DeleteMinidumpFilesForID(const nsAString& id)
+{
+  nsCOMPtr<nsIFile> minidumpFile;
+  GetMinidumpForID(id, getter_AddRefs(minidumpFile));
+  bool exists = false;
+  if (minidumpFile && NS_SUCCEEDED(minidumpFile->Exists(&exists)) && exists) {
+    nsCOMPtr<nsIFile> childExtraFile;
+    GetExtraFileForMinidump(minidumpFile, getter_AddRefs(childExtraFile));
+    if (childExtraFile) {
+      childExtraFile->Remove(false);
+    }
+    minidumpFile->Remove(false);
+  }
+}
+
 bool
 GetMinidumpForID(const nsAString& id, nsIFile** minidump)
 {
   if (!GetMinidumpLimboDir(minidump))
     return false;
   (*minidump)->Append(id + NS_LITERAL_STRING(".dmp")); 
   return true;
 }
 
 bool
 GetIDFromMinidump(nsIFile* minidump, nsAString& id)
 {
-  if (NS_SUCCEEDED(minidump->GetLeafName(id))) {
+  if (minidump && NS_SUCCEEDED(minidump->GetLeafName(id))) {
     id.Replace(id.Length() - 4, 4, NS_LITERAL_STRING(""));
     return true;
   }
   return false;
 }
 
 bool
 GetExtraFileForID(const nsAString& id, nsIFile** extraFile)
@@ -3072,30 +3088,32 @@ TakeMinidumpForChild(uint32_t childPid, 
 }
 
 //-----------------------------------------------------------------------------
 // CreatePairedMinidumps() and helpers
 //
 
 void
 RenameAdditionalHangMinidump(nsIFile* minidump, nsIFile* childMinidump,
-                           const nsACString& name)
+                             const nsACString& name)
 {
   nsCOMPtr<nsIFile> directory;
   childMinidump->GetParent(getter_AddRefs(directory));
   if (!directory)
     return;
 
   nsAutoCString leafName;
   childMinidump->GetNativeLeafName(leafName);
 
   // turn "<id>.dmp" into "<id>-<name>.dmp
   leafName.Insert(NS_LITERAL_CSTRING("-") + name, leafName.Length() - 4);
 
-  minidump->MoveToNative(directory, leafName);
+  if (NS_FAILED(minidump->MoveToNative(directory, leafName))) {
+    NS_WARNING("RenameAdditionalHangMinidump failed to move minidump.");
+  }
 }
 
 static bool
 PairedDumpCallback(
 #ifdef XP_LINUX
                    const MinidumpDescriptor& descriptor,
 #else
                    const XP_CHAR* dump_path,
@@ -3194,76 +3212,109 @@ GetChildThread(ProcessHandle childPid, T
       == KERN_SUCCESS && childBlamedThread < thread_count) {
     childThread = threads_for_task[childBlamedThread];
   }
 
   return childThread;
 }
 #endif
 
-bool
-CreatePairedMinidumps(ProcessHandle childPid,
-                      ThreadId childBlamedThread,
-                      nsIFile** childDump)
+bool TakeMinidump(nsIFile** aResult, bool aMoveToPending)
 {
   if (!GetEnabled())
     return false;
 
+  xpstring dump_path;
+#ifndef XP_LINUX
+  dump_path = gExceptionHandler->dump_path();
+#else
+  dump_path = gExceptionHandler->minidump_descriptor().directory();
+#endif
+
+  // capture the dump
+  if (!google_breakpad::ExceptionHandler::WriteMinidump(
+         dump_path,
 #ifdef XP_MACOSX
-  mach_port_t childThread = GetChildThread(childPid, childBlamedThread);
+         true,
+#endif
+         PairedDumpCallback,
+         static_cast<void*>(aResult))) {
+    return false;
+  }
+
+  if (aMoveToPending) {
+    MoveToPending(*aResult, nullptr);
+  }
+  return true;
+}
+
+bool
+CreateMinidumpsAndPair(ProcessHandle aTargetPid,
+                       ThreadId aTargetBlamedThread,
+                       const nsACString& aIncomingPairName,
+                       nsIFile* aIncomingDumpToPair,
+                       nsIFile** aMainDumpOut)
+{
+  if (!GetEnabled()) {
+    return false;
+  }
+
+#ifdef XP_MACOSX
+  mach_port_t targetThread = GetChildThread(aTargetPid, aTargetBlamedThread);
 #else
-  ThreadId childThread = childBlamedThread;
+  ThreadId targetThread = aTargetBlamedThread;
 #endif
 
   xpstring dump_path;
 #ifndef XP_LINUX
   dump_path = gExceptionHandler->dump_path();
 #else
   dump_path = gExceptionHandler->minidump_descriptor().directory();
 #endif
 
-  // dump the child
-  nsCOMPtr<nsIFile> childMinidump;
+  // dump the target
+  nsCOMPtr<nsIFile> targetMinidump;
   if (!google_breakpad::ExceptionHandler::WriteMinidumpForChild(
-         childPid,
-         childThread,
+         aTargetPid,
+         targetThread,
          dump_path,
          PairedDumpCallbackExtra,
-         static_cast<void*>(&childMinidump)))
+         static_cast<void*>(&targetMinidump)))
     return false;
 
-  nsCOMPtr<nsIFile> childExtra;
-  GetExtraFileForMinidump(childMinidump, getter_AddRefs(childExtra));
-
-  // dump the parent
-  nsCOMPtr<nsIFile> parentMinidump;
-  if (!google_breakpad::ExceptionHandler::WriteMinidump(
-         dump_path,
+  nsCOMPtr<nsIFile> targetExtra;
+  GetExtraFileForMinidump(targetMinidump, getter_AddRefs(targetExtra));
+
+  // If aIncomingDumpToPair isn't valid, create a dump of this process.
+  nsCOMPtr<nsIFile> incomingDump;
+  if (aIncomingDumpToPair == nullptr) {
+    if (!google_breakpad::ExceptionHandler::WriteMinidump(
+        dump_path,
 #ifdef XP_MACOSX
-         true,                  // write exception stream
+        true,
 #endif
-         PairedDumpCallback,
-         static_cast<void*>(&parentMinidump))) {
-
-    childMinidump->Remove(false);
-    childExtra->Remove(false);
-
-    return false;
+        PairedDumpCallback,
+        static_cast<void*>(&incomingDump))) {
+
+      targetMinidump->Remove(false);
+      targetExtra->Remove(false);
+      return false;
+    }
+  } else {
+    incomingDump = aIncomingDumpToPair;
   }
-
-  // success
-  RenameAdditionalHangMinidump(parentMinidump, childMinidump,
-                               NS_LITERAL_CSTRING("browser"));
+  
+  RenameAdditionalHangMinidump(incomingDump, targetMinidump, aIncomingPairName);
 
   if (ShouldReport()) {
-    MoveToPending(childMinidump, childExtra);
-    MoveToPending(parentMinidump, nullptr);
+    MoveToPending(targetMinidump, targetExtra);
+    MoveToPending(incomingDump, nullptr);
   }
 
-  childMinidump.forget(childDump);
+  targetMinidump.forget(aMainDumpOut);
 
   return true;
 }
 
 bool
 CreateAdditionalChildMinidump(ProcessHandle childPid,
                               ThreadId childBlamedThread,
                               nsIFile* parentMinidump,
--- a/toolkit/crashreporter/nsExceptionHandler.h
+++ b/toolkit/crashreporter/nsExceptionHandler.h
@@ -82,24 +82,36 @@ bool GetLastRunCrashID(nsAString& id);
 
 // Registers an additional memory region to be included in the minidump
 nsresult RegisterAppMemory(void* ptr, size_t length);
 nsresult UnregisterAppMemory(void* ptr);
 
 // Functions for working with minidumps and .extras
 typedef nsDataHashtable<nsCStringHashKey, nsCString> AnnotationTable;
 
+void DeleteMinidumpFilesForID(const nsAString& id);
 bool GetMinidumpForID(const nsAString& id, nsIFile** minidump);
 bool GetIDFromMinidump(nsIFile* minidump, nsAString& id);
 bool GetExtraFileForID(const nsAString& id, nsIFile** extraFile);
 bool GetExtraFileForMinidump(nsIFile* minidump, nsIFile** extraFile);
 bool AppendExtraData(const nsAString& id, const AnnotationTable& data);
 bool AppendExtraData(nsIFile* extraFile, const AnnotationTable& data);
-void RenameAdditionalHangMinidump(nsIFile* minidump, nsIFile* childMinidump,
-                                  const nsACString& name);
+
+/*
+ * Renames the stand alone dump file aDumpFile to:
+ *  |aOwnerDumpFile-aDumpFileProcessType.dmp|
+ * and moves it into the same directory as aOwnerDumpFile. Does not
+ * modify aOwnerDumpFile in any way.
+ *
+ * @param aDumpFile - the dump file to associate with aOwnerDumpFile.
+ * @param aOwnerDumpFile - the new owner of aDumpFile.
+ * @param aDumpFileProcessType - process name associated with aDumpFile.
+ */
+void RenameAdditionalHangMinidump(nsIFile* aDumpFile, const nsIFile* aOwnerDumpFile,
+                                  const nsACString& aDumpFileProcessType);
 
 #ifdef XP_WIN32
   nsresult WriteMinidumpForException(EXCEPTION_POINTERS* aExceptionInfo);
 #endif
 #ifdef XP_LINUX
   bool WriteMinidumpForSigInfo(int signo, siginfo_t* info, void* uc);
 #endif
 #ifdef XP_MACOSX
@@ -111,16 +123,27 @@ nsresult SetSubmitReports(bool aSubmitRe
 // Out-of-process crash reporter API.
 
 // Initializes out-of-process crash reporting. This method must be called
 // before the platform-specific notification pipe APIs are called. If called
 // from off the main thread, this method will synchronously proxy to the main
 // thread.
 void OOPInit();
 
+/*
+ * Takes a minidump for the current process and returns the dump file.
+ * Callers are responsible for managing the resulting file.
+ *
+ * @param aResult - file pointer that holds the resulting minidump.
+ * @param aMoveToPending - if true move the report to the report
+ *   pending directory.
+ * @returns boolean indicating success or failure.
+ */
+bool TakeMinidump(nsIFile** aResult, bool aMoveToPending = false);
+
 // Return true if a dump was found for |childPid|, and return the
 // path in |dump|.  The caller owns the last reference to |dump| if it
 // is non-nullptr. The sequence parameter will be filled with an ordinal
 // indicating which remote process crashed first.
 bool TakeMinidumpForChild(uint32_t childPid,
                           nsIFile** dump,
                           uint32_t* aSequence = nullptr);
 
@@ -138,29 +161,41 @@ typedef int ThreadId;
 // Return the current thread's ID.
 //
 // XXX: this is a somewhat out-of-place interface to expose through
 // crashreporter, but it takes significant work to call sys_gettid()
 // correctly on Linux and breakpad has already jumped through those
 // hoops for us.
 ThreadId CurrentThreadId();
 
-// Create a crash report with two minidumps that are snapshots of the state
-// of this parent process and |childPid|. The "main" minidump will be the
-// child process, and this parent process will have the -browser extension.
-//
-// Returns true on success. If this function fails, it will attempt to delete
-// any files that were created.
-//
-// The .extra information created will not include an additional_minidumps
-// annotation: the caller should annotate additional_minidumps with
-// at least "browser" and perhaps other minidumps attached to this report.
-bool CreatePairedMinidumps(ProcessHandle childPid,
-                           ThreadId childBlamedThread,
-                           nsIFile** childDump);
+/*
+ * Take a minidump of the target process and pair it with an incoming minidump
+ * provided by the caller or a new minidump of the calling process and thread.
+ * The caller will own both dumps after this call. If this function fails
+ * it will attempt to delete any files that were created.
+ *
+ * The .extra information created will not include an 'additional_minidumps'
+ * annotation.
+ *
+ * @param aTargetPid The target process for the minidump.
+ * @param aTargetBlamedThread The target thread for the minidump.
+ * @param aIncomingPairName The name to apply to the paired dump the caller
+ *   passes in.
+ * @param aIncomingDumpToPair Existing dump to pair with the new dump. if this
+ *   is null, TakeMinidumpAndPair will take a new minidump of the calling
+ *   process and thread and use it in aIncomingDumpToPairs place.
+ * @param aTargetDumpOut The target minidump file paired up with
+ *   aIncomingDumpToPair.
+ * @return bool indicating success or failure
+ */
+bool CreateMinidumpsAndPair(ProcessHandle aTargetPid,
+                            ThreadId aTargetBlamedThread,
+                            const nsACString& aIncomingPairName,
+                            nsIFile* aIncomingDumpToPair,
+                            nsIFile** aTargetDumpOut);
 
 // Create an additional minidump for a child of a process which already has
 // a minidump (|parentMinidump|).
 // The resulting dump will get the id of the parent and use the |name| as
 // an extension.
 bool CreateAdditionalChildMinidump(ProcessHandle childPid,
                                    ThreadId childBlamedThread,
                                    nsIFile* parentMinidump,