Merge backout of revision 08e208698ef0, bug 533688 because of Tinderbox orange. last-mozilla-central
authorBenjamin Smedberg <benjamin@smedbergs.us>
Wed, 16 Dec 2009 10:32:57 -0500
changeset 36290 dba2abb7db57078c5a4810884834d3056a5d56c2
parent 36288 088fc4c3f9df535eccd25e6b207cb6549d026f65 (diff)
parent 36289 ada564e50e86a6285a5a6773cadf7b2f5bc16885 (current diff)
child 36291 7210af2c43680affeb74452fc8257c4bf13800d7
child 36301 5c9ee961025c99614e0d01cf5ba421eaf9bb668d
child 36307 8a63ddd1754704a916d53e567c94fae75f093b4f
push idunknown
push userunknown
push dateunknown
bugs533688
milestone1.9.3a1pre
Merge backout of revision 08e208698ef0, bug 533688 because of Tinderbox orange.
--- a/build/automation.py.in
+++ b/build/automation.py.in
@@ -521,25 +521,27 @@ else:
     return (f.readline(), False)
 
   def isPidAlive(pid):
     try:
       # kill(pid, 0) checks for a valid PID without actually sending a signal
       # The method throws OSError if the PID is invalid, which we catch below.
       os.kill(pid, 0)
 
-      # wait on it to see if it's a zombie
+      # Wait on it to see if it's a zombie. This can throw OSError.ECHILD if
+      # the process terminates before we get to this point.
       wpid, wstatus = os.waitpid(pid, os.WNOHANG)
       if wpid == 0:
         return True
 
       return False
     except OSError, err:
-      # Catch the one error we expect from os.kill, and re-raise any others
-      if err.errno == errno.ESRCH:
+      # Catch the errors we might expect from os.kill/os.waitpid, 
+      # and re-raise any others
+      if err.errno == errno.ESRCH or err.errno == errno.ECHILD:
         return False
       raise
 
   def killPid(pid):
     os.kill(pid, signal.SIGKILL)
 
 def triggerBreakpad(proc, utilityPath):
   """Attempt to kill this process in a way that triggers Breakpad crash
--- a/dom/plugins/NPEventWindows.h
+++ b/dom/plugins/NPEventWindows.h
@@ -46,17 +46,17 @@ namespace mozilla {
 namespace plugins {
 
 // We use an NPRemoteEvent struct so that we can store the extra data on
 // the stack so that we don't need to worry about managing the memory.
 struct NPRemoteEvent
 {
     NPEvent event;
     union {
-        NPRect rect;
+        RECT rect;
         WINDOWPOS windowpos;
     } lParamData;
 };
 
 }
 
 }
 
@@ -82,19 +82,19 @@ struct ParamTraits<mozilla::plugins::NPR
         switch (paramCopy.event.event) {
             case WM_WINDOWPOSCHANGED:
                 // The lParam paramter of WM_WINDOWPOSCHANGED holds a pointer to
                 // a WINDOWPOS structure that contains information about the
                 // window's new size and position
                 paramCopy.lParamData.windowpos = *(reinterpret_cast<WINDOWPOS*>(paramCopy.event.lParam));
                 break;
             case WM_PAINT:
-                // The lParam paramter of WM_PAINT holds a pointer to an NPRect
+                // The lParam paramter of WM_PAINT holds a pointer to an RECT
                 // structure specifying the bounding box of the update area.
-                paramCopy.lParamData.rect = *(reinterpret_cast<NPRect*>(paramCopy.event.lParam));
+                paramCopy.lParamData.rect = *(reinterpret_cast<RECT*>(paramCopy.event.lParam));
                 break;
 
             // the white list of events that we will ipc to the client
             case WM_CHAR:
             case WM_SYSCHAR:
 
             case WM_KEYUP:
             case WM_SYSKEYUP:
@@ -122,35 +122,39 @@ struct ParamTraits<mozilla::plugins::NPR
             case WM_LBUTTONDBLCLK:
             case WM_MBUTTONDBLCLK:
             case WM_RBUTTONDBLCLK:
 
             case WM_SETFOCUS:
             case WM_KILLFOCUS:
                 break;
 
-            // ignore any events we don't expect
             default:
+                // RegisterWindowMessage events should be passed.
+                if (paramCopy.event.event >= 0xC000 && paramCopy.event.event <= 0xFFFF)
+                    break;
+
+                // ignore any events we don't expect
                 return;
         }
 
         aMsg->WriteBytes(&paramCopy, sizeof(paramType));
     }
 
     static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
     {
         const char* bytes = 0;
 
         if (!aMsg->ReadBytes(aIter, &bytes, sizeof(paramType))) {
             return false;
         }
         memcpy(aResult, bytes, sizeof(paramType));
 
         if (aResult->event.event == WM_PAINT) {
-            // restore the lParam to point at the NPRect
+            // restore the lParam to point at the RECT
             aResult->event.lParam = reinterpret_cast<LPARAM>(&aResult->lParamData.rect);
         } else if (aResult->event.event == WM_WINDOWPOSCHANGED) {
             // restore the lParam to point at the WINDOWPOS
             aResult->event.lParam = reinterpret_cast<LPARAM>(&aResult->lParamData.windowpos);
         }
 
         return true;
     }
--- a/dom/plugins/PluginInstanceChild.cpp
+++ b/dom/plugins/PluginInstanceChild.cpp
@@ -54,16 +54,17 @@ using namespace mozilla::plugins;
 #include <gdk/gdk.h>
 #include "gtk2xtbin.h"
 
 #elif defined(OS_WIN)
 using mozilla::gfx::SharedDIB;
 
 #include <windows.h>
 
+#define NS_OOPP_DOUBLEPASS_MSGID TEXT("MozDoublePassMsg")
 #endif
 
 PluginInstanceChild::PluginInstanceChild(const NPPluginFuncs* aPluginIface) :
         mPluginIface(aPluginIface)
 #if defined(OS_WIN)
         , mPluginWindowHWND(0)
         , mPluginWndProc(0)
         , mPluginParentHWND(0)
@@ -73,16 +74,20 @@ PluginInstanceChild::PluginInstanceChild
         mData.ndata = (void*) this;
 #if defined(MOZ_X11) && defined(XP_UNIX) && !defined(XP_MACOSX)
         mWindow.ws_info = &mWsInfo;
         memset(&mWsInfo, 0, sizeof(mWsInfo));
 #  ifdef MOZ_WIDGET_GTK2
         mWsInfo.display = GDK_DISPLAY();
 #  endif
 #endif
+#if defined(OS_WIN)
+    memset(&mAlphaExtract, 0, sizeof(mAlphaExtract));
+    mAlphaExtract.doublePassEvent = ::RegisterWindowMessage(NS_OOPP_DOUBLEPASS_MSGID);
+#endif
     }
 
 PluginInstanceChild::~PluginInstanceChild()
 {
 #if defined(OS_WIN)
   DestroyPluginWindow();
 #endif
 }
@@ -337,19 +342,31 @@ PluginInstanceChild::AnswerNPP_HandleEve
         printf("  received drawable 0x%lx\n",
                event.event.xgraphicsexpose.drawable);
 #endif
 
     // Make a copy since we may modify values.
     NPEvent evcopy = event.event;
 
 #ifdef OS_WIN
-    // Setup the shared dib for painting and update evcopy.
-    if (NPWindowTypeDrawable == mWindow.type && WM_PAINT == evcopy.event)
-        SharedSurfaceBeforePaint(evcopy);
+    // Painting for win32. SharedSurfacePaint handles everything.
+    if (mWindow.type == NPWindowTypeDrawable) {
+       if (evcopy.event == WM_PAINT) {
+          *handled = SharedSurfacePaint(evcopy);
+          return true;
+       }
+       else if (evcopy.event == mAlphaExtract.doublePassEvent) {
+            // We'll render to mSharedSurfaceDib first, then render to a cached bitmap
+            // we store locally. The two passes are for alpha extraction, so the second
+            // pass must be to a flat white surface in order for things to work.
+            mAlphaExtract.doublePass = RENDER_BACK_ONE;
+            *handled = true;
+            return true;
+       }
+    }
 #endif
 
     *handled = mPluginIface->event(&mData, reinterpret_cast<void*>(&evcopy));
 
 #ifdef MOZ_X11
     if (GraphicsExpose == event.event.type) {
         // Make sure the X server completes the drawing before the parent
         // draws on top and destroys the Drawable.
@@ -670,16 +687,19 @@ PluginInstanceChild::SharedSurfaceSetWin
             return false;
         }
     }
     else {
         // Attach to the new shared surface parent handed us.
         if (NS_FAILED(mSharedSurfaceDib.Attach((SharedDIB::Handle)aWindow.surfaceHandle,
                                                aWindow.width, aWindow.height, 32)))
           return false;
+        // Free any alpha extraction resources if needed. This will be reset
+        // the next time it's used.
+        AlphaExtractCacheRelease();
     }
       
     // NPRemoteWindow's origin is the origin of our shared dib.
     mWindow.x      = 0;
     mWindow.y      = 0;
     mWindow.width  = aWindow.width;
     mWindow.height = aWindow.height;
     mWindow.type   = aWindow.type;
@@ -689,30 +709,147 @@ PluginInstanceChild::SharedSurfaceSetWin
 
     return true;
 }
 
 void
 PluginInstanceChild::SharedSurfaceRelease()
 {
     mSharedSurfaceDib.Close();
+    AlphaExtractCacheRelease();
+}
+
+/* double pass cache buffer - (rarely) used in cases where alpha extraction
+ * occurs for windowless plugins. */
+ 
+bool
+PluginInstanceChild::AlphaExtractCacheSetup()
+{
+    AlphaExtractCacheRelease();
+
+    mAlphaExtract.hdc = ::CreateCompatibleDC(NULL);
+
+    if (!mAlphaExtract.hdc)
+        return false;
+
+    BITMAPINFOHEADER bmih;
+    memset((void*)&bmih, 0, sizeof(BITMAPINFOHEADER));
+    bmih.biSize        = sizeof(BITMAPINFOHEADER);
+    bmih.biWidth       = mWindow.width;
+    bmih.biHeight      = mWindow.height;
+    bmih.biPlanes      = 1;
+    bmih.biBitCount    = 32;
+    bmih.biCompression = BI_RGB;
+
+    void* ppvBits = nsnull;
+    mAlphaExtract.bmp = ::CreateDIBSection(mAlphaExtract.hdc,
+                                           (BITMAPINFO*)&bmih,
+                                           DIB_RGB_COLORS,
+                                           (void**)&ppvBits,
+                                           NULL,
+                                           (unsigned long)sizeof(BITMAPINFOHEADER));
+    if (!mAlphaExtract.bmp)
+      return false;
+
+    DeleteObject(::SelectObject(mAlphaExtract.hdc, mAlphaExtract.bmp));
+    return true;
+}
+
+void
+PluginInstanceChild::AlphaExtractCacheRelease()
+{
+    if (mAlphaExtract.bmp)
+        ::DeleteObject(mAlphaExtract.bmp);
+
+    if (mAlphaExtract.hdc)
+        ::DeleteObject(mAlphaExtract.hdc);
+
+    mAlphaExtract.bmp = NULL;
+    mAlphaExtract.hdc = NULL;
 }
 
 void
-PluginInstanceChild::SharedSurfaceBeforePaint(NPEvent& evcopy)
+PluginInstanceChild::UpdatePaintClipRect(RECT* aRect)
 {
-    // Update the clip rect on our internal hdc
+    if (aRect) {
+        // Update the clip rect on our internal hdc
+        HRGN clip = ::CreateRectRgnIndirect(aRect);
+        ::SelectClipRgn(mSharedSurfaceDib.GetHDC(), clip);
+        ::DeleteObject(clip);
+    }
+}
+
+int16_t
+PluginInstanceChild::SharedSurfacePaint(NPEvent& evcopy)
+{
     RECT* pRect = reinterpret_cast<RECT*>(evcopy.lParam);
-    if (pRect) {
-      HRGN clip = ::CreateRectRgnIndirect(pRect);
-      ::SelectClipRgn(mSharedSurfaceDib.GetHDC(), clip);
-      ::DeleteObject(clip);
+
+    switch(mAlphaExtract.doublePass) {
+        case RENDER_NATIVE:
+            // pass the internal hdc to the plugin
+            UpdatePaintClipRect(pRect);
+            evcopy.wParam = WPARAM(mSharedSurfaceDib.GetHDC());
+            return mPluginIface->event(&mData, reinterpret_cast<void*>(&evcopy));
+        break;
+        case RENDER_BACK_ONE:
+              // Handle a double pass render used in alpha extraction for transparent
+              // plugins. (See nsObjectFrame and gfxWindowsNativeDrawing for details.)
+              // We render twice, once to the shared dib, and once to a cache which
+              // we copy back on a second paint. These paints can't be spread across
+              // multiple rpc messages as delays cause animation frame changes.
+              if (!mAlphaExtract.bmp && !AlphaExtractCacheSetup()) {
+                  mAlphaExtract.doublePass = RENDER_NATIVE;
+                  return false;
+              }
+
+              // See gfxWindowsNativeDrawing, color order doesn't have to match.
+              ::FillRect(mSharedSurfaceDib.GetHDC(), pRect, (HBRUSH)GetStockObject(WHITE_BRUSH));
+              UpdatePaintClipRect(pRect);
+              evcopy.wParam = WPARAM(mSharedSurfaceDib.GetHDC());
+              if (!mPluginIface->event(&mData, reinterpret_cast<void*>(&evcopy))) {
+                  mAlphaExtract.doublePass = RENDER_NATIVE;
+                  return false;
+              }
+
+              // Copy to cache. We render to shared dib so we don't have to call
+              // setwindow between calls (flash issue).  
+              ::BitBlt(mAlphaExtract.hdc,
+                       pRect->left,
+                       pRect->top,
+                       pRect->right - pRect->left,
+                       pRect->bottom - pRect->top,
+                       mSharedSurfaceDib.GetHDC(),
+                       pRect->left,
+                       pRect->top,
+                       SRCCOPY);
+
+              ::FillRect(mSharedSurfaceDib.GetHDC(), pRect, (HBRUSH)GetStockObject(BLACK_BRUSH));
+              if (!mPluginIface->event(&mData, reinterpret_cast<void*>(&evcopy))) {
+                  mAlphaExtract.doublePass = RENDER_NATIVE;
+                  return false;
+              }
+              mAlphaExtract.doublePass = RENDER_BACK_TWO;
+              return true;
+        break;
+        case RENDER_BACK_TWO:
+              // copy our cached surface back
+              ::BitBlt(mSharedSurfaceDib.GetHDC(),
+                       pRect->left,
+                       pRect->top,
+                       pRect->right - pRect->left,
+                       pRect->bottom - pRect->top,
+                       mAlphaExtract.hdc,
+                       pRect->left,
+                       pRect->top,
+                       SRCCOPY);
+              mAlphaExtract.doublePass = RENDER_NATIVE;
+              return true;
+        break;
     }
-    // pass the internal hdc to the plugin
-    evcopy.wParam = WPARAM(mSharedSurfaceDib.GetHDC());
+    return false;
 }
 
 #endif // OS_WIN
 
 PPluginScriptableObjectChild*
 PluginInstanceChild::AllocPPluginScriptableObject()
 {
     AssertPluginThread();
--- a/dom/plugins/PluginInstanceChild.h
+++ b/dom/plugins/PluginInstanceChild.h
@@ -193,20 +193,34 @@ private:
 #endif
 
     nsTArray<nsAutoPtr<PluginScriptableObjectChild> > mScriptableObjects;
 
 #if defined(OS_WIN)
 private:
     // Shared dib rendering management for windowless plugins.
     bool SharedSurfaceSetWindow(const NPRemoteWindow& aWindow, NPError* rv);
-    void SharedSurfaceBeforePaint(NPEvent& evcopy);
+    int16_t SharedSurfacePaint(NPEvent& evcopy);
     void SharedSurfaceRelease();
+    bool AlphaExtractCacheSetup();
+    void AlphaExtractCacheRelease();
+    void UpdatePaintClipRect(RECT* aRect);
 
 private:
+    enum {
+      RENDER_NATIVE,
+      RENDER_BACK_ONE,
+      RENDER_BACK_TWO 
+    };
     gfx::SharedDIBWin mSharedSurfaceDib;
+    struct {
+      PRUint32        doublePassEvent;
+      PRUint16        doublePass;
+      HDC             hdc;
+      HBITMAP         bmp;
+    } mAlphaExtract;
 #endif // defined(OS_WIN)
 };
 
 } // namespace plugins
 } // namespace mozilla
 
 #endif // ifndef dom_plugins_PluginInstanceChild_h
--- a/dom/plugins/PluginInstanceParent.cpp
+++ b/dom/plugins/PluginInstanceParent.cpp
@@ -43,37 +43,29 @@
 #include "PluginModuleParent.h"
 #include "PluginStreamParent.h"
 #include "StreamNotifyParent.h"
 
 #include "npfunctions.h"
 #include "nsAutoPtr.h"
 
 #if defined(OS_WIN)
-#define NS_OOPP_DOUBLEPASS_MSGID TEXT("MozDoublePassMsg")
+#include <windowsx.h>
 #endif
 
 using namespace mozilla::plugins;
 
 PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent,
                                            NPP npp,
                                            const NPNetscapeFuncs* npniface)
   : mParent(parent),
     mNPP(npp),
     mNPNIface(npniface),
     mWindowType(NPWindowTypeWindow)
 {
-#if defined(OS_WIN)
-    // Event sent from nsObjectFrame indicating double pass rendering for
-    // windowless plugins. RegisterWindowMessage makes it easy sync event
-    // values, and insures we never conflict with windowing events we allow
-    // for windowless plugins.
-    mDoublePassEvent = ::RegisterWindowMessage(NS_OOPP_DOUBLEPASS_MSGID);
-    mLocalCopyRender = false;
-#endif
 }
 
 PluginInstanceParent::~PluginInstanceParent()
 {
     if (mNPP)
         mNPP->pdata = NULL;
 }
 
@@ -459,30 +451,68 @@ PluginInstanceParent::NPP_GetValue(NPPVa
 int16_t
 PluginInstanceParent::NPP_HandleEvent(void* event)
 {
     _MOZ_LOG(__FUNCTION__);
 
     NPEvent* npevent = reinterpret_cast<NPEvent*>(event);
     NPRemoteEvent npremoteevent;
     npremoteevent.event = *npevent;
+    int16_t handled;
 
 #if defined(OS_WIN)
     RECT rect;
     if (mWindowType == NPWindowTypeDrawable) {
-        if (mDoublePassEvent && mDoublePassEvent == npevent->event) {
-            // Sent from nsObjectFrame to let us know a double pass render is in progress.
-            mLocalCopyRender = PR_TRUE;
-            return true;
-        } else if (WM_PAINT == npevent->event) {
-            // Don't forward on the second pass, otherwise, fall through.
-            if (!SharedSurfaceBeforePaint(rect, npremoteevent))
-                return true;
+        switch(npevent->event) {
+            case WM_PAINT:
+            {
+                RECT rect;
+                SharedSurfaceBeforePaint(rect, npremoteevent);
+                if (!CallNPP_HandleEvent(npremoteevent, &handled))
+                    return 0;
+                if (handled)
+                    SharedSurfaceAfterPaint(npevent);
+            }
+            break;
+            case WM_WINDOWPOSCHANGED:
+                SharedSurfaceSetOrigin(npremoteevent);
+                if (!CallNPP_HandleEvent(npremoteevent, &handled))
+                    return 0;
+            break;
+            case WM_MOUSEMOVE:
+            case WM_RBUTTONDOWN:
+            case WM_MBUTTONDOWN:
+            case WM_LBUTTONDOWN:
+            case WM_LBUTTONUP:
+            case WM_MBUTTONUP:
+            case WM_RBUTTONUP:
+            case WM_LBUTTONDBLCLK:
+            case WM_MBUTTONDBLCLK:
+            case WM_RBUTTONDBLCLK:
+            {
+                // Received mouse events have an origin at the position of the plugin rect
+                // in the page. However, when rendering to the shared dib, the rect origin
+                // changes to 0,0 via the WM_WINDOWPOSCHANGED event. In this case we need to
+                // translate these coords to the proper location.
+                nsPoint pt(GET_X_LPARAM(npremoteevent.event.lParam), GET_Y_LPARAM(npremoteevent.event.lParam));
+                pt.MoveBy(-mPluginPosOrigin.x, -mPluginPosOrigin.y);
+                npremoteevent.event.lParam = MAKELPARAM(pt.x, pt.y);
+                if (!CallNPP_HandleEvent(npremoteevent, &handled))
+                    return 0;
+            }
+            default:
+                if (!CallNPP_HandleEvent(npremoteevent, &handled))
+                    return 0;
+            break;
         }
     }
+    else {
+        if (!CallNPP_HandleEvent(npremoteevent, &handled))
+            return 0;
+    }
 #endif
 
 #if defined(MOZ_X11)
     if (GraphicsExpose == npevent->type) {
         printf("  schlepping drawable 0x%lx across the pipe\n",
                npevent->xgraphicsexpose.drawable);
         // Make sure the X server has created the Drawable and completes any
         // drawing before the plugin draws on top.
@@ -490,26 +520,19 @@ PluginInstanceParent::NPP_HandleEvent(vo
         // XSync() waits for the X server to complete.  Really this parent
         // process does not need to wait; the child is the process that needs
         // to wait.  A possibly-slightly-better alternative would be to send
         // an X event to the child that the child would wait for.
 #  ifdef MOZ_WIDGET_GTK2
         XSync(GDK_DISPLAY(), False);
 #  endif
     }
-#endif
 
-    int16_t handled;
-    if (!CallNPP_HandleEvent(npremoteevent, &handled)) {
-        return 0;               // no good way to handle errors here...
-    }
-
-#if defined(OS_WIN)
-    if (handled && mWindowType == NPWindowTypeDrawable && WM_PAINT == npevent->event)
-        SharedSurfaceAfterPaint(npevent);
+    if (!CallNPP_HandleEvent(npremoteevent, &handled))
+        return 0; // no good way to handle errors here...
 #endif
 
     return handled;
 }
 
 NPError
 PluginInstanceParent::NPP_NewStream(NPMIMEType type, NPStream* stream,
                                     NPBool seekable, uint16_t* stype)
@@ -675,16 +698,51 @@ PluginInstanceParent::AnswerNPN_PopPopup
     *aSuccess = mNPNIface->poppopupsenabledstate(mNPP);
     return true;
 }
 
 #if defined(OS_WIN)
 
 /* windowless drawing helpers */
 
+/*
+ * Origin info:
+ *
+ * windowless, offscreen:
+ *
+ * WM_WINDOWPOSCHANGED: origin is relative to container 
+ * setwindow: origin is 0,0
+ * WM_PAINT: origin is 0,0
+ *
+ * windowless, native:
+ *
+ * WM_WINDOWPOSCHANGED: origin is relative to container 
+ * setwindow: origin is relative to container
+ * WM_PAINT: origin is relative to container
+ *
+ * PluginInstanceParent:
+ *
+ * painting: mPluginPort (nsIntRect, saved in SetWindow)
+ * event translation: mPluginPosOrigin (nsIntPoint, saved in SetOrigin)
+ */
+
+void
+PluginInstanceParent::SharedSurfaceSetOrigin(NPRemoteEvent& npremoteevent)
+{
+    WINDOWPOS* winpos = (WINDOWPOS*)npremoteevent.event.lParam;
+
+    // save the origin, we'll use this to translate input coordinates
+    mPluginPosOrigin.x = winpos->x;
+    mPluginPosOrigin.y = winpos->y;
+
+    // Reset to the offscreen dib origin
+    winpos->x  = 0;
+    winpos->y  = 0;
+}
+
 void
 PluginInstanceParent::SharedSurfaceRelease()
 {
     mSharedSurfaceDib.Close();
 }
 
 bool
 PluginInstanceParent::SharedSurfaceSetWindow(const NPWindow* aWindow,
@@ -706,79 +764,63 @@ PluginInstanceParent::SharedSurfaceSetWi
     newPort.MoveTo(0,0);
 
     // check to see if we have the room in shared surface
     if (mSharedSurfaceDib.IsValid() && mSharedSize.Contains(newPort)) {
       // ok to paint
       aRemoteWindow.surfaceHandle = 0;
       return true;
     }
-    
+
     // allocate a new shared surface
     SharedSurfaceRelease();
     if (NS_FAILED(mSharedSurfaceDib.Create(reinterpret_cast<HDC>(aWindow->window),
                                            newPort.width, newPort.height, 32)))
       return false;
 
     // save the new shared surface size we just allocated
     mSharedSize = newPort;
-    
+
     base::SharedMemoryHandle handle;
     if (NS_FAILED(mSharedSurfaceDib.ShareToProcess(mParent->ChildProcessHandle(), &handle)))
       return false;
 
     aRemoteWindow.surfaceHandle = handle;
-    
+
     return true;
 }
 
-bool
+void
 PluginInstanceParent::SharedSurfaceBeforePaint(RECT& rect,
                                                NPRemoteEvent& npremoteevent)
 {
     RECT* dr = (RECT*)npremoteevent.event.lParam;
     HDC parentHdc = (HDC)npremoteevent.event.wParam;
 
-    // We render twice per frame for windowless plugins that sit in transparent
-    // frames. (See nsObjectFrame and gfxWindowsNativeDrawing for details.) IPC
-    // message delays in OOP plugin painting can result in two passes yeilding
-    // different animation frames. The second rendering doesn't need to go over
-    // the wire (we already have a copy of the frame in mSharedSurfaceDib) so we
-    // skip off requesting the second. This also gives us a nice perf boost.
-    if (mLocalCopyRender) {
-      mLocalCopyRender = false;
-      // Reuse the old render.
-      SharedSurfaceAfterPaint(&npremoteevent.event);
-      return false;
-    }
-
     nsIntRect dirtyRect(dr->left, dr->top, dr->right-dr->left, dr->bottom-dr->top);
     dirtyRect.MoveBy(-mPluginPort.x, -mPluginPort.y); // should always be smaller than dirtyRect
 
     ::BitBlt(mSharedSurfaceDib.GetHDC(),
              dirtyRect.x,
              dirtyRect.y,
              dirtyRect.width,
              dirtyRect.height,
              parentHdc,
              dr->left,
              dr->top,
              SRCCOPY);
 
     // setup the translated dirty rect we'll send to the child
     rect.left   = dirtyRect.x;
     rect.top    = dirtyRect.y;
-    rect.right  = dirtyRect.width;
-    rect.bottom = dirtyRect.height;
+    rect.right  = dirtyRect.x + dirtyRect.width;
+    rect.bottom = dirtyRect.y + dirtyRect.height;
 
     npremoteevent.event.wParam = WPARAM(0);
     npremoteevent.event.lParam = LPARAM(&rect);
-
-    // Send the event to the plugin
-    return true;
 }
 
 void
 PluginInstanceParent::SharedSurfaceAfterPaint(NPEvent* npevent)
 {
     RECT* dr = (RECT*)npevent->lParam;
     HDC parentHdc = (HDC)npevent->wParam;
 
--- a/dom/plugins/PluginInstanceParent.h
+++ b/dom/plugins/PluginInstanceParent.h
@@ -212,26 +212,26 @@ private:
     NPWindowType mWindowType;
 
     nsTArray<nsAutoPtr<PluginScriptableObjectParent> > mScriptableObjects;
 
 #if defined(OS_WIN)
 private:
     // Used in rendering windowless plugins in other processes.
     bool SharedSurfaceSetWindow(const NPWindow* aWindow, NPRemoteWindow& aRemoteWindow);
-    bool SharedSurfaceBeforePaint(RECT &rect, NPRemoteEvent& npremoteevent);
+    void SharedSurfaceBeforePaint(RECT &rect, NPRemoteEvent& npremoteevent);
     void SharedSurfaceAfterPaint(NPEvent* npevent);
+    void SharedSurfaceSetOrigin(NPRemoteEvent& npremoteevent);
     void SharedSurfaceRelease();
 
 private:
     gfx::SharedDIBWin  mSharedSurfaceDib;
     nsIntRect          mPluginPort;
     nsIntRect          mSharedSize;
-    PRUint32           mDoublePassEvent;
-    bool               mLocalCopyRender;
+    nsIntPoint         mPluginPosOrigin;
 #endif // defined(XP_WIN)
 };
 
 
 } // namespace plugins
 } // namespace mozilla
 
 #endif // ifndef dom_plugins_PluginInstanceParent_h
--- a/dom/plugins/PluginProcessParent.cpp
+++ b/dom/plugins/PluginProcessParent.cpp
@@ -62,17 +62,21 @@ PluginProcessParent::PluginProcessParent
 PluginProcessParent::~PluginProcessParent()
 {
 }
 
 bool
 PluginProcessParent::Launch()
 {
     std::vector<std::string> args;
+#if defined(XP_WIN)
+    args.push_back("\""+ mPluginFilePath +"\"");
+#else
     args.push_back(mPluginFilePath);
+#endif
     return SyncLaunch(args);
 }
 
 void
 PluginProcessParent::Delete()
 {
   MessageLoop* currentLoop = MessageLoop::current();
   MessageLoop* ioLoop = 
--- a/gfx/cairo/cairo/src/cairo-surface.c
+++ b/gfx/cairo/cairo/src/cairo-surface.c
@@ -1536,66 +1536,61 @@ struct acquire_source_image_data
     cairo_image_surface_t *image;
     void *image_extra;
 };
 
 static void
 _wrap_release_source_image (void *data)
 {
     struct acquire_source_image_data *acquire_data = data;
-    _cairo_surface_release_source_image (acquire_data->src,
-					 acquire_data->image,
-					 acquire_data->image_extra);
+    _cairo_surface_release_source_image (acquire_data->src, acquire_data->image, acquire_data->image_extra);
     free(data);
 }
 
 static cairo_status_t
 _wrap_image (cairo_surface_t *src,
 	     cairo_image_surface_t *image,
 	     void *image_extra,
 	     cairo_image_surface_t **out)
 {
     static cairo_user_data_key_t wrap_image_key;
     cairo_image_surface_t *surface;
     cairo_status_t status;
 
-    struct acquire_source_image_data *data = malloc (sizeof (*data));
-    if (unlikely (data == NULL))
-	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
+    struct acquire_source_image_data *data = malloc(sizeof(*data));
     data->src = src;
     data->image = image;
     data->image_extra = image_extra;
 
-    surface = (cairo_image_surface_t*)
-	_cairo_image_surface_create_for_pixman_image (image->pixman_image,
-						      image->pixman_format);
+    surface = (cairo_image_surface_t*)cairo_image_surface_create_for_data (image->data,
+	    image->format,
+	    image->width,
+	    image->height,
+	    image->stride);
     status = surface->base.status;
-    if (status) {
-	free (data);
+    if (status)
 	return status;
-    }
 
     status = _cairo_user_data_array_set_data (&surface->base.user_data,
-					      &wrap_image_key,
-					      data,
-					      _wrap_release_source_image);
+	    &wrap_image_key,
+	    data,
+	    _wrap_release_source_image);
     if (status) {
 	cairo_surface_destroy (&surface->base);
-	free (data);
 	return status;
     }
 
-    pixman_image_set_component_alpha (
-	surface->pixman_image,
-	pixman_image_get_component_alpha (image->pixman_image));
+    pixman_image_set_component_alpha (surface->pixman_image,
+            pixman_image_get_component_alpha (image->pixman_image));
 
     *out = surface;
     return CAIRO_STATUS_SUCCESS;
 }
 
+
 /**
  * _cairo_surface_clone_similar:
  * @surface: a #cairo_surface_t
  * @src: the source image
  * @content: target content mask
  * @src_x: extent for the rectangle in src we actually care about
  * @src_y: extent for the rectangle in src we actually care about
  * @width: extent for the rectangle in src we actually care about
@@ -1661,23 +1656,23 @@ cairo_status_t
 	    /* If we failed, try again with an image surface */
 	    status = _cairo_surface_acquire_source_image (src, &image, &image_extra);
 	    if (status == CAIRO_STATUS_SUCCESS) {
 		status = _wrap_image(src, image, image_extra, &image);
 		if (status != CAIRO_STATUS_SUCCESS) {
 		    _cairo_surface_release_source_image (src, image, image_extra);
 		} else {
 		    status =
-			surface->backend->clone_similar (surface, &image->base,
-							 content,
-							 src_x, src_y,
-							 width, height,
-							 clone_offset_x,
-							 clone_offset_y,
-							 clone_out);
+		    surface->backend->clone_similar (surface, &image->base,
+						     content,
+						     src_x, src_y,
+						     width, height,
+						     clone_offset_x,
+						     clone_offset_y,
+						     clone_out);
 		    cairo_surface_destroy(&image->base);
 		}
 	    }
 	}
     }
 
     /* If we're still unsupported, hit our fallback path to get a clone */
     if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
--- a/gfx/cairo/wrap-source_image.patch
+++ b/gfx/cairo/wrap-source_image.patch
@@ -1,102 +1,97 @@
+commit 367aa46142f7c0cf3405814487bbbbc7411b96a4
 Author: Jeff Muizelaar <jmuizelaar@mozilla.com>
+Date:   Thu Apr 23 15:42:55 2009 -0400
+
+    wrap source_image
+
 diff --git a/src/cairo-surface.c b/src/cairo-surface.c
-index 9aa707f..78ab987 100644
+index a4a7084..e4c3752 100644
 --- a/src/cairo-surface.c
 +++ b/src/cairo-surface.c
-@@ -1484,6 +1484,67 @@ _cairo_recording_surface_clone_similar (cairo_surface_t  *surface,
-     return CAIRO_STATUS_SUCCESS;
+@@ -1264,6 +1264,63 @@ _cairo_surface_release_dest_image (cairo_surface_t         *surface,
+ 					      image, image_rect, image_extra);
  }
  
 +struct acquire_source_image_data
 +{
 +    cairo_surface_t *src;
 +    cairo_image_surface_t *image;
 +    void *image_extra;
 +};
 +
 +static void
 +_wrap_release_source_image (void *data)
 +{
 +    struct acquire_source_image_data *acquire_data = data;
-+    _cairo_surface_release_source_image (acquire_data->src,
-+					 acquire_data->image,
-+					 acquire_data->image_extra);
++    _cairo_surface_release_source_image (acquire_data->src, acquire_data->image, acquire_data->image_extra);
 +    free(data);
 +}
 +
 +static cairo_status_t
 +_wrap_image (cairo_surface_t *src,
 +	     cairo_image_surface_t *image,
 +	     void *image_extra,
 +	     cairo_image_surface_t **out)
 +{
 +    static cairo_user_data_key_t wrap_image_key;
 +    cairo_image_surface_t *surface;
 +    cairo_status_t status;
 +
-+    struct acquire_source_image_data *data = malloc (sizeof (*data));
-+    if (unlikely (data == NULL))
-+	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
++    struct acquire_source_image_data *data = malloc(sizeof(*data));
 +    data->src = src;
 +    data->image = image;
 +    data->image_extra = image_extra;
 +
-+    surface = (cairo_image_surface_t *)
-+	_cairo_image_surface_create_for_pixman_image (image->pixman_image,
-+						      image->pixman_format);
++    surface = (cairo_image_surface_t*)cairo_image_surface_create_for_data (image->data,
++	    image->format,
++	    image->width,
++	    image->height,
++	    image->stride);
 +    status = surface->base.status;
++    if (status)
++	return status;
++
++    status = _cairo_user_data_array_set_data (&surface->base.user_data,
++	    &wrap_image_key,
++	    data,
++	    _wrap_release_source_image);
 +    if (status) {
-+	free (data);
++	cairo_surface_destroy (&surface->base);
 +	return status;
 +    }
 +
-+    status = _cairo_user_data_array_set_data (&surface->base.user_data,
-+					      &wrap_image_key,
-+					      data,
-+					      _wrap_release_source_image);
-+    if (status) {
-+	cairo_surface_destroy (&surface->base);
-+	free (data);
-+	return status;
-+    }
-+
-+    pixman_image_set_component_alpha (
-+	surface->pixman_image,
-+	pixman_image_get_component_alpha (surface->pixman_image));
++    pixman_image_set_component_alpha (surface->pixman_image,
++            pixman_image_get_component_alpha (surface->pixman_image));
 +
 +    *out = surface;
 +    return CAIRO_STATUS_SUCCESS;
 +}
 +
++
++
  /**
   * _cairo_surface_clone_similar:
   * @surface: a #cairo_surface_t
-@@ -1560,15 +1621,19 @@ _cairo_surface_clone_similar (cairo_surface_t  *surface,
+@@ -1342,15 +1399,19 @@ _cairo_surface_clone_similar (cairo_surface_t  *surface,
  	    /* If we failed, try again with an image surface */
  	    status = _cairo_surface_acquire_source_image (src, &image, &image_extra);
  	    if (status == CAIRO_STATUS_SUCCESS) {
 -		status =
--		    surface->backend->clone_similar (surface, &image->base,
--						     src_x, src_y,
--						     width, height,
--						     clone_offset_x,
--						     clone_offset_y,
--						     clone_out);
--
--		_cairo_surface_release_source_image (src, image, image_extra);
 +		status = _wrap_image(src, image, image_extra, &image);
 +		if (status != CAIRO_STATUS_SUCCESS) {
 +		    _cairo_surface_release_source_image (src, image, image_extra);
 +		} else {
 +		    status =
-+			surface->backend->clone_similar (surface, &image->base,
-+							 src_x, src_y,
-+							 width, height,
-+							 clone_offset_x,
-+							 clone_offset_y,
-+							 clone_out);
+ 		    surface->backend->clone_similar (surface, &image->base,
+ 						     src_x, src_y,
+ 						     width, height,
+ 						     clone_offset_x,
+ 						     clone_offset_y,
+ 						     clone_out);
+-
+-		_cairo_surface_release_source_image (src, image, image_extra);
 +		    cairo_surface_destroy(&image->base);
 +		}
  	    }
  	}
      }
--- a/gfx/thebes/public/gfxWindowsNativeDrawing.h
+++ b/gfx/thebes/public/gfxWindowsNativeDrawing.h
@@ -106,16 +106,19 @@ public:
     void TransformToNativeRect(const gfxRect& r, RECT& rout);
 
     /* Marks the end of native drawing */
     void EndNativeDrawing();
 
     /* Returns PR_TRUE if the native drawing should be executed again */
     PRBool ShouldRenderAgain();
 
+    /* Returns PR_TRUE if double pass alpha extraction is taking place. */
+    PRBool IsDoublePass();
+
     /* Places the result to the context, if necessary */
     void PaintToContext();
 
 private:
 
     nsRefPtr<gfxContext> mContext;
     gfxRect mNativeRect;
     PRUint32 mNativeDrawFlags;
--- a/gfx/thebes/src/gfxWindowsNativeDrawing.cpp
+++ b/gfx/thebes/src/gfxWindowsNativeDrawing.cpp
@@ -201,16 +201,32 @@ gfxWindowsNativeDrawing::BeginNativeDraw
         return mDC;
     } else {
         NS_ERROR("Bogus render state!");
         return nsnull;
     }
 }
 
 PRBool
+gfxWindowsNativeDrawing::IsDoublePass()
+{
+    // this is the same test we use in BeginNativeDrawing.
+    nsRefPtr<gfxASurface> surf = mContext->CurrentSurface(&mDeviceOffset.x, &mDeviceOffset.y);
+    if (!surf || surf->CairoStatus())
+        return false;
+    if ((surf->GetType() == gfxASurface::SurfaceTypeWin32 ||
+         surf->GetType() == gfxASurface::SurfaceTypeWin32Printing) &&
+        (surf->GetContentType() != gfxASurface::CONTENT_COLOR ||
+         (surf->GetContentType() == gfxASurface::CONTENT_COLOR_ALPHA &&
+          !(mNativeDrawFlags & CAN_DRAW_TO_COLOR_ALPHA))))
+        return PR_TRUE;
+    return PR_FALSE;
+}
+
+PRBool
 gfxWindowsNativeDrawing::ShouldRenderAgain()
 {
     switch (mRenderState) {
         case RENDER_STATE_NATIVE_DRAWING_DONE:
             return PR_FALSE;
 
         case RENDER_STATE_ALPHA_RECOVERY_BLACK_DONE:
             mRenderState = RENDER_STATE_ALPHA_RECOVERY_WHITE;
--- a/ipc/ipdl/ipdl/ast.py
+++ b/ipc/ipdl/ipdl/ast.py
@@ -118,17 +118,17 @@ class Loc:
         self.lineno = lineno
     def __repr__(self):
         return '%r:%r'% (self.filename, self.lineno)
     def __str__(self):
         return '%s:%s'% (self.filename, self.lineno)
 
 Loc.NONE = Loc(filename='<??>', lineno=0)
 
-class _struct():
+class _struct:
     pass
 
 class Node:
     def __init__(self, loc=Loc.NONE):
         self.loc = loc
 
     def accept(self, visitor):
         visit = getattr(visitor, 'visit'+ self.__class__.__name__, None)
--- a/layout/generic/nsObjectFrame.cpp
+++ b/layout/generic/nsObjectFrame.cpp
@@ -1667,19 +1667,36 @@ nsObjectFrame::PaintPlugin(nsIRenderingC
     NPWindow *window;
     mInstanceOwner->GetWindow(window);
 
     if (window->type == NPWindowTypeDrawable) {
       // check if we need to call SetWindow with updated parameters
       PRBool doupdatewindow = PR_FALSE;
       // the offset of the DC
       nsPoint origin;
-      
+
       gfxWindowsNativeDrawing nativeDraw(ctx, frameGfxRect);
-      PRBool doublePass = PR_FALSE;
+#ifdef MOZ_IPC
+      if (nativeDraw.IsDoublePass()) {
+        // OOP plugin specific: let the shim know before we paint if we are doing a
+        // double pass render. If this plugin isn't oop, the register window message
+        // will be ignored.
+        if (!mDoublePassEvent)
+          mDoublePassEvent = ::RegisterWindowMessage(NS_OOPP_DOUBLEPASS_MSGID);
+        if (mDoublePassEvent) {
+          NPEvent pluginEvent;
+          pluginEvent.event = mDoublePassEvent;
+          pluginEvent.wParam = 0;
+          pluginEvent.lParam = 0;
+          PRBool eventHandled = PR_FALSE;
+
+          inst->HandleEvent(&pluginEvent, &eventHandled);
+        }
+      }
+#endif
       do {
         HDC hdc = nativeDraw.BeginNativeDrawing();
         if (!hdc)
           return;
 
         RECT dest;
         nativeDraw.TransformToNativeRect(frameGfxRect, dest);
         RECT dirty;
@@ -1688,27 +1705,32 @@ nsObjectFrame::PaintPlugin(nsIRenderingC
         // XXX how can we be sure that window->window doesn't point to
         // a dead DC and hdc has been reallocated at the same address?
         if (reinterpret_cast<HDC>(window->window) != hdc ||
             window->x != dest.left || window->y != dest.top) {
           window->window = hdc;
           window->x = dest.left;
           window->y = dest.top;
 
-          // Windowless plugins on windows need a special event to update their location, see bug 135737
+          // Windowless plugins on windows need a special event to update their location,
+          // see bug 135737.
+          //
           // bug 271442: note, the rectangle we send is now purely the bounds of the plugin
-          // relative to the window it is contained in, which is useful for the plugin to correctly translate mouse coordinates
+          // relative to the window it is contained in, which is useful for the plugin to
+          // correctly translate mouse coordinates.
           //
           // this does not mesh with the comments for bug 135737 which imply that the rectangle
-          // must be clipped in some way to prevent the plugin attempting to paint over areas it shouldn't;
+          // must be clipped in some way to prevent the plugin attempting to paint over areas
+          // it shouldn't.
           //
-          // since the two uses of the rectangle are mutually exclusive in some cases,
-          // and since I don't see any incorrect painting (at least with Flash and ViewPoint - the originator of 135737),
-          // it seems that windowless plugins are not relying on information here for clipping their drawing,
-          // and we can safely use this message to tell the plugin exactly where it is in all cases.
+          // since the two uses of the rectangle are mutually exclusive in some cases, and
+          // since I don't see any incorrect painting (at least with Flash and ViewPoint -
+          // the originator of bug 135737), it seems that windowless plugins are not relying
+          // on information here for clipping their drawing, and we can safely use this message
+          // to tell the plugin exactly where it is in all cases.
 
           nsIntPoint origin = GetWindowOriginInPixels(PR_TRUE);
           nsIntRect winlessRect = nsIntRect(origin, nsIntSize(window->width, window->height));
           // XXX I don't think we can be certain that the location wrt to
           // the window only changes when the location wrt to the drawable
           // changes, but the hdc probably changes on every paint so
           // doupdatewindow is rarely false, and there is not likely to be
           // a problem.
@@ -1727,42 +1749,21 @@ nsObjectFrame::PaintPlugin(nsIRenderingC
             pluginEvent.event = WM_WINDOWPOSCHANGED;
             pluginEvent.wParam = 0;
             pluginEvent.lParam = (uint32)&winpos;
             PRBool eventHandled = PR_FALSE;
 
             inst->HandleEvent(&pluginEvent, &eventHandled);
           }
 
-          inst->SetWindow(window);        
+          inst->SetWindow(window);
         }
-
         mInstanceOwner->Paint(dirty, hdc);
         nativeDraw.EndNativeDrawing();
-        doublePass = nativeDraw.ShouldRenderAgain();
-#ifdef MOZ_IPC
-        if (doublePass) {
-          // OOP plugin specific: let the shim know we are in the middle of a double pass
-          // render. The second pass will reuse the previous rendering without going over
-          // the wire.
-          if (!mDoublePassEvent)
-            mDoublePassEvent = ::RegisterWindowMessage(NS_OOPP_DOUBLEPASS_MSGID);
-          if (mDoublePassEvent) {
-            NPEvent pluginEvent;
-            pluginEvent.event = mDoublePassEvent;
-            pluginEvent.wParam = 0;
-            pluginEvent.lParam = 0;
-            PRBool eventHandled = PR_FALSE;
-
-            inst->HandleEvent(&pluginEvent, &eventHandled);
-          }          
-        }
-#endif
-      } while (doublePass);
-
+      } while (nativeDraw.ShouldRenderAgain());
       nativeDraw.PaintToContext();
     } else if (!(ctx->GetFlags() & gfxContext::FLAG_DESTINED_FOR_SCREEN)) {
       // Get PrintWindow dynamically since it's not present on Win2K,
       // which we still support
       typedef BOOL (WINAPI * PrintWindowPtr)
           (HWND hwnd, HDC hdcBlt, UINT nFlags);
       PrintWindowPtr printProc = nsnull;
       HMODULE module = ::GetModuleHandleW(L"user32.dll");
--- a/modules/plugin/base/src/Makefile.in
+++ b/modules/plugin/base/src/Makefile.in
@@ -52,16 +52,17 @@ GRE_MODULE	= 1
 LIBXUL_LIBRARY = 1
 
 CPPSRCS		= \
 		nsNPAPIPlugin.cpp \
 		nsNPAPIPluginInstance.cpp \
 		nsPluginHost.cpp \
 		nsPluginModule.cpp \
 		nsJSNPRuntime.cpp \
+		nsPluginTags.cpp \
 		$(NULL)
 
 ifeq ($(OS_ARCH), BeOS)
 	CPPSRCS += nsPluginsDirBeOS.cpp
 	CPPSRCS += nsPluginNativeWindow.cpp
 else
 ifneq (,$(filter WINNT WINCE,$(OS_ARCH)))
 	CPPSRCS += nsPluginsDirWin.cpp
--- a/modules/plugin/base/src/nsNPAPIPlugin.cpp
+++ b/modules/plugin/base/src/nsNPAPIPlugin.cpp
@@ -219,29 +219,29 @@ nsNPAPIPlugin::CheckClassInitialized(voi
 }
 
 NS_IMPL_ISUPPORTS1(nsNPAPIPlugin, nsIPlugin)
 
 nsNPAPIPlugin::nsNPAPIPlugin(NPPluginFuncs* callbacks, 
                              PluginLibrary* aLibrary)
 {
   memset((void*) &fCallbacks, 0, sizeof(fCallbacks));
+
+  fCallbacks.size = sizeof(fCallbacks);
   fLibrary = nsnull;
 
 #if defined(XP_WIN) || defined(XP_OS2)
   // On Windows (and Mac) we need to keep a direct reference to the
   // fCallbacks and NOT just copy the struct. See Bugzilla 85334
 
   NPError gepError;
   nsresult gepResult = aLibrary->NP_GetEntryPoints(&fCallbacks, &gepError);
   if (gepResult != NS_OK || gepError != NPERR_NO_ERROR)
     return;
 
-  fCallbacks.size = sizeof(fCallbacks);
-
   NS_ASSERTION(HIBYTE(fCallbacks.version) >= NP_VERSION_MAJOR,
                "callback version is less than NP version");
 
 #elif defined(XP_MACOSX)
   NPPluginFuncs np_callbacks;
   memset((void*) &np_callbacks, 0, sizeof(np_callbacks));
   np_callbacks.size = sizeof(np_callbacks);
 
@@ -256,17 +256,16 @@ nsNPAPIPlugin::nsNPAPIPlugin(NPPluginFun
   nsresult initResult = aLibrary->NP_Initialize(&(nsNPAPIPlugin::CALLBACKS), &initError);
   if (initResult != NS_OK || initError != NPERR_NO_ERROR)
     return;
   NPError gepError;
   nsresult gepResult = aLibrary->NP_GetEntryPoints(&np_callbacks, &gepError);
   if (gepResult != NS_OK || gepError != NPERR_NO_ERROR)
     return;
 
-  fCallbacks.size = sizeof(fCallbacks);
   fCallbacks.version = np_callbacks.version;
   fCallbacks.newp = (NPP_NewProcPtr)np_callbacks.newp;
   fCallbacks.destroy = (NPP_DestroyProcPtr)np_callbacks.destroy;
   fCallbacks.setwindow = (NPP_SetWindowProcPtr)np_callbacks.setwindow;
   fCallbacks.newstream = (NPP_NewStreamProcPtr)np_callbacks.newstream;
   fCallbacks.destroystream = (NPP_DestroyStreamProcPtr)np_callbacks.destroystream;
   fCallbacks.asfile = (NPP_StreamAsFileProcPtr)np_callbacks.asfile;
   fCallbacks.writeready = (NPP_WriteReadyProcPtr)np_callbacks.writeready;
--- a/modules/plugin/base/src/nsPluginHost.cpp
+++ b/modules/plugin/base/src/nsPluginHost.cpp
@@ -87,17 +87,16 @@
 #include "nsPrintfCString.h"
 #include "nsIBlocklistService.h"
 #include "nsVersionComparator.h"
 #include "nsIPrivateBrowsingService.h"
 
 #include "nsEnumeratorUtils.h"
 #include "nsXPCOM.h"
 #include "nsXPCOMCID.h"
-#include "nsICategoryManager.h"
 #include "nsISupportsPrimitives.h"
 
 // for the dialog
 #include "nsIStringBundle.h"
 #include "nsIWindowWatcher.h"
 #include "nsPIDOMWindow.h"
 
 #include "nsIScriptGlobalObject.h"
@@ -221,18 +220,16 @@ PRLogModuleInfo* nsPluginLogging::gPlugi
 #define PLUGIN_PROPERTIES_URL "chrome://global/locale/downloadProgress.properties"
 
 // #defines for plugin cache and prefs
 #define NS_PREF_MAX_NUM_CACHED_PLUGINS "browser.plugins.max_num_cached_plugins"
 #define DEFAULT_NUMBER_OF_STOPPED_PLUGINS 10
 
 #define MAGIC_REQUEST_CONTEXT 0x01020304
 
-nsresult PostPluginUnloadEvent(PRLibrary * aLibrary);
-
 static nsPluginInstanceTagList *gActivePluginList;
 
 #ifdef CALL_SAFETY_ON
 PRBool gSkipPluginSafeCalls = PR_FALSE;
 #endif
 
 nsIFile *nsPluginHost::sPluginTempDir;
 nsPluginHost *nsPluginHost::sInst;
@@ -304,629 +301,16 @@ NS_IMETHODIMP nsPluginDocReframeEvent::R
 
       }
     }
   }
 
   return mDocs->Clear();
 }
 
-nsPluginInstanceTag::nsPluginInstanceTag(nsPluginTag* aPluginTag,
-                               nsIPluginInstance* aInstance,
-                               const char * url,
-                               PRBool aDefaultPlugin)
-{
-  mNext = nsnull;
-  mPluginTag = aPluginTag;
-
-  mURL = PL_strdup(url);
-  mInstance = aInstance;
-  if (aInstance)
-    NS_ADDREF(aInstance);
-  mXPConnected = PR_FALSE;
-  mDefaultPlugin = aDefaultPlugin;
-  mStopped = PR_FALSE;
-  mllStopTime = LL_ZERO;
-}
-
-nsPluginInstanceTag::~nsPluginInstanceTag()
-{
-  mPluginTag = nsnull;
-  if (mInstance) {
-    nsCOMPtr<nsIPluginInstanceOwner> owner;
-    mInstance->GetOwner(getter_AddRefs(owner));
-    if (owner)
-      owner->SetInstance(nsnull);
-    mInstance->InvalidateOwner();
-
-    NS_RELEASE(mInstance);
-  }
-  PL_strfree(mURL);
-}
-
-void nsPluginInstanceTag::setStopped(PRBool stopped)
-{
-  mStopped = stopped;
-  if (mStopped) // plugin instance is told to stop
-    mllStopTime = PR_Now();
-  else
-    mllStopTime = LL_ZERO;
-}
-
-nsPluginInstanceTagList::nsPluginInstanceTagList()
-{
-  mFirst = nsnull;
-  mLast = nsnull;
-  mCount = 0;
-}
-
-nsPluginInstanceTagList::~nsPluginInstanceTagList()
-{
-  if (!mFirst)
-    return;
-  shutdown();
-}
-
-void nsPluginInstanceTagList::shutdown()
-{
-  if (!mFirst)
-    return;
-
-  for (nsPluginInstanceTag * plugin = mFirst; plugin != nsnull;) {
-    nsPluginInstanceTag * next = plugin->mNext;
-    remove(plugin);
-    plugin = next;
-  }
-  mFirst = nsnull;
-  mLast = nsnull;
-}
-
-PRInt32 nsPluginInstanceTagList::add(nsPluginInstanceTag * plugin)
-{
-  if (!mFirst) {
-    mFirst = plugin;
-    mLast = plugin;
-    mFirst->mNext = nsnull;
-  }
-  else {
-    mLast->mNext = plugin;
-    mLast = plugin;
-  }
-  mLast->mNext = nsnull;
-  mCount++;
-  return mCount;
-}
-
-PRBool nsPluginInstanceTagList::IsLastInstance(nsPluginInstanceTag * plugin)
-{
-  if (!plugin)
-    return PR_FALSE;
-
-  if (!plugin->mPluginTag)
-    return PR_FALSE;
-
-  for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
-    if ((p->mPluginTag == plugin->mPluginTag) && (p != plugin))
-      return PR_FALSE;
-  }
-  return PR_TRUE;
-}
-
-PRBool nsPluginInstanceTagList::remove(nsPluginInstanceTag * plugin)
-{
-  if (!mFirst)
-    return PR_FALSE;
-
-  nsPluginInstanceTag * prev = nsnull;
-  for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
-    if (p == plugin) {
-      PRBool lastInstance = IsLastInstance(p);
-
-      if (p == mFirst)
-        mFirst = p->mNext;
-      else
-        prev->mNext = p->mNext;
-
-      if (prev && !prev->mNext)
-        mLast = prev;
-
-      if (lastInstance) {
-        nsRefPtr<nsPluginTag> pluginTag = p->mPluginTag;
-
-        delete p;
-
-        if (pluginTag) {
-          nsresult rv;
-          nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
-          NS_ENSURE_SUCCESS(rv, rv);
-
-          PRBool unloadPluginsASAP = PR_FALSE;
-          rv = pref->GetBoolPref("plugins.unloadASAP", &unloadPluginsASAP);
-          if (NS_SUCCEEDED(rv) && unloadPluginsASAP)
-            pluginTag->TryUnloadPlugin();
-        } else {
-          NS_ASSERTION(pluginTag, "pluginTag was not set, plugin not shutdown");
-        }
-      } else {
-        delete p;
-      }
-
-      mCount--;
-      return PR_TRUE;
-    }
-    prev = p;
-  }
-  return PR_FALSE;
-}
-
-// This method terminates all running instances of plugins and collects their
-// documents to be returned through an array. This method is used
-// when we are shutting down or when a plugins.refresh(1) happens.
-// If aPluginTag is given, then only that plugin is terminated
-void nsPluginInstanceTagList::stopRunning(nsISupportsArray* aReloadDocs,
-                                     nsPluginTag* aPluginTag)
-{
-  if (!mFirst)
-    return;
-
-  for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
-    if (!p->mStopped && p->mInstance &&
-       (!aPluginTag || aPluginTag == p->mPluginTag)) {
-      p->mInstance->SetWindow(nsnull);
-      p->mInstance->Stop();
-      p->setStopped(PR_TRUE);
-
-      // If we've been passed an array to return, lets collect all our documents,
-      // removing duplicates. These will be reframed (embedded) or reloaded (full-page) later
-      // to kickstart our instances.
-      if (aReloadDocs && p->mInstance) {
-        nsCOMPtr<nsIPluginInstanceOwner> owner;
-        p->mInstance->GetOwner(getter_AddRefs(owner));
-        if (owner) {
-          nsCOMPtr<nsIDocument> doc;
-          owner->GetDocument(getter_AddRefs(doc));
-          if (doc && aReloadDocs->IndexOf(doc) == -1)  // don't allow for duplicates
-            aReloadDocs->AppendElement(doc);
-        }
-      }
-    }
-  }
-}
-
-void nsPluginInstanceTagList::removeAllStopped()
-{
-  if (!mFirst)
-    return;
-
-  nsPluginInstanceTag * next = nsnull;
-
-  for (nsPluginInstanceTag * p = mFirst; p != nsnull;) {
-    next = p->mNext;
-
-    if (p->mStopped)
-      remove(p);
-
-    p = next;
-  }
-  return;
-}
-
-nsPluginInstanceTag * nsPluginInstanceTagList::find(nsIPluginInstance* instance)
-{
-  for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
-    if (p->mInstance == instance)
-      return p;
-  }
-  return nsnull;
-}
-
-nsPluginInstanceTag * nsPluginInstanceTagList::find(const char * mimetype)
-{
-  PRBool defaultplugin = (PL_strcmp(mimetype, "*") == 0);
-
-  for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
-    // give it some special treatment for the default plugin first
-    // because we cannot tell the default plugin by asking instance for a mime type
-    if (defaultplugin && p->mDefaultPlugin)
-      return p;
-
-    if (!p->mInstance)
-      continue;
-
-    const char* mt;
-    nsresult rv = p->mInstance->GetMIMEType(&mt);
-    if (NS_FAILED(rv))
-      continue;
-
-    if (PL_strcasecmp(mt, mimetype) == 0)
-      return p;
-  }
-  return nsnull;
-}
-
-nsPluginInstanceTag * nsPluginInstanceTagList::findStopped(const char * url)
-{
-  for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
-    if (!PL_strcmp(url, p->mURL) && p->mStopped)
-       return p;
-  }
-  return nsnull;
-}
-
-PRUint32 nsPluginInstanceTagList::getStoppedCount()
-{
-  PRUint32 stoppedCount = 0;
-  for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
-    if (p->mStopped)
-      stoppedCount++;
-  }
-  return stoppedCount;
-}
-
-nsPluginInstanceTag * nsPluginInstanceTagList::findOldestStopped()
-{
-  nsPluginInstanceTag * res = nsnull;
-  PRInt64 llTime = LL_MAXINT;
-  for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
-    if (!p->mStopped)
-      continue;
-
-    if (LL_CMP(p->mllStopTime, <, llTime)) {
-      llTime = p->mllStopTime;
-      res = p;
-    }
-  }
-
-  return res;
-}
-
-inline char* new_str(const char* str)
-{
-  if (str == nsnull)
-    return nsnull;
-
-  char* result = new char[strlen(str) + 1];
-  if (result != nsnull)
-    return strcpy(result, str);
-  return result;
-}
-
-nsPluginTag::nsPluginTag(nsPluginTag* aPluginTag)
-  : mPluginHost(nsnull),
-    mName(aPluginTag->mName),
-    mDescription(aPluginTag->mDescription),
-    mVariants(aPluginTag->mVariants),
-    mMimeTypeArray(nsnull),
-    mMimeDescriptionArray(aPluginTag->mMimeDescriptionArray),
-    mExtensionsArray(nsnull),
-    mLibrary(nsnull),
-    mCanUnloadLibrary(PR_TRUE),
-    mXPConnected(PR_FALSE),
-    mIsJavaPlugin(aPluginTag->mIsJavaPlugin),
-    mIsNPRuntimeEnabledJavaPlugin(aPluginTag->mIsNPRuntimeEnabledJavaPlugin),
-    mFileName(aPluginTag->mFileName),
-    mFullPath(aPluginTag->mFullPath),
-    mVersion(aPluginTag->mVersion),
-    mLastModifiedTime(0),
-    mFlags(NS_PLUGIN_FLAG_ENABLED)
-{
-  if (aPluginTag->mMimeTypeArray != nsnull) {
-    mMimeTypeArray = new char*[mVariants];
-    for (int i = 0; i < mVariants; i++)
-      mMimeTypeArray[i] = new_str(aPluginTag->mMimeTypeArray[i]);
-  }
-
-  if (aPluginTag->mExtensionsArray != nsnull) {
-    mExtensionsArray = new char*[mVariants];
-    for (int i = 0; i < mVariants; i++)
-      mExtensionsArray[i] = new_str(aPluginTag->mExtensionsArray[i]);
-  }
-}
-
-nsPluginTag::nsPluginTag(nsPluginInfo* aPluginInfo)
-  : mPluginHost(nsnull),
-    mName(aPluginInfo->fName),
-    mDescription(aPluginInfo->fDescription),
-    mVariants(aPluginInfo->fVariantCount),
-    mMimeTypeArray(nsnull),
-    mExtensionsArray(nsnull),
-    mLibrary(nsnull),
-#ifdef XP_MACOSX
-    mCanUnloadLibrary(!aPluginInfo->fBundle),
-#else
-    mCanUnloadLibrary(PR_TRUE),
-#endif
-    mXPConnected(PR_FALSE),
-    mIsJavaPlugin(PR_FALSE),
-    mIsNPRuntimeEnabledJavaPlugin(PR_FALSE),
-    mFileName(aPluginInfo->fFileName),
-    mFullPath(aPluginInfo->fFullPath),
-    mVersion(aPluginInfo->fVersion),
-    mLastModifiedTime(0),
-    mFlags(NS_PLUGIN_FLAG_ENABLED)
-{
-  if (aPluginInfo->fMimeTypeArray != nsnull) {
-    mMimeTypeArray = new char*[mVariants];
-    for (int i = 0; i < mVariants; i++) {
-      if (mIsJavaPlugin && aPluginInfo->fMimeTypeArray[i] &&
-          strcmp(aPluginInfo->fMimeTypeArray[i],
-                 "application/x-java-vm-npruntime") == 0) {
-        mIsNPRuntimeEnabledJavaPlugin = PR_TRUE;
-
-        // Stop processing here, any mimetypes after the magic "I'm a
-        // NPRuntime enabled Java plugin" mimetype will be ignored.
-        mVariants = i;
-
-        break;
-      }
-
-      mMimeTypeArray[i] = new_str(aPluginInfo->fMimeTypeArray[i]);
-      if (nsPluginHost::IsJavaMIMEType(mMimeTypeArray[i]))
-        mIsJavaPlugin = PR_TRUE;
-    }
-  }
-
-  if (aPluginInfo->fMimeDescriptionArray != nsnull) {
-    for (int i = 0; i < mVariants; i++) {
-      // we should cut off the list of suffixes which the mime
-      // description string may have, see bug 53895
-      // it is usually in form "some description (*.sf1, *.sf2)"
-      // so we can search for the opening round bracket
-      char cur = '\0';
-      char pre = '\0';
-      char * p = PL_strrchr(aPluginInfo->fMimeDescriptionArray[i], '(');
-      if (p && (p != aPluginInfo->fMimeDescriptionArray[i])) {
-        if ((p - 1) && *(p - 1) == ' ') {
-          pre = *(p - 1);
-          *(p - 1) = '\0';
-        } else {
-          cur = *p;
-          *p = '\0';
-        }
-
-      }
-      mMimeDescriptionArray.AppendElement(
-        aPluginInfo->fMimeDescriptionArray[i]);
-      // restore the original string
-      if (cur != '\0')
-        *p = cur;
-      if (pre != '\0')
-        *(p - 1) = pre;
-    }
-  } else {
-    mMimeDescriptionArray.SetLength(mVariants);
-  }
-
-  if (aPluginInfo->fExtensionArray != nsnull) {
-    mExtensionsArray = new char*[mVariants];
-    for (int i = 0; i < mVariants; i++)
-      mExtensionsArray[i] = new_str(aPluginInfo->fExtensionArray[i]);
-  }
-
-  EnsureMembersAreUTF8();
-}
-
-nsPluginTag::nsPluginTag(const char* aName,
-                         const char* aDescription,
-                         const char* aFileName,
-                         const char* aFullPath,
-                         const char* aVersion,
-                         const char* const* aMimeTypes,
-                         const char* const* aMimeDescriptions,
-                         const char* const* aExtensions,
-                         PRInt32 aVariants,
-                         PRInt64 aLastModifiedTime,
-                         PRBool aCanUnload,
-                         PRBool aArgsAreUTF8)
-  : mPluginHost(nsnull),
-    mName(aName),
-    mDescription(aDescription),
-    mVariants(aVariants),
-    mMimeTypeArray(nsnull),
-    mExtensionsArray(nsnull),
-    mLibrary(nsnull),
-    mCanUnloadLibrary(aCanUnload),
-    mXPConnected(PR_FALSE),
-    mIsJavaPlugin(PR_FALSE),
-    mIsNPRuntimeEnabledJavaPlugin(PR_FALSE),
-    mFileName(aFileName),
-    mFullPath(aFullPath),
-    mVersion(aVersion),
-    mLastModifiedTime(aLastModifiedTime),
-    mFlags(0) // Caller will read in our flags from cache
-{
-  if (aVariants) {
-    mMimeTypeArray        = new char*[mVariants];
-    mExtensionsArray      = new char*[mVariants];
-
-    for (PRInt32 i = 0; i < aVariants; ++i) {
-      if (mIsJavaPlugin && aMimeTypes[i] &&
-          strcmp(aMimeTypes[i], "application/x-java-vm-npruntime") == 0) {
-        mIsNPRuntimeEnabledJavaPlugin = PR_TRUE;
-
-        // Stop processing here, any mimetypes after the magic "I'm a
-        // NPRuntime enabled Java plugin" mimetype will be ignored.
-        mVariants = i;
-
-        break;
-      }
-
-      mMimeTypeArray[i]        = new_str(aMimeTypes[i]);
-      mMimeDescriptionArray.AppendElement(aMimeDescriptions[i]);
-      mExtensionsArray[i]      = new_str(aExtensions[i]);
-      if (nsPluginHost::IsJavaMIMEType(mMimeTypeArray[i]))
-        mIsJavaPlugin = PR_TRUE;
-    }
-  }
-
-  if (!aArgsAreUTF8)
-    EnsureMembersAreUTF8();
-}
-
-nsPluginTag::~nsPluginTag()
-{
-  NS_ASSERTION(!mNext, "Risk of exhausting the stack space, bug 486349");
-
-  if (mMimeTypeArray) {
-    for (int i = 0; i < mVariants; i++)
-      delete[] mMimeTypeArray[i];
-
-    delete[] (mMimeTypeArray);
-    mMimeTypeArray = nsnull;
-  }
-
-  if (mExtensionsArray) {
-    for (int i = 0; i < mVariants; i++)
-      delete[] mExtensionsArray[i];
-
-    delete[] (mExtensionsArray);
-    mExtensionsArray = nsnull;
-  }
-}
-
-NS_IMPL_ISUPPORTS1(nsPluginTag, nsIPluginTag)
-
-static nsresult ConvertToUTF8(nsIUnicodeDecoder *aUnicodeDecoder,
-                              nsAFlatCString& aString)
-{
-  PRInt32 numberOfBytes = aString.Length();
-  PRInt32 outUnicodeLen;
-  nsAutoString buffer;
-  nsresult rv = aUnicodeDecoder->GetMaxLength(aString.get(), numberOfBytes,
-                                              &outUnicodeLen);
-  NS_ENSURE_SUCCESS(rv, rv);
-  if (!EnsureStringLength(buffer, outUnicodeLen))
-    return NS_ERROR_OUT_OF_MEMORY;
-  rv = aUnicodeDecoder->Convert(aString.get(), &numberOfBytes,
-                                buffer.BeginWriting(), &outUnicodeLen);
-  NS_ENSURE_SUCCESS(rv, rv);
-  buffer.SetLength(outUnicodeLen);
-  CopyUTF16toUTF8(buffer, aString);
-
-  return NS_OK;
-}
-
-nsresult nsPluginTag::EnsureMembersAreUTF8()
-{
-  nsresult rv;
-
-  nsCOMPtr<nsIPlatformCharset> pcs =
-    do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-  nsCOMPtr<nsIUnicodeDecoder> decoder;
-  nsCOMPtr<nsICharsetConverterManager> ccm =
-    do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCAutoString charset;
-  rv = pcs->GetCharset(kPlatformCharsetSel_FileName, charset);
-  NS_ENSURE_SUCCESS(rv, rv);
-  if (!charset.LowerCaseEqualsLiteral("utf-8")) {
-    rv = ccm->GetUnicodeDecoderRaw(charset.get(), getter_AddRefs(decoder));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    ConvertToUTF8(decoder, mFileName);
-    ConvertToUTF8(decoder, mFullPath);
-  }
-
-  // The description of the plug-in and the various MIME type descriptions
-  // should be encoded in the standard plain text file encoding for this system.
-  // XXX should we add kPlatformCharsetSel_PluginResource?
-  rv = pcs->GetCharset(kPlatformCharsetSel_PlainTextInFile, charset);
-  NS_ENSURE_SUCCESS(rv, rv);
-  if (!charset.LowerCaseEqualsLiteral("utf-8")) {
-    rv = ccm->GetUnicodeDecoderRaw(charset.get(), getter_AddRefs(decoder));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    ConvertToUTF8(decoder, mName);
-    ConvertToUTF8(decoder, mDescription);
-    for (PRUint32 i = 0; i < mMimeDescriptionArray.Length(); ++i) {
-      ConvertToUTF8(decoder, mMimeDescriptionArray[i]);
-    }
-  }
-  return NS_OK;
-}
-
-void nsPluginTag::SetHost(nsPluginHost * aHost)
-{
-  mPluginHost = aHost;
-}
-
-NS_IMETHODIMP
-nsPluginTag::GetDescription(nsACString& aDescription)
-{
-  aDescription = mDescription;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsPluginTag::GetFilename(nsACString& aFileName)
-{
-  aFileName = mFileName;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsPluginTag::GetVersion(nsACString& aVersion)
-{
-  aVersion = mVersion;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsPluginTag::GetName(nsACString& aName)
-{
-  aName = mName;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsPluginTag::GetDisabled(PRBool* aDisabled)
-{
-  *aDisabled = !HasFlag(NS_PLUGIN_FLAG_ENABLED);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsPluginTag::SetDisabled(PRBool aDisabled)
-{
-  if (HasFlag(NS_PLUGIN_FLAG_ENABLED) == !aDisabled)
-    return NS_OK;
-
-  if (aDisabled)
-    UnMark(NS_PLUGIN_FLAG_ENABLED);
-  else
-    Mark(NS_PLUGIN_FLAG_ENABLED);
-
-  mPluginHost->UpdatePluginInfo(this);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsPluginTag::GetBlocklisted(PRBool* aBlocklisted)
-{
-  *aBlocklisted = HasFlag(NS_PLUGIN_FLAG_BLOCKLISTED);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
-nsPluginTag::SetBlocklisted(PRBool aBlocklisted)
-{
-  if (HasFlag(NS_PLUGIN_FLAG_BLOCKLISTED) == aBlocklisted)
-    return NS_OK;
-
-  if (aBlocklisted)
-    Mark(NS_PLUGIN_FLAG_BLOCKLISTED);
-  else
-    UnMark(NS_PLUGIN_FLAG_BLOCKLISTED);
-
-  mPluginHost->UpdatePluginInfo(nsnull);
-  return NS_OK;
-}
-
 // helper struct for asynchronous handling of plugin unloading
 class nsPluginUnloadEvent : public nsRunnable {
 public:
   nsPluginUnloadEvent(PRLibrary* aLibrary)
     : mLibrary(aLibrary)
   {}
  
   NS_DECL_NSIRUNNABLE
@@ -941,121 +325,28 @@ NS_IMETHODIMP nsPluginUnloadEvent::Run()
     NS_TRY_SAFE_CALL_VOID(PR_UnloadLibrary(mLibrary), nsnull, nsnull);
   } else {
     NS_WARNING("missing library from nsPluginUnloadEvent");
   }
   return NS_OK;
 }
 
 // unload plugin asynchronously if possible, otherwise just unload now
-nsresult PostPluginUnloadEvent(PRLibrary* aLibrary)
+nsresult nsPluginHost::PostPluginUnloadEvent(PRLibrary* aLibrary)
 {
   nsCOMPtr<nsIRunnable> ev = new nsPluginUnloadEvent(aLibrary);
   if (ev && NS_SUCCEEDED(NS_DispatchToCurrentThread(ev)))
     return NS_OK;
 
   // failure case
   NS_TRY_SAFE_CALL_VOID(PR_UnloadLibrary(aLibrary), nsnull, nsnull);
 
   return NS_ERROR_FAILURE;
 }
 
-void nsPluginTag::TryUnloadPlugin()
-{
-  if (mEntryPoint) {
-    mEntryPoint->Shutdown();
-    mEntryPoint = nsnull;
-  }
-
-  // before we unload check if we are allowed to, see bug #61388
-  if (mLibrary && mCanUnloadLibrary) {
-    // NPAPI plugins can be unloaded now if they don't use XPConnect
-    if (!mXPConnected) {
-      // unload the plugin asynchronously by posting a PLEvent
-      PostPluginUnloadEvent(mLibrary);
-    }
-    else {
-      // add library to the unused library list to handle it later
-      if (mPluginHost)
-        mPluginHost->AddUnusedLibrary(mLibrary);
-    }
-  }
-
-  // we should zero it anyway, it is going to be unloaded by
-  // CleanUnsedLibraries before we need to call the library
-  // again so the calling code should not be fooled and reload
-  // the library fresh
-  mLibrary = nsnull;
-
-  // Remove mime types added to the category manager
-  // only if we were made 'active' by setting the host
-  if (mPluginHost) {
-    RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginUnregister);
-  }
-}
-
-void nsPluginTag::Mark(PRUint32 mask)
-{
-  PRBool wasEnabled = IsEnabled();
-  mFlags |= mask;
-  // Update entries in the category manager if necessary.
-  if (mPluginHost && wasEnabled != IsEnabled()) {
-    if (wasEnabled)
-      RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginUnregister);
-    else
-      RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginRegister);
-  }
-}
-
-void nsPluginTag::UnMark(PRUint32 mask)
-{
-  PRBool wasEnabled = IsEnabled();
-  mFlags &= ~mask;
-  // Update entries in the category manager if necessary.
-  if (mPluginHost && wasEnabled != IsEnabled()) {
-    if (wasEnabled)
-      RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginUnregister);
-    else
-      RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginRegister);
-  }
-}
-
-PRBool nsPluginTag::HasFlag(PRUint32 flag)
-{
-  return (mFlags & flag) != 0;
-}
-
-PRUint32 nsPluginTag::Flags()
-{
-  return mFlags;
-}
-
-PRBool nsPluginTag::IsEnabled()
-{
-  return HasFlag(NS_PLUGIN_FLAG_ENABLED) && !HasFlag(NS_PLUGIN_FLAG_BLOCKLISTED);
-}
-
-PRBool nsPluginTag::Equals(nsPluginTag *aPluginTag)
-{
-  NS_ENSURE_TRUE(aPluginTag, PR_FALSE);
-
-  if ((!mName.Equals(aPluginTag->mName)) ||
-      (!mDescription.Equals(aPluginTag->mDescription)) ||
-      (mVariants != aPluginTag->mVariants))
-    return PR_FALSE;
-
-  if (mVariants && mMimeTypeArray && aPluginTag->mMimeTypeArray) {
-    for (PRInt32 i = 0; i < mVariants; i++) {
-      if (PL_strcmp(mMimeTypeArray[i], aPluginTag->mMimeTypeArray[i]) != 0)
-        return PR_FALSE;
-    }
-  }
-  return PR_TRUE;
-}
-
 class nsPluginStreamListenerPeer;
 
 class nsPluginStreamInfo : public nsINPAPIPluginStreamInfo
 {
 public:
   nsPluginStreamInfo();
   virtual ~nsPluginStreamInfo();
 
@@ -3340,90 +2631,16 @@ nsresult nsPluginHost::AddInstanceToActi
 
   if (!plugin)
     return NS_ERROR_OUT_OF_MEMORY;
 
   mPluginInstanceTagList.add(plugin);
   return NS_OK;
 }
 
-void
-nsPluginTag::RegisterWithCategoryManager(PRBool aOverrideInternalTypes,
-                                         nsPluginTag::nsRegisterType aType)
-{
-  if (!mMimeTypeArray)
-    return;
-
-  PLUGIN_LOG(PLUGIN_LOG_NORMAL,
-  ("nsPluginTag::RegisterWithCategoryManager plugin=%s, removing = %s\n",
-  mFileName.get(), aType == ePluginUnregister ? "yes" : "no"));
-
-  nsCOMPtr<nsICategoryManager> catMan = do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
-  if (!catMan)
-    return;
-
-  const char *contractId = "@mozilla.org/content/plugin/document-loader-factory;1";
-
-  nsCOMPtr<nsIPrefBranch> psvc(do_GetService(NS_PREFSERVICE_CONTRACTID));
-  if (!psvc)
-    return; // NS_ERROR_OUT_OF_MEMORY
-
-  // A preference controls whether or not the full page plugin is disabled for
-  // a particular type. The string must be in the form:
-  //   type1,type2,type3,type4
-  // Note: need an actual interface to control this and subsequent disabling 
-  // (and other plugin host settings) so applications can reliably disable 
-  // plugins - without relying on implementation details such as prefs/category
-  // manager entries.
-  nsXPIDLCString overrideTypes;
-  psvc->GetCharPref("plugin.disable_full_page_plugin_for_types", getter_Copies(overrideTypes));
-  nsCAutoString overrideTypesFormatted;
-  overrideTypesFormatted.Assign(',');
-  overrideTypesFormatted += overrideTypes;
-  overrideTypesFormatted.Append(',');
-
-  nsACString::const_iterator start, end;
-  for (int i = 0; i < mVariants; i++) {
-    if (aType == ePluginUnregister) {
-      nsXPIDLCString value;
-      if (NS_SUCCEEDED(catMan->GetCategoryEntry("Gecko-Content-Viewers",
-                                                mMimeTypeArray[i],
-                                                getter_Copies(value)))) {
-        // Only delete the entry if a plugin registered for it
-        if (strcmp(value, contractId) == 0) {
-          catMan->DeleteCategoryEntry("Gecko-Content-Viewers",
-                                      mMimeTypeArray[i],
-                                      PR_TRUE);
-        }
-      }
-    } else {
-      overrideTypesFormatted.BeginReading(start);
-      overrideTypesFormatted.EndReading(end);
-      
-      nsDependentCString mimeType(mMimeTypeArray[i]);
-      nsCAutoString commaSeparated; 
-      commaSeparated.Assign(',');
-      commaSeparated += mimeType;
-      commaSeparated.Append(',');
-      if (!FindInReadable(commaSeparated, start, end)) {
-        catMan->AddCategoryEntry("Gecko-Content-Viewers",
-                                 mMimeTypeArray[i],
-                                 contractId,
-                                 PR_FALSE, /* persist: broken by bug 193031 */
-                                 aOverrideInternalTypes, /* replace if we're told to */
-                                 nsnull);
-      }
-    }
-
-    PLUGIN_LOG(PLUGIN_LOG_NOISY,
-    ("nsPluginTag::RegisterWithCategoryManager mime=%s, plugin=%s\n",
-    mMimeTypeArray[i], mFileName.get()));
-  }
-}
-
 NS_IMETHODIMP nsPluginHost::SetUpPluginInstance(const char *aMimeType,
                                                 nsIURI *aURL,
                                                 nsIPluginInstanceOwner *aOwner)
 {
   nsresult rv = NS_OK;
 
   rv = TrySetUpPluginInstance(aMimeType, aURL, aOwner);
 
--- a/modules/plugin/base/src/nsPluginHost.h
+++ b/modules/plugin/base/src/nsPluginHost.h
@@ -55,144 +55,27 @@
 #include "nsIPrompt.h"
 #include "nsISupportsArray.h"
 #include "nsIPrefBranch.h"
 #include "nsWeakReference.h"
 #include "nsThreadUtils.h"
 #include "nsTArray.h"
 #include "nsTObserverArray.h"
 #include "nsITimer.h"
+#include "nsPluginTags.h"
 
 class nsNPAPIPlugin;
 class nsIComponentManager;
 class nsIFile;
 class nsIChannel;
-class nsPluginHost;
-
-// Remember that flags are written out to pluginreg.dat, be careful
-// changing their meaning.
-#define NS_PLUGIN_FLAG_ENABLED      0x0001    // is this plugin enabled?
-// no longer used                   0x0002    // reuse only if regenerating pluginreg.dat
-#define NS_PLUGIN_FLAG_FROMCACHE    0x0004    // this plugintag info was loaded from cache
-#define NS_PLUGIN_FLAG_UNWANTED     0x0008    // this is an unwanted plugin
-#define NS_PLUGIN_FLAG_BLOCKLISTED  0x0010    // this is a blocklisted plugin
 
 #if defined(XP_MACOSX) && !defined(NP_NO_CARBON)
 #define MAC_CARBON_PLUGINS
 #endif
 
-// A linked-list of plugin information that is used for instantiating plugins
-// and reflecting plugin information into JavaScript.
-class nsPluginTag : public nsIPluginTag
-{
-public:
-  enum nsRegisterType {
-    ePluginRegister,
-    ePluginUnregister
-  };
-
-  NS_DECL_ISUPPORTS
-  NS_DECL_NSIPLUGINTAG
-
-  nsPluginTag(nsPluginTag* aPluginTag);
-  nsPluginTag(nsPluginInfo* aPluginInfo);
-  nsPluginTag(const char* aName,
-              const char* aDescription,
-              const char* aFileName,
-              const char* aFullPath,
-              const char* aVersion,
-              const char* const* aMimeTypes,
-              const char* const* aMimeDescriptions,
-              const char* const* aExtensions,
-              PRInt32 aVariants,
-              PRInt64 aLastModifiedTime = 0,
-              PRBool aCanUnload = PR_TRUE,
-              PRBool aArgsAreUTF8 = PR_FALSE);
-  ~nsPluginTag();
-
-  void SetHost(nsPluginHost * aHost);
-  void TryUnloadPlugin();
-  void Mark(PRUint32 mask);
-  void UnMark(PRUint32 mask);
-  PRBool HasFlag(PRUint32 flag);
-  PRUint32 Flags();
-  PRBool Equals(nsPluginTag* aPluginTag);
-  PRBool IsEnabled();
-  void RegisterWithCategoryManager(PRBool aOverrideInternalTypes,
-                                   nsRegisterType aType = ePluginRegister);
-
-  nsRefPtr<nsPluginTag> mNext;
-  nsPluginHost *mPluginHost;
-  nsCString     mName; // UTF-8
-  nsCString     mDescription; // UTF-8
-  PRInt32       mVariants;
-  char          **mMimeTypeArray;
-  nsTArray<nsCString> mMimeDescriptionArray; // UTF-8
-  char          **mExtensionsArray;
-  PRLibrary     *mLibrary;
-  nsCOMPtr<nsIPlugin> mEntryPoint;
-  PRPackedBool  mCanUnloadLibrary;
-  PRPackedBool  mXPConnected;
-  PRPackedBool  mIsJavaPlugin;
-  PRPackedBool  mIsNPRuntimeEnabledJavaPlugin;
-  nsCString     mFileName; // UTF-8
-  nsCString     mFullPath; // UTF-8
-  nsCString     mVersion;  // UTF-8
-  PRInt64       mLastModifiedTime;
-private:
-  PRUint32      mFlags;
-
-  nsresult EnsureMembersAreUTF8();
-};
-
-struct nsPluginInstanceTag
-{
-  nsPluginInstanceTag*   mNext;
-  char*                  mURL;
-  nsRefPtr<nsPluginTag>  mPluginTag;
-  nsIPluginInstance*     mInstance;
-  PRTime                 mllStopTime;
-  PRPackedBool           mStopped;
-  PRPackedBool           mDefaultPlugin;
-  PRPackedBool           mXPConnected;
-  // Array holding all opened stream listeners for this entry
-  nsCOMPtr <nsISupportsArray> mStreams; 
-
-  nsPluginInstanceTag(nsPluginTag* aPluginTag,
-                      nsIPluginInstance* aInstance, 
-                      const char * url,
-                      PRBool aDefaultPlugin);
-  ~nsPluginInstanceTag();
-
-  void setStopped(PRBool stopped);
-};
-
-class nsPluginInstanceTagList
-{
-public:
-  nsPluginInstanceTag *mFirst;
-  nsPluginInstanceTag *mLast;
-  PRInt32 mCount;
-
-  nsPluginInstanceTagList();
-  ~nsPluginInstanceTagList();
-
-  void shutdown();
-  PRBool add(nsPluginInstanceTag *plugin);
-  PRBool remove(nsPluginInstanceTag *plugin);
-  nsPluginInstanceTag *find(nsIPluginInstance *instance);
-  nsPluginInstanceTag *find(const char *mimetype);
-  nsPluginInstanceTag *findStopped(const char *url);
-  PRUint32 getStoppedCount();
-  nsPluginInstanceTag *findOldestStopped();
-  void removeAllStopped();
-  void stopRunning(nsISupportsArray *aReloadDocs, nsPluginTag *aPluginTag);
-  PRBool IsLastInstance(nsPluginInstanceTag *plugin);
-};
-
 class nsPluginHost : public nsIPluginHost,
                      public nsIObserver,
                      public nsITimerCallback,
                      public nsSupportsWeakReference
 {
 public:
   nsPluginHost();
   virtual ~nsPluginHost();
@@ -269,16 +152,18 @@ public:
   nsresult UpdatePluginInfo(nsPluginTag* aPluginTag);
 
   // checks whether aTag is a "java" plugin tag (a tag for a plugin
   // that does Java)
   static PRBool IsJavaMIMEType(const char *aType);
 
   static nsresult GetPrompt(nsIPluginInstanceOwner *aOwner, nsIPrompt **aPrompt);
 
+  static nsresult PostPluginUnloadEvent(PRLibrary* aLibrary);
+
   void AddIdleTimeTarget(nsIPluginInstanceOwner* objectFrame, PRBool isVisible);
   void RemoveIdleTimeTarget(nsIPluginInstanceOwner* objectFrame);
   
 private:
   nsresult
   TrySetUpPluginInstance(const char *aMimeType, nsIURI *aURL, nsIPluginInstanceOwner *aOwner);
 
   nsresult
new file mode 100644
--- /dev/null
+++ b/modules/plugin/base/src/nsPluginTags.cpp
@@ -0,0 +1,842 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Sean Echevarria <sean@beatnik.com>
+ *   HÃ¥kan Waara <hwaara@chello.se>
+ *   Josh Aas <josh@mozilla.com>
+ *
+ * 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 "nsPluginTags.h"
+
+#include "prlink.h"
+#include "plstr.h"
+#include "nsIPluginInstanceOwner.h"
+#include "nsIDocument.h"
+#include "nsServiceManagerUtils.h"
+#include "nsIPrefService.h"
+#include "nsIPrefBranch.h"
+#include "nsPluginsDir.h"
+#include "nsPluginHost.h"
+#include "nsIUnicodeDecoder.h"
+#include "nsIPlatformCharset.h"
+#include "nsICharsetConverterManager.h"
+#include "nsPluginLogging.h"
+#include "nsICategoryManager.h"
+
+inline char* new_str(const char* str)
+{
+  if (str == nsnull)
+    return nsnull;
+  
+  char* result = new char[strlen(str) + 1];
+  if (result != nsnull)
+    return strcpy(result, str);
+  return result;
+}
+
+/* nsPluginTag */
+
+nsPluginTag::nsPluginTag(nsPluginTag* aPluginTag)
+: mPluginHost(nsnull),
+mName(aPluginTag->mName),
+mDescription(aPluginTag->mDescription),
+mVariants(aPluginTag->mVariants),
+mMimeTypeArray(nsnull),
+mMimeDescriptionArray(aPluginTag->mMimeDescriptionArray),
+mExtensionsArray(nsnull),
+mLibrary(nsnull),
+mCanUnloadLibrary(PR_TRUE),
+mXPConnected(PR_FALSE),
+mIsJavaPlugin(aPluginTag->mIsJavaPlugin),
+mIsNPRuntimeEnabledJavaPlugin(aPluginTag->mIsNPRuntimeEnabledJavaPlugin),
+mFileName(aPluginTag->mFileName),
+mFullPath(aPluginTag->mFullPath),
+mVersion(aPluginTag->mVersion),
+mLastModifiedTime(0),
+mFlags(NS_PLUGIN_FLAG_ENABLED)
+{
+  if (aPluginTag->mMimeTypeArray != nsnull) {
+    mMimeTypeArray = new char*[mVariants];
+    for (int i = 0; i < mVariants; i++)
+      mMimeTypeArray[i] = new_str(aPluginTag->mMimeTypeArray[i]);
+  }
+  
+  if (aPluginTag->mExtensionsArray != nsnull) {
+    mExtensionsArray = new char*[mVariants];
+    for (int i = 0; i < mVariants; i++)
+      mExtensionsArray[i] = new_str(aPluginTag->mExtensionsArray[i]);
+  }
+}
+
+nsPluginTag::nsPluginTag(nsPluginInfo* aPluginInfo)
+: mPluginHost(nsnull),
+mName(aPluginInfo->fName),
+mDescription(aPluginInfo->fDescription),
+mVariants(aPluginInfo->fVariantCount),
+mMimeTypeArray(nsnull),
+mExtensionsArray(nsnull),
+mLibrary(nsnull),
+#ifdef XP_MACOSX
+mCanUnloadLibrary(!aPluginInfo->fBundle),
+#else
+mCanUnloadLibrary(PR_TRUE),
+#endif
+mXPConnected(PR_FALSE),
+mIsJavaPlugin(PR_FALSE),
+mIsNPRuntimeEnabledJavaPlugin(PR_FALSE),
+mFileName(aPluginInfo->fFileName),
+mFullPath(aPluginInfo->fFullPath),
+mVersion(aPluginInfo->fVersion),
+mLastModifiedTime(0),
+mFlags(NS_PLUGIN_FLAG_ENABLED)
+{
+  if (aPluginInfo->fMimeTypeArray != nsnull) {
+    mMimeTypeArray = new char*[mVariants];
+    for (int i = 0; i < mVariants; i++) {
+      if (mIsJavaPlugin && aPluginInfo->fMimeTypeArray[i] &&
+          strcmp(aPluginInfo->fMimeTypeArray[i],
+                 "application/x-java-vm-npruntime") == 0) {
+            mIsNPRuntimeEnabledJavaPlugin = PR_TRUE;
+            
+            // Stop processing here, any mimetypes after the magic "I'm a
+            // NPRuntime enabled Java plugin" mimetype will be ignored.
+            mVariants = i;
+            
+            break;
+          }
+      
+      mMimeTypeArray[i] = new_str(aPluginInfo->fMimeTypeArray[i]);
+      if (nsPluginHost::IsJavaMIMEType(mMimeTypeArray[i]))
+        mIsJavaPlugin = PR_TRUE;
+    }
+  }
+  
+  if (aPluginInfo->fMimeDescriptionArray != nsnull) {
+    for (int i = 0; i < mVariants; i++) {
+      // we should cut off the list of suffixes which the mime
+      // description string may have, see bug 53895
+      // it is usually in form "some description (*.sf1, *.sf2)"
+      // so we can search for the opening round bracket
+      char cur = '\0';
+      char pre = '\0';
+      char * p = PL_strrchr(aPluginInfo->fMimeDescriptionArray[i], '(');
+      if (p && (p != aPluginInfo->fMimeDescriptionArray[i])) {
+        if ((p - 1) && *(p - 1) == ' ') {
+          pre = *(p - 1);
+          *(p - 1) = '\0';
+        } else {
+          cur = *p;
+          *p = '\0';
+        }
+        
+      }
+      mMimeDescriptionArray.AppendElement(
+                                          aPluginInfo->fMimeDescriptionArray[i]);
+      // restore the original string
+      if (cur != '\0')
+        *p = cur;
+      if (pre != '\0')
+        *(p - 1) = pre;
+    }
+  } else {
+    mMimeDescriptionArray.SetLength(mVariants);
+  }
+  
+  if (aPluginInfo->fExtensionArray != nsnull) {
+    mExtensionsArray = new char*[mVariants];
+    for (int i = 0; i < mVariants; i++)
+      mExtensionsArray[i] = new_str(aPluginInfo->fExtensionArray[i]);
+  }
+  
+  EnsureMembersAreUTF8();
+}
+
+nsPluginTag::nsPluginTag(const char* aName,
+                         const char* aDescription,
+                         const char* aFileName,
+                         const char* aFullPath,
+                         const char* aVersion,
+                         const char* const* aMimeTypes,
+                         const char* const* aMimeDescriptions,
+                         const char* const* aExtensions,
+                         PRInt32 aVariants,
+                         PRInt64 aLastModifiedTime,
+                         PRBool aCanUnload,
+                         PRBool aArgsAreUTF8)
+: mPluginHost(nsnull),
+mName(aName),
+mDescription(aDescription),
+mVariants(aVariants),
+mMimeTypeArray(nsnull),
+mExtensionsArray(nsnull),
+mLibrary(nsnull),
+mCanUnloadLibrary(aCanUnload),
+mXPConnected(PR_FALSE),
+mIsJavaPlugin(PR_FALSE),
+mIsNPRuntimeEnabledJavaPlugin(PR_FALSE),
+mFileName(aFileName),
+mFullPath(aFullPath),
+mVersion(aVersion),
+mLastModifiedTime(aLastModifiedTime),
+mFlags(0) // Caller will read in our flags from cache
+{
+  if (aVariants) {
+    mMimeTypeArray        = new char*[mVariants];
+    mExtensionsArray      = new char*[mVariants];
+    
+    for (PRInt32 i = 0; i < aVariants; ++i) {
+      if (mIsJavaPlugin && aMimeTypes[i] &&
+          strcmp(aMimeTypes[i], "application/x-java-vm-npruntime") == 0) {
+        mIsNPRuntimeEnabledJavaPlugin = PR_TRUE;
+        
+        // Stop processing here, any mimetypes after the magic "I'm a
+        // NPRuntime enabled Java plugin" mimetype will be ignored.
+        mVariants = i;
+        
+        break;
+      }
+      
+      mMimeTypeArray[i]        = new_str(aMimeTypes[i]);
+      mMimeDescriptionArray.AppendElement(aMimeDescriptions[i]);
+      mExtensionsArray[i]      = new_str(aExtensions[i]);
+      if (nsPluginHost::IsJavaMIMEType(mMimeTypeArray[i]))
+        mIsJavaPlugin = PR_TRUE;
+    }
+  }
+  
+  if (!aArgsAreUTF8)
+    EnsureMembersAreUTF8();
+}
+
+nsPluginTag::~nsPluginTag()
+{
+  NS_ASSERTION(!mNext, "Risk of exhausting the stack space, bug 486349");
+  
+  if (mMimeTypeArray) {
+    for (int i = 0; i < mVariants; i++)
+      delete[] mMimeTypeArray[i];
+    
+    delete[] (mMimeTypeArray);
+    mMimeTypeArray = nsnull;
+  }
+  
+  if (mExtensionsArray) {
+    for (int i = 0; i < mVariants; i++)
+      delete[] mExtensionsArray[i];
+    
+    delete[] (mExtensionsArray);
+    mExtensionsArray = nsnull;
+  }
+}
+
+NS_IMPL_ISUPPORTS1(nsPluginTag, nsIPluginTag)
+
+static nsresult ConvertToUTF8(nsIUnicodeDecoder *aUnicodeDecoder,
+                              nsAFlatCString& aString)
+{
+  PRInt32 numberOfBytes = aString.Length();
+  PRInt32 outUnicodeLen;
+  nsAutoString buffer;
+  nsresult rv = aUnicodeDecoder->GetMaxLength(aString.get(), numberOfBytes,
+                                              &outUnicodeLen);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (!EnsureStringLength(buffer, outUnicodeLen))
+    return NS_ERROR_OUT_OF_MEMORY;
+  rv = aUnicodeDecoder->Convert(aString.get(), &numberOfBytes,
+                                buffer.BeginWriting(), &outUnicodeLen);
+  NS_ENSURE_SUCCESS(rv, rv);
+  buffer.SetLength(outUnicodeLen);
+  CopyUTF16toUTF8(buffer, aString);
+  
+  return NS_OK;
+}
+
+nsresult nsPluginTag::EnsureMembersAreUTF8()
+{
+  nsresult rv;
+  
+  nsCOMPtr<nsIPlatformCharset> pcs =
+  do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsIUnicodeDecoder> decoder;
+  nsCOMPtr<nsICharsetConverterManager> ccm =
+  do_GetService(NS_CHARSETCONVERTERMANAGER_CONTRACTID, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+  
+  nsCAutoString charset;
+  rv = pcs->GetCharset(kPlatformCharsetSel_FileName, charset);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (!charset.LowerCaseEqualsLiteral("utf-8")) {
+    rv = ccm->GetUnicodeDecoderRaw(charset.get(), getter_AddRefs(decoder));
+    NS_ENSURE_SUCCESS(rv, rv);
+    
+    ConvertToUTF8(decoder, mFileName);
+    ConvertToUTF8(decoder, mFullPath);
+  }
+  
+  // The description of the plug-in and the various MIME type descriptions
+  // should be encoded in the standard plain text file encoding for this system.
+  // XXX should we add kPlatformCharsetSel_PluginResource?
+  rv = pcs->GetCharset(kPlatformCharsetSel_PlainTextInFile, charset);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (!charset.LowerCaseEqualsLiteral("utf-8")) {
+    rv = ccm->GetUnicodeDecoderRaw(charset.get(), getter_AddRefs(decoder));
+    NS_ENSURE_SUCCESS(rv, rv);
+    
+    ConvertToUTF8(decoder, mName);
+    ConvertToUTF8(decoder, mDescription);
+    for (PRUint32 i = 0; i < mMimeDescriptionArray.Length(); ++i) {
+      ConvertToUTF8(decoder, mMimeDescriptionArray[i]);
+    }
+  }
+  return NS_OK;
+}
+
+void nsPluginTag::SetHost(nsPluginHost * aHost)
+{
+  mPluginHost = aHost;
+}
+
+NS_IMETHODIMP
+nsPluginTag::GetDescription(nsACString& aDescription)
+{
+  aDescription = mDescription;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPluginTag::GetFilename(nsACString& aFileName)
+{
+  aFileName = mFileName;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPluginTag::GetVersion(nsACString& aVersion)
+{
+  aVersion = mVersion;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPluginTag::GetName(nsACString& aName)
+{
+  aName = mName;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPluginTag::GetDisabled(PRBool* aDisabled)
+{
+  *aDisabled = !HasFlag(NS_PLUGIN_FLAG_ENABLED);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPluginTag::SetDisabled(PRBool aDisabled)
+{
+  if (HasFlag(NS_PLUGIN_FLAG_ENABLED) == !aDisabled)
+    return NS_OK;
+  
+  if (aDisabled)
+    UnMark(NS_PLUGIN_FLAG_ENABLED);
+  else
+    Mark(NS_PLUGIN_FLAG_ENABLED);
+  
+  mPluginHost->UpdatePluginInfo(this);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPluginTag::GetBlocklisted(PRBool* aBlocklisted)
+{
+  *aBlocklisted = HasFlag(NS_PLUGIN_FLAG_BLOCKLISTED);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPluginTag::SetBlocklisted(PRBool aBlocklisted)
+{
+  if (HasFlag(NS_PLUGIN_FLAG_BLOCKLISTED) == aBlocklisted)
+    return NS_OK;
+  
+  if (aBlocklisted)
+    Mark(NS_PLUGIN_FLAG_BLOCKLISTED);
+  else
+    UnMark(NS_PLUGIN_FLAG_BLOCKLISTED);
+  
+  mPluginHost->UpdatePluginInfo(nsnull);
+  return NS_OK;
+}
+
+void
+nsPluginTag::RegisterWithCategoryManager(PRBool aOverrideInternalTypes,
+                                         nsPluginTag::nsRegisterType aType)
+{
+  if (!mMimeTypeArray)
+    return;
+  
+  PLUGIN_LOG(PLUGIN_LOG_NORMAL,
+             ("nsPluginTag::RegisterWithCategoryManager plugin=%s, removing = %s\n",
+              mFileName.get(), aType == ePluginUnregister ? "yes" : "no"));
+  
+  nsCOMPtr<nsICategoryManager> catMan = do_GetService(NS_CATEGORYMANAGER_CONTRACTID);
+  if (!catMan)
+    return;
+  
+  const char *contractId = "@mozilla.org/content/plugin/document-loader-factory;1";
+  
+  nsCOMPtr<nsIPrefBranch> psvc(do_GetService(NS_PREFSERVICE_CONTRACTID));
+  if (!psvc)
+    return; // NS_ERROR_OUT_OF_MEMORY
+  
+  // A preference controls whether or not the full page plugin is disabled for
+  // a particular type. The string must be in the form:
+  //   type1,type2,type3,type4
+  // Note: need an actual interface to control this and subsequent disabling 
+  // (and other plugin host settings) so applications can reliably disable 
+  // plugins - without relying on implementation details such as prefs/category
+  // manager entries.
+  nsXPIDLCString overrideTypes;
+  psvc->GetCharPref("plugin.disable_full_page_plugin_for_types", getter_Copies(overrideTypes));
+  nsCAutoString overrideTypesFormatted;
+  overrideTypesFormatted.Assign(',');
+  overrideTypesFormatted += overrideTypes;
+  overrideTypesFormatted.Append(',');
+  
+  nsACString::const_iterator start, end;
+  for (int i = 0; i < mVariants; i++) {
+    if (aType == ePluginUnregister) {
+      nsXPIDLCString value;
+      if (NS_SUCCEEDED(catMan->GetCategoryEntry("Gecko-Content-Viewers",
+                                                mMimeTypeArray[i],
+                                                getter_Copies(value)))) {
+        // Only delete the entry if a plugin registered for it
+        if (strcmp(value, contractId) == 0) {
+          catMan->DeleteCategoryEntry("Gecko-Content-Viewers",
+                                      mMimeTypeArray[i],
+                                      PR_TRUE);
+        }
+      }
+    } else {
+      overrideTypesFormatted.BeginReading(start);
+      overrideTypesFormatted.EndReading(end);
+      
+      nsDependentCString mimeType(mMimeTypeArray[i]);
+      nsCAutoString commaSeparated; 
+      commaSeparated.Assign(',');
+      commaSeparated += mimeType;
+      commaSeparated.Append(',');
+      if (!FindInReadable(commaSeparated, start, end)) {
+        catMan->AddCategoryEntry("Gecko-Content-Viewers",
+                                 mMimeTypeArray[i],
+                                 contractId,
+                                 PR_FALSE, /* persist: broken by bug 193031 */
+                                 aOverrideInternalTypes, /* replace if we're told to */
+                                 nsnull);
+      }
+    }
+    
+    PLUGIN_LOG(PLUGIN_LOG_NOISY,
+               ("nsPluginTag::RegisterWithCategoryManager mime=%s, plugin=%s\n",
+                mMimeTypeArray[i], mFileName.get()));
+  }
+}
+
+void nsPluginTag::Mark(PRUint32 mask)
+{
+  PRBool wasEnabled = IsEnabled();
+  mFlags |= mask;
+  // Update entries in the category manager if necessary.
+  if (mPluginHost && wasEnabled != IsEnabled()) {
+    if (wasEnabled)
+      RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginUnregister);
+    else
+      RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginRegister);
+  }
+}
+
+void nsPluginTag::UnMark(PRUint32 mask)
+{
+  PRBool wasEnabled = IsEnabled();
+  mFlags &= ~mask;
+  // Update entries in the category manager if necessary.
+  if (mPluginHost && wasEnabled != IsEnabled()) {
+    if (wasEnabled)
+      RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginUnregister);
+    else
+      RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginRegister);
+  }
+}
+
+PRBool nsPluginTag::HasFlag(PRUint32 flag)
+{
+  return (mFlags & flag) != 0;
+}
+
+PRUint32 nsPluginTag::Flags()
+{
+  return mFlags;
+}
+
+PRBool nsPluginTag::IsEnabled()
+{
+  return HasFlag(NS_PLUGIN_FLAG_ENABLED) && !HasFlag(NS_PLUGIN_FLAG_BLOCKLISTED);
+}
+
+PRBool nsPluginTag::Equals(nsPluginTag *aPluginTag)
+{
+  NS_ENSURE_TRUE(aPluginTag, PR_FALSE);
+  
+  if ((!mName.Equals(aPluginTag->mName)) ||
+      (!mDescription.Equals(aPluginTag->mDescription)) ||
+      (mVariants != aPluginTag->mVariants))
+    return PR_FALSE;
+  
+  if (mVariants && mMimeTypeArray && aPluginTag->mMimeTypeArray) {
+    for (PRInt32 i = 0; i < mVariants; i++) {
+      if (PL_strcmp(mMimeTypeArray[i], aPluginTag->mMimeTypeArray[i]) != 0)
+        return PR_FALSE;
+    }
+  }
+  return PR_TRUE;
+}
+
+void nsPluginTag::TryUnloadPlugin()
+{
+  if (mEntryPoint) {
+    mEntryPoint->Shutdown();
+    mEntryPoint = nsnull;
+  }
+  
+  // before we unload check if we are allowed to, see bug #61388
+  if (mLibrary && mCanUnloadLibrary) {
+    // NPAPI plugins can be unloaded now if they don't use XPConnect
+    if (!mXPConnected) {
+      // unload the plugin asynchronously by posting a PLEvent
+      nsPluginHost::PostPluginUnloadEvent(mLibrary);
+    }
+    else {
+      // add library to the unused library list to handle it later
+      if (mPluginHost)
+        mPluginHost->AddUnusedLibrary(mLibrary);
+    }
+  }
+  
+  // we should zero it anyway, it is going to be unloaded by
+  // CleanUnsedLibraries before we need to call the library
+  // again so the calling code should not be fooled and reload
+  // the library fresh
+  mLibrary = nsnull;
+  
+  // Remove mime types added to the category manager
+  // only if we were made 'active' by setting the host
+  if (mPluginHost) {
+    RegisterWithCategoryManager(PR_FALSE, nsPluginTag::ePluginUnregister);
+  }
+}
+
+/* nsPluginInstanceTag */
+
+nsPluginInstanceTag::nsPluginInstanceTag(nsPluginTag* aPluginTag,
+                                         nsIPluginInstance* aInstance,
+                                         const char * url,
+                                         PRBool aDefaultPlugin)
+{
+  mNext = nsnull;
+  mPluginTag = aPluginTag;
+  
+  mURL = PL_strdup(url);
+  mInstance = aInstance;
+  if (aInstance)
+    NS_ADDREF(aInstance);
+  mXPConnected = PR_FALSE;
+  mDefaultPlugin = aDefaultPlugin;
+  mStopped = PR_FALSE;
+  mllStopTime = LL_ZERO;
+}
+
+nsPluginInstanceTag::~nsPluginInstanceTag()
+{
+  mPluginTag = nsnull;
+  if (mInstance) {
+    nsCOMPtr<nsIPluginInstanceOwner> owner;
+    mInstance->GetOwner(getter_AddRefs(owner));
+    if (owner)
+      owner->SetInstance(nsnull);
+    mInstance->InvalidateOwner();
+    
+    NS_RELEASE(mInstance);
+  }
+  PL_strfree(mURL);
+}
+
+void nsPluginInstanceTag::setStopped(PRBool stopped)
+{
+  mStopped = stopped;
+  if (mStopped) // plugin instance is told to stop
+    mllStopTime = PR_Now();
+  else
+    mllStopTime = LL_ZERO;
+}
+
+/* nsPluginInstanceTagList */
+
+nsPluginInstanceTagList::nsPluginInstanceTagList()
+{
+  mFirst = nsnull;
+  mLast = nsnull;
+  mCount = 0;
+}
+
+nsPluginInstanceTagList::~nsPluginInstanceTagList()
+{
+  if (!mFirst)
+    return;
+  shutdown();
+}
+
+void nsPluginInstanceTagList::shutdown()
+{
+  if (!mFirst)
+    return;
+  
+  for (nsPluginInstanceTag * plugin = mFirst; plugin != nsnull;) {
+    nsPluginInstanceTag * next = plugin->mNext;
+    remove(plugin);
+    plugin = next;
+  }
+  mFirst = nsnull;
+  mLast = nsnull;
+}
+
+PRInt32 nsPluginInstanceTagList::add(nsPluginInstanceTag * plugin)
+{
+  if (!mFirst) {
+    mFirst = plugin;
+    mLast = plugin;
+    mFirst->mNext = nsnull;
+  }
+  else {
+    mLast->mNext = plugin;
+    mLast = plugin;
+  }
+  mLast->mNext = nsnull;
+  mCount++;
+  return mCount;
+}
+
+PRBool nsPluginInstanceTagList::IsLastInstance(nsPluginInstanceTag * plugin)
+{
+  if (!plugin)
+    return PR_FALSE;
+  
+  if (!plugin->mPluginTag)
+    return PR_FALSE;
+  
+  for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
+    if ((p->mPluginTag == plugin->mPluginTag) && (p != plugin))
+      return PR_FALSE;
+  }
+  return PR_TRUE;
+}
+
+PRBool nsPluginInstanceTagList::remove(nsPluginInstanceTag * plugin)
+{
+  if (!mFirst)
+    return PR_FALSE;
+  
+  nsPluginInstanceTag * prev = nsnull;
+  for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
+    if (p == plugin) {
+      PRBool lastInstance = IsLastInstance(p);
+      
+      if (p == mFirst)
+        mFirst = p->mNext;
+      else
+        prev->mNext = p->mNext;
+      
+      if (prev && !prev->mNext)
+        mLast = prev;
+      
+      if (lastInstance) {
+        nsRefPtr<nsPluginTag> pluginTag = p->mPluginTag;
+        
+        delete p;
+        
+        if (pluginTag) {
+          nsresult rv;
+          nsCOMPtr<nsIPrefBranch> pref(do_GetService(NS_PREFSERVICE_CONTRACTID, &rv));
+          NS_ENSURE_SUCCESS(rv, rv);
+          
+          PRBool unloadPluginsASAP = PR_FALSE;
+          rv = pref->GetBoolPref("plugins.unloadASAP", &unloadPluginsASAP);
+          if (NS_SUCCEEDED(rv) && unloadPluginsASAP)
+            pluginTag->TryUnloadPlugin();
+        } else {
+          NS_ASSERTION(pluginTag, "pluginTag was not set, plugin not shutdown");
+        }
+      } else {
+        delete p;
+      }
+      
+      mCount--;
+      return PR_TRUE;
+    }
+    prev = p;
+  }
+  return PR_FALSE;
+}
+
+// This method terminates all running instances of plugins and collects their
+// documents to be returned through an array. This method is used
+// when we are shutting down or when a plugins.refresh(1) happens.
+// If aPluginTag is given, then only that plugin is terminated
+void nsPluginInstanceTagList::stopRunning(nsISupportsArray* aReloadDocs,
+                                          nsPluginTag* aPluginTag)
+{
+  if (!mFirst)
+    return;
+  
+  for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
+    if (!p->mStopped && p->mInstance &&
+        (!aPluginTag || aPluginTag == p->mPluginTag)) {
+      p->mInstance->SetWindow(nsnull);
+      p->mInstance->Stop();
+      p->setStopped(PR_TRUE);
+      
+      // If we've been passed an array to return, lets collect all our documents,
+      // removing duplicates. These will be reframed (embedded) or reloaded (full-page) later
+      // to kickstart our instances.
+      if (aReloadDocs && p->mInstance) {
+        nsCOMPtr<nsIPluginInstanceOwner> owner;
+        p->mInstance->GetOwner(getter_AddRefs(owner));
+        if (owner) {
+          nsCOMPtr<nsIDocument> doc;
+          owner->GetDocument(getter_AddRefs(doc));
+          if (doc && aReloadDocs->IndexOf(doc) == -1)  // don't allow for duplicates
+            aReloadDocs->AppendElement(doc);
+        }
+      }
+    }
+  }
+}
+
+void nsPluginInstanceTagList::removeAllStopped()
+{
+  if (!mFirst)
+    return;
+  
+  nsPluginInstanceTag * next = nsnull;
+  
+  for (nsPluginInstanceTag * p = mFirst; p != nsnull;) {
+    next = p->mNext;
+    
+    if (p->mStopped)
+      remove(p);
+    
+    p = next;
+  }
+  return;
+}
+
+nsPluginInstanceTag * nsPluginInstanceTagList::find(nsIPluginInstance* instance)
+{
+  for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
+    if (p->mInstance == instance)
+      return p;
+  }
+  return nsnull;
+}
+
+nsPluginInstanceTag * nsPluginInstanceTagList::find(const char * mimetype)
+{
+  PRBool defaultplugin = (PL_strcmp(mimetype, "*") == 0);
+  
+  for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
+    // give it some special treatment for the default plugin first
+    // because we cannot tell the default plugin by asking instance for a mime type
+    if (defaultplugin && p->mDefaultPlugin)
+      return p;
+    
+    if (!p->mInstance)
+      continue;
+    
+    const char* mt;
+    nsresult rv = p->mInstance->GetMIMEType(&mt);
+    if (NS_FAILED(rv))
+      continue;
+    
+    if (PL_strcasecmp(mt, mimetype) == 0)
+      return p;
+  }
+  return nsnull;
+}
+
+nsPluginInstanceTag * nsPluginInstanceTagList::findStopped(const char * url)
+{
+  for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
+    if (!PL_strcmp(url, p->mURL) && p->mStopped)
+      return p;
+  }
+  return nsnull;
+}
+
+PRUint32 nsPluginInstanceTagList::getStoppedCount()
+{
+  PRUint32 stoppedCount = 0;
+  for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
+    if (p->mStopped)
+      stoppedCount++;
+  }
+  return stoppedCount;
+}
+
+nsPluginInstanceTag * nsPluginInstanceTagList::findOldestStopped()
+{
+  nsPluginInstanceTag * res = nsnull;
+  PRInt64 llTime = LL_MAXINT;
+  for (nsPluginInstanceTag * p = mFirst; p != nsnull; p = p->mNext) {
+    if (!p->mStopped)
+      continue;
+    
+    if (LL_CMP(p->mllStopTime, <, llTime)) {
+      llTime = p->mllStopTime;
+      res = p;
+    }
+  }
+  
+  return res;
+}
new file mode 100644
--- /dev/null
+++ b/modules/plugin/base/src/nsPluginTags.h
@@ -0,0 +1,172 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Josh Aas <josh@mozilla.com>
+ *
+ * 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 ***** */
+
+#ifndef nsPluginTags_h_
+#define nsPluginTags_h_
+
+#include "nscore.h"
+#include "prtypes.h"
+#include "nsAutoPtr.h"
+#include "nsCOMPtr.h"
+#include "nsIPluginTag.h"
+#include "nsIPlugin.h"
+#include "nsIPluginInstance.h"
+#include "nsISupportsArray.h"
+
+class nsPluginHost;
+struct PRLibrary;
+struct nsPluginInfo;
+
+// Remember that flags are written out to pluginreg.dat, be careful
+// changing their meaning.
+#define NS_PLUGIN_FLAG_ENABLED      0x0001    // is this plugin enabled?
+// no longer used                   0x0002    // reuse only if regenerating pluginreg.dat
+#define NS_PLUGIN_FLAG_FROMCACHE    0x0004    // this plugintag info was loaded from cache
+#define NS_PLUGIN_FLAG_UNWANTED     0x0008    // this is an unwanted plugin
+#define NS_PLUGIN_FLAG_BLOCKLISTED  0x0010    // this is a blocklisted plugin
+
+// A linked-list of plugin information that is used for instantiating plugins
+// and reflecting plugin information into JavaScript.
+class nsPluginTag : public nsIPluginTag
+{
+public:
+  enum nsRegisterType {
+    ePluginRegister,
+    ePluginUnregister
+  };
+  
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPLUGINTAG
+  
+  nsPluginTag(nsPluginTag* aPluginTag);
+  nsPluginTag(nsPluginInfo* aPluginInfo);
+  nsPluginTag(const char* aName,
+              const char* aDescription,
+              const char* aFileName,
+              const char* aFullPath,
+              const char* aVersion,
+              const char* const* aMimeTypes,
+              const char* const* aMimeDescriptions,
+              const char* const* aExtensions,
+              PRInt32 aVariants,
+              PRInt64 aLastModifiedTime = 0,
+              PRBool aCanUnload = PR_TRUE,
+              PRBool aArgsAreUTF8 = PR_FALSE);
+  ~nsPluginTag();
+  
+  void SetHost(nsPluginHost * aHost);
+  void TryUnloadPlugin();
+  void Mark(PRUint32 mask);
+  void UnMark(PRUint32 mask);
+  PRBool HasFlag(PRUint32 flag);
+  PRUint32 Flags();
+  PRBool Equals(nsPluginTag* aPluginTag);
+  PRBool IsEnabled();
+  void RegisterWithCategoryManager(PRBool aOverrideInternalTypes,
+                                   nsRegisterType aType = ePluginRegister);
+  
+  nsRefPtr<nsPluginTag> mNext;
+  nsPluginHost *mPluginHost;
+  nsCString     mName; // UTF-8
+  nsCString     mDescription; // UTF-8
+  PRInt32       mVariants;
+  char          **mMimeTypeArray;
+  nsTArray<nsCString> mMimeDescriptionArray; // UTF-8
+  char          **mExtensionsArray;
+  PRLibrary     *mLibrary;
+  nsCOMPtr<nsIPlugin> mEntryPoint;
+  PRPackedBool  mCanUnloadLibrary;
+  PRPackedBool  mXPConnected;
+  PRPackedBool  mIsJavaPlugin;
+  PRPackedBool  mIsNPRuntimeEnabledJavaPlugin;
+  nsCString     mFileName; // UTF-8
+  nsCString     mFullPath; // UTF-8
+  nsCString     mVersion;  // UTF-8
+  PRInt64       mLastModifiedTime;
+private:
+  PRUint32      mFlags;
+  
+  nsresult EnsureMembersAreUTF8();
+};
+
+struct nsPluginInstanceTag
+{
+  nsPluginInstanceTag*   mNext;
+  char*                  mURL;
+  nsRefPtr<nsPluginTag>  mPluginTag;
+  nsIPluginInstance*     mInstance;
+  PRTime                 mllStopTime;
+  PRPackedBool           mStopped;
+  PRPackedBool           mDefaultPlugin;
+  PRPackedBool           mXPConnected;
+  // Array holding all opened stream listeners for this entry
+  nsCOMPtr <nsISupportsArray> mStreams; 
+  
+  nsPluginInstanceTag(nsPluginTag* aPluginTag,
+                      nsIPluginInstance* aInstance, 
+                      const char * url,
+                      PRBool aDefaultPlugin);
+  ~nsPluginInstanceTag();
+  
+  void setStopped(PRBool stopped);
+};
+
+class nsPluginInstanceTagList
+{
+public:
+  nsPluginInstanceTag *mFirst;
+  nsPluginInstanceTag *mLast;
+  PRInt32 mCount;
+  
+  nsPluginInstanceTagList();
+  ~nsPluginInstanceTagList();
+  
+  void shutdown();
+  PRBool add(nsPluginInstanceTag *plugin);
+  PRBool remove(nsPluginInstanceTag *plugin);
+  nsPluginInstanceTag *find(nsIPluginInstance *instance);
+  nsPluginInstanceTag *find(const char *mimetype);
+  nsPluginInstanceTag *findStopped(const char *url);
+  PRUint32 getStoppedCount();
+  nsPluginInstanceTag *findOldestStopped();
+  void removeAllStopped();
+  void stopRunning(nsISupportsArray *aReloadDocs, nsPluginTag *aPluginTag);
+  PRBool IsLastInstance(nsPluginInstanceTag *plugin);
+};
+
+#endif // nsPluginTags_h_
new file mode 100644
--- /dev/null
+++ b/modules/plugin/test/reftest/div-alpha-opacity.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<html>
+<head>
+<style type="text/css">
+#one {
+  position:absolute;
+  left:0px; top:0px;
+  width:400px; height:400px;
+  background-color: rgb(160,160,160);
+  opacity:0.5;
+  z-index:1;
+}
+#two {
+  position:absolute;
+  top:100px; left:100px;
+  width:200px; height:200px;
+  z-index:0;
+  background-color: rgb(255,0,0);
+}
+</style>
+</head>
+<body>
+<div id="two"></div>
+<div id="one"></div>
+</body>
+</html>
+
new file mode 100644
--- /dev/null
+++ b/modules/plugin/test/reftest/plugin-alpha-opacity.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<html>
+<head>
+<style type="text/css">
+#one {
+  position:absolute;
+  left:0px; top:0px;
+  width:400px; height:400px;
+  opacity:.5;
+  z-index:1;
+}
+#two {
+  position:absolute;
+  top:100px; left:100px;
+  width:200px; height:200px;
+  z-index:0;
+  background-color: rgb(255,0,0);
+}
+</style>
+</head>
+<body>
+<div id="two"></div>
+<embed id="one" type="application/x-test" width="400" height="400" drawmode="solid" color="FFa0a0a0"></embed>
+</body>
+</html>
+
--- a/modules/plugin/test/reftest/reftest.list
+++ b/modules/plugin/test/reftest/reftest.list
@@ -1,9 +1,10 @@
 # basic sanity checking
 random-if(!haveTestPlugin) != plugin-sanity.html about:blank
 fails-if(!haveTestPlugin) == plugin-sanity.html div-sanity.html
 fails-if(!haveTestPlugin) == plugin-alpha-zindex.html div-alpha-zindex.html
+fails-if(!haveTestPlugin) == plugin-alpha-opacity.html div-alpha-opacity.html
 fails-if(!haveTestPlugin) == windowless-clipping-1.html windowless-clipping-1-ref.html
 fails-if(!haveTestPlugin) == border-padding-1.html border-padding-1-ref.html
 fails-if(!haveTestPlugin) == border-padding-2.html border-padding-2-ref.html
 # Disabled for now to investigate Windows/Linux test failures
 # fails-if(!haveTestPlugin) == border-padding-3.html border-padding-3-ref.html
--- a/toolkit/crashreporter/Makefile.in
+++ b/toolkit/crashreporter/Makefile.in
@@ -73,17 +73,16 @@ endif
 ifeq ($(OS_ARCH),Linux)
 # there's no define for this normally
 DEFINES += -DXP_LINUX
 DIRS += \
   google-breakpad/src/common \
   google-breakpad/src/common/linux \
   google-breakpad/src/client \
   google-breakpad/src/client/linux/handler \
-  google-breakpad/src/client/linux/minidump_writer \
   google-breakpad/src/tools/linux/dump_syms \
   $(NULL)
 endif
 
 ifeq ($(OS_ARCH),SunOS)
 # there's no define for this normally
 DEFINES += -DXP_SOLARIS
 DIRS += \
--- a/toolkit/crashreporter/client/Makefile.in
+++ b/toolkit/crashreporter/client/Makefile.in
@@ -79,27 +79,29 @@ endif
 ifeq ($(OS_ARCH),Linux)
 CPPSRCS += crashreporter_linux.cpp crashreporter_unix.cpp
 LIBS += \
   $(DEPTH)/toolkit/crashreporter/google-breakpad/src/common/linux/$(LIB_PREFIX)breakpad_linux_common_s.$(LIB_SUFFIX) \
   $(NULL)
 LOCAL_INCLUDES += -I$(srcdir)
 OS_CXXFLAGS += $(MOZ_GTK2_CFLAGS) $(MOZ_GTHREAD_CFLAGS)
 OS_LIBS += $(MOZ_GTK2_LIBS) $(MOZ_GTHREAD_LIBS)
+CPPSRCS += http_upload.cc
 FORCE_USE_PIC=1
 endif
 
 ifeq ($(OS_ARCH),SunOS)
 CPPSRCS += crashreporter_linux.cpp crashreporter_unix.cpp
 LIBS += \
   $(DEPTH)/toolkit/crashreporter/google-breakpad/src/common/solaris/$(LIB_PREFIX)breakpad_solaris_common_s.$(LIB_SUFFIX) \
   $(NULL)
 LOCAL_INCLUDES += -I$(srcdir)
 OS_CXXFLAGS += $(MOZ_GTK2_CFLAGS) $(MOZ_GTHREAD_CFLAGS)
 OS_LIBS += $(MOZ_GTK2_LIBS) $(MOZ_GTHREAD_LIBS)
+CPPSRCS += http_upload.cc
 FORCE_USE_PIC=1
 endif
 
 include $(topsrcdir)/config/rules.mk
 
 ifeq ($(OS_ARCH),Darwin)
 libs::
 	$(NSINSTALL) -D $(DIST)/bin/crashreporter.app
@@ -107,11 +109,14 @@ libs::
 	sed -e "s/%APP_NAME%/$(MOZ_APP_DISPLAYNAME)/" $(srcdir)/macbuild/Contents/Resources/English.lproj/InfoPlist.strings.in | \
 	  iconv -f UTF-8 -t UTF-16 > $(DIST)/bin/crashreporter.app/Contents/Resources/English.lproj/InfoPlist.strings
 	$(NSINSTALL) -D $(DIST)/bin/crashreporter.app/Contents/MacOS
 	$(NSINSTALL) $(DIST)/bin/crashreporter $(DIST)/bin/crashreporter.app/Contents/MacOS
 	rm -f $(DIST)/bin/crashreporter
 endif
 
 ifeq (,$(filter-out Linux SunOS,$(OS_ARCH)))
+export:: $(srcdir)/../google-breakpad/src/common/linux/http_upload.cc
+	$(INSTALL) $^ .
+
 libs:: $(topsrcdir)/toolkit/themes/winstripe/global/throbber/Throbber-small.gif
 	$(INSTALL) $^ $(DIST)/bin
 endif
deleted file mode 100644
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/data/linux-gate-amd.sym
+++ /dev/null
@@ -1,3 +0,0 @@
-MODULE Linux x86 B8CFDE93002D54DA1900A40AA1BD67690 linux-gate.so
-PUBLIC 400 0 __kernel_vsyscall
-STACK WIN 4 400 100 1 1 0 0 0 0 0 1
deleted file mode 100644
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/data/linux-gate-intel.sym
+++ /dev/null
@@ -1,3 +0,0 @@
-MODULE Linux x86 4FBDA58B5A1DF5A379E3CF19A235EA090 linux-gate.so
-PUBLIC 400 0 __kernel_vsyscall
-STACK WIN 4 400 200 3 3 0 0 0 0 0 1
\ No newline at end of file
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/handler/Makefile.in
+++ b/toolkit/crashreporter/google-breakpad/src/client/linux/handler/Makefile.in
@@ -44,15 +44,17 @@ include $(DEPTH)/config/autoconf.mk
 MODULE		= handler
 LIBRARY_NAME	= exception_handler_s
 XPI_NAME 	= crashreporter
 
 LOCAL_INCLUDES 	= -I$(srcdir)/../../..
 
 CPPSRCS	= \
   exception_handler.cc \
+  minidump_generator.cc \
+  linux_thread.cc \
   $(NULL)
 
 # need static lib
 FORCE_STATIC_LIB = 1
 FORCE_USE_PIC = 1
 
 include $(topsrcdir)/config/rules.mk
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler.cc
+++ b/toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler.cc
@@ -1,11 +1,13 @@
-// Copyright (c) 2009, Google Inc.
+// Copyright (c) 2006, Google Inc.
 // All rights reserved.
 //
+// Author: Li Liu
+//
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
 //
 //     * Redistributions of source code must retain the above copyright
 // notice, this list of conditions and the following disclaimer.
 //     * Redistributions in binary form must reproduce the above
 // copyright notice, this list of conditions and the following disclaimer
@@ -22,177 +24,273 @@
 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// The ExceptionHandler object installs signal handlers for a number of
-// signals. We rely on the signal handler running on the thread which crashed
-// in order to identify it. This is true of the synchronous signals (SEGV etc),
-// but not true of ABRT. Thus, if you send ABRT to yourself in a program which
-// uses ExceptionHandler, you need to use tgkill to direct it to the current
-// thread.
-//
-// The signal flow looks like this:
-//
-//   SignalHandler (uses a global stack of ExceptionHandler objects to find
-//        |         one to handle the signal. If the first rejects it, try
-//        |         the second etc...)
-//        V
-//   HandleSignal ----------------------------| (clones a new process which
-//        |                                   |  shares an address space with
-//   (wait for cloned                         |  the crashed process. This
-//     process)                               |  allows us to ptrace the crashed
-//        |                                   |  process)
-//        V                                   V
-//   (set signal handler to             ThreadEntry (static function to bounce
-//    SIG_DFL and rethrow,                    |      back into the object)
-//    killing the crashed                     |
-//    process)                                V
-//                                          DoDump  (writes minidump)
-//                                            |
-//                                            V
-//                                         sys_exit
-//
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <string.h>
+#include <unistd.h>
 
-// This code is a little fragmented. Different functions of the ExceptionHandler
-// class run in a number of different contexts. Some of them run in a normal
-// context and are easy to code, others run in a compromised context and the
-// restrictions at the top of minidump_writer.cc apply: no libc and use the
-// alternative malloc. Each function should have comment above it detailing the
-// context which it runs in.
+#include <cassert>
+#include <cstdlib>
+#include <cstdio>
+#include <ctime>
+#include <linux/limits.h>
 
 #include "client/linux/handler/exception_handler.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/limits.h>
-#include <sched.h>
-#include <signal.h>
-#include <stdio.h>
-#include <sys/mman.h>
-#include <sys/signal.h>
-#include <sys/syscall.h>
-#include <sys/ucontext.h>
-#include <sys/user.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include "common/linux/linux_libc_support.h"
-#include "common/linux/linux_syscall_support.h"
-#include "common/linux/memory.h"
-#include "client/linux/minidump_writer//minidump_writer.h"
 #include "common/linux/guid_creator.h"
-
-// A wrapper for the tgkill syscall: send a signal to a specific thread.
-static int tgkill(pid_t tgid, pid_t tid, int sig) {
-  syscall(__NR_tgkill, tgid, tid, sig);
-  return 0;
-}
+#include "google_breakpad/common/minidump_format.h"
 
 namespace google_breakpad {
 
-// The list of signals which we consider to be crashes. The default action for
-// all these signals must be Core (see man 7 signal) because we rethrow the
-// signal after handling it and expect that it'll be fatal.
-static const int kExceptionSignals[] = {
-  SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS, -1
+// Signals that we are interested.
+int SigTable[] = {
+#if defined(SIGSEGV)
+  SIGSEGV,
+#endif
+#ifdef SIGABRT
+  SIGABRT,
+#endif
+#ifdef SIGFPE
+  SIGFPE,
+#endif
+#ifdef SIGILL
+  SIGILL,
+#endif
+#ifdef SIGBUS
+  SIGBUS,
+#endif
 };
 
-// We can stack multiple exception handlers. In that case, this is the global
-// which holds the stack.
-std::vector<ExceptionHandler*>* ExceptionHandler::handler_stack_ = NULL;
-unsigned ExceptionHandler::handler_stack_index_ = 0;
+std::vector<ExceptionHandler*> *ExceptionHandler::handler_stack_ = NULL;
+int ExceptionHandler::handler_stack_index_ = 0;
 pthread_mutex_t ExceptionHandler::handler_stack_mutex_ =
-    PTHREAD_MUTEX_INITIALIZER;
+PTHREAD_MUTEX_INITIALIZER;
 
-// Runs before crashing: normal context.
-ExceptionHandler::ExceptionHandler(const std::string &dump_path,
+ExceptionHandler::ExceptionHandler(const string &dump_path,
                                    FilterCallback filter,
                                    MinidumpCallback callback,
                                    void *callback_context,
                                    bool install_handler)
     : filter_(filter),
       callback_(callback),
       callback_context_(callback_context),
       dump_path_(),
-      handler_installed_(install_handler),
-      crash_handler_(NULL) {
+      installed_handler_(install_handler) {
   set_dump_path(dump_path);
 
+  act_.sa_handler = HandleException;
+  act_.sa_flags = SA_ONSTACK;
+  sigemptyset(&act_.sa_mask);
+  // now, make sure we're blocking all the signals we are handling
+  // when we're handling any of them
+  for ( size_t i = 0; i < sizeof(SigTable) / sizeof(SigTable[0]); ++i) {
+    sigaddset(&act_.sa_mask, SigTable[i]);
+  }
+
   if (install_handler) {
-    InstallHandlers();
-
+    SetupHandler();
     pthread_mutex_lock(&handler_stack_mutex_);
-      if (handler_stack_ == NULL)
-        handler_stack_ = new std::vector<ExceptionHandler *>;
-      handler_stack_->push_back(this);
+    if (handler_stack_ == NULL)
+      handler_stack_ = new std::vector<ExceptionHandler *>;
+    handler_stack_->push_back(this);
     pthread_mutex_unlock(&handler_stack_mutex_);
   }
 }
 
-// Runs before crashing: normal context.
 ExceptionHandler::~ExceptionHandler() {
-  UninstallHandlers();
+  TeardownAllHandler();
+  pthread_mutex_lock(&handler_stack_mutex_);
+  if (handler_stack_->back() == this) {
+    handler_stack_->pop_back();
+  } else {
+    fprintf(stderr, "warning: removing Breakpad handler out of order\n");
+    for (std::vector<ExceptionHandler *>::iterator iterator =
+         handler_stack_->begin();
+         iterator != handler_stack_->end();
+         ++iterator) {
+      if (*iterator == this) {
+        handler_stack_->erase(iterator);
+      }
+    }
+  }
+
+  if (handler_stack_->empty()) {
+    // When destroying the last ExceptionHandler that installed a handler,
+    // clean up the handler stack.
+    delete handler_stack_;
+    handler_stack_ = NULL;
+  }
+  pthread_mutex_unlock(&handler_stack_mutex_);
+}
+
+bool ExceptionHandler::WriteMinidump() {
+  bool success = InternalWriteMinidump(0, 0, NULL);
+  UpdateNextID();
+  return success;
+}
+
+// static
+bool ExceptionHandler::WriteMinidump(const string &dump_path,
+                   MinidumpCallback callback,
+                   void *callback_context) {
+  ExceptionHandler handler(dump_path, NULL, callback,
+                           callback_context, false);
+  return handler.InternalWriteMinidump(0, 0, NULL);
+}
+
+void ExceptionHandler::SetupHandler() {
+  // Signal on a different stack to avoid using the stack
+  // of the crashing thread.
+  struct sigaltstack sig_stack;
+  sig_stack.ss_sp = malloc(MINSIGSTKSZ);
+  if (sig_stack.ss_sp == NULL)
+    return;
+  sig_stack.ss_size = MINSIGSTKSZ;
+  sig_stack.ss_flags = 0;
+
+  if (sigaltstack(&sig_stack, NULL) < 0)
+    return;
+  for (size_t i = 0; i < sizeof(SigTable) / sizeof(SigTable[0]); ++i)
+    SetupHandler(SigTable[i]);
+}
+
+void ExceptionHandler::SetupHandler(int signo) {
+
+  // We're storing pointers to the old signal action
+  // structure, rather than copying the structure
+  // because we can't count on the sa_mask field to
+  // be scalar.
+  struct sigaction *old_act = &old_actions_[signo];
+
+  if (sigaction(signo, &act_, old_act) < 0)
+   return;
+}
+
+void ExceptionHandler::TeardownHandler(int signo) {
+  TeardownHandler(signo, NULL);
 }
 
-// Runs before crashing: normal context.
-bool ExceptionHandler::InstallHandlers() {
-  // We run the signal handlers on an alternative stack because we might have
-  // crashed because of a stack overflow.
+void ExceptionHandler::TeardownHandler(int signo, struct sigaction *final_handler) {
+  if (old_actions_[signo].sa_handler) {
+    struct sigaction *act = &old_actions_[signo];
+    sigaction(signo, act, final_handler);
+    memset(&old_actions_[signo], 0x0, sizeof(struct sigaction));
+  }
+}
+
+void ExceptionHandler::TeardownAllHandler() {
+  for (size_t i = 0; i < sizeof(SigTable) / sizeof(SigTable[0]); ++i) {
+    TeardownHandler(SigTable[i]);
+  }
+}
+
+// static
+void ExceptionHandler::HandleException(int signo) {
+  // In Linux, the context information about the signal is put on the stack of
+  // the signal handler frame as value parameter. For some reasons, the
+  // prototype of the handler doesn't declare this information as parameter, we
+  // will do it by hand. It is the second parameter above the signal number.
+  // However, if we are being called by another signal handler passing the
+  // signal up the chain, then we may not have this random extra parameter,
+  // so we may have to walk the stack to find it.  We do the actual work
+  // on another thread, where it's a little safer, but we want the ebp
+  // from this frame to find it.
+  uintptr_t current_ebp = 0;
+  asm volatile ("movl %%ebp, %0"
+                :"=m"(current_ebp));
+
+  pthread_mutex_lock(&handler_stack_mutex_);
+  ExceptionHandler *current_handler =
+    handler_stack_->at(handler_stack_->size() - ++handler_stack_index_);
+  pthread_mutex_unlock(&handler_stack_mutex_);
+
+  // Restore original handler.
+  struct sigaction old_action;
+  current_handler->TeardownHandler(signo, &old_action);
 
-  // We use this value rather than SIGSTKSZ because we would end up overrunning
-  // such a small stack.
-  static const unsigned kSigStackSize = 8192;
+  struct sigcontext *sig_ctx = NULL;
+  if (current_handler->InternalWriteMinidump(signo, current_ebp, &sig_ctx)) {
+    // Fully handled this exception, safe to exit.
+    exit(EXIT_FAILURE);
+  } else {
+    // Exception not fully handled, will call the next handler in stack to
+    // process it.
+    if (old_action.sa_handler != NULL && sig_ctx != NULL) {
+
+      // Have our own typedef, because of the comment above w.r.t signal
+      // context on the stack
+      typedef void (*SignalHandler)(int signo, struct sigcontext);
+
+      SignalHandler old_handler =
+          reinterpret_cast<SignalHandler>(old_action.sa_handler);
 
-  signal_stack = malloc(kSigStackSize);
-  stack_t stack;
-  memset(&stack, 0, sizeof(stack));
-  stack.ss_sp = signal_stack;
-  stack.ss_size = kSigStackSize;
+      sigset_t old_set;
+      // Use SIG_BLOCK here because we don't want to unblock a signal
+      // that the signal handler we're currently in needs to block
+      sigprocmask(SIG_BLOCK, &old_action.sa_mask, &old_set);
+      old_handler(signo, *sig_ctx);
+      sigprocmask(SIG_SETMASK, &old_set, NULL);
+    }
+
+  }
 
-  if (sigaltstack(&stack, NULL) == -1)
+  pthread_mutex_lock(&handler_stack_mutex_);
+  current_handler->SetupHandler(signo);
+  --handler_stack_index_;
+  // All the handlers in stack have been invoked to handle the exception,
+  // normally the process should be terminated and should not reach here.
+  // In case we got here, ask the OS to handle it to avoid endless loop,
+  // normally the OS will generate a core and termiate the process. This
+  // may be desired to debug the program.
+  if (handler_stack_index_ == 0)
+    signal(signo, SIG_DFL);
+  pthread_mutex_unlock(&handler_stack_mutex_);
+}
+
+bool ExceptionHandler::InternalWriteMinidump(int signo,
+                                             uintptr_t sighandler_ebp,
+                                             struct sigcontext **sig_ctx) {
+  if (filter_ && !filter_(callback_context_))
     return false;
 
-  struct sigaction sa;
-  memset(&sa, 0, sizeof(sa));
-  sigemptyset(&sa.sa_mask);
-
-  // mask all exception signals when we're handling one of them.
-  for (unsigned i = 0; kExceptionSignals[i] != -1; ++i)
-    sigaddset(&sa.sa_mask, kExceptionSignals[i]);
+  bool success = false;
+  // Block all the signals we want to process when writting minidump.
+  // We don't want it to be interrupted.
+  sigset_t sig_blocked, sig_old;
+  bool blocked = true;
+  sigfillset(&sig_blocked);
+  for (size_t i = 0; i < sizeof(SigTable) / sizeof(SigTable[0]); ++i)
+    sigdelset(&sig_blocked, SigTable[i]);
+  if (sigprocmask(SIG_BLOCK, &sig_blocked, &sig_old) != 0) {
+    blocked = false;
+    fprintf(stderr, "google_breakpad::ExceptionHandler::HandleException: "
+                    "failed to block signals.\n");
+  }
 
-  sa.sa_sigaction = SignalHandler;
-  sa.sa_flags = SA_ONSTACK | SA_SIGINFO;
+  success = minidump_generator_.WriteMinidumpToFile(
+                     next_minidump_path_c_, signo, sighandler_ebp, sig_ctx);
 
-  for (unsigned i = 0; kExceptionSignals[i] != -1; ++i) {
-    struct sigaction* old = new struct sigaction;
-    if (sigaction(kExceptionSignals[i], &sa, old) == -1)
-      return false;
-    old_handlers_.push_back(std::make_pair(kExceptionSignals[i], old));
+  // Unblock the signals.
+  if (blocked) {
+    sigprocmask(SIG_SETMASK, &sig_old, NULL);
   }
-  return true;
+
+  if (callback_)
+    success = callback_(dump_path_c_, next_minidump_id_c_,
+                          callback_context_, success);
+  return success;
 }
 
-// Runs before crashing: normal context.
-void ExceptionHandler::UninstallHandlers() {
-  for (unsigned i = 0; i < old_handlers_.size(); ++i) {
-    struct sigaction *action =
-        reinterpret_cast<struct sigaction*>(old_handlers_[i].second);
-    sigaction(old_handlers_[i].first, action, NULL);
-    delete action;
-  }
-
-  old_handlers_.clear();
-}
-
-// Runs before crashing: normal context.
 void ExceptionHandler::UpdateNextID() {
   GUID guid;
   char guid_str[kGUIDStringLength + 1];
   if (CreateGUID(&guid) && GUIDToString(&guid, guid_str, sizeof(guid_str))) {
     next_minidump_id_ = guid_str;
     next_minidump_id_c_ = next_minidump_id_.c_str();
 
     char minidump_path[PATH_MAX];
@@ -200,125 +298,9 @@ void ExceptionHandler::UpdateNextID() {
              dump_path_c_,
              guid_str);
 
     next_minidump_path_ = minidump_path;
     next_minidump_path_c_ = next_minidump_path_.c_str();
   }
 }
 
-// This function runs in a compromised context: see the top of the file.
-// Runs on the crashing thread.
-// static
-void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) {
-  // All the exception signals are blocked at this point.
-
-  pthread_mutex_lock(&handler_stack_mutex_);
-
-  if (!handler_stack_->size()) {
-    pthread_mutex_unlock(&handler_stack_mutex_);
-    return;
-  }
-
-  for (int i = handler_stack_->size() - 1; i >= 0; --i) {
-    if ((*handler_stack_)[i]->HandleSignal(sig, info, uc)) {
-      // successfully handled: We are in an invalid state since an exception
-      // signal has been delivered. We don't call the exit handlers because
-      // they could end up corrupting on-disk state.
-      break;
-    }
-  }
-
-  pthread_mutex_unlock(&handler_stack_mutex_);
-
-  // Terminate ourselves with the same signal so that our parent knows that we
-  // crashed. The default action for all the signals which we catch is Core, so
-  // this is the end of us.
-  signal(sig, SIG_DFL);
-  tgkill(getpid(), sys_gettid(), sig);
-
-  // not reached.
-}
-
-struct ThreadArgument {
-  pid_t pid;  // the crashing process
-  ExceptionHandler* handler;
-  const void* context;  // a CrashContext structure
-  size_t context_size;
-};
-
-// This is the entry function for the cloned process. We are in a compromised
-// context here: see the top of the file.
-// static
-int ExceptionHandler::ThreadEntry(void *arg) {
-  const ThreadArgument *thread_arg = reinterpret_cast<ThreadArgument*>(arg);
-  return thread_arg->handler->DoDump(thread_arg->pid, thread_arg->context,
-                                     thread_arg->context_size) == false;
-}
-
-// This function runs in a compromised context: see the top of the file.
-// Runs on the crashing thread.
-bool ExceptionHandler::HandleSignal(int sig, siginfo_t* info, void* uc) {
-  if (filter_ && !filter_(callback_context_))
-    return false;
-
-  // Allow ourselves to be dumped.
-  sys_prctl(PR_SET_DUMPABLE, 1);
-
-  CrashContext context;
-  memcpy(&context.siginfo, info, sizeof(siginfo_t));
-  memcpy(&context.context, uc, sizeof(struct ucontext));
-  memcpy(&context.float_state, ((struct ucontext *)uc)->uc_mcontext.fpregs,
-         sizeof(context.float_state));
-  context.tid = sys_gettid();
-
-  if (crash_handler_ && crash_handler_(&context, sizeof(context),
-                                       callback_context_))
-    return true;
-
-  static const unsigned kChildStackSize = 8000;
-  PageAllocator allocator;
-  uint8_t* stack = (uint8_t*) allocator.Alloc(kChildStackSize);
-  if (!stack)
-    return false;
-  // clone() needs the top-most address. (scrub just to be safe)
-  stack += kChildStackSize;
-  my_memset(stack - 16, 0, 16);
-
-  ThreadArgument thread_arg;
-  thread_arg.handler = this;
-  thread_arg.pid = getpid();
-  thread_arg.context = &context;
-  thread_arg.context_size = sizeof(context);
-
-  const pid_t child = sys_clone(
-      ThreadEntry, stack, CLONE_FILES | CLONE_FS | CLONE_UNTRACED,
-      &thread_arg, NULL, NULL, NULL);
-  int r, status;
-  do {
-    r = sys_waitpid(child, &status, __WALL);
-  } while (r == -1 && errno == EINTR);
-
-  if (r == -1) {
-    static const char msg[] = "ExceptionHandler::HandleSignal: waitpid failed:";
-    sys_write(2, msg, sizeof(msg) - 1);
-    sys_write(2, strerror(errno), strlen(strerror(errno)));
-    sys_write(2, "\n", 1);
-  }
-
-  bool success = r != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0;
-
-  if (callback_)
-    success = callback_(dump_path_c_, next_minidump_id_c_,
-                        callback_context_, success);
-
-  return success;
-}
-
-// This function runs in a compromised context: see the top of the file.
-// Runs on the cloned process.
-bool ExceptionHandler::DoDump(pid_t crashing_process, const void* context,
-                              size_t context_size) {
-  return google_breakpad::WriteMinidump(
-      next_minidump_path_c_, crashing_process, context, context_size);
-}
-
 }  // namespace google_breakpad
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler.h
+++ b/toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler.h
@@ -1,11 +1,13 @@
-// Copyright (c) 2009, Google Inc.
+// Copyright (c) 2006, Google Inc.
 // All rights reserved.
 //
+// Author: Li Liu
+//
 // Redistribution and use in source and binary forms, with or without
 // modification, are permitted provided that the following conditions are
 // met:
 //
 //     * Redistributions of source code must retain the above copyright
 // notice, this list of conditions and the following disclaimer.
 //     * Redistributions in binary form must reproduce the above
 // copyright notice, this list of conditions and the following disclaimer
@@ -22,26 +24,36 @@
 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-#ifndef CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_
-#define CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_
+#ifndef CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H__
+#define CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H__
 
+#include <pthread.h>
+
+#include <map>
+#include <string>
+#include <signal.h>
 #include <vector>
-#include <string>
+
+#include "client/linux/handler/minidump_generator.h"
 
-#include <signal.h>
+// Context information when exception occured.
+struct sigcontex;
 
 namespace google_breakpad {
 
+using std::string;
+
+//
 // ExceptionHandler
 //
 // ExceptionHandler can write a minidump file when an exception occurs,
 // or when WriteMinidump() is called explicitly by your program.
 //
 // To have the exception handler write minidumps when an uncaught exception
 // (crash) occurs, you should create an instance early in the execution
 // of your program, and keep it around for the entire time you want to
@@ -56,16 +68,17 @@ namespace google_breakpad {
 //
 // In either case, a callback function is called when a minidump is written,
 // which receives the unqiue id of the minidump.  The caller can use this
 // id to collect and write additional application state, and to launch an
 // external crash-reporting application.
 //
 // Caller should try to make the callbacks as crash-friendly as possible,
 // it should avoid use heap memory allocation as much as possible.
+//
 class ExceptionHandler {
  public:
   // A callback function to run before Breakpad performs any substantial
   // processing of an exception.  A FilterCallback is called before writing
   // a minidump.  context is the parameter supplied by the user as
   // callback_context when the handler was created.
   //
   // If a FilterCallback returns true, Breakpad will continue processing,
@@ -90,109 +103,124 @@ class ExceptionHandler {
   // should normally return the value of |succeeded|, or when they wish to
   // not report an exception of handled, false.  Callbacks will rarely want to
   // return true directly (unless |succeeded| is true).
   typedef bool (*MinidumpCallback)(const char *dump_path,
                                    const char *minidump_id,
                                    void *context,
                                    bool succeeded);
 
-  // In certain cases, a user may wish to handle the generation of the minidump
-  // themselves. In this case, they can install a handler callback which is
-  // called when a crash has occured. If this function returns true, no other
-  // processing of occurs and the process will shortly be crashed. If this
-  // returns false, the normal processing continues.
-  typedef bool (*HandlerCallback)(const void* crash_context,
-                                  size_t crash_context_size,
-                                  void* context);
-
   // Creates a new ExceptionHandler instance to handle writing minidumps.
   // Before writing a minidump, the optional filter callback will be called.
   // Its return value determines whether or not Breakpad should write a
   // minidump.  Minidump files will be written to dump_path, and the optional
   // callback is called after writing the dump file, as described above.
   // If install_handler is true, then a minidump will be written whenever
   // an unhandled exception occurs.  If it is false, minidumps will only
   // be written when WriteMinidump is called.
-  ExceptionHandler(const std::string &dump_path,
+  ExceptionHandler(const string &dump_path,
                    FilterCallback filter, MinidumpCallback callback,
                    void *callback_context,
                    bool install_handler);
   ~ExceptionHandler();
 
   // Get and set the minidump path.
-  std::string dump_path() const { return dump_path_; }
-  void set_dump_path(const std::string &dump_path) {
+  string dump_path() const { return dump_path_; }
+  void set_dump_path(const string &dump_path) {
     dump_path_ = dump_path;
     dump_path_c_ = dump_path_.c_str();
     UpdateNextID();
   }
 
-  void set_crash_handler(HandlerCallback callback) {
-    crash_handler_ = callback;
-  }
-
   // Writes a minidump immediately.  This can be used to capture the
   // execution state independently of a crash.  Returns true on success.
   bool WriteMinidump();
 
   // Convenience form of WriteMinidump which does not require an
   // ExceptionHandler instance.
-  static bool WriteMinidump(const std::string &dump_path,
+  static bool WriteMinidump(const string &dump_path,
                             MinidumpCallback callback,
                             void *callback_context);
 
-  // This structure is passed to minidump_writer.h:WriteMinidump via an opaque
-  // blob. It shouldn't be needed in any user code.
-  struct CrashContext {
-    siginfo_t siginfo;
-    pid_t tid;  // the crashing thread.
-    struct ucontext context;
-    struct _libc_fpstate float_state;
-  };
+ private:
+  // Setup crash handler.
+  void SetupHandler();
+  // Setup signal handler for a signal.
+  void SetupHandler(int signo);
+  // Teardown the handler for a signal.
+  void TeardownHandler(int signo);
+  // Teardown the handler for a signal.
+  void TeardownHandler(int signo, struct sigaction *old);
+  // Teardown all handlers.
+  void TeardownAllHandler();
+
+  // Signal handler.
+  static void HandleException(int signo);
+
+  // If called from a signal handler, sighandler_ebp is the ebp of
+  // that signal handler's frame, and sig_ctx is an out parameter
+  // that will be set to point at the sigcontext that was placed
+  // on the stack by the kernel.  You can pass zero and NULL
+  // for the second and third parameters if you are not calling
+  // this from a signal handler.
+  bool InternalWriteMinidump(int signo, uintptr_t sighandler_ebp,
+                             struct sigcontext **sig_ctx);
+
+  // Generates a new ID and stores it in next_minidump_id, and stores the
+  // path of the next minidump to be written in next_minidump_path_.
+  void UpdateNextID();
 
  private:
-  bool InstallHandlers();
-  void UninstallHandlers();
-  void PreresolveSymbols();
+  FilterCallback filter_;
+  MinidumpCallback callback_;
+  void *callback_context_;
 
-  void UpdateNextID();
-  static void SignalHandler(int sig, siginfo_t* info, void* uc);
-  bool HandleSignal(int sig, siginfo_t* info, void* uc);
-  static int ThreadEntry(void* arg);
-  bool DoDump(pid_t crashing_process, const void* context,
-              size_t context_size);
+  // The directory in which a minidump will be written, set by the dump_path
+  // argument to the constructor, or set_dump_path.
+  string dump_path_;
 
-  const FilterCallback filter_;
-  const MinidumpCallback callback_;
-  void* const callback_context_;
+  // The basename of the next minidump to be written, without the extension
+  string next_minidump_id_;
 
-  std::string dump_path_;
-  std::string next_minidump_path_;
-  std::string next_minidump_id_;
+  // The full pathname of the next minidump to be written, including the file
+  // extension
+  string next_minidump_path_;
 
   // Pointers to C-string representations of the above. These are set
   // when the above are set so we can avoid calling c_str during
   // an exception.
-  const char* dump_path_c_;
-  const char* next_minidump_path_c_;
-  const char* next_minidump_id_c_;
+  const char *dump_path_c_;
+  const char *next_minidump_id_c_;
+  const char *next_minidump_path_c_;
 
-  const bool handler_installed_;
-  void* signal_stack;  // the handler stack.
-  HandlerCallback crash_handler_;
+  // True if the ExceptionHandler installed an unhandled exception filter
+  // when created (with an install_handler parameter set to true).
+  bool installed_handler_;
 
   // The global exception handler stack. This is need becuase there may exist
   // multiple ExceptionHandler instances in a process. Each will have itself
   // registered in this stack.
-  static std::vector<ExceptionHandler*> *handler_stack_;
+  static std::vector<ExceptionHandler *> *handler_stack_;
   // The index of the handler that should handle the next exception.
-  static unsigned handler_stack_index_;
+  static int handler_stack_index_;
   static pthread_mutex_t handler_stack_mutex_;
 
-  // A vector of the old signal handlers. The void* is a pointer to a newly
-  // allocated sigaction structure to avoid pulling in too many includes.
-  std::vector<std::pair<int, void *> > old_handlers_;
+  // The minidump generator.
+  MinidumpGenerator minidump_generator_;
+
+  // disallow copy ctor and operator=
+  explicit ExceptionHandler(const ExceptionHandler &);
+  void operator=(const ExceptionHandler &);
+
+  // The sigactions structure we use for each signal
+  struct sigaction act_;
+
+
+  // Keep the previous handlers for the signal.
+  // We're wasting a bit of memory here since we only change
+  // the handler for some signals but i want to avoid allocating
+  // memory in the signal handler
+  struct sigaction old_actions_[NSIG];
 };
 
 }  // namespace google_breakpad
 
-#endif  // CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_
+#endif  // CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H__
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler_test.cc
@@ -0,0 +1,124 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Author: Li Liu
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <pthread.h>
+#include <unistd.h>
+
+#include <cassert>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#include "client/linux/handler/exception_handler.h"
+#include "client/linux/handler/linux_thread.h"
+
+using namespace google_breakpad;
+
+// Thread use this to see if it should stop working.
+static bool should_exit = false;
+
+static int foo2(int arg) {
+  // Stack variable, used for debugging stack dumps.
+  /*DDDebug*/printf("%s:%d\n", __FUNCTION__, __LINE__);
+  int c = 0xcccccccc;
+  fprintf(stderr, "Thread trying to crash: %x\n", getpid());
+  c = *reinterpret_cast<int *>(0x5);
+  return c;
+}
+
+static int foo(int arg) {
+  // Stack variable, used for debugging stack dumps.
+  int b = 0xbbbbbbbb;
+  b = foo2(b);
+  return b;
+}
+
+static void *thread_crash(void *) {
+  // Stack variable, used for debugging stack dumps.
+  int a = 0xaaaaaaaa;
+  sleep(1);
+  a = foo(a);
+  printf("%x\n", a);
+  return NULL;
+}
+
+static void *thread_main(void *) {
+  while (!should_exit)
+    sleep(1);
+  return NULL;
+}
+
+static void CreateCrashThread() {
+  pthread_t h;
+  pthread_create(&h, NULL, thread_crash, NULL);
+  pthread_detach(h);
+}
+
+// Create working threads.
+static void CreateThread(int num) {
+  pthread_t h;
+  for (int i = 0; i < num; ++i) {
+    pthread_create(&h, NULL, thread_main, NULL);
+    pthread_detach(h);
+  }
+}
+
+// Callback when minidump written.
+static bool MinidumpCallback(const char *dump_path,
+                             const char *minidump_id,
+                             void *context,
+                             bool succeeded) {
+  int index = reinterpret_cast<int>(context);
+  printf("%d %s: %s is dumped\n", index, __FUNCTION__, minidump_id);
+  if (index == 0) {
+    should_exit = true;
+    return true;
+  }
+  // Don't process it.
+  return false;
+}
+
+int main(int argc, char *argv[]) {
+  int handler_index = 0;
+  ExceptionHandler handler_ignore(".", NULL, MinidumpCallback,
+                           (void*)handler_index, true);
+  ++handler_index;
+  ExceptionHandler handler_process(".", NULL, MinidumpCallback,
+                           (void*)handler_index, true);
+  CreateCrashThread();
+  CreateThread(10);
+
+  while (true)
+    sleep(1);
+  should_exit = true;
+
+  return 0;
+}
deleted file mode 100644
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/handler/exception_handler_unittest.cc
+++ /dev/null
@@ -1,256 +0,0 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include <string>
-
-#include <stdint.h>
-#include <unistd.h>
-#include <signal.h>
-#include <sys/poll.h>
-#include <sys/socket.h>
-#include <sys/uio.h>
-
-#include "client/linux/handler//exception_handler.h"
-#include "client/linux/minidump_writer/minidump_writer.h"
-#include "common/linux/linux_libc_support.h"
-#include "common/linux/linux_syscall_support.h"
-#include "breakpad_googletest_includes.h"
-
-// This provides a wrapper around system calls which may be
-// interrupted by a signal and return EINTR. See man 7 signal.
-#define HANDLE_EINTR(x) ({ \
-  typeof(x) __eintr_result__; \
-  do { \
-    __eintr_result__ = x; \
-  } while (__eintr_result__ == -1 && errno == EINTR); \
-  __eintr_result__;\
-})
-
-using namespace google_breakpad;
-
-static void sigchld_handler(int signo) { }
-
-class ExceptionHandlerTest : public ::testing::Test {
- protected:
-  void SetUp() {
-    // We need to be able to wait for children, so SIGCHLD cannot be SIG_IGN.
-    struct sigaction sa;
-    memset(&sa, 0, sizeof(sa));
-    sa.sa_handler = sigchld_handler;
-    ASSERT_NE(sigaction(SIGCHLD, &sa, &old_action), -1);
-  }
-
-  void TearDown() {
-    sigaction(SIGCHLD, &old_action, NULL);
-  }
-
-  struct sigaction old_action;
-};
-
-TEST(ExceptionHandlerTest, Simple) {
-  ExceptionHandler handler("/tmp", NULL, NULL, NULL, true);
-}
-
-static bool DoneCallback(const char* dump_path,
-                         const char* minidump_id,
-                         void* context,
-                         bool succeeded) {
-  if (!succeeded)
-    return succeeded;
-
-  int fd = (intptr_t) context;
-  uint32_t len = my_strlen(minidump_id);
-  HANDLE_EINTR(sys_write(fd, &len, sizeof(len)));
-  HANDLE_EINTR(sys_write(fd, minidump_id, len));
-  sys_close(fd);
-
-  return true;
-}
-
-TEST(ExceptionHandlerTest, ChildCrash) {
-  int fds[2];
-  ASSERT_NE(pipe(fds), -1);
-
-  const pid_t child = fork();
-  if (child == 0) {
-    close(fds[0]);
-    ExceptionHandler handler("/tmp", NULL, DoneCallback, (void*) fds[1],
-                             true);
-    *reinterpret_cast<int*>(NULL) = 0;
-  }
-  close(fds[1]);
-
-  int status;
-  ASSERT_NE(HANDLE_EINTR(waitpid(child, &status, 0)), -1);
-  ASSERT_TRUE(WIFSIGNALED(status));
-  ASSERT_EQ(WTERMSIG(status), SIGSEGV);
-
-  struct pollfd pfd;
-  memset(&pfd, 0, sizeof(pfd));
-  pfd.fd = fds[0];
-  pfd.events = POLLIN | POLLERR;
-
-  const int r = HANDLE_EINTR(poll(&pfd, 1, 0));
-  ASSERT_EQ(r, 1);
-  ASSERT_TRUE(pfd.revents & POLLIN);
-
-  uint32_t len;
-  ASSERT_EQ(read(fds[0], &len, sizeof(len)), sizeof(len));
-  ASSERT_LT(len, 2048);
-  char* filename = reinterpret_cast<char*>(malloc(len + 1));
-  ASSERT_EQ(read(fds[0], filename, len), len);
-  filename[len] = 0;
-  close(fds[0]);
-
-  const std::string minidump_filename = std::string("/tmp/") + filename +
-                                        ".dmp";
-
-  struct stat st;
-  ASSERT_EQ(stat(minidump_filename.c_str(), &st), 0);
-  ASSERT_GT(st.st_size, 0u);
-  unlink(minidump_filename.c_str());
-}
-
-static const unsigned kControlMsgSize =
-    CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred));
-
-static bool
-CrashHandler(const void* crash_context, size_t crash_context_size,
-             void* context) {
-  const int fd = (intptr_t) context;
-  int fds[2];
-  pipe(fds);
-
-  struct kernel_msghdr msg = {0};
-  struct kernel_iovec iov;
-  iov.iov_base = const_cast<void*>(crash_context);
-  iov.iov_len = crash_context_size;
-
-  msg.msg_iov = &iov;
-  msg.msg_iovlen = 1;
-  char cmsg[kControlMsgSize];
-  memset(cmsg, 0, kControlMsgSize);
-  msg.msg_control = cmsg;
-  msg.msg_controllen = sizeof(cmsg);
-
-  struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg);
-  hdr->cmsg_level = SOL_SOCKET;
-  hdr->cmsg_type = SCM_RIGHTS;
-  hdr->cmsg_len = CMSG_LEN(sizeof(int));
-  *((int*) CMSG_DATA(hdr)) = fds[1];
-  hdr = CMSG_NXTHDR((struct msghdr*) &msg, hdr);
-  hdr->cmsg_level = SOL_SOCKET;
-  hdr->cmsg_type = SCM_CREDENTIALS;
-  hdr->cmsg_len = CMSG_LEN(sizeof(struct ucred));
-  struct ucred *cred = reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
-  cred->uid = getuid();
-  cred->gid = getgid();
-  cred->pid = getpid();
-
-  HANDLE_EINTR(sys_sendmsg(fd, &msg, 0));
-  sys_close(fds[1]);
-
-  char b;
-  HANDLE_EINTR(sys_read(fds[0], &b, 1));
-
-  return true;
-}
-
-TEST(ExceptionHandlerTest, ExternalDumper) {
-  int fds[2];
-  ASSERT_NE(socketpair(AF_UNIX, SOCK_DGRAM, 0, fds), -1);
-  static const int on = 1;
-  setsockopt(fds[0], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
-  setsockopt(fds[1], SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
-
-  const pid_t child = fork();
-  if (child == 0) {
-    close(fds[0]);
-    ExceptionHandler handler("/tmp", NULL, NULL, (void*) fds[1], true);
-    handler.set_crash_handler(CrashHandler);
-    *reinterpret_cast<int*>(NULL) = 0;
-  }
-
-  close(fds[1]);
-  struct msghdr msg = {0};
-  struct iovec iov;
-  static const unsigned kCrashContextSize =
-      sizeof(ExceptionHandler::CrashContext);
-  char context[kCrashContextSize];
-  char control[kControlMsgSize];
-  iov.iov_base = context;
-  iov.iov_len = kCrashContextSize;
-  msg.msg_iov = &iov;
-  msg.msg_iovlen = 1;
-  msg.msg_control = control;
-  msg.msg_controllen = kControlMsgSize;
-
-  const ssize_t n = HANDLE_EINTR(recvmsg(fds[0], &msg, 0));
-  ASSERT_EQ(n, kCrashContextSize);
-  ASSERT_EQ(msg.msg_controllen, kControlMsgSize);
-  ASSERT_EQ(msg.msg_flags, 0);
-
-  pid_t crashing_pid = -1;
-  int signal_fd = -1;
-  for (struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); hdr;
-       hdr = CMSG_NXTHDR(&msg, hdr)) {
-    if (hdr->cmsg_level != SOL_SOCKET)
-      continue;
-    if (hdr->cmsg_type == SCM_RIGHTS) {
-      const unsigned len = hdr->cmsg_len -
-          (((uint8_t*)CMSG_DATA(hdr)) - (uint8_t*)hdr);
-      ASSERT_EQ(len, sizeof(int));
-      signal_fd = *((int *) CMSG_DATA(hdr));
-    } else if (hdr->cmsg_type == SCM_CREDENTIALS) {
-      const struct ucred *cred =
-          reinterpret_cast<struct ucred*>(CMSG_DATA(hdr));
-      crashing_pid = cred->pid;
-    }
-  }
-
-  ASSERT_NE(crashing_pid, -1);
-  ASSERT_NE(signal_fd, -1);
-
-  char templ[] = "/tmp/exception-handler-unittest-XXXXXX";
-  mktemp(templ);
-  ASSERT_TRUE(WriteMinidump(templ, crashing_pid, context,
-                            kCrashContextSize));
-  static const char b = 0;
-  HANDLE_EINTR(write(signal_fd, &b, 1));
-
-  int status;
-  ASSERT_NE(HANDLE_EINTR(waitpid(child, &status, 0)), -1);
-  ASSERT_TRUE(WIFSIGNALED(status));
-  ASSERT_EQ(WTERMSIG(status), SIGSEGV);
-
-  struct stat st;
-  ASSERT_EQ(stat(templ, &st), 0);
-  ASSERT_GT(st.st_size, 0u);
-  unlink(templ);
-}
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/google-breakpad/src/client/linux/handler/linux_thread.cc
@@ -0,0 +1,411 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Author: Li Liu
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+#include <errno.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <sys/ptrace.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <string.h>
+
+#include <algorithm>
+#include <cassert>
+#include <cstdio>
+#include <cstdlib>
+#include <functional>
+
+#include "client/linux/handler/linux_thread.h"
+
+using namespace google_breakpad;
+
+// This unamed namespace contains helper function.
+namespace {
+
+// Context information for the callbacks when validating address by listing
+// modules.
+struct AddressValidatingContext {
+  uintptr_t address;
+  bool is_mapped;
+
+  AddressValidatingContext() : address(0UL), is_mapped(false) {
+  }
+};
+
+// Convert from string to int.
+bool LocalAtoi(char *s, int *r) {
+  assert(s != NULL);
+  assert(r != NULL);
+  char *endptr = NULL;
+  int ret = strtol(s, &endptr, 10);
+  if (endptr == s)
+    return false;
+  *r = ret;
+  return true;
+}
+
+// Fill the proc path of a thread given its id.
+void FillProcPath(int pid, char *path, int path_size) {
+  char pid_str[32];
+  snprintf(pid_str, sizeof(pid_str), "%d", pid);
+  snprintf(path, path_size, "/proc/%s/", pid_str);
+}
+
+// Read thread info from /proc/$pid/status.
+bool ReadThreadInfo(int pid, ThreadInfo *info) {
+  assert(info != NULL);
+  char status_path[80];
+  // Max size we want to read from status file.
+  static const int kStatusMaxSize = 1024;
+  char status_content[kStatusMaxSize];
+
+  FillProcPath(pid, status_path, sizeof(status_path));
+  strcat(status_path, "status");
+  int fd = open(status_path, O_RDONLY, 0);
+  if (fd < 0)
+    return false;
+
+  int num_read = read(fd, status_content, kStatusMaxSize - 1);
+  if (num_read < 0) {
+    close(fd);
+    return false;
+  }
+  close(fd);
+  status_content[num_read] = '\0';
+
+  char *tgid_start = strstr(status_content, "Tgid:");
+  if (tgid_start)
+    sscanf(tgid_start, "Tgid:\t%d\n", &(info->tgid));
+  else
+    // tgid not supported by kernel??
+    info->tgid = 0;
+
+  tgid_start = strstr(status_content, "Pid:");
+  if (tgid_start) {
+    sscanf(tgid_start, "Pid:\t%d\n" "PPid:\t%d\n", &(info->pid),
+           &(info->ppid));
+    return true;
+  }
+  return false;
+}
+
+// Callback invoked for each mapped module.
+// It use the module's adderss range to validate the address.
+bool IsAddressInModuleCallback(const ModuleInfo &module_info,
+                               void *context) {
+  AddressValidatingContext *addr =
+    reinterpret_cast<AddressValidatingContext *>(context);
+  addr->is_mapped = ((addr->address >= module_info.start_addr) &&
+                     (addr->address <= module_info.start_addr +
+                      module_info.size));
+  return !addr->is_mapped;
+}
+
+#if defined(__i386__) && !defined(NO_FRAME_POINTER)
+void *GetNextFrame(void **last_ebp) {
+  void *sp = *last_ebp;
+  if ((unsigned long)sp == (unsigned long)last_ebp)
+    return NULL;
+  if ((unsigned long)sp & (sizeof(void *) - 1))
+    return NULL;
+  if ((unsigned long)sp - (unsigned long)last_ebp > 100000)
+    return NULL;
+  return sp;
+}
+#else
+void *GetNextFrame(void **last_ebp) {
+  return reinterpret_cast<void*>(last_ebp);
+}
+#endif
+
+// Suspend a thread by attaching to it.
+bool SuspendThread(int pid, void *context) {
+  // This may fail if the thread has just died or debugged.
+  errno = 0;
+  if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) != 0 &&
+      errno != 0) {
+    return false;
+  }
+  while (waitpid(pid, NULL, __WALL) < 0) {
+    if (errno != EINTR) {
+      ptrace(PTRACE_DETACH, pid, NULL, NULL);
+      return false;
+    }
+  }
+  return true;
+}
+
+// Resume a thread by detaching from it.
+bool ResumeThread(int pid, void *context) {
+  return ptrace(PTRACE_DETACH, pid, NULL, NULL) >= 0;
+}
+
+// Callback to get the thread information.
+// Will be called for each thread found.
+bool ThreadInfoCallback(int pid, void *context) {
+  CallbackParam<ThreadCallback> *thread_callback =
+    reinterpret_cast<CallbackParam<ThreadCallback> *>(context);
+  ThreadInfo thread_info;
+  if (ReadThreadInfo(pid, &thread_info) && thread_callback) {
+    // Invoke callback from caller.
+    return (thread_callback->call_back)(thread_info, thread_callback->context);
+  }
+  return false;
+}
+
+}  // namespace
+
+namespace google_breakpad {
+
+LinuxThread::LinuxThread(int pid) : pid_(pid) , threads_suspened_(false) {
+}
+
+LinuxThread::~LinuxThread() {
+  if (threads_suspened_)
+    ResumeAllThreads();
+}
+
+int LinuxThread::SuspendAllThreads() {
+  CallbackParam<PidCallback> callback_param(SuspendThread, NULL);
+  int thread_count = 0;
+  if ((thread_count = IterateProcSelfTask(pid_, &callback_param)) > 0)
+    threads_suspened_ = true;
+  return thread_count;
+}
+
+void LinuxThread::ResumeAllThreads() const {
+  CallbackParam<PidCallback> callback_param(ResumeThread, NULL);
+  IterateProcSelfTask(pid_, &callback_param);
+}
+
+int LinuxThread::GetThreadCount() const {
+  return IterateProcSelfTask(pid_, NULL);
+}
+
+int LinuxThread::ListThreads(
+    CallbackParam<ThreadCallback> *thread_callback_param) const {
+  CallbackParam<PidCallback> callback_param(ThreadInfoCallback,
+                                            thread_callback_param);
+  return IterateProcSelfTask(pid_, &callback_param);
+}
+
+bool LinuxThread::GetRegisters(int pid, user_regs_struct *regs) const {
+  assert(regs);
+  return (regs != NULL &&
+          (ptrace(PTRACE_GETREGS, pid, NULL, regs) == 0) &&
+          errno == 0);
+}
+
+// Get the floating-point registers of a thread.
+// The caller must get the thread pid by ListThreads.
+bool LinuxThread::GetFPRegisters(int pid, user_fpregs_struct *regs) const {
+  assert(regs);
+  return (regs != NULL &&
+          (ptrace(PTRACE_GETREGS, pid, NULL, regs) ==0) &&
+          errno == 0);
+}
+
+bool LinuxThread::GetFPXRegisters(int pid, user_fpxregs_struct *regs) const {
+  assert(regs);
+  return (regs != NULL &&
+          (ptrace(PTRACE_GETFPREGS, pid, NULL, regs) != 0) &&
+          errno == 0);
+}
+
+bool LinuxThread::GetDebugRegisters(int pid, DebugRegs *regs) const {
+  assert(regs);
+
+#define GET_DR(name, num)\
+  name->dr##num = ptrace(PTRACE_PEEKUSER, pid,\
+                         offsetof(struct user, u_debugreg[num]), NULL)
+  GET_DR(regs, 0);
+  GET_DR(regs, 1);
+  GET_DR(regs, 2);
+  GET_DR(regs, 3);
+  GET_DR(regs, 4);
+  GET_DR(regs, 5);
+  GET_DR(regs, 6);
+  GET_DR(regs, 7);
+  return true;
+}
+
+int LinuxThread::GetThreadStackDump(uintptr_t current_ebp,
+                                    uintptr_t current_esp,
+                                    void *buf,
+                                    int buf_size) const {
+  assert(buf);
+  assert(buf_size > 0);
+
+  uintptr_t stack_bottom = GetThreadStackBottom(current_ebp);
+  int size = stack_bottom - current_esp;
+  size = buf_size > size ? size : buf_size;
+  if (size > 0)
+    memcpy(buf, reinterpret_cast<void*>(current_esp), size);
+  return size;
+}
+
+// Get the stack bottom of a thread by stack walking. It works
+// unless the stack has been corrupted or the frame pointer has been omited.
+// This is just a temporary solution before we get better ideas about how
+// this can be done.
+//
+// We will check each frame address by checking into module maps.
+// TODO(liuli): Improve it.
+uintptr_t LinuxThread::GetThreadStackBottom(uintptr_t current_ebp) const {
+  void **sp = reinterpret_cast<void **>(current_ebp);
+  void **previous_sp = sp;
+  while (sp && IsAddressMapped((uintptr_t)sp)) {
+    previous_sp = sp;
+    sp = reinterpret_cast<void **>(GetNextFrame(sp));
+  }
+  return (uintptr_t)previous_sp;
+}
+
+int LinuxThread::GetModuleCount() const {
+  return ListModules(NULL);
+}
+
+int LinuxThread::ListModules(
+    CallbackParam<ModuleCallback> *callback_param) const {
+  char line[512];
+  const char *maps_path = "/proc/self/maps";
+
+  int module_count = 0;
+  FILE *fp = fopen(maps_path, "r");
+  if (fp == NULL)
+    return -1;
+
+  uintptr_t start_addr;
+  uintptr_t end_addr;
+  while (fgets(line, sizeof(line), fp) != NULL) {
+    if (sscanf(line, "%x-%x", &start_addr, &end_addr) == 2) {
+      ModuleInfo module;
+      memset(&module, 0, sizeof(module));
+      module.start_addr = start_addr;
+      module.size = end_addr - start_addr;
+      char *name = NULL;
+      assert(module.size > 0);
+      // Only copy name if the name is a valid path name.
+      if ((name = strchr(line, '/')) != NULL) {
+        // Get rid of the last '\n' in line
+        char *last_return = strchr(line, '\n');
+        if (last_return != NULL)
+          *last_return = '\0';
+        // Keep a space for the ending 0.
+        strncpy(module.name, name, sizeof(module.name) - 1);
+        ++module_count;
+      }
+      if (callback_param &&
+          !(callback_param->call_back(module, callback_param->context)))
+        break;
+    }
+  }
+  fclose(fp);
+  return module_count;
+}
+
+// Parse /proc/$pid/tasks to list all the threads of the process identified by
+// pid.
+int LinuxThread::IterateProcSelfTask(int pid,
+                          CallbackParam<PidCallback> *callback_param) const {
+  char task_path[80];
+  FillProcPath(pid, task_path, sizeof(task_path));
+  strcat(task_path, "task");
+
+  DIR *dir = opendir(task_path);
+  if (dir == NULL)
+    return -1;
+
+  int pid_number = 0;
+  // Record the last pid we've found. This is used for duplicated thread
+  // removal. Duplicated thread information can be found in /proc/$pid/tasks.
+  int last_pid = -1;
+  struct dirent *entry = NULL;
+  while ((entry = readdir(dir)) != NULL) {
+    if (strcmp(entry->d_name, ".") &&
+        strcmp(entry->d_name, "..")) {
+      int tpid = 0;
+      if (LocalAtoi(entry->d_name, &tpid) &&
+          last_pid != tpid) {
+        last_pid = tpid;
+        ++pid_number;
+        // Invoke the callback.
+        if (callback_param &&
+            !(callback_param->call_back)(tpid, callback_param->context))
+          break;
+      }
+    }
+  }
+  closedir(dir);
+  return pid_number;
+}
+
+// Check if the address is a valid virtual address.
+// If the address is in any of the mapped modules, we take it as valid.
+// Otherwise it is invalid.
+bool LinuxThread::IsAddressMapped(uintptr_t address) const {
+  AddressValidatingContext addr;
+  addr.address = address;
+  CallbackParam<ModuleCallback> callback_param(IsAddressInModuleCallback,
+                                               &addr);
+  ListModules(&callback_param);
+  return addr.is_mapped;
+}
+
+bool LinuxThread::FindSigContext(uintptr_t sighandler_ebp,
+                                 struct sigcontext **sig_ctx) {
+  uintptr_t previous_ebp;
+  const int MAX_STACK_DEPTH = 10;
+  int depth_counter = 0;
+
+  do {
+    // We're looking for a |struct sigcontext| as the second parameter
+    // to a signal handler function call.  Luckily, the sigcontext
+    // has an ebp member which should match the ebp pointed to
+    // by the ebp of the signal handler frame.
+    previous_ebp = reinterpret_cast<uintptr_t>(GetNextFrame(
+                                  reinterpret_cast<void**>(sighandler_ebp)));
+    // The stack looks like this:
+    // | previous ebp | previous eip | first param | second param |,
+    // so we need to offset by 3 to get to the second parameter.
+    *sig_ctx = reinterpret_cast<struct sigcontext*>(sighandler_ebp +
+                                                    3 * sizeof(uintptr_t));
+    sighandler_ebp = previous_ebp;
+    depth_counter++;
+  } while(previous_ebp != (*sig_ctx)->ebp && sighandler_ebp != 0 &&
+          IsAddressMapped(sighandler_ebp) && depth_counter < MAX_STACK_DEPTH);
+
+  return previous_ebp == (*sig_ctx)->ebp && previous_ebp != 0;
+}
+
+}  // namespace google_breakpad
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/google-breakpad/src/client/linux/handler/linux_thread.h
@@ -0,0 +1,204 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Author: Li Liu
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+#ifndef CLIENT_LINUX_HANDLER_LINUX_THREAD_H__
+#define CLIENT_LINUX_HANDLER_LINUX_THREAD_H__
+
+#include <stdint.h>
+#include <sys/user.h>
+
+namespace google_breakpad {
+
+// Max module path name length.
+#define kMaxModuleNameLength 256
+
+// Holding information about a thread in the process.
+struct ThreadInfo {
+  // Id of the thread group.
+  int tgid;
+  // Id of the thread.
+  int pid;
+  // Id of the parent process.
+  int ppid;
+};
+
+// Holding infomaton about a module in the process.
+struct ModuleInfo {
+  char name[kMaxModuleNameLength];
+  uintptr_t start_addr;
+  int size;
+};
+
+// Holding debug registers.
+struct DebugRegs {
+  int dr0;
+  int dr1;
+  int dr2;
+  int dr3;
+  int dr4;
+  int dr5;
+  int dr6;
+  int dr7;
+};
+
+// A callback to run when got a thread in the process.
+// Return true will go on to the next thread while return false will stop the
+// iteration.
+typedef bool (*ThreadCallback)(const ThreadInfo &thread_info, void *context);
+
+// A callback to run when a new module is found in the process.
+// Return true will go on to the next module while return false will stop the
+// iteration.
+typedef bool (*ModuleCallback)(const ModuleInfo &module_info, void *context);
+
+// Holding the callback information.
+template<class CallbackFunc>
+struct CallbackParam {
+  // Callback function address.
+  CallbackFunc call_back;
+  // Callback context;
+  void *context;
+
+  CallbackParam() : call_back(NULL), context(NULL) {
+  }
+
+  CallbackParam(CallbackFunc func, void *func_context) :
+    call_back(func), context(func_context) {
+  }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+//
+// LinuxThread
+//
+// Provides handy support for operation on linux threads.
+// It uses ptrace to get thread registers. Since ptrace only works in a
+// different process other than the one being ptraced, user of this class
+// should create another process before using the class.
+//
+// The process should be created in the following way:
+//    int cloned_pid = clone(ProcessEntryFunction, stack_address,
+//                           CLONE_VM | CLONE_FILES | CLONE_FS | CLONE_UNTRACED,
+//                           (void*)&arguments);
+//    waitpid(cloned_pid, NULL, __WALL);
+//
+// If CLONE_VM is not used, GetThreadStackBottom, GetThreadStackDump
+// will not work since it just use memcpy to get the stack dump.
+//
+class LinuxThread {
+ public:
+  // Create a LinuxThread instance to list all the threads in a process.
+  explicit LinuxThread(int pid);
+  ~LinuxThread();
+
+  // Stop all the threads in the process.
+  // Return the number of stopped threads in the process.
+  // Return -1 means failed to stop threads.
+  int SuspendAllThreads();
+
+  // Resume all the suspended threads.
+  void ResumeAllThreads() const;
+
+  // Get the count of threads in the process.
+  // Return -1 means error.
+  int GetThreadCount() const;
+
+  // List the threads of process.
+  // Whenever there is a thread found, the callback will be invoked to process
+  // the information.
+  // Return number of threads listed.
+  int ListThreads(CallbackParam<ThreadCallback> *thread_callback_param) const;
+
+  // Get the general purpose registers of a thread.
+  // The caller must get the thread pid by ListThreads.
+  bool GetRegisters(int pid, user_regs_struct *regs) const;
+
+  // Get the floating-point registers of a thread.
+  // The caller must get the thread pid by ListThreads.
+  bool GetFPRegisters(int pid, user_fpregs_struct *regs) const;
+
+  // Get all the extended floating-point registers. May not work on all
+  // machines.
+  // The caller must get the thread pid by ListThreads.
+  bool GetFPXRegisters(int pid, user_fpxregs_struct *regs) const;
+
+  // Get the debug registers.
+  // The caller must get the thread pid by ListThreads.
+  bool GetDebugRegisters(int pid, DebugRegs *regs) const;
+
+  // Get the stack memory dump.
+  int GetThreadStackDump(uintptr_t current_ebp,
+                         uintptr_t current_esp,
+                         void *buf,
+                         int buf_size) const;
+
+  // Get the module count of the current process.
+  int GetModuleCount() const;
+
+  // Get the mapped modules in the address space.
+  // Whenever a module is found, the callback will be invoked to process the
+  // information.
+  // Return how may modules are found.
+  int ListModules(CallbackParam<ModuleCallback> *callback_param) const;
+
+  // Get the bottom of the stack from ebp.
+  uintptr_t GetThreadStackBottom(uintptr_t current_ebp) const;
+
+  // Finds a sigcontext on the stack given the ebp of our signal handler.
+  bool FindSigContext(uintptr_t sighandler_ebp, struct sigcontext **sig_ctx);
+
+ private:
+  // This callback will run when a new thread has been found.
+  typedef bool (*PidCallback)(int pid, void *context);
+
+  // Read thread information from /proc/$pid/task.
+  // Whenever a thread has been found, and callback will be invoked with
+  // the pid of the thread.
+  // Return number of threads found.
+  // Return -1 means the directory doesn't exist.
+  int IterateProcSelfTask(int pid,
+                          CallbackParam<PidCallback> *callback_param) const;
+
+  // Check if the address is a valid virtual address.
+  bool IsAddressMapped(uintptr_t address) const;
+
+ private:
+  // The pid of the process we are listing threads.
+  int pid_;
+
+  // Mark if we have suspended the threads.
+  bool threads_suspened_;
+};
+
+}  // namespace google_breakpad
+
+#endif  // CLIENT_LINUX_HANDLER_LINUX_THREAD_H__
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/google-breakpad/src/client/linux/handler/linux_thread_test.cc
@@ -0,0 +1,224 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Author: Li Liu
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <pthread.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#include "client/linux/handler/linux_thread.h"
+
+using namespace google_breakpad;
+
+// Thread use this to see if it should stop working.
+static bool should_exit = false;
+
+static void foo2(int *a) {
+  // Stack variable, used for debugging stack dumps.
+  int c = 0xcccccccc;
+  c = c;
+  while (!should_exit)
+    sleep(1);
+}
+
+static void foo() {
+  // Stack variable, used for debugging stack dumps.
+  int a = 0xaaaaaaaa;
+  foo2(&a);
+}
+
+static void *thread_main(void *) {
+  // Stack variable, used for debugging stack dumps.
+  int b = 0xbbbbbbbb;
+  b = b;
+  while (!should_exit) {
+    foo();
+  }
+  return NULL;
+}
+
+static void CreateThreads(int num) {
+  pthread_t handle;
+  for (int i = 0; i < num; i++) {
+    if (0 != pthread_create(&handle, NULL, thread_main, NULL))
+      fprintf(stderr, "Failed to create thread.\n");
+    else
+      pthread_detach(handle);
+  }
+}
+
+static bool ProcessOneModule(const struct ModuleInfo &module_info,
+                             void *context) {
+  printf("0x%x[%8d]         %s\n", module_info.start_addr, module_info.size,
+         module_info.name);
+  return true;
+}
+
+static bool ProcessOneThread(const struct ThreadInfo &thread_info,
+                             void *context) {
+  printf("\n\nPID: %d, TGID: %d, PPID: %d\n",
+         thread_info.pid,
+         thread_info.tgid,
+         thread_info.ppid);
+
+  struct user_regs_struct regs;
+  struct user_fpregs_struct fp_regs;
+  struct user_fpxregs_struct fpx_regs;
+  struct DebugRegs dbg_regs;
+
+  LinuxThread *threads = reinterpret_cast<LinuxThread *>(context);
+  memset(&regs, 0, sizeof(regs));
+  if (threads->GetRegisters(thread_info.pid, &regs)) {
+    printf("  gs                           = 0x%lx\n", regs.xgs);
+    printf("  fs                           = 0x%lx\n", regs.xfs);
+    printf("  es                           = 0x%lx\n", regs.xes);
+    printf("  ds                           = 0x%lx\n", regs.xds);
+    printf("  edi                          = 0x%lx\n", regs.edi);
+    printf("  esi                          = 0x%lx\n", regs.esi);
+    printf("  ebx                          = 0x%lx\n", regs.ebx);
+    printf("  edx                          = 0x%lx\n", regs.edx);
+    printf("  ecx                          = 0x%lx\n", regs.ecx);
+    printf("  eax                          = 0x%lx\n", regs.eax);
+    printf("  ebp                          = 0x%lx\n", regs.ebp);
+    printf("  eip                          = 0x%lx\n", regs.eip);
+    printf("  cs                           = 0x%lx\n", regs.xcs);
+    printf("  eflags                       = 0x%lx\n", regs.eflags);
+    printf("  esp                          = 0x%lx\n", regs.esp);
+    printf("  ss                           = 0x%lx\n", regs.xss);
+  } else {
+    fprintf(stderr, "ERROR: Failed to get general purpose registers\n");
+  }
+  memset(&fp_regs, 0, sizeof(fp_regs));
+  if (threads->GetFPRegisters(thread_info.pid, &fp_regs)) {
+    printf("\n Floating point registers:\n");
+    printf("  fctl                         = 0x%lx\n", fp_regs.cwd);
+    printf("  fstat                        = 0x%lx\n", fp_regs.swd);
+    printf("  ftag                         = 0x%lx\n", fp_regs.twd);
+    printf("  fioff                        = 0x%lx\n", fp_regs.fip);
+    printf("  fiseg                        = 0x%lx\n", fp_regs.fcs);
+    printf("  fooff                        = 0x%lx\n", fp_regs.foo);
+    printf("  foseg                        = 0x%lx\n", fp_regs.fos);
+    int st_space_size = sizeof(fp_regs.st_space) / sizeof(fp_regs.st_space[0]);
+    printf("  st_space[%2d]                 = 0x", st_space_size);
+    for (int i = 0; i < st_space_size; ++i)
+      printf("%02lx", fp_regs.st_space[i]);
+    printf("\n");
+  } else {
+    fprintf(stderr, "ERROR: Failed to get floating-point registers\n");
+  }
+  memset(&fpx_regs, 0, sizeof(fpx_regs));
+  if (threads->GetFPXRegisters(thread_info.pid, &fpx_regs)) {
+    printf("\n Extended floating point registers:\n");
+    printf("  fctl                         = 0x%x\n", fpx_regs.cwd);
+    printf("  fstat                        = 0x%x\n", fpx_regs.swd);
+    printf("  ftag                         = 0x%x\n", fpx_regs.twd);
+    printf("  fioff                        = 0x%lx\n", fpx_regs.fip);
+    printf("  fiseg                        = 0x%lx\n", fpx_regs.fcs);
+    printf("  fooff                        = 0x%lx\n", fpx_regs.foo);
+    printf("  foseg                        = 0x%lx\n", fpx_regs.fos);
+    printf("  fop                          = 0x%x\n", fpx_regs.fop);
+    printf("  mxcsr                        = 0x%lx\n", fpx_regs.mxcsr);
+    int space_size = sizeof(fpx_regs.st_space) / sizeof(fpx_regs.st_space[0]);
+    printf("  st_space[%2d]                 = 0x", space_size);
+    for (int i = 0; i < space_size; ++i)
+      printf("%02lx", fpx_regs.st_space[i]);
+    printf("\n");
+    space_size = sizeof(fpx_regs.xmm_space) / sizeof(fpx_regs.xmm_space[0]);
+    printf("  xmm_space[%2d]                = 0x", space_size);
+    for (int i = 0; i < space_size; ++i)
+      printf("%02lx", fpx_regs.xmm_space[i]);
+    printf("\n");
+  }
+  if (threads->GetDebugRegisters(thread_info.pid, &dbg_regs)) {
+    printf("\n Debug registers:\n");
+    printf("  dr0                          = 0x%x\n", dbg_regs.dr0);
+    printf("  dr1                          = 0x%x\n", dbg_regs.dr1);
+    printf("  dr2                          = 0x%x\n", dbg_regs.dr2);
+    printf("  dr3                          = 0x%x\n", dbg_regs.dr3);
+    printf("  dr4                          = 0x%x\n", dbg_regs.dr4);
+    printf("  dr5                          = 0x%x\n", dbg_regs.dr5);
+    printf("  dr6                          = 0x%x\n", dbg_regs.dr6);
+    printf("  dr7                          = 0x%x\n", dbg_regs.dr7);
+    printf("\n");
+  }
+  if (regs.esp != 0) {
+    // Print the stack content.
+    int size = 1024 * 2;
+    char *buf = new char[size];
+    size = threads->GetThreadStackDump(regs.ebp,
+                                       regs.esp,
+                                      (void*)buf, size);
+    printf(" Stack content:                 = 0x");
+    size /= sizeof(unsigned long);
+    unsigned long *p_buf = (unsigned long *)(buf);
+    for (int i = 0; i < size; i += 1)
+      printf("%.8lx ", p_buf[i]);
+    delete []buf;
+    printf("\n");
+  }
+  return true;
+}
+
+static int PrintAllThreads(void *argument) {
+  int pid = (int)argument;
+
+  LinuxThread threads(pid);
+  int total_thread = threads.SuspendAllThreads();
+  printf("There are %d threads in the process: %d\n", total_thread, pid);
+  int total_module = threads.GetModuleCount();
+  printf("There are %d modules in the process: %d\n", total_module, pid);
+  CallbackParam<ModuleCallback> module_callback(ProcessOneModule, &threads);
+  threads.ListModules(&module_callback);
+  CallbackParam<ThreadCallback> thread_callback(ProcessOneThread, &threads);
+  threads.ListThreads(&thread_callback);
+  return 0;
+}
+
+int main(int argc, char **argv) {
+  int pid = getpid();
+  printf("Main thread is %d\n", pid);
+  CreateThreads(1);
+  // Create stack for the process.
+  char *stack = new char[1024 * 100];
+  int cloned_pid = clone(PrintAllThreads, stack + 1024 * 100,
+                           CLONE_VM | CLONE_FILES | CLONE_FS | CLONE_UNTRACED,
+                           (void*)getpid());
+  waitpid(cloned_pid, NULL, __WALL);
+  should_exit = true;
+  printf("Test finished.\n");
+
+  delete []stack;
+  return 0;
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/google-breakpad/src/client/linux/handler/minidump_generator.cc
@@ -0,0 +1,816 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Author: Li Liu
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <fcntl.h>
+#include <pthread.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/utsname.h>
+#include <sys/wait.h>
+
+#include <cstdlib>
+#include <cstdio>
+#include <ctime>
+#include <string.h>
+
+#include "common/linux/file_id.h"
+#include "client/linux/handler/linux_thread.h"
+#include "client/minidump_file_writer.h"
+#include "client/minidump_file_writer-inl.h"
+#include "google_breakpad/common/minidump_format.h"
+#include "client/linux/handler/minidump_generator.h"
+
+#ifndef CLONE_UNTRACED
+#define CLONE_UNTRACED 0x00800000
+#endif
+
+// This unnamed namespace contains helper functions.
+namespace {
+
+using namespace google_breakpad;
+
+// Argument for the writer function.
+struct WriterArgument {
+  MinidumpFileWriter *minidump_writer;
+
+  // Context for the callback.
+  void *version_context;
+
+  // Pid of the thread who called WriteMinidumpToFile
+  int requester_pid;
+
+  // The stack bottom of the thread which caused the dump.
+  // Mainly used to find the thread id of the crashed thread since signal
+  // handler may not be called in the thread who caused it.
+  uintptr_t crashed_stack_bottom;
+
+  // Pid of the crashing thread.
+  int crashed_pid;
+
+  // Signal number when crash happed. Can be 0 if this is a requested dump.
+  int signo;
+
+  // The ebp of the signal handler frame.  Can be zero if this
+  // is a requested dump.
+  uintptr_t sighandler_ebp;
+
+  // Signal context when crash happed. Can be NULL if this is a requested dump.
+  // This is actually an out parameter, but it will be filled in at the start
+  // of the writer thread.
+  struct sigcontext *sig_ctx;
+
+  // Used to get information about the threads.
+  LinuxThread *thread_lister;
+};
+
+// Holding context information for the callback of finding the crashing thread.
+struct FindCrashThreadContext {
+  const LinuxThread *thread_lister;
+  uintptr_t crashing_stack_bottom;
+  int crashing_thread_pid;
+
+  FindCrashThreadContext() :
+    thread_lister(NULL),
+    crashing_stack_bottom(0UL),
+    crashing_thread_pid(-1) {
+  }
+};
+
+// Callback for list threads.
+// It will compare the stack bottom of the provided thread with the stack
+// bottom of the crashed thread, it they are eqaul, this is thread is the one
+// who crashed.
+bool IsThreadCrashedCallback(const ThreadInfo &thread_info, void *context) {
+  FindCrashThreadContext *crashing_context =
+    static_cast<FindCrashThreadContext *>(context);
+  const LinuxThread *thread_lister = crashing_context->thread_lister;
+  struct user_regs_struct regs;
+  if (thread_lister->GetRegisters(thread_info.pid, &regs)) {
+    uintptr_t last_ebp = regs.ebp;
+    uintptr_t stack_bottom = thread_lister->GetThreadStackBottom(last_ebp);
+    if (stack_bottom > last_ebp &&
+        stack_bottom == crashing_context->crashing_stack_bottom) {
+      // Got it. Stop iteration.
+      crashing_context->crashing_thread_pid = thread_info.pid;
+      return false;
+    }
+  }
+  return true;
+}
+
+// Find the crashing thread id.
+// This is done based on stack bottom comparing.
+int FindCrashingThread(uintptr_t crashing_stack_bottom,
+                       int requester_pid,
+                       const LinuxThread *thread_lister) {
+  FindCrashThreadContext context;
+  context.thread_lister = thread_lister;
+  context.crashing_stack_bottom = crashing_stack_bottom;
+  CallbackParam<ThreadCallback> callback_param(IsThreadCrashedCallback,
+                                               &context);
+  thread_lister->ListThreads(&callback_param);
+  return context.crashing_thread_pid;
+}
+
+// Write the thread stack info minidump.
+bool WriteThreadStack(uintptr_t last_ebp,
+                      uintptr_t last_esp,
+                      const LinuxThread *thread_lister,
+                      UntypedMDRVA *memory,
+                      MDMemoryDescriptor *loc) {
+  // Maximum stack size for a thread.
+  uintptr_t stack_bottom = thread_lister->GetThreadStackBottom(last_ebp);
+  if (stack_bottom > last_esp) {
+    int size = stack_bottom - last_esp;
+    if (size > 0) {
+      if (!memory->Allocate(size))
+        return false;
+      memory->Copy(reinterpret_cast<void*>(last_esp), size);
+      loc->start_of_memory_range = 0 | last_esp;
+      loc->memory = memory->location();
+    }
+    return true;
+  }
+  return false;
+}
+
+// Write CPU context based on signal context.
+bool WriteContext(MDRawContextX86 *context, const struct sigcontext *sig_ctx,
+                  const DebugRegs *debug_regs) {
+  assert(sig_ctx != NULL);
+  context->context_flags = MD_CONTEXT_X86_FULL;
+  context->gs = sig_ctx->gs;
+  context->fs = sig_ctx->fs;
+  context->es = sig_ctx->es;
+  context->ds = sig_ctx->ds;
+  context->cs = sig_ctx->cs;
+  context->ss = sig_ctx->ss;
+  context->edi = sig_ctx->edi;
+  context->esi = sig_ctx->esi;
+  context->ebp = sig_ctx->ebp;
+  context->esp = sig_ctx->esp;
+  context->ebx = sig_ctx->ebx;
+  context->edx = sig_ctx->edx;
+  context->ecx = sig_ctx->ecx;
+  context->eax = sig_ctx->eax;
+  context->eip = sig_ctx->eip;
+  context->eflags = sig_ctx->eflags;
+  if (sig_ctx->fpstate != NULL) {
+    context->context_flags = MD_CONTEXT_X86_FULL |
+      MD_CONTEXT_X86_FLOATING_POINT;
+    context->float_save.control_word = sig_ctx->fpstate->cw;
+    context->float_save.status_word = sig_ctx->fpstate->sw;
+    context->float_save.tag_word = sig_ctx->fpstate->tag;
+    context->float_save.error_offset = sig_ctx->fpstate->ipoff;
+    context->float_save.error_selector = sig_ctx->fpstate->cssel;
+    context->float_save.data_offset = sig_ctx->fpstate->dataoff;
+    context->float_save.data_selector = sig_ctx->fpstate->datasel;
+    memcpy(context->float_save.register_area, sig_ctx->fpstate->_st,
+           sizeof(context->float_save.register_area));
+  }
+
+  if (debug_regs != NULL) {
+    context->context_flags |= MD_CONTEXT_X86_DEBUG_REGISTERS;
+    context->dr0 = debug_regs->dr0;
+    context->dr1 = debug_regs->dr1;
+    context->dr2 = debug_regs->dr2;
+    context->dr3 = debug_regs->dr3;
+    context->dr6 = debug_regs->dr6;
+    context->dr7 = debug_regs->dr7;
+  }
+  return true;
+}
+
+// Write CPU context based on provided registers.
+bool WriteContext(MDRawContextX86 *context,
+                  const struct user_regs_struct *regs,
+                  const struct user_fpregs_struct *fp_regs,
+                  const DebugRegs *dbg_regs) {
+  if (!context || !regs)
+    return false;
+
+  context->context_flags = MD_CONTEXT_X86_FULL;
+
+  context->cs = regs->xcs;
+  context->ds = regs->xds;
+  context->es = regs->xes;
+  context->fs = regs->xfs;
+  context->gs = regs->xgs;
+  context->ss = regs->xss;
+  context->edi = regs->edi;
+  context->esi = regs->esi;
+  context->ebx = regs->ebx;
+  context->edx = regs->edx;
+  context->ecx = regs->ecx;
+  context->eax = regs->eax;
+  context->ebp = regs->ebp;
+  context->eip = regs->eip;
+  context->esp = regs->esp;
+  context->eflags = regs->eflags;
+
+  if (dbg_regs != NULL) {
+    context->context_flags |= MD_CONTEXT_X86_DEBUG_REGISTERS;
+    context->dr0 = dbg_regs->dr0;
+    context->dr1 = dbg_regs->dr1;
+    context->dr2 = dbg_regs->dr2;
+    context->dr3 = dbg_regs->dr3;
+    context->dr6 = dbg_regs->dr6;
+    context->dr7 = dbg_regs->dr7;
+  }
+
+  if (fp_regs != NULL) {
+    context->context_flags |= MD_CONTEXT_X86_FLOATING_POINT;
+    context->float_save.control_word = fp_regs->cwd;
+    context->float_save.status_word = fp_regs->swd;
+    context->float_save.tag_word = fp_regs->twd;
+    context->float_save.error_offset = fp_regs->fip;
+    context->float_save.error_selector = fp_regs->fcs;
+    context->float_save.data_offset = fp_regs->foo;
+    context->float_save.data_selector = fp_regs->fos;
+    context->float_save.data_selector = fp_regs->fos;
+
+    memcpy(context->float_save.register_area, fp_regs->st_space,
+           sizeof(context->float_save.register_area));
+  }
+  return true;
+}
+
+// Write information about a crashed thread.
+// When a thread crash, kernel will write something on the stack for processing
+// signal. This makes the current stack not reliable, and our stack walker
+// won't figure out the whole call stack for this. So we write the stack at the
+// time of the crash into the minidump file, not the current stack.
+bool WriteCrashedThreadStream(MinidumpFileWriter *minidump_writer,
+                       const WriterArgument *writer_args,
+                       const ThreadInfo &thread_info,
+                       MDRawThread *thread) {
+  assert(writer_args->sig_ctx != NULL);
+
+  thread->thread_id = thread_info.pid;
+
+  UntypedMDRVA memory(minidump_writer);
+  if (!WriteThreadStack(writer_args->sig_ctx->ebp,
+                        writer_args->sig_ctx->esp,
+                        writer_args->thread_lister,
+                        &memory,
+                        &thread->stack))
+    return false;
+
+  TypedMDRVA<MDRawContextX86> context(minidump_writer);
+  if (!context.Allocate())
+    return false;
+  thread->thread_context = context.location();
+  memset(context.get(), 0, sizeof(MDRawContextX86));
+  return WriteContext(context.get(), writer_args->sig_ctx, NULL);
+}
+
+// Write information about a thread.
+// This function only processes thread running normally at the crash.
+bool WriteThreadStream(MinidumpFileWriter *minidump_writer,
+                       const LinuxThread *thread_lister,
+                       const ThreadInfo &thread_info,
+                       MDRawThread *thread) {
+  thread->thread_id = thread_info.pid;
+
+  struct user_regs_struct regs;
+  memset(&regs, 0, sizeof(regs));
+  if (!thread_lister->GetRegisters(thread_info.pid, &regs)) {
+    perror(NULL);
+    return false;
+  }
+
+  UntypedMDRVA memory(minidump_writer);
+  if (!WriteThreadStack(regs.ebp,
+                   regs.esp,
+                   thread_lister,
+                   &memory,
+                   &thread->stack))
+    return false;
+
+  struct user_fpregs_struct fp_regs;
+  DebugRegs dbg_regs;
+  memset(&fp_regs, 0, sizeof(fp_regs));
+  // Get all the registers.
+  thread_lister->GetFPRegisters(thread_info.pid, &fp_regs);
+  thread_lister->GetDebugRegisters(thread_info.pid, &dbg_regs);
+
+  // Write context
+  TypedMDRVA<MDRawContextX86> context(minidump_writer);
+  if (!context.Allocate())
+    return false;
+  thread->thread_context = context.location();
+  memset(context.get(), 0, sizeof(MDRawContextX86));
+  return WriteContext(context.get(), &regs, &fp_regs, &dbg_regs);
+}
+
+bool WriteCPUInformation(MDRawSystemInfo *sys_info) {
+  const char *proc_cpu_path = "/proc/cpuinfo";
+  char line[128];
+  char vendor_id[13];
+  const char vendor_id_name[] = "vendor_id";
+  const size_t vendor_id_name_length = sizeof(vendor_id_name) - 1;
+
+  struct CpuInfoEntry {
+    const char *info_name;
+    int value;
+  } cpu_info_table[] = {
+    { "processor", -1 },
+    { "model", 0 },
+    { "stepping",  0 },
+    { "cpuid level", 0 },
+    { NULL, -1 },
+  };
+
+  memset(vendor_id, 0, sizeof(vendor_id));
+
+  FILE *fp = fopen(proc_cpu_path, "r");
+  if (fp != NULL) {
+    while (fgets(line, sizeof(line), fp)) {
+      CpuInfoEntry *entry = &cpu_info_table[0];
+      while (entry->info_name != NULL) {
+        if (!strncmp(line, entry->info_name, strlen(entry->info_name))) {
+          char *value = strchr(line, ':');
+          value++;
+          if (value != NULL)
+            sscanf(value, " %d", &(entry->value));
+        }
+        entry++;
+      }
+
+      // special case for vendor_id
+      if (!strncmp(line, vendor_id_name, vendor_id_name_length)) {
+        char *value = strchr(line, ':');
+        if (value == NULL)
+          continue;
+
+        value++;
+        while (*value && isspace(*value))
+          value++;
+        if (*value) {
+          size_t length = strlen(value);
+          // we don't want the trailing newline
+          if (value[length - 1] == '\n')
+            length--;
+          // ensure we have space for the value
+          if (length < sizeof(vendor_id))
+            strncpy(vendor_id, value, length);
+        }
+      }
+    }
+    fclose(fp);
+  }
+
+  // /proc/cpuinfo contains cpu id, change it into number by adding one.
+  cpu_info_table[0].value++;
+
+  sys_info->number_of_processors = cpu_info_table[0].value;
+  sys_info->processor_level      = cpu_info_table[3].value;
+  sys_info->processor_revision   = cpu_info_table[1].value << 8 |
+                                   cpu_info_table[2].value;
+
+  sys_info->processor_architecture = MD_CPU_ARCHITECTURE_UNKNOWN;
+  struct utsname uts;
+  if (uname(&uts) == 0) {
+    // Match i*86 and x86* as X86 architecture.
+    if ((strstr(uts.machine, "x86") == uts.machine) ||
+        (strlen(uts.machine) == 4 &&
+         uts.machine[0] == 'i' &&
+         uts.machine[2] == '8' &&
+         uts.machine[3] == '6')) {
+      sys_info->processor_architecture = MD_CPU_ARCHITECTURE_X86;
+      if (vendor_id[0] != '\0')
+        memcpy(sys_info->cpu.x86_cpu_info.vendor_id, vendor_id,
+               sizeof(sys_info->cpu.x86_cpu_info.vendor_id));
+    }
+  }
+  return true;
+}
+
+bool WriteOSInformation(MinidumpFileWriter *minidump_writer,
+                        MDRawSystemInfo *sys_info) {
+  sys_info->platform_id = MD_OS_LINUX;
+
+  struct utsname uts;
+  if (uname(&uts) == 0) {
+    char os_version[512];
+    size_t space_left = sizeof(os_version);
+    memset(os_version, 0, space_left);
+    const char *os_info_table[] = {
+      uts.sysname,
+      uts.release,
+      uts.version,
+      uts.machine,
+      "GNU/Linux",
+      NULL
+    };
+    for (const char **cur_os_info = os_info_table;
+         *cur_os_info != NULL;
+         cur_os_info++) {
+      if (cur_os_info != os_info_table && space_left > 1) {
+        strcat(os_version, " ");
+        space_left--;
+      }
+      if (space_left > strlen(*cur_os_info)) {
+        strcat(os_version, *cur_os_info);
+        space_left -= strlen(*cur_os_info);
+      } else {
+        break;
+      }
+    }
+
+    MDLocationDescriptor location;
+    if (!minidump_writer->WriteString(os_version, 0, &location))
+      return false;
+    sys_info->csd_version_rva = location.rva;
+  }
+  return true;
+}
+
+// Callback context for get writting thread information.
+struct ThreadInfoCallbackCtx {
+  MinidumpFileWriter *minidump_writer;
+  const WriterArgument *writer_args;
+  TypedMDRVA<MDRawThreadList> *list;
+  int thread_index;
+};
+
+// Callback run for writing threads information in the process.
+bool ThreadInfomationCallback(const ThreadInfo &thread_info,
+                                 void *context) {
+  ThreadInfoCallbackCtx *callback_context =
+    static_cast<ThreadInfoCallbackCtx *>(context);
+  bool success = true;
+  MDRawThread thread;
+  memset(&thread, 0, sizeof(MDRawThread));
+  if (thread_info.pid != callback_context->writer_args->crashed_pid ||
+      callback_context->writer_args->sig_ctx == NULL) {
+    success = WriteThreadStream(callback_context->minidump_writer,
+                           callback_context->writer_args->thread_lister,
+                           thread_info, &thread);
+  } else {
+    success = WriteCrashedThreadStream(callback_context->minidump_writer,
+                                       callback_context->writer_args,
+                                       thread_info, &thread);
+  }
+  if (success) {
+    callback_context->list->CopyIndexAfterObject(
+        callback_context->thread_index++,
+        &thread, sizeof(MDRawThread));
+  }
+  return success;
+}
+
+// Stream writers
+bool WriteThreadListStream(MinidumpFileWriter *minidump_writer,
+                           const WriterArgument *writer_args,
+                           MDRawDirectory *dir) {
+  // Get the thread information.
+  const LinuxThread *thread_lister = writer_args->thread_lister;
+  int thread_count = thread_lister->GetThreadCount();
+  if (thread_count < 0)
+    return false;
+  TypedMDRVA<MDRawThreadList> list(minidump_writer);
+  if (!list.AllocateObjectAndArray(thread_count, sizeof(MDRawThread)))
+    return false;
+  dir->stream_type = MD_THREAD_LIST_STREAM;
+  dir->location = list.location();
+  list.get()->number_of_threads = thread_count;
+
+  ThreadInfoCallbackCtx context;
+  context.minidump_writer = minidump_writer;
+  context.writer_args = writer_args;
+  context.list = &list;
+  context.thread_index = 0;
+  CallbackParam<ThreadCallback> callback_param(ThreadInfomationCallback,
+                                               &context);
+  int written = thread_lister->ListThreads(&callback_param);
+  return written == thread_count;
+}
+
+bool WriteCVRecord(MinidumpFileWriter *minidump_writer,
+                   MDRawModule *module,
+                   const char *module_path) {
+  TypedMDRVA<MDCVInfoPDB70> cv(minidump_writer);
+
+  // Only return the last path component of the full module path
+  const char *module_name = strrchr(module_path, '/');
+  // Increment past the slash
+  if (module_name)
+    ++module_name;
+  else
+    module_name = "<Unknown>";
+
+  size_t module_name_length = strlen(module_name);
+  if (!cv.AllocateObjectAndArray(module_name_length + 1, sizeof(u_int8_t)))
+    return false;
+  if (!cv.CopyIndexAfterObject(0, const_cast<char *>(module_name),
+                               module_name_length))
+    return false;
+
+  module->cv_record = cv.location();
+  MDCVInfoPDB70 *cv_ptr = cv.get();
+  memset(cv_ptr, 0, sizeof(MDCVInfoPDB70));
+  cv_ptr->cv_signature = MD_CVINFOPDB70_SIGNATURE;
+  cv_ptr->age = 0;
+
+  // Get the module identifier
+  FileID file_id(module_path);
+  unsigned char identifier[16];
+
+  if (file_id.ElfFileIdentifier(identifier)) {
+    cv_ptr->signature.data1 = (uint32_t)identifier[0] << 24 |
+      (uint32_t)identifier[1] << 16 | (uint32_t)identifier[2] << 8 |
+      (uint32_t)identifier[3];
+    cv_ptr->signature.data2 = (uint32_t)identifier[4] << 8 | identifier[5];
+    cv_ptr->signature.data3 = (uint32_t)identifier[6] << 8 | identifier[7];
+    cv_ptr->signature.data4[0] = identifier[8];
+    cv_ptr->signature.data4[1] = identifier[9];
+    cv_ptr->signature.data4[2] = identifier[10];
+    cv_ptr->signature.data4[3] = identifier[11];
+    cv_ptr->signature.data4[4] = identifier[12];
+    cv_ptr->signature.data4[5] = identifier[13];
+    cv_ptr->signature.data4[6] = identifier[14];
+    cv_ptr->signature.data4[7] = identifier[15];
+  }
+  return true;
+}
+
+struct ModuleInfoCallbackCtx {
+  MinidumpFileWriter *minidump_writer;
+  const WriterArgument *writer_args;
+  TypedMDRVA<MDRawModuleList> *list;
+  int module_index;
+};
+
+bool ModuleInfoCallback(const ModuleInfo &module_info,
+                           void *context) {
+  ModuleInfoCallbackCtx *callback_context =
+    static_cast<ModuleInfoCallbackCtx *>(context);
+  // Skip those modules without name, or those that are not modules.
+  if (strlen(module_info.name) == 0 ||
+      !strchr(module_info.name, '/'))
+    return true;
+
+  MDRawModule module;
+  memset(&module, 0, sizeof(module));
+  MDLocationDescriptor loc;
+  if (!callback_context->minidump_writer->WriteString(module_info.name, 0,
+                                                      &loc))
+    return false;
+  module.base_of_image = (u_int64_t)module_info.start_addr;
+  module.size_of_image = module_info.size;
+  module.module_name_rva = loc.rva;
+
+  if (!WriteCVRecord(callback_context->minidump_writer, &module,
+                     module_info.name))
+    return false;
+  callback_context->list->CopyIndexAfterObject(
+      callback_context->module_index++, &module, MD_MODULE_SIZE);
+  return true;
+}
+
+bool WriteModuleListStream(MinidumpFileWriter *minidump_writer,
+                           const WriterArgument *writer_args,
+                           MDRawDirectory *dir) {
+  TypedMDRVA<MDRawModuleList> list(minidump_writer);
+  int module_count  = writer_args->thread_lister->GetModuleCount();
+  if (module_count <= 0 ||
+      !list.AllocateObjectAndArray(module_count, MD_MODULE_SIZE))
+    return false;
+  dir->stream_type = MD_MODULE_LIST_STREAM;
+  dir->location = list.location();
+  list.get()->number_of_modules = module_count;
+  ModuleInfoCallbackCtx context;
+  context.minidump_writer = minidump_writer;
+  context.writer_args = writer_args;
+  context.list = &list;
+  context.module_index = 0;
+  CallbackParam<ModuleCallback> callback(ModuleInfoCallback, &context);
+  return writer_args->thread_lister->ListModules(&callback) == module_count;
+}
+
+bool WriteSystemInfoStream(MinidumpFileWriter *minidump_writer,
+                           const WriterArgument *writer_args,
+                           MDRawDirectory *dir) {
+  TypedMDRVA<MDRawSystemInfo> sys_info(minidump_writer);
+  if (!sys_info.Allocate())
+    return false;
+  dir->stream_type = MD_SYSTEM_INFO_STREAM;
+  dir->location = sys_info.location();
+
+  return WriteCPUInformation(sys_info.get()) &&
+         WriteOSInformation(minidump_writer, sys_info.get());
+}
+
+bool WriteExceptionStream(MinidumpFileWriter *minidump_writer,
+                           const WriterArgument *writer_args,
+                           MDRawDirectory *dir) {
+  // This happenes when this is not a crash, but a requested dump.
+  if (writer_args->sig_ctx == NULL)
+    return false;
+
+  TypedMDRVA<MDRawExceptionStream> exception(minidump_writer);
+  if (!exception.Allocate())
+    return false;
+
+  dir->stream_type = MD_EXCEPTION_STREAM;
+  dir->location = exception.location();
+  exception.get()->thread_id = writer_args->crashed_pid;
+  exception.get()->exception_record.exception_code = writer_args->signo;
+  exception.get()->exception_record.exception_flags = 0;
+  if (writer_args->sig_ctx != NULL) {
+    exception.get()->exception_record.exception_address =
+      writer_args->sig_ctx->eip;
+  } else {
+    return true;
+  }
+
+  // Write context of the exception.
+  TypedMDRVA<MDRawContextX86> context(minidump_writer);
+  if (!context.Allocate())
+    return false;
+  exception.get()->thread_context = context.location();
+  memset(context.get(), 0, sizeof(MDRawContextX86));
+  return WriteContext(context.get(), writer_args->sig_ctx, NULL);
+}
+
+bool WriteMiscInfoStream(MinidumpFileWriter *minidump_writer,
+                           const WriterArgument *writer_args,
+                           MDRawDirectory *dir) {
+  TypedMDRVA<MDRawMiscInfo> info(minidump_writer);
+  if (!info.Allocate())
+    return false;
+
+  dir->stream_type = MD_MISC_INFO_STREAM;
+  dir->location = info.location();
+  info.get()->size_of_info = sizeof(MDRawMiscInfo);
+  info.get()->flags1 = MD_MISCINFO_FLAGS1_PROCESS_ID;
+  info.get()->process_id = writer_args->requester_pid;
+
+  return true;
+}
+
+bool WriteBreakpadInfoStream(MinidumpFileWriter *minidump_writer,
+                           const WriterArgument *writer_args,
+                           MDRawDirectory *dir) {
+  TypedMDRVA<MDRawBreakpadInfo> info(minidump_writer);
+  if (!info.Allocate())
+    return false;
+
+  dir->stream_type = MD_BREAKPAD_INFO_STREAM;
+  dir->location = info.location();
+
+  info.get()->validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
+                        MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
+  info.get()->dump_thread_id = getpid();
+  info.get()->requesting_thread_id = writer_args->requester_pid;
+  return true;
+}
+
+// Prototype of writer functions.
+typedef bool (*WriteStringFN)(MinidumpFileWriter *,
+                              const WriterArgument *,
+                              MDRawDirectory *);
+
+// Function table to writer a full minidump.
+WriteStringFN writers[] = {
+  WriteThreadListStream,
+  WriteModuleListStream,
+  WriteSystemInfoStream,
+  WriteExceptionStream,
+  WriteMiscInfoStream,
+  WriteBreakpadInfoStream,
+};
+
+// Will call each writer function in the writers table.
+// It runs in a different process from the crashing process, but sharing
+// the same address space. This enables it to use ptrace functions.
+int Write(void *argument) {
+  WriterArgument *writer_args =
+    static_cast<WriterArgument *>(argument);
+
+  if (!writer_args->thread_lister->SuspendAllThreads())
+    return -1;
+
+  if (writer_args->sighandler_ebp != 0 &&
+      writer_args->thread_lister->FindSigContext(writer_args->sighandler_ebp,
+                                                 &writer_args->sig_ctx)) {
+    writer_args->crashed_stack_bottom =
+      writer_args->thread_lister->GetThreadStackBottom(
+                                             writer_args->sig_ctx->ebp);
+    int crashed_pid =  FindCrashingThread(writer_args->crashed_stack_bottom,
+                                          writer_args->requester_pid,
+                                          writer_args->thread_lister);
+    if (crashed_pid > 0)
+      writer_args->crashed_pid = crashed_pid;
+  }
+
+
+  MinidumpFileWriter *minidump_writer = writer_args->minidump_writer;
+  TypedMDRVA<MDRawHeader> header(minidump_writer);
+  TypedMDRVA<MDRawDirectory> dir(minidump_writer);
+  if (!header.Allocate())
+    return 0;
+
+  int writer_count = sizeof(writers) / sizeof(writers[0]);
+  // Need directory space for all writers.
+  if (!dir.AllocateArray(writer_count))
+    return 0;
+  header.get()->signature = MD_HEADER_SIGNATURE;
+  header.get()->version = MD_HEADER_VERSION;
+  header.get()->time_date_stamp = time(NULL);
+  header.get()->stream_count = writer_count;
+  header.get()->stream_directory_rva = dir.position();
+
+  int dir_index = 0;
+  MDRawDirectory local_dir;
+  for (int i = 0; i < writer_count; ++i) {
+    if (writers[i](minidump_writer, writer_args, &local_dir))
+      dir.CopyIndex(dir_index++, &local_dir);
+  }
+
+  writer_args->thread_lister->ResumeAllThreads();
+  return 0;
+}
+
+}  // namespace
+
+namespace google_breakpad {
+
+MinidumpGenerator::MinidumpGenerator() {
+  AllocateStack();
+}
+
+MinidumpGenerator::~MinidumpGenerator() {
+}
+
+void MinidumpGenerator::AllocateStack() {
+  stack_.reset(new char[kStackSize]);
+}
+
+bool MinidumpGenerator::WriteMinidumpToFile(const char *file_pathname,
+                                   int signo,
+                                   uintptr_t sighandler_ebp,
+                                   struct sigcontext **sig_ctx) const {
+  assert(file_pathname != NULL);
+  assert(stack_ != NULL);
+
+  if (stack_ == NULL || file_pathname == NULL)
+    return false;
+
+  MinidumpFileWriter minidump_writer;
+  if (minidump_writer.Open(file_pathname)) {
+    WriterArgument argument;
+    memset(&argument, 0, sizeof(argument));
+    LinuxThread thread_lister(getpid());
+    argument.thread_lister = &thread_lister;
+    argument.minidump_writer = &minidump_writer;
+    argument.requester_pid = getpid();
+    argument.crashed_pid = getpid();
+    argument.signo = signo;
+    argument.sighandler_ebp = sighandler_ebp;
+    argument.sig_ctx = NULL;
+
+    int cloned_pid = clone(Write, stack_.get() + kStackSize,
+                           CLONE_VM | CLONE_FILES | CLONE_FS | CLONE_UNTRACED,
+                           (void*)&argument);
+    waitpid(cloned_pid, NULL, __WALL);
+    if (sig_ctx != NULL)
+        *sig_ctx = argument.sig_ctx;
+    return true;
+  }
+
+  return false;
+}
+
+}  // namespace google_breakpad
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/google-breakpad/src/client/linux/handler/minidump_generator.h
@@ -0,0 +1,73 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Author: Li Liu
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef CLIENT_LINUX_HANDLER_MINIDUMP_GENERATOR_H__
+#define CLIENT_LINUX_HANDLER_MINIDUMP_GENERATOR_H__
+
+#include <stdint.h>
+
+#include "google_breakpad/common/breakpad_types.h"
+#include "processor/scoped_ptr.h"
+
+struct sigcontext;
+
+namespace google_breakpad {
+
+//
+// MinidumpGenerator
+//
+// Write a minidump to file based on the signo and sig_ctx.
+// A minidump generator should be created before any exception happen.
+//
+class MinidumpGenerator {
+  public:
+   MinidumpGenerator();
+
+   ~MinidumpGenerator();
+
+   // Write minidump.
+   bool WriteMinidumpToFile(const char *file_pathname,
+                            int signo,
+                            uintptr_t sighandler_ebp,
+                            struct sigcontext **sig_ctx) const;
+  private:
+   // Allocate memory for stack.
+   void AllocateStack();
+
+  private:
+   // Stack size of the writer thread.
+   static const int kStackSize = 1024 * 1024;
+   scoped_array<char> stack_;
+};
+
+}  // namespace google_breakpad
+
+#endif   // CLIENT_LINUX_HANDLER_MINIDUMP_GENERATOR_H__
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/google-breakpad/src/client/linux/handler/minidump_test.cc
@@ -0,0 +1,86 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Author: Li Liu
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <pthread.h>
+#include <unistd.h>
+
+#include <cassert>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#include "client/linux/handler/minidump_generator.h"
+
+using namespace google_breakpad;
+
+// Thread use this to see if it should stop working.
+static bool should_exit = false;
+
+static void foo2(int arg) {
+  // Stack variable, used for debugging stack dumps.
+  int c = arg;
+  c = 0xcccccccc;
+  while (!should_exit)
+    sleep(1);
+}
+
+static void foo(int arg) {
+  // Stack variable, used for debugging stack dumps.
+  int b = arg;
+  b = 0xbbbbbbbb;
+  foo2(b);
+}
+
+static void *thread_main(void *) {
+  // Stack variable, used for debugging stack dumps.
+  int a = 0xaaaaaaaa;
+  foo(a);
+  return NULL;
+}
+
+static void CreateThread(int num) {
+  pthread_t h;
+  for (int i = 0; i < num; ++i) {
+    pthread_create(&h, NULL, thread_main, NULL);
+    pthread_detach(h);
+  }
+}
+
+int main(int argc, char *argv[]) {
+  CreateThread(10);
+  google_breakpad::MinidumpGenerator mg;
+  if (mg.WriteMinidumpToFile("minidump_test.out", -1, 0, NULL))
+    printf("Succeeded written minidump\n");
+  else
+    printf("Failed to write minidump\n");
+  should_exit = true;
+  return 0;
+}
deleted file mode 100644
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/Makefile.in
+++ /dev/null
@@ -1,60 +0,0 @@
-# ***** 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 Breakpad integration
-#
-# The Initial Developer of the Original Code is
-# The Mozilla Foundation.
-# Portions created by the Initial Developer are Copyright (C) 2009
-# the Initial Developer. All Rights Reserved.
-#
-# Contributor(s):
-#  Ted Mielczarek <ted.mielczarek@gmail.com>
-#
-# 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 *****
-
-DEPTH		= ../../../../../../..
-topsrcdir	= @top_srcdir@
-srcdir		= @srcdir@
-VPATH		= @srcdir@
-
-include $(DEPTH)/config/autoconf.mk
-
-MODULE		= writer
-LIBRARY_NAME	= minidump_writer_s
-XPI_NAME 	= crashreporter
-
-LOCAL_INCLUDES 	= -I$(srcdir)/../../..
-
-CPPSRCS	= \
-  linux_dumper.cc \
-  minidump_writer.cc \
-  $(NULL)
-
-# need static lib
-FORCE_STATIC_LIB = 1
-FORCE_USE_PIC = 1
-
-include $(topsrcdir)/config/rules.mk
deleted file mode 100644
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/directory_reader.h
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef CLIENT_LINUX_MINIDUMP_WRITER_DIRECTORY_READER_H_
-#define CLIENT_LINUX_MINIDUMP_WRITER_DIRECTORY_READER_H_
-
-#include <stdint.h>
-#include <unistd.h>
-#include <limits.h>
-#include <assert.h>
-#include <errno.h>
-#include <string.h>
-
-#include "common/linux/linux_syscall_support.h"
-
-namespace google_breakpad {
-
-// A class for enumerating a directory without using diropen/readdir or other
-// functions which may allocate memory.
-class DirectoryReader {
- public:
-  DirectoryReader(int fd)
-      : fd_(fd),
-        buf_used_(0) {
-  }
-
-  // Return the next entry from the directory
-  //   name: (output) the NUL terminated entry name
-  //
-  // Returns true iff successful (false on EOF).
-  //
-  // After calling this, one must call |PopEntry| otherwise you'll get the same
-  // entry over and over.
-  bool GetNextEntry(const char** name) {
-    struct kernel_dirent* const dent =
-      reinterpret_cast<kernel_dirent*>(buf_);
-
-    if (buf_used_ == 0) {
-      // need to read more entries.
-      const int n = sys_getdents(fd_, dent, sizeof(buf_));
-      if (n < 0) {
-        return false;
-      } else if (n == 0) {
-        hit_eof_ = true;
-      } else {
-        buf_used_ += n;
-      }
-    }
-
-    if (buf_used_ == 0 && hit_eof_)
-      return false;
-
-    assert(buf_used_ > 0);
-
-    *name = dent->d_name;
-    return true;
-  }
-
-  void PopEntry() {
-    if (!buf_used_)
-      return;
-
-    const struct kernel_dirent* const dent =
-      reinterpret_cast<kernel_dirent*>(buf_);
-
-    buf_used_ -= dent->d_reclen;
-    memmove(buf_, buf_ + dent->d_reclen, buf_used_);
-  }
-
- private:
-  const int fd_;
-  bool hit_eof_;
-  unsigned buf_used_;
-  uint8_t buf_[sizeof(struct kernel_dirent) + NAME_MAX + 1];
-};
-
-}  // namespace google_breakpad
-
-#endif  // CLIENT_LINUX_MINIDUMP_WRITER_DIRECTORY_READER_H_
deleted file mode 100644
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/directory_reader_unittest.cc
+++ /dev/null
@@ -1,77 +0,0 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include <set>
-#include <string>
-
-#include <dirent.h>
-#include <fcntl.h>
-#include <sys/types.h>
-
-#include "client/linux/minidump_writer/directory_reader.h"
-#include "breakpad_googletest_includes.h"
-
-using namespace google_breakpad;
-
-namespace {
-typedef testing::Test DirectoryReaderTest;
-}
-
-TEST(DirectoryReaderTest, CompareResults) {
-  std::set<std::string> dent_set;
-
-  DIR *const dir = opendir("/proc/self");
-  ASSERT_TRUE(dir != NULL);
-
-  struct dirent* dent;
-  while ((dent = readdir(dir)))
-    dent_set.insert(dent->d_name);
-
-  closedir(dir);
-
-  const int fd = open("/proc/self", O_DIRECTORY | O_RDONLY);
-  ASSERT_GE(fd, 0);
-
-  DirectoryReader dir_reader(fd);
-  unsigned seen = 0;
-
-  const char* name;
-  while (dir_reader.GetNextEntry(&name)) {
-    ASSERT_TRUE(dent_set.find(name) != dent_set.end());
-    seen++;
-    dir_reader.PopEntry();
-  }
-
-  ASSERT_TRUE(dent_set.find("status") != dent_set.end());
-  ASSERT_TRUE(dent_set.find("stat") != dent_set.end());
-  ASSERT_TRUE(dent_set.find("cmdline") != dent_set.end());
-
-  ASSERT_EQ(dent_set.size(), seen);
-  close(fd);
-}
deleted file mode 100644
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/line_reader.h
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef CLIENT_LINUX_MINIDUMP_WRITER_LINE_READER_H_
-#define CLIENT_LINUX_MINIDUMP_WRITER_LINE_READER_H_
-
-#include <stdint.h>
-#include <assert.h>
-#include <string.h>
-
-#include "common/linux/linux_syscall_support.h"
-
-namespace google_breakpad {
-
-// A class for reading a file, line by line, without using fopen/fgets or other
-// functions which may allocate memory.
-class LineReader {
- public:
-  LineReader(int fd)
-      : fd_(fd),
-        hit_eof_(false),
-        buf_used_(0) {
-  }
-
-  // The maximum length of a line.
-  static const size_t kMaxLineLen = 512;
-
-  // Return the next line from the file.
-  //   line: (output) a pointer to the start of the line. The line is NUL
-  //     terminated.
-  //   len: (output) the length of the line (not inc the NUL byte)
-  //
-  // Returns true iff successful (false on EOF).
-  //
-  // One must call |PopLine| after this function, otherwise you'll continue to
-  // get the same line over and over.
-  bool GetNextLine(const char **line, unsigned *len) {
-    for (;;) {
-      if (buf_used_ == 0 && hit_eof_)
-        return false;
-
-      for (unsigned i = 0; i < buf_used_; ++i) {
-        if (buf_[i] == '\n' || buf_[i] == 0) {
-          buf_[i] = 0;
-          *len = i;
-          *line = buf_;
-          return true;
-        }
-      }
-
-      if (buf_used_ == sizeof(buf_)) {
-        // we scanned the whole buffer and didn't find an end-of-line marker.
-        // This line is too long to process.
-        return false;
-      }
-
-      // We didn't find any end-of-line terminators in the buffer. However, if
-      // this is the last line in the file it might not have one:
-      if (hit_eof_) {
-        assert(buf_used_);
-        // There's room for the NUL because of the buf_used_ == sizeof(buf_)
-        // check above.
-        buf_[buf_used_] = 0;
-        *len = buf_used_;
-        buf_used_ += 1;  // since we appended the NUL.
-        *line = buf_;
-        return true;
-      }
-
-      // Otherwise, we should pull in more data from the file
-      const ssize_t n = sys_read(fd_, buf_ + buf_used_,
-                                 sizeof(buf_) - buf_used_);
-      if (n < 0) {
-        return false;
-      } else if (n == 0) {
-        hit_eof_ = true;
-      } else {
-        buf_used_ += n;
-      }
-
-      // At this point, we have either set the hit_eof_ flag, or we have more
-      // data to process...
-    }
-  }
-
-  void PopLine(unsigned len) {
-    // len doesn't include the NUL byte at the end.
-
-    assert(buf_used_ >= len + 1);
-    buf_used_ -= len + 1;
-    memmove(buf_, buf_ + len + 1, buf_used_);
-  }
-
- private:
-  const int fd_;
-
-  bool hit_eof_;
-  unsigned buf_used_;
-  char buf_[kMaxLineLen];
-};
-
-}  // namespace google_breakpad
-
-#endif  // CLIENT_LINUX_MINIDUMP_WRITER_LINE_READER_H_
deleted file mode 100644
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/line_reader_unittest.cc
+++ /dev/null
@@ -1,184 +0,0 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/types.h>
-
-#include "client/linux/minidump_writer/line_reader.h"
-#include "breakpad_googletest_includes.h"
-
-using namespace google_breakpad;
-
-static int TemporaryFile() {
-  static const char templ[] = "/tmp/line-reader-unittest-XXXXXX";
-  char templ_copy[sizeof(templ)];
-  memcpy(templ_copy, templ, sizeof(templ));
-  const int fd = mkstemp(templ_copy);
-  if (fd >= 0)
-    unlink(templ_copy);
-
-  return fd;
-}
-
-namespace {
-typedef testing::Test LineReaderTest;
-}
-
-TEST(LineReaderTest, EmptyFile) {
-  const int fd = TemporaryFile();
-  LineReader reader(fd);
-
-  const char *line;
-  unsigned len;
-  ASSERT_FALSE(reader.GetNextLine(&line, &len));
-
-  close(fd);
-}
-
-TEST(LineReaderTest, OneLineTerminated) {
-  const int fd = TemporaryFile();
-  write(fd, "a\n", 2);
-  lseek(fd, 0, SEEK_SET);
-  LineReader reader(fd);
-
-  const char *line;
-  unsigned len;
-  ASSERT_TRUE(reader.GetNextLine(&line, &len));
-  ASSERT_EQ(len, 1);
-  ASSERT_EQ(line[0], 'a');
-  ASSERT_EQ(line[1], 0);
-  reader.PopLine(len);
-
-  ASSERT_FALSE(reader.GetNextLine(&line, &len));
-
-  close(fd);
-}
-
-TEST(LineReaderTest, OneLine) {
-  const int fd = TemporaryFile();
-  write(fd, "a", 1);
-  lseek(fd, 0, SEEK_SET);
-  LineReader reader(fd);
-
-  const char *line;
-  unsigned len;
-  ASSERT_TRUE(reader.GetNextLine(&line, &len));
-  ASSERT_EQ(len, 1);
-  ASSERT_EQ(line[0], 'a');
-  ASSERT_EQ(line[1], 0);
-  reader.PopLine(len);
-
-  ASSERT_FALSE(reader.GetNextLine(&line, &len));
-
-  close(fd);
-}
-
-TEST(LineReaderTest, TwoLinesTerminated) {
-  const int fd = TemporaryFile();
-  write(fd, "a\nb\n", 4);
-  lseek(fd, 0, SEEK_SET);
-  LineReader reader(fd);
-
-  const char *line;
-  unsigned len;
-  ASSERT_TRUE(reader.GetNextLine(&line, &len));
-  ASSERT_EQ(len, 1);
-  ASSERT_EQ(line[0], 'a');
-  ASSERT_EQ(line[1], 0);
-  reader.PopLine(len);
-
-  ASSERT_TRUE(reader.GetNextLine(&line, &len));
-  ASSERT_EQ(len, 1);
-  ASSERT_EQ(line[0], 'b');
-  ASSERT_EQ(line[1], 0);
-  reader.PopLine(len);
-
-  ASSERT_FALSE(reader.GetNextLine(&line, &len));
-
-  close(fd);
-}
-
-TEST(LineReaderTest, TwoLines) {
-  const int fd = TemporaryFile();
-  write(fd, "a\nb", 3);
-  lseek(fd, 0, SEEK_SET);
-  LineReader reader(fd);
-
-  const char *line;
-  unsigned len;
-  ASSERT_TRUE(reader.GetNextLine(&line, &len));
-  ASSERT_EQ(len, 1);
-  ASSERT_EQ(line[0], 'a');
-  ASSERT_EQ(line[1], 0);
-  reader.PopLine(len);
-
-  ASSERT_TRUE(reader.GetNextLine(&line, &len));
-  ASSERT_EQ(len, 1);
-  ASSERT_EQ(line[0], 'b');
-  ASSERT_EQ(line[1], 0);
-  reader.PopLine(len);
-
-  ASSERT_FALSE(reader.GetNextLine(&line, &len));
-
-  close(fd);
-}
-
-TEST(LineReaderTest, MaxLength) {
-  const int fd = TemporaryFile();
-  char l[LineReader::kMaxLineLen - 1];
-  memset(l, 'a', sizeof(l));
-  write(fd, l, sizeof(l));
-  lseek(fd, 0, SEEK_SET);
-  LineReader reader(fd);
-
-  const char *line;
-  unsigned len;
-  ASSERT_TRUE(reader.GetNextLine(&line, &len));
-  ASSERT_EQ(len, sizeof(l));
-  ASSERT_TRUE(memcmp(l, line, sizeof(l)) == 0);
-  ASSERT_EQ(line[len], 0);
-
-  close(fd);
-}
-
-TEST(LineReaderTest, TooLong) {
-  const int fd = TemporaryFile();
-  char l[LineReader::kMaxLineLen];
-  memset(l, 'a', sizeof(l));
-  write(fd, l, sizeof(l));
-  lseek(fd, 0, SEEK_SET);
-  LineReader reader(fd);
-
-  const char *line;
-  unsigned len;
-  ASSERT_FALSE(reader.GetNextLine(&line, &len));
-
-  close(fd);
-}
deleted file mode 100644
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_dumper.cc
+++ /dev/null
@@ -1,421 +0,0 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// This code deals with the mechanics of getting information about a crashed
-// process. Since this code may run in a compromised address space, the same
-// rules apply as detailed at the top of minidump_writer.h: no libc calls and
-// use the alternative allocator.
-
-#include "client/linux/minidump_writer/linux_dumper.h"
-
-#include <assert.h>
-#include <limits.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-
-#include <sys/types.h>
-#include <sys/ptrace.h>
-#include <sys/wait.h>
-
-#include "client/linux/minidump_writer/directory_reader.h"
-#include "client/linux/minidump_writer/line_reader.h"
-#include "common/linux/linux_libc_support.h"
-#include "common/linux/linux_syscall_support.h"
-
-// Suspend a thread by attaching to it.
-static bool SuspendThread(pid_t pid) {
-  // This may fail if the thread has just died or debugged.
-  errno = 0;
-  if (sys_ptrace(PTRACE_ATTACH, pid, NULL, NULL) != 0 &&
-      errno != 0) {
-    return false;
-  }
-  while (sys_waitpid(pid, NULL, __WALL) < 0) {
-    if (errno != EINTR) {
-      sys_ptrace(PTRACE_DETACH, pid, NULL, NULL);
-      return false;
-    }
-  }
-  return true;
-}
-
-// Resume a thread by detaching from it.
-static bool ResumeThread(pid_t pid) {
-  return sys_ptrace(PTRACE_DETACH, pid, NULL, NULL) >= 0;
-}
-
-namespace google_breakpad {
-
-LinuxDumper::LinuxDumper(int pid)
-    : pid_(pid),
-      threads_suspened_(false),
-      threads_(&allocator_, 8),
-      mappings_(&allocator_) {
-}
-
-bool LinuxDumper::Init() {
-  return EnumerateThreads(&threads_) &&
-         EnumerateMappings(&mappings_);
-}
-
-bool LinuxDumper::ThreadsSuspend() {
-  if (threads_suspened_)
-    return true;
-  bool good = true;
-  for (size_t i = 0; i < threads_.size(); ++i)
-    good &= SuspendThread(threads_[i]);
-  threads_suspened_ = true;
-  return good;
-}
-
-bool LinuxDumper::ThreadsResume() {
-  if (!threads_suspened_)
-    return false;
-  bool good = true;
-  for (size_t i = 0; i < threads_.size(); ++i)
-    good &= ResumeThread(threads_[i]);
-  threads_suspened_ = false;
-  return good;
-}
-
-void
-LinuxDumper::BuildProcPath(char* path, pid_t pid, const char* node) const {
-  assert(path);
-  if (!path) {
-    return;
-  }
-
-  path[0] = '\0';
-
-  const unsigned pid_len = my_int_len(pid);
-
-  assert(node);
-  if (!node) {
-    return;
-  }
-
-  size_t node_len = my_strlen(node);
-  assert(node_len < NAME_MAX);
-  if (node_len >= NAME_MAX) {
-    return;
-  }
-
-  assert(node_len > 0);
-  if (node_len == 0) {
-    return;
-  }
-
-  assert(pid > 0);
-  if (pid <= 0) {
-    return;
-  }
-
-  const size_t total_length = 6 + pid_len + 1 + node_len;
-
-  assert(total_length < NAME_MAX);
-  if (total_length >= NAME_MAX) {
-    return;
-  }
-
-  memcpy(path, "/proc/", 6);
-  my_itos(path + 6, pid, pid_len);
-  memcpy(path + 6 + pid_len, "/", 1);
-  memcpy(path + 6 + pid_len + 1, node, node_len);
-  memcpy(path + total_length, "\0", 1);
-}
-
-void*
-LinuxDumper::FindBeginningOfLinuxGateSharedLibrary(const pid_t pid) const {
-  char auxv_path[80];
-  BuildProcPath(auxv_path, pid, "auxv");
-
-  // If BuildProcPath errors out due to invalid input, we'll handle it when
-  // we try to sys_open the file.
-
-  // Find the AT_SYSINFO_EHDR entry for linux-gate.so
-  // See http://www.trilithium.com/johan/2005/08/linux-gate/ for more
-  // information.
-  int fd = sys_open(auxv_path, O_RDONLY, 0);
-  if (fd < 0) {
-    return NULL;
-  }
-
-  elf_aux_entry one_aux_entry;
-  while (sys_read(fd,
-                  &one_aux_entry,
-                  sizeof(elf_aux_entry)) == sizeof(elf_aux_entry) &&
-         one_aux_entry.a_type != AT_NULL) {
-    if (one_aux_entry.a_type == AT_SYSINFO_EHDR) {
-      close(fd);
-      return reinterpret_cast<void*>(one_aux_entry.a_un.a_val);
-    }
-  }
-  close(fd);
-  return NULL;
-}
-
-bool
-LinuxDumper::EnumerateMappings(wasteful_vector<MappingInfo*>* result) const {
-  char maps_path[80];
-  BuildProcPath(maps_path, pid_, "maps");
-
-  // linux_gate_loc is the beginning of the kernel's mapping of
-  // linux-gate.so in the process.  It doesn't actually show up in the
-  // maps list as a filename, so we use the aux vector to find it's
-  // load location and special case it's entry when creating the list
-  // of mappings.
-  const void* linux_gate_loc;
-  linux_gate_loc = FindBeginningOfLinuxGateSharedLibrary(pid_);
-
-  const int fd = sys_open(maps_path, O_RDONLY, 0);
-  if (fd < 0)
-    return false;
-  LineReader* const line_reader = new(allocator_) LineReader(fd);
-
-  const char* line;
-  unsigned line_len;
-  while (line_reader->GetNextLine(&line, &line_len)) {
-    uintptr_t start_addr, end_addr, offset;
-
-    const char* i1 = my_read_hex_ptr(&start_addr, line);
-    if (*i1 == '-') {
-      const char* i2 = my_read_hex_ptr(&end_addr, i1 + 1);
-      if (*i2 == ' ') {
-        const char* i3 = my_read_hex_ptr(&offset, i2 + 6 /* skip ' rwxp ' */);
-        if (*i3 == ' ') {
-          MappingInfo* const module = new(allocator_) MappingInfo;
-          memset(module, 0, sizeof(MappingInfo));
-          module->start_addr = start_addr;
-          module->size = end_addr - start_addr;
-          module->offset = offset;
-          const char* name = NULL;
-          // Only copy name if the name is a valid path name, or if
-          // we've found the VDSO image
-          if ((name = my_strchr(line, '/')) != NULL) {
-            const unsigned l = my_strlen(name);
-            if (l < sizeof(module->name))
-              memcpy(module->name, name, l);
-          } else if (linux_gate_loc &&
-                     reinterpret_cast<void*>(module->start_addr) ==
-                     linux_gate_loc) {
-            memcpy(module->name,
-                   kLinuxGateLibraryName,
-                   my_strlen(kLinuxGateLibraryName));
-            module->offset = 0;
-          }
-          result->push_back(module);
-        }
-      }
-    }
-    line_reader->PopLine(line_len);
-  }
-
-  sys_close(fd);
-
-  return result->size() > 0;
-}
-
-// Parse /proc/$pid/task to list all the threads of the process identified by
-// pid.
-bool LinuxDumper::EnumerateThreads(wasteful_vector<pid_t>* result) const {
-  char task_path[80];
-  BuildProcPath(task_path, pid_, "task");
-
-  const int fd = sys_open(task_path, O_RDONLY | O_DIRECTORY, 0);
-  if (fd < 0)
-    return false;
-  DirectoryReader* dir_reader = new(allocator_) DirectoryReader(fd);
-
-  // The directory may contain duplicate entries which we filter by assuming
-  // that they are consecutive.
-  int last_tid = -1;
-  const char* dent_name;
-  while (dir_reader->GetNextEntry(&dent_name)) {
-    if (my_strcmp(dent_name, ".") &&
-        my_strcmp(dent_name, "..")) {
-      int tid = 0;
-      if (my_strtoui(&tid, dent_name) &&
-          last_tid != tid) {
-        last_tid = tid;
-        result->push_back(tid);
-      }
-    }
-    dir_reader->PopEntry();
-  }
-
-  sys_close(fd);
-  return true;
-}
-
-// Read thread info from /proc/$pid/status.
-// Fill out the |tgid|, |ppid| and |pid| members of |info|. If unavailible,
-// these members are set to -1. Returns true iff all three members are
-// availible.
-bool LinuxDumper::ThreadInfoGet(pid_t tid, ThreadInfo* info) {
-  assert(info != NULL);
-  char status_path[80];
-  BuildProcPath(status_path, tid, "status");
-
-  const int fd = open(status_path, O_RDONLY);
-  if (fd < 0)
-    return false;
-
-  LineReader* const line_reader = new(allocator_) LineReader(fd);
-  const char* line;
-  unsigned line_len;
-
-  info->ppid = info->tgid = -1;
-
-  while (line_reader->GetNextLine(&line, &line_len)) {
-    if (my_strncmp("Tgid:\t", line, 6) == 0) {
-      my_strtoui(&info->tgid, line + 6);
-    } else if (my_strncmp("PPid:\t", line, 6) == 0) {
-      my_strtoui(&info->ppid, line + 6);
-    }
-
-    line_reader->PopLine(line_len);
-  }
-
-  if (info->ppid == -1 || info->tgid == -1)
-    return false;
-
-  if (sys_ptrace(PTRACE_GETREGS, tid, NULL, &info->regs) == -1 ||
-      sys_ptrace(PTRACE_GETFPREGS, tid, NULL, &info->fpregs) == -1) {
-    return false;
-  }
-
-#if defined(__i386)
-  if (sys_ptrace(PTRACE_GETFPXREGS, tid, NULL, &info->fpxregs) == -1)
-    return false;
-#endif
-
-#if defined(__i386) || defined(__x86_64)
-  for (unsigned i = 0; i < ThreadInfo::kNumDebugRegisters; ++i) {
-    if (sys_ptrace(
-        PTRACE_PEEKUSER, tid,
-        reinterpret_cast<void*> (offsetof(struct user,
-                                          u_debugreg[0]) + i *
-                                 sizeof(debugreg_t)),
-        &info->dregs[i]) == -1) {
-      return false;
-    }
-  }
-#endif
-
-  const uint8_t* stack_pointer;
-#if defined(__i386)
-  memcpy(&stack_pointer, &info->regs.esp, sizeof(info->regs.esp));
-#elif defined(__x86_64)
-  memcpy(&stack_pointer, &info->regs.rsp, sizeof(info->regs.rsp));
-#else
-#error "This code hasn't been ported to your platform yet."
-#endif
-
-  if (!GetStackInfo(&info->stack, &info->stack_len,
-                    (uintptr_t) stack_pointer))
-    return false;
-
-  return true;
-}
-
-// Get information about the stack, given the stack pointer. We don't try to
-// walk the stack since we might not have all the information needed to do
-// unwind. So we just grab, up to, 32k of stack.
-bool LinuxDumper::GetStackInfo(const void** stack, size_t* stack_len,
-                               uintptr_t int_stack_pointer) {
-#if defined(__i386) || defined(__x86_64)
-  static const bool stack_grows_down = true;
-  static const uintptr_t page_size = 4096;
-#else
-#error "This code has not been ported to your platform yet."
-#endif
-  // Move the stack pointer to the bottom of the page that it's in.
-  uint8_t* const stack_pointer =
-      reinterpret_cast<uint8_t*>(int_stack_pointer & ~(page_size - 1));
-
-  // The number of bytes of stack which we try to capture.
-  static unsigned kStackToCapture = 32 * 1024;
-
-  const MappingInfo* mapping = FindMapping(stack_pointer);
-  if (!mapping)
-    return false;
-  if (stack_grows_down) {
-    const ptrdiff_t offset = stack_pointer - (uint8_t*) mapping->start_addr;
-    const ptrdiff_t distance_to_end =
-        static_cast<ptrdiff_t>(mapping->size) - offset;
-    *stack_len = distance_to_end > kStackToCapture ?
-                 kStackToCapture : distance_to_end;
-    *stack = stack_pointer;
-  } else {
-    const ptrdiff_t offset = stack_pointer - (uint8_t*) mapping->start_addr;
-    *stack_len = offset > kStackToCapture ? kStackToCapture : offset;
-    *stack = stack_pointer - *stack_len;
-  }
-
-  return true;
-}
-
-// static
-void LinuxDumper::CopyFromProcess(void* dest, pid_t child, const void* src,
-                                  size_t length) {
-  unsigned long tmp;
-  size_t done = 0;
-  static const size_t word_size = sizeof(tmp);
-  uint8_t* const local = (uint8_t*) dest;
-  uint8_t* const remote = (uint8_t*) src;
-
-  while (done < length) {
-    const size_t l = length - done > word_size ? word_size : length - done;
-    if (sys_ptrace(PTRACE_PEEKDATA, child, remote + done, &tmp) == -1)
-      tmp = 0;
-    memcpy(local + done, &tmp, l);
-    done += l;
-  }
-}
-
-// Find the mapping which the given memory address falls in.
-const MappingInfo* LinuxDumper::FindMapping(const void* address) const {
-  const uintptr_t addr = (uintptr_t) address;
-
-  for (size_t i = 0; i < mappings_.size(); ++i) {
-    const uintptr_t start = static_cast<uintptr_t>(mappings_[i]->start_addr);
-    if (addr >= start && addr - start < mappings_[i]->size)
-      return mappings_[i];
-  }
-
-  return NULL;
-}
-
-}  // namespace google_breakpad
deleted file mode 100644
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_dumper.h
+++ /dev/null
@@ -1,146 +0,0 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef CLIENT_LINUX_MINIDUMP_WRITER_LINUX_DUMPER_H_
-#define CLIENT_LINUX_MINIDUMP_WRITER_LINUX_DUMPER_H_
-
-#include <elf.h>
-#include <linux/limits.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <sys/user.h>
-
-#include "common/linux/memory.h"
-
-namespace google_breakpad {
-
-typedef typeof(((struct user*) 0)->u_debugreg[0]) debugreg_t;
-
-// Typedef for our parsing of the auxv variables in /proc/pid/auxv.
-#if defined(__i386)
-typedef Elf32_auxv_t elf_aux_entry;
-#elif defined(__x86_64__)
-typedef Elf64_auxv_t elf_aux_entry;
-#endif
-// When we find the VDSO mapping in the process's address space, this
-// is the name we use for it when writing it to the minidump.
-// This should always be less than NAME_MAX!
-const char kLinuxGateLibraryName[] = "linux-gate.so";
-
-// We produce one of these structures for each thread in the crashed process.
-struct ThreadInfo {
-  pid_t tgid;   // thread group id
-  pid_t ppid;   // parent process
-
-  // Even on platforms where the stack grows down, the following will point to
-  // the smallest address in the stack.
-  const void* stack;  // pointer to the stack area
-  size_t stack_len;  // length of the stack to copy
-
-  user_regs_struct regs;
-  user_fpregs_struct fpregs;
-#if defined(__i386)
-  user_fpxregs_struct fpxregs;
-#endif
-
-#if defined(__i386) || defined(__x86_64)
-
-  static const unsigned kNumDebugRegisters = 8;
-  debugreg_t dregs[8];
-#endif
-};
-
-// One of these is produced for each mapping in the process (i.e. line in
-// /proc/$x/maps).
-struct MappingInfo {
-  uintptr_t start_addr;
-  size_t size;
-  size_t offset;  // offset into the backed file.
-  char name[NAME_MAX];
-};
-
-class LinuxDumper {
- public:
-  explicit LinuxDumper(pid_t pid);
-
-  // Parse the data for |threads| and |mappings|.
-  bool Init();
-
-  // Suspend/resume all threads in the given process.
-  bool ThreadsSuspend();
-  bool ThreadsResume();
-
-  // Read information about the given thread. Returns true on success. One must
-  // have called |ThreadsSuspend| first.
-  bool ThreadInfoGet(pid_t tid, ThreadInfo* info);
-
-  // These are only valid after a call to |Init|.
-  const wasteful_vector<pid_t> &threads() { return threads_; }
-  const wasteful_vector<MappingInfo*> &mappings() { return mappings_; }
-  const MappingInfo* FindMapping(const void* address) const;
-
-  // Find a block of memory to take as the stack given the top of stack pointer.
-  //   stack: (output) the lowest address in the memory area
-  //   stack_len: (output) the length of the memory area
-  //   stack_top: the current top of the stack
-  bool GetStackInfo(const void** stack, size_t* stack_len, uintptr_t stack_top);
-
-  PageAllocator* allocator() { return &allocator_; }
-
-  // memcpy from a remote process.
-  static void CopyFromProcess(void* dest, pid_t child, const void* src,
-                              size_t length);
-
-  // Builds a proc path for a certain pid for a node.  path is a
-  // character array that is overwritten, and node is the final node
-  // without any slashes.
-  void BuildProcPath(char* path, pid_t pid, const char* node) const;
-
-  // Utility method to find the location of where the kernel has
-  // mapped linux-gate.so in memory(shows up in /proc/pid/maps as
-  // [vdso], but we can't guarantee that it's the only virtual dynamic
-  // shared object.  Parsing the auxilary vector for AT_SYSINFO_EHDR
-  // is the safest way to go.)
-  void* FindBeginningOfLinuxGateSharedLibrary(const pid_t pid) const;
- private:
-  bool EnumerateMappings(wasteful_vector<MappingInfo*>* result) const;
-  bool EnumerateThreads(wasteful_vector<pid_t>* result) const;
-
-  const pid_t pid_;
-
-  mutable PageAllocator allocator_;
-
-  bool threads_suspened_;
-  wasteful_vector<pid_t> threads_;  // the ids of all the threads
-  wasteful_vector<MappingInfo*> mappings_;  // info from /proc/<pid>/maps
-};
-
-}  // namespace google_breakpad
-
-#endif  // CLIENT_LINUX_HANDLER_LINUX_DUMPER_H_
deleted file mode 100644
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/linux_dumper_unittest.cc
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include <unistd.h>
-
-#include "client/linux/minidump_writer/linux_dumper.h"
-#include "breakpad_googletest_includes.h"
-
-using namespace google_breakpad;
-
-namespace {
-typedef testing::Test LinuxDumperTest;
-}
-
-TEST(LinuxDumperTest, Setup) {
-  LinuxDumper dumper(getpid());
-}
-
-TEST(LinuxDumperTest, FindMappings) {
-  LinuxDumper dumper(getpid());
-  ASSERT_TRUE(dumper.Init());
-
-  ASSERT_TRUE(dumper.FindMapping(reinterpret_cast<void*>(getpid)));
-  ASSERT_TRUE(dumper.FindMapping(reinterpret_cast<void*>(printf)));
-  ASSERT_FALSE(dumper.FindMapping(NULL));
-}
-
-TEST(LinuxDumperTest, ThreadList) {
-  LinuxDumper dumper(getpid());
-  ASSERT_TRUE(dumper.Init());
-
-  ASSERT_GE(dumper.threads().size(), 1);
-  bool found = false;
-  for (size_t i = 0; i < dumper.threads().size(); ++i) {
-    if (dumper.threads()[i] == getpid()) {
-      found = true;
-      break;
-    }
-  }
-}
-
-TEST(LinuxDumperTest, BuildProcPath) {
-  const pid_t pid = getpid();
-  LinuxDumper dumper(pid);
-
-  char maps_path[256] = "dummymappath";
-  char maps_path_expected[256];
-  snprintf(maps_path_expected, sizeof(maps_path_expected),
-           "/proc/%d/maps", pid);
-  dumper.BuildProcPath(maps_path, pid, "maps");
-  ASSERT_STREQ(maps_path, maps_path_expected);
-
-  // In release mode, we expect BuildProcPath to handle the invalid
-  // parameters correctly and fill map_path with an empty
-  // NULL-terminated string.
-#ifdef NDEBUG
-  snprintf(maps_path, sizeof(maps_path), "dummymappath");
-  dumper.BuildProcPath(maps_path, 0, "maps");
-  EXPECT_STREQ(maps_path, "");
-
-  snprintf(maps_path, sizeof(maps_path), "dummymappath");
-  dumper.BuildProcPath(maps_path, getpid(), "");
-  EXPECT_STREQ(maps_path, "");
-
-  snprintf(maps_path, sizeof(maps_path), "dummymappath");
-  dumper.BuildProcPath(maps_path, getpid(), NULL);
-  EXPECT_STREQ(maps_path, "");
-#endif
-}
-
-TEST(LinuxDumperTest, MappingsIncludeLinuxGate) {
-  LinuxDumper dumper(getpid());
-  ASSERT_TRUE(dumper.Init());
-
-  void* linux_gate_loc = dumper.FindBeginningOfLinuxGateSharedLibrary(getpid());
-  if (linux_gate_loc) {
-    bool found_linux_gate = false;
-
-    const wasteful_vector<MappingInfo*> mappings = dumper.mappings();
-    const MappingInfo* mapping;
-    for (unsigned i = 0; i < mappings.size(); ++i) {
-      mapping = mappings[i];
-      if (!strcmp(mapping->name, kLinuxGateLibraryName)) {
-        found_linux_gate = true;
-        break;
-      }
-    }
-    EXPECT_TRUE(found_linux_gate);
-    EXPECT_EQ(linux_gate_loc, reinterpret_cast<void*>(mapping->start_addr));
-    EXPECT_EQ(0, memcmp(linux_gate_loc, ELFMAG, SELFMAG));
-  }
-}
deleted file mode 100644
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer.cc
+++ /dev/null
@@ -1,872 +0,0 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-// This code writes out minidump files:
-//   http://msdn.microsoft.com/en-us/library/ms680378(VS.85,loband).aspx
-//
-// Minidumps are a Microsoft format which Breakpad uses for recording crash
-// dumps. This code has to run in a compromised environment (the address space
-// may have received SIGSEGV), thus the following rules apply:
-//   * You may not enter the dynamic linker. This means that we cannot call
-//     any symbols in a shared library (inc libc). Because of this we replace
-//     libc functions in linux_libc_support.h.
-//   * You may not call syscalls via the libc wrappers. This rule is a subset
-//     of the first rule but it bears repeating. We have direct wrappers
-//     around the system calls in linux_syscall_support.h.
-//   * You may not malloc. There's an alternative allocator in memory.h and
-//     a canonical instance in the LinuxDumper object. We use the placement
-//     new form to allocate objects and we don't delete them.
-
-#include "client/linux/minidump_writer/minidump_writer.h"
-#include "client/minidump_file_writer-inl.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/ucontext.h>
-#include <sys/user.h>
-#include <sys/utsname.h>
-
-#include "client/minidump_file_writer.h"
-#include "google_breakpad/common/minidump_format.h"
-#include "google_breakpad/common/minidump_cpu_amd64.h"
-#include "google_breakpad/common/minidump_cpu_x86.h"
-
-#include "client/linux/handler/exception_handler.h"
-#include "client/linux/minidump_writer/line_reader.h"
-#include "client/linux/minidump_writer//linux_dumper.h"
-#include "common/linux/linux_libc_support.h"
-#include "common/linux/linux_syscall_support.h"
-
-// These are additional minidump stream values which are specific to the linux
-// breakpad implementation.
-enum {
-  MD_LINUX_CPU_INFO              = 0x47670003,    /* /proc/cpuinfo    */
-  MD_LINUX_PROC_STATUS           = 0x47670004,    /* /proc/$x/status  */
-  MD_LINUX_LSB_RELEASE           = 0x47670005,    /* /etc/lsb-release */
-  MD_LINUX_CMD_LINE              = 0x47670006,    /* /proc/$x/cmdline */
-  MD_LINUX_ENVIRON               = 0x47670007,    /* /proc/$x/environ */
-  MD_LINUX_AUXV                  = 0x47670008     /* /proc/$x/auxv    */
-};
-
-// Minidump defines register structures which are different from the raw
-// structures which we get from the kernel. These are platform specific
-// functions to juggle the ucontext and user structures into minidump format.
-#if defined(__i386)
-typedef MDRawContextX86 RawContextCPU;
-
-// Write a uint16_t to memory
-//   out: memory location to write to
-//   v: value to write.
-static void U16(void* out, uint16_t v) {
-  memcpy(out, &v, sizeof(v));
-}
-
-// Write a uint32_t to memory
-//   out: memory location to write to
-//   v: value to write.
-static void U32(void* out, uint32_t v) {
-  memcpy(out, &v, sizeof(v));
-}
-
-// Juggle an x86 user_(fp|fpx|)regs_struct into minidump format
-//   out: the minidump structure
-//   info: the collection of register structures.
-static void CPUFillFromThreadInfo(MDRawContextX86 *out,
-                                  const google_breakpad::ThreadInfo &info) {
-  out->context_flags = MD_CONTEXT_X86_ALL;
-
-  out->dr0 = info.dregs[0];
-  out->dr1 = info.dregs[1];
-  out->dr2 = info.dregs[2];
-  out->dr3 = info.dregs[3];
-  // 4 and 5 deliberatly omitted because they aren't included in the minidump
-  // format.
-  out->dr6 = info.dregs[6];
-  out->dr7 = info.dregs[7];
-
-  out->gs = info.regs.xgs;
-  out->fs = info.regs.xfs;
-  out->es = info.regs.xes;
-  out->ds = info.regs.xds;
-
-  out->edi = info.regs.edi;
-  out->esi = info.regs.esi;
-  out->ebx = info.regs.ebx;
-  out->edx = info.regs.edx;
-  out->ecx = info.regs.ecx;
-  out->eax = info.regs.eax;
-
-  out->ebp = info.regs.ebp;
-  out->eip = info.regs.eip;
-  out->cs = info.regs.xcs;
-  out->eflags = info.regs.eflags;
-  out->esp = info.regs.esp;
-  out->ss = info.regs.xss;
-
-  out->float_save.control_word = info.fpregs.cwd;
-  out->float_save.status_word = info.fpregs.swd;
-  out->float_save.tag_word = info.fpregs.twd;
-  out->float_save.error_offset = info.fpregs.fip;
-  out->float_save.error_selector = info.fpregs.fcs;
-  out->float_save.data_offset = info.fpregs.foo;
-  out->float_save.data_selector = info.fpregs.fos;
-
-  // 8 registers * 10 bytes per register.
-  memcpy(out->float_save.register_area, info.fpregs.st_space, 10 * 8);
-
-  // This matches the Intel fpsave format.
-  U16(out->extended_registers + 0, info.fpregs.cwd);
-  U16(out->extended_registers + 2, info.fpregs.swd);
-  U16(out->extended_registers + 4, info.fpregs.twd);
-  U16(out->extended_registers + 6, info.fpxregs.fop);
-  U32(out->extended_registers + 8, info.fpxregs.fip);
-  U16(out->extended_registers + 12, info.fpxregs.fcs);
-  U32(out->extended_registers + 16, info.fpregs.foo);
-  U16(out->extended_registers + 20, info.fpregs.fos);
-  U32(out->extended_registers + 24, info.fpxregs.mxcsr);
-
-  memcpy(out->extended_registers + 32, &info.fpxregs.st_space, 128);
-  memcpy(out->extended_registers + 160, &info.fpxregs.xmm_space, 128);
-}
-
-// Juggle an x86 ucontext into minidump format
-//   out: the minidump structure
-//   info: the collection of register structures.
-static void CPUFillFromUContext(MDRawContextX86 *out, const ucontext *uc,
-                                const struct _libc_fpstate* fp) {
-  const greg_t* regs = uc->uc_mcontext.gregs;
-
-  out->context_flags = MD_CONTEXT_X86_FULL |
-                       MD_CONTEXT_X86_FLOATING_POINT;
-
-  out->gs = regs[REG_GS];
-  out->fs = regs[REG_FS];
-  out->es = regs[REG_ES];
-  out->ds = regs[REG_DS];
-
-  out->edi = regs[REG_EDI];
-  out->esi = regs[REG_ESI];
-  out->ebx = regs[REG_EBX];
-  out->edx = regs[REG_EDX];
-  out->ecx = regs[REG_ECX];
-  out->eax = regs[REG_EAX];
-
-  out->ebp = regs[REG_EBP];
-  out->eip = regs[REG_EIP];
-  out->cs = regs[REG_CS];
-  out->eflags = regs[REG_EFL];
-  out->esp = regs[REG_UESP];
-  out->ss = regs[REG_SS];
-
-  out->float_save.control_word = fp->cw;
-  out->float_save.status_word = fp->sw;
-  out->float_save.tag_word = fp->tag;
-  out->float_save.error_offset = fp->ipoff;
-  out->float_save.error_selector = fp->cssel;
-  out->float_save.data_offset = fp->dataoff;
-  out->float_save.data_selector = fp->datasel;
-
-  // 8 registers * 10 bytes per register.
-  memcpy(out->float_save.register_area, fp->_st, 10 * 8);
-}
-
-#elif defined(__x86_64)
-typedef MDRawContextAMD64 RawContextCPU;
-
-static void CPUFillFromThreadInfo(MDRawContextAMD64 *out,
-                                  const google_breakpad::ThreadInfo &info) {
-  out->context_flags = MD_CONTEXT_AMD64_FULL |
-                       MD_CONTEXT_AMD64_SEGMENTS;
-
-  out->cs = info.regs.cs;
-
-  out->ds = info.regs.ds;
-  out->es = info.regs.es;
-  out->fs = info.regs.fs;
-  out->gs = info.regs.gs;
-
-  out->ss = info.regs.ss;
-  out->eflags = info.regs.eflags;
-
-  out->dr0 = info.dregs[0];
-  out->dr1 = info.dregs[1];
-  out->dr2 = info.dregs[2];
-  out->dr3 = info.dregs[3];
-  // 4 and 5 deliberatly omitted because they aren't included in the minidump
-  // format.
-  out->dr6 = info.dregs[6];
-  out->dr7 = info.dregs[7];
-
-  out->rax = info.regs.rax;
-  out->rcx = info.regs.rcx;
-  out->rdx = info.regs.rdx;
-  out->rbx = info.regs.rbx;
-
-  out->rsp = info.regs.rsp;
-
-  out->rbp = info.regs.rbp;
-  out->rsi = info.regs.rsi;
-  out->rdi = info.regs.rdi;
-  out->r8 = info.regs.r8;
-  out->r9 = info.regs.r9;
-  out->r10 = info.regs.r10;
-  out->r11 = info.regs.r11;
-  out->r12 = info.regs.r12;
-  out->r13 = info.regs.r13;
-  out->r14 = info.regs.r14;
-  out->r15 = info.regs.r15;
-
-  out->rip = info.regs.rip;
-
-  out->flt_save.control_word = info.fpregs.cwd;
-  out->flt_save.status_word = info.fpregs.swd;
-  out->flt_save.tag_word = info.fpregs.ftw;
-  out->flt_save.error_opcode = info.fpregs.fop;
-  out->flt_save.error_offset = info.fpregs.rip;
-  out->flt_save.error_selector = 0; // We don't have this.
-  out->flt_save.data_offset = info.fpregs.rdp;
-  out->flt_save.data_selector = 0;  // We don't have this.
-  out->flt_save.mx_csr = info.fpregs.mxcsr;
-  out->flt_save.mx_csr_mask = info.fpregs.mxcr_mask;
-  memcpy(&out->flt_save.float_registers, &info.fpregs.st_space, 8 * 16);
-  memcpy(&out->flt_save.xmm_registers, &info.fpregs.xmm_space, 16 * 16);
-}
-
-static void CPUFillFromUContext(MDRawContextAMD64 *out, const ucontext *uc,
-                                const struct _libc_fpstate* fpregs) {
-  const greg_t* regs = uc->uc_mcontext.gregs;
-
-  out->context_flags = MD_CONTEXT_AMD64_FULL;
-
-  out->cs = regs[REG_CSGSFS] & 0xffff;
-
-  out->fs = (regs[REG_CSGSFS] >> 32) & 0xffff;
-  out->gs = (regs[REG_CSGSFS] >> 16) & 0xffff;
-
-  out->eflags = regs[REG_EFL];
-
-  out->rax = regs[REG_RAX];
-  out->rcx = regs[REG_RCX];
-  out->rdx = regs[REG_RDX];
-  out->rbx = regs[REG_RBX];
-
-  out->rsp = regs[REG_RSP];
-  out->rbp = regs[REG_RBP];
-  out->rsi = regs[REG_RSI];
-  out->rdi = regs[REG_RDI];
-  out->r8 = regs[REG_R8];
-  out->r9 = regs[REG_R9];
-  out->r10 = regs[REG_R10];
-  out->r11 = regs[REG_R11];
-  out->r12 = regs[REG_R12];
-  out->r13 = regs[REG_R13];
-  out->r14 = regs[REG_R14];
-  out->r15 = regs[REG_R15];
-
-  out->rip = regs[REG_RIP];
-
-  out->flt_save.control_word = fpregs->cwd;
-  out->flt_save.status_word = fpregs->swd;
-  out->flt_save.tag_word = fpregs->ftw;
-  out->flt_save.error_opcode = fpregs->fop;
-  out->flt_save.error_offset = fpregs->rip;
-  out->flt_save.data_offset = fpregs->rdp;
-  out->flt_save.error_selector = 0; // We don't have this.
-  out->flt_save.data_selector = 0;  // We don't have this.
-  out->flt_save.mx_csr = fpregs->mxcsr;
-  out->flt_save.mx_csr_mask = fpregs->mxcr_mask;
-  memcpy(&out->flt_save.float_registers, &fpregs->_st, 8 * 16);
-  memcpy(&out->flt_save.xmm_registers, &fpregs->_xmm, 16 * 16);
-}
-
-#else
-#error "This code has not been ported to your platform yet."
-#endif
-
-namespace google_breakpad {
-
-class MinidumpWriter {
- public:
-  MinidumpWriter(const char* filename,
-                 pid_t crashing_pid,
-                 const ExceptionHandler::CrashContext* context)
-      : filename_(filename),
-        siginfo_(&context->siginfo),
-        ucontext_(&context->context),
-        float_state_(&context->float_state),
-        crashing_tid_(context->tid),
-        dumper_(crashing_pid) {
-  }
-
-  bool Init() {
-    return dumper_.Init() && minidump_writer_.Open(filename_) &&
-           dumper_.ThreadsSuspend();
-  }
-
-  ~MinidumpWriter() {
-    minidump_writer_.Close();
-    dumper_.ThreadsResume();
-  }
-
-  bool Dump() {
-    // A minidump file contains a number of tagged streams. This is the number
-    // of stream which we write.
-    static const unsigned kNumWriters = 11;
-
-    TypedMDRVA<MDRawHeader> header(&minidump_writer_);
-    TypedMDRVA<MDRawDirectory> dir(&minidump_writer_);
-    if (!header.Allocate())
-      return false;
-    if (!dir.AllocateArray(kNumWriters))
-      return false;
-    memset(header.get(), 0, sizeof(MDRawHeader));
-
-    header.get()->signature = MD_HEADER_SIGNATURE;
-    header.get()->version = MD_HEADER_VERSION;
-    header.get()->time_date_stamp = time(NULL);
-    header.get()->stream_count = kNumWriters;
-    header.get()->stream_directory_rva = dir.position();
-
-    unsigned dir_index = 0;
-    MDRawDirectory dirent;
-
-    if (!WriteThreadListStream(&dirent))
-      return false;
-    dir.CopyIndex(dir_index++, &dirent);
-
-    if (!WriteMappings(&dirent))
-      return false;
-    dir.CopyIndex(dir_index++, &dirent);
-
-    if (!WriteExceptionStream(&dirent))
-      return false;
-    dir.CopyIndex(dir_index++, &dirent);
-
-    if (!WriteSystemInfoStream(&dirent))
-      return false;
-    dir.CopyIndex(dir_index++, &dirent);
-
-    dirent.stream_type = MD_LINUX_CPU_INFO;
-    if (!WriteFile(&dirent.location, "/proc/cpuinfo"))
-      NullifyDirectoryEntry(&dirent);
-    dir.CopyIndex(dir_index++, &dirent);
-
-    dirent.stream_type = MD_LINUX_PROC_STATUS;
-    if (!WriteProcFile(&dirent.location, crashing_tid_, "status"))
-      NullifyDirectoryEntry(&dirent);
-    dir.CopyIndex(dir_index++, &dirent);
-
-    dirent.stream_type = MD_LINUX_LSB_RELEASE;
-    if (!WriteFile(&dirent.location, "/etc/lsb-release"))
-      NullifyDirectoryEntry(&dirent);
-    dir.CopyIndex(dir_index++, &dirent);
-
-    dirent.stream_type = MD_LINUX_CMD_LINE;
-    if (!WriteProcFile(&dirent.location, crashing_tid_, "cmdline"))
-      NullifyDirectoryEntry(&dirent);
-    dir.CopyIndex(dir_index++, &dirent);
-
-    dirent.stream_type = MD_LINUX_ENVIRON;
-    if (!WriteProcFile(&dirent.location, crashing_tid_, "environ"))
-      NullifyDirectoryEntry(&dirent);
-    dir.CopyIndex(dir_index++, &dirent);
-
-    dirent.stream_type = MD_LINUX_AUXV;
-    if (!WriteProcFile(&dirent.location, crashing_tid_, "auxv"))
-      NullifyDirectoryEntry(&dirent);
-    dir.CopyIndex(dir_index++, &dirent);
-
-    dirent.stream_type = MD_LINUX_AUXV;
-    if (!WriteProcFile(&dirent.location, crashing_tid_, "maps"))
-      NullifyDirectoryEntry(&dirent);
-    dir.CopyIndex(dir_index++, &dirent);
-
-    // If you add more directory entries, don't forget to update kNumWriters,
-    // above.
-
-    dumper_.ThreadsResume();
-    return true;
-  }
-
-  // Write information about the threads.
-  bool WriteThreadListStream(MDRawDirectory* dirent) {
-    const unsigned num_threads = dumper_.threads().size();
-
-    TypedMDRVA<uint32_t> list(&minidump_writer_);
-    if (!list.AllocateObjectAndArray(num_threads, sizeof(MDRawThread)))
-      return false;
-
-    dirent->stream_type = MD_THREAD_LIST_STREAM;
-    dirent->location = list.location();
-
-    *list.get() = num_threads;
-
-    for (unsigned i = 0; i < num_threads; ++i) {
-      MDRawThread thread;
-      my_memset(&thread, 0, sizeof(thread));
-      thread.thread_id = dumper_.threads()[i];
-      // We have a different source of information for the crashing thread. If
-      // we used the actual state of the thread we would find it running in the
-      // signal handler with the alternative stack, which would be deeply
-      // unhelpful.
-      if (thread.thread_id == crashing_tid_) {
-        const void* stack;
-        size_t stack_len;
-        if (!dumper_.GetStackInfo(&stack, &stack_len, GetStackPointer()))
-          return false;
-        UntypedMDRVA memory(&minidump_writer_);
-        if (!memory.Allocate(stack_len))
-          return false;
-        uint8_t* stack_copy = (uint8_t*) dumper_.allocator()->Alloc(stack_len);
-        dumper_.CopyFromProcess(stack_copy, thread.thread_id, stack, stack_len);
-        memory.Copy(stack_copy, stack_len);
-        thread.stack.start_of_memory_range = (uintptr_t) (stack);
-        thread.stack.memory = memory.location();
-        TypedMDRVA<RawContextCPU> cpu(&minidump_writer_);
-        if (!cpu.Allocate())
-          return false;
-        my_memset(cpu.get(), 0, sizeof(RawContextCPU));
-        CPUFillFromUContext(cpu.get(), ucontext_, float_state_);
-        thread.thread_context = cpu.location();
-        crashing_thread_context_ = cpu.location();
-      } else {
-        ThreadInfo info;
-        if (!dumper_.ThreadInfoGet(dumper_.threads()[i], &info))
-          return false;
-        UntypedMDRVA memory(&minidump_writer_);
-        if (!memory.Allocate(info.stack_len))
-          return false;
-        uint8_t* stack_copy =
-            (uint8_t*) dumper_.allocator()->Alloc(info.stack_len);
-        dumper_.CopyFromProcess(stack_copy, thread.thread_id, info.stack,
-                                info.stack_len);
-        memory.Copy(stack_copy, info.stack_len);
-        thread.stack.start_of_memory_range = (uintptr_t)(info.stack);
-        thread.stack.memory = memory.location();
-        TypedMDRVA<RawContextCPU> cpu(&minidump_writer_);
-        if (!cpu.Allocate())
-          return false;
-        my_memset(cpu.get(), 0, sizeof(RawContextCPU));
-        CPUFillFromThreadInfo(cpu.get(), info);
-        thread.thread_context = cpu.location();
-      }
-
-      list.CopyIndexAfterObject(i, &thread, sizeof(thread));
-    }
-
-    return true;
-  }
-
-  static bool ShouldIncludeMapping(const MappingInfo& mapping) {
-    if (mapping.name[0] == 0 || // we only want modules with filenames.
-        mapping.offset || // we only want to include one mapping per shared lib.
-        mapping.size < 4096) {  // too small to get a signature for.
-      return false;
-    }
-
-    return true;
-  }
-
-  // Write information about the mappings in effect. Because we are using the
-  // minidump format, the information about the mappings is pretty limited.
-  // Because of this, we also include the full, unparsed, /proc/$x/maps file in
-  // another stream in the file.
-  bool WriteMappings(MDRawDirectory* dirent) {
-    const unsigned num_mappings = dumper_.mappings().size();
-    unsigned num_output_mappings = 0;
-
-    for (unsigned i = 0; i < dumper_.mappings().size(); ++i) {
-      const MappingInfo& mapping = *dumper_.mappings()[i];
-      if (ShouldIncludeMapping(mapping))
-        num_output_mappings++;
-    }
-
-    TypedMDRVA<uint32_t> list(&minidump_writer_);
-    if (!list.AllocateObjectAndArray(num_output_mappings, MD_MODULE_SIZE))
-      return false;
-
-    dirent->stream_type = MD_MODULE_LIST_STREAM;
-    dirent->location = list.location();
-    *list.get() = num_output_mappings;
-
-    for (unsigned i = 0, j = 0; i < num_mappings; ++i) {
-      const MappingInfo& mapping = *dumper_.mappings()[i];
-      if (!ShouldIncludeMapping(mapping))
-        continue;
-
-      MDRawModule mod;
-      my_memset(&mod, 0, MD_MODULE_SIZE);
-      mod.base_of_image = mapping.start_addr;
-      mod.size_of_image = mapping.size;
-      const size_t filepath_len = my_strlen(mapping.name);
-
-      // Figure out file name from path
-      const char* filename_ptr = mapping.name + filepath_len - 1;
-      while (filename_ptr >= mapping.name) {
-        if (*filename_ptr == '/')
-          break;
-        filename_ptr--;
-      }
-      filename_ptr++;
-      const size_t filename_len = mapping.name + filepath_len - filename_ptr;
-
-      uint8_t cv_buf[MDCVInfoPDB70_minsize + NAME_MAX];
-      uint8_t* cv_ptr = cv_buf;
-      UntypedMDRVA cv(&minidump_writer_);
-      if (!cv.Allocate(MDCVInfoPDB70_minsize + filename_len + 1))
-        return false;
-
-      const uint32_t cv_signature = MD_CVINFOPDB70_SIGNATURE;
-      memcpy(cv_ptr, &cv_signature, sizeof(cv_signature));
-      cv_ptr += sizeof(cv_signature);
-
-      {
-        // We XOR the first page of the file to get a signature for it.
-        uint8_t xor_buf[sizeof(MDGUID)];
-        size_t done = 0;
-        uint8_t* signature = cv_ptr;
-        cv_ptr += sizeof(xor_buf);
-
-        my_memset(signature, 0, sizeof(xor_buf));
-        while (done < 4096) {
-          dumper_.CopyFromProcess(xor_buf, crashing_tid_,
-                                  (void *) (mod.base_of_image + done),
-                                  sizeof(xor_buf));
-          for (unsigned i = 0; i < sizeof(xor_buf); ++i)
-            signature[i] ^= xor_buf[i];
-          done += sizeof(xor_buf);
-        }
-        my_memset(cv_ptr, 0, sizeof(uint32_t));  // Set age to 0 on Linux.
-        cv_ptr += sizeof(uint32_t);
-      }
-
-      // Write pdb_file_name
-      memcpy(cv_ptr, filename_ptr, filename_len + 1);
-      cv.Copy(cv_buf, MDCVInfoPDB70_minsize + filename_len + 1);
-
-      mod.cv_record = cv.location();
-
-      MDLocationDescriptor ld;
-      if (!minidump_writer_.WriteString(mapping.name, filepath_len, &ld))
-        return false;
-      mod.module_name_rva = ld.rva;
-
-      list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE);
-    }
-
-    return true;
-  }
-
-  bool WriteExceptionStream(MDRawDirectory* dirent) {
-    TypedMDRVA<MDRawExceptionStream> exc(&minidump_writer_);
-    if (!exc.Allocate())
-      return false;
-    my_memset(exc.get(), 0, sizeof(MDRawExceptionStream));
-
-    dirent->stream_type = MD_EXCEPTION_STREAM;
-    dirent->location = exc.location();
-
-    exc.get()->thread_id = crashing_tid_;
-    exc.get()->exception_record.exception_code = siginfo_->si_signo;
-    exc.get()->exception_record.exception_address =
-        (uintptr_t) siginfo_->si_addr;
-    exc.get()->thread_context = crashing_thread_context_;
-
-    return true;
-  }
-
-  bool WriteSystemInfoStream(MDRawDirectory* dirent) {
-    TypedMDRVA<MDRawSystemInfo> si(&minidump_writer_);
-    if (!si.Allocate())
-      return false;
-    my_memset(si.get(), 0, sizeof(MDRawSystemInfo));
-
-    dirent->stream_type = MD_SYSTEM_INFO_STREAM;
-    dirent->location = si.location();
-
-    WriteCPUInformation(si.get());
-    WriteOSInformation(si.get());
-
-    return true;
-  }
-
- private:
-#if defined(__i386)
-  uintptr_t GetStackPointer() {
-    return ucontext_->uc_mcontext.gregs[REG_ESP];
-  }
-#elif defined(__x86_64)
-  uintptr_t GetStackPointer() {
-    return ucontext_->uc_mcontext.gregs[REG_RSP];
-  }
-#else
-#error "This code has not been ported to your platform yet."
-#endif
-
-  void NullifyDirectoryEntry(MDRawDirectory* dirent) {
-    dirent->stream_type = 0;
-    dirent->location.data_size = 0;
-    dirent->location.rva = 0;
-  }
-
-  bool WriteCPUInformation(MDRawSystemInfo* sys_info) {
-    char vendor_id[sizeof(sys_info->cpu.x86_cpu_info.vendor_id) + 1] = {0};
-    static const char vendor_id_name[] = "vendor_id";
-    static const size_t vendor_id_name_length = sizeof(vendor_id_name) - 1;
-
-    struct CpuInfoEntry {
-      const char* info_name;
-      int value;
-      bool found;
-    } cpu_info_table[] = {
-      { "processor", -1, false },
-      { "model", 0, false },
-      { "stepping",  0, false },
-      { "cpu family", 0, false },
-    };
-
-    // processor_architecture should always be set, do this first
-    sys_info->processor_architecture =
-#if defined(__i386)
-        MD_CPU_ARCHITECTURE_X86;
-#elif defined(__x86_64)
-        MD_CPU_ARCHITECTURE_AMD64;
-#else
-#error "Unknown CPU arch"
-#endif
-
-    const int fd = sys_open("/proc/cpuinfo", O_RDONLY, 0);
-    if (fd < 0)
-      return false;
-
-    {
-      PageAllocator allocator;
-      LineReader* const line_reader = new(allocator) LineReader(fd);
-      const char* line;
-      unsigned line_len;
-      while (line_reader->GetNextLine(&line, &line_len)) {
-        for (size_t i = 0;
-             i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]);
-             i++) {
-          CpuInfoEntry* entry = &cpu_info_table[i];
-          if (entry->found)
-            continue;
-          if (!strncmp(line, entry->info_name, strlen(entry->info_name))) {
-            const char* value = strchr(line, ':');
-            if (!value)
-              continue;
-
-            // the above strncmp only matches the prefix, it might be the wrong
-            // line. i.e. we matched "model name" instead of "model".
-            // check and make sure there is only spaces between the prefix and
-            // the colon.
-            const char* space_ptr = line + strlen(entry->info_name);
-            for (; space_ptr < value; space_ptr++) {
-              if (!isspace(*space_ptr)) {
-                break;
-              }
-            }
-            if (space_ptr != value)
-              continue;
-
-            sscanf(++value, " %d", &(entry->value));
-            entry->found = true;
-          }
-        }
-
-        // special case for vendor_id
-        if (!strncmp(line, vendor_id_name, vendor_id_name_length)) {
-          const char* value = strchr(line, ':');
-          if (!value)
-            goto popline;
-
-          // skip ':" and all the spaces that follows
-          do {
-            value++;
-          } while (isspace(*value));
-
-          if (*value) {
-            size_t length = strlen(value);
-            if (length == 0)
-              goto popline;
-            // we don't want the trailing newline
-            if (value[length - 1] == '\n')
-              length--;
-            // ensure we have space for the value
-            if (length < sizeof(vendor_id))
-              strncpy(vendor_id, value, length);
-          }
-        }
-
-popline:
-        line_reader->PopLine(line_len);
-      }
-      sys_close(fd);
-    }
-
-    // make sure we got everything we wanted
-    for (size_t i = 0;
-         i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]);
-         i++) {
-      if (!cpu_info_table[i].found) {
-        return false;
-      }
-    }
-    // /proc/cpuinfo contains cpu id, change it into number by adding one.
-    cpu_info_table[0].value++;
-
-    sys_info->number_of_processors = cpu_info_table[0].value;
-    sys_info->processor_level      = cpu_info_table[3].value;
-    sys_info->processor_revision   = cpu_info_table[1].value << 8 |
-                                     cpu_info_table[2].value;
-
-    if (vendor_id[0] != '\0') {
-      memcpy(sys_info->cpu.x86_cpu_info.vendor_id, vendor_id,
-             sizeof(sys_info->cpu.x86_cpu_info.vendor_id));
-    }
-    return true;
-  }
-
-  bool WriteFile(MDLocationDescriptor* result, const char* filename) {
-    const int fd = sys_open(filename, O_RDONLY, 0);
-    if (fd < 0)
-      return false;
-
-    // We can't stat the files because several of the files that we want to
-    // read are kernel seqfiles, which always have a length of zero. So we have
-    // to read as much as we can into a buffer.
-    static const unsigned kMaxFileSize = 1024;
-    uint8_t* data = (uint8_t*) dumper_.allocator()->Alloc(kMaxFileSize);
-
-    size_t done = 0;
-    while (done < kMaxFileSize) {
-      ssize_t r;
-      do {
-        r = sys_read(fd, data + done, kMaxFileSize - done);
-      } while (r == -1 && errno == EINTR);
-
-      if (r < 1)
-        break;
-      done += r;
-    }
-    sys_close(fd);
-
-    if (!done)
-      return false;
-
-    UntypedMDRVA memory(&minidump_writer_);
-    if (!memory.Allocate(done))
-      return false;
-    memory.Copy(data, done);
-    *result = memory.location();
-    return true;
-  }
-
-  bool WriteOSInformation(MDRawSystemInfo* sys_info) {
-    sys_info->platform_id = MD_OS_LINUX;
-
-    struct utsname uts;
-    if (uname(&uts))
-      return false;
-
-    static const size_t buf_len = 512;
-    char buf[buf_len] = {0};
-    size_t space_left = buf_len - 1;
-    const char* info_table[] = {
-      uts.sysname,
-      uts.release,
-      uts.version,
-      uts.machine,
-      NULL
-    };
-    bool first_item = true;
-    for (const char** cur_info = info_table; *cur_info; cur_info++) {
-      static const char* separator = " ";
-      size_t separator_len = strlen(separator);
-      size_t info_len = strlen(*cur_info);
-      if (info_len == 0)
-        continue;
-
-      if (space_left < info_len + (first_item ? 0 : separator_len))
-        break;
-
-      if (!first_item) {
-        strcat(buf, separator);
-        space_left -= separator_len;
-      }
-
-      first_item = false;
-      strcat(buf, *cur_info);
-      space_left -= info_len;
-    }
-
-    MDLocationDescriptor location;
-    if (!minidump_writer_.WriteString(buf, 0, &location))
-      return false;
-    sys_info->csd_version_rva = location.rva;
-
-    return true;
-  }
-
-  bool WriteProcFile(MDLocationDescriptor* result, pid_t pid,
-                     const char* filename) {
-    char buf[80];
-    memcpy(buf, "/proc/", 6);
-    const unsigned pid_len = my_int_len(pid);
-    my_itos(buf + 6, pid, pid_len);
-    buf[6 + pid_len] = '/';
-    memcpy(buf + 6 + pid_len + 1, filename, my_strlen(filename) + 1);
-    return WriteFile(result, buf);
-  }
-
-  const char* const filename_;  // output filename
-  const siginfo_t* const siginfo_;  // from the signal handler (see sigaction)
-  const struct ucontext* const ucontext_;  // also from the signal handler
-  const struct _libc_fpstate* const float_state_;  // ditto
-  const pid_t crashing_tid_;  // the process which actually crashed
-  LinuxDumper dumper_;
-  MinidumpFileWriter minidump_writer_;
-  MDLocationDescriptor crashing_thread_context_;
-};
-
-bool WriteMinidump(const char* filename, pid_t crashing_process,
-                   const void* blob, size_t blob_size) {
-  if (blob_size != sizeof(ExceptionHandler::CrashContext))
-    return false;
-  const ExceptionHandler::CrashContext* context =
-      reinterpret_cast<const ExceptionHandler::CrashContext*>(blob);
-  MinidumpWriter writer(filename, crashing_process, context);
-  if (!writer.Init())
-    return false;
-  return writer.Dump();
-}
-
-}  // namespace google_breakpad
deleted file mode 100644
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer.h
+++ /dev/null
@@ -1,53 +0,0 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifndef CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_WRITER_H_
-#define CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_WRITER_H_
-
-#include <stdint.h>
-#include <unistd.h>
-
-namespace google_breakpad {
-
-// Write a minidump to the filesystem. This function does not malloc nor use
-// libc functions which may. Thus, it can be used in contexts where the state
-// of the heap may be corrupt.
-//   filename: the filename to write to. This is opened O_EXCL and fails if
-//     open fails.
-//   crashing_process: the pid of the crashing process. This must be trusted.
-//   blob: a blob of data from the crashing process. See exception_handler.h
-//   blob_size: the length of |blob|, in bytes
-//
-// Returns true iff successful.
-bool WriteMinidump(const char* filename, pid_t crashing_process,
-                   const void* blob, size_t blob_size);
-
-}  // namespace google_breakpad
-
-#endif  // CLIENT_LINUX_MINIDUMP_WRITER_MINIDUMP_WRITER_H_
deleted file mode 100644
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/minidump_writer/minidump_writer_unittest.cc
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include <unistd.h>
-#include <sys/syscall.h>
-
-#include "client/linux/handler/exception_handler.h"
-#include "client/linux/minidump_writer/minidump_writer.h"
-#include "breakpad_googletest_includes.h"
-
-using namespace google_breakpad;
-
-// This provides a wrapper around system calls which may be
-// interrupted by a signal and return EINTR. See man 7 signal.
-#define HANDLE_EINTR(x) ({ \
-  typeof(x) __eintr_result__; \
-  do { \
-    __eintr_result__ = x; \
-  } while (__eintr_result__ == -1 && errno == EINTR); \
-  __eintr_result__;\
-})
-
-namespace {
-typedef testing::Test MinidumpWriterTest;
-}
-
-TEST(MinidumpWriterTest, Setup) {
-  int fds[2];
-  ASSERT_NE(-1, pipe(fds));
-
-  const pid_t child = fork();
-  if (child == 0) {
-    close(fds[1]);
-    char b;
-    HANDLE_EINTR(read(fds[0], &b, sizeof(b)));
-    close(fds[0]);
-    syscall(__NR_exit);
-  }
-  close(fds[0]);
-
-  ExceptionHandler::CrashContext context;
-  memset(&context, 0, sizeof(context));
-
-  char templ[] = "/tmp/minidump-writer-unittest-XXXXXX";
-  mktemp(templ);
-  ASSERT_TRUE(WriteMinidump(templ, child, &context, sizeof(context)));
-  struct stat st;
-  ASSERT_EQ(stat(templ, &st), 0);
-  ASSERT_GT(st.st_size, 0u);
-  unlink(templ);
-
-  close(fds[1]);
-}
deleted file mode 100644
--- a/toolkit/crashreporter/google-breakpad/src/client/linux/sender/google_crash_report_sender.cc
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright (c) 2009, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#include "common/linux/google_crashdump_uploader.h"
-#include "third_party/linux/include/glog/logging.h"
-#include "third_party/linux/include/gflags/gflags.h"
-#include <string>
-
-DEFINE_string(crash_server, "http://clients2.google.com/cr",
-              "The crash server to upload minidumps to.");
-DEFINE_string(product_name, "",
-              "The product name that the minidump corresponds to.");
-DEFINE_string(product_version, "",
-              "The version of the product that produced the minidump.");
-DEFINE_string(client_id, "",
-              "The client GUID");
-DEFINE_string(minidump_path, "",
-              "The path of the minidump file.");
-DEFINE_string(ptime, "",
-              "The process uptime in milliseconds.");
-DEFINE_string(ctime, "",
-              "The cumulative process uptime in milliseconds.");
-DEFINE_string(email, "",
-              "The user's email address.");
-DEFINE_string(comments, "",
-              "Extra user comments");
-DEFINE_string(proxy_host, "",
-              "Proxy host");
-DEFINE_string(proxy_userpasswd, "",
-              "Proxy username/password in user:pass format.");
-
-
-bool CheckForRequiredFlagsOrDie() {
-  std::string error_text = "";
-  if (FLAGS_product_name.empty()) {
-    error_text.append("\nProduct name must be specified.");
-  }
-
-  if (FLAGS_product_version.empty()) {
-    error_text.append("\nProduct version must be specified.");
-  }
-
-  if (FLAGS_client_id.empty()) {
-    error_text.append("\nClient ID must be specified.");
-  }
-
-  if (FLAGS_minidump_path.empty()) {
-    error_text.append("\nMinidump pathname must be specified.");
-  }
-
-  if (!error_text.empty()) {
-    LOG(ERROR) << error_text;
-    return false;
-  }
-  return true;
-}
-
-int main(int argc, char *argv[]) {
-  google::InitGoogleLogging(argv[0]);
-  google::ParseCommandLineFlags(&argc, &argv, true);
-  if (!CheckForRequiredFlagsOrDie()) {
-    return 1;
-  }
-  google_breakpad::GoogleCrashdumpUploader g(FLAGS_product_name,
-                                             FLAGS_product_version,
-                                             FLAGS_client_id,
-                                             FLAGS_ptime,
-                                             FLAGS_ctime,
-                                             FLAGS_email,
-                                             FLAGS_comments,
-                                             FLAGS_minidump_path,
-                                             FLAGS_crash_server,
-                                             FLAGS_proxy_host,
-                                             FLAGS_proxy_userpasswd);
-  g.Upload();
-}
--- a/toolkit/crashreporter/google-breakpad/src/client/mac/Breakpad.xcodeproj/project.pbxproj
+++ b/toolkit/crashreporter/google-breakpad/src/client/mac/Breakpad.xcodeproj/project.pbxproj
@@ -14,19 +14,16 @@
 			);
 			dependencies = (
 				F94585880F78232B009A47BF /* PBXTargetDependency */,
 				F945858A0F78232E009A47BF /* PBXTargetDependency */,
 				F945858C0F782330009A47BF /* PBXTargetDependency */,
 				F945858E0F782333009A47BF /* PBXTargetDependency */,
 				F94585900F782336009A47BF /* PBXTargetDependency */,
 				F93DE3A70F830D1D00608B94 /* PBXTargetDependency */,
-				F95BB8B3101F94D300AA053B /* PBXTargetDependency */,
-				F95BB8B5101F94D300AA053B /* PBXTargetDependency */,
-				F95BB8B7101F94D300AA053B /* PBXTargetDependency */,
 			);
 			name = All;
 			productName = All;
 		};
 /* End PBXAggregateTarget section */
 
 /* Begin PBXBuildFile section */
 		3329D4ED0FA16D820007BBC5 /* Breakpad.nib in Resources */ = {isa = PBXBuildFile; fileRef = 3329D4EC0FA16D820007BBC5 /* Breakpad.nib */; };
@@ -86,17 +83,16 @@
 		F93DE33A0F82C66B00608B94 /* string_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53850ECCE6AD009BE4BA /* string_conversion.cc */; };
 		F93DE33B0F82C66B00608B94 /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53740ECCE635009BE4BA /* file_id.cc */; };
 		F93DE33C0F82C66B00608B94 /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C537A0ECCE635009BE4BA /* macho_id.cc */; };
 		F93DE33D0F82C66B00608B94 /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C537C0ECCE635009BE4BA /* macho_utilities.cc */; };
 		F93DE33E0F82C66B00608B94 /* macho_walker.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C537E0ECCE635009BE4BA /* macho_walker.cc */; };
 		F93DE33F0F82C66B00608B94 /* string_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = F92C53820ECCE635009BE4BA /* string_utilities.cc */; };
 		F93DE3410F82C68300608B94 /* exception_handler_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = F93DE3400F82C68300608B94 /* exception_handler_test.cc */; };
 		F945849E0F280E3C009A47BF /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = F945849C0F280E3C009A47BF /* Localizable.strings */; };
-		F9B630A0100FF96B00D0F4AC /* goArrow.png in Resources */ = {isa = PBXBuildFile; fileRef = F9B6309F100FF96B00D0F4AC /* goArrow.png */; };
 		F9C44DB20EF07288003AEBAA /* Controller.m in Sources */ = {isa = PBXBuildFile; fileRef = F9C44DAC0EF07288003AEBAA /* Controller.m */; };
 		F9C44DB30EF07288003AEBAA /* crashduringload in Resources */ = {isa = PBXBuildFile; fileRef = F9C44DAD0EF07288003AEBAA /* crashduringload */; };
 		F9C44DB40EF07288003AEBAA /* crashInMain in Resources */ = {isa = PBXBuildFile; fileRef = F9C44DAE0EF07288003AEBAA /* crashInMain */; };
 		F9C44DB60EF07288003AEBAA /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = F9C44DB00EF07288003AEBAA /* main.m */; };
 		F9C44DB70EF07288003AEBAA /* TestClass.mm in Sources */ = {isa = PBXBuildFile; fileRef = F9C44DB10EF07288003AEBAA /* TestClass.mm */; };
 		F9C44DBC0EF072A0003AEBAA /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = F9C44DB80EF072A0003AEBAA /* InfoPlist.strings */; };
 		F9C44DBD0EF072A0003AEBAA /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = F9C44DBA0EF072A0003AEBAA /* MainMenu.nib */; };
 		F9C44E000EF077CD003AEBAA /* Breakpad.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* Breakpad.framework */; };
@@ -190,65 +186,16 @@
 		};
 		F945858F0F782336009A47BF /* PBXContainerItemProxy */ = {
 			isa = PBXContainerItemProxy;
 			containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
 			proxyType = 1;
 			remoteGlobalIDString = F9C44DA40EF060A8003AEBAA;
 			remoteInfo = BreakpadTest;
 		};
-		F95BB884101F949F00AA053B /* PBXContainerItemProxy */ = {
-			isa = PBXContainerItemProxy;
-			containerPortal = F95BB87C101F949F00AA053B /* crash_report.xcodeproj */;
-			proxyType = 2;
-			remoteGlobalIDString = 8DD76FA10486AA7600D96B5E /* crash_report */;
-			remoteInfo = crash_report;
-		};
-		F95BB891101F94AC00AA053B /* PBXContainerItemProxy */ = {
-			isa = PBXContainerItemProxy;
-			containerPortal = F95BB889101F94AC00AA053B /* dump_syms.xcodeproj */;
-			proxyType = 2;
-			remoteGlobalIDString = 8DD76FA10486AA7600D96B5E /* dump_syms */;
-			remoteInfo = dump_syms;
-		};
-		F95BB89E101F94C000AA053B /* PBXContainerItemProxy */ = {
-			isa = PBXContainerItemProxy;
-			containerPortal = F95BB894101F94C000AA053B /* symupload.xcodeproj */;
-			proxyType = 2;
-			remoteGlobalIDString = 8DD76FA10486AA7600D96B5E /* symupload */;
-			remoteInfo = symupload;
-		};
-		F95BB8A0101F94C000AA053B /* PBXContainerItemProxy */ = {
-			isa = PBXContainerItemProxy;
-			containerPortal = F95BB894101F94C000AA053B /* symupload.xcodeproj */;
-			proxyType = 2;
-			remoteGlobalIDString = 9BD835FB0B0544950055103E /* minidump_upload */;
-			remoteInfo = minidump_upload;
-		};
-		F95BB8B2101F94D300AA053B /* PBXContainerItemProxy */ = {
-			isa = PBXContainerItemProxy;
-			containerPortal = F95BB889101F94AC00AA053B /* dump_syms.xcodeproj */;
-			proxyType = 1;
-			remoteGlobalIDString = 8DD76F960486AA7600D96B5E /* dump_syms */;
-			remoteInfo = dump_syms;
-		};
-		F95BB8B4101F94D300AA053B /* PBXContainerItemProxy */ = {
-			isa = PBXContainerItemProxy;
-			containerPortal = F95BB894101F94C000AA053B /* symupload.xcodeproj */;
-			proxyType = 1;
-			remoteGlobalIDString = 8DD76F960486AA7600D96B5E /* symupload */;
-			remoteInfo = symupload;
-		};
-		F95BB8B6101F94D300AA053B /* PBXContainerItemProxy */ = {
-			isa = PBXContainerItemProxy;
-			containerPortal = F95BB87C101F949F00AA053B /* crash_report.xcodeproj */;
-			proxyType = 1;
-			remoteGlobalIDString = 8DD76F960486AA7600D96B5E /* crash_report */;
-			remoteInfo = crash_report;
-		};
 		F9C44E190EF0790F003AEBAA /* PBXContainerItemProxy */ = {
 			isa = PBXContainerItemProxy;
 			containerPortal = 0867D690FE84028FC02AAC07 /* Project object */;
 			proxyType = 1;
 			remoteGlobalIDString = 8DC2EF4F0486A6940098B216;
 			remoteInfo = Breakpad;
 		};
 		F9C44E960EF09F4B003AEBAA /* PBXContainerItemProxy */ = {
@@ -336,20 +283,16 @@
 		F93803BE0F80820F004D428B /* generator_test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = generator_test; sourceTree = BUILT_PRODUCTS_DIR; };
 		F93803D90F8083D8004D428B /* minidump_generator_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = minidump_generator_test.cc; path = handler/minidump_generator_test.cc; sourceTree = "<group>"; };
 		F93DE2D10F82A67300608B94 /* minidump_file_writer_unittest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = minidump_file_writer_unittest; sourceTree = BUILT_PRODUCTS_DIR; };
 		F93DE2D70F82A70E00608B94 /* minidump_file_writer_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = minidump_file_writer_unittest.cc; path = ../minidump_file_writer_unittest.cc; sourceTree = SOURCE_ROOT; };
 		F93DE32C0F82C55600608B94 /* handler_test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = handler_test; sourceTree = BUILT_PRODUCTS_DIR; };
 		F93DE3400F82C68300608B94 /* exception_handler_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = exception_handler_test.cc; path = handler/exception_handler_test.cc; sourceTree = "<group>"; };
 		F945849D0F280E3C009A47BF /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = sender/English.lproj/Localizable.strings; sourceTree = "<group>"; };
 		F945859D0F78241E009A47BF /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Framework/Info.plist; sourceTree = "<group>"; };
-		F95BB87C101F949F00AA053B /* crash_report.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = crash_report.xcodeproj; path = ../../tools/mac/crash_report/crash_report.xcodeproj; sourceTree = SOURCE_ROOT; };
-		F95BB889101F94AC00AA053B /* dump_syms.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = dump_syms.xcodeproj; path = ../../tools/mac/dump_syms/dump_syms.xcodeproj; sourceTree = SOURCE_ROOT; };
-		F95BB894101F94C000AA053B /* symupload.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = symupload.xcodeproj; path = ../../tools/mac/symupload/symupload.xcodeproj; sourceTree = SOURCE_ROOT; };
-		F9B6309F100FF96B00D0F4AC /* goArrow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = goArrow.png; path = sender/goArrow.png; sourceTree = "<group>"; };
 		F9C44DA50EF060A8003AEBAA /* BreakpadTest.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BreakpadTest.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		F9C44DAC0EF07288003AEBAA /* Controller.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Controller.m; path = testapp/Controller.m; sourceTree = "<group>"; };
 		F9C44DAD0EF07288003AEBAA /* crashduringload */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; name = crashduringload; path = testapp/crashduringload; sourceTree = "<group>"; };
 		F9C44DAE0EF07288003AEBAA /* crashInMain */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; name = crashInMain; path = testapp/crashInMain; sourceTree = "<group>"; };
 		F9C44DAF0EF07288003AEBAA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = testapp/Info.plist; sourceTree = "<group>"; };
 		F9C44DB00EF07288003AEBAA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = testapp/main.m; sourceTree = "<group>"; };
 		F9C44DB10EF07288003AEBAA /* TestClass.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = TestClass.mm; path = testapp/TestClass.mm; sourceTree = "<group>"; };
 		F9C44DB90EF072A0003AEBAA /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = testapp/English.lproj/InfoPlist.strings; sourceTree = "<group>"; };
@@ -456,17 +399,16 @@
 				F93DE32C0F82C55600608B94 /* handler_test */,
 			);
 			name = Products;
 			sourceTree = "<group>";
 		};
 		0867D691FE84028FC02AAC07 /* Breakpad */ = {
 			isa = PBXGroup;
 			children = (
-				F95BB8A3101F94C300AA053B /* Tools */,
 				32DBCF5E0370ADEE00C91783 /* Breakpad_Prefix.pch */,
 				F92C538D0ECCE6F2009BE4BA /* client */,
 				F92C53600ECCE3D6009BE4BA /* common */,
 				0867D69AFE84028FC02AAC07 /* Frameworks */,
 				034768DFFF38A50411DB9C8B /* Products */,
 				F9C77DDB0F7DD5CF0045F7DB /* UnitTests-Info.plist */,
 			);
 			name = Breakpad;
@@ -588,63 +530,27 @@
 				F92C55CF0ECD0064009BE4BA /* Breakpad.mm */,
 			);
 			name = Framework;
 			sourceTree = "<group>";
 		};
 		F92C56A60ECE04B6009BE4BA /* sender */ = {
 			isa = PBXGroup;
 			children = (
-				F9B6309F100FF96B00D0F4AC /* goArrow.png */,
 				F92C56A70ECE04C5009BE4BA /* crash_report_sender.h */,
 				F92C56A80ECE04C5009BE4BA /* crash_report_sender.m */,
 				F945849C0F280E3C009A47BF /* Localizable.strings */,
 				33880C7E0F9E097100817F82 /* InfoPlist.strings */,
 				3329D4EC0FA16D820007BBC5 /* Breakpad.nib */,
 				4084699C0F5D9CF900FDCA37 /* crash_report_sender.icns */,
 				F92C56A20ECE04A7009BE4BA /* crash_report_sender-Info.plist */,
 			);
 			name = sender;
 			sourceTree = "<group>";
 		};
-		F95BB87D101F949F00AA053B /* Products */ = {
-			isa = PBXGroup;
-			children = (
-				F95BB885101F949F00AA053B /* crash_report */,
-			);
-			name = Products;
-			sourceTree = "<group>";
-		};
-		F95BB88A101F94AC00AA053B /* Products */ = {
-			isa = PBXGroup;
-			children = (
-				F95BB892101F94AC00AA053B /* dump_syms */,
-			);
-			name = Products;
-			sourceTree = "<group>";
-		};
-		F95BB895101F94C000AA053B /* Products */ = {
-			isa = PBXGroup;
-			children = (
-				F95BB89F101F94C000AA053B /* symupload */,
-				F95BB8A1101F94C000AA053B /* minidump_upload */,
-			);
-			name = Products;
-			sourceTree = "<group>";
-		};
-		F95BB8A3101F94C300AA053B /* Tools */ = {
-			isa = PBXGroup;
-			children = (
-				F95BB894101F94C000AA053B /* symupload.xcodeproj */,
-				F95BB889101F94AC00AA053B /* dump_syms.xcodeproj */,
-				F95BB87C101F949F00AA053B /* crash_report.xcodeproj */,
-			);
-			name = Tools;
-			sourceTree = "<group>";
-		};
 		F9C44DAB0EF0726F003AEBAA /* testapp */ = {
 			isa = PBXGroup;
 			children = (
 				F9C44DBF0EF0778F003AEBAA /* Controller.h */,
 				F9C44DC00EF0778F003AEBAA /* TestClass.h */,
 				F9C44DB80EF072A0003AEBAA /* InfoPlist.strings */,
 				F9C44DBA0EF072A0003AEBAA /* MainMenu.nib */,
 				F9C44DAC0EF07288003AEBAA /* Controller.m */,
@@ -867,77 +773,32 @@
 		0867D690FE84028FC02AAC07 /* Project object */ = {
 			isa = PBXProject;
 			buildConfigurationList = 1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "Breakpad" */;
 			compatibilityVersion = "Xcode 2.4";
 			hasScannedForEncodings = 1;
 			mainGroup = 0867D691FE84028FC02AAC07 /* Breakpad */;
 			productRefGroup = 034768DFFF38A50411DB9C8B /* Products */;
 			projectDirPath = "";
-			projectReferences = (
-				{
-					ProductGroup = F95BB87D101F949F00AA053B /* Products */;
-					ProjectRef = F95BB87C101F949F00AA053B /* crash_report.xcodeproj */;
-				},
-				{
-					ProductGroup = F95BB88A101F94AC00AA053B /* Products */;
-					ProjectRef = F95BB889101F94AC00AA053B /* dump_syms.xcodeproj */;
-				},
-				{
-					ProductGroup = F95BB895101F94C000AA053B /* Products */;
-					ProjectRef = F95BB894101F94C000AA053B /* symupload.xcodeproj */;
-				},
-			);
 			projectRoot = "";
 			targets = (
 				8DC2EF4F0486A6940098B216 /* Breakpad */,
 				F92C53530ECCE349009BE4BA /* Inspector */,
 				F92C563B0ECD10B3009BE4BA /* breakpadUtilities */,
 				F92C569F0ECE04A7009BE4BA /* crash_report_sender */,
 				F9C44DA40EF060A8003AEBAA /* BreakpadTest */,
 				F94585840F782326009A47BF /* All */,
 				F9C77DD90F7DD5CF0045F7DB /* UnitTests */,
 				F93803BD0F80820F004D428B /* generator_test */,
 				F93DE2D00F82A67300608B94 /* minidump_file_writer_unittest */,
 				F93DE32B0F82C55600608B94 /* handler_test */,
 			);
 		};
 /* End PBXProject section */
 
-/* Begin PBXReferenceProxy section */
-		F95BB885101F949F00AA053B /* crash_report */ = {
-			isa = PBXReferenceProxy;
-			fileType = "compiled.mach-o.executable";
-			path = crash_report;
-			remoteRef = F95BB884101F949F00AA053B /* PBXContainerItemProxy */;
-			sourceTree = BUILT_PRODUCTS_DIR;
-		};
-		F95BB892101F94AC00AA053B /* dump_syms */ = {
-			isa = PBXReferenceProxy;
-			fileType = "compiled.mach-o.executable";
-			path = dump_syms;
-			remoteRef = F95BB891101F94AC00AA053B /* PBXContainerItemProxy */;
-			sourceTree = BUILT_PRODUCTS_DIR;
-		};
-		F95BB89F101F94C000AA053B /* symupload */ = {
-			isa = PBXReferenceProxy;
-			fileType = "compiled.mach-o.executable";
-			path = symupload;
-			remoteRef = F95BB89E101F94C000AA053B /* PBXContainerItemProxy */;
-			sourceTree = BUILT_PRODUCTS_DIR;
-		};
-		F95BB8A1101F94C000AA053B /* minidump_upload */ = {
-			isa = PBXReferenceProxy;
-			fileType = "compiled.mach-o.executable";
-			path = minidump_upload;
-			remoteRef = F95BB8A0101F94C000AA053B /* PBXContainerItemProxy */;
-			sourceTree = BUILT_PRODUCTS_DIR;
-		};
-/* End PBXReferenceProxy section */
-
 /* Begin PBXResourcesBuildPhase section */
 		8DC2EF520486A6940098B216 /* Resources */ = {
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 				F9C44E980EF09F56003AEBAA /* crash_report_sender.app in Resources */,
 				F92C568A0ECD15F9009BE4BA /* Inspector in Resources */,
 				F92C56650ECD1185009BE4BA /* breakpadUtilities.dylib in Resources */,
@@ -947,17 +808,16 @@
 		F92C569C0ECE04A7009BE4BA /* Resources */ = {
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 				F945849E0F280E3C009A47BF /* Localizable.strings in Resources */,
 				4084699D0F5D9CF900FDCA37 /* crash_report_sender.icns in Resources */,
 				33880C800F9E097100817F82 /* InfoPlist.strings in Resources */,
 				3329D4ED0FA16D820007BBC5 /* Breakpad.nib in Resources */,
-				F9B630A0100FF96B00D0F4AC /* goArrow.png in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 		F9C44DA10EF060A8003AEBAA /* Resources */ = {
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 				F9C44DB30EF07288003AEBAA /* crashduringload in Resources */,
@@ -1198,31 +1058,16 @@
 			target = F92C569F0ECE04A7009BE4BA /* crash_report_sender */;
 			targetProxy = F945858D0F782333009A47BF /* PBXContainerItemProxy */;
 		};
 		F94585900F782336009A47BF /* PBXTargetDependency */ = {
 			isa = PBXTargetDependency;
 			target = F9C44DA40EF060A8003AEBAA /* BreakpadTest */;
 			targetProxy = F945858F0F782336009A47BF /* PBXContainerItemProxy */;
 		};
-		F95BB8B3101F94D300AA053B /* PBXTargetDependency */ = {
-			isa = PBXTargetDependency;
-			name = dump_syms;
-			targetProxy = F95BB8B2101F94D300AA053B /* PBXContainerItemProxy */;
-		};
-		F95BB8B5101F94D300AA053B /* PBXTargetDependency */ = {
-			isa = PBXTargetDependency;
-			name = symupload;
-			targetProxy = F95BB8B4101F94D300AA053B /* PBXContainerItemProxy */;
-		};
-		F95BB8B7101F94D300AA053B /* PBXTargetDependency */ = {
-			isa = PBXTargetDependency;
-			name = crash_report;
-			targetProxy = F95BB8B6101F94D300AA053B /* PBXContainerItemProxy */;
-		};
 		F9C44E1A0EF0790F003AEBAA /* PBXTargetDependency */ = {
 			isa = PBXTargetDependency;
 			target = 8DC2EF4F0486A6940098B216 /* Breakpad */;
 			targetProxy = F9C44E190EF0790F003AEBAA /* PBXContainerItemProxy */;
 		};
 		F9C44E970EF09F4B003AEBAA /* PBXTargetDependency */ = {
 			isa = PBXTargetDependency;
 			target = F92C569F0ECE04A7009BE4BA /* crash_report_sender */;
--- a/toolkit/crashreporter/google-breakpad/src/client/mac/Framework/Breakpad.h
+++ b/toolkit/crashreporter/google-breakpad/src/client/mac/Framework/Breakpad.h
@@ -84,17 +84,16 @@ extern "C" {
 #define BREAKPAD_SERVER_PARAMETER_DICT "BreakpadServerParameters"
 
 // The keys below are NOT user supplied, and are used internally.
 #define BREAKPAD_PROCESS_START_TIME       "BreakpadProcStartTime"
 #define BREAKPAD_PROCESS_UP_TIME          "BreakpadProcessUpTime"
 #define BREAKPAD_PROCESS_CRASH_TIME       "BreakpadProcessCrashTime"
 #define BREAKPAD_LOGFILE_KEY_PREFIX       "BreakpadAppLogFile"
 #define BREAKPAD_SERVER_PARAMETER_PREFIX  "BreakpadServerParameterPrefix_"
-#define BREAKPAD_ON_DEMAND                "BreakpadOnDemand"
 
 // Optional user-defined function to dec to decide if we should handle
 // this crash or forward it along.
 // Return true if you want Breakpad to handle it.
 // Return false if you want Breakpad to skip it
 // The exception handler always returns false, as if SEND_AND_EXIT were false
 // (which means the next exception handler will take the exception)
 typedef bool (*BreakpadFilterCallback)(int exception_type,
@@ -211,17 +210,17 @@ typedef bool (*BreakpadFilterCallback)(i
 // It's easiest to use Breakpad via the Framework, but if you're compiling the
 // code in directly, BREAKPAD_INSPECTOR_LOCATION and
 // BREAKPAD_REPORTER_EXE_LOCATION allow you to specify custom paths
 // to the helper executables.
 //
 //=============================================================================
 // The following are NOT user-supplied but are documented here for
 // completeness.  They are calculated by Breakpad during initialization &
-// crash-dump generation, or entered in by the user.
+// crash-dump generation.
 //
 // BREAKPAD_PROCESS_START_TIME       The time the process started.
 //
 // BREAKPAD_PROCESS_CRASH_TIME       The time the process crashed.
 //
 // BREAKPAD_PROCESS_UP_TIME          The total time the process has been
 //                                   running.  This parameter is not set
 //                                   until the crash-dump-generation phase.
@@ -238,22 +237,16 @@ typedef bool (*BreakpadFilterCallback)(i
 //                                   parameters meant to be uploaded
 //                                   to the server.  This string is
 //                                   used internally by Breakpad to
 //                                   prefix user-supplied parameter
 //                                   names so those can be sent to the
 //                                   server without leaking Breakpad's
 //                                   internal values.
 //
-// BREAKPAD_ON_DEMAND                Used internally to indicate to the
-//                                   Reporter that we're sending on-demand,
-//                                   not as result of a crash.
-//
-// BREAKPAD_COMMENTS                 The text the user provided as comments.
-//                                   Only used in crash_report_sender.
 
 // Returns a new BreakpadRef object on success, NULL otherwise.
 BreakpadRef BreakpadCreate(NSDictionary *parameters);
 
 // Uninstall and release the data associated with |ref|.
 void BreakpadRelease(BreakpadRef ref);
 
 // Clients may set an optional callback which gets called when a crash
@@ -288,17 +281,17 @@ void BreakpadSetKeyValue(BreakpadRef ref
 NSString *BreakpadKeyValue(BreakpadRef ref, NSString *key);
 void BreakpadRemoveKeyValue(BreakpadRef ref, NSString *key);
 
 // You can use this method to specify parameters that will be uploaded
 // to the crash server.  They will be automatically encoded as
 // necessary.  Note that as mentioned above there are limits on both
 // the number of keys and their length.
 void BreakpadAddUploadParameter(BreakpadRef ref, NSString *key,
-                                NSString *value);
+				NSString *value);
 
 // This method will remove a previously-added parameter from the
 // upload parameter set.
 void BreakpadRemoveUploadParameter(BreakpadRef ref, NSString *key);
 
 // Add a log file for Breakpad to read and send upon crash dump
 void BreakpadAddLogFile(BreakpadRef ref, NSString *logPathname);
 
--- a/toolkit/crashreporter/google-breakpad/src/client/mac/Framework/Breakpad.mm
+++ b/toolkit/crashreporter/google-breakpad/src/client/mac/Framework/Breakpad.mm
@@ -404,16 +404,17 @@ bool Breakpad::ExtractParameters(NSDicti
   NSString *interval = [parameters objectForKey:@BREAKPAD_REPORT_INTERVAL];
   NSString *inspectorPathString =
                 [parameters objectForKey:@BREAKPAD_INSPECTOR_LOCATION];
   NSString *reporterPathString =
                 [parameters objectForKey:@BREAKPAD_REPORTER_EXE_LOCATION];
   NSString *timeout = [parameters objectForKey:@BREAKPAD_CONFIRM_TIMEOUT];
   NSArray  *logFilePaths = [parameters objectForKey:@BREAKPAD_LOGFILES];
   NSString *logFileTailSize = [parameters objectForKey:@BREAKPAD_LOGFILE_UPLOAD_SIZE];
+  NSString *reportEmail = [parameters objectForKey:@BREAKPAD_EMAIL];
   NSString *requestUserText =
                 [parameters objectForKey:@BREAKPAD_REQUEST_COMMENTS];
   NSString *requestEmail = [parameters objectForKey:@BREAKPAD_REQUEST_EMAIL];
   NSString *vendor =
     [parameters objectForKey:@BREAKPAD_VENDOR];
   NSString *dumpSubdirectory =
     [parameters objectForKey:@BREAKPAD_DUMP_DIRECTORY];
 
@@ -445,17 +446,17 @@ bool Breakpad::ExtractParameters(NSDicti
 
   if (!logFileTailSize)
     logFileTailSize = @"200000";
 
   if (!vendor) {
     vendor = @"Vendor not specified";
   }
 
-  // Normalize the values.
+  // Normalize the values
   if (skipConfirm) {
     skipConfirm = [skipConfirm uppercaseString];
 
     if ([skipConfirm isEqualToString:@"YES"] ||
         [skipConfirm isEqualToString:@"TRUE"] ||
         [skipConfirm isEqualToString:@"1"])
       skipConfirm = @"YES";
     else
@@ -498,30 +499,30 @@ bool Breakpad::ExtractParameters(NSDicti
   }
 
   // Find Inspector.
   if (!inspectorPathString) {
     inspectorPathString =
         [resourcePath stringByAppendingPathComponent:@"Inspector"];
   }
 
-  // Verify that there is an Inspector tool.
+  // Verify that there is an Inspector tool
   if (![[NSFileManager defaultManager] fileExistsAtPath:inspectorPathString]) {
     DEBUGLOG(stderr, "Cannot find Inspector tool\n");
     return false;
   }
 
   // Find Reporter.
   if (!reporterPathString) {
     reporterPathString =
       [resourcePath stringByAppendingPathComponent:@"crash_report_sender.app"];
     reporterPathString = [[NSBundle bundleWithPath:reporterPathString] executablePath];
   }
 
-  // Verify that there is a Reporter application.
+  // Verify that there is a Reporter application
   if (![[NSFileManager defaultManager]
              fileExistsAtPath:reporterPathString]) {
     DEBUGLOG(stderr, "Cannot find Reporter tool\n");
     return false;
   }
 
   if (!dumpSubdirectory) {
     dumpSubdirectory = @"";
@@ -582,16 +583,21 @@ bool Breakpad::ExtractParameters(NSDicti
     for(unsigned int i = 0; i < [logFilePaths count]; i++) {
       sprintf(logFileKey,"%s%d", BREAKPAD_LOGFILE_KEY_PREFIX, i);
       dictionary.SetKeyValue(logFileKey,
                              [[logFilePaths objectAtIndex:i]
                                fileSystemRepresentation]);
     }
   }
 
+  if (reportEmail) {
+    dictionary.SetKeyValue(BREAKPAD_EMAIL,
+                           [reportEmail UTF8String]);
+  }
+
   if (serverParameters) {
     // For each key-value pair, call BreakpadAddUploadParameter()
     NSEnumerator *keyEnumerator = [serverParameters keyEnumerator];
     NSString *aParameter;
     while (aParameter = [keyEnumerator nextObject]) {
       BreakpadAddUploadParameter(this, aParameter,
 				 [serverParameters objectForKey:aParameter]);
     }
@@ -622,19 +628,17 @@ void        Breakpad::RemoveKeyValue(NSS
   if (!config_params_ || !key)
     return;
 
   config_params_->RemoveKey([key UTF8String]);
 }
 
 //=============================================================================
 void        Breakpad::GenerateAndSendReport() {
-  config_params_->SetKeyValue(BREAKPAD_ON_DEMAND, "YES");
   HandleException(0, 0, 0, mach_thread_self()); 
-  config_params_->SetKeyValue(BREAKPAD_ON_DEMAND, "NO");
 }
 
 //=============================================================================
 bool Breakpad::HandleException(int           exception_type,
                                int           exception_code,
                                int           exception_subcode,
                                mach_port_t   crashing_thread) {
   DEBUGLOG(stderr, "Breakpad: an exception occurred\n");
@@ -742,69 +746,75 @@ BreakpadRef BreakpadCreate(NSDictionary 
       new ProtectedMemoryAllocator(sizeof(ProtectedMemoryAllocator) * 2);
 
     gKeyValueAllocator =
       new (gMasterAllocator->Allocate(sizeof(ProtectedMemoryAllocator)))
         ProtectedMemoryAllocator(sizeof(SimpleStringDictionary));
 
     // Create a mutex for use in accessing the SimpleStringDictionary
     int mutexResult = pthread_mutex_init(&gDictionaryMutex, NULL);
-    if (mutexResult == 0) {
+    if (mutexResult != 0) {
+      throw mutexResult;   // caught down below
+    }
 
-      // With the current compiler, gBreakpadAllocator is allocating 1444 bytes.
-      // Let's round up to the nearest page size.
-      //
-      int breakpad_pool_size = 4096;
+    // With the current compiler, gBreakpadAllocator is allocating 1444 bytes.
+    // Let's round up to the nearest page size.
+    //
+    int breakpad_pool_size = 4096;
 
-      /*
-       sizeof(Breakpad)
-       + sizeof(google_breakpad::ExceptionHandler)
-       + sizeof( STUFF ALLOCATED INSIDE ExceptionHandler )
-       */
+    /*
+     sizeof(Breakpad)
+     + sizeof(google_breakpad::ExceptionHandler)
+     + sizeof( STUFF ALLOCATED INSIDE ExceptionHandler )
+     */
 
-      gBreakpadAllocator =
-        new (gMasterAllocator->Allocate(sizeof(ProtectedMemoryAllocator)))
-          ProtectedMemoryAllocator(breakpad_pool_size);
+    gBreakpadAllocator =
+      new (gMasterAllocator->Allocate(sizeof(ProtectedMemoryAllocator)))
+        ProtectedMemoryAllocator(breakpad_pool_size);
 
-      // Stack-based autorelease pool for Breakpad::Create() obj-c code.
-      NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-      Breakpad *breakpad = Breakpad::Create(parameters);
+    // Stack-based autorelease pool for Breakpad::Create() obj-c code.
+    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+    Breakpad *breakpad = Breakpad::Create(parameters);
 
-      if (breakpad) {
-        // Make read-only to protect against memory smashers
-        gMasterAllocator->Protect();
-        gKeyValueAllocator->Protect();
-        gBreakpadAllocator->Protect();
-        // Can uncomment this line to figure out how much space was actually
-        // allocated using this allocator
-        //     printf("gBreakpadAllocator allocated size = %d\n",
-        //         gBreakpadAllocator->GetAllocatedSize() );
-        [pool release];
-        return (BreakpadRef)breakpad;
-      }
+    if (breakpad) {
+      // Make read-only to protect against memory smashers
+      gMasterAllocator->Protect();
+      gKeyValueAllocator->Protect();
+      gBreakpadAllocator->Protect();
+    } else {
+      [pool release];
+#ifdef __EXCEPTIONS
+      throw(-1);
+#else
+      return NULL;
+#endif
+    }
 
-      [pool release];
-    }
+    // Can uncomment this line to figure out how much space was actually
+    // allocated using this allocator
+    //     printf("gBreakpadAllocator allocated size = %d\n",
+    //         gBreakpadAllocator->GetAllocatedSize() );
+
+    [pool release];
+    return (BreakpadRef)breakpad;
   } catch(...) {    // don't let exceptions leave this C API
-    fprintf(stderr, "BreakpadCreate() : error\n");
-  }
-
-  if (gKeyValueAllocator) {
-    gKeyValueAllocator->~ProtectedMemoryAllocator();
-    gKeyValueAllocator = NULL;
-  }
+    if (gKeyValueAllocator) {
+      gKeyValueAllocator->~ProtectedMemoryAllocator();
+      gKeyValueAllocator = NULL;
+    }
 
-  if (gBreakpadAllocator) {
-    gBreakpadAllocator->~ProtectedMemoryAllocator();
-    gBreakpadAllocator = NULL;
+    if (gBreakpadAllocator) {
+      gBreakpadAllocator->~ProtectedMemoryAllocator();
+      gBreakpadAllocator = NULL;
+    }
+
+    delete gMasterAllocator;
+    gMasterAllocator = NULL;
   }
 
-  delete gMasterAllocator;
-  gMasterAllocator = NULL;
-
   return NULL;
 }
 
 //=============================================================================
 void BreakpadRelease(BreakpadRef ref) {
   try {
     Breakpad *breakpad = (Breakpad *)ref;
 
--- a/toolkit/crashreporter/google-breakpad/src/client/mac/crash_generation/Inspector.mm
+++ b/toolkit/crashreporter/google-breakpad/src/client/mac/crash_generation/Inspector.mm
@@ -314,52 +314,33 @@ kern_return_t Inspector::ReadMessages() 
     printf("exception_subcode = %d\n", exception_subcode_);
     printf("remote_task = %d\n", remote_task_);
     printf("crashing_thread = %d\n", crashing_thread_);
     printf("handler_thread = %d\n", handler_thread_);
     printf("ack_port_ = %d\n", ack_port_);
     printf("parameter count = %d\n", info.parameter_count);
 #endif
 
-    // In certain situations where multiple crash requests come
-    // through quickly, we can end up with the mach IPC messages not
-    // coming through correctly.  Since we don't know what parameters
-    // we've missed, we can't do much besides abort the crash dump
-    // situation in this case.
-    unsigned int parameters_read = 0;
     // The initial message contains the number of key value pairs that
     // we are expected to read.
     // Read each key/value pair, one mach message per key/value pair.
     for (unsigned int i = 0; i < info.parameter_count; ++i) {
       MachReceiveMessage message;
       result = receive_port.WaitForMessage(&message, 1000);
 
       if(result == KERN_SUCCESS) {
         KeyValueMessageData &key_value_data =
           (KeyValueMessageData&)*message.GetData();
-        // If we get a blank key, make sure we don't increment the
-        // parameter count; in some cases (notably on-demand generation
-        // many times in a short period of time) caused the Mach IPC
-        // messages to not come through correctly.
-        if (strlen(key_value_data.key) == 0) {
-          continue;
-        }
-        parameters_read++;
 
         config_params_.SetKeyValue(key_value_data.key, key_value_data.value);
       } else {
         PRINT_MACH_RESULT(result, "Inspector: key/value message");
         break;
       }
     }
-    if (parameters_read != info.parameter_count) {
-      DEBUGLOG(stderr, "Only read %d parameters instead of %d, aborting crash "
-               "dump generation.", parameters_read, info.parameter_count);
-      return KERN_FAILURE;
-    }
   }
 
   return result;
 }
 
 //=============================================================================
 // Sets keys in the parameters dictionary that are specific to process uptime.
 // The two we set are process up time, and process crash time.
@@ -393,17 +374,17 @@ bool Inspector::InspectTask() {
   NSString *minidumpDir;
 
   const char *minidumpDirectory =
     config_params_.GetValueForKey(BREAKPAD_DUMP_DIRECTORY);
 
   SetCrashTimeParameters();
   // If the client app has not specified a minidump directory,
   // use a default of Library/<kDefaultLibrarySubdirectory>/<Product Name>
-  if (!minidumpDirectory || 0 == strlen(minidumpDirectory)) {
+  if (0 == strlen(minidumpDirectory)) {
     NSArray *libraryDirectories =
       NSSearchPathForDirectoriesInDomains(NSLibraryDirectory,
                                           NSUserDomainMask,
                                           YES);
 
     NSString *applicationSupportDirectory =
         [libraryDirectories objectAtIndex:0];
     NSString *library_subdirectory = [NSString 
--- a/toolkit/crashreporter/google-breakpad/src/client/mac/handler/exception_handler.cc
+++ b/toolkit/crashreporter/google-breakpad/src/client/mac/handler/exception_handler.cc
@@ -87,25 +87,22 @@ exception_mask_t s_exception_mask = EXC_
 EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC | EXC_MASK_BREAKPOINT;
 
 extern "C"
 {
   // Forward declarations for functions that need "C" style compilation
   boolean_t exc_server(mach_msg_header_t *request,
                        mach_msg_header_t *reply);
 
-  // This symbol must be visible to dlsym() - see
-  // http://code.google.com/p/google-breakpad/issues/detail?id=345 for details.
   kern_return_t catch_exception_raise(mach_port_t target_port,
                                       mach_port_t failed_thread,
                                       mach_port_t task,
                                       exception_type_t exception,
                                       exception_data_t code,
-                                      mach_msg_type_number_t code_count)
-      __attribute__((visibility("default")));
+                                      mach_msg_type_number_t code_count);
 
   kern_return_t ForwardException(mach_port_t task,
                                  mach_port_t failed_thread,
                                  exception_type_t exception,
                                  exception_data_t code,
                                  mach_msg_type_number_t code_count);
 
   kern_return_t exception_raise(mach_port_t target_port,
@@ -433,19 +430,16 @@ kern_return_t ForwardException(mach_port
 }
 
 // Callback from exc_server()
 kern_return_t catch_exception_raise(mach_port_t port, mach_port_t failed_thread,
                                     mach_port_t task,
                                     exception_type_t exception,
                                     exception_data_t code,
                                     mach_msg_type_number_t code_count) {
-  if (task != mach_task_self()) {
-    return KERN_FAILURE;
-  }
   return ForwardException(task, failed_thread, exception, code, code_count);
 }
 
 // static
 void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
   ExceptionHandler *self =
     reinterpret_cast<ExceptionHandler *>(exception_handler_class);
   ExceptionMessage receive;
--- a/toolkit/crashreporter/google-breakpad/src/client/mac/handler/minidump_generator.cc
+++ b/toolkit/crashreporter/google-breakpad/src/client/mac/handler/minidump_generator.cc
@@ -632,38 +632,23 @@ bool MinidumpGenerator::WriteSystemInfoS
       int unused, unused2;
       // get vendor id
       cpuid(0, unused, info_ptr->cpu.x86_cpu_info.vendor_id[0],
             info_ptr->cpu.x86_cpu_info.vendor_id[2],
             info_ptr->cpu.x86_cpu_info.vendor_id[1]);
       // get version and feature info
       cpuid(1, info_ptr->cpu.x86_cpu_info.version_information, unused, unused2,
             info_ptr->cpu.x86_cpu_info.feature_information);
-
       // family
       info_ptr->processor_level =
         (info_ptr->cpu.x86_cpu_info.version_information & 0xF00) >> 8;
       // 0xMMSS (Model, Stepping)
       info_ptr->processor_revision =
         (info_ptr->cpu.x86_cpu_info.version_information & 0xF) |
         ((info_ptr->cpu.x86_cpu_info.version_information & 0xF0) << 4);
-
-      // decode extended model info
-      if (info_ptr->processor_level == 0xF ||
-          info_ptr->processor_level == 0x6) {
-        info_ptr->processor_revision |=
-          ((info_ptr->cpu.x86_cpu_info.version_information & 0xF0000) >> 4);
-      }
-
-      // decode extended family info
-      if (info_ptr->processor_level == 0xF) {
-        info_ptr->processor_level +=
-          ((info_ptr->cpu.x86_cpu_info.version_information & 0xFF00000) >> 20);
-      }
-
 #endif // __i386__
       break;
     default:
       info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_UNKNOWN;
       break;
   }
 
   info_ptr->number_of_processors = number_of_processors;
--- a/toolkit/crashreporter/google-breakpad/src/client/mac/handler/minidump_generator.h
+++ b/toolkit/crashreporter/google-breakpad/src/client/mac/handler/minidump_generator.h
@@ -63,17 +63,17 @@ typedef ppc_thread_state64_t breakpad_th
 typedef MDRawContextPPC64 MinidumpContext;
 #elif TARGET_CPU_PPC
 typedef ppc_thread_state_t breakpad_thread_state_t;
 typedef MDRawContextPPC MinidumpContext;
 #endif
 
 // Use the REGISTER_FROM_THREADSTATE to access a register name from the
 // breakpad_thread_state_t structure.
-#if __DARWIN_UNIX03 || TARGET_CPU_X86_64 || TARGET_CPU_PPC64
+#if __DARWIN_UNIX03 || !TARGET_CPU_X86 || TARGET_CPU_X86_64
 // In The 10.5 SDK Headers Apple prepended __ to the variable names in the
 // i386_thread_state_t structure.  There's no good way to tell what version of
 // the SDK we're compiling against so we just toggle on the same preprocessor
 // symbol Apple's headers use.
 #define REGISTER_FROM_THREADSTATE(a, b) ((a)->__ ## b)
 #else
 #define REGISTER_FROM_THREADSTATE(a, b) (a->b)
 #endif
--- a/toolkit/crashreporter/google-breakpad/src/client/mac/sender/Breakpad.nib/classes.nib
+++ b/toolkit/crashreporter/google-breakpad/src/client/mac/sender/Breakpad.nib/classes.nib
@@ -1,23 +1,15 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
 	<key>IBClasses</key>
 	<array>
 		<dict>
-			<key>CLASS</key>
-			<string>LengthLimitingTextField</string>
-			<key>LANGUAGE</key>
-			<string>ObjC</string>
-			<key>SUPERCLASS</key>
-			<string>NSTextField</string>
-		</dict>
-		<dict>
 			<key>ACTIONS</key>
 			<dict>
 				<key>cancel</key>
 				<string>id</string>
 				<key>sendReport</key>
 				<string>id</string>
 				<key>showPrivacyPolicy</key>
 				<string>id</string>
@@ -29,24 +21,20 @@
 			<key>OUTLETS</key>
 			<dict>
 				<key>alertWindow_</key>
 				<string>NSWindow</string>
 				<key>cancelButton_</key>
 				<string>NSButton</string>
 				<key>commentMessage_</key>
 				<string>NSTextField</string>
-				<key>commentsEntryField_</key>
-				<string>LengthLimitingTextField</string>
-				<key>countdownLabel_</key>
-				<string>NSTextField</string>
 				<key>dialogTitle_</key>
 				<string>NSTextField</string>
 				<key>emailEntryField_</key>
-				<string>LengthLimitingTextField</string>
+				<string>NSView</string>
 				<key>emailLabel_</key>
 				<string>NSTextField</string>
 				<key>emailMessage_</key>
 				<string>NSTextField</string>
 				<key>emailSectionBox_</key>
 				<string>NSBox</string>
 				<key>headerBox_</key>
 				<string>NSBox</string>
--- a/toolkit/crashreporter/google-breakpad/src/client/mac/sender/Breakpad.nib/info.nib
+++ b/toolkit/crashreporter/google-breakpad/src/client/mac/sender/Breakpad.nib/info.nib
@@ -1,20 +1,20 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 <plist version="1.0">
 <dict>
 	<key>IBFramework Version</key>
-	<string>676</string>
+	<string>672</string>
 	<key>IBLastKnownRelativeProjectPath</key>
 	<string>../Breakpad.xcodeproj</string>
 	<key>IBOldestOS</key>
 	<integer>5</integer>
 	<key>IBOpenObjects</key>
 	<array>
-		<integer>132</integer>
+		<integer>2</integer>
 	</array>
 	<key>IBSystem Version</key>
-	<string>9J61</string>
+	<string>9G55</string>
 	<key>targetFramework</key>
 	<string>IBCocoaFramework</string>
 </dict>
 </plist>
index e370206c166426f1ec3ff2a9578fe891ac3a5190..d0cbd3f24e2a9e3bb76f28d9c4aadec5398cdac7
GIT binary patch
literal 13747
zc%1Ee2~<<p+UVZ<oM1u{a*`mBkl`e8Bu5H}h(oR5RIB0uqD*3dBcz4|Gk{2`n^x_3
zZELNy&U39=t+usxZng7tZ-?93TI=n#gLd|Mo!YAZcTNI=`nuk~-u>5mZ>_QxoMC_a
zo5y{qYVdhO;f#!r5Jm(sh(!t%hg2wjdXGji81e@EMLoiShLRqhV0E1rUQO>2sJc<C
z4u=c~FIx9L>V}jRWAoFaFKawu55<+7uAp$7*eurM#WwBIV>MDE4a!6VP!1Z3u0?rh
z6sknEs0p>f$}MOKx*x4XtI%5X2-=3WqsP!5^c32Mo<%RBSJ7+eE%aCPEjotk(Q$MF
zoy8i=;S|hc2TsS=;A}hq=i+PeFgyldk0;|PxD1!$20RBh;ud@pZp9SeiWlL<_#XTq
zUXEAc)p#vlhu7nW@m9P8@4|cVGx%BjCVmUQjX%U6;m`45`~^Oaf5iXBzY>P9L`^iL
zJ4qsT!V@>ShUAbTWCR&W#*+zTGMPduNgeT$8_8_qBlW~j0;HL=lAB2zSwI$&MdWU>
znA}6|CCkWiq$UrM6=Wq@Mb?saWHZ@9wv!!XH`zm;BKyem<OOnoyh2_l?~r%N2joL?
zkbFwMAV<ho<ZJRB`JVhjPLR{&HwH17iDSAk8b-?)7$ak6c*emvnZ8UK<7U#COlA->
zm>I(4G1Hkcrkt6<M3_67wahwZJ+pz?$ZTRZGh3L4nXSwt%r<5_vx9k**~#o;9%FVh
zPcTn0->}`;BsLlCWK&oZ`ieEPsjLMZWv#4@wX;0yV4bXs?ZNhBd$GOQK5Sn$jdimE
z+QRn3FR|(DHEaf($!4+r*=%+Io5K!dbJ;=cV0H*Ql)aA4XGcx#;g9%yM>qr0q6DNv
z9MU5LGNMG(9VMY;l!8pij8c&WS&<Fd5sw_miCm}$>WO-x-lz}ii_(xA38)`RN7tZ?
z;)22{fk3#pN43ur3RM&oPK>%M_+v<R%n{OiF;wjFMMQXGDk#jWt`<WfZ<W{Q4L48p
z*2LCe?}&ik51SzhLS+So1)h3Q#sl}GgYeK42+pqPz$mSh0zE(=-B!dl{I3Yba0h}C
z<miAuJi+7l)QZ7Mjw>iE_5zqsoaXh{1e&6J$K+^7mwXkzC9)+zR-7A#$MPsI(G8Te
z;duH2J=lg-R7np|1^tA6N?&Qi-6*1QbblLGa+~O9AAl9IP=AzN7L!YofwGjDK1FN@
z1jAzR12hojqCsfz^r(u(P-*nW50D$sU^HX~Y>kA%f%+)R)7yCm$;Rf72vi3=9omz~
z4MW$V;h?x!4hhk2>!LLB(TI&`1R9BkfG86pVGn4ePz+BkD1^V!ouknhI%*e}jIKvx
z(G6%E8jmKR0yGg#LX*)HREUbuR8)+nq3Ngum7+3Kjw;X$s-kv!H(gBcrAz2ix{N+V
zSJKsVEnQDH(#`Z?x|Kdcx6?=IF1njO^AS**i9DzZRihek!C7Fhkzy$9^?M}G0PzX~
zkzlnrt)Otcr%Lou8;z%gS`VT+*y%+#qS?p?dCQLir~%DEK@>t^6hQ&mtdg;&h@pmn
zzeWsBi#ZlJ@d(l91JsS9eV$s$sH6On_%-k<>J(s~!bpP{Z1jpvR81{ZLlgAasiIn{
z{zRrc7w9(2bmyTKbQ5YtHv`pqrP9VKX<LUM7kcN3v=<#i`{*&EqX9*)O0IiLOXfg<
z@1N5u@GaQ`as+;0Mr-RqbSt1<fEJ=f=r(jax&z&b?m~B?zo5mSoO{uIWl`2;wktV(
zL1Dh9dUkCv5b@WH2>1fQQaP%^qCYH21tLgZ6%Dm;FyJc&zREkH$O3#tpdxv%fyEaP
zO{GSvqa2MlaQO()luA9GHz^os^wxO&wR|(!f*0#OULWtNsR=@W@ZJy~Xpl_hfp`8I
zzRBx@8=o)G#79DWH4yexhoz0Y*UwjbLL%QJ@_tdQ;p+oIk*^WMfGw2HkB6sv-rEq0
z)blkGKYYj==0Sg9LBbLO=M}?1-BaUj@P?`-ZbS&pbiNQ!LH&&Ik)Yor@C^}PBREgz
z?chw+-kOLXo~s3ZmKdxD1p%1|togjP5uYcWpB(Xq=0rrk-kZ*kgnQlx1S7y#vE+<Z
z5g))eMhQ*`1gpF}@B)0K^92!qHSY=YHC|7B7e=E1d}F{D2{!;hI0(If7ia*103;`V
zjzmV<1~NoK4Whrs3jxoEszsj|l(|WlqGKs~04+lgqUGozv;urr@~7fx`U8KRB^#0&
zT*G@I`G@ND8cX^32uSQ169kKh(Rg2t)@(p)(2(M2KKwgiUWeAB4QM0Ugf^os=wY;V
zn&c^<`tsPdu)$L;mc<?<f|4si7vc-l%9$&fCUJ4JJ54MuYz~FR`ts_ipULna0)_Qx
z2Vmccb^+#Tb>1*+;h1q5={eD#K`6@GZnSO#a5JPUQ%?X>Pok|r#Y{~!5fWSseTU0-
zCh-hS&d-S9dk#In2|bTqfb1|t&I8hp(O%J4Be{OLl-wncl^&uSUP3Q#MlYlN=m2^J
z4Jqriq2yBVNQFa`QbR{ZsgOfq0)zq7mdYrq*U=jr(HrPZiE<*C$y+rs684GVj*2ux
ze%bNZIRU-{3GhA0a6DwVyFN#MgQfRDqz}<Y=<n!b^a(nMK1H9QL+EpK7=3|`pnsq*
z(Ld2q^cDIVxy#$LS1im6tAnEGp8`}W+E<FazzT>otw?s8j`wmg>ew%B0iX$<xstER
z3XCpD*#-hn&OFgKh2dtOIKdN|Ex~*J5`0-yPcll{gWgGRqfP@4y)Si92fc$M9HzHZ
z1Vy%`Wnh-TXAQ`dli;8XfzQqz)Y>}f@(de+4EqE65&Z;rzd-&RLwoA6k}ibXMeUX9
zBptO0Qt>Ht8l8b`JCPRAk}m+yIavP{>cnp{zTW}gd2|7AUIZ=f#26FIU=}NI9PWl9
zSOtF%p#TVzADCOz+#m@f>r8SL&{h!yRH(rdg#1x1!34nxBrw=8an`Jm7>;%m@|H;f
z$Uxv_6&*QQQVVFLfZjl_SJK{k%y9^07z^*zF*$Go9km_>E<GFQsLiMbC*tln2`5AC
z>r1m}4$Zr2{llr)(q8}MvXw^Na?Ju)Y-!1bf-^``b>^S}0-p(*{;X@g!A|T#ci<lA
zF5C;;YcWtwLt!l7ezL_!20cxoO9iKrGZqw1@<E2E3-~|}g^=L<wZ@C^vvkgdJg6l7
zs1qtlU#KK3Qc;0sOmD9gT>>3vqAfT}4)kkix)kWfFofS_rL9w}<AD(CndpjafrrGh
zMJ7!w3AZPSt7|F`=i?EbG}WJG>v4}u%95&crtFwGlCrX|Qk?NvsW{{Dps4P6BD&AO
z>MsnJ3+Mn4JIeqaI26#bQBsbOdzZmiVFefAskj(V>tJO#9Y}Na*b!p|8U?vM$jp!}
zC*2KfZ9OdUf-CS0T#095Pn0KI1tzS<HCRMn;96XVy>Ok4ec(8L+zkh0gXQ_4%Y@!a
zZ0{4KPC5{*_xQ%vOG%6~fKj3R1Zuq1V*w)A=<z|u%8!J@0e`e<XrDkwK>>qRKq9|s
z-!)S7d73M_Y>}N}fz)1H2QD#$8^`s4>mWLq=IHUg^6H|R;TLC23If9FW`0t@=dEt;
zRQzxVJ%l4tl}qcWa%`gH5?Qzj&&ADn-V8Y}%e|spn}*S$^jau8F|l~5>`7h8c&~r<
zXh@8qFw{nH*dnpM!3X+~vp2pO&)<OOOSzkC@3Y&nMgiLJEt~Ky(b7`hE@Vd`!3*%h
z&3IvZA(`F|aCINN1K-)n@D`d+N5rh2)Y8&_z<_oS%*@F6V;5WkE|`oTK=;YsHxj%r
z&wym_1AE4l8r7-nhf!7^!Yel76?mmQQp5&;ykOAN3`&!)rO}+636!Hd)}R9$qk_qP
z32U8Fw*=N&EWONV{iGA0u`U+(!kh4BaKkNfVi-rq(+N}MJb77<gSS%y)pK0uc;88r
zCuHy$>A4y5PiC~t<HzvsO?Y>dqp5PrzEaPJAi$o)dt-V&1gUm7okS-~dhQX`bAO5X
zELqRl5MKSWE`^sAT+ek4FLb9IUN7R8Ah7o11K5X7;n(o%_zl@*I>JkKJIUQS6W0cg
zUP!0F--+BC1|_&})a7p(ei0(45E{Se_$M1@vi9miyodkVMTn`i_>vG=nb{peWd1jW
zIEX(5Ax=kykOOouold90-=eY+9zS%WQNB|DcgpFP_@7Wtze25-$|*i3*SuTlElOG%
zD|cn><?VYYcK}d!dC5P6TJSG`<pjukhL%9dFQ;v=xukvLX*y~nK7-HVbF_kbsCb3a
z@G*$6^Y{Y3C@D>%0TDKX!aNf%>8(uGo0R2q`*+M>nFFpCWYHmvbb}x}BMo74kj;c3
ztB}Sca;&Hhns&MWl?R|exK4yIrJ(`hO`c&xe4VEeW}ZNpuY!h*_sp6l%?LH=d>$W^
z4G#dJ=o++a;5;>axXu$DnyNj1J_H`ZhXef3DIyG3%`hs#@G~M%-{A2#^HQ=KCau<q
zz6Rb~1L@d1s~Hf8d_yn*F<t-XY<1Pys)MZ#sp`F;KX?pEyp0M=L>s+fkJv#@e(;O(
zCNP^v;;9x;#m7(biPC5*+W^MiS>CywEx=bb!=M|g4tlF3-8M<atpg7c{h;3}ah5a)
zOW@T(PpIzyS#w=A#E6b?MBgdIs%W(y8)6{_RU#`|yW|jq+nmhS)=w{QJJB5^St=34
z3^8^VVl0gN84^7guv{x@Ak;i6ngO9Z397fqXY&8~OV<CurT_oHCHp^n`NNzJ_Jy2I
zT%-qPNv}&e9UmiUVCw=ppWdvbv*es!Mr&iKne>C44gj^6<#c=wwU8{-O8Ntqb5w+!
zUPoJDv)H~dmyX&%29d$kO9NLp8%YCa8%C~+=5q-@INObMw&ZEGvZv(^Xm6AI=Vn50
z@&~zm47nZ%-4M&=K3Y$`25z`~-o@oh`Mgv5?wWS<8XDx3%U>@BA@53w8*)vUkNCy8
z4RTudHFrL?Arr|YsikoZ7h;{OABL&U$20x%VSM^5DlRERH<F@DB9meQHJ_A_Qc@Nb
zyR@KiRE<||*2?6OtX7&oL!gbDXp@T0r44$lk#!O~{UsjSZ40R))ue`qWEQEVb7+u;
zXqZN5V<l$-fqWuAY2;|W!2>m{D&Pr1u>qWy)(Xa4xz-)}X)pBt(jojLd7(&tpIIPI
zFXBh}t38mud~z*=K{#9pxvwG2H)f`1U5U#k?<pEPdNkjdot|+efH}s<*bzlnE*e|p
zu}C(24zxiz?RF;(Xd#(Hg6MV<B4HB2-AE%iZ#U9}S?F=)qYJ6mg}mpNo~vP&0rlqj
zz4gGi^a&0ImKNG<AYe9Sr(uKKBu^Lf<f%CClBbM?<ScilWImxA36*Aqve*RDF(Qy#
z$gP{nt)0%A<aOz6prj=`H%mSVj?R4opOrm8&YZE=f7Do$yE+<cdRgxrYvlW94QQ3S
z9w{T|WOQ`y()&Ne{6Gih1y{!`9ow{z1kpJ)I~#6u2j;f6PLCe)3<LmkOaJujjI7)&
z(cM26=w5n=4j5!LS+jwxiA`Uz6RX&GRu0AqhNJH)JDr)~BxEO>sEy`OLjM95X^4(H
z(wGNR%w@pc0eBk#X94g%Wn#x<-WdqZ1E9wMs22d;2dv0oh0!lnFk^H<m<+Ic0X7d{
z@9#?eO2lUX_&ESB0pJJ98-k*IG|&Ylc@f#sX|kU#2bd!I;IwMF10NjK&#UCMjpViH
z*<$zhW5noz>y@X8kZ<keZ6GHCsuiVmqNhd-UdBJN<Fn*_fFaOBubN&1-BB$lyDK}V
z$R{#86X}|=P{*(`xDy&O2uK|UG+qE(R}OubFHkEFcU_2`2B@O|RRmBQDx#7_=i@Fq
zO$4yx0M-}4Hnr=26v){upU8HBJqz6Z46q*HZc7>D;P5!HS&F4D2tml7WrQBOr87gP
zaH7005th0x01Fr81wyyULSN3Oq#2yVC}hp#&>b*nhw1`NU54$>DuU6$&Zq%p1;Fow
zv9CH%FZEvShsRy1zr*Nd>O6f6EbaAsp&9j!_69?jzGfYiHZX}ycWD!o#3VB*K*7wU
z;<JpEv7w_S@*&M6Pq<Dx&h*NM9nv|ad;}M&<SeoS#TGgos5tt63G``T^9lMmXlxIC
zvXV<|ls<G0=3`t(zk5!VUsiN^2ML04p<zr9rYF-IvTFKlu{lKdt!H}Cz3Z7i^eH)M
z7DRl$PDh9EuHze0J2u(l8G-4yf$1k7wT$%25$FjvN0+W)GBz?9orB?WS+1_4Y*0}m
zGmyzeM`bCW11bB`XX*36MNCTB<79D4FWp{}>{{l!c8Rb+1-Z~N`OFCV@-8kB&65sl
znK7tFYGu$nkaG^fn3_n^ARy0x8=OJ`n6{5WddY#b@gj|v+8wZT7R<#S;G`A;wglW{
zB2`1Al*PUoGo_TJFI9A@H&H!Q;FTMsQ=E1-W=7dK1Y`mby#eSV(xfY}atsCVIrw`>
z`h`4q2xjXZKt>H}Py^vw`N~5xrv@g<q(L2id%<r>JN70CyCEthC{q?w5)wp}#q1FB
zbWA`J6HyW{5EHRoz@m1ncgt9rzc7oLdzgEf`<Nxn{mfG40cIKVAhVo#h*`m`WL7b&
znKkrP`Wk(mzCqulZ_&5uJM>-p9{nr*8-1UCKtH4((ZAD=%OK0~edPSpw~}*Ck<O5L
z>7xc8jbgq}*Mmj?;tRu|(rRA%?$fc{>By{axzz3S4)GJ4{9>@IlM!Glx&5-ue||0f
zzcbN;9Vc}$#s7IH-?uo{a&V?Dm^&Tn167;c!tqkw;rm?C680^RowdsV;4c+24!M}|
zeg2$i|Ff6ArI)l@(J2x1%j)u!S*a(duW*(>kMaJ$3;I8g@&23Uf_!D26baRJ6vN9t
zK)|}G%X+7e0DapF_T%*Bb?x_iJKaAm6><TML#1dQGzKN8M(%(rP=VAQpc|mMAB(1-
za%d5X(F~Xf#-oX-5KTa3IEf67wG>6@dNfu3C$s6%u1W5hra{lNm~Mx*!b=~4mO^SM
zcGIPDOK~?e6?VFs?t->rGkpg7rhDl!x|S}Xk3tg?h_xZ>sfuot{~c{>tjm&mtcPP?
zBY^v3GWX1J<~!zl<_G3S<|pQ7<`?D!^DpKk^Ka%9bDBBBoMp~2zcRluzcc5V3(Q3p
zv6v++!?LV`jbpp9N>;_jvuakuYS{!<$8xNmHLylDkshL-)5G)&dW8Oieo6mHkJ7K`
z*Yq3uEj>n$)9>i_^auJQ{fYief1xMnzvxN&Z+eQJrf29`dXD}|f1|(C^Yj9}*oILX
z#%-9iVWthUZCKHU<G5Aa0B!-dmK)3^ayN0yxG=YYGjNN!eq0%+<mPjwTmrY8OXpT{
z4{<BF3@%^(3I#vsxi#EIZaw!PN4ZvRDR)12AE)6KayN5JVn=iAFgmK;#%$gtd$S|u
zduT)1(d?KF>=^lD;@JG?za)<Iggr=!Ovs6Pqf9gyU57@3@r%$bLdhcXJ~>E^kRQoK
zCY9;S3}Et@iA*U|$1H&EZ!_~0^FDKkIR>Wq5sYvG)PEXO|0}5d0;rq;Wp@KbYe2;u
zYhrt{z1hBO7CVF;$xdX8*lO0t&S!6D?`I!im$7TvE$rj$)9ils74{T+hCRpr#-3*{
zDzJi4C=}fkDur61Rp=CYg;CL6k*qK&QWaK(UExr;6xoV=#W+QwVya@AqC`=qxJj{C
zu}raAu|@Hi;%UXJiq{oyD&AJStN5GZeZ_~0zbpQwI3K5qQ^#rJba95b#JHrml(>wz
z$#E5NbK-7_TNJl6ZhhRNaeLyPh}#>tFYcMR=i*+DJD|){PEnR9XDYqQ*~+l8QQ53q
zq`XJDRJl_5m~x-;RptB2Bg!w8N0nbIzf~Sr{-QjuidPv_iK--(Q{`4=s79&AsK%<s
zsV1mqs_In%RZ!KUTA*5{+Nj#0dP;Rb^{(n8)jw1}sm`b_#CMPH5kDY)VEmx?A@SG7
z`{P^UZ;xLVzb<}f{Il_|#(xt3ef%jkRx@gax|>?1PEd1dgE~>2q)t(r)fRP*dZ4;U
zU96t2E>%~kE7cx#wc4lltDDr#>K1jYdcJy}dcXQT_2=s2>XRCU#;ED8N!FM&sTzyM
zrg3Oonx2~8n!XyhCR>xE8KfDa8L1hqnXD<)Ow~-&lxWH{H)(FxP|Yox1)7DL+cbA*
z)@k0<9M+uF{I0p6MOva|wQ*XtR-;YOa$1u%U7MlJ(q?OOwBxlU+A{47ZAcr@Hffu+
zE!u_JE!wTxZQ32$o!Z^nJ=!O<d$sRsf6|`Rp3<Jtp40xOJ)b}l*aR*iGogRNfP{ew
zgA#@&T$^xRLS8~i!s3KY340P=Pxv_DSi-M5rB1Ii>bmQabtYY^&Z@KP96Fb-m+l(f
zFx^DmWL>GQTvw^{=~{HHy7{^`-5t6ex+itd=-$<RtUIFnL3fHnoQg~11c<;4E{p3A
z(K?Wu#LeMCT!d@lnz<GTzgr*(*KrSXd$||5H@OeEPq`D^S$%hXvfiXm)m!y;eNTOk
zK36|jKU6<fKTcnwuhP%f&(SZ@FV!#8FW0Zouhg&Buhs9<|7bu4Vqgt%2Bjh1pfMyE
zID^5EXfPR^hHOKQVVa@DP-dtwR2pU)sth%TR>K~{6NbHpeTHWY&lz4YykvOC@Sd@o
zQDsycwMLzhGa8JE#w25k(QI@Xdm8%~(~M(`V~yjC6O0p$lZ}POa^no6Xsk7QjkAq+
z8y6ezH7+qOH9lxuZd_qpWqi{3vGJhsGvnvRFO2^%{xj*lq@R;cB%Mq;m2@WQ*QDQ)
z&L>?=PEH=0oR>Tzc~tV4<gv-)lE)_(q-;nzlyW%bNXnNfM^nB^`6lI9%6BP0r2Ld}
zCgohp?<p5dsV1w*ZgQAhrk<wWrVLY-X`pG4X^5%ZG{ZF0RAs6$iKbeU*VJa(VA^Eb
zV%lojX4+xeZF<~v)~qtC&57nDbDFu(Ji~mW*=P2f8_aXeA#=n$*W7GwF}Io*nQu2g
zV1Cg2ka?wfwRx?1z4>|br{)u>JyS=gR;M<nu1MXGx-E52>hr1lQ(sAaE%oixcTzu1
zJ(PMl^+@W;)ZZ<PMQ2H|xGdLL23aOs{FVkw&=R&ZTIO07T5hu}v23@zVR_5)j^#be
z-z*<kj#$35{9t9RT5FoMzctr7&N|)dwa&KITLacP)`iw(*5%d})>YOu)@{~jt<PIu
zw7zUTVEx$ot@XI|d+U$ZpKXjS(UxROv6*caTVLB?+fdsu+i+XH?FL(+t<)B@-D+EC
zyUlio?JnCg+rzd;Y};**+IHFY+1|9hZF|@DSKIrx!?vGnzu5j|`?u}1ov|m{lk6#W
zv)y7(vk$RfYroE(XCGlNw%6Ld_SyD&d%)gezuUgpey@FreW`u3{bBnf_U-mZ?JwA0
zvhTOQVt>v4f&HlcYx}qM<M!`)#Orw@-<?n9O}v{Q$`9j*^ZEQpzMOC6Z{zRdSMtyB
z&+#wtFY){NSNPZXH~1s`*ZfHbawr|~4y{AyFgOw&eH=p_qZ~Ilra5LhY8~?(>l_;#
zn;cslTOHdRI~+S5`yKB(K68BTIO6!y@s;Bn$Ip%vPK(p#<eg4u4`(lDA7`3VaHcym
zoLSCnXO1)1IoLVWIm|iSneQCwoZy`3ob0T0);a5)jn28wjn2)^hn<f&w>uwo?sD#S
zKJI+d`IPf%=d;e|oi93Hb{=rP>U`b#rt@v*N6wF(=baZ_*u}UMu5K=sOYPFSbS}Ni
z=<4oDc9~qMF00G#a=6l5f~(Lq)iupk;wp1hxGG&9SG7xY)w;Z{*{*t5z%|Deaz$KC
zu3KGOU2nS%y1we!(DOjgw|ailt6Q(c-jUw4_u}5G(w3#|P5U72P}<?NFVenEJD&Dk
z+R3z2?n&+`?jm=wd%C;SUGARYp6RY~*SKf7>)bcGeQv+I!5wsm-Hq<K?s@K;+&8<a
z`xf^C_agW0?mOLgyBE9fbuV!*buV)-cdu}-a<6f(b8m2Oa&K{Ob?<gRE+hz?U=R|8
zBq2pG3l_m9@Pbq5A@maZ2x)>Kqzf5BmXIyv2)V*wVW==n7%t=sBZbkz^}-Fpc%eX;
zBuo*CgkoX3P$tX}JVK37E8Hm53jtw{5E3Fnlh7=*2(7|=p-s3|SSZ{k+#%d0{6)A&
zxKFrWctChict}_&tQOV^TZL`H4q>P8n6O89Lf9+p6P^*C6J8Kr67~yk3-1c=37-g`
e3ZDr_g|CHggr9|fM?b<561}q5qb@)FnEwJU)5tgg
index 70626567c95f166a7ac0bf7d3b89d695264e4b1b..efc832acfbb8b635940dedec2d123ae8975e009f
GIT binary patch
literal 1488
zc$~#k%TB{E5Zp6gVO8SNLwW}x@eo`nP*M5;Zjv^YnkLj~OMV_0kDbJ&=^0s0Z12wQ
z%zFLvJ(8g)nMx&FS;<D0Vz6IGfxVI$b}3h{IH};Vz>Gz6UBF-AyTDgt#_-fYWLOVn
zBo{KkI>lMSC{L0DH-Pm9b08nIT5O52K8buOxA<m^spM03uvA#>U`^!<m=uT#-vsDd
zBE-CA)*OiC*?b1RhPa&BH^3|E%e>ltM#i(*Gs=btC3Eaj^3|xsBH$F^><)8_UCD}8
zfu0T*(?ffdA`ea98mJvTG(8Ow&ZlTA<kpt^8hI4hCiHXnRr`pRbBRm^GOww<tC!U>
z^|4=AyZ@|O!zzYvj^VVJ6J`_Y(5y<Rf9HF6g&sMl-7>J1v6V8sffY{N3s7=sZy@uk
zQubWpnY;Iq2GP6T@A%t18Zp;B%q^EaZ>q`Z?%LL|!zsR<gt-h=9eD06_Fv$nQSAC4
zX4Na$<D(v0`Ce=4b@2C*dR=*|$=0Ou3{0<{G5&MbyVLa8TCZ9}$-3^zrS3&djyx3h
zh3}xcjnZ`ed+?6#p{b(cO%Sc=VRhu&^^@(|m<;;y4}nMD+vrEV$@3Y-p_&;ujRRE1
gNF}N@!Z>h5=!61e$u5oj3mE;0S_V-g#>qY3UlaWQmH+?%
--- a/toolkit/crashreporter/google-breakpad/src/client/mac/sender/crash_report_sender.h
+++ b/toolkit/crashreporter/google-breakpad/src/client/mac/sender/crash_report_sender.h
@@ -36,71 +36,45 @@
 
 #include "client/mac/Framework/Breakpad.h"
 
 #define kClientIdPreferenceKey @"clientid"
 
 extern NSString *const kGoogleServerType;
 extern NSString *const kSocorroServerType;
 extern NSString *const kDefaultServerType;
-
-// We're sublcassing NSTextField in order to override a particular
-// method (see the implementation) that lets us reject changes if they
-// are longer than a particular length.  Bindings would normally solve
-// this problem, but when we implemented a validation method, and
-// returned NO for strings that were too long, the UI was not updated
-// right away, which was a poor user experience.  The UI would be
-// updated as soon as the text field lost first responder status,
-// which isn't soon enough.  It is a known bug that the UI KVO didn't
-// work in the middle of a validation.
-@interface LengthLimitingTextField : NSTextField {
-  @private
-   unsigned int maximumLength_;
-}
-
-- (void) setMaximumLength:(unsigned int)maxLength;
-@end
-
 @interface Reporter : NSObject {
  @public
   IBOutlet NSWindow *alertWindow_;        // The alert window
 
   // Grouping boxes used for resizing.
   IBOutlet NSBox *headerBox_;
   IBOutlet NSBox *preEmailBox_;
   IBOutlet NSBox *emailSectionBox_;
   // Localized elements (or things that need to be moved during localization).
-  IBOutlet NSTextField                *dialogTitle_;
-  IBOutlet NSTextField                *commentMessage_;
-  IBOutlet NSTextField                *emailMessage_;
-  IBOutlet NSTextField                *emailLabel_;
-  IBOutlet NSTextField                *privacyLinkLabel_;
-  IBOutlet NSButton                   *sendButton_;
-  IBOutlet NSButton                   *cancelButton_;
-  IBOutlet LengthLimitingTextField    *emailEntryField_;
-  IBOutlet LengthLimitingTextField    *commentsEntryField_;
-  IBOutlet NSTextField                *countdownLabel_;
-  IBOutlet NSView                     *privacyLinkArrow_;
+  IBOutlet NSTextField *dialogTitle_;
+  IBOutlet NSTextField *commentMessage_;
+  IBOutlet NSTextField *emailMessage_;
+  IBOutlet NSTextField *emailLabel_;
+  IBOutlet NSTextField *privacyLinkLabel_;
+  IBOutlet NSButton    *sendButton_;
+  IBOutlet NSButton    *cancelButton_;
+  IBOutlet NSView      *emailEntryField_;
+  IBOutlet NSView      *privacyLinkArrow_;
 
   // Text field bindings, for user input.
   NSString *commentsValue_;                // Comments from the user
   NSString *emailValue_;                   // Email from the user
-  NSString *countdownMessage_;             // Message indicating time
-                                           // left for input.
+
  @private
   int configFile_;                         // File descriptor for config file
   NSMutableDictionary *parameters_;        // Key value pairs of data (STRONG)
   NSData *minidumpContents_;               // The data in the minidump (STRONG)
   NSData *logFileData_;                    // An NSdata for the tar,
                                            // bz2'd log file.
-  NSTimeInterval remainingDialogTime_;     // Keeps track of how long
-                                           // we have until we cancel
-                                           // the dialog
-  NSTimer *messageTimer_;                  // Timer we use to update
-                                           // the dialog
   NSMutableDictionary *serverDictionary_;  // The dictionary mapping a
                                            // server type name to a
                                            // dictionary of server
                                            // parameter names.
   NSMutableDictionary *socorroDictionary_; // The dictionary for
                                            // Socorro.
   NSMutableDictionary *googleDictionary_;  // The dictionary for
                                            // Google.
@@ -128,12 +102,9 @@ extern NSString *const kDefaultServerTyp
 
 // Accessors to make bindings work
 - (NSString *)commentsValue;
 - (void)setCommentsValue:(NSString *)value;
 
 - (NSString *)emailValue;
 - (void)setEmailValue:(NSString *)value;
 
-- (NSString *)countdownMessage;
-- (void)setCountdownMessage:(NSString *)value;
-
 @end
--- a/toolkit/crashreporter/google-breakpad/src/client/mac/sender/crash_report_sender.m
+++ b/toolkit/crashreporter/google-breakpad/src/client/mac/sender/crash_report_sender.m
@@ -37,21 +37,18 @@
 #import "common/mac/HTTPMultipartUpload.h"
 
 #import "crash_report_sender.h"
 #import "common/mac/GTMLogger.h"
 
 
 #define kLastSubmission @"LastSubmission"
 const int kMinidumpFileLengthLimit = 800000;
-const int kUserCommentsMaxLength = 1500;
-const int kEmailMaxLength = 64;
 
-#define kApplePrefsSyncExcludeAllKey \
-  @"com.apple.PreferenceSync.ExcludeAllSyncKeys"
+#define kApplePrefsSyncExcludeAllKey @"com.apple.PreferenceSync.ExcludeAllSyncKeys"
 
 NSString *const kGoogleServerType = @"google";
 NSString *const kSocorroServerType = @"socorro";
 NSString *const kDefaultServerType = @"google";
 
 #pragma mark -
 
 @interface NSView (ResizabilityExtentions)
@@ -107,22 +104,19 @@ NSString *const kDefaultServerType = @"g
 // current text, preserving the existing height and origin.
 // Returns the change in width.
 - (float)breakpad_adjustWidthToFit;
 @end
 
 @implementation NSTextField (ResizabilityExtentions)
 - (float)breakpad_adjustHeightToFit {
   NSRect oldFrame = [self frame];
-  // Starting with the 10.5 SDK, height won't grow, so make it huge to start.
-  NSRect presizeFrame = oldFrame;
-  presizeFrame.size.height = MAXFLOAT;
   // sizeToFit will blow out the width rather than making the field taller, so
   // we do it manually.
-  NSSize newSize = [[self cell] cellSizeForBounds:presizeFrame];
+  NSSize newSize = [[self cell] cellSizeForBounds:oldFrame];
   NSRect newFrame = NSMakeRect(oldFrame.origin.x, oldFrame.origin.y,
                                NSWidth(oldFrame), newSize.height);
   [self setFrame:newFrame];
 
   return newSize.height - NSHeight(oldFrame);
 }
 
 - (float)breakpad_adjustWidthToFit {
@@ -175,53 +169,50 @@ NSString *const kDefaultServerType = @"g
 
 // Returns YES if it has been long enough since the last report that we should
 // submit a report for this crash.
 - (BOOL)reportIntervalElapsed;
 
 // Returns YES if we should send the report without asking the user first.
 - (BOOL)shouldSubmitSilently;
 
-// Returns YES if the minidump was generated on demand.
-- (BOOL)isOnDemand;
-
 // Returns YES if we should ask the user to provide comments.
 - (BOOL)shouldRequestComments;
 
 // Returns YES if we should ask the user to provide an email address.
 - (BOOL)shouldRequestEmail;
 
 // Shows UI to the user to ask for permission to send and any extra information
 // we've been instructed to request. Returns YES if the user allows the report
 // to be sent.
 - (BOOL)askUserPermissionToSend;
 
 // Returns the short description of the crash, suitable for use as a dialog
<