Bug 1402519 - When the crash reporter code is disabled at configure time replace it with a dummy implementation; r=ted.mielczarek
authorGabriele Svelto <gsvelto@mozilla.com>
Tue, 14 Nov 2017 14:49:33 +0100
changeset 437935 de8b3d96bc5501134a14048a9fd9875c291bf395
parent 437934 2ad64876cb085ecdd761f5cbc215655a4ea3f577
child 437936 7a584878bf70642cbf4ba342ffb85e6fa9a2c93e
push id117
push userfmarier@mozilla.com
push dateTue, 28 Nov 2017 20:17:16 +0000
reviewersted
bugs1402519
milestone59.0a1
Bug 1402519 - When the crash reporter code is disabled at configure time replace it with a dummy implementation; r=ted.mielczarek MozReview-Commit-ID: F5QbaI1LlmZ
browser/base/content/test/general/browser_restore_isAppTab.js
js/xpconnect/src/XPCShellImpl.cpp
memory/gtest/TestJemalloc.cpp
mobile/android/chrome/content/browser.js
mobile/android/components/SessionStore.js
testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
toolkit/components/crashes/moz.build
toolkit/components/moz.build
toolkit/crashreporter/jar.mn
toolkit/crashreporter/moz.build
toolkit/crashreporter/nsDummyExceptionHandler.cpp
toolkit/crashreporter/nsExceptionHandler.cpp
toolkit/crashreporter/nsExceptionHandler.h
toolkit/crashreporter/nsExceptionHandlerUtils.cpp
toolkit/crashreporter/nsExceptionHandlerUtils.h
toolkit/moz.build
--- a/browser/base/content/test/general/browser_restore_isAppTab.js
+++ b/browser/base/content/test/general/browser_restore_isAppTab.js
@@ -81,18 +81,19 @@ add_task(async function navigate() {
   loadFrameScript(browser);
   isAppTab = await isBrowserAppTab(browser);
   ok(isAppTab, "Docshell should think it is an app tab");
 
   gBrowser.removeCurrentTab();
 });
 
 add_task(async function crash() {
-  if (!gMultiProcessBrowser || !("nsICrashReporter" in Ci))
+  if (!gMultiProcessBrowser || !AppConstants.MOZ_CRASHREPORTER) {
     return;
+  }
 
   let tab = BrowserTestUtils.addTab(gBrowser, DUMMY);
   let browser = tab.linkedBrowser;
   gBrowser.selectedTab = tab;
   await BrowserTestUtils.browserStopped(gBrowser);
   loadFrameScript(browser);
   let isAppTab = await isBrowserAppTab(browser);
   ok(!isAppTab, "Docshell shouldn't think it is an app tab");
--- a/js/xpconnect/src/XPCShellImpl.cpp
+++ b/js/xpconnect/src/XPCShellImpl.cpp
@@ -1190,17 +1190,17 @@ XRE_XPCShellMain(int argc, char** argv, 
             XRE_AddManifestLocation(NS_APP_LOCATION, lf);
 
             argc -= 2;
             argv += 2;
         }
 
 #ifdef MOZ_CRASHREPORTER
         const char* val = getenv("MOZ_CRASHREPORTER");
-        if (val && *val) {
+        if (val && *val && !CrashReporter::IsDummy()) {
             rv = CrashReporter::SetExceptionHandler(greDir, true);
             if (NS_FAILED(rv)) {
                 printf("CrashReporter::SetExceptionHandler failed!\n");
                 return 1;
             }
             MOZ_ASSERT(CrashReporter::GetEnabled());
         }
 #endif
--- a/memory/gtest/TestJemalloc.cpp
+++ b/memory/gtest/TestJemalloc.cpp
@@ -3,43 +3,39 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/mozalloc.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/Vector.h"
 #include "mozmemory.h"
+#include "nsCOMPtr.h"
+#include "nsICrashReporter.h"
+#include "nsServiceManagerUtils.h"
 #include "Utils.h"
 
 #include "gtest/gtest.h"
 
-#ifdef MOZ_CRASHREPORTER
-#include "nsCOMPtr.h"
-#include "nsICrashReporter.h"
-#include "nsServiceManagerUtils.h"
-#endif
 
 #ifdef NIGHTLY_BUILD
 #if defined(DEBUG) && !defined(XP_WIN) && !defined(ANDROID)
 #define HAS_GDB_SLEEP_DURATION 1
 extern unsigned int _gdb_sleep_duration;
 #endif
 
 // Death tests are too slow on OSX because of the system crash reporter.
 #ifndef XP_DARWIN
 static void DisableCrashReporter()
 {
-#ifdef MOZ_CRASHREPORTER
   nsCOMPtr<nsICrashReporter> crashreporter =
     do_GetService("@mozilla.org/toolkit/crash-reporter;1");
   if (crashreporter) {
     crashreporter->SetEnabled(false);
   }
-#endif
 }
 
 // Wrap ASSERT_DEATH_IF_SUPPORTED to disable the crash reporter
 // when entering the subprocess, so that the expected crashes don't
 // create a minidump that the gtest harness will interpret as an error.
 #define ASSERT_DEATH_WRAP(a, b) \
   ASSERT_DEATH_IF_SUPPORTED({ DisableCrashReporter(); a; }, b)
 #else
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -1986,19 +1986,17 @@ var BrowserApp = {
           case "privacy.trackingprotection.state": {
             aSubject.setAsAString(this.getTrackingProtectionState());
             break;
           }
 
           // Crash reporter submit pref must be fetched from nsICrashReporter
           // service.
           case "datareporting.crashreporter.submitEnabled":
-            let crashReporterBuilt = "nsICrashReporter" in Ci &&
-                Services.appinfo instanceof Ci.nsICrashReporter;
-            if (crashReporterBuilt) {
+            if (AppConstants.MOZ_CRASHREPORTER) {
               aSubject.setAsBool(Services.appinfo.submitReports);
             }
             break;
         }
         break;
       }
 
       case "android-set-pref": {
@@ -2041,19 +2039,17 @@ var BrowserApp = {
                 break;
             }
             aSubject.setAsEmpty();
             break;
           }
 
           // Crash reporter preference is in a service; set and return.
           case "datareporting.crashreporter.submitEnabled":
-            let crashReporterBuilt = "nsICrashReporter" in Ci &&
-                Services.appinfo instanceof Ci.nsICrashReporter;
-            if (crashReporterBuilt) {
+            if (AppConstants.MOZ_CRASHREPORTER) {
               Services.appinfo.submitReports = value;
               aSubject.setAsEmpty();
             }
             break;
         }
         break;
       }
 
--- a/mobile/android/components/SessionStore.js
+++ b/mobile/android/components/SessionStore.js
@@ -1234,18 +1234,17 @@ SessionStore.prototype = {
     aFileTemp.renameTo(null, aFile.leafName);
     log("_write() writing synchronously");
 
     // Return a resolved promise to make the caller happy
     return Promise.resolve();
   },
 
   _updateCrashReportURL: function ss_updateCrashReportURL(aWindow) {
-    let crashReporterBuilt = "nsICrashReporter" in Ci && Services.appinfo instanceof Ci.nsICrashReporter;
-    if (!crashReporterBuilt) {
+    if (!AppConstants.MOZ_CRASHREPORTER) {
       return;
     }
 
     if (!aWindow.BrowserApp.selectedBrowser) {
       return;
     }
 
     try {
--- a/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
+++ b/testing/mochitest/BrowserTestUtils/BrowserTestUtils.jsm
@@ -1083,17 +1083,17 @@ this.BrowserTestUtils = {
         // we might see this called as the process terminates due to previous tests.
         // We are only looking for "abnormal" exits...
         if (!subject.hasKey("abnormal")) {
           dump("\nThis is a normal termination and isn't the one we are looking for...\n");
           return;
         }
 
         let dumpID;
-        if ('nsICrashReporter' in Ci) {
+        if (AppConstants.MOZ_CRASHREPORTER) {
           dumpID = subject.getPropertyAsAString('dumpID');
           if (!dumpID) {
             return reject("dumpID was not present despite crash reporting " +
                           "being enabled");
           }
         }
 
         let removalPromise = Promise.resolve();
--- a/toolkit/components/crashes/moz.build
+++ b/toolkit/components/crashes/moz.build
@@ -1,31 +1,33 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 SPHINX_TREES['crash-manager'] = 'docs'
 
-EXTRA_COMPONENTS += [
-    'CrashService.js',
-    'CrashService.manifest',
-]
-
-EXTRA_JS_MODULES += [
-    'CrashManager.jsm',
-]
-
-TESTING_JS_MODULES += [
-    'CrashManagerTest.jsm',
-]
-
-XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini']
-
 XPIDL_MODULE = 'toolkit_crashservice'
 
 XPIDL_SOURCES += [
     'nsICrashService.idl',
 ]
 
+if CONFIG['MOZ_CRASHREPORTER']:
+    EXTRA_COMPONENTS += [
+        'CrashService.js',
+        'CrashService.manifest',
+    ]
+
+    EXTRA_JS_MODULES += [
+        'CrashManager.jsm',
+    ]
+
+    TESTING_JS_MODULES += [
+        'CrashManagerTest.jsm',
+    ]
+
+    XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini']
+
 with Files('**'):
     BUG_COMPONENT = ('Toolkit', 'Crash Reporting')
+
--- a/toolkit/components/moz.build
+++ b/toolkit/components/moz.build
@@ -21,16 +21,17 @@ DIRS += [
     'apppicker',
     'asyncshutdown',
     'backgroundhangmonitor',
     'browser',
     'cloudstorage',
     'commandlines',
     'contentprefs',
     'contextualidentity',
+    'crashes',
     'crashmonitor',
     'diskspacewatcher',
     'downloads',
     'extensions',
     'filewatcher',
     'finalizationwitness',
     'find',
     'jsdownloads',
@@ -75,19 +76,16 @@ DIRS += [
 ]
 
 if CONFIG['MOZ_BUILD_APP'] != 'mobile/android':
     DIRS += ['narrate', 'viewsource'];
 
     if CONFIG['NS_PRINTING']:
         DIRS += ['printing']
 
-if CONFIG['MOZ_CRASHREPORTER']:
-    DIRS += ['crashes']
-
 if CONFIG['BUILD_CTYPES']:
     DIRS += ['ctypes']
 
 if CONFIG['MOZ_FEEDS']:
     DIRS += ['feeds']
 
 if CONFIG['MOZ_XUL']:
     DIRS += ['autocomplete', 'printingui', 'satchel']
--- a/toolkit/crashreporter/jar.mn
+++ b/toolkit/crashreporter/jar.mn
@@ -1,7 +1,9 @@
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 toolkit.jar:
+#ifdef MOZ_CRASHREPORTER
   content/global/crashes.xhtml            (content/crashes.xhtml)
   content/global/crashes.js               (content/crashes.js)
+#endif
--- a/toolkit/crashreporter/moz.build
+++ b/toolkit/crashreporter/moz.build
@@ -1,115 +1,125 @@
 # -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 SPHINX_TREES['crashreporter'] = 'docs'
 
-if CONFIG['OS_ARCH'] == 'WINNT':
-    DIRS += [
-        'google-breakpad/src/common',
-        'google-breakpad/src/processor',
-        'breakpad-windows-libxul',
-    ]
-
-    if CONFIG['MSVC_HAS_DIA_SDK']:
-        DIRS += ['google-breakpad/src/tools/windows/dump_syms']
-
-    if CONFIG['MOZ_CRASHREPORTER_INJECTOR']:
-        DIRS += ['breakpad-windows-standalone']
-
-elif CONFIG['OS_ARCH'] == 'Darwin':
-    DIRS += [
-        'breakpad-client',
-        'breakpad-client/mac/crash_generation',
-        'breakpad-client/mac/handler',
-        'google-breakpad/src/common',
-        'google-breakpad/src/common/mac',
-        'google-breakpad/src/processor',
-        'google-breakpad/src/tools/mac/dump_syms',
-    ]
-
-elif CONFIG['OS_ARCH'] == 'Linux':
-    DIRS += [
-        'breakpad-client',
-        'breakpad-client/linux/',
-        'google-breakpad/src/common',
-        'google-breakpad/src/common/linux',
-        'google-breakpad/src/processor',
-        'google-breakpad/src/tools/linux/dump_syms',
-    ]
-
-
-DIRS += [
-    'client',
-    'minidump-analyzer',
-]
-
-if CONFIG['MOZ_CRASHREPORTER_INJECTOR']:
-    DIRS += ['injector']
-    UNIFIED_SOURCES += [
-        'InjectCrashReporter.cpp',
-        'LoadLibraryRemote.cpp',
-    ]
-
-if CONFIG['ENABLE_TESTS']:
-    DIRS += ['test/gtest']
-
-TEST_DIRS += ['test']
-
 EXPORTS += [
     'nsExceptionHandler.h',
 ]
 
-UNIFIED_SOURCES += [
-    'nsExceptionHandler.cpp',
-    'ThreadAnnotation.cpp',
-]
+JAR_MANIFESTS += ['jar.mn']
 
-if CONFIG['OS_ARCH'] == 'Darwin':
-    UNIFIED_SOURCES += [
-        'mac_utils.mm',
-    ]
-
-EXTRA_JS_MODULES += [
-    'CrashReports.jsm',
-    'CrashSubmit.jsm',
-    'KeyValueParser.jsm',
+UNIFIED_SOURCES = [
+    'nsExceptionHandlerUtils.cpp',
 ]
 
-include('/ipc/chromium/chromium-config.mozbuild')
-
 FINAL_LIBRARY = 'xul'
 
-if CONFIG['OS_TARGET'] == 'Android':
-    DEFINES['ANDROID_NDK_MAJOR_VERSION'] = CONFIG['ANDROID_NDK_MAJOR_VERSION']
-    DEFINES['ANDROID_NDK_MINOR_VERSION'] = CONFIG['ANDROID_NDK_MINOR_VERSION']
-    DEFINES['ANDROID_PACKAGE_NAME'] = '"%s"' % CONFIG['ANDROID_PACKAGE_NAME']
-    # NDK5 workarounds
-    DEFINES['_STLP_CONST_CONSTRUCTOR_BUG'] = True
-    DEFINES['_STLP_NO_MEMBER_TEMPLATES'] = True
-    LOCAL_INCLUDES += [
-        '/toolkit/crashreporter/google-breakpad/src/common/android/include',
+if CONFIG['MOZ_CRASHREPORTER']:
+    if CONFIG['OS_ARCH'] == 'WINNT':
+        DIRS += [
+            'google-breakpad/src/common',
+            'google-breakpad/src/processor',
+            'breakpad-windows-libxul',
+        ]
+
+        if CONFIG['MSVC_HAS_DIA_SDK']:
+            DIRS += ['google-breakpad/src/tools/windows/dump_syms']
+
+        if CONFIG['MOZ_CRASHREPORTER_INJECTOR']:
+            DIRS += ['breakpad-windows-standalone']
+
+    elif CONFIG['OS_ARCH'] == 'Darwin':
+        DIRS += [
+            'breakpad-client',
+            'breakpad-client/mac/crash_generation',
+            'breakpad-client/mac/handler',
+            'google-breakpad/src/common',
+            'google-breakpad/src/common/mac',
+            'google-breakpad/src/processor',
+            'google-breakpad/src/tools/mac/dump_syms',
+        ]
+
+    elif CONFIG['OS_ARCH'] == 'Linux':
+        DIRS += [
+            'breakpad-client',
+            'breakpad-client/linux/',
+            'google-breakpad/src/common',
+            'google-breakpad/src/common/linux',
+            'google-breakpad/src/processor',
+            'google-breakpad/src/tools/linux/dump_syms',
+        ]
+
+
+    DIRS += [
+        'client',
+        'minidump-analyzer',
     ]
 
-DEFINES['UNICODE'] = True
-DEFINES['_UNICODE'] = True
+    if CONFIG['MOZ_CRASHREPORTER_INJECTOR']:
+        DIRS += ['injector']
+        UNIFIED_SOURCES += [
+            'InjectCrashReporter.cpp',
+            'LoadLibraryRemote.cpp',
+        ]
+
+    if CONFIG['ENABLE_TESTS']:
+        DIRS += ['test/gtest']
+
+    TEST_DIRS += ['test']
 
-JAR_MANIFESTS += ['jar.mn']
+    UNIFIED_SOURCES += [
+        'nsExceptionHandler.cpp',
+        'ThreadAnnotation.cpp',
+    ]
+
+    if CONFIG['OS_ARCH'] == 'Darwin':
+        UNIFIED_SOURCES += [
+            'mac_utils.mm',
+        ]
+
+    EXTRA_JS_MODULES += [
+        'CrashReports.jsm',
+        'CrashSubmit.jsm',
+        'KeyValueParser.jsm',
+    ]
+
+    include('/ipc/chromium/chromium-config.mozbuild')
 
-LOCAL_INCLUDES += [
-    'google-breakpad/src',
-]
+    if CONFIG['OS_TARGET'] == 'Android':
+        DEFINES['ANDROID_NDK_MAJOR_VERSION'] = CONFIG['ANDROID_NDK_MAJOR_VERSION']
+        DEFINES['ANDROID_NDK_MINOR_VERSION'] = CONFIG['ANDROID_NDK_MINOR_VERSION']
+        DEFINES['ANDROID_PACKAGE_NAME'] = '"%s"' % CONFIG['ANDROID_PACKAGE_NAME']
+        # NDK5 workarounds
+        DEFINES['_STLP_CONST_CONSTRUCTOR_BUG'] = True
+        DEFINES['_STLP_NO_MEMBER_TEMPLATES'] = True
+        LOCAL_INCLUDES += [
+            '/toolkit/crashreporter/google-breakpad/src/common/android/include',
+        ]
+
+    DEFINES['UNICODE'] = True
+    DEFINES['_UNICODE'] = True
 
-PYTHON_UNITTEST_MANIFESTS += [
-    'tools/python.ini',
-]
+    LOCAL_INCLUDES += [
+        'google-breakpad/src',
+    ]
+
+    PYTHON_UNITTEST_MANIFESTS += [
+        'tools/python.ini',
+    ]
 
-include('/toolkit/crashreporter/crashreporter.mozbuild')
+    include('/toolkit/crashreporter/crashreporter.mozbuild')
+
+    if CONFIG['GNU_CXX']:
+        CXXFLAGS += ['-Wno-shadow']
+else:
+    UNIFIED_SOURCES += [
+        'nsDummyExceptionHandler.cpp',
+    ]
+
 
 with Files('**'):
     BUG_COMPONENT = ('Toolkit', 'Crash Reporting')
-
-if CONFIG['GNU_CXX']:
-    CXXFLAGS += ['-Wno-shadow']
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/nsDummyExceptionHandler.cpp
@@ -0,0 +1,425 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsExceptionHandler.h"
+#include "nsExceptionHandlerUtils.h"
+
+namespace CrashReporter {
+
+void
+AnnotateOOMAllocationSize(size_t size)
+{
+}
+
+void
+AnnotateTexturesSize(size_t size)
+{
+}
+
+void
+AnnotatePendingIPC(size_t aNumOfPendingIPC,
+                   uint32_t aTopPendingIPCCount,
+                   const char* aTopPendingIPCName,
+                   uint32_t aTopPendingIPCType)
+{
+}
+
+nsresult
+SetExceptionHandler(nsIFile* aXREDirectory,
+                    bool force/*=false*/)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+bool
+GetEnabled()
+{
+  return false;
+}
+
+bool
+GetMinidumpPath(nsAString& aPath)
+{
+  return false;
+}
+
+nsresult
+SetMinidumpPath(const nsAString& aPath)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
+SetupExtraData(nsIFile* aAppDataDirectory,
+               const nsACString& aBuildID)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
+UnsetExceptionHandler()
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
+AnnotateCrashReport(const nsACString& key,
+                    const nsACString& data)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
+RemoveCrashReportAnnotation(const nsACString& key)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
+SetGarbageCollecting(bool collecting)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+void
+SetEventloopNestingLevel(uint32_t level)
+{
+}
+
+void
+SetMinidumpAnalysisAllThreads()
+{
+}
+
+nsresult
+AppendAppNotesToCrashReport(const nsACString& data)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+bool
+GetAnnotation(const nsACString& key, nsACString& data)
+{
+  return false;
+}
+
+nsresult
+RegisterAppMemory(void* ptr, size_t length)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
+UnregisterAppMemory(void* ptr)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+void
+SetIncludeContextHeap(bool aValue)
+{
+}
+
+bool
+GetServerURL(nsACString& aServerURL)
+{
+  return false;
+}
+
+nsresult
+SetServerURL(const nsACString& aServerURL)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
+SetRestartArgs(int argc, char** argv)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+#ifdef XP_WIN32
+nsresult
+WriteMinidumpForException(EXCEPTION_POINTERS* aExceptionInfo)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+#endif
+
+#ifdef XP_LINUX
+bool
+WriteMinidumpForSigInfo(int signo,
+                        siginfo_t* info,
+                        void* uc)
+{
+  return false;
+}
+#endif
+
+#ifdef XP_MACOSX
+nsresult
+AppendObjCExceptionInfoToAppNotes(void *inException)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+#endif
+
+nsresult
+GetSubmitReports(bool* aSubmitReports)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+nsresult
+SetSubmitReports(bool aSubmitReports)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+void
+SetProfileDirectory(nsIFile* aDir)
+{
+}
+
+void
+SetUserAppDataDirectory(nsIFile* aDir)
+{
+}
+
+void
+UpdateCrashEventsDir()
+{
+}
+
+bool
+GetCrashEventsDir(nsAString& aPath)
+{
+  return false;
+}
+
+void
+SetMemoryReportFile(nsIFile* aFile)
+{
+}
+
+nsresult
+GetDefaultMemoryReportFile(nsIFile** aFile)
+{
+  return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+void
+SetTelemetrySessionId(const nsACString& id)
+{
+}
+
+void
+DeleteMinidumpFilesForID(const nsAString& id)
+{
+}
+
+bool
+GetMinidumpForID(const nsAString& id, nsIFile** minidump)
+{
+  return false;
+}
+
+bool
+GetIDFromMinidump(nsIFile* minidump, nsAString& id)
+{
+  return false;
+}
+
+bool
+GetExtraFileForID(const nsAString& id,
+                  nsIFile** extraFile)
+{
+  return false;
+}
+
+bool
+GetExtraFileForMinidump(nsIFile* minidump,
+                        nsIFile** extraFile)
+{
+  return false;
+}
+
+bool
+AppendExtraData(const nsAString& id,
+                const AnnotationTable& data)
+{
+  return false;
+}
+
+bool
+AppendExtraData(nsIFile* extraFile,
+                const AnnotationTable& data)
+{
+  return false;
+}
+
+void
+OOPInit()
+{
+}
+
+void
+GetChildProcessTmpDir(nsIFile** aOutTmpDir)
+{
+}
+
+#if defined(XP_WIN) || defined(XP_MACOSX)
+const char*
+GetChildNotificationPipe()
+{
+  return nullptr;
+}
+#endif
+
+#ifdef MOZ_CRASHREPORTER_INJECTOR
+void
+InjectCrashReporterIntoProcess(DWORD processID, InjectorCrashCallback* cb)
+{
+}
+
+void
+UnregisterInjectorCallback(DWORD processID)
+{
+}
+
+#endif // MOZ_CRASHREPORTER_INJECTOR
+
+bool
+GetLastRunCrashID(nsAString& id)
+{
+  return false;
+}
+
+#if defined(XP_WIN) || defined(XP_MACOSX)
+void
+InitChildProcessTmpDir(nsIFile* aDirOverride)
+{
+}
+#endif // defined(XP_WIN) || defined(XP_MACOSX)
+
+#if defined(XP_WIN)
+bool
+SetRemoteExceptionHandler(const nsACString& crashPipe)
+{
+  return false;
+}
+
+#elif defined(XP_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
+
+bool
+CreateNotificationPipeForChild(int* childCrashFd, int* childCrashRemapFd)
+{
+  return false;
+}
+
+bool
+SetRemoteExceptionHandler()
+{
+  return false;
+}
+
+#elif defined(XP_MACOSX)
+
+bool
+SetRemoteExceptionHandler(const nsACString& crashPipe)
+{
+  return false;
+}
+#endif  // XP_WIN
+
+bool
+TakeMinidumpForChild(uint32_t childPid, nsIFile** dump, uint32_t* aSequence)
+{
+  return false;
+}
+
+void
+RenameAdditionalHangMinidump(nsIFile* minidump, nsIFile* childMinidump,
+                             const nsACString& name)
+{
+}
+
+ThreadId
+CurrentThreadId()
+{
+  return -1;
+}
+
+bool
+TakeMinidump(nsIFile** aResult, bool aMoveToPending)
+{
+  return false;
+}
+
+void
+CreateMinidumpsAndPair(ProcessHandle aTargetPid,
+                       ThreadId aTargetBlamedThread,
+                       const nsACString& aIncomingPairName,
+                       nsIFile* aIncomingDumpToPair,
+                       nsIFile** aMainDumpOut,
+                       std::function<void(bool)>&& aCallback,
+                       bool aAsync)
+{
+}
+
+bool
+CreateAdditionalChildMinidump(ProcessHandle childPid,
+                              ThreadId childBlamedThread,
+                              nsIFile* parentMinidump,
+                              const nsACString& name)
+{
+  return false;
+}
+
+bool
+UnsetRemoteExceptionHandler()
+{
+  return false;
+}
+
+#if defined(MOZ_WIDGET_ANDROID)
+void
+SetNotificationPipeForChild(int childCrashFd)
+{
+}
+
+void
+AddLibraryMapping(const char* library_name,
+                  uintptr_t   start_address,
+                  size_t      mapping_length,
+                  size_t      file_offset)
+{
+}
+#endif
+
+// From ThreadAnnotation.cpp
+
+void
+InitThreadAnnotation()
+{
+}
+
+void
+SetCurrentThreadName(const char* aName)
+{
+}
+
+void
+GetFlatThreadAnnotation(const std::function<void(const char*)>& aCallback)
+{
+}
+
+void
+ShutdownThreadAnnotation()
+{
+}
+
+} // namespace CrashReporter
--- a/toolkit/crashreporter/nsExceptionHandler.cpp
+++ b/toolkit/crashreporter/nsExceptionHandler.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsExceptionHandler.h"
+#include "nsExceptionHandlerUtils.h"
 
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsDirectoryService.h"
 #include "nsDataHashtable.h"
 #include "mozilla/ArrayUtils.h"
 #include "mozilla/Services.h"
 #include "nsIObserverService.h"
@@ -82,17 +83,16 @@ using mozilla::InjectCrashRunnable;
 #include <prio.h>
 #include "mozilla/Mutex.h"
 #include "nsDebug.h"
 #include "nsCRT.h"
 #include "nsIFile.h"
 #include <map>
 #include <vector>
 
-#include "mozilla/double-conversion.h"
 #include "mozilla/IOInterposer.h"
 #include "mozilla/mozalloc_oom.h"
 #include "mozilla/WindowsDllBlocklist.h"
 
 #if defined(XP_MACOSX)
 CFStringRef reporterClientAppID = CFSTR("org.mozilla.crashreporter");
 #endif
 #if defined(MOZ_WIDGET_ANDROID)
@@ -408,64 +408,16 @@ typedef struct {
   size_t      length;
   size_t      file_offset;
 } mapping_info;
 static std::vector<mapping_info> library_mappings;
 typedef std::map<uint32_t,google_breakpad::MappingList> MappingMap;
 #endif
 }
 
-// Format a non-negative double to a string, without using C-library functions,
-// which need to be avoided (.e.g. bug 1240160, comment 10).  Leave the utility
-// non-file static so that we can gtest it.  Return false if we failed to
-// get the formatting done correctly.
-bool SimpleNoCLibDtoA(double aValue, char* aBuffer, int aBufferLength)
-{
-  // aBufferLength is the size of the buffer.  Be paranoid.
-  aBuffer[aBufferLength-1] = '\0';
-
-  if (aValue < 0) {
-    return false;
-  }
-
-  int length, point, i;
-  bool sign;
-  bool ok = true;
-  double_conversion::DoubleToStringConverter::DoubleToAscii(
-                                     aValue,
-                                     double_conversion::DoubleToStringConverter::SHORTEST,
-                                     8,
-                                     aBuffer,
-                                     aBufferLength,
-                                     &sign,
-                                     &length,
-                                     &point);
-
-  // length does not account for the 0 terminator.
-  if (length > point && (length+1) < (aBufferLength-1)) {
-    // We have to insert a decimal point.  Not worried about adding a leading zero
-    // in the < 1 (point == 0) case.
-    aBuffer[length+1] = '\0';
-    for (i=length; i>point; i-=1) {
-      aBuffer[i] = aBuffer[i-1];
-    }
-    aBuffer[i] = '.'; // Not worried about locales
-  } else if (length < point) {
-    // Trailing zeros scenario
-    for (i=length; i<point; i+=1) {
-      if (i >= aBufferLength-2) {
-        ok = false;
-      }
-      aBuffer[i] = '0';
-    }
-    aBuffer[i] = '\0';
-  }
-  return ok;
-}
-
 namespace CrashReporter {
 
 #ifdef XP_LINUX
 static inline void
 my_inttostring(intmax_t t, char* buffer, size_t buffer_length)
 {
   my_memset(buffer, 0, buffer_length);
   my_uitos(buffer, t, my_uint_len(t));
--- a/toolkit/crashreporter/nsExceptionHandler.h
+++ b/toolkit/crashreporter/nsExceptionHandler.h
@@ -1,13 +1,19 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+// This header has two implementations, the real one in nsExceptionHandler.cpp
+// and a dummy in nsDummyExceptionHandler.cpp. The latter is used in builds
+// configured with --disable-crashreporter. If you add or remove a function
+// from this header you must update both implementations otherwise you'll break
+// builds that disable the crash reporter.
+
 #ifndef nsExceptionHandler_h__
 #define nsExceptionHandler_h__
 
 #include "mozilla/Assertions.h"
 
 #include <functional>
 #include <stddef.h>
 #include <stdint.h>
@@ -29,16 +35,29 @@
 #include <signal.h>
 #endif
 
 class nsIFile;
 template<class KeyClass, class DataType> class nsDataHashtable;
 class nsCStringHashKey;
 
 namespace CrashReporter {
+
+/**
+ * Returns true if the crash reporter is using the dummy implementation.
+ */
+static inline bool
+IsDummy() {
+#ifdef MOZ_CRASHREPORTER
+  return false;
+#else
+  return true;
+#endif
+}
+
 nsresult SetExceptionHandler(nsIFile* aXREDirectory, bool force=false);
 nsresult UnsetExceptionHandler();
 
 /**
  * Tell the crash reporter to recalculate where crash events files should go.
  * SetCrashEventsDir is used before XPCOM is initialized from the startup
  * code.
  *
@@ -243,17 +262,17 @@ public:
 void InjectCrashReporterIntoProcess(DWORD processID, InjectorCrashCallback* cb);
 void UnregisterInjectorCallback(DWORD processID);
 #endif
 
 // Child-side API
 bool SetRemoteExceptionHandler(const nsACString& crashPipe);
 void InitChildProcessTmpDir(nsIFile* aDirOverride = nullptr);
 
-#  elif defined(XP_LINUX)
+#  elif defined(XP_LINUX) || defined(OS_BSD) || defined(OS_SOLARIS)
 // Parent-side API for children
 
 // Set the outparams for crash reporter server's fd (|childCrashFd|)
 // and the magic fd number it should be remapped to
 // (|childCrashRemapFd|) before exec() in the child process.
 // |SetRemoteExceptionHandler()| in the child process expects to find
 // the server at |childCrashRemapFd|.  Return true iff successful.
 //
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/nsExceptionHandlerUtils.cpp
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsExceptionHandlerUtils.h"
+
+#include "mozilla/double-conversion.h"
+
+// Format a non-negative double to a string, without using C-library functions,
+// which need to be avoided (.e.g. bug 1240160, comment 10).  Return false if
+// we failed to get the formatting done correctly.
+bool SimpleNoCLibDtoA(double aValue, char* aBuffer, int aBufferLength)
+{
+  // aBufferLength is the size of the buffer.  Be paranoid.
+  aBuffer[aBufferLength-1] = '\0';
+
+  if (aValue < 0) {
+    return false;
+  }
+
+  int length, point, i;
+  bool sign;
+  bool ok = true;
+  double_conversion::DoubleToStringConverter::DoubleToAscii(
+                                     aValue,
+                                     double_conversion::DoubleToStringConverter::SHORTEST,
+                                     8,
+                                     aBuffer,
+                                     aBufferLength,
+                                     &sign,
+                                     &length,
+                                     &point);
+
+  // length does not account for the 0 terminator.
+  if (length > point && (length+1) < (aBufferLength-1)) {
+    // We have to insert a decimal point.  Not worried about adding a leading zero
+    // in the < 1 (point == 0) case.
+    aBuffer[length+1] = '\0';
+    for (i=length; i>point; i-=1) {
+      aBuffer[i] = aBuffer[i-1];
+    }
+    aBuffer[i] = '.'; // Not worried about locales
+  } else if (length < point) {
+    // Trailing zeros scenario
+    for (i=length; i<point; i+=1) {
+      if (i >= aBufferLength-2) {
+        ok = false;
+      }
+      aBuffer[i] = '0';
+    }
+    aBuffer[i] = '\0';
+  }
+  return ok;
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/crashreporter/nsExceptionHandlerUtils.h
@@ -0,0 +1,12 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsExceptionHandlerUtils_h__
+#define nsExceptionHandlerUtils_h__
+
+bool SimpleNoCLibDtoA(double aValue, char* aBuffer, int aBufferLength);
+
+#endif // nsExceptionHandlerUtils_h__
--- a/toolkit/moz.build
+++ b/toolkit/moz.build
@@ -2,16 +2,17 @@
 # vim: set filetype=python:
 # This Source Code Form is subject to the terms of the Mozilla Public
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DIRS += [
     'components',
     'content',
+    'crashreporter',
     'forgetaboutsite',
     'locales',
     'modules',
     'mozapps/downloads',
     'mozapps/extensions',
     'mozapps/handling',
     'mozapps/preferences',
     'pluginproblem',
@@ -41,19 +42,16 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk
     DIRS += ['system/unixproxy']
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     DIRS += ['system/osxproxy']
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     DIRS += ['system/windowsproxy']
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
     DIRS += ['system/androidproxy']
 
-if CONFIG['MOZ_CRASHREPORTER']:
-    DIRS += ['crashreporter']
-
 TEST_HARNESS_FILES.testing.mochitest.browser.toolkit.crashreporter.test.browser += [
     'crashreporter/test/browser/crashreport.sjs',
 ]
 
 with Files('moz.*'):
     BUG_COMPONENT = ('Core', 'Build Config')
 
 with Files('toolkit.mozbuild'):