Bug 581341 - Part 1: Make crash report annotation work OOP and subsume existing workarounds. r=cjones
authorJosh Matthews <josh@joshmatthews.net>
Wed, 08 Jun 2011 15:56:31 -0400
changeset 77923 942a7f001562701f2472fcbe5bebc0408f2de33a
parent 77922 3f3b6a106ed8766b0ca4e6836ede1f4e54e62bd1
child 77924 47da01006e3dd38cf4ef3361927760267df6e3ec
push id21257
push usermak77@bonardo.net
push dateSat, 01 Oct 2011 09:11:07 +0000
treeherdermozilla-central@164fd1bbd06f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscjones
bugs581341
milestone10.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 581341 - Part 1: Make crash report annotation work OOP and subsume existing workarounds. r=cjones
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/CrashReporterChild.cpp
dom/ipc/CrashReporterChild.h
dom/ipc/CrashReporterParent.cpp
dom/ipc/CrashReporterParent.h
dom/ipc/Makefile.in
dom/ipc/PContent.ipdl
dom/ipc/PCrashReporter.ipdl
dom/ipc/TabMessageUtils.h
dom/plugins/ipc/PPluginModule.ipdl
dom/plugins/ipc/PluginMessageUtils.h
dom/plugins/ipc/PluginModuleChild.cpp
dom/plugins/ipc/PluginModuleChild.h
dom/plugins/ipc/PluginModuleParent.cpp
dom/plugins/ipc/PluginModuleParent.h
dom/plugins/ipc/PluginProcessChild.cpp
dom/plugins/ipc/PluginProcessChild.h
toolkit/xre/nsX11ErrorHandler.cpp
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -260,30 +260,35 @@ ContentChild::Init(MessageLoop* aIOLoop,
     XRE_InstallX11ErrorHandler();
 #endif
 
     NS_ASSERTION(!sSingleton, "only one ContentChild per child");
 
     Open(aChannel, aParentHandle, aIOLoop);
     sSingleton = this;
 
-#if defined(ANDROID) && defined(MOZ_CRASHREPORTER)
-    PCrashReporterChild* crashreporter = SendPCrashReporterConstructor();
+#ifdef MOZ_CRASHREPORTER
+    SendPCrashReporterConstructor(CrashReporter::CurrentThreadId(),
+                                  XRE_GetProcessType());
+#if defined(ANDROID)
+    PCrashReporterChild* crashreporter = ManagedPCrashReporter()[0];
+
     InfallibleTArray<Mapping> mappings;
     const struct mapping_info *info = getLibraryMapping();
     while (info && info->name) {
         mappings.AppendElement(Mapping(nsDependentCString(info->name),
                                        nsDependentCString(info->file_id),
                                        info->base,
                                        info->len,
                                        info->offset));
         info++;
     }
     crashreporter->SendAddLibraryMappings(mappings);
 #endif
+#endif
 
     return true;
 }
 
 void
 ContentChild::InitXPCOM()
 {
     nsCOMPtr<nsIConsoleService> svc(do_GetService(NS_CONSOLESERVICE_CONTRACTID));
@@ -413,19 +418,24 @@ bool
 ContentChild::DeallocPBrowser(PBrowserChild* iframe)
 {
     TabChild* child = static_cast<TabChild*>(iframe);
     NS_RELEASE(child);
     return true;
 }
 
 PCrashReporterChild*
-ContentChild::AllocPCrashReporter()
+ContentChild::AllocPCrashReporter(const mozilla::dom::NativeThreadId& id,
+                                  const PRUint32& processType)
 {
+#ifdef MOZ_CRASHREPORTER
     return new CrashReporterChild();
+#else
+    return nsnull;
+#endif
 }
 
 bool
 ContentChild::DeallocPCrashReporter(PCrashReporterChild* crashreporter)
 {
     delete crashreporter;
     return true;
 }
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -75,18 +75,21 @@ public:
     }
 
     /* if you remove this, please talk to cjones or dougt */
     virtual bool RecvDummy(Shmem& foo) { return true; }
 
     virtual PBrowserChild* AllocPBrowser(const PRUint32& aChromeFlags);
     virtual bool DeallocPBrowser(PBrowserChild*);
 
-    virtual PCrashReporterChild* AllocPCrashReporter();
-    virtual bool DeallocPCrashReporter(PCrashReporterChild*);
+    virtual PCrashReporterChild*
+    AllocPCrashReporter(const mozilla::dom::NativeThreadId& id,
+                        const PRUint32& processType);
+    virtual bool
+    DeallocPCrashReporter(PCrashReporterChild*);
 
     virtual PMemoryReportRequestChild*
     AllocPMemoryReportRequest();
 
     virtual bool
     DeallocPMemoryReportRequest(PMemoryReportRequestChild* actor);
 
     virtual bool
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -350,37 +350,24 @@ ContentParent::ActorDestroy(ActorDestroy
     if (obs) {
         nsRefPtr<nsHashPropertyBag> props = new nsHashPropertyBag();
         props->Init();
 
         if (AbnormalShutdown == why) {
             props->SetPropertyAsBool(NS_LITERAL_STRING("abnormal"), PR_TRUE);
 
 #ifdef MOZ_CRASHREPORTER
-            nsAutoString dumpID;
-
-            nsCOMPtr<nsILocalFile> crashDump;
-            TakeMinidump(getter_AddRefs(crashDump)) &&
-                CrashReporter::GetIDFromMinidump(crashDump, dumpID);
-
-            props->SetPropertyAsAString(NS_LITERAL_STRING("dumpID"), dumpID);
+            MOZ_ASSERT(ManagedPCrashReporterParent().Length() > 0);
+            CrashReporterParent* crashReporter =
+                    static_cast<CrashReporterParent*>(ManagedPCrashReporterParent()[0]);
 
-            if (!dumpID.IsEmpty()) {
-                CrashReporter::AnnotationTable notes;
-                notes.Init();
-                notes.Put(NS_LITERAL_CSTRING("ProcessType"), NS_LITERAL_CSTRING("content"));
-
-                char startTime[32];
-                sprintf(startTime, "%lld", static_cast<long long>(mProcessStartTime));
-                notes.Put(NS_LITERAL_CSTRING("StartupTime"),
-                          nsDependentCString(startTime));
-
-                // TODO: Additional per-process annotations.
-                CrashReporter::AppendExtraData(dumpID, notes);
-            }
+            crashReporter->GenerateCrashReport(this, NULL);
+ 
+            nsAutoString dumpID(crashReporter->ChildDumpID());
+            props->SetPropertyAsAString(NS_LITERAL_STRING("dumpID"), dumpID);
 #endif
 
             obs->NotifyObservers((nsIPropertyBag2*) props, "ipc:content-shutdown", nsnull);
         }
     }
 
     MessageLoop::current()->
         PostTask(FROM_HERE,
@@ -415,17 +402,16 @@ ContentParent::DestroyTestShell(TestShel
     return PTestShellParent::Send__delete__(aTestShell);
 }
 
 ContentParent::ContentParent()
     : mGeolocationWatchID(-1)
     , mRunToCompletionDepth(0)
     , mShouldCallUnblockChild(false)
     , mIsAlive(true)
-    , mProcessStartTime(time(NULL))
     , mSendPermissionUpdates(false)
 {
     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     mSubprocess = new GeckoChildProcessHost(GeckoProcessType_Content);
     mSubprocess->AsyncLaunch();
     Open(mSubprocess->GetChannel(), mSubprocess->GetChildProcessHandle());
 
     nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
@@ -786,19 +772,33 @@ bool
 ContentParent::DeallocPBrowser(PBrowserParent* frame)
 {
   TabParent* parent = static_cast<TabParent*>(frame);
   NS_RELEASE(parent);
   return true;
 }
 
 PCrashReporterParent*
-ContentParent::AllocPCrashReporter()
+ContentParent::AllocPCrashReporter(const NativeThreadId& tid,
+                                   const PRUint32& processType)
 {
+#ifdef MOZ_CRASHREPORTER
   return new CrashReporterParent();
+#else
+  return nsnull;
+#endif
+}
+
+bool
+ContentParent::RecvPCrashReporterConstructor(PCrashReporterParent* actor,
+                                             const NativeThreadId& tid,
+                                             const PRUint32& processType)
+{
+  static_cast<CrashReporterParent*>(actor)->SetChildData(tid, processType);
+  return true;
 }
 
 bool
 ContentParent::DeallocPCrashReporter(PCrashReporterParent* crashreporter)
 {
   delete crashreporter;
   return true;
 }
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -94,16 +94,20 @@ public:
 
     void ReportChildAlreadyBlocked();
     bool RequestRunToCompletion();
 
     bool IsAlive();
 
     void SetChildMemoryReporters(const InfallibleTArray<MemoryReport>& report);
 
+    GeckoChildProcessHost* Process() {
+        return mSubprocess;
+    }
+
     bool NeedsPermissionsUpdate() {
         return mSendPermissionUpdates;
     }
 
 protected:
     void OnChannelConnected(int32 pid);
     virtual void ActorDestroy(ActorDestroyReason why);
 
@@ -118,18 +122,22 @@ private:
     ContentParent();
     virtual ~ContentParent();
 
     void Init();
 
     virtual PBrowserParent* AllocPBrowser(const PRUint32& aChromeFlags);
     virtual bool DeallocPBrowser(PBrowserParent* frame);
 
-    virtual PCrashReporterParent* AllocPCrashReporter();
+    virtual PCrashReporterParent* AllocPCrashReporter(const NativeThreadId& tid,
+                                                      const PRUint32& processType);
     virtual bool DeallocPCrashReporter(PCrashReporterParent* crashreporter);
+    virtual bool RecvPCrashReporterConstructor(PCrashReporterParent* actor,
+                                               const NativeThreadId& tid,
+                                               const PRUint32& processType);
 
     virtual PMemoryReportRequestParent* AllocPMemoryReportRequest();
     virtual bool DeallocPMemoryReportRequest(PMemoryReportRequestParent* actor);
 
     virtual PTestShellParent* AllocPTestShell();
     virtual bool DeallocPTestShell(PTestShellParent* shell);
 
     virtual PAudioParent* AllocPAudio(const PRInt32&,
@@ -225,19 +233,20 @@ private:
     // This is a cache of all of the memory reporters
     // registered in the child process.  To update this, one
     // can broadcast the topic "child-memory-reporter-request" using
     // the nsIObserverService.
     nsCOMArray<nsIMemoryReporter> mMemoryReporters;
 
     bool mIsAlive;
     nsCOMPtr<nsIPrefServiceInternal> mPrefService;
-    time_t mProcessStartTime;
 
     bool mSendPermissionUpdates;
 
     nsRefPtr<nsFrameMessageManager> mMessageManager;
+
+    friend class CrashReporterParent;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
new file mode 100644
--- /dev/null
+++ b/dom/ipc/CrashReporterChild.cpp
@@ -0,0 +1,75 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * vim: set sw=4 ts=8 et tw=80 : 
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Crash Reporter.
+ *
+ * The Initial Developer of the Original Code is
+ *   The Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Josh Matthews <josh@joshmatthews.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+#include "mozilla/plugins/PluginModuleChild.h"
+#include "ContentChild.h"
+#include "CrashReporterChild.h"
+#include "nsXULAppAPI.h"
+
+using mozilla::plugins::PluginModuleChild;
+
+namespace mozilla {
+namespace dom {
+
+/*static*/
+PCrashReporterChild*
+CrashReporterChild::GetCrashReporter()
+{
+  const InfallibleTArray<PCrashReporterChild*>* reporters = nsnull;
+  switch (XRE_GetProcessType()) {
+    case GeckoProcessType_Content: {
+      ContentChild* child = ContentChild::GetSingleton();
+      reporters = &child->ManagedPCrashReporterChild();
+      break;
+    }
+    case GeckoProcessType_Plugin: {
+      PluginModuleChild* child = PluginModuleChild::current();
+      reporters = &child->ManagedPCrashReporterChild();
+      break;
+    }
+    default:
+      break;
+  }
+  if (reporters && reporters->Length() > 0) {
+    return reporters->ElementAt(0);
+  }
+  return nsnull;
+}
+
+}
+}
--- a/dom/ipc/CrashReporterChild.h
+++ b/dom/ipc/CrashReporterChild.h
@@ -31,25 +31,38 @@
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
+
+#ifndef mozilla_dom_CrashReporterChild_h
+#define mozilla_dom_CrashReporterChild_h
+
 #include "mozilla/dom/PCrashReporterChild.h"
+#ifdef MOZ_CRASHREPORTER
+#include "nsExceptionHandler.h"
+#include "nsXULAppAPI.h"
+#endif
 
 namespace mozilla {
 namespace dom {
 class CrashReporterChild :
     public PCrashReporterChild
 {
  public:
     CrashReporterChild() {
-      MOZ_COUNT_CTOR(CrashReporterChild);
+        MOZ_COUNT_CTOR(CrashReporterChild);
+    }
+    ~CrashReporterChild() {
+        MOZ_COUNT_DTOR(CrashReporterChild);
     }
-    virtual ~CrashReporterChild() {
-      MOZ_COUNT_DTOR(CrashReporterChild);
-    }
+
+    static PCrashReporterChild* GetCrashReporter();
 };
+
 } // namespace dom
 } // namespace mozilla
+
+#endif // mozilla_dom_CrashReporterChild_h
--- a/dom/ipc/CrashReporterParent.cpp
+++ b/dom/ipc/CrashReporterParent.cpp
@@ -32,22 +32,21 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 #include "CrashReporterParent.h"
-#if defined(MOZ_CRASHREPORTER)
-#include "nsExceptionHandler.h"
-#endif
 
 #include "base/process_util.h"
 
+#include <time.h>
+
 using namespace base;
 
 namespace mozilla {
 namespace dom {
 
 void
 CrashReporterParent::ActorDestroy(ActorDestroyReason why)
 {
@@ -68,20 +67,105 @@ CrashReporterParent::RecvAddLibraryMappi
                                              m.start_address(),
                                              m.mapping_length(),
                                              m.file_offset());
   }
 #endif
   return true;
 }
 
+bool
+CrashReporterParent::RecvAnnotateCrashReport(const nsCString& key,
+                                             const nsCString& data)
+{
+#ifdef MOZ_CRASHREPORTER
+    mNotes.Put(key, data);
+#endif
+    return true;
+}
+
+bool
+CrashReporterParent::RecvAppendAppNotes(const nsCString& data)
+{
+    mAppNotes.Append(data);
+    return true;
+}
+
 CrashReporterParent::CrashReporterParent()
+: mStartTime(time(NULL))
+, mInitialized(false)
 {
     MOZ_COUNT_CTOR(CrashReporterParent);
+
+#ifdef MOZ_CRASHREPORTER
+    mNotes.Init(4);
+#endif
 }
 
 CrashReporterParent::~CrashReporterParent()
 {
     MOZ_COUNT_DTOR(CrashReporterParent);
 }
 
+void
+CrashReporterParent::SetChildData(const NativeThreadId& tid,
+                                  const PRUint32& processType)
+{
+    mInitialized = true;
+    mMainThread = tid;
+    mProcessType = processType;
+}
+
+#ifdef MOZ_CRASHREPORTER
+bool
+CrashReporterParent::GenerateHangCrashReport(const AnnotationTable* processNotes)
+{
+    if (mChildDumpID.IsEmpty())
+        return false;
+
+    GenerateChildData(processNotes);
+
+    CrashReporter::AnnotationTable notes;
+    if (!notes.Init(4))
+        return false;
+    notes.Put(nsDependentCString("HangID"), NS_ConvertUTF16toUTF8(mHangID));
+    if (!CrashReporter::AppendExtraData(mParentDumpID, notes))
+        NS_WARNING("problem appending parent data to .extra");
+    return true;
+}
+
+bool
+CrashReporterParent::GenerateChildData(const AnnotationTable* processNotes)
+{
+    MOZ_ASSERT(mInitialized);
+
+    nsCAutoString type;
+    switch (mProcessType) {
+        case GeckoProcessType_Content:
+            type = NS_LITERAL_CSTRING("content");
+            break;
+        case GeckoProcessType_Plugin:
+            type = NS_LITERAL_CSTRING("plugin");
+            break;
+        default:
+            NS_ERROR("unknown process type");
+            break;
+    }
+    mNotes.Put(NS_LITERAL_CSTRING("ProcessType"), type);
+
+    char startTime[32];
+    sprintf(startTime, "%lld", static_cast<PRInt64>(mStartTime));
+    mNotes.Put(NS_LITERAL_CSTRING("StartupTime"), nsDependentCString(startTime));
+
+    if (!mAppNotes.IsEmpty())
+        mNotes.Put(NS_LITERAL_CSTRING("Notes"), mAppNotes);
+
+    bool ret = CrashReporter::AppendExtraData(mChildDumpID, mNotes);
+    if (ret && processNotes)
+        ret = CrashReporter::AppendExtraData(mChildDumpID, *processNotes);
+    if (!ret)
+        NS_WARNING("problem appending child data to .extra");
+    return ret;
+}
+#endif
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/ipc/CrashReporterParent.h
+++ b/dom/ipc/CrashReporterParent.h
@@ -1,9 +1,9 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * vim: set sw=4 ts=8 et tw=80 : 
  * ***** BEGIN LICENSE BLOCK *****
  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
  * the License. You may obtain a copy of the License at
  * http://www.mozilla.org/MPL/
@@ -32,26 +32,167 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 #include "mozilla/dom/PCrashReporterParent.h"
+#include "mozilla/dom/TabMessageUtils.h"
+#include "nsXULAppAPI.h"
+#include "nsILocalFile.h"
+#ifdef MOZ_CRASHREPORTER
+#include "nsExceptionHandler.h"
+#endif
 
 namespace mozilla {
 namespace dom {
+class ProcessReporter;
+
 class CrashReporterParent :
     public PCrashReporterParent
 {
+#ifdef MOZ_CRASHREPORTER
+  typedef CrashReporter::AnnotationTable AnnotationTable;
+#endif
 public:
-    CrashReporterParent();
-    virtual ~CrashReporterParent();
+  CrashReporterParent();
+  virtual ~CrashReporterParent();
+
+#ifdef MOZ_CRASHREPORTER
+  /* Attempt to generate a parent/child pair of minidumps from the given
+     toplevel actor in the event of a hang. Returns true if successful,
+     false otherwise.
+  */
+  template<class Toplevel>
+  bool
+  GeneratePairedMinidump(Toplevel* t);
+
+  /* Attempt to create a bare-bones crash report for a hang, along with extra
+     process-specific annotations present in the given AnnotationTable. Returns
+     true if successful, false otherwise.
+  */
+  bool
+  GenerateHangCrashReport(const AnnotationTable* processNotes);
+
+  /* Attempt to create a bare-bones crash report, along with extra process-
+     specific annotations present in the given AnnotationTable. Returns true if
+     successful, false otherwise.
+  */
+  template<class Toplevel>
+  bool
+  GenerateCrashReport(Toplevel* t, const AnnotationTable* processNotes);
+
+  /* Instantiate a new crash reporter actor from a given parent that manages
+     the protocol.
+  */
+  template<class Toplevel>
+  static void CreateCrashReporter(Toplevel* actor);
+#endif
+  /* Initialize this reporter with data from the child process */
+  void
+    SetChildData(const NativeThreadId& id, const PRUint32& processType);
+
+  /* Returns the shared hang ID of a parent/child paired minidump.
+     GeneratePairedMinidump must be called first.
+  */
+  const nsString& HangID() {
+    return mHangID;
+  }
+  /* Returns the ID of the parent minidump.
+     GeneratePairedMinidump must be called first.
+  */
+  const nsString& ParentDumpID() {
+    return mParentDumpID;
+  }
+  /* Returns the ID of the child minidump.
+     GeneratePairedMinidump or GenerateCrashReport must be called first.
+  */
+  const nsString& ChildDumpID() {
+    return mChildDumpID;
+  }
 
  protected:
   virtual void ActorDestroy(ActorDestroyReason why);
 
   virtual bool
     RecvAddLibraryMappings(const InfallibleTArray<Mapping>& m);
+  virtual bool
+    RecvAnnotateCrashReport(const nsCString& key, const nsCString& data);
+  virtual bool
+    RecvAppendAppNotes(const nsCString& data);
+
+#ifdef MOZ_CRASHREPORTER
+  bool
+  GenerateChildData(const AnnotationTable* processNotes);
+
+  AnnotationTable mNotes;
+#endif
+  nsCString mAppNotes;
+  nsString mHangID;
+  nsString mChildDumpID;
+  nsString mParentDumpID;
+  NativeThreadId mMainThread;
+  time_t mStartTime;
+  PRUint32 mProcessType;
+  bool mInitialized;
 };
+
+#ifdef MOZ_CRASHREPORTER
+template<class Toplevel>
+inline bool
+CrashReporterParent::GeneratePairedMinidump(Toplevel* t)
+{
+  CrashReporter::ProcessHandle child;
+#ifdef XP_MACOSX
+  child = t->Process()->GetChildTask();
+#else
+  child = t->OtherProcess();
+#endif
+  nsCOMPtr<nsILocalFile> childDump;
+  nsCOMPtr<nsILocalFile> parentDump;
+  if (CrashReporter::CreatePairedMinidumps(child,
+                                           mMainThread,
+                                           &mHangID,
+                                           getter_AddRefs(childDump),
+                                           getter_AddRefs(parentDump)) &&
+      CrashReporter::GetIDFromMinidump(childDump, mChildDumpID) &&
+      CrashReporter::GetIDFromMinidump(parentDump, mParentDumpID)) {
+    return true;
+  }
+  return false;
+}
+
+template<class Toplevel>
+inline bool
+CrashReporterParent::GenerateCrashReport(Toplevel* t,
+                                         const AnnotationTable* processNotes)
+{
+  nsCOMPtr<nsILocalFile> crashDump;
+  if (t->TakeMinidump(getter_AddRefs(crashDump)) &&
+      CrashReporter::GetIDFromMinidump(crashDump, mChildDumpID)) {
+    return GenerateChildData(processNotes);
+  }
+  return false;
+}
+
+template<class Toplevel>
+/* static */ void
+CrashReporterParent::CreateCrashReporter(Toplevel* actor)
+{
+#ifdef MOZ_CRASHREPORTER
+  NativeThreadId id;
+  PRUint32 processType;
+  PCrashReporterParent* p =
+      actor->CallPCrashReporterConstructor(&id, &processType);
+  if (p) {
+    static_cast<CrashReporterParent*>(p)->SetChildData(id, processType);
+  } else {
+    NS_ERROR("Error creating crash reporter actor");
+  }
+#endif
+}
+
+#endif
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/ipc/Makefile.in
+++ b/dom/ipc/Makefile.in
@@ -60,40 +60,41 @@ EXPORTS_NAMESPACES = mozilla/dom
 EXPORTS_mozilla/dom = \
   ContentChild.h \
   ContentParent.h \
   ContentProcess.h \
   CrashReporterChild.h \
   CrashReporterParent.h \
   TabParent.h \
   TabChild.h \
+  TabMessageUtils.h \
   $(NULL)
 
 CPPSRCS = \
   ContentProcess.cpp \
   ContentParent.cpp \
   ContentChild.cpp \
   CrashReporterParent.cpp \
+  CrashReporterChild.cpp \
   TabParent.cpp \
   TabChild.cpp \
   TabMessageUtils.cpp \
   $(NULL)
 
 ifdef MOZ_SYDNEYAUDIO
 EXPORTS_mozilla/dom += \
   AudioChild.h \
   AudioParent.h \
   $(NULL)
 CPPSRCS += \
   AudioChild.cpp \
   AudioParent.cpp \
   $(NULL)
 endif
 
-
 include $(topsrcdir)/config/config.mk
 include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 LOCAL_INCLUDES += \
 	-I$(srcdir)/../../content/base/src \
 	-I$(srcdir)/../../content/events/src \
 	-I$(srcdir)/../../toolkit/components/places \
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -42,29 +42,31 @@ include protocol PCrashReporter;
 include protocol PTestShell;
 include protocol PNecko;
 include protocol PExternalHelperApp;
 include protocol PStorage;
 include protocol PMemoryReportRequest;
 
 include "mozilla/chrome/RegistryMessageUtils.h";
 include "mozilla/net/NeckoMessageUtils.h";
+include "mozilla/dom/TabMessageUtils.h";
 
 include "nsGeoPositionIPCSerialiser.h";
 include "PPrefTuple.h";
 
 using GeoPosition;
 using PrefTuple;
 
 using ChromePackage;
 using ResourceMapping;
 using OverrideMapping;
 using IPC::URI;
 using IPC::Permission;
 using mozilla::null_t;
+using mozilla::dom::NativeThreadId;
 using gfxIntSize;
 
 namespace mozilla {
 namespace dom {
 
 // Data required to clone an existing DOMStorageImpl in the parent
 struct StorageClone
 {
@@ -138,22 +140,23 @@ child:
     
     /**
      * Start accessibility engine in content process.
      */
     ActivateA11y();
 
 parent:
     PNecko();
-    PCrashReporter();
     
     PStorage(StorageConstructData data);
 
     PAudio(PRInt32 aNumChannels, PRInt32 aRate, PRInt32 aFormat);
 
+    sync PCrashReporter(NativeThreadId tid, PRUint32 processType);
+
     // Services remoting
 
     async StartVisitedQuery(URI uri);
     async VisitURI(URI uri, URI referrer, PRUint32 flags);
     async SetURITitle(URI uri, nsString title);
     
     // filepicker remoting
     sync ShowFilePicker(PRInt16 mode, PRInt16 selectedType, bool addToRecentDocs,
--- a/dom/ipc/PCrashReporter.ipdl
+++ b/dom/ipc/PCrashReporter.ipdl
@@ -33,29 +33,32 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 include protocol PContent;
+include protocol PPluginModule;
 
 namespace mozilla {
 namespace dom {
 
 struct Mapping {
   nsCString library_name;
   nsCString file_id;
   uintptr_t start_address;
   size_t mapping_length;
   size_t file_offset;
 };
 
 protocol PCrashReporter {
-  manager PContent;
+  manager PContent or PPluginModule;
 parent:
   AddLibraryMappings(Mapping[] m);
+  AnnotateCrashReport(nsCString key, nsCString data);
+  AppendAppNotes(nsCString data);
   __delete__();
 };
 
 }
-}
\ No newline at end of file
+}
--- a/dom/ipc/TabMessageUtils.h
+++ b/dom/ipc/TabMessageUtils.h
@@ -38,26 +38,37 @@
 
 #ifndef TABMESSAGE_UTILS_H
 #define TABMESSAGE_UTILS_H
 
 #include "IPC/IPCMessageUtils.h"
 #include "nsIPrivateDOMEvent.h"
 #include "nsCOMPtr.h"
 
+#ifdef MOZ_CRASHREPORTER
+#include "nsExceptionHandler.h"
+#endif
+
 namespace mozilla {
 namespace dom {
 struct RemoteDOMEvent
 {
   nsCOMPtr<nsIPrivateDOMEvent> mEvent;
 };
 
 bool ReadRemoteEvent(const IPC::Message* aMsg, void** aIter,
                      mozilla::dom::RemoteDOMEvent* aResult);
 
+#ifdef MOZ_CRASHREPORTER
+typedef CrashReporter::ThreadId NativeThreadId;
+#else
+// unused in this case
+typedef int32 NativeThreadId;
+#endif
+
 }
 }
 
 namespace IPC {
 
 template<>
 struct ParamTraits<mozilla::dom::RemoteDOMEvent>
 {
@@ -73,13 +84,12 @@ struct ParamTraits<mozilla::dom::RemoteD
     return mozilla::dom::ReadRemoteEvent(aMsg, aIter, aResult);
   }
 
   static void Log(const paramType& aParam, std::wstring* aLog)
   {
   }
 };
 
-
 }
 
 
 #endif
--- a/dom/plugins/ipc/PPluginModule.ipdl
+++ b/dom/plugins/ipc/PPluginModule.ipdl
@@ -35,34 +35,37 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 include protocol PPluginIdentifier;
 include protocol PPluginInstance;
 include protocol PPluginScriptableObject;
+include protocol PCrashReporter;
 
 include "npapi.h";
 include "mozilla/plugins/PluginMessageUtils.h";
+include "mozilla/dom/TabMessageUtils.h";
 
 using NPError;
 using NPNVariable;
 using base::FileDescriptor;
-using mozilla::plugins::NativeThreadId;
+using mozilla::dom::NativeThreadId;
 using mac_plugin_interposing::NSCursorInfo;
 using nsID;
 
 namespace mozilla {
 namespace plugins {
 
 rpc protocol PPluginModule
 {
   manages PPluginInstance;
   manages PPluginIdentifier;
+  manages PCrashReporter;
 
 both:
   /**
    * Sending a void string to this constructor creates an int identifier whereas
    * sending a non-void string will create a string identifier. This constructor
    * may be called by either child or parent. If a race occurs by calling the
    * constructor with the same string or int argument then we create two actors
    * and detect the second instance in the child. We prevent the parent's actor
@@ -79,19 +82,18 @@ both:
   // a nested event loop for the current RPC call.
   async ProcessNativeEventsInRPCCall();
 
 child:
   // Forces the child process to update its plugin function table.
   rpc NP_GetEntryPoints()
     returns (NPError rv);
 
-  // Return the plugin's thread ID, if it can be found.
   rpc NP_Initialize()
-    returns (NativeThreadId tid, NPError rv);
+    returns (NPError rv);
 
   rpc PPluginInstance(nsCString aMimeType,
                       uint16_t aMode,
                       nsCString[] aNames,
                       nsCString[] aValues)
     returns (NPError rv);
 
   rpc NP_Shutdown()
@@ -109,16 +111,19 @@ child:
 
   // Windows specific message to set up an audio session in the plugin process
   async SetAudioSessionData(nsID aID,
                             nsString aDisplayName,
                             nsString aIconPath);
 
   async SetParentHangTimeout(uint32_t seconds);
 
+  rpc PCrashReporter()
+    returns (NativeThreadId tid, PRUint32 processType);
+
 parent:
   /**
    * This message is only used on X11 platforms.
    *
    * Send a dup of the plugin process's X socket to the parent
    * process.  In theory, this scheme keeps the plugin's X resources
    * around until after both the plugin process shuts down *and* the
    * parent process closes the dup fd.  This is used to prevent the
@@ -136,18 +141,16 @@ parent:
              bool aBoolVal);
 
   // Wake up and process a few native events.  Periodically called by
   // Gtk-specific code upon detecting that the plugin process has
   // entered a nested event loop.  If the browser doesn't process
   // native events, then "livelock" and some other glitches can occur.
   rpc ProcessSomeEvents();
 
-  sync AppendNotesToCrashReport(nsCString aNotes);
-
   // OS X Specific calls to manage the plugin's window
   // when interposing system calls.
   async PluginShowWindow(uint32_t aWindowId, bool aModal,
                          int32_t aX, int32_t aY,
                          size_t aWidth, size_t aHeight);
   async PluginHideWindow(uint32_t aWindowId);
 
   // OS X Specific calls to allow the plugin to manage the cursor.
--- a/dom/plugins/ipc/PluginMessageUtils.h
+++ b/dom/plugins/ipc/PluginMessageUtils.h
@@ -137,23 +137,16 @@ typedef intptr_t NativeWindowHandle; // 
 #endif
 
 #ifdef XP_WIN
 typedef base::SharedMemoryHandle WindowsSharedMemoryHandle;
 #else
 typedef mozilla::null_t WindowsSharedMemoryHandle;
 #endif
 
-#ifdef MOZ_CRASHREPORTER
-typedef CrashReporter::ThreadId NativeThreadId;
-#else
-// unused in this case
-typedef int32 NativeThreadId;
-#endif
-
 // XXX maybe not the best place for these. better one?
 
 #define VARSTR(v_)  case v_: return #v_
 inline const char* const
 NPPVariableToString(NPPVariable aVar)
 {
     switch (aVar) {
         VARSTR(NPPVpluginNameString);
--- a/dom/plugins/ipc/PluginModuleChild.cpp
+++ b/dom/plugins/ipc/PluginModuleChild.cpp
@@ -61,31 +61,34 @@
 #ifdef MOZ_X11
 # include "mozilla/X11Util.h"
 #endif
 #include "mozilla/plugins/PluginInstanceChild.h"
 #include "mozilla/plugins/StreamNotifyChild.h"
 #include "mozilla/plugins/BrowserStreamChild.h"
 #include "mozilla/plugins/PluginStreamChild.h"
 #include "PluginIdentifierChild.h"
+#include "mozilla/dom/CrashReporterChild.h"
 
 #include "nsNPAPIPlugin.h"
 
 #ifdef XP_WIN
 #include "COMMessageFilter.h"
 #include "nsWindowsDllInterceptor.h"
 #include "mozilla/widget/AudioSession.h"
 #endif
 
 #ifdef MOZ_WIDGET_COCOA
 #include "PluginInterposeOSX.h"
 #include "PluginUtilsOSX.h"
 #endif
 
 using namespace mozilla::plugins;
+using mozilla::dom::CrashReporterChild;
+using mozilla::dom::PCrashReporterChild;
 
 #if defined(XP_WIN)
 const PRUnichar * kFlashFullscreenClass = L"ShockwaveFlashFullScreen";
 const PRUnichar * kMozillaWindowClass = L"MozillaWindowClass";
 #endif
 
 namespace {
 PluginModuleChild* gInstance = nsnull;
@@ -587,17 +590,16 @@ PluginModuleChild::InitGraphics()
     }
 #else
     // may not be necessary on all platforms
 #endif
 #ifdef MOZ_X11
     // Do this after initializing GDK, or GDK will install its own handler.
     XRE_InstallX11ErrorHandler();
 #endif
-
     return true;
 }
 
 void
 PluginModuleChild::DeinitGraphics()
 {
 #ifdef MOZ_WIDGET_QT
     nsQAppInstance::Release();
@@ -700,16 +702,43 @@ PluginModuleChild::RecvSetAudioSessionDa
 
 void
 PluginModuleChild::QuickExit()
 {
     NS_WARNING("plugin process _exit()ing");
     _exit(0);
 }
 
+PCrashReporterChild*
+PluginModuleChild::AllocPCrashReporter(mozilla::dom::NativeThreadId* id,
+                                       PRUint32* processType)
+{
+    return new CrashReporterChild();
+}
+
+bool
+PluginModuleChild::DeallocPCrashReporter(PCrashReporterChild* actor)
+{
+    delete actor;
+    return true;
+}
+
+bool
+PluginModuleChild::AnswerPCrashReporterConstructor(
+        PCrashReporterChild* actor,
+        mozilla::dom::NativeThreadId* id,
+        PRUint32* processType)
+{
+#ifdef MOZ_CRASHREPORTER
+    *id = CrashReporter::CurrentThreadId();
+    *processType = XRE_GetProcessType();
+#endif
+    return true;
+}
+
 void
 PluginModuleChild::ActorDestroy(ActorDestroyReason why)
 {
     if (AbnormalShutdown == why) {
         NS_WARNING("shutting down early because of crash!");
         QuickExit();
     }
 
@@ -1796,27 +1825,21 @@ PluginModuleChild::AnswerNP_GetEntryPoin
     *_retval = mGetEntryPointsFunc(&mFunctions);
     return true;
 #else
 #  error Please implement me for your platform
 #endif
 }
 
 bool
-PluginModuleChild::AnswerNP_Initialize(NativeThreadId* tid, NPError* _retval)
+PluginModuleChild::AnswerNP_Initialize(NPError* _retval)
 {
     PLUGIN_LOG_DEBUG_METHOD;
     AssertPluginThread();
 
-#ifdef MOZ_CRASHREPORTER
-    *tid = CrashReporter::CurrentThreadId();
-#else
-    *tid = 0;
-#endif
-
 #ifdef OS_WIN
     SetEventHooks();
 #endif
 
 #ifdef MOZ_X11
     // Send the parent a dup of our X socket, to act as a proxy
     // reference for our X resources
     int xSocketFd = ConnectionNumber(DefaultXDisplay());
--- a/dom/plugins/ipc/PluginModuleChild.h
+++ b/dom/plugins/ipc/PluginModuleChild.h
@@ -86,42 +86,47 @@
 #endif
 
 typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_GETENTRYPOINTS) (NPPluginFuncs* pCallbacks);
 typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGININIT) (const NPNetscapeFuncs* pCallbacks);
 typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGINUNIXINIT) (const NPNetscapeFuncs* pCallbacks, NPPluginFuncs* fCallbacks);
 typedef NS_NPAPIPLUGIN_CALLBACK(NPError, NP_PLUGINSHUTDOWN) (void);
 
 namespace mozilla {
+namespace dom {
+class PCrashReporterChild;
+}
+
 namespace plugins {
 
 #ifdef MOZ_WIDGET_QT
 class NestedLoopTimer;
 static const int kNestedLoopDetectorIntervalMs = 90;
 #endif
 
 class PluginScriptableObjectChild;
 class PluginInstanceChild;
 
 class PluginModuleChild : public PPluginModuleChild
 {
+    typedef mozilla::dom::PCrashReporterChild PCrashReporterChild;
 protected:
     NS_OVERRIDE
     virtual mozilla::ipc::RPCChannel::RacyRPCPolicy
     MediateRPCRace(const Message& parent, const Message& child)
     {
         return MediateRace(parent, child);
     }
 
     NS_OVERRIDE
     virtual bool ShouldContinueFromReplyTimeout();
 
     // Implement the PPluginModuleChild interface
     virtual bool AnswerNP_GetEntryPoints(NPError* rv);
-    virtual bool AnswerNP_Initialize(NativeThreadId* tid, NPError* rv);
+    virtual bool AnswerNP_Initialize(NPError* rv);
 
     virtual PPluginIdentifierChild*
     AllocPPluginIdentifier(const nsCString& aString,
                            const int32_t& aInt,
                            const bool& aTemporary);
 
     virtual bool
     RecvPPluginIdentifierConstructor(PPluginIdentifierChild* actor,
@@ -169,16 +174,26 @@ protected:
     virtual bool
     RecvSetAudioSessionData(const nsID& aId,
                             const nsString& aDisplayName,
                             const nsString& aIconPath);
 
     virtual bool
     RecvSetParentHangTimeout(const uint32_t& aSeconds);
 
+    virtual PCrashReporterChild*
+    AllocPCrashReporter(mozilla::dom::NativeThreadId* id,
+                        PRUint32* processType);
+    virtual bool
+    DeallocPCrashReporter(PCrashReporterChild* actor);
+    virtual bool
+    AnswerPCrashReporterConstructor(PCrashReporterChild* actor,
+                                    mozilla::dom::NativeThreadId* id,
+                                    PRUint32* processType);
+
     virtual void
     ActorDestroy(ActorDestroyReason why);
 
     NS_NORETURN void QuickExit();
 
     NS_OVERRIDE virtual bool
     RecvProcessNativeEventsInRPCCall();
 
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -51,34 +51,37 @@
 
 #include "base/process_util.h"
 
 #include "mozilla/Preferences.h"
 #include "mozilla/unused.h"
 #include "mozilla/ipc/SyncChannel.h"
 #include "mozilla/plugins/PluginModuleParent.h"
 #include "mozilla/plugins/BrowserStreamParent.h"
+#include "mozilla/dom/PCrashReporterParent.h"
 #include "PluginIdentifierParent.h"
 
 #include "nsAutoPtr.h"
 #include "nsCRT.h"
 #ifdef MOZ_CRASHREPORTER
-#include "nsExceptionHandler.h"
+#include "mozilla/dom/CrashReporterParent.h"
 #endif
 #include "nsNPAPIPlugin.h"
 #include "nsILocalFile.h"
 
 #ifdef XP_WIN
 #include "mozilla/widget/AudioSession.h"
 #endif
 
 using base::KillProcess;
 
 using mozilla::PluginLibrary;
 using mozilla::ipc::SyncChannel;
+using mozilla::dom::PCrashReporterParent;
+using mozilla::dom::CrashReporterParent;
 
 using namespace mozilla;
 using namespace mozilla::plugins;
 using namespace mozilla::plugins::parent;
 
 static const char kChildTimeoutPref[] = "dom.ipc.plugins.timeoutSecs";
 static const char kParentTimeoutPref[] = "dom.ipc.plugins.parentTimeoutSecs";
 static const char kLaunchTimeoutPref[] = "dom.ipc.plugins.processLaunchTimeoutSecs";
@@ -106,29 +109,32 @@ PluginModuleParent::LoadModule(const cha
         // Need to set this so the destructor doesn't complain.
         parent->mShutdown = true;
         return nsnull;
     }
     parent->Open(parent->mSubprocess->GetChannel(),
                  parent->mSubprocess->GetChildProcessHandle());
 
     TimeoutChanged(kChildTimeoutPref, parent);
+
+#ifdef MOZ_CRASHREPORTER
+    CrashReporterParent::CreateCrashReporter(parent.get());
+#endif
+
     return parent.forget();
 }
 
 
 PluginModuleParent::PluginModuleParent(const char* aFilePath)
     : mSubprocess(new PluginProcessParent(aFilePath))
-    , mPluginThread(0)
     , mShutdown(false)
     , mClearSiteDataSupported(false)
     , mGetSitesWithDataSupported(false)
     , mNPNIface(NULL)
     , mPlugin(NULL)
-    , mProcessStartTime(time(NULL))
     , mTaskFactory(this)
 {
     NS_ASSERTION(mSubprocess, "Out of memory!");
 
     if (!mIdentifiers.Init()) {
         NS_ERROR("Out of memory");
     }
 
@@ -159,77 +165,40 @@ PluginModuleParent::~PluginModuleParent(
     }
 
     Preferences::UnregisterCallback(TimeoutChanged, kChildTimeoutPref, this);
     Preferences::UnregisterCallback(TimeoutChanged, kParentTimeoutPref, this);
 }
 
 #ifdef MOZ_CRASHREPORTER
 void
-PluginModuleParent::WritePluginExtraDataForMinidump(const nsAString& id)
+PluginModuleParent::WriteExtraDataForMinidump(CrashReporter::AnnotationTable& notes)
 {
     typedef nsDependentCString CS;
 
-    CrashReporter::AnnotationTable notes;
-    if (!notes.Init(32))
-        return;
-
-    notes.Put(CS("ProcessType"), CS("plugin"));
-
-    char startTime[32];
-    sprintf(startTime, "%lld", static_cast<PRInt64>(mProcessStartTime));
-    notes.Put(CS("StartupTime"), CS(startTime));
-
     // Get the plugin filename, try to get just the file leafname
     const std::string& pluginFile = mSubprocess->GetPluginFilePath();
     size_t filePos = pluginFile.rfind(FILE_PATH_SEPARATOR);
     if (filePos == std::string::npos)
         filePos = 0;
     else
         filePos++;
     notes.Put(CS("PluginFilename"), CS(pluginFile.substr(filePos).c_str()));
 
     //TODO: add plugin name and version: bug 539841
     // (as PluginName, PluginVersion)
     notes.Put(CS("PluginName"), CS(""));
     notes.Put(CS("PluginVersion"), CS(""));
 
-    if (!mCrashNotes.IsEmpty())
-        notes.Put(CS("Notes"), CS(mCrashNotes.get()));
-
-    if (!mHangID.IsEmpty())
-        notes.Put(CS("HangID"), NS_ConvertUTF16toUTF8(mHangID));
-
-    if (!CrashReporter::AppendExtraData(id, notes))
-        NS_WARNING("problem appending plugin data to .extra");
-}
-
-void
-PluginModuleParent::WriteExtraDataForHang()
-{
-    // this writes HangID
-    WritePluginExtraDataForMinidump(mPluginDumpID);
-
-    CrashReporter::AnnotationTable notes;
-    if (!notes.Init(4))
-        return;
-
-    notes.Put(nsDependentCString("HangID"), NS_ConvertUTF16toUTF8(mHangID));
-    if (!CrashReporter::AppendExtraData(mBrowserDumpID, notes))
-        NS_WARNING("problem appending browser data to .extra");
+    const nsString& hangID = CrashReporter()->HangID();
+    if (!hangID.IsEmpty())
+        notes.Put(CS("HangID"), NS_ConvertUTF16toUTF8(hangID));
 }
 #endif  // MOZ_CRASHREPORTER
 
-bool
-PluginModuleParent::RecvAppendNotesToCrashReport(const nsCString& aNotes)
-{
-    mCrashNotes.Append(aNotes);
-    return true;
-}
-
 int
 PluginModuleParent::TimeoutChanged(const char* aPref, void* aModule)
 {
     NS_ASSERTION(NS_IsMainThread(), "Wrong thead!");
     if (!strcmp(aPref, kChildTimeoutPref)) {
       // The timeout value used by the parent for children
       PRInt32 timeoutSecs = Preferences::GetInt(kChildTimeoutPref, 0);
       int32 timeoutMs = (timeoutSecs > 0) ? (1000 * timeoutSecs) :
@@ -249,39 +218,26 @@ PluginModuleParent::CleanupFromTimeout()
     if (!mShutdown)
         Close();
 }
 
 bool
 PluginModuleParent::ShouldContinueFromReplyTimeout()
 {
 #ifdef MOZ_CRASHREPORTER
-    nsCOMPtr<nsILocalFile> pluginDump;
-    nsCOMPtr<nsILocalFile> browserDump;
-    CrashReporter::ProcessHandle child;
-#ifdef XP_MACOSX
-    child = mSubprocess->GetChildTask();
-#else
-    child = OtherProcess();
-#endif
-    if (CrashReporter::CreatePairedMinidumps(child,
-                                             mPluginThread,
-                                             &mHangID,
-                                             getter_AddRefs(pluginDump),
-                                             getter_AddRefs(browserDump)) &&
-        CrashReporter::GetIDFromMinidump(pluginDump, mPluginDumpID) &&
-        CrashReporter::GetIDFromMinidump(browserDump, mBrowserDumpID)) {
-
+    CrashReporterParent* crashReporter = CrashReporter();
+    if (crashReporter->GeneratePairedMinidump(this)) {
+        mBrowserDumpID = crashReporter->ParentDumpID();
+        mPluginDumpID = crashReporter->ChildDumpID();
         PLUGIN_LOG_DEBUG(
-            ("generated paired browser/plugin minidumps: %s/%s (ID=%s)",
-             NS_ConvertUTF16toUTF8(mBrowserDumpID).get(),
-             NS_ConvertUTF16toUTF8(mPluginDumpID).get(),
-             NS_ConvertUTF16toUTF8(mHangID).get()));
-    }
-    else {
+                ("generated paired browser/plugin minidumps: %s/%s (ID=%s)",
+                 NS_ConvertUTF16toUTF8(mBrowserDumpID).get(),
+                 NS_ConvertUTF16toUTF8(mPluginDumpID).get(),
+                 NS_ConvertUTF16toUTF8(crashReporter->HangID()).get()));
+    } else {
         NS_WARNING("failed to capture paired minidumps from hang");
     }
 #endif
 
     // this must run before the error notification from the channel,
     // or not at all
     MessageLoop::current()->PostTask(
         FROM_HERE,
@@ -289,31 +245,44 @@ PluginModuleParent::ShouldContinueFromRe
             &PluginModuleParent::CleanupFromTimeout));
 
     if (!KillProcess(OtherProcess(), 1, false))
         NS_WARNING("failed to kill subprocess!");
 
     return false;
 }
 
+#ifdef MOZ_CRASHREPORTER
+CrashReporterParent*
+PluginModuleParent::CrashReporter()
+{
+    MOZ_ASSERT(ManagedPCrashReporterParent().Length() > 0);
+    return static_cast<CrashReporterParent*>(ManagedPCrashReporterParent()[0]);
+}
+#endif
+
 void
 PluginModuleParent::ActorDestroy(ActorDestroyReason why)
 {
     switch (why) {
     case AbnormalShutdown: {
 #ifdef MOZ_CRASHREPORTER
-        nsCOMPtr<nsILocalFile> pluginDump;
-        if (TakeMinidump(getter_AddRefs(pluginDump)) &&
-            CrashReporter::GetIDFromMinidump(pluginDump, mPluginDumpID)) {
+        CrashReporterParent* crashReporter = CrashReporter();
+
+        CrashReporter::AnnotationTable notes;
+        notes.Init(4);
+        WriteExtraDataForMinidump(notes);
+        
+        if (crashReporter->GenerateCrashReport(this, &notes)) {
+            mPluginDumpID = crashReporter->ChildDumpID();
             PLUGIN_LOG_DEBUG(("got child minidump: %s",
                               NS_ConvertUTF16toUTF8(mPluginDumpID).get()));
-            WritePluginExtraDataForMinidump(mPluginDumpID);
         }
         else if (!mPluginDumpID.IsEmpty() && !mBrowserDumpID.IsEmpty()) {
-            WriteExtraDataForHang();
+            crashReporter->GenerateHangCrashReport(&notes);
         }
         else {
             NS_WARNING("[PluginModuleParent::ActorDestroy] abnormal shutdown without minidump!");
         }
 #endif
 
         mShutdown = true;
         // Defer the PluginCrashed method so that we don't re-enter
@@ -776,17 +745,17 @@ PluginModuleParent::NP_Initialize(NPNets
 
     mNPNIface = bFuncs;
 
     if (mShutdown) {
         *error = NPERR_GENERIC_ERROR;
         return NS_ERROR_FAILURE;
     }
 
-    if (!CallNP_Initialize(&mPluginThread, error)) {
+    if (!CallNP_Initialize(error)) {
         return NS_ERROR_FAILURE;
     }
     else if (*error != NPERR_NO_ERROR) {
         return NS_OK;
     }
 
     SetPluginFuncs(pFuncs);
 
@@ -800,17 +769,17 @@ PluginModuleParent::NP_Initialize(NPNets
 
     mNPNIface = bFuncs;
 
     if (mShutdown) {
         *error = NPERR_GENERIC_ERROR;
         return NS_ERROR_FAILURE;
     }
 
-    if (!CallNP_Initialize(&mPluginThread, error))
+    if (!CallNP_Initialize(error))
         return NS_ERROR_FAILURE;
 
 #if defined XP_WIN && MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
     // Send the info needed to join the chrome process's audio session to the
     // plugin process
     nsID id;
     nsString sessionName;
     nsString iconPath;
@@ -1101,16 +1070,34 @@ PluginModuleParent::RecvPluginHideWindow
     return true;
 #else
     NS_NOTREACHED(
         "PluginInstanceParent::RecvPluginHideWindow not implemented!");
     return false;
 #endif
 }
 
+PCrashReporterParent*
+PluginModuleParent::AllocPCrashReporter(mozilla::dom::NativeThreadId* id,
+                                        PRUint32* processType)
+{
+#ifdef MOZ_CRASHREPORTER
+    return new CrashReporterParent();
+#else
+    return nsnull;
+#endif
+}
+
+bool
+PluginModuleParent::DeallocPCrashReporter(PCrashReporterParent* actor)
+{
+    delete actor;
+    return true;
+}
+
 bool
 PluginModuleParent::RecvSetCursor(const NSCursorInfo& aCursorInfo)
 {
     PLUGIN_LOG_DEBUG(("%s", FULLFUNCTION));
 #if defined(XP_MACOSX)
     mac_plugin_interposing::parent::OnSetCursor(aCursorInfo);
     return true;
 #else
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -60,16 +60,21 @@
 #include "nsAutoPtr.h"
 #include "nsDataHashtable.h"
 #include "nsHashKeys.h"
 #include "nsIFileStreams.h"
 #include "nsTObserverArray.h"
 #include "nsITimer.h"
 
 namespace mozilla {
+namespace dom {
+class PCrashReporterParent;
+class CrashReporterParent;
+}
+
 namespace plugins {
 //-----------------------------------------------------------------------------
 
 class BrowserStreamParent;
 
 /**
  * PluginModuleParent
  *
@@ -80,16 +85,18 @@ class BrowserStreamParent;
  * This class /also/ implements a version of the NPN API, because the
  * child process needs to make these calls back into Gecko proper.
  * This class is responsible for "actually" making those function calls.
  */
 class PluginModuleParent : public PPluginModuleParent, PluginLibrary
 {
 private:
     typedef mozilla::PluginLibrary PluginLibrary;
+    typedef mozilla::dom::PCrashReporterParent PCrashReporterParent;
+    typedef mozilla::dom::CrashReporterParent CrashReporterParent;
 
 protected:
 
     virtual PPluginIdentifierParent*
     AllocPPluginIdentifier(const nsCString& aString,
                            const int32_t& aInt,
                            const bool& aTemporary);
 
@@ -179,27 +186,30 @@ protected:
                                       bool* aBoolVal);
 
     NS_OVERRIDE
     virtual bool AnswerProcessSomeEvents();
 
     NS_OVERRIDE virtual bool
     RecvProcessNativeEventsInRPCCall();
 
-    virtual bool
-    RecvAppendNotesToCrashReport(const nsCString& aNotes);
-
     NS_OVERRIDE virtual bool
     RecvPluginShowWindow(const uint32_t& aWindowId, const bool& aModal,
                          const int32_t& aX, const int32_t& aY,
                          const size_t& aWidth, const size_t& aHeight);
 
     NS_OVERRIDE virtual bool
     RecvPluginHideWindow(const uint32_t& aWindowId);
 
+    NS_OVERRIDE virtual PCrashReporterParent*
+    AllocPCrashReporter(mozilla::dom::NativeThreadId* id,
+                        PRUint32* processType);
+    NS_OVERRIDE virtual bool
+    DeallocPCrashReporter(PCrashReporterParent* actor);
+
     NS_OVERRIDE virtual bool
     RecvSetCursor(const NSCursorInfo& aCursorInfo);
 
     NS_OVERRIDE virtual bool
     RecvShowCursor(const bool& aShow);
 
     NS_OVERRIDE virtual bool
     RecvPushCursor(const NSCursorInfo& aCursorInfo);
@@ -297,46 +307,49 @@ private:
     virtual nsresult IsRemoteDrawingCoreAnimation(NPP instance, bool *aDrawing);
 #endif
 #if defined(MOZ_WIDGET_QT) && (MOZ_PLATFORM_MAEMO == 6)
     virtual nsresult HandleGUIEvent(NPP instance, const nsGUIEvent& anEvent,
                                     bool* handled);
 #endif
 
 private:
-    void WritePluginExtraDataForMinidump(const nsAString& id);
-    void WriteExtraDataForHang();
+    CrashReporterParent* CrashReporter();
+
+#ifdef MOZ_CRASHREPORTER
+    void WriteExtraDataForMinidump(CrashReporter::AnnotationTable& notes);
+#endif
     void CleanupFromTimeout();
     static int TimeoutChanged(const char* aPref, void* aModule);
     void NotifyPluginCrashed();
 
-    nsCString mCrashNotes;
     PluginProcessParent* mSubprocess;
     // the plugin thread in mSubprocess
     NativeThreadId mPluginThread;
     bool mShutdown;
     bool mClearSiteDataSupported;
     bool mGetSitesWithDataSupported;
     const NPNetscapeFuncs* mNPNIface;
     nsDataHashtable<nsVoidPtrHashKey, PluginIdentifierParent*> mIdentifiers;
     nsNPAPIPlugin* mPlugin;
-    time_t mProcessStartTime;
     ScopedRunnableMethodFactory<PluginModuleParent> mTaskFactory;
     nsString mPluginDumpID;
     nsString mBrowserDumpID;
     nsString mHangID;
 
 #ifdef OS_MACOSX
     nsCOMPtr<nsITimer> mCATimer;
     nsTObserverArray<PluginInstanceParent*> mCATimerTargets;
 #endif
 
 #ifdef MOZ_X11
     // Dup of plugin's X socket, used to scope its resources to this
     // object instead of the plugin process's lifetime
     ScopedClose mPluginXSocketFdDup;
 #endif
+
+    friend class mozilla::dom::CrashReporterParent;
 };
 
 } // namespace plugins
 } // namespace mozilla
 
 #endif  // ifndef dom_plugins_PluginModuleParent_h
--- a/dom/plugins/ipc/PluginProcessChild.cpp
+++ b/dom/plugins/ipc/PluginProcessChild.cpp
@@ -170,22 +170,10 @@ void
 PluginProcessChild::CleanUp()
 {
 #ifdef XP_WIN
     ::OleUninitialize();
 #endif
     nsRegion::ShutdownStatic();
 }
 
-/* static */
-void
-PluginProcessChild::AppendNotesToCrashReport(const nsCString& aNotes)
-{
-    AssertPluginThread();
-
-    PluginProcessChild* p = PluginProcessChild::current();
-    if (p) {
-        p->mPlugin.SendAppendNotesToCrashReport(aNotes);
-    }
-}
-
 } // namespace plugins
 } // namespace mozilla
--- a/dom/plugins/ipc/PluginProcessChild.h
+++ b/dom/plugins/ipc/PluginProcessChild.h
@@ -56,19 +56,16 @@ public:
     { }
 
     virtual ~PluginProcessChild()
     { }
 
     NS_OVERRIDE virtual bool Init();
     NS_OVERRIDE virtual void CleanUp();
 
-    // For use on the plugin thread.
-    static void AppendNotesToCrashReport(const nsCString& aNotes);
-
 protected:
     static PluginProcessChild* current() {
         return static_cast<PluginProcessChild*>(ProcessChild::current());
     }
 
 private:
     PluginModuleChild mPlugin;
 
--- a/toolkit/xre/nsX11ErrorHandler.cpp
+++ b/toolkit/xre/nsX11ErrorHandler.cpp
@@ -33,19 +33,16 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsX11ErrorHandler.h"
 
-#include "mozilla/plugins/PluginProcessChild.h"
-using mozilla::plugins::PluginProcessChild;
-
 #include "prenv.h"
 #include "nsXULAppAPI.h"
 #include "nsExceptionHandler.h"
 #include "nsDebug.h"
 
 #include "mozilla/X11Util.h"
 #include <X11/Xlib.h>
 
@@ -151,26 +148,20 @@ X11Error(Display *display, XErrorEvent *
       notes.AppendInt(PRUint32(age));
       notes.Append(" requests ago");
     }
   }
 
 #ifdef MOZ_CRASHREPORTER
   switch (XRE_GetProcessType()) {
   case GeckoProcessType_Default:
+  case GeckoProcessType_Plugin:
+  case GeckoProcessType_Content:
     CrashReporter::AppendAppNotesToCrashReport(notes);
     break;
-  case GeckoProcessType_Plugin:
-    if (CrashReporter::GetEnabled()) {
-      // This is assuming that X operations are performed on the plugin
-      // thread.  If plugins are using X on another thread, then we'll need to
-      // handle that differently.
-      PluginProcessChild::AppendNotesToCrashReport(notes);
-    }
-    break;
   default: 
     ; // crash report notes not supported.
   }
 #endif
 
 #ifdef DEBUG
   // The resource id is unlikely to be useful in a crash report without
   // context of other ids, but add it to the debug console output.