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 72019 4f72ab0813ebc1050e9bd0a3e3006703d120b17e
parent 72018 b7b987a52c33bfc6e3372d83f36016b467888baf
child 72020 1b9505774c93a459cae7a4080f8382225336ddbc
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewerscjones
bugs581341
milestone7.0a1
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
@@ -255,18 +255,19 @@ ContentChild::Init(MessageLoop* aIOLoop,
     XRE_InstallX11ErrorHandler();
 #endif
 
     NS_ASSERTION(!sSingleton, "only one ContentChild per child");
 
     Open(aChannel, aParentHandle, aIOLoop);
     sSingleton = this;
 
+    CrashReporterChild::CreateCrashReporter(this);
 #if defined(ANDROID) && defined(MOZ_CRASHREPORTER)
-    PCrashReporterChild* crashreporter = SendPCrashReporterConstructor();
+    PCrashReporterChild* crashreporter = ManagedPCrashReporterChild()[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));
@@ -358,19 +359,24 @@ bool
 ContentChild::DeallocPBrowser(PBrowserChild* iframe)
 {
     TabChild* child = static_cast<TabChild*>(iframe);
     NS_RELEASE(child);
     return true;
 }
 
 PCrashReporterChild*
-ContentChild::AllocPCrashReporter()
+ContentChild::AllocPCrashReporter(const NativeThreadId& tid,
+                                  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 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
@@ -285,37 +285,23 @@ 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);
+            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"));
+            crashReporter->GenerateCrashReport(this, NULL);
 
-                char startTime[32];
-                sprintf(startTime, "%lld", static_cast<PRInt64>(mProcessStartTime));
-                notes.Put(NS_LITERAL_CSTRING("StartupTime"),
-                          nsDependentCString(startTime));
-
-                // TODO: Additional per-process annotations.
-                CrashReporter::AppendExtraData(dumpID, notes);
-            }
+            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,
@@ -341,17 +327,16 @@ ContentParent::DestroyTestShell(TestShel
     return PTestShellParent::Send__delete__(aTestShell);
 }
 
 ContentParent::ContentParent()
     : mGeolocationWatchID(-1)
     , mRunToCompletionDepth(0)
     , mShouldCallUnblockChild(false)
     , mIsAlive(true)
-    , mProcessStartTime(time(NULL))
 {
     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     mSubprocess = new GeckoChildProcessHost(GeckoProcessType_Content);
     mSubprocess->AsyncLaunch();
     Open(mSubprocess->GetChannel(), mSubprocess->GetChildProcessHandle());
 
     nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService();
     nsChromeRegistryChrome* chromeRegistry =
@@ -674,19 +659,24 @@ 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)
 {
-  return new CrashReporterParent();
+#ifdef MOZ_CRASHREPORTER
+  return new CrashReporterParent(tid, processType);
+#else
+  return nsnull;
+#endif
 }
 
 bool
 ContentParent::DeallocPCrashReporter(PCrashReporterParent* crashreporter)
 {
   delete crashreporter;
   return true;
 }
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -97,16 +97,20 @@ public:
 
     void ReportChildAlreadyBlocked();
     bool RequestRunToCompletion();
 
     bool IsAlive();
 
     void SetChildMemoryReporters(const InfallibleTArray<MemoryReport>& report);
 
+    GeckoChildProcessHost* Process() {
+        return mSubprocess;
+    }
+
 protected:
     void OnChannelConnected(int32 pid);
     virtual void ActorDestroy(ActorDestroyReason why);
 
 private:
     static ContentParent* gSingleton;
 
     // Hide the raw constructor methods since we don't want client code
@@ -117,17 +121,18 @@ 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 PMemoryReportRequestParent* AllocPMemoryReportRequest();
     virtual bool DeallocPMemoryReportRequest(PMemoryReportRequestParent* actor);
 
     virtual PTestShellParent* AllocPTestShell();
     virtual bool DeallocPTestShell(PTestShellParent* shell);
 
@@ -223,15 +228,16 @@ 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;
+
+    friend class CrashReporterParent;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
new file mode 100644
--- /dev/null
+++ b/dom/ipc/CrashReporterChild.cpp
@@ -0,0 +1,68 @@
+/* -*- 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()
+{
+  switch (XRE_GetProcessType()) {
+    case GeckoProcessType_Content: {
+      ContentChild* child = ContentChild::GetSingleton();
+      return child->ManagedPCrashReporterChild()[0];
+    }
+    case GeckoProcessType_Plugin: {
+      PluginModuleChild* child = PluginModuleChild::current();
+      return child->ManagedPCrashReporterChild()[0];
+    }
+    default:
+      return nsnull;
+  }
+}
+
+}
+}
--- a/dom/ipc/CrashReporterChild.h
+++ b/dom/ipc/CrashReporterChild.h
@@ -32,24 +32,41 @@
  * 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/PCrashReporterChild.h"
+#include "mozilla/Util.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();
+
+    template<class Toplevel>
+    static void CreateCrashReporter(Toplevel* actor) {
+#ifdef MOZ_CRASHREPORTER
+        MOZ_ASSERT(actor->ManagedPCrashReporterChild().Length() == 0);
+        actor->SendPCrashReporterConstructor(
+                CrashReporter::CurrentThreadId(),
+                XRE_GetProcessType());
+#endif
     }
 };
 } // namespace dom
 } // namespace mozilla
--- 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,96 @@ CrashReporterParent::RecvAddLibraryMappi
                                              m.start_address(),
                                              m.mapping_length(),
                                              m.file_offset());
   }
 #endif
   return true;
 }
 
-CrashReporterParent::CrashReporterParent()
+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(const NativeThreadId& tid,
+                                         const PRUint32& processType)
+: mMainThread(tid)
+, mStartTime(time(NULL))
+, mProcessType(processType)
 {
     MOZ_COUNT_CTOR(CrashReporterParent);
+
+#ifdef MOZ_CRASHREPORTER
+    mNotes.Init(4);
+#endif
 }
 
 CrashReporterParent::~CrashReporterParent()
 {
     MOZ_COUNT_DTOR(CrashReporterParent);
 }
 
+#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)
+{
+    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,139 @@
  * 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(const NativeThreadId& tid, const PRUint32& processType);
+  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);
+#endif
+
+  /* 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);
+
+  CrashReporter::AnnotationTable mNotes;
+#endif
+  nsCString mAppNotes;
+  nsString mHangID;
+  nsString mChildDumpID;
+  nsString mParentDumpID;
+  NativeThreadId mMainThread;
+  time_t mStartTime;
+  PRUint32 mProcessType;
 };
+
+#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;
+}
+#endif
+
 } // namespace dom
 } // namespace mozilla
--- a/dom/ipc/Makefile.in
+++ b/dom/ipc/Makefile.in
@@ -58,40 +58,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
 {
@@ -126,17 +128,17 @@ child:
     DeviceMotionChanged(long type, double x, double y, double z);
 
     ScreenSizeChanged(gfxIntSize size);
 
     FlushMemory(nsString reason);
 
 parent:
     PNecko();
-    PCrashReporter();
+    PCrashReporter(NativeThreadId tid, PRUint32 processType);
     
     PStorage(StorageConstructData data);
 
     PAudio(PRInt32 aNumChannels, PRInt32 aRate, PRInt32 aFormat);
 
     // Services remoting
 
     async StartVisitedQuery(URI uri);
--- 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
@@ -34,34 +34,37 @@
  * 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 PPluginIdentifier;
 include protocol PPluginInstance;
+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
@@ -80,17 +83,17 @@ both:
 
 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()
@@ -133,25 +136,25 @@ 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);
 
+  async PCrashReporter(NativeThreadId tid, PRUint32 processType);
+
   // OS X Specific calls to allow the plugin to manage the cursor.
   async SetCursor(NSCursorInfo cursorInfo);
   async ShowCursor(bool show);
   async PushCursor(NSCursorInfo cursorInfo);
   async PopCursor();
   sync GetNativeCursorsSupported() returns (bool supported);
 };
 
--- 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
@@ -60,31 +60,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;
@@ -258,16 +261,17 @@ PluginModuleChild::Init(const std::strin
 #ifdef XP_MACOSX
     nsPluginInfo info = nsPluginInfo();
     rv = pluginFile.GetPluginInfo(info, &mLibrary);
     if (rv == NS_OK) {
         mozilla::plugins::PluginUtilsOSX::SetProcessName(info.fName);
     }
 #endif
 
+    CrashReporterChild::CreateCrashReporter(this);
     return true;
 }
 
 #if defined(MOZ_WIDGET_GTK2)
 typedef void (*GObjectDisposeFn)(GObject*);
 typedef gboolean (*GtkWidgetScrollEventFn)(GtkWidget*, GdkEventScroll*);
 typedef void (*GtkPlugEmbeddedFn)(GtkPlug*);
 
@@ -570,17 +574,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();
@@ -684,16 +687,30 @@ PluginModuleChild::RecvSetAudioSessionDa
 
 void
 PluginModuleChild::QuickExit()
 {
     NS_WARNING("plugin process _exit()ing");
     _exit(0);
 }
 
+PCrashReporterChild*
+PluginModuleChild::AllocPCrashReporter(const mozilla::dom::NativeThreadId& id,
+                                       const PRUint32& processType)
+{
+    return new CrashReporterChild;
+}
+
+bool
+PluginModuleChild::DeallocPCrashReporter(PCrashReporterChild* actor)
+{
+    delete actor;
+    return true;
+}
+
 void
 PluginModuleChild::ActorDestroy(ActorDestroyReason why)
 {
     if (AbnormalShutdown == why) {
         NS_WARNING("shutting down early because of crash!");
         QuickExit();
     }
 
@@ -1768,27 +1785,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,39 +86,45 @@
 #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);
     }
 
     // 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,
@@ -163,16 +169,22 @@ protected:
     virtual bool
     AnswerNPP_GetSitesWithData(InfallibleTArray<nsCString>* aResult);
 
     virtual bool
     RecvSetAudioSessionData(const nsID& aId,
                             const nsString& aDisplayName,
                             const nsString& aIconPath);
 
+    virtual PCrashReporterChild*
+    AllocPCrashReporter(const mozilla::dom::NativeThreadId& id,
+                            const PRUint32& processType);
+    virtual bool
+    DeallocPCrashReporter(PCrashReporterChild* actor);
+
     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 kTimeoutPref[] = "dom.ipc.plugins.timeoutSecs";
 static const char kLaunchTimeoutPref[] = "dom.ipc.plugins.processLaunchTimeoutSecs";
 
@@ -111,23 +114,21 @@ PluginModuleParent::LoadModule(const cha
 
     TimeoutChanged(kTimeoutPref, parent);
     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");
     }
 
@@ -156,77 +157,40 @@ PluginModuleParent::~PluginModuleParent(
         mSubprocess = nsnull;
     }
 
     Preferences::UnregisterCallback(TimeoutChanged, kTimeoutPref, 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!");
     NS_ABORT_IF_FALSE(!strcmp(aPref, kTimeoutPref),
                       "unexpected pref callback");
 
     PRInt32 timeoutSecs = Preferences::GetInt(kTimeoutPref, 0);
@@ -243,39 +207,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,
@@ -283,31 +234,43 @@ PluginModuleParent::ShouldContinueFromRe
             &PluginModuleParent::CleanupFromTimeout));
 
     if (!KillProcess(OtherProcess(), 1, false))
         NS_WARNING("failed to kill subprocess!");
 
     return false;
 }
 
+#ifdef MOZ_CRASHREPORTER
+CrashReporterParent*
+PluginModuleParent::CrashReporter()
+{
+    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
@@ -758,17 +721,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);
 
@@ -782,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;
 
 #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;
@@ -1069,16 +1032,34 @@ PluginModuleParent::RecvPluginHideWindow
     return true;
 #else
     NS_NOTREACHED(
         "PluginInstanceParent::RecvPluginHideWindow not implemented!");
     return false;
 #endif
 }
 
+PCrashReporterParent*
+PluginModuleParent::AllocPCrashReporter(const NativeThreadId& tid,
+                                        const PRUint32& processType)
+{
+#ifdef MOZ_CRASHREPORTER
+    return new CrashReporterParent(tid, processType);
+#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(const NativeThreadId& tid,
+                        const 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);
@@ -285,46 +295,49 @@ private:
                              uint16_t mode, int16_t argc, char* argn[],
                              char* argv[], NPSavedData* saved,
                              NPError* error);
     virtual nsresult NPP_ClearSiteData(const char* site, uint64_t flags,
                                        uint64_t maxAge);
     virtual nsresult NPP_GetSitesWithData(InfallibleTArray<nsCString>& result);
 
 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.