diff --git a/accessible/base/nsAccessibilityService.cpp b/accessible/base/nsAccessibilityService.cpp index 26f2c774c92e..c96879cbafcb 100644 --- a/accessible/base/nsAccessibilityService.cpp +++ b/accessible/base/nsAccessibilityService.cpp @@ -1393,7 +1393,7 @@ nsAccessibilityService::Init() gApplicationAccessible->Init(); CrashReporter:: - AnnotateCrashReport(NS_LITERAL_CSTRING("Accessibility"), + AnnotateCrashReport(CrashReporter::Annotation::Accessibility, NS_LITERAL_CSTRING("Active")); #ifdef XP_WIN diff --git a/accessible/windows/msaa/Compatibility.cpp b/accessible/windows/msaa/Compatibility.cpp index f4434f37c0b5..723ec10165f2 100644 --- a/accessible/windows/msaa/Compatibility.cpp +++ b/accessible/windows/msaa/Compatibility.cpp @@ -242,7 +242,7 @@ Compatibility::Init() InitConsumers(); CrashReporter:: - AnnotateCrashReport(NS_LITERAL_CSTRING("AccessibilityInProcClient"), + AnnotateCrashReport(CrashReporter::Annotation::AccessibilityInProcClient, nsPrintfCString("0x%X", sConsumers)); // Gather telemetry @@ -436,8 +436,9 @@ UseIAccessibleProxyStub() // If we reach this point then something is seriously wrong with the // IAccessible configuration in the computer's registry. Let's annotate this // so that we can easily determine this condition during crash analysis. - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IAccessibleConfig"), - NS_LITERAL_CSTRING("NoSystemTypeLibOrPS")); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::IAccessibleConfig, + NS_LITERAL_CSTRING("NoSystemTypeLibOrPS")); return false; } diff --git a/accessible/windows/msaa/LazyInstantiator.cpp b/accessible/windows/msaa/LazyInstantiator.cpp index 608812ebcb1f..64b8f8567a8b 100644 --- a/accessible/windows/msaa/LazyInstantiator.cpp +++ b/accessible/windows/msaa/LazyInstantiator.cpp @@ -17,7 +17,6 @@ #include "nsAccessibilityService.h" #include "nsWindowsHelpers.h" #include "nsCOMPtr.h" -#include "nsExceptionHandler.h" #include "nsIFile.h" #include "nsXPCOM.h" #include "RootAccessibleWrap.h" diff --git a/accessible/windows/msaa/Platform.cpp b/accessible/windows/msaa/Platform.cpp index e21ce86bbb9c..2fb785fde307 100644 --- a/accessible/windows/msaa/Platform.cpp +++ b/accessible/windows/msaa/Platform.cpp @@ -358,7 +358,7 @@ AccumulateInstantiatorTelemetry(const nsAString& aValue) #endif // defined(MOZ_TELEMETRY_REPORTING) #if defined(MOZ_CRASHREPORTER) CrashReporter:: - AnnotateCrashReport(NS_LITERAL_CSTRING("AccessibilityClient"), + AnnotateCrashReport(CrashReporter::Annotation::AccessibilityClient, NS_ConvertUTF16toUTF8(aValue)); #endif // defined(MOZ_CRASHREPORTER) } diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index 7489a70391dc..35ae80f88134 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -1700,8 +1700,8 @@ NS_IMETHODIMP nsDocShell::SetRemoteTabs(bool aUseRemoteTabs) { if (aUseRemoteTabs) { - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("DOMIPCEnabled"), - NS_LITERAL_CSTRING("1")); + CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::DOMIPCEnabled, + true); } mUseRemoteTabs = aUseRemoteTabs; diff --git a/dom/events/TouchEvent.cpp b/dom/events/TouchEvent.cpp index 3d037cf76377..fab88a848087 100644 --- a/dom/events/TouchEvent.cpp +++ b/dom/events/TouchEvent.cpp @@ -276,10 +276,8 @@ TouchEvent::PrefEnabled(nsIDocShell* aDocShell) // The touch screen data seems to be inaccurate in the parent process, // and we really need the crash annotation in child processes. if (firstTime && !XRE_IsParentProcess()) { - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("HasDeviceTouchScreen"), - enabled ? - NS_LITERAL_CSTRING("1") : - NS_LITERAL_CSTRING("0")); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::HasDeviceTouchScreen, enabled); firstTime = false; } diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index 84a59e7d3055..fdbf1ff690d5 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -1777,16 +1777,13 @@ ContentChild::RecvSetProcessSandbox(const MaybeFileDesc& aBroker) #endif CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("ContentSandboxEnabled"), - sandboxEnabled? NS_LITERAL_CSTRING("1") : NS_LITERAL_CSTRING("0")); + CrashReporter::Annotation::ContentSandboxEnabled, sandboxEnabled); #if defined(XP_LINUX) && !defined(OS_ANDROID) - nsAutoCString flagsString; - flagsString.AppendInt(SandboxInfo::Get().AsInteger()); - CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("ContentSandboxCapabilities"), flagsString); + CrashReporter::Annotation::ContentSandboxCapabilities, + static_cast(SandboxInfo::Get().AsInteger())); #endif /* XP_LINUX && !OS_ANDROID */ - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("RemoteType"), + CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::RemoteType, NS_ConvertUTF16toUTF8(GetRemoteType())); #endif /* MOZ_CONTENT_SANDBOX */ @@ -2448,7 +2445,8 @@ ContentChild::ProcessingError(Result aCode, const char* aReason) } nsDependentCString reason(aReason); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ipc_channel_error"), reason); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::ipc_channel_error, reason); MOZ_CRASH("Content child abort due to IPC error"); } @@ -3123,8 +3121,9 @@ ContentChild::ShutdownInternal() // to wait for that event loop to finish. Otherwise we could prematurely // terminate an "unload" or "pagehide" event handler (which might be doing a // sync XHR, for example). - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCShutdownState"), - NS_LITERAL_CSTRING("RecvShutdown")); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::IPCShutdownState, + NS_LITERAL_CSTRING("RecvShutdown")); MOZ_ASSERT(NS_IsMainThread()); RefPtr mainThread = nsThreadManager::get().GetCurrentThread(); @@ -3182,10 +3181,11 @@ ContentChild::ShutdownInternal() // parent closes. StartForceKillTimer(); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCShutdownState"), - NS_LITERAL_CSTRING("SendFinishShutdown (sending)")); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::IPCShutdownState, + NS_LITERAL_CSTRING("SendFinishShutdown (sending)")); bool sent = SendFinishShutdown(); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCShutdownState"), + CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::IPCShutdownState, sent ? NS_LITERAL_CSTRING("SendFinishShutdown (sent)") : NS_LITERAL_CSTRING("SendFinishShutdown (failed)")); } diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 356eca614184..ddc7fece3931 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -3370,13 +3370,11 @@ ContentParent::KillHard(const char* aReason) // minidump tagging along, so we have to tell the crash reporter that // it exists and is being appended. nsAutoCString additionalDumps("browser"); - mCrashReporter->AddNote( - NS_LITERAL_CSTRING("additional_minidumps"), - additionalDumps); + mCrashReporter->AddAnnotation( + CrashReporter::Annotation::additional_minidumps, additionalDumps); nsDependentCString reason(aReason); - mCrashReporter->AddNote( - NS_LITERAL_CSTRING("ipc_channel_error"), - reason); + mCrashReporter->AddAnnotation(CrashReporter::Annotation::ipc_channel_error, + reason); Telemetry::Accumulate(Telemetry::SUBPROCESS_KILL_HARD, reason, 1); diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index cb2531d44335..a8e582806a4b 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -1163,7 +1163,7 @@ TabChild::RecvLoadURL(const nsCString& aURI, NS_WARNING("WebNavigation()->LoadURI failed. Eating exception, what else can I do?"); } - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("URL"), aURI); + CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::URL, aURI); return IPC_OK(); } diff --git a/dom/media/gmp/GMPChild.cpp b/dom/media/gmp/GMPChild.cpp index 65b0b96c1508..69f87afad8ae 100644 --- a/dom/media/gmp/GMPChild.cpp +++ b/dom/media/gmp/GMPChild.cpp @@ -560,8 +560,9 @@ GMPChild::AnswerStartPlugin(const nsString& aAdapter) nsCString libPath; if (!GetUTF8LibPath(libPath)) { - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("GMPLibraryPath"), - NS_ConvertUTF16toUTF8(mPluginPath)); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::GMPLibraryPath, + NS_ConvertUTF16toUTF8(mPluginPath)); #ifdef XP_WIN return IPC_FAIL( @@ -615,8 +616,9 @@ GMPChild::AnswerStartPlugin(const nsString& aAdapter) adapter)) { NS_WARNING("Failed to load GMP"); delete platformAPI; - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("GMPLibraryPath"), - NS_ConvertUTF16toUTF8(mPluginPath)); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::GMPLibraryPath, + NS_ConvertUTF16toUTF8(mPluginPath)); #ifdef XP_WIN return IPC_FAIL( diff --git a/dom/media/gmp/GMPParent.cpp b/dom/media/gmp/GMPParent.cpp index 140b6e2e310f..0326c36b6703 100644 --- a/dom/media/gmp/GMPParent.cpp +++ b/dom/media/gmp/GMPParent.cpp @@ -463,10 +463,13 @@ GMPParent::EnsureProcessLoaded() void GMPParent::WriteExtraDataForMinidump() { - mCrashReporter->AddNote(NS_LITERAL_CSTRING("GMPPlugin"), NS_LITERAL_CSTRING("1")); - mCrashReporter->AddNote(NS_LITERAL_CSTRING("PluginFilename"), NS_ConvertUTF16toUTF8(mName)); - mCrashReporter->AddNote(NS_LITERAL_CSTRING("PluginName"), mDisplayName); - mCrashReporter->AddNote(NS_LITERAL_CSTRING("PluginVersion"), mVersion); + mCrashReporter->AddAnnotation(CrashReporter::Annotation::GMPPlugin, true); + mCrashReporter->AddAnnotation(CrashReporter::Annotation::PluginFilename, + NS_ConvertUTF16toUTF8(mName)); + mCrashReporter->AddAnnotation(CrashReporter::Annotation::PluginName, + mDisplayName); + mCrashReporter->AddAnnotation(CrashReporter::Annotation::PluginVersion, + mVersion); } bool diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp index 4fbfa83c77d4..9d879d98c48c 100644 --- a/dom/plugins/base/nsPluginHost.cpp +++ b/dom/plugins/base/nsPluginHost.cpp @@ -11,7 +11,6 @@ #include #include #include "prio.h" -#include "nsExceptionHandler.h" #include "nsNPAPIPlugin.h" #include "nsNPAPIPluginStreamListener.h" #include "nsNPAPIPluginInstance.h" diff --git a/dom/plugins/base/nsPluginsDirDarwin.cpp b/dom/plugins/base/nsPluginsDirDarwin.cpp index ba774197a7a0..9f47961a5e92 100644 --- a/dom/plugins/base/nsPluginsDirDarwin.cpp +++ b/dom/plugins/base/nsPluginsDirDarwin.cpp @@ -410,28 +410,6 @@ nsresult nsPluginFile::GetPluginInfo(nsPluginInfo& info, PRLibrary **outLibrary) return NS_OK; } - // Don't load "fbplugin" or any plugins whose name starts with "fbplugin_" - // (Facebook plugins) if we're running on OS X 10.10 (Yosemite) or later. - // A "fbplugin" file crashes on load, in the call to LoadPlugin() below. - // See bug 1086977. - if (nsCocoaFeatures::OnYosemiteOrLater()) { - if (fileName.EqualsLiteral("fbplugin") || - StringBeginsWith(fileName, NS_LITERAL_CSTRING("fbplugin_"))) { - nsAutoCString msg; - msg.AppendPrintf("Preventing load of %s (see bug 1086977)", - fileName.get()); - NS_WARNING(msg.get()); - return NS_ERROR_FAILURE; - } - - // The block above assumes that "fbplugin" is the filename of the plugin - // to be blocked, or that the filename starts with "fbplugin_". But we - // don't yet know for sure if this is always true. So for the time being - // record extra information in our crash logs. - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Bug_1086977"), - fileName); - } - // It's possible that our plugin has 2 entry points that'll give us mime type // info. Quicktime does this to get around the need of having admin rights to // change mime info in the resource fork. We need to use this info instead of @@ -440,13 +418,6 @@ nsresult nsPluginFile::GetPluginInfo(nsPluginInfo& info, PRLibrary **outLibrary) // Sadly we have to load the library for this to work. rv = LoadPlugin(outLibrary); - if (nsCocoaFeatures::OnYosemiteOrLater()) { - // If we didn't crash in LoadPlugin(), change the previous annotation so we - // don't sow confusion. - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Bug_1086977"), - NS_LITERAL_CSTRING("Didn't crash, please ignore")); - } - if (NS_FAILED(rv)) return rv; diff --git a/dom/plugins/ipc/PluginMessageUtils.h b/dom/plugins/ipc/PluginMessageUtils.h index ed3957d9e7cc..c2d5b8bd9949 100644 --- a/dom/plugins/ipc/PluginMessageUtils.h +++ b/dom/plugins/ipc/PluginMessageUtils.h @@ -23,7 +23,6 @@ #include "nsString.h" #include "nsTArray.h" #include "mozilla/Logging.h" -#include "nsExceptionHandler.h" #include "nsHashKeys.h" #ifdef XP_MACOSX diff --git a/dom/plugins/ipc/PluginModuleParent.cpp b/dom/plugins/ipc/PluginModuleParent.cpp index b3508712b89b..f98ad981ce2e 100644 --- a/dom/plugins/ipc/PluginModuleParent.cpp +++ b/dom/plugins/ipc/PluginModuleParent.cpp @@ -738,26 +738,36 @@ PluginModuleChromeParent::WriteExtraDataForMinidump() filePos = 0; else filePos++; - mCrashReporter->AddNote(NS_LITERAL_CSTRING("PluginFilename"), cstring(pluginFile.substr(filePos).c_str())); - - mCrashReporter->AddNote(NS_LITERAL_CSTRING("PluginName"), mPluginName); - mCrashReporter->AddNote(NS_LITERAL_CSTRING("PluginVersion"), mPluginVersion); + mCrashReporter->AddAnnotation(CrashReporter::Annotation::PluginFilename, + cstring(pluginFile.substr(filePos).c_str())); + mCrashReporter->AddAnnotation(CrashReporter::Annotation::PluginName, + mPluginName); + mCrashReporter->AddAnnotation(CrashReporter::Annotation::PluginVersion, + mPluginVersion); if (mCrashReporter) { #ifdef XP_WIN if (mPluginCpuUsageOnHang.Length() > 0) { - mCrashReporter->AddNote(NS_LITERAL_CSTRING("NumberOfProcessors"), - nsPrintfCString("%d", PR_GetNumberOfProcessors())); + mCrashReporter->AddAnnotation( + CrashReporter::Annotation::NumberOfProcessors, + PR_GetNumberOfProcessors()); nsCString cpuUsageStr; cpuUsageStr.AppendFloat(std::ceil(mPluginCpuUsageOnHang[0] * 100) / 100); - mCrashReporter->AddNote(NS_LITERAL_CSTRING("PluginCpuUsage"), cpuUsageStr); + mCrashReporter->AddAnnotation( + CrashReporter::Annotation::PluginCpuUsage, + cpuUsageStr); #ifdef MOZ_CRASHREPORTER_INJECTOR - for (uint32_t i=1; iAddNote(nsPrintfCString("CpuUsageFlashProcess%d", i), tempStr); + // HACK: There can only be at most two flash processes hence + // the hardcoded annotations + CrashReporter::Annotation annotation = + (i == 1) ? CrashReporter::Annotation::CpuUsageFlashProcess1 + : CrashReporter::Annotation::CpuUsageFlashProcess2; + mCrashReporter->AddAnnotation(annotation, tempStr); } #endif } @@ -1244,8 +1254,8 @@ PluginModuleChromeParent::OnTakeFullMinidumpComplete(bool aReportsReady, } } } - mCrashReporter->AddNote(NS_LITERAL_CSTRING("additional_minidumps"), - additionalDumps); + mCrashReporter->AddAnnotation(Annotation::additional_minidumps, + additionalDumps); mTakeFullMinidumpCallback.Invoke(mCrashReporter->MinidumpID()); } else { @@ -1306,18 +1316,15 @@ PluginModuleChromeParent::TerminateChildProcessOnDumpComplete(MessageLoop* aMsgL mTerminateChildProcessCallback.Invoke(true); return; } - mCrashReporter->AddNote(NS_LITERAL_CSTRING("PluginHang"), - NS_LITERAL_CSTRING("1")); - mCrashReporter->AddNote(NS_LITERAL_CSTRING("HangMonitorDescription"), - aMonitorDescription); + mCrashReporter->AddAnnotation(Annotation::PluginHang, true); + mCrashReporter->AddAnnotation(Annotation::HangMonitorDescription, + aMonitorDescription); #ifdef XP_WIN if (mHangUIParent) { unsigned int hangUIDuration = mHangUIParent->LastShowDurationMs(); if (hangUIDuration) { - nsPrintfCString strHangUIDuration("%u", hangUIDuration); - mCrashReporter->AddNote( - NS_LITERAL_CSTRING("PluginHangUIDuration"), - strHangUIDuration); + mCrashReporter->AddAnnotation(Annotation::PluginHangUIDuration, + hangUIDuration); } } #endif // XP_WIN @@ -1583,7 +1590,8 @@ PluginModuleChromeParent::ProcessFirstMinidump() NS_ConvertUTF16toUTF8(mCrashReporter->MinidumpID()).get())); if (!flashProcessType.IsEmpty()) { - mCrashReporter->AddNote(NS_LITERAL_CSTRING("FlashProcessDump"), flashProcessType); + mCrashReporter->AddAnnotation(Annotation::FlashProcessDump, + flashProcessType); } mCrashReporter->FinalizeCrashReport(); } diff --git a/gfx/ipc/GPUProcessManager.cpp b/gfx/ipc/GPUProcessManager.cpp index 9fc0a9370e7c..f635dbe1d227 100644 --- a/gfx/ipc/GPUProcessManager.cpp +++ b/gfx/ipc/GPUProcessManager.cpp @@ -380,12 +380,11 @@ GPUProcessManager::OnProcessLaunchComplete(GPUProcessHost* aHost) mGPUChild->SendInitVsyncBridge(std::move(vsyncParent)); CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("GPUProcessStatus"), - NS_LITERAL_CSTRING("Running")); + CrashReporter::Annotation::GPUProcessStatus, NS_LITERAL_CSTRING("Running")); CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("GPUProcessLaunchCount"), - nsPrintfCString("%d", mNumProcessAttempts)); + CrashReporter::Annotation::GPUProcessLaunchCount, + static_cast(mNumProcessAttempts)); } static bool @@ -727,7 +726,7 @@ GPUProcessManager::DestroyProcess() } CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("GPUProcessStatus"), + CrashReporter::Annotation::GPUProcessStatus, NS_LITERAL_CSTRING("Destroyed")); } diff --git a/gfx/src/DriverCrashGuard.cpp b/gfx/src/DriverCrashGuard.cpp index 6763114a0db2..b923e1a4634a 100644 --- a/gfx/src/DriverCrashGuard.cpp +++ b/gfx/src/DriverCrashGuard.cpp @@ -165,9 +165,8 @@ DriverCrashGuard::~DriverCrashGuard() dom::ContentChild::GetSingleton()->SendEndDriverCrashGuard(uint32_t(mType)); } - // Remove the crash report annotation. - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("GraphicsStartupTest"), - NS_LITERAL_CSTRING("")); + CrashReporter::RemoveCrashReportAnnotation( + CrashReporter::Annotation::GraphicsStartupTest); } bool @@ -210,8 +209,8 @@ DriverCrashGuard::ActivateGuard() // attribute a random parent process crash to a graphics problem in a child // process. if (mMode != Mode::Proxy) { - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("GraphicsStartupTest"), - NS_LITERAL_CSTRING("1")); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::GraphicsStartupTest, true); } // If we're in the content process, the rest of the guarding is handled diff --git a/gfx/thebes/DeviceManagerDx.cpp b/gfx/thebes/DeviceManagerDx.cpp index 189707ac752e..2dcf71515685 100644 --- a/gfx/thebes/DeviceManagerDx.cpp +++ b/gfx/thebes/DeviceManagerDx.cpp @@ -885,10 +885,8 @@ DeviceManagerDx::MaybeResetAndReacquireDevices() Telemetry::Accumulate(Telemetry::DEVICE_RESET_REASON, uint32_t(resetReason)); } - nsPrintfCString reasonString("%d", int(resetReason)); CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("DeviceResetReason"), - reasonString); + CrashReporter::Annotation::DeviceResetReason, int(resetReason)); bool createCompositorDevice = !!mCompositorDevice; bool createContentDevice = !!mContentDevice; diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 9b4ea9a24a32..6e8fc0d77402 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -199,7 +199,7 @@ public: class CrashStatsLogForwarder: public mozilla::gfx::LogForwarder { public: - explicit CrashStatsLogForwarder(const char* aKey); + explicit CrashStatsLogForwarder(CrashReporter::Annotation aKey); void Log(const std::string& aString) override; void CrashAction(LogReason aReason) override; bool UpdateStringsVector(const std::string& aString) override; @@ -214,13 +214,13 @@ private: private: LoggingRecord mBuffer; - nsCString mCrashCriticalKey; + CrashReporter::Annotation mCrashCriticalKey; uint32_t mMaxCapacity; int32_t mIndex; Mutex mMutex; }; -CrashStatsLogForwarder::CrashStatsLogForwarder(const char* aKey) +CrashStatsLogForwarder::CrashStatsLogForwarder(CrashReporter::Annotation aKey) : mBuffer() , mCrashCriticalKey(aKey) , mMaxCapacity(0) @@ -298,11 +298,13 @@ void CrashStatsLogForwarder::UpdateCrashReport() } nsCString reportString(message.str().c_str()); - nsresult annotated = CrashReporter::AnnotateCrashReport(mCrashCriticalKey, reportString); + nsresult annotated = CrashReporter::AnnotateCrashReport(mCrashCriticalKey, + reportString); if (annotated != NS_OK) { printf("Crash Annotation %s: %s", - mCrashCriticalKey.get(), message.str().c_str()); + CrashReporter::AnnotationToString(mCrashCriticalKey), + message.str().c_str()); } } @@ -922,7 +924,8 @@ gfxPlatform::MaxAllocSize() /* static */ void gfxPlatform::InitMoz2DLogging() { - auto fwd = new CrashStatsLogForwarder("GraphicsCriticalError"); + auto fwd = new CrashStatsLogForwarder( + CrashReporter::Annotation::GraphicsCriticalError); fwd->SetCircularBufferSize(gfxPrefs::GfxLoggingCrashLength()); mozilla::gfx::Config cfg; diff --git a/ipc/chromium/src/chrome/common/ipc_channel_posix.cc b/ipc/chromium/src/chrome/common/ipc_channel_posix.cc index 1a972f266c30..4fa5f5439649 100644 --- a/ipc/chromium/src/chrome/common/ipc_channel_posix.cc +++ b/ipc/chromium/src/chrome/common/ipc_channel_posix.cc @@ -248,13 +248,15 @@ bool Channel::ChannelImpl::CreatePipe(const std::wstring& channel_id, if (mode == MODE_SERVER) { int pipe_fds[2]; if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds) != 0) { - mozilla::ipc::AnnotateCrashReportWithErrno("IpcCreatePipeSocketPairErrno", errno); + mozilla::ipc::AnnotateCrashReportWithErrno( + CrashReporter::Annotation::IpcCreatePipeSocketPairErrno, errno); return false; } // Set both ends to be non-blocking. if (fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK) == -1 || fcntl(pipe_fds[1], F_SETFL, O_NONBLOCK) == -1) { - mozilla::ipc::AnnotateCrashReportWithErrno("IpcCreatePipeFcntlErrno", errno); + mozilla::ipc::AnnotateCrashReportWithErrno( + CrashReporter::Annotation::IpcCreatePipeFcntlErrno, errno); IGNORE_EINTR(close(pipe_fds[0])); IGNORE_EINTR(close(pipe_fds[1])); return false; @@ -262,7 +264,8 @@ bool Channel::ChannelImpl::CreatePipe(const std::wstring& channel_id, if (!SetCloseOnExec(pipe_fds[0]) || !SetCloseOnExec(pipe_fds[1])) { - mozilla::ipc::AnnotateCrashReportWithErrno("IpcCreatePipeCloExecErrno", errno); + mozilla::ipc::AnnotateCrashReportWithErrno( + CrashReporter::Annotation::IpcCreatePipeCloExecErrno, errno); IGNORE_EINTR(close(pipe_fds[0])); IGNORE_EINTR(close(pipe_fds[1])); return false; diff --git a/ipc/glue/CrashReporterClient.cpp b/ipc/glue/CrashReporterClient.cpp index 004ca3b57448..2e52f0080b9d 100644 --- a/ipc/glue/CrashReporterClient.cpp +++ b/ipc/glue/CrashReporterClient.cpp @@ -26,7 +26,8 @@ CrashReporterClient::~CrashReporterClient() } void -CrashReporterClient::AnnotateCrashReport(const nsCString& aKey, const nsCString& aData) +CrashReporterClient::AnnotateCrashReport(CrashReporter::Annotation aKey, + const nsCString& aData) { StaticMutexAutoLock lock(sLock); mMetadata->AnnotateCrashReport(aKey, aData); diff --git a/ipc/glue/CrashReporterClient.h b/ipc/glue/CrashReporterClient.h index 12da1ab38108..37c4534e8961 100644 --- a/ipc/glue/CrashReporterClient.h +++ b/ipc/glue/CrashReporterClient.h @@ -65,7 +65,8 @@ public: static void DestroySingleton(); static RefPtr GetSingleton(); - void AnnotateCrashReport(const nsCString& aKey, const nsCString& aData); + void AnnotateCrashReport(CrashReporter::Annotation aKey, + const nsCString& aData); void AppendAppNotes(const nsCString& aData); private: diff --git a/ipc/glue/CrashReporterHost.cpp b/ipc/glue/CrashReporterHost.cpp index b837216cf876..0547b760f4cf 100644 --- a/ipc/glue/CrashReporterHost.cpp +++ b/ipc/glue/CrashReporterHost.cpp @@ -65,7 +65,7 @@ CrashReporterHost::FinalizeCrashReport() MOZ_ASSERT(!mFinalized); MOZ_ASSERT(HasMinidump()); - CrashReporter::AnnotationTable notes; + CrashReporter::AnnotationTable annotations; nsAutoCString type; switch (mProcessType) { @@ -83,22 +83,23 @@ CrashReporterHost::FinalizeCrashReport() NS_ERROR("unknown process type"); break; } - notes.Put(NS_LITERAL_CSTRING("ProcessType"), type); + annotations[CrashReporter::Annotation::ProcessType] = type; char startTime[32]; SprintfLiteral(startTime, "%lld", static_cast(mStartTime)); - notes.Put(NS_LITERAL_CSTRING("StartupTime"), nsDependentCString(startTime)); + annotations[CrashReporter::Annotation::StartupTime] = + nsDependentCString(startTime); // We might not have shmem (for example, when running crashreporter tests). if (mShmem.IsReadable()) { - CrashReporterMetadataShmem::ReadAppNotes(mShmem, ¬es); + CrashReporterMetadataShmem::ReadAppNotes(mShmem, annotations); } - CrashReporter::AppendExtraData(mDumpID, mExtraNotes); - CrashReporter::AppendExtraData(mDumpID, notes); + CrashReporter::AppendExtraData(mDumpID, mExtraAnnotations); + CrashReporter::AppendExtraData(mDumpID, annotations); - // Use mExtraNotes, since NotifyCrashService looks for "PluginHang" which is - // set in the parent process. - NotifyCrashService(mProcessType, mDumpID, &mExtraNotes); + // Use mExtraAnnotations, since NotifyCrashService looks for "PluginHang" + // which is set in the parent process. + NotifyCrashService(mProcessType, mDumpID, mExtraAnnotations); mFinalized = true; return true; @@ -221,11 +222,11 @@ CrashReporterHost::GenerateMinidumpAndPair(GeckoChildProcessHost* aChildProcess, /* static */ void CrashReporterHost::NotifyCrashService(GeckoProcessType aProcessType, const nsString& aChildDumpID, - const AnnotationTable* aNotes) + const AnnotationTable& aNotes) { if (!NS_IsMainThread()) { RefPtr runnable = NS_NewRunnableFunction( - "ipc::CrashReporterHost::NotifyCrashService", [=]() -> void { + "ipc::CrashReporterHost::NotifyCrashService", [&]() -> void { CrashReporterHost::NotifyCrashService( aProcessType, aChildDumpID, aNotes); }); @@ -255,9 +256,8 @@ CrashReporterHost::NotifyCrashService(GeckoProcessType aProcessType, case GeckoProcessType_Plugin: { processType = nsICrashService::PROCESS_TYPE_PLUGIN; telemetryKey.AssignLiteral("plugin"); - nsAutoCString val; - if (aNotes->Get(NS_LITERAL_CSTRING("PluginHang"), &val) && - val.EqualsLiteral("1")) { + nsCString val = aNotes[CrashReporter::Annotation::PluginHang]; + if (val.Equals(NS_LITERAL_CSTRING("1"))) { crashType = nsICrashService::CRASH_TYPE_HANG; telemetryKey.AssignLiteral("pluginhang"); } @@ -282,9 +282,35 @@ CrashReporterHost::NotifyCrashService(GeckoProcessType aProcessType, } void -CrashReporterHost::AddNote(const nsCString& aKey, const nsCString& aValue) +CrashReporterHost::AddAnnotation(CrashReporter::Annotation aKey, bool aValue) { - mExtraNotes.Put(aKey, aValue); + mExtraAnnotations[aKey] = aValue ? NS_LITERAL_CSTRING("1") + : NS_LITERAL_CSTRING("0"); +} + +void +CrashReporterHost::AddAnnotation(CrashReporter::Annotation aKey, + int aValue) +{ + nsAutoCString valueString; + valueString.AppendInt(aValue); + mExtraAnnotations[aKey] = valueString; +} + +void +CrashReporterHost::AddAnnotation(CrashReporter::Annotation aKey, + unsigned int aValue) +{ + nsAutoCString valueString; + valueString.AppendInt(aValue); + mExtraAnnotations[aKey] = valueString; +} + +void +CrashReporterHost::AddAnnotation(CrashReporter::Annotation aKey, + const nsCString& aValue) +{ + mExtraAnnotations[aKey] = aValue; } } // namespace ipc diff --git a/ipc/glue/CrashReporterHost.h b/ipc/glue/CrashReporterHost.h index 612e25e82368..261bb017115c 100644 --- a/ipc/glue/CrashReporterHost.h +++ b/ipc/glue/CrashReporterHost.h @@ -130,9 +130,12 @@ public: static void NotifyCrashService( GeckoProcessType aProcessType, const nsString& aChildDumpID, - const AnnotationTable* aNotes); + const AnnotationTable& aNotes); - void AddNote(const nsCString& aKey, const nsCString& aValue); + void AddAnnotation(CrashReporter::Annotation aKey, bool aValue); + void AddAnnotation(CrashReporter::Annotation aKey, int aValue); + void AddAnnotation(CrashReporter::Annotation aKey, unsigned int aValue); + void AddAnnotation(CrashReporter::Annotation aKey, const nsCString& aValue); bool HasMinidump() const { return !mDumpID.IsEmpty(); @@ -152,7 +155,7 @@ private: Shmem mShmem; ThreadId mThreadId; time_t mStartTime; - AnnotationTable mExtraNotes; + AnnotationTable mExtraAnnotations; nsString mDumpID; bool mFinalized; nsCOMPtr mTargetDump; diff --git a/ipc/glue/CrashReporterMetadataShmem.cpp b/ipc/glue/CrashReporterMetadataShmem.cpp index 73a0cf9ab626..6c5e0dcfcc07 100644 --- a/ipc/glue/CrashReporterMetadataShmem.cpp +++ b/ipc/glue/CrashReporterMetadataShmem.cpp @@ -6,11 +6,14 @@ #include "CrashReporterMetadataShmem.h" #include "mozilla/Attributes.h" +#include "mozilla/EnumeratedRange.h" #include "nsISupportsImpl.h" namespace mozilla { namespace ipc { +using CrashReporter::Annotation; + enum class EntryType : uint8_t { None, Annotation, @@ -28,9 +31,10 @@ CrashReporterMetadataShmem::~CrashReporterMetadataShmem() } void -CrashReporterMetadataShmem::AnnotateCrashReport(const nsCString& aKey, const nsCString& aData) +CrashReporterMetadataShmem::AnnotateCrashReport(Annotation aKey, + const nsCString& aData) { - mNotes.Put(aKey, aData); + mAnnotations[aKey] = aData; SyncNotesToShmem(); } @@ -38,7 +42,7 @@ void CrashReporterMetadataShmem::AppendAppNotes(const nsCString& aData) { mAppNotes.Append(aData); - mNotes.Put(NS_LITERAL_CSTRING("Notes"), mAppNotes); + mAnnotations[Annotation::Notes] = mAppNotes; SyncNotesToShmem(); } @@ -52,7 +56,7 @@ public: *mCursor = uint8_t(EntryType::None); } - MOZ_MUST_USE bool WriteAnnotation(const nsCString& aKey, const nsCString& aValue) { + MOZ_MUST_USE bool WriteAnnotation(Annotation aKey, const nsCString& aValue) { // This shouldn't happen because Commit() guarantees mCursor < mEnd. But // we might as well be safe. if (mCursor >= mEnd) { @@ -125,11 +129,11 @@ CrashReporterMetadataShmem::SyncNotesToShmem() { MetadataShmemWriter writer(mShmem); - for (auto it = mNotes.Iter(); !it.Done(); it.Next()) { - nsCString key = nsCString(it.Key()); - nsCString value = nsCString(it.Data()); - if (!writer.WriteAnnotation(key, value)) { - return; + for (auto key : MakeEnumeratedRange(Annotation::Count)) { + if (!mAnnotations[key].IsEmpty()) { + if (!writer.WriteAnnotation(key, mAnnotations[key])) { + return; + } } } } @@ -162,6 +166,11 @@ public: } } + template + bool Read(T* aOut) { + return Read(aOut, sizeof(T)); + } + bool Read(nsCString& aOut) { uint32_t length = 0; if (!Read(&length)) { @@ -178,10 +187,6 @@ public: } private: - template - bool Read(T* aOut) { - return Read(aOut, sizeof(T)); - } bool Read(void* aOut, size_t aLength) { const uint8_t* src = Read(aLength); if (!src) { @@ -209,17 +214,19 @@ private: }; void -CrashReporterMetadataShmem::ReadAppNotes(const Shmem& aShmem, CrashReporter::AnnotationTable* aNotes) +CrashReporterMetadataShmem::ReadAppNotes(const Shmem& aShmem, + AnnotationTable& aNotes) { for (MetadataShmemReader reader(aShmem); !reader.Done(); reader.Next()) { switch (reader.Type()) { case EntryType::Annotation: { - nsCString key, value; - if (!reader.Read(key) || !reader.Read(value)) { + Annotation key; + nsCString value; + if (!reader.Read(&key) || !reader.Read(value)) { return; } - aNotes->Put(key, value); + aNotes[key] = value; break; } default: diff --git a/ipc/glue/CrashReporterMetadataShmem.h b/ipc/glue/CrashReporterMetadataShmem.h index ba0a6373e55e..1ae8f2fb581f 100644 --- a/ipc/glue/CrashReporterMetadataShmem.h +++ b/ipc/glue/CrashReporterMetadataShmem.h @@ -25,10 +25,12 @@ public: ~CrashReporterMetadataShmem(); // Metadata writers. These must only be called in child processes. - void AnnotateCrashReport(const nsCString& aKey, const nsCString& aData); + void AnnotateCrashReport(CrashReporter::Annotation aKey, + const nsCString& aData); void AppendAppNotes(const nsCString& aData); - static void ReadAppNotes(const Shmem& aShmem, CrashReporter::AnnotationTable* aNotes); + static void ReadAppNotes(const Shmem& aShmem, + CrashReporter::AnnotationTable& aNotes); private: void SyncNotesToShmem(); @@ -36,7 +38,7 @@ private: private: Shmem mShmem; - AnnotationTable mNotes; + AnnotationTable mAnnotations; nsCString mAppNotes; }; diff --git a/ipc/glue/IPCMessageUtils.h b/ipc/glue/IPCMessageUtils.h index 3a9a6234395f..f959bf432bee 100644 --- a/ipc/glue/IPCMessageUtils.h +++ b/ipc/glue/IPCMessageUtils.h @@ -137,12 +137,14 @@ struct EnumSerializer { static bool Read(const Message* aMsg, PickleIterator* aIter, paramType* aResult) { uintParamType value; if (!ReadParam(aMsg, aIter, &value)) { - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCReadErrorReason"), - NS_LITERAL_CSTRING("Bad iter")); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::IPCReadErrorReason, + NS_LITERAL_CSTRING("Bad iter")); return false; } else if (!EnumValidator::IsLegalValue(paramType(value))) { - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCReadErrorReason"), - NS_LITERAL_CSTRING("Illegal value")); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::IPCReadErrorReason, + NS_LITERAL_CSTRING("Illegal value")); return false; } *aResult = paramType(value); diff --git a/ipc/glue/MessageChannel.cpp b/ipc/glue/MessageChannel.cpp index 0129af4a3fe6..0e1adc5b1c8b 100644 --- a/ipc/glue/MessageChannel.cpp +++ b/ipc/glue/MessageChannel.cpp @@ -774,9 +774,8 @@ void MessageChannel::WillDestroyCurrentMessageLoop() { #if defined(DEBUG) - CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("IPCFatalErrorProtocol"), - nsDependentCString(mName)); + CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::IPCFatalErrorProtocol, + nsDependentCString(mName)); MOZ_CRASH("MessageLoop destroyed before MessageChannel that's bound to it"); #endif @@ -804,8 +803,7 @@ MessageChannel::Clear() // shouldn't intentionally crash here. if (!Unsound_IsClosed() && !mInKillHardShutdown) { CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("IPCFatalErrorProtocol"), - nsDependentCString(mName)); + CrashReporter::Annotation::IPCFatalErrorProtocol, nsDependentCString(mName)); switch (mChannelState) { case ChannelOpening: MOZ_CRASH("MessageChannel destroyed without being closed " \ diff --git a/ipc/glue/MessageLink.cpp b/ipc/glue/MessageLink.cpp index 02084515c82b..3fbd6eaea536 100644 --- a/ipc/glue/MessageLink.cpp +++ b/ipc/glue/MessageLink.cpp @@ -159,8 +159,12 @@ void ProcessLink::SendMessage(Message *msg) { if (msg->size() > IPC::Channel::kMaximumMessageSize) { - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCMessageName"), nsDependentCString(msg->name())); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCMessageSize"), nsPrintfCString("%d", msg->size())); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::IPCMessageName, + nsDependentCString(msg->name())); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::IPCMessageSize, + static_cast(msg->size())); MOZ_CRASH("IPC message size is too large"); } diff --git a/ipc/glue/ProtocolUtils.cpp b/ipc/glue/ProtocolUtils.cpp index 1298407e49a4..d22131c3d280 100644 --- a/ipc/glue/ProtocolUtils.cpp +++ b/ipc/glue/ProtocolUtils.cpp @@ -211,7 +211,7 @@ bool DuplicateHandle(HANDLE aSourceHandle, aTargetProcessId)); if (!targetProcess) { CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("IPCTransportFailureReason"), + CrashReporter::Annotation::IPCTransportFailureReason, NS_LITERAL_CSTRING("Failed to open target process.")); return false; } @@ -233,20 +233,18 @@ AnnotateSystemError() #endif if (error) { CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("IPCSystemError"), + CrashReporter::Annotation::IPCSystemError, nsPrintfCString("%" PRId64, error)); } } #if defined(XP_MACOSX) void -AnnotateCrashReportWithErrno(const char* tag, int error) +AnnotateCrashReportWithErrno(CrashReporter::Annotation tag, int error) { - CrashReporter::AnnotateCrashReport( - nsCString(tag), - nsPrintfCString("%d", error)); + CrashReporter::AnnotateCrashReport(tag, error); } -#endif +#endif // defined(XP_MACOSX) void LogMessageForProtocol(const char* aTopLevelProtocol, base::ProcessId aOtherPid, @@ -290,8 +288,9 @@ FatalError(const char* aMsg, bool aIsParent) // this process if we're off the main thread. formattedMessage.AppendLiteral("\". Intentionally crashing."); NS_ERROR(formattedMessage.get()); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IPCFatalErrorMsg"), - nsDependentCString(aMsg)); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::IPCFatalErrorMsg, + nsDependentCString(aMsg)); AnnotateSystemError(); #ifndef FUZZING MOZ_CRASH("IPC FatalError in the parent process!"); diff --git a/ipc/glue/ProtocolUtils.h b/ipc/glue/ProtocolUtils.h index 9bb202fead7e..d3c1ec6dd5be 100644 --- a/ipc/glue/ProtocolUtils.h +++ b/ipc/glue/ProtocolUtils.h @@ -33,6 +33,7 @@ #include "mozilla/Scoped.h" #include "mozilla/UniquePtr.h" #include "MainThreadUtils.h" +#include "nsICrashReporter.h" #include "nsILabelableRunnable.h" #if defined(ANDROID) && defined(DEBUG) @@ -914,9 +915,9 @@ private: }; #if defined(XP_MACOSX) -void AnnotateCrashReportWithErrno(const char* tag, int error); +void AnnotateCrashReportWithErrno(CrashReporter::Annotation tag, int error); #else -static inline void AnnotateCrashReportWithErrno(const char* tag, int error) +static inline void AnnotateCrashReportWithErrno(CrashReporter::Annotation tag, int error) {} #endif @@ -936,7 +937,8 @@ CreateEndpoints(const PrivateIPDLInterface& aPrivate, TransportDescriptor parentTransport, childTransport; nsresult rv; if (NS_FAILED(rv = CreateTransport(aParentDestPid, &parentTransport, &childTransport))) { - AnnotateCrashReportWithErrno("IpcCreateEndpointsNsresult", int(rv)); + AnnotateCrashReportWithErrno( + CrashReporter::Annotation::IpcCreateEndpointsNsresult, int(rv)); return rv; } diff --git a/ipc/glue/Transport_posix.cpp b/ipc/glue/Transport_posix.cpp index 09cba86bd019..004082c708d7 100644 --- a/ipc/glue/Transport_posix.cpp +++ b/ipc/glue/Transport_posix.cpp @@ -40,11 +40,13 @@ CreateTransport(base::ProcessId aProcIdOne, // dup them here fd1 = dup(fd1); if (fd1 < 0) { - AnnotateCrashReportWithErrno("IpcCreateTransportDupErrno", errno); + AnnotateCrashReportWithErrno( + CrashReporter::Annotation::IpcCreateTransportDupErrno, errno); } fd2 = dup(fd2); if (fd2 < 0) { - AnnotateCrashReportWithErrno("IpcCreateTransportDupErrno", errno); + AnnotateCrashReportWithErrno( + CrashReporter::Annotation::IpcCreateTransportDupErrno, errno); } if (fd1 < 0 || fd2 < 0) { diff --git a/ipc/mscom/COMPtrHolder.h b/ipc/mscom/COMPtrHolder.h index 3e6536d35c87..d46b06f007c7 100644 --- a/ipc/mscom/COMPtrHolder.h +++ b/ipc/mscom/COMPtrHolder.h @@ -210,8 +210,9 @@ struct ParamTraits> mozilla::mscom::ProxyStream proxyStream(_IID, buf.get(), length, &env); if (!proxyStream.IsValid()) { - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProxyStreamValid"), - NS_LITERAL_CSTRING("false")); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::ProxyStreamValid, + NS_LITERAL_CSTRING("false")); return false; } diff --git a/ipc/mscom/ProxyStream.cpp b/ipc/mscom/ProxyStream.cpp index 362b020cb3c1..d2d0e5b212f1 100644 --- a/ipc/mscom/ProxyStream.cpp +++ b/ipc/mscom/ProxyStream.cpp @@ -44,7 +44,8 @@ ProxyStream::ProxyStream(REFIID aIID, const BYTE* aInitBuf, , mBufSize(aInitBufSize) , mPreserveStream(false) { - NS_NAMED_LITERAL_CSTRING(kCrashReportKey, "ProxyStreamUnmarshalStatus"); + CrashReporter::Annotation kCrashReportKey = + CrashReporter::Annotation::ProxyStreamUnmarshalStatus; if (!aInitBufSize) { CrashReporter::AnnotateCrashReport(kCrashReportKey, @@ -136,7 +137,7 @@ ProxyStream::ProxyStream(REFIID aIID, const BYTE* aInitBuf, if (FAILED(unmarshalResult) || !mUnmarshaledProxy) { nsPrintfCString hrAsStr("0x%08X", unmarshalResult); CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("CoUnmarshalInterfaceResult"), hrAsStr); + CrashReporter::Annotation::CoUnmarshalInterfaceResult, hrAsStr); AnnotateInterfaceRegistration(aIID); if (!mUnmarshaledProxy) { CrashReporter::AnnotateCrashReport(kCrashReportKey, @@ -145,24 +146,21 @@ ProxyStream::ProxyStream(REFIID aIID, const BYTE* aInitBuf, #if defined(ACCESSIBILITY) AnnotateClassRegistration(CLSID_AccessibleHandler); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("UnmarshalActCtx"), - strActCtx); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("UnmarshalActCtxManifestPath"), - NS_ConvertUTF16toUTF8(manifestPath)); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("A11yHandlerRegistered"), - a11y::IsHandlerRegistered() ? - NS_LITERAL_CSTRING("true") : - NS_LITERAL_CSTRING("false")); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::UnmarshalActCtx, strActCtx); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::UnmarshalActCtxManifestPath, + NS_ConvertUTF16toUTF8(manifestPath)); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::A11yHandlerRegistered, + a11y::IsHandlerRegistered() ? NS_LITERAL_CSTRING("true") + : NS_LITERAL_CSTRING("false")); - nsAutoCString strExpectedStreamLen; - strExpectedStreamLen.AppendInt(expectedStreamLen); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ExpectedStreamLen"), - strExpectedStreamLen); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::ExpectedStreamLen, expectedStreamLen); - nsAutoCString actualStreamLen; - actualStreamLen.AppendInt(aInitBufSize); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ActualStreamLen"), - actualStreamLen); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::ActualStreamLen, aInitBufSize); #endif // defined(ACCESSIBILITY) } } @@ -360,38 +358,37 @@ ProxyStream::ProxyStream(REFIID aIID, IUnknown* aObject, Environment* aEnv, if (FAILED(createStreamResult)) { nsPrintfCString hrAsStr("0x%08X", createStreamResult); CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("CreateStreamOnHGlobalFailure"), - hrAsStr); + CrashReporter::Annotation::CreateStreamOnHGlobalFailure, hrAsStr); } if (FAILED(marshalResult)) { AnnotateInterfaceRegistration(aIID); nsPrintfCString hrAsStr("0x%08X", marshalResult); CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("CoMarshalInterfaceFailure"), hrAsStr); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("MarshalActCtxManifestPath"), - NS_ConvertUTF16toUTF8(manifestPath)); + CrashReporter::Annotation::CoMarshalInterfaceFailure, hrAsStr); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::MarshalActCtxManifestPath, + NS_ConvertUTF16toUTF8(manifestPath)); } if (FAILED(statResult)) { nsPrintfCString hrAsStr("0x%08X", statResult); - CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("StatFailure"), - hrAsStr); + CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::StatFailure, + hrAsStr); } if (FAILED(getHGlobalResult)) { nsPrintfCString hrAsStr("0x%08X", getHGlobalResult); CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("GetHGlobalFromStreamFailure"), - hrAsStr); + CrashReporter::Annotation::GetHGlobalFromStreamFailure, hrAsStr); } mStream = std::move(stream); if (streamSize) { - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProxyStreamSizeFrom"), - NS_LITERAL_CSTRING("IStream::Stat")); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::ProxyStreamSizeFrom, + NS_LITERAL_CSTRING("IStream::Stat")); mBufSize = streamSize; } @@ -406,16 +403,14 @@ ProxyStream::ProxyStream(REFIID aIID, IUnknown* aObject, Environment* aEnv, // the size of the memory block allocated by the HGLOBAL, though it might // be larger than the actual stream size. if (!streamSize) { - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProxyStreamSizeFrom"), - NS_LITERAL_CSTRING("GlobalSize")); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::ProxyStreamSizeFrom, + NS_LITERAL_CSTRING("GlobalSize")); mBufSize = static_cast(::GlobalSize(hglobal)); } - nsAutoCString strBufSize; - strBufSize.AppendInt(mBufSize); - - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProxyStreamSize"), - strBufSize); + CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::ProxyStreamSize, + mBufSize); } } // namespace mscom diff --git a/ipc/mscom/RegistrationAnnotator.cpp b/ipc/mscom/RegistrationAnnotator.cpp index 337d9c8105d3..31c25604751c 100644 --- a/ipc/mscom/RegistrationAnnotator.cpp +++ b/ipc/mscom/RegistrationAnnotator.cpp @@ -376,16 +376,15 @@ AnnotateInterfaceRegistration(REFIID aIid) json.End(); - nsAutoCString annotationKey; - annotationKey.AppendLiteral("InterfaceRegistrationInfo"); + CrashReporter::Annotation annotationKey; if (XRE_IsParentProcess()) { - annotationKey.AppendLiteral("Parent"); + annotationKey = CrashReporter::Annotation::InterfaceRegistrationInfoParent; } else { - annotationKey.AppendLiteral("Child"); + annotationKey = CrashReporter::Annotation::InterfaceRegistrationInfoChild; } - - CrashReporter::AnnotateCrashReport(annotationKey, - static_cast(json.WriteFunc())->Get()); + CrashReporter::AnnotateCrashReport( + annotationKey, + static_cast(json.WriteFunc())->Get()); } void @@ -414,12 +413,11 @@ AnnotateClassRegistration(REFCLSID aClsid) json.End(); - nsAutoCString annotationKey; - annotationKey.AppendLiteral("ClassRegistrationInfo"); + CrashReporter::Annotation annotationKey; if (XRE_IsParentProcess()) { - annotationKey.AppendLiteral("Parent"); + annotationKey = CrashReporter::Annotation::ClassRegistrationInfoParent; } else { - annotationKey.AppendLiteral("Child"); + annotationKey = CrashReporter::Annotation::ClassRegistrationInfoChild; } CrashReporter::AnnotateCrashReport(annotationKey, diff --git a/js/xpconnect/loader/mozJSComponentLoader.cpp b/js/xpconnect/loader/mozJSComponentLoader.cpp index 90c9e61f371c..75d52f01414a 100644 --- a/js/xpconnect/loader/mozJSComponentLoader.cpp +++ b/js/xpconnect/loader/mozJSComponentLoader.cpp @@ -20,6 +20,7 @@ #include "js/Printf.h" #include "nsCOMPtr.h" #include "nsAutoPtr.h" +#include "nsExceptionHandler.h" #include "nsIComponentManager.h" #include "mozilla/Module.h" #include "nsIFile.h" @@ -56,10 +57,6 @@ #include "mozilla/UniquePtrExtensions.h" #include "mozilla/Unused.h" -#ifdef MOZ_CRASHREPORTER -#include "mozilla/ipc/CrashReporterClient.h" -#endif - using namespace mozilla; using namespace mozilla::scache; using namespace mozilla::loader; @@ -363,11 +360,10 @@ ResolveModuleObjectProperty(JSContext* aCx, HandleObject aModObj, const char* na return aModObj; } -#ifdef MOZ_CRASHREPORTER static mozilla::Result ReadScript(ComponentLoaderInfo& aInfo); static nsresult -AnnotateScriptContents(const nsACString& aName, const nsACString& aURI) +AnnotateScriptContents(CrashReporter::Annotation aName, const nsACString& aURI) { ComponentLoaderInfo info(aURI); @@ -384,20 +380,17 @@ AnnotateScriptContents(const nsACString& aName, const nsACString& aURI) return NS_OK; } -#endif // defined MOZ_CRASHREPORTER nsresult mozJSComponentLoader::AnnotateCrashReport() { -#ifdef MOZ_CRASHREPORTER Unused << AnnotateScriptContents( - NS_LITERAL_CSTRING("nsAsyncShutdownComponent"), + CrashReporter::Annotation::nsAsyncShutdownComponent, NS_LITERAL_CSTRING("resource://gre/components/nsAsyncShutdown.js")); Unused << AnnotateScriptContents( - NS_LITERAL_CSTRING("AsyncShutdownModule"), + CrashReporter::Annotation::AsyncShutdownModule, NS_LITERAL_CSTRING("resource://gre/modules/AsyncShutdown.jsm")); -#endif // defined MOZ_CRASHREPORTER return NS_OK; } diff --git a/layout/style/ServoBindings.h b/layout/style/ServoBindings.h index e30f744bc9de..ab7266568b5b 100644 --- a/layout/style/ServoBindings.h +++ b/layout/style/ServoBindings.h @@ -684,7 +684,7 @@ bool Gecko_DocumentRule_UseForPresentation(RawGeckoPresContextBorrowed, void Gecko_SetJemallocThreadLocalArena(bool enabled); void Gecko_AddBufferToCrashReport(const void* addr, size_t len); -void Gecko_AnnotateCrashReport(const char* key_str, const char* value_str); +void Gecko_AnnotateCrashReport(uint32_t key, const char* value_str); // Pseudo-element flags. #define CSS_PSEUDO_ELEMENT(name_, value_, flags_) \ diff --git a/layout/style/nsLayoutStylesheetCache.cpp b/layout/style/nsLayoutStylesheetCache.cpp index aec84faa6c11..26dd91988028 100644 --- a/layout/style/nsLayoutStylesheetCache.cpp +++ b/layout/style/nsLayoutStylesheetCache.cpp @@ -712,8 +712,9 @@ AnnotateCrashReport(nsIURI* aURI) annotation.AppendLiteral("No GRE omnijar\n"); } - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("SheetLoadFailure"), - NS_ConvertUTF16toUTF8(annotation)); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::SheetLoadFailure, + NS_ConvertUTF16toUTF8(annotation)); } static void diff --git a/mobile/android/base/java/org/mozilla/gecko/telemetry/pingbuilders/TelemetryCrashPingBuilder.java b/mobile/android/base/java/org/mozilla/gecko/telemetry/pingbuilders/TelemetryCrashPingBuilder.java index 6b336b9aa9f5..5d02c6eee53a 100644 --- a/mobile/android/base/java/org/mozilla/gecko/telemetry/pingbuilders/TelemetryCrashPingBuilder.java +++ b/mobile/android/base/java/org/mozilla/gecko/telemetry/pingbuilders/TelemetryCrashPingBuilder.java @@ -8,6 +8,7 @@ package org.mozilla.gecko.telemetry.pingbuilders; import android.util.Log; +import org.mozilla.gecko.CrashReporterConstants; import org.mozilla.gecko.sync.ExtendedJSONObject; import org.mozilla.gecko.sync.NonObjectJSONException; import org.mozilla.gecko.util.StringUtils; @@ -35,40 +36,6 @@ public class TelemetryCrashPingBuilder extends TelemetryPingBuilder { private static final String ISO8601_DATE = "yyyy-MM-dd"; private static final String ISO8601_DATE_HOURS = "yyyy-MM-dd'T'HH':00:00.000Z'"; - // The following list should be kept in sync with the one in CrashManager.jsm - private static final String[] ANNOTATION_WHITELIST = { - "AsyncShutdownTimeout", - "AvailablePageFile", - "AvailablePhysicalMemory", - "AvailableVirtualMemory", - "BlockedDllList", - "BlocklistInitFailed", - "BuildID", - "ContainsMemoryReport", - "CrashTime", - "EventLoopNestingLevel", - "ipc_channel_error", - "IsGarbageCollecting", - "LowCommitSpaceEvents", - "MozCrashReason", - "OOMAllocationSize", - "ProductID", - "ProductName", - "ReleaseChannel", - "RemoteType", - "SecondsSinceLastCrash", - "ShutdownProgress", - "StartupCrash", - "SystemMemoryUsePercentage", - "TextureUsage", - "TotalPageFile", - "TotalPhysicalMemory", - "TotalVirtualMemory", - "UptimeTS", - "User32BeforeBlocklist", - "Version", - }; - public TelemetryCrashPingBuilder(String crashId, String clientId, HashMap annotations) { super(TelemetryPingBuilder.UNIFIED_TELEMETRY_VERSION); @@ -178,7 +145,7 @@ public class TelemetryCrashPingBuilder extends TelemetryPingBuilder { ExtendedJSONObject node = new ExtendedJSONObject(); for (Entry pair : annotations.entrySet()) { - if (Arrays.binarySearch(ANNOTATION_WHITELIST, pair.getKey()) >= 0) { + if (Arrays.binarySearch(CrashReporterConstants.ANNOTATION_WHITELIST, pair.getKey()) >= 0) { node.put(pair.getKey(), pair.getValue()); } } diff --git a/mobile/android/base/moz.build b/mobile/android/base/moz.build index 27d0abd6386a..9d845e4e3316 100644 --- a/mobile/android/base/moz.build +++ b/mobile/android/base/moz.build @@ -116,6 +116,7 @@ GENERATED_FILES += [ 'AndroidManifest.xml', 'generated/preprocessed/org/mozilla/gecko/AdjustConstants.java', 'generated/preprocessed/org/mozilla/gecko/AppConstants.java', + 'generated/preprocessed/org/mozilla/gecko/CrashReporterConstants.java', 'generated/preprocessed/org/mozilla/gecko/MmaConstants.java', ] x = GENERATED_FILES['generated/preprocessed/org/mozilla/gecko/AdjustConstants.java'] @@ -131,6 +132,11 @@ z = GENERATED_FILES['AndroidManifest.xml'] z.script = 'generate_build_config.py:generate_android_manifest' z.inputs += ['AndroidManifest.xml.in'] +# Generate CrashReporterConstants.java +crash_reporter_constants = GENERATED_FILES['generated/preprocessed/org/mozilla/gecko/CrashReporterConstants.java'] +crash_reporter_constants.script = '/toolkit/crashreporter/generate_crash_reporter_sources.py:emit_class' +crash_reporter_constants.inputs += ['/toolkit/crashreporter/CrashAnnotations.yaml'] + # Regular builds invoke `libs` targets that localize files with no AB_CD set # into the default resources (res/{values,raw}). # @@ -192,6 +198,7 @@ GENERATED_FILES[t].inputs += [ '!AndroidManifest.xml', '!generated/preprocessed/org/mozilla/gecko/AdjustConstants.java', '!generated/preprocessed/org/mozilla/gecko/AppConstants.java', + '!generated/preprocessed/org/mozilla/gecko/CrashReporterConstants.java', '!generated/preprocessed/org/mozilla/gecko/MmaConstants.java', # These all depend on AB_CD, which isn't captured in this definition. Due # to subtle RecursiveMake details, everything works out. In the future we diff --git a/mozglue/build/WindowsDllBlocklist.cpp b/mozglue/build/WindowsDllBlocklist.cpp index 50bd1e88e7b8..59d277021bef 100644 --- a/mozglue/build/WindowsDllBlocklist.cpp +++ b/mozglue/build/WindowsDllBlocklist.cpp @@ -24,6 +24,7 @@ #pragma warning( pop ) #include "Authenticode.h" +#include "CrashAnnotations.h" #include "nsAutoPtr.h" #include "nsWindowsDllInterceptor.h" #include "mozilla/Sprintf.h" @@ -38,6 +39,9 @@ using namespace mozilla; +using CrashReporter::Annotation; +using CrashReporter::AnnotationToString; + #define DLL_BLOCKLIST_ENTRY(name, ...) \ { name, __VA_ARGS__ }, #define DLL_BLOCKLIST_STRING_TYPE const char* @@ -46,18 +50,6 @@ using namespace mozilla; // define this for very verbose dll load debug spew #undef DEBUG_very_verbose -static const char kBlockedDllsParameter[] = "BlockedDllList="; -static const int kBlockedDllsParameterLen = - sizeof(kBlockedDllsParameter) - 1; - -static const char kBlocklistInitFailedParameter[] = "BlocklistInitFailed=1\n"; -static const int kBlocklistInitFailedParameterLen = - sizeof(kBlocklistInitFailedParameter) - 1; - -static const char kUser32BeforeBlocklistParameter[] = "User32BeforeBlocklist=1\n"; -static const int kUser32BeforeBlocklistParameterLen = - sizeof(kUser32BeforeBlocklistParameter) - 1; - static uint32_t sInitFlags; static bool sBlocklistInitAttempted; static bool sBlocklistInitFailed; @@ -779,23 +771,31 @@ DllBlocklist_Initialize(uint32_t aInitFlags) #endif } +static void +WriteAnnotation(HANDLE aFile, Annotation aAnnotation, const char* aValue, + DWORD* aNumBytes) +{ + const char* str = AnnotationToString(aAnnotation); + WriteFile(aFile, str, strlen(str), aNumBytes, nullptr); + WriteFile(aFile, "=", 1, aNumBytes, nullptr); + WriteFile(aFile, aValue, strlen(aValue), aNumBytes, nullptr); +} + static void InternalWriteNotes(HANDLE file) { DWORD nBytes; - WriteFile(file, kBlockedDllsParameter, kBlockedDllsParameterLen, &nBytes, nullptr); + WriteAnnotation(file, Annotation::BlockedDllList, "", &nBytes); DllBlockSet::Write(file); WriteFile(file, "\n", 1, &nBytes, nullptr); if (sBlocklistInitFailed) { - WriteFile(file, kBlocklistInitFailedParameter, - kBlocklistInitFailedParameterLen, &nBytes, nullptr); + WriteAnnotation(file, Annotation::BlocklistInitFailed, "1\n", &nBytes); } if (sUser32BeforeBlocklist) { - WriteFile(file, kUser32BeforeBlocklistParameter, - kUser32BeforeBlocklistParameterLen, &nBytes, nullptr); + WriteAnnotation(file, Annotation::User32BeforeBlocklist, "1\n", &nBytes); } } diff --git a/netwerk/ipc/NeckoMessageUtils.h b/netwerk/ipc/NeckoMessageUtils.h index ad60c4624ae8..7e3ed492aed2 100644 --- a/netwerk/ipc/NeckoMessageUtils.h +++ b/netwerk/ipc/NeckoMessageUtils.h @@ -107,7 +107,8 @@ struct ParamTraits } else { if (XRE_IsParentProcess()) { nsPrintfCString msg("%d", aParam.raw.family); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Unknown NetAddr socket family"), msg); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::UnknownNetAddrSocketFamily, msg); } MOZ_CRASH("Unknown socket family"); diff --git a/storage/mozStorageService.cpp b/storage/mozStorageService.cpp index d4e52ff71173..d42447c97c5c 100644 --- a/storage/mozStorageService.cpp +++ b/storage/mozStorageService.cpp @@ -796,7 +796,7 @@ Service::Observe(nsISupports *, const char *aTopic, const char16_t *) // getFilename is only the leaf name for the database file, // so it shouldn't contain privacy-sensitive information. CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("StorageConnectionNotClosed"), + CrashReporter::Annotation::StorageConnectionNotClosed, connections[i]->getFilename()); #ifdef DEBUG printf_stderr("Storage connection not closed: %s", diff --git a/toolkit/components/crashes/CrashManager.jsm b/toolkit/components/crashes/CrashManager.jsm index 2b9b16f3fe4e..97eb8196ef52 100644 --- a/toolkit/components/crashes/CrashManager.jsm +++ b/toolkit/components/crashes/CrashManager.jsm @@ -221,44 +221,6 @@ this.CrashManager.prototype = Object.freeze({ // The type of event is unknown. EVENT_FILE_ERROR_UNKNOWN_EVENT: "unknown-event", - // A whitelist of crash annotations which do not contain sensitive data - // and are saved in the crash record and sent with Firefox Health Report. - ANNOTATION_WHITELIST: [ - "AsyncShutdownTimeout", - "BuildID", - "ipc_channel_error", - "LowCommitSpaceEvents", - "ProductID", - "ProductName", - "ReleaseChannel", - "RemoteType", - "SecondsSinceLastCrash", - "ShutdownProgress", - "StartupCrash", - "TelemetryEnvironment", - "Version", - // The following entries are not normal annotations that can be found in - // the .extra file but are included in the crash record/FHR: - "AvailablePageFile", - "AvailablePhysicalMemory", - "AvailableVirtualMemory", - "BlockedDllList", - "BlocklistInitFailed", - "ContainsMemoryReport", - "CrashTime", - "EventLoopNestingLevel", - "IsGarbageCollecting", - "MozCrashReason", - "OOMAllocationSize", - "SystemMemoryUsePercentage", - "TextureUsage", - "TotalPageFile", - "TotalPhysicalMemory", - "TotalVirtualMemory", - "UptimeTS", - "User32BeforeBlocklist", - ], - /** * Obtain a list of all dumps pending upload. * @@ -637,10 +599,16 @@ this.CrashManager.prototype = Object.freeze({ _filterAnnotations(annotations) { let filteredAnnotations = {}; + let crashReporter = Cc["@mozilla.org/toolkit/crash-reporter;1"] + .getService(Ci.nsICrashReporter); for (let line in annotations) { - if (this.ANNOTATION_WHITELIST.includes(line)) { - filteredAnnotations[line] = annotations[line]; + try { + if (crashReporter.isAnnotationWhitelistedForPing(line)) { + filteredAnnotations[line] = annotations[line]; + } + } catch (e) { + // Silently drop unknown annotations } } diff --git a/toolkit/components/crashes/tests/xpcshell/crash.extra b/toolkit/components/crashes/tests/xpcshell/crash.extra index 60086c71a8f3..8e396d14913a 100644 --- a/toolkit/components/crashes/tests/xpcshell/crash.extra +++ b/toolkit/components/crashes/tests/xpcshell/crash.extra @@ -8,7 +8,6 @@ Vendor=Mozilla InstallTime=1000000000 Theme=classic/1.0 ReleaseChannel=default -AddonsShouldHaveBlockedE10s=1 ServerURL=https://crash-reports.mozilla.com SafeMode=0 ContentSandboxCapable=1 diff --git a/toolkit/components/gfx/SanityTest.js b/toolkit/components/gfx/SanityTest.js index 3a8883d22b50..9e1033c78143 100644 --- a/toolkit/components/gfx/SanityTest.js +++ b/toolkit/components/gfx/SanityTest.js @@ -72,12 +72,20 @@ function reportTestReason(val) { histogram.add(val); } -function annotateCrashReport(value) { +function annotateCrashReport() { try { - // "1" if we're annotating the crash report, "" to remove the annotation. var crashReporter = Cc["@mozilla.org/toolkit/crash-reporter;1"]. getService(Ci.nsICrashReporter); - crashReporter.annotateCrashReport("GraphicsSanityTest", value ? "1" : ""); + crashReporter.annotateCrashReport("GraphicsSanityTest", "1"); + } catch (e) { + } +} + +function removeCrashReportAnnotation(value) { + try { + var crashReporter = Cc["@mozilla.org/toolkit/crash-reporter;1"]. + getService(Ci.nsICrashReporter); + crashReporter.removeCrashReportAnnotation("GraphicsSanityTest"); } catch (e) { } } @@ -242,7 +250,7 @@ var listener = { // Remove the annotation after we've cleaned everything up, to catch any // incidental crashes from having performed the sanity test. - annotateCrashReport(false); + removeCrashReportAnnotation(); } }; @@ -330,7 +338,7 @@ SanityTest.prototype = { if (!this.shouldRunTest()) return; - annotateCrashReport(true); + annotateCrashReport(); // Open a tiny window to render our test page, and notify us when it's loaded var sanityTest = Services.ww.openWindow(null, diff --git a/toolkit/components/telemetry/TelemetrySend.jsm b/toolkit/components/telemetry/TelemetrySend.jsm index efd88adbc317..da748002641a 100644 --- a/toolkit/components/telemetry/TelemetrySend.jsm +++ b/toolkit/components/telemetry/TelemetrySend.jsm @@ -690,8 +690,8 @@ var TelemetrySendImpl = { if (!this.sendingEnabled() || !TelemetryReportingPolicy.canUpload()) { // If we cannot send pings then clear the crash annotations - crs.annotateCrashReport("TelemetryClientId", ""); - crs.annotateCrashReport("TelemetryServerURL", ""); + crs.removeCrashReportAnnotation("TelemetryClientId"); + crs.removeCrashReportAnnotation("TelemetryServerURL"); } else { crs.annotateCrashReport("TelemetryClientId", clientId); crs.annotateCrashReport("TelemetryServerURL", server); diff --git a/toolkit/components/telemetry/tests/unit/test_TelemetrySend.js b/toolkit/components/telemetry/tests/unit/test_TelemetrySend.js index 2991514af410..bdf3e3b99f13 100644 --- a/toolkit/components/telemetry/tests/unit/test_TelemetrySend.js +++ b/toolkit/components/telemetry/tests/unit/test_TelemetrySend.js @@ -639,9 +639,14 @@ add_task(async function test_pref_observer() { reject(Error("Crash report annotation without expected value.")); } - if (!expectedValue && value != "") { + if (keys.size == 0) { + MockRegistrar.unregister(gMockCrs); + resolve(); + } + }, + removeCrashReportAnnotation(key) { + if (!keys.delete(key)) { MockRegistrar.unregister(gMockCrs); - reject(Error(`Crash report annotation ("${key}") with unexpected value: "${value}".`)); } if (keys.size == 0) { diff --git a/toolkit/components/terminator/nsTerminator.cpp b/toolkit/components/terminator/nsTerminator.cpp index 44d3486132bc..c417777fb6c2 100644 --- a/toolkit/components/terminator/nsTerminator.cpp +++ b/toolkit/components/terminator/nsTerminator.cpp @@ -603,8 +603,8 @@ nsTerminator::UpdateCrashReport(const char* aTopic) // In case of crash, we wish to know where in shutdown we are nsAutoCString report(aTopic); - Unused << CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ShutdownProgress"), - report); + Unused << CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::ShutdownProgress, report); } void diff --git a/toolkit/crashreporter/CrashAnnotations.cpp b/toolkit/crashreporter/CrashAnnotations.cpp new file mode 100644 index 000000000000..19886ace1f8a --- /dev/null +++ b/toolkit/crashreporter/CrashAnnotations.cpp @@ -0,0 +1,63 @@ +/* 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 "CrashAnnotations.h" + +#include +#include +#include + +using std::begin; +using std::end; +using std::find_if; + +namespace CrashReporter { + +bool +AnnotationFromString(Annotation& aResult, const char* aValue) +{ + auto elem = find_if( + begin(kAnnotationStrings), + end(kAnnotationStrings), + [&aValue](const char* aString) { + return strcmp(aString, aValue) == 0; + } + ); + + if (elem == end(kAnnotationStrings)) { + return false; + } + + aResult = static_cast(elem - begin(kAnnotationStrings)); + return true; +} + +bool +IsAnnotationWhitelistedForPing(Annotation aAnnotation) { + auto elem = find_if( + begin(kCrashPingWhitelist), + end(kCrashPingWhitelist), + [&aAnnotation](Annotation aElement) { + return aElement == aAnnotation; + } + ); + + return elem != end(kCrashPingWhitelist); +} + +bool +IsAnnotationBlacklistedForContent(Annotation aAnnotation) +{ + auto elem = find_if( + begin(kContentProcessBlacklist), + end(kContentProcessBlacklist), + [&aAnnotation](Annotation aElement) { + return aElement == aAnnotation; + } + ); + + return elem != end(kContentProcessBlacklist); +} + +} // namespace CrashReporter diff --git a/toolkit/crashreporter/CrashAnnotations.h.in b/toolkit/crashreporter/CrashAnnotations.h.in new file mode 100644 index 000000000000..99a5ebfb9ef7 --- /dev/null +++ b/toolkit/crashreporter/CrashAnnotations.h.in @@ -0,0 +1,76 @@ +/* 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 CrashAnnotations_h +#define CrashAnnotations_h + +#include + +namespace CrashReporter { + +// Typed enum representing all crash annotations +enum class Annotation : uint32_t { +${enum} +}; + +// Stringified crash annotation names +const char* const kAnnotationStrings[] = { +${strings} +}; + +// Whitelist of crash annotations that can be included in a crash ping +const Annotation kCrashPingWhitelist[] = { +${whitelist} +}; + +// Blacklist of crash annotations that shouldn't be read from a content process +const Annotation kContentProcessBlacklist[] = { +${blacklist} +}; + +/** + * Return the string representation of a crash annotation. + * + * @param aAnnotation a crash annotation + * @returns A constant string holding the annotation name + */ +static inline const char* +AnnotationToString(Annotation aAnnotation) { + return kAnnotationStrings[static_cast(aAnnotation)]; +} + +/** + * Converts a string to its corresponding crash annotation. + * + * @param aResult a reference where the annotation will be stored + * @param aValue the string to be converted + * @return true if the string was successfully converted, false if it did not + * correspond to any known annotation + */ +bool AnnotationFromString(Annotation& aResult, const char* aValue); + +/** + * Checks if the given crash annotation is whitelisted for inclusion in the + * crash ping. + * + * @param aAnnotation the crash annotation to be checked + * @return true if the annotation can be included in the crash ping, false + * otherwise + */ +bool IsAnnotationWhitelistedForPing(Annotation aAnnotation); + +/** + * Checks if the given crash annotation needs to be filtered out when reading + * a content process crash annotations. Blacklisted annotations will be + * replaced with ones provided by the parent process. + * + * @param aAnnotation the crash annotation to be checked + * @return true if the annotation needs to be filtered out when reading + * annotations provided by a content process, false otherwise + */ +bool IsAnnotationBlacklistedForContent(Annotation aAnnotation); + +} // namespace CrashReporter + +#endif // CrashAnnotations_h diff --git a/toolkit/crashreporter/CrashAnnotations.yaml b/toolkit/crashreporter/CrashAnnotations.yaml new file mode 100644 index 000000000000..f2f13e953aab --- /dev/null +++ b/toolkit/crashreporter/CrashAnnotations.yaml @@ -0,0 +1,776 @@ +# This lists all the available crash annotations. +# +# Mandatory fields for each entry are: +# - description: A string describing the annotation +# - type: the annotation type, currently `string`, `integer` or `boolean`. +# The latter are stringified to `1` for true and `0` for false. +# +# Additionally a field can have the following optional fields: +# - altname: A string that will be used when writing out the annotation to the +# .extra file instead of the annotation name +# - ping: A boolean that indicates whether the annotation is whitelisted for +# going into the crash ping, if not specified this defaults to false +# - content: A boolean that indicates whether the field will be included in +# subprocess reports, if not specified this defaults to true + +A11yHandlerRegistered: + description: > + Set to "true" if the accessibility handler is registered, "false" otherwise. + type: string + +AbortMessage: + description: > + Message passed to NS_DebugBreak(). + type: string + +Accessibility: + description: > + Set to "Active" by the accessibility service when it is active. + type: string + +AccessibilityClient: + description: > + Accessibility client ID. + type: string + +AccessibilityInProcClient: + description: > + Hexadecimal mask of in-process accessibility consumers, see + accessible/windows/msaa/Compatibility.h for the mappings. + type: string + +ActualStreamLen: + description: > + Actual length of an IPC proxy stream. + type: integer + +AdapterDeviceID: + description: > + Graphics adapter name. + type: string + +AdapterDriverVersion: + description: > + Graphics adapter driver version. + type: string + +AdapterSubsysID: + description: > + Graphics adapter subsystem ID. + type: string + +AdapterVendorID: + description: > + Graphics adapter vendor name. + type: string + +additional_minidumps: + description: > + Comma separated list of additional minidumps for this crash, each element + in the list represent the suffix used in the dump filename. E.g. the + "browser" entry for crash fa909194-737b-4b93-b8da-da110ac785e0 implies the + existence of the fa909194-737b-4b93-b8da-da110ac785e0-browser.dmp file. + type: string + +Addons: + description: > + List of currently enabled add-ons. + type: string + altname: Add-ons + +AppInitDLLs: + description: > + List of DLLs loaded when launching any application on Windows, this + reflects the contents of the AppInit_DLLs registry key. + type: string + +AsyncShutdownModule: + description: > + Holds the contents of the AsyncShutdown.js script + type: string + +AsyncShutdownTimeout: + description: > + This annotation is present if a shutdown blocker was not released in time + and the browser was crashed instead of waiting for shutdown to finish. The + condition that caused the hang is contained in the annotation. + type: string + ping: true + +AvailablePageFile: + description: > + Windows-only, maximum amount of memory that can be committed. This + annotation is populated with the contents of the MEMORYSTATUSEX's structure + ullAvailPageFile field. + type: string + ping: true + +AvailablePhysicalMemory: + description: > + Windows-only, amount of free physical memory in bytes. This annotation + is populated with the contents of the MEMORYSTATUSEX's structure + ullAvailPhys field. + type: string + ping: true + +AvailableVirtualMemory: + description: > + Windows-only, amount of free virtual memory in bytes. This annotation is + populated with the contents of the MEMORYSTATUSEX's structure + ullAvailVirtual field. + type: string + ping: true + +BIOS_Manufacturer: + description: > + Name of the BIOS manufacturer. + type: string + +BlockedDllList: + description: > + Comma-separated list of blocked DLLS, Windows-only + type: string + ping: true + +BlocklistInitFailed: + description: > + Set to 1 if the DLL blocklist could not be initialized. + type: boolean + ping: true + +BreakpadReserveAddress: + description: > + Address of the buffer reserved by Breakpad. + type: string + +BreakpadReserveSize: + description: > + Size of the buffer reserved by Breakpad. + type: string + +BuildID: + description: > + Application build ID, the format is YYYYMMDDHHMMSS. + type: string + ping: true + +ClassRegistrationInfoChild: + description: > + Microsoft COM class registration annotation for the child process. + type: string + +ClassRegistrationInfoParent: + description: > + Microsoft COM class registration annotation for the parent process. + type: string + +CoMarshalInterfaceFailure: + description: > + Annotation describing the error returned by trying to marshal an object + via CoMarshalInterface during the creation of an IPC proxy stream. + type: string + +ContainsMemoryReport: + description: > + Indicates that the crash dump contains a memory report. + type: boolean + ping: true + +ContentSandboxCapabilities: + description: > + List of capabilities of the content process sandbox. + type: string + +ContentSandboxEnabled: + description: > + Set to 1 when content process sandboxing is enabled. + type: boolean + +ContentSandboxCapable: + description: > + Set to 1 if the client is capable of content sandboxing. + type: boolean + +ContentSandboxLevel: + description: > + Content sandbox level. + type: integer + +CoUnmarshalInterfaceResult: + description: > + Annotation describing the error returned by trying to unmarshal an object + via CoUnmarshalInterface during the creation of an IPC proxy stream. + type: integer + +CPUMicrocodeVersion: + description: > + Version of the CPU microcode. + type: string + +CpuUsageFlashProcess1: + description: > + CPU usage of the first Adobe Flash plugin process. + type: string + +CpuUsageFlashProcess2: + description: > + CPU usage of the second Adobe Flash plugin process. + type: string + +CrashAddressLikelyWrong: + description: > + Set to 1 if signal handling is broken, in which case the crash address is + likely to be wrong. + type: boolean + +CrashTime: + description: > + Crash time in seconds since the Epoch. + type: string + ping: true + +CreateStreamOnHGlobalFailure: + description: > + Set when failing to obtain a global memory handle during the creation of an + IPC proxy stream. + type: string + +CycleCollector: + description: > + Reason why the cycle collector crashed. + type: string + +DeviceResetReason: + description: > + Reason why a DirectX device has been reset, Windows only. + type: string + +DOMIPCEnabled: + description: > + Set to 1 when a tab is running in a content process + type: boolean + +EMCheckCompatibility: + description: > + Set to 1 if add-on compatibility checking is enabled. + type: boolean + +EventLoopNestingLevel: + description: > + Present only if higher than 0, indicates that we're running in a nested + event loop and indicates the nesting level. + type: integer + ping: true + +ExpectedStreamLen: + description: > + Expected length of an IPC proxy stream. + type: integer + +FlashProcessDump: + description: > + Type of process the flash plugin is running in, can be either "Broker" or + "Sandbox". + type: string + +FramePoisonBase: + description: > + Base pointer of the memory area used for the poison value we place in freed + memory. + type: string + content: false + +FramePoisonSize: + description: > + Size of the memory area used for the poison value we place in freed + memory. + type: integer + content: false + +GetHGlobalFromStreamFailure: + description: > + Error returned when invoking GetHGlobalFromStreamFailure() during the + creation of an IPC stream proxy. + type: string + +GMPLibraryPath: + description: > + Holds the path to the GMP plugin library. + type: string + +GMPPlugin: + description: > + Set to 1 if the GMP plugin is enabled. + type: boolean + +GPUProcessLaunchCount: + description: > + Number of times the GPU process was launched. + type: integer + +GPUProcessStatus: + description: > + Status of the GPU process, can be set to "Running" or "Destroyed" + type: string + +GraphicsCriticalError: + description: > + Information of a critical error that occurred within the graphics code. + type: string + +GraphicsSanityTest: + description: > + Annotation used in tests. + type: string + +GraphicsStartupTest: + description: > + Set to 1 by the graphics driver crash guard when it's activated. + type: boolean + +HangMonitorDescription: + description: > + Name of the hang monitor that generated the crash. + type: string + +HasDeviceTouchScreen: + description: > + Set to 1 if the device had a touch-screen, this only applies to Firefox + desktop as on mobile devices we assume a touch-screen is always present. + type: boolean + +IAccessibleConfig: + description: > + Set when something is seriously wrong with the IAccessible configuration in + the computer's registry. The value is always set to "NoSystemTypeLibOrPS" + type: string + +InstallTime: + description: > + The time when Firefox was installed expressed as seconds since the Epoch + type: integer + +InterfaceRegistrationInfoChild: + description: > + Microsoft COM interface registration annotation for the child process. + type: string + +InterfaceRegistrationInfoParent: + description: > + Microsoft COM interface registration annotation for the parent process. + type: string + +ipc_channel_error: + description: > + Set before a content process crashes because of an IPC channel error, holds + a description of the error. + type: string + ping: true + +IpcCreateEndpointsNsresult: + description: > + errno value retrieved after failing to create an IPC transport object. + type: integer + +IpcCreatePipeCloExecErrno: + description: > + errno value retrieved after failing to set the O_CLOEXEC flag on a pipe + used for IPC. + type: integer + +IpcCreatePipeFcntlErrno: + description: > + errno value retrieved after a call to fcntl() on a pipe used for IPC failed. + type: integer + +IpcCreatePipeSocketPairErrno: + description: > + errno value retrieved after a socketpair() call failed while creating an IPC + transport object. + type: integer + +IpcCreateTransportDupErrno: + description: > + errno value retrieved after a dup() call failed while creating an IPC + transport object. + type: integer + +IPCFatalErrorMsg: + description: > + Describes a fatal error that occurred during IPC operation. + type: string + +IPCFatalErrorProtocol: + description: > + Name of the protocol used by IPC when a fatal error occurred. + type: string + +IPCMessageName: + description: > + Name of the IPC message that caused a crash because it was too large. + type: string + +IPCMessageSize: + description: > + Size of the IPC message that caused a crash because it was too large. + type: integer + +IPCReadErrorReason: + description: > + Reason why reading an object via IPC failed. + type: string + +IPCShutdownState: + description: > + IPC shutdown state, can be set to either "RecvShutdown" or + "SendFinishShutdown" by a content process while it's shutting down. + type: string + +IPCSystemError: + description: > + Description of the last system error that occurred during IPC operation. + type: string + +IPCTransportFailureReason: + description: > + Reason why creating an IPC channel failed. + type: string + +IsGarbageCollecting: + description: > + If true then the JavaScript garbage collector was running when the crash + occurred. + type: boolean + ping: true + +JavaStackTrace: + description: > + Java stack trace, only present on Firefox for Android if we encounter an + uncaught Java exception. + type: string + +JSLargeAllocationFailure: + description: > + A large allocation couldn't be satisfied, check the JSOutOfMemory + description for the possible values of this annotation. + type: string + +JSOutOfMemory: + description: > + A small allocation couldn't be satisfied, the annotation may contain the + "Reporting", "Reported" or "Recovered" value. The first one means that + we crashed while responding to the OOM condition (possibly while running a + memory-pressure observers), the second that we crashed after having tried to + free some memory, and the last that the GC had managed to free enough memory + to satisfy the allocation. + type: string + +LowCommitSpaceEvents: + description: > + Number of times the available memory tracker has detected a that + commit-space was running low. This is a Windows-specific annotation. + type: integer + ping: true + +MarshalActCtxManifestPath: + description: > + Proxy stream marshalling current activation context manifest path. + type: string + +MozCrashReason: + description: > + Plaintext description of why Firefox crashed, this is usually set by + assertions and the like. + type: string + ping: true + +Notes: + description: > + Miscellaneous notes that can be appended to a crash. + type: string + +nsAsyncShutdownComponent: + description: > + Holds the contents of the nsAsyncShutdown.js script + type: string + +NumberOfProcessors: + description: > + Number of logical processors in the system. + type: integer + +OOMAllocationSize: + description: > + Size of the allocation that caused an out-of-memory condition. + type: string + ping: true + +PluginCpuUsage: + description: > + CPU usage of the plugin process. + type: string + +PluginFilename: + description: > + Plugin filename, only the process holding the plugin has this annotation. + type: string + +PluginHang: + description: > + The presence of this annotation indicates that this crash was generated in + response to a plugin hanging. + type: boolean + +PluginHangUIDuration: + description: > + Duration in milliseconds of the plugin hang that caused this crash. + type: integer + +PluginName: + description: > + Display name of a plugin, only the process holding the plugin has this + annotation. + type: string + +PluginVersion: + description: > + Version of a plugin, only the process holding the plugin has this + annotation. + type: string + +ProcessType: + description: > + Type of the process that crashed, can hold the values "content", "plugin" or + "gpu" currently. + type: string + +ProductName: + description: > + Application name (e.g. Firefox). + type: string + ping: true + +ProductID: + description: > + Application UUID (e.g. ec8030f7-c20a-464f-9b0e-13a3a9e97384). + type: string + ping: true + +ProxyStreamSize: + description: > + Size of an IPC proxy stream. + type: integer + +ProxyStreamSizeFrom: + description: > + Describes how the size of a proxy stream was obtained. It can be set to + either Stream::Stat or GlobalSize. + type: string + +ProxyStreamUnmarshalStatus: + description: > + Status of the proxy stream unmarshalling, see ipc/mscom/ProxyStream.cpp for + the various value this annotation can take. + type: string + +ProxyStreamValid: + description: > + Set to "false" when encountering an invalid IPC proxy stream. + type: string + +ReleaseChannel: + description: > + Application release channel (e.g. default, beta, ...) + type: string + ping: true + +RemoteType: + description: > + Type of the content process, can be set to "web", "file" or "extension". + type: string + ping: true + +SafeMode: + description: > + Set to 1 if the browser was started in safe mode. + type: boolean + +SecondsSinceLastCrash: + description: > + Time in seconds since the last crash occurred. + type: string + ping: true + +ServerURL: + description: > + URL used to post the crash report. + type: string + +SheetLoadFailure: + description: > + Set when failing to load a built-in style sheet. This can contain a + potentially very large amount of diagnostic information. + type: string + +ShutdownProgress: + description: > + Shutdown step at which the browser crashed, can be set to "quit-application", + "profile-change-teardown", "profile-before-change", "xpcom-will-shutdown" or + "xpcom-shutdown". + type: string + ping: true + +StartupCrash: + description: > + If set to 1 then this crash occurred during startup. + type: boolean + content: false + ping: true + +StartupTime: + description: > + The time when Firefox was launched expressed in seconds since the Epoch. + type: integer + content: false + +StatFailure: + description: > + Error returned when invoking IStream's Stat function during the creation + of an IPC proxy stream. + type: string + +StorageConnectionNotClosed: + description: > + This annotation is added when a mozStorage connection has not been properly + closed during shutdown. The annotation holds the filename of the database + associated with the connection. + type: string + +SystemMemoryUsePercentage: + description: > + Windows-only, percentage of physical memory in use. This annotation is + populated with the contents of the MEMORYSTATUSEX's structure dwMemoryLoad + field. + type: integer + ping: true + +TelemetryClientId: + description: > + Telemetry client ID. + type: string + +TelemetryEnvironment: + description: > + The telemetry environment in JSON format. + type: string + +TelemetryServerURL: + description: > + Telemetry server URL. Used to send main process crash pings directly from + the crashreporter client. + type: string + +TelemetrySessionId: + description: > + Telemetry session ID. + type: string + +TestKey: + description: > + Annotation used in tests. + type: string + +TestUnicode: + description: > + Annotation used in tests. + type: string + +TextureUsage: + description: > + Amount of memory in bytes consumed by textures. + type: string + ping: true + +ThreadIdNameMapping: + description: > + List of thread names with their corresponding thread IDs. + type: string + +TotalPageFile: + description: > + Windows-only, current committed memory limit. This annotation is + populated with the contents of the MEMORYSTATUSEX's structure + ullTotalPageFile field. + type: string + ping: true + +TotalPhysicalMemory: + description: > + Windows-only, amount of physical memory in bytes. This annotation is + populated with the contents of the MEMORYSTATUSEX's structure + ullTotalPhys field. + type: string + ping: true + +TotalVirtualMemory: + description: > + Windows-only, size of the virtual address space. This annotation is + populated with the contents of the MEMORYSTATUSEX's structure + ullTotalVirtual field. + type: string + ping: true + +UnknownNetAddrSocketFamily: + description: > + An unknown network address family was requested to Necko. The value is the + requested family number. + type: integer + +UnmarshalActCtx: + description: > + Proxy stream unmarshalling current activation context. + type: string + +UnmarshalActCtxManifestPath: + description: > + Proxy stream unmarshalling current activation context manifest path. + type: string + +UptimeTS: + description: > + Uptime in seconds. This annotation uses a string instead of an integer + because it has a fractional component. + type: string + ping: true + +URL: + description: > + URL being loaded. + type: string + content: false + +User32BeforeBlocklist: + description: > + Set to 1 if user32.dll was loaded before we could install the DLL blocklist. + type: boolean + ping: true + +useragent_locale: + description: > + User-agent locale. + type: string + +Vendor: + description: > + Application vendor (e.g. Mozilla). + type: string + +Version: + description: > + Product version. + type: string + +Winsock_LSP: + description: > + Information on winsock LSPs injected in our networking stack. + type: string diff --git a/toolkit/crashreporter/client/moz.build b/toolkit/crashreporter/client/moz.build index 277502fac9f5..85f5cb40faa0 100644 --- a/toolkit/crashreporter/client/moz.build +++ b/toolkit/crashreporter/client/moz.build @@ -8,6 +8,7 @@ if CONFIG['OS_TARGET'] != 'Android': Program('crashreporter') UNIFIED_SOURCES += [ + '../CrashAnnotations.cpp', 'crashreporter.cpp', 'ping.cpp', ] diff --git a/toolkit/crashreporter/client/ping.cpp b/toolkit/crashreporter/client/ping.cpp index 8340d0cc3722..05a9566bbda3 100644 --- a/toolkit/crashreporter/client/ping.cpp +++ b/toolkit/crashreporter/client/ping.cpp @@ -20,6 +20,8 @@ #include "json/json.h" +#include "CrashAnnotations.h" + using std::string; namespace CrashReporter { @@ -120,45 +122,15 @@ const int kTelemetryVersion = 4; static Json::Value CreateMetadataNode(StringTable& strings) { - // The following list should be kept in sync with the one in CrashManager.jsm - const char *entries[] = { - "AsyncShutdownTimeout", - "AvailablePageFile", - "AvailablePhysicalMemory", - "AvailableVirtualMemory", - "BlockedDllList", - "BlocklistInitFailed", - "BuildID", - "ContainsMemoryReport", - "CrashTime", - "EventLoopNestingLevel", - "ipc_channel_error", - "IsGarbageCollecting", - "LowCommitSpaceEvents", - "MozCrashReason", - "OOMAllocationSize", - "ProductID", - "ProductName", - "ReleaseChannel", - "RemoteType", - "SecondsSinceLastCrash", - "ShutdownProgress", - "StartupCrash", - "SystemMemoryUsePercentage", - "TextureUsage", - "TotalPageFile", - "TotalPhysicalMemory", - "TotalVirtualMemory", - "UptimeTS", - "User32BeforeBlocklist", - "Version", - }; - Json::Value node; - for (auto entry : entries) { - if ((strings.find(entry) != strings.end()) && !strings[entry].empty()) { - node[entry] = strings[entry]; + for (auto line : strings) { + Annotation annotation; + + if (AnnotationFromString(annotation, line.first.c_str())) { + if (IsAnnotationWhitelistedForPing(annotation)) { + node[line.first] = line.second; + } } } diff --git a/toolkit/crashreporter/generate_crash_reporter_sources.py b/toolkit/crashreporter/generate_crash_reporter_sources.py new file mode 100644 index 000000000000..30ac6dad8282 --- /dev/null +++ b/toolkit/crashreporter/generate_crash_reporter_sources.py @@ -0,0 +1,200 @@ +# 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/. + +import string +import sys +import textwrap +import yaml + +############################################################################### +# Language-agnostic functionality # +############################################################################### + +template_header = "/* This file was autogenerated by " \ + "toolkit/crashreporter/generate_crash_reporter_sources.py. DO NOT EDIT */\n\n" + + +def validate_annotations(annotations): + """ Ensure that the annotations have all the required fields """ + + for (name, data) in sorted(annotations.items()): + if "description" not in data: + print("Annotation " + name + " does not have a description\n") + sys.exit(1) + if "type" not in data: + print("Annotation " + name + " does not have a type\n") + sys.exit(1) + else: + annotation_type = data.get("type") + valid_types = ["boolean", "integer", "string"] + if not any(annotation_type == t for t in valid_types): + print("Annotation " + name + " has an unknown type: " + annotation_type + "\n") + sys.exit(1) + + +def read_annotations(annotations_filename): + """Read the annotations from a YAML file. + If an error is encountered quit the program.""" + + try: + with open(annotations_filename, "r") as annotations_file: + annotations = yaml.safe_load(annotations_file) + except (IOError, ValueError) as e: + print("Error parsing " + annotations_filename + ":\n" + str(e) + "\n") + sys.exit(1) + + validate_annotations(annotations) + + return annotations + + +def read_template(template_filename): + """Read the contents of the template. + If an error is encountered quit the program.""" + + try: + with open(template_filename, "r") as template_file: + template = template_file.read() + except IOError as ex: + print("Error when reading " + template_filename + ":\n" + str(ex) + "\n") + sys.exit(1) + + return template + + +def extract_crash_ping_whitelist(annotations): + """Extract an array holding the names of the annotations whitelisted for + inclusion in the crash ping.""" + + return [name + for (name, data) + in sorted(annotations.items()) + if data.get("ping", False)] + + +def extract_content_process_blacklist(annotations): + """Extract an array holding the names of the annotations blacklisted when + read from a content process.""" + + return [name + for (name, data) + in sorted(annotations.items()) + if not data.get("content", True)] + +############################################################################### +# C++ code generation # +############################################################################### + + +def generate_strings(annotations): + """Generate strings corresponding to every annotation.""" + + names = [" \"" + data.get("altname", name) + "\"" + for (name, data) + in sorted(annotations.items())] + + return ",\n".join(names) + + +def generate_enum(annotations): + """Generate the C++ typed enum holding all the annotations and return it + as a string.""" + + enum = "" + + for i, (name, _) in enumerate(sorted(annotations.items())): + enum += " " + name + " = " + str(i) + ",\n" + + enum += " Count = " + str(len(annotations)) + + return enum + + +def generate_array_initializer(contents): + """Generates the initializer for a C++ array of annotations.""" + + initializer = [" Annotation::" + name for name in contents] + + return ",\n".join(initializer) + + +def generate_header(template, annotations): + """Generate a header by filling the template with the the list of + annotations and return it as a string.""" + + whitelist = extract_crash_ping_whitelist(annotations) + blacklist = extract_content_process_blacklist(annotations) + + return template_header + string.Template(template).substitute({ + "enum": generate_enum(annotations), + "strings": generate_strings(annotations), + "whitelist": generate_array_initializer(whitelist), + "blacklist": generate_array_initializer(blacklist), + }) + + +def emit_header(output, template_filename, annotations_filename): + """Generate the C++ header from the template and write it out.""" + + annotations = read_annotations(annotations_filename) + template = read_template(template_filename) + generated_header = generate_header(template, annotations) + + try: + output.write(generated_header) + except IOError as ex: + print("Error while writing out the generated file:\n" + str(ex) + "\n") + sys.exit(1) + +############################################################################### +# Java code generation # +############################################################################### + + +def generate_java_array_initializer(contents): + """Generates the initializer for an array of strings. + Effectively turns `["a", "b"]` into ' \"a\",\n \"b\"\n'.""" + + initializer = "" + + for name in contents: + initializer += " \"" + name + "\",\n" + + return initializer.strip(",\n") + + +def generate_class(template, annotations): + """Fill the class template from the list of annotations.""" + + whitelist = extract_crash_ping_whitelist(annotations) + + return template_header + string.Template(template).substitute({ + "whitelist": generate_java_array_initializer(whitelist), + }) + + +def emit_class(output, annotations_filename): + """Generate the CrashReporterConstants.java file.""" + + template = textwrap.dedent("""\ + package org.mozilla.gecko; + + /** + * Constants used by the crash reporter. These are generated so that they + * are kept in sync with the other C++ and JS users. + */ + public class CrashReporterConstants { + public static final String[] ANNOTATION_WHITELIST = { + ${whitelist} + }; + }""") + + annotations = read_annotations(annotations_filename) + generated_class = generate_class(template, annotations) + + try: + output.write(generated_class) + except IOError as ex: + print("Error while writing out the generated file:\n" + str(ex) + "\n") + sys.exit(1) diff --git a/toolkit/crashreporter/moz.build b/toolkit/crashreporter/moz.build index c5e8b111d323..0b710b8348ef 100644 --- a/toolkit/crashreporter/moz.build +++ b/toolkit/crashreporter/moz.build @@ -9,13 +9,19 @@ SPHINX_TREES['crashreporter'] = 'docs' with Files('docs/**'): SCHEDULES.exclusive = ['docs'] +GENERATED_FILES += [ + 'CrashAnnotations.h', +] + EXPORTS += [ + '!CrashAnnotations.h', 'nsExceptionHandler.h', ] JAR_MANIFESTS += ['jar.mn'] UNIFIED_SOURCES = [ + 'CrashAnnotations.cpp', 'nsExceptionHandlerUtils.cpp', ] @@ -125,6 +131,13 @@ else: 'nsDummyExceptionHandler.cpp', ] +# Generate CrashAnnotations.h +crash_annotations = GENERATED_FILES['CrashAnnotations.h'] +crash_annotations.script = 'generate_crash_reporter_sources.py:emit_header' +crash_annotations.inputs = [ + 'CrashAnnotations.h.in', + 'CrashAnnotations.yaml', +] with Files('**'): BUG_COMPONENT = ('Toolkit', 'Crash Reporting') diff --git a/toolkit/crashreporter/nsDummyExceptionHandler.cpp b/toolkit/crashreporter/nsDummyExceptionHandler.cpp index f4eef3f04239..26780d0e2ff5 100644 --- a/toolkit/crashreporter/nsDummyExceptionHandler.cpp +++ b/toolkit/crashreporter/nsDummyExceptionHandler.cpp @@ -66,14 +66,31 @@ UnsetExceptionHandler() } nsresult -AnnotateCrashReport(const nsACString& key, - const nsACString& data) +AnnotateCrashReport(Annotation key, bool data) { return NS_ERROR_NOT_IMPLEMENTED; } nsresult -RemoveCrashReportAnnotation(const nsACString& key) +AnnotateCrashReport(Annotation key, int data) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult +AnnotateCrashReport(Annotation key, unsigned int data) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult +AnnotateCrashReport(Annotation key, const nsACString& data) +{ + return NS_ERROR_NOT_IMPLEMENTED; +} + +nsresult +RemoveCrashReportAnnotation(Annotation key) { return NS_ERROR_NOT_IMPLEMENTED; } diff --git a/toolkit/crashreporter/nsExceptionHandler.cpp b/toolkit/crashreporter/nsExceptionHandler.cpp index 7fb75ccc5f0c..1fd7adc06da3 100644 --- a/toolkit/crashreporter/nsExceptionHandler.cpp +++ b/toolkit/crashreporter/nsExceptionHandler.cpp @@ -12,6 +12,7 @@ #include "nsDirectoryService.h" #include "nsDataHashtable.h" #include "mozilla/ArrayUtils.h" +#include "mozilla/EnumeratedRange.h" #include "mozilla/Services.h" #include "nsIObserverService.h" #include "mozilla/Unused.h" @@ -233,7 +234,7 @@ static const char* androidCrashReporterJobId = nullptr; // this holds additional data sent via the API static Mutex* crashReporterAPILock; static Mutex* notesFieldLock; -static AnnotationTable* crashReporterAPIData_Hash; +static AnnotationTable crashReporterAPIData_Table; static nsCString* crashReporterAPIData = nullptr; static nsCString* crashEventAPIData = nullptr; static nsCString* notesField = nullptr; @@ -324,15 +325,6 @@ private: }; #endif // MOZ_CRASHREPORTER_INJECTOR -// Crashreporter annotations that we don't send along in subprocess reports. -static const char* kSubprocessBlacklist[] = { - "FramePoisonBase", - "FramePoisonSize", - "StartupCrash", - "StartupTime", - "URL" -}; - // If annotations are attempted before the crash reporter is enabled, // they queue up here. class DelayedNote; @@ -679,13 +671,16 @@ WriteString(PlatformWriter& pw, const char* str) { pw.WriteBuffer(str, len); } -template static void -WriteAnnotation(PlatformWriter& pw, const char (&name)[N], - const char* value) { - WriteLiteral(pw, name); +WriteAnnotation(PlatformWriter& pw, const Annotation name, + const char* value, size_t len = 0) { + WriteString(pw, AnnotationToString(name)); WriteLiteral(pw, "="); - WriteString(pw, value); + if (len == 0) { + WriteString(pw, value); + } else { + pw.WriteBuffer(value, len); + } WriteLiteral(pw, "\n"); }; @@ -737,13 +732,18 @@ WriteGlobalMemoryStatus(PlatformWriter* apiData, PlatformWriter* eventFile) WriteAnnotation(*eventFile, name, buffer); \ } - WRITE_STATEX_FIELD(dwMemoryLoad, "SystemMemoryUsePercentage", ltoa); - WRITE_STATEX_FIELD(ullTotalVirtual, "TotalVirtualMemory", _ui64toa); - WRITE_STATEX_FIELD(ullAvailVirtual, "AvailableVirtualMemory", _ui64toa); - WRITE_STATEX_FIELD(ullTotalPageFile, "TotalPageFile", _ui64toa); - WRITE_STATEX_FIELD(ullAvailPageFile, "AvailablePageFile", _ui64toa); - WRITE_STATEX_FIELD(ullTotalPhys, "TotalPhysicalMemory", _ui64toa); - WRITE_STATEX_FIELD(ullAvailPhys, "AvailablePhysicalMemory", _ui64toa); + WRITE_STATEX_FIELD(dwMemoryLoad, Annotation::SystemMemoryUsePercentage, + ltoa); + WRITE_STATEX_FIELD(ullTotalVirtual, Annotation::TotalVirtualMemory, + _ui64toa); + WRITE_STATEX_FIELD(ullAvailVirtual, Annotation::AvailableVirtualMemory, + _ui64toa); + WRITE_STATEX_FIELD(ullTotalPageFile, Annotation::TotalPageFile, _ui64toa); + WRITE_STATEX_FIELD(ullAvailPageFile, Annotation::AvailablePageFile, + _ui64toa); + WRITE_STATEX_FIELD(ullTotalPhys, Annotation::TotalPhysicalMemory, _ui64toa); + WRITE_STATEX_FIELD(ullAvailPhys, Annotation::AvailablePhysicalMemory, + _ui64toa); #undef WRITE_STATEX_FIELD } @@ -1035,41 +1035,43 @@ MinidumpCallback( } if (currentSessionId) { - WriteAnnotation(apiData, "TelemetrySessionId", currentSessionId); - WriteAnnotation(eventFile, "TelemetrySessionId", currentSessionId); + WriteAnnotation(apiData, Annotation::TelemetrySessionId, + currentSessionId); + WriteAnnotation(eventFile, Annotation::TelemetrySessionId, + currentSessionId); } - WriteAnnotation(apiData, "CrashTime", crashTimeString); - WriteAnnotation(eventFile, "CrashTime", crashTimeString); + WriteAnnotation(apiData, Annotation::CrashTime, crashTimeString); + WriteAnnotation(eventFile, Annotation::CrashTime, crashTimeString); - WriteAnnotation(apiData, "UptimeTS", uptimeTSString); - WriteAnnotation(eventFile, "UptimeTS", uptimeTSString); + WriteAnnotation(apiData, Annotation::UptimeTS, uptimeTSString); + WriteAnnotation(eventFile, Annotation::UptimeTS, uptimeTSString); if (timeSinceLastCrash != 0) { - WriteAnnotation(apiData, "SecondsSinceLastCrash", + WriteAnnotation(apiData, Annotation::SecondsSinceLastCrash, timeSinceLastCrashString); - WriteAnnotation(eventFile, "SecondsSinceLastCrash", + WriteAnnotation(eventFile, Annotation::SecondsSinceLastCrash, timeSinceLastCrashString); } if (isGarbageCollecting) { - WriteAnnotation(apiData, "IsGarbageCollecting", "1"); - WriteAnnotation(eventFile, "IsGarbageCollecting", "1"); + WriteAnnotation(apiData, Annotation::IsGarbageCollecting, "1"); + WriteAnnotation(eventFile, Annotation::IsGarbageCollecting, "1"); } char buffer[128]; if (eventloopNestingLevel > 0) { XP_STOA(eventloopNestingLevel, buffer, 10); - WriteAnnotation(apiData, "EventLoopNestingLevel", buffer); - WriteAnnotation(eventFile, "EventLoopNestingLevel", buffer); + WriteAnnotation(apiData, Annotation::EventLoopNestingLevel, buffer); + WriteAnnotation(eventFile, Annotation::EventLoopNestingLevel, buffer); } #ifdef XP_WIN if (gBreakpadReservedVM) { _ui64toa(uintptr_t(gBreakpadReservedVM), buffer, 10); - WriteAnnotation(apiData, "BreakpadReserveAddress", buffer); + WriteAnnotation(apiData, Annotation::BreakpadReserveAddress, buffer); _ui64toa(kReserveSize, buffer, 10); - WriteAnnotation(apiData, "BreakpadReserveSize", buffer); + WriteAnnotation(apiData, Annotation::BreakpadReserveSize, buffer); } #ifdef HAS_DLL_BLOCKLIST @@ -1085,41 +1087,37 @@ MinidumpCallback( size_t rust_panic_len; if (get_rust_panic_reason(&rust_panic_reason, &rust_panic_len)) { // rust_panic_reason is not null-terminated. - WriteLiteral(apiData, "MozCrashReason="); - apiData.WriteBuffer(rust_panic_reason, rust_panic_len); - WriteLiteral(apiData, "\n"); - WriteLiteral(eventFile, "MozCrashReason="); - eventFile.WriteBuffer(rust_panic_reason, rust_panic_len); - WriteLiteral(eventFile, "\n"); + WriteAnnotation(apiData, Annotation::MozCrashReason, rust_panic_reason, + rust_panic_len); + WriteAnnotation(eventFile, Annotation::MozCrashReason, rust_panic_reason, + rust_panic_len); } else if (gMozCrashReason) { - WriteAnnotation(apiData, "MozCrashReason", gMozCrashReason); - WriteAnnotation(eventFile, "MozCrashReason", gMozCrashReason); + WriteAnnotation(apiData, Annotation::MozCrashReason, gMozCrashReason); + WriteAnnotation(eventFile, Annotation::MozCrashReason, gMozCrashReason); } if (oomAllocationSizeBuffer[0]) { - WriteAnnotation(apiData, "OOMAllocationSize", oomAllocationSizeBuffer); - WriteAnnotation(eventFile, "OOMAllocationSize", oomAllocationSizeBuffer); + WriteAnnotation(apiData, Annotation::OOMAllocationSize, + oomAllocationSizeBuffer); + WriteAnnotation(eventFile, Annotation::OOMAllocationSize, + oomAllocationSizeBuffer); } if (texturesSizeBuffer[0]) { - WriteAnnotation(apiData, "TextureUsage", texturesSizeBuffer); - WriteAnnotation(eventFile, "TextureUsage", texturesSizeBuffer); + WriteAnnotation(apiData, Annotation::TextureUsage, texturesSizeBuffer); + WriteAnnotation(eventFile, Annotation::TextureUsage, texturesSizeBuffer); } if (memoryReportPath) { - WriteLiteral(apiData, "ContainsMemoryReport=1\n"); - WriteLiteral(eventFile, "ContainsMemoryReport=1\n"); + WriteAnnotation(apiData, Annotation::ContainsMemoryReport, "1"); + WriteAnnotation(eventFile, Annotation::ContainsMemoryReport, "1"); } std::function getThreadAnnotationCB = - [&] (const char * aAnnotation) -> void { - if (aAnnotation) { - WriteLiteral(apiData, "ThreadIdNameMapping="); - WriteLiteral(eventFile, "ThreadIdNameMapping="); - WriteString(apiData, aAnnotation); - WriteString(eventFile, aAnnotation); - WriteLiteral(apiData, "\n"); - WriteLiteral(eventFile, "\n"); + [&] (const char* aValue) -> void { + if (aValue) { + WriteAnnotation(apiData, Annotation::ThreadIdNameMapping, aValue); + WriteAnnotation(eventFile, Annotation::ThreadIdNameMapping, aValue); } }; GetFlatThreadAnnotation(getThreadAnnotationCB, false); @@ -1286,26 +1284,24 @@ PrepareChildExceptionTimeAnnotations(void* context) } if (oomAllocationSizeBuffer[0]) { - WriteAnnotation(apiData, "OOMAllocationSize", oomAllocationSizeBuffer); + WriteAnnotation(apiData, Annotation::OOMAllocationSize, + oomAllocationSizeBuffer); } char* rust_panic_reason; size_t rust_panic_len; if (get_rust_panic_reason(&rust_panic_reason, &rust_panic_len)) { // rust_panic_reason is not null-terminated. - WriteLiteral(apiData, "MozCrashReason="); - apiData.WriteBuffer(rust_panic_reason, rust_panic_len); - WriteLiteral(apiData, "\n"); + WriteAnnotation(apiData, Annotation::MozCrashReason, rust_panic_reason, + rust_panic_len); } else if (gMozCrashReason) { - WriteAnnotation(apiData, "MozCrashReason", gMozCrashReason); + WriteAnnotation(apiData, Annotation::MozCrashReason, gMozCrashReason); } std::function getThreadAnnotationCB = - [&] (const char * aAnnotation) -> void { - if (aAnnotation) { - WriteLiteral(apiData, "ThreadIdNameMapping="); - WriteString(apiData, aAnnotation); - WriteLiteral(apiData, "\n"); + [&] (const char * aValue) -> void { + if (aValue) { + WriteAnnotation(apiData, Annotation::ThreadIdNameMapping, aValue); } }; GetFlatThreadAnnotation(getThreadAnnotationCB, true); @@ -1508,10 +1504,6 @@ nsresult SetExceptionHandler(nsIFile* aXREDirectory, NS_ASSERTION(!notesFieldLock, "Shouldn't have a lock yet"); notesFieldLock = new Mutex("notesFieldLock"); - crashReporterAPIData_Hash = - new nsDataHashtable(); - NS_ENSURE_TRUE(crashReporterAPIData_Hash, NS_ERROR_OUT_OF_MEMORY); - notesField = new nsCString(); NS_ENSURE_TRUE(notesField, NS_ERROR_OUT_OF_MEMORY); @@ -1678,8 +1670,7 @@ nsresult SetExceptionHandler(nsIFile* aXREDirectory, char timeString[32]; time_t startupTime = time(nullptr); XP_TTOA(startupTime, timeString, 10); - AnnotateCrashReport(NS_LITERAL_CSTRING("StartupTime"), - nsDependentCString(timeString)); + AnnotateCrashReport(Annotation::StartupTime, nsDependentCString(timeString)); #if defined(XP_MACOSX) // On OS X, many testers like to see the OS crash reporting dialog @@ -1933,7 +1924,7 @@ nsresult SetupExtraData(nsIFile* aAppDataDirectory, const nsACString& aBuildID) if(NS_SUCCEEDED(GetOrInit(dataDirectory, NS_LITERAL_CSTRING("InstallTime") + aBuildID, data, InitInstallTime))) - AnnotateCrashReport(NS_LITERAL_CSTRING("InstallTime"), data); + AnnotateCrashReport(Annotation::InstallTime, data); // this is a little different, since we can't init it with anything, // since it's stored at crash time, and we can't annotate the @@ -1991,8 +1982,9 @@ nsresult UnsetExceptionHandler() // do this here in the unlikely case that we succeeded in allocating // our strings but failed to allocate gExceptionHandler. - delete crashReporterAPIData_Hash; - crashReporterAPIData_Hash = nullptr; + std::fill(crashReporterAPIData_Table.begin(), + crashReporterAPIData_Table.end(), + EmptyCString()); delete crashReporterAPILock; crashReporterAPILock = nullptr; @@ -2079,12 +2071,8 @@ static void ReplaceChar(nsCString& str, const nsACString& character, } static nsresult -EscapeAnnotation(const nsACString& key, const nsACString& data, nsCString& escapedData) +EscapeAnnotation(const nsACString& data, nsCString& escapedData) { - if (FindInReadable(NS_LITERAL_CSTRING("="), key) || - FindInReadable(NS_LITERAL_CSTRING("\n"), key)) - return NS_ERROR_INVALID_ARG; - if (FindInReadable(NS_LITERAL_CSTRING("\0"), data)) return NS_ERROR_INVALID_ARG; @@ -2102,15 +2090,15 @@ EscapeAnnotation(const nsACString& key, const nsACString& data, nsCString& escap class DelayedNote { public: - DelayedNote(const nsACString& aKey, const nsACString& aData) - : mKey(aKey), mData(aData), mType(Annotation) {} + DelayedNote(Annotation aKey, const nsACString& aData) + : mKey(aKey), mData(aData), mType(CrashAnnotation) {} explicit DelayedNote(const nsACString& aData) : mData(aData), mType(AppNote) {} void Run() { - if (mType == Annotation) { + if (mType == CrashAnnotation) { AnnotateCrashReport(mKey, mData); } else { AppendAppNotesToCrashReport(mData); @@ -2118,9 +2106,9 @@ class DelayedNote } private: - nsCString mKey; + Annotation mKey; nsCString mData; - enum AnnotationType { Annotation, AppNote } mType; + enum AnnotationType { CrashAnnotation, AppNote } mType; }; static void @@ -2144,20 +2132,42 @@ RunAndCleanUpDelayedNotes() } } -nsresult AnnotateCrashReport(const nsACString& key, const nsACString& data) +nsresult AnnotateCrashReport(Annotation key, bool data) +{ + return AnnotateCrashReport(key, data ? NS_LITERAL_CSTRING("1") + : NS_LITERAL_CSTRING("0")); +} + +nsresult AnnotateCrashReport(Annotation key, int data) +{ + nsAutoCString dataString; + dataString.AppendInt(data); + + return AnnotateCrashReport(key, dataString); +} + +nsresult AnnotateCrashReport(Annotation key, unsigned int data) +{ + nsAutoCString dataString; + dataString.AppendInt(data); + + return AnnotateCrashReport(key, dataString); +} + +nsresult AnnotateCrashReport(Annotation key, const nsACString& data) { if (!GetEnabled()) return NS_ERROR_NOT_INITIALIZED; nsCString escapedData; - nsresult rv = EscapeAnnotation(key, data, escapedData); + nsresult rv = EscapeAnnotation(data, escapedData); if (NS_FAILED(rv)) return rv; if (!XRE_IsParentProcess()) { // The newer CrashReporterClient can be used from any thread. if (RefPtr client = CrashReporterClient::GetSingleton()) { - client->AnnotateCrashReport(nsCString(key), escapedData); + client->AnnotateCrashReport(key, escapedData); return NS_OK; } @@ -2170,18 +2180,18 @@ nsresult AnnotateCrashReport(const nsACString& key, const nsACString& data) MutexAutoLock lock(*crashReporterAPILock); - crashReporterAPIData_Hash->Put(key, escapedData); + crashReporterAPIData_Table[key] = escapedData; // now rebuild the file contents crashReporterAPIData->Truncate(0); crashEventAPIData->Truncate(0); - for (auto it = crashReporterAPIData_Hash->Iter(); !it.Done(); it.Next()) { - const nsACString& key = it.Key(); - nsCString entry = it.Data(); + for (auto key : MakeEnumeratedRange(Annotation::Count)) { + nsDependentCString str(AnnotationToString(key)); + nsCString entry = crashReporterAPIData_Table[key]; if (!entry.IsEmpty()) { NS_NAMED_LITERAL_CSTRING(kEquals, "="); NS_NAMED_LITERAL_CSTRING(kNewline, "\n"); - nsAutoCString line = key + kEquals + entry + kNewline; + nsAutoCString line = str + kEquals + entry + kNewline; crashReporterAPIData->Append(line); crashEventAPIData->Append(line); @@ -2191,9 +2201,9 @@ nsresult AnnotateCrashReport(const nsACString& key, const nsACString& data) return NS_OK; } -nsresult RemoveCrashReportAnnotation(const nsACString& key) +nsresult RemoveCrashReportAnnotation(Annotation key) { - return AnnotateCrashReport(key, NS_LITERAL_CSTRING("")); + return AnnotateCrashReport(key, EmptyCString()); } nsresult SetGarbageCollecting(bool collecting) @@ -2230,7 +2240,7 @@ nsresult AppendAppNotesToCrashReport(const nsACString& data) // we must ensure that the data is escaped and valid before the parent // sees it. nsCString escapedData; - nsresult rv = EscapeAnnotation(NS_LITERAL_CSTRING("Notes"), data, escapedData); + nsresult rv = EscapeAnnotation(data, escapedData); if (NS_FAILED(rv)) return rv; @@ -2249,20 +2259,21 @@ nsresult AppendAppNotesToCrashReport(const nsACString& data) MutexAutoLock lock(*notesFieldLock); notesField->Append(data); - return AnnotateCrashReport(NS_LITERAL_CSTRING("Notes"), *notesField); + return AnnotateCrashReport(Annotation::Notes, *notesField); } // Returns true if found, false if not found. static bool -GetAnnotation(const nsACString& key, nsACString& data) +GetAnnotation(CrashReporter::Annotation key, nsACString& data) { if (!gExceptionHandler) return false; MutexAutoLock lock(*crashReporterAPILock); - nsAutoCString entry; - if (!crashReporterAPIData_Hash->Get(key, &entry)) + nsCString entry = crashReporterAPIData_Table[key]; + if (entry.IsEmpty()) { return false; + } data = entry; return true; @@ -2310,15 +2321,14 @@ bool GetServerURL(nsACString& aServerURL) if (!gExceptionHandler) return false; - return GetAnnotation(NS_LITERAL_CSTRING("ServerURL"), aServerURL); + return GetAnnotation(CrashReporter::Annotation::ServerURL, aServerURL); } nsresult SetServerURL(const nsACString& aServerURL) { // store server URL with the API data // the client knows to handle this specially - return AnnotateCrashReport(NS_LITERAL_CSTRING("ServerURL"), - aServerURL); + return AnnotateCrashReport(Annotation::ServerURL, aServerURL); } nsresult @@ -2941,25 +2951,11 @@ AppendExtraData(const nsAString& id, const AnnotationTable& data) //----------------------------------------------------------------------------- // Helpers for AppendExtraData() // -struct Blacklist { - Blacklist() : mItems(nullptr), mLen(0) { } - Blacklist(const char** items, int len) : mItems(items), mLen(len) { } - - bool Contains(const nsACString& key) const { - for (int i = 0; i < mLen; ++i) - if (key.EqualsASCII(mItems[i])) - return true; - return false; - } - - const char** mItems; - const int mLen; -}; - static void -WriteAnnotation(PRFileDesc* fd, const nsACString& key, const nsACString& value) +WriteAnnotation(PRFileDesc* fd, const Annotation key, const nsACString& value) { - PR_Write(fd, key.BeginReading(), key.Length()); + const char* annotation = AnnotationToString(key); + PR_Write(fd, annotation, strlen(annotation)); PR_Write(fd, "=", 1); PR_Write(fd, value.BeginReading(), value.Length()); PR_Write(fd, "\n", 1); @@ -2979,9 +2975,9 @@ WriteLiteral(PRFileDesc* fd, const char (&str)[N]) static bool WriteExtraData(nsIFile* extraFile, const AnnotationTable& data, - const Blacklist& blacklist, bool writeCrashTime=false, - bool truncate=false) + bool truncate=false, + bool content=false) { PRFileDesc* fd; int truncOrAppend = truncate ? PR_TRUNCATE : PR_APPEND; @@ -2991,13 +2987,14 @@ WriteExtraData(nsIFile* extraFile, if (NS_FAILED(rv)) return false; - for (auto iter = data.ConstIter(); !iter.Done(); iter.Next()) { - // Skip entries in the blacklist. - const nsACString& key = iter.Key(); - if (blacklist.Contains(key)) { - continue; + for (auto key : MakeEnumeratedRange(Annotation::Count)) { + nsCString value = data[key]; + // Skip entries in the blacklist and empty entries. + if ((content && IsAnnotationBlacklistedForContent(key)) || + value.IsEmpty()) { + continue; } - WriteAnnotation(fd, key, iter.Data()); + WriteAnnotation(fd, key, value); } if (writeCrashTime) { @@ -3006,7 +3003,7 @@ WriteExtraData(nsIFile* extraFile, XP_TTOA(crashTime, crashTimeString, 10); WriteAnnotation(fd, - nsDependentCString("CrashTime"), + Annotation::CrashTime, nsDependentCString(crashTimeString)); double uptimeTS = (TimeStamp::NowLoRes() - @@ -3015,12 +3012,13 @@ WriteExtraData(nsIFile* extraFile, SimpleNoCLibDtoA(uptimeTS, uptimeTSString, sizeof(uptimeTSString)); WriteAnnotation(fd, - nsDependentCString("UptimeTS"), + Annotation::UptimeTS, nsDependentCString(uptimeTSString)); } if (memoryReportPath) { - WriteLiteral(fd, "ContainsMemoryReport=1\n"); + WriteAnnotation(fd, Annotation::ContainsMemoryReport, + NS_LITERAL_CSTRING("1")); } PR_Close(fd); @@ -3030,7 +3028,7 @@ WriteExtraData(nsIFile* extraFile, bool AppendExtraData(nsIFile* extraFile, const AnnotationTable& data) { - return WriteExtraData(extraFile, data, Blacklist()); + return WriteExtraData(extraFile, data); } static bool @@ -3075,24 +3073,32 @@ ReadAndValidateExceptionTimeAnnotations(FILE*& aFd, if (strchr(line, '\n')) { break; } + // The annotation sould be known + Annotation annotation; + if (!AnnotationFromString(annotation, line)) { + break; + } // Data should have been escaped by the child if (!IsDataEscaped(data)) { break; } // Looks good, save the (line,data) pair - aAnnotations.Put(nsDependentCString(line), - nsDependentCString(data, dataLen)); + aAnnotations[annotation] = nsDependentCString(data, dataLen); } } /** + * Writes extra data in the .extra file corresponding to the specified + * minidump. If `content` is set to true then this assumes that of a child + * process. + * * NOTE: One side effect of this function is that it deletes the * GeckoChildCrash.extra file if it exists, once processed. */ static bool WriteExtraForMinidump(nsIFile* minidump, uint32_t pid, - const Blacklist& blacklist, + bool content, nsIFile** extraFile) { nsCOMPtr extra; @@ -3102,10 +3108,10 @@ WriteExtraForMinidump(nsIFile* minidump, { MutexAutoLock lock(*crashReporterAPILock); - if (!WriteExtraData(extra, *crashReporterAPIData_Hash, - blacklist, + if (!WriteExtraData(extra, crashReporterAPIData_Table, true /*write crash time*/, - true /*truncate*/)) { + true /*truncate*/, + content)) { return false; } } @@ -3210,11 +3216,10 @@ OnChildProcessDumpRequested(void* aContext, aClientInfo->pid(); #endif - if (!WriteExtraForMinidump(minidump, pid, - Blacklist(kSubprocessBlacklist, - ArrayLength(kSubprocessBlacklist)), - getter_AddRefs(extraFile))) + if (!WriteExtraForMinidump(minidump, pid, /* content */ true, + getter_AddRefs(extraFile))) { return; + } if (ShouldReport()) { nsCOMPtr memoryReport; @@ -3737,7 +3742,8 @@ PairedDumpCallbackExtra( nsCOMPtr& minidump = *static_cast< nsCOMPtr* >(context); nsCOMPtr extra; - return WriteExtraForMinidump(minidump, 0, Blacklist(), getter_AddRefs(extra)); + return WriteExtraForMinidump(minidump, 0, /* content */ false, + getter_AddRefs(extra)); } ThreadId diff --git a/toolkit/crashreporter/nsExceptionHandler.h b/toolkit/crashreporter/nsExceptionHandler.h index 9c5d4c26ec52..7ffa38eff5e8 100644 --- a/toolkit/crashreporter/nsExceptionHandler.h +++ b/toolkit/crashreporter/nsExceptionHandler.h @@ -13,6 +13,9 @@ #define nsExceptionHandler_h__ #include "mozilla/Assertions.h" +#include "mozilla/EnumeratedArray.h" + +#include "CrashAnnotations.h" #include #include @@ -37,8 +40,6 @@ #endif class nsIFile; -template class nsDataHashtable; -class nsCStringHashKey; namespace CrashReporter { @@ -92,8 +93,11 @@ nsresult SetMinidumpPath(const nsAString& aPath); // AnnotateCrashReport, RemoveCrashReportAnnotation and // AppendAppNotesToCrashReport may be called from any thread in a chrome // process, but may only be called from the main thread in a content process. -nsresult AnnotateCrashReport(const nsACString& key, const nsACString& data); -nsresult RemoveCrashReportAnnotation(const nsACString& key); +nsresult AnnotateCrashReport(Annotation key, bool data); +nsresult AnnotateCrashReport(Annotation key, int data); +nsresult AnnotateCrashReport(Annotation key, unsigned int data); +nsresult AnnotateCrashReport(Annotation key, const nsACString& data); +nsresult RemoveCrashReportAnnotation(Annotation key); nsresult AppendAppNotesToCrashReport(const nsACString& data); void AnnotateOOMAllocationSize(size_t size); @@ -113,7 +117,8 @@ nsresult UnregisterAppMemory(void* ptr); void SetIncludeContextHeap(bool aValue); // Functions for working with minidumps and .extras -typedef nsDataHashtable AnnotationTable; +typedef mozilla::EnumeratedArray + AnnotationTable; void DeleteMinidumpFilesForID(const nsAString& id); bool GetMinidumpForID(const nsAString& id, nsIFile** minidump); diff --git a/toolkit/crashreporter/test/unit/test_crash_after_js_large_allocation_failure.js b/toolkit/crashreporter/test/unit/test_crash_after_js_large_allocation_failure.js index 72d9ac904c77..00e3fc76e19f 100644 --- a/toolkit/crashreporter/test/unit/test_crash_after_js_large_allocation_failure.js +++ b/toolkit/crashreporter/test/unit/test_crash_after_js_large_allocation_failure.js @@ -7,12 +7,12 @@ function run_test() { do_crash( function() { crashType = CrashTestUtils.CRASH_MOZ_CRASH; - crashReporter.annotateCrashReport("TestingOOMCrash", "Yes"); + crashReporter.annotateCrashReport("TestKey", "Yes"); Cu.getJSTestingFunctions().reportLargeAllocationFailure(); Cu.forceGC(); }, function(mdump, extra) { - Assert.equal(extra.TestingOOMCrash, "Yes"); + Assert.equal(extra.TestKey, "Yes"); Assert.equal(false, "JSOutOfMemory" in extra); Assert.equal(extra.JSLargeAllocationFailure, "Recovered"); }, diff --git a/toolkit/crashreporter/test/unit/test_crash_after_js_large_allocation_failure_reporting.js b/toolkit/crashreporter/test/unit/test_crash_after_js_large_allocation_failure_reporting.js index 3e68171cbc57..f3dbb6b45380 100644 --- a/toolkit/crashreporter/test/unit/test_crash_after_js_large_allocation_failure_reporting.js +++ b/toolkit/crashreporter/test/unit/test_crash_after_js_large_allocation_failure_reporting.js @@ -7,7 +7,7 @@ function run_test() { do_crash( function() { crashType = CrashTestUtils.CRASH_MOZ_CRASH; - crashReporter.annotateCrashReport("TestingOOMCrash", "Yes"); + crashReporter.annotateCrashReport("TestKey", "Yes"); function crashWhileReporting() { CrashTestUtils.crash(crashType); @@ -17,7 +17,7 @@ function run_test() { Cu.getJSTestingFunctions().reportLargeAllocationFailure(); }, function(mdump, extra) { - Assert.equal(extra.TestingOOMCrash, "Yes"); + Assert.equal(extra.TestKey, "Yes"); Assert.equal(extra.JSLargeAllocationFailure, "Reporting"); }, true); diff --git a/toolkit/crashreporter/test/unit/test_crash_after_js_oom_recovered.js b/toolkit/crashreporter/test/unit/test_crash_after_js_oom_recovered.js index b9b20333633d..eb71811dc182 100644 --- a/toolkit/crashreporter/test/unit/test_crash_after_js_oom_recovered.js +++ b/toolkit/crashreporter/test/unit/test_crash_after_js_oom_recovered.js @@ -7,12 +7,12 @@ function run_test() { do_crash( function() { crashType = CrashTestUtils.CRASH_MOZ_CRASH; - crashReporter.annotateCrashReport("TestingOOMCrash", "Yes"); + crashReporter.annotateCrashReport("TestKey", "Yes"); Cu.getJSTestingFunctions().reportOutOfMemory(); Cu.forceGC(); }, function(mdump, extra) { - Assert.equal(extra.TestingOOMCrash, "Yes"); + Assert.equal(extra.TestKey, "Yes"); Assert.equal(extra.JSOutOfMemory, "Recovered"); }, true); diff --git a/toolkit/crashreporter/test/unit/test_crash_after_js_oom_reported.js b/toolkit/crashreporter/test/unit/test_crash_after_js_oom_reported.js index 842ad6e9cfe4..4161cdc9742d 100644 --- a/toolkit/crashreporter/test/unit/test_crash_after_js_oom_reported.js +++ b/toolkit/crashreporter/test/unit/test_crash_after_js_oom_reported.js @@ -7,7 +7,7 @@ function run_test() { do_crash( function() { crashType = CrashTestUtils.CRASH_MOZ_CRASH; - crashReporter.annotateCrashReport("TestingOOMCrash", "Yes"); + crashReporter.annotateCrashReport("TestKey", "Yes"); // GC now to avoid having it happen randomly later, which would make the // test bogusly fail. See comment below. @@ -16,7 +16,7 @@ function run_test() { Cu.getJSTestingFunctions().reportOutOfMemory(); }, function(mdump, extra) { - Assert.equal(extra.TestingOOMCrash, "Yes"); + Assert.equal(extra.TestKey, "Yes"); // The JSOutOfMemory field is absent if the JS engine never reported OOM, // "Reported" if it did, and "Recovered" if it reported OOM but diff --git a/toolkit/crashreporter/test/unit/test_crash_after_js_oom_reported_2.js b/toolkit/crashreporter/test/unit/test_crash_after_js_oom_reported_2.js index 53d4946a8728..d55b6eeaadd0 100644 --- a/toolkit/crashreporter/test/unit/test_crash_after_js_oom_reported_2.js +++ b/toolkit/crashreporter/test/unit/test_crash_after_js_oom_reported_2.js @@ -7,13 +7,13 @@ function run_test() { do_crash( function() { crashType = CrashTestUtils.CRASH_MOZ_CRASH; - crashReporter.annotateCrashReport("TestingOOMCrash", "Yes"); + crashReporter.annotateCrashReport("TestKey", "Yes"); Cu.getJSTestingFunctions().reportOutOfMemory(); Cu.forceGC(); // recover from first OOM Cu.getJSTestingFunctions().reportOutOfMemory(); }, function(mdump, extra) { - Assert.equal(extra.TestingOOMCrash, "Yes"); + Assert.equal(extra.TestKey, "Yes"); // Technically, GC can happen at any time, but it would be really // peculiar for it to happen again heuristically right after a GC was diff --git a/toolkit/crashreporter/test/unit/test_crash_oom.js b/toolkit/crashreporter/test/unit/test_crash_oom.js index 105c8e0ed594..946d3fe59f8e 100644 --- a/toolkit/crashreporter/test/unit/test_crash_oom.js +++ b/toolkit/crashreporter/test/unit/test_crash_oom.js @@ -7,10 +7,10 @@ function run_test() { do_crash( function() { crashType = CrashTestUtils.CRASH_OOM; - crashReporter.annotateCrashReport("TestingOOMCrash", "Yes"); + crashReporter.annotateCrashReport("TestKey", "Yes"); }, function(mdump, extra) { - Assert.equal(extra.TestingOOMCrash, "Yes"); + Assert.equal(extra.TestKey, "Yes"); Assert.ok("OOMAllocationSize" in extra); Assert.ok(Number(extra.OOMAllocationSize) > 0); }, diff --git a/toolkit/crashreporter/test/unit/test_crashreporter.js b/toolkit/crashreporter/test/unit/test_crashreporter.js index f378e9493036..1011d131ccac 100644 --- a/toolkit/crashreporter/test/unit/test_crashreporter.js +++ b/toolkit/crashreporter/test/unit/test_crashreporter.js @@ -39,27 +39,28 @@ function run_test() { cr.minidumpPath = cwd; Assert.equal(cr.minidumpPath.path, cwd.path); + // Test annotateCrashReport() try { - cr.annotateCrashReport("equal=equal", ""); - do_throw("Calling annotateCrashReport() with an '=' in key should have thrown!"); + cr.annotateCrashReport(undefined, ""); + do_throw("Calling annotateCrashReport() with an undefined key should have thrown!"); } catch (ex) { Assert.equal(ex.result, Cr.NS_ERROR_INVALID_ARG); } try { - cr.annotateCrashReport("new\nline", ""); - do_throw("Calling annotateCrashReport() with a '\\n' in key should have thrown!"); + cr.annotateCrashReport("foobar", ""); + do_throw("Calling annotateCrashReport() with a bogus key should have thrown!"); } catch (ex) { Assert.equal(ex.result, Cr.NS_ERROR_INVALID_ARG); } try { - cr.annotateCrashReport("", "da\0ta"); + cr.annotateCrashReport("TestKey", "da\0ta"); do_throw("Calling annotateCrashReport() with a '\\0' in data should have thrown!"); } catch (ex) { Assert.equal(ex.result, Cr.NS_ERROR_INVALID_ARG); } - cr.annotateCrashReport("testKey", "testData1"); + cr.annotateCrashReport("TestKey", "testData1"); // Replace previous data. - cr.annotateCrashReport("testKey", "testData2"); + cr.annotateCrashReport("TestKey", "testData2"); try { cr.appendAppNotesToCrashReport("da\0ta"); @@ -71,6 +72,22 @@ function run_test() { // Add more data. cr.appendAppNotesToCrashReport("additional testData4"); + // Test removeCrashReportAnnotation() + try { + cr.removeCrashReportAnnotation(undefined); + do_throw("Calling removeCrashReportAnnotation() with an undefined key should have thrown!"); + } catch (ex) { + Assert.equal(ex.result, Cr.NS_ERROR_INVALID_ARG); + } + try { + cr.removeCrashReportAnnotation("foobar"); + do_throw("Calling removeCrashReportAnnotation() with a bogus key should have thrown!"); + } catch (ex) { + Assert.equal(ex.result, Cr.NS_ERROR_INVALID_ARG); + } + cr.removeCrashReportAnnotation("TestKey"); + + // Testing setting the minidumpPath field cr.minidumpPath = cwd; Assert.equal(cr.minidumpPath.path, cwd.path); } diff --git a/toolkit/crashreporter/test/unit/test_crashreporter_crash.js b/toolkit/crashreporter/test/unit/test_crashreporter_crash.js index df17b7472492..9d4dd65ddd2a 100644 --- a/toolkit/crashreporter/test/unit/test_crashreporter_crash.js +++ b/toolkit/crashreporter/test/unit/test_crashreporter_crash.js @@ -34,7 +34,8 @@ function run_test() { do_crash(function() { // Add various annotations crashReporter.annotateCrashReport("TestKey", "TestValue"); - crashReporter.annotateCrashReport("\u2665", "\u{1F4A9}"); + crashReporter.annotateCrashReport("TestUnicode", "\u{1F4A9}"); + crashReporter.annotateCrashReport("Add-ons", "test%40mozilla.org:0.1"); crashReporter.appendAppNotesToCrashReport("Junk"); crashReporter.appendAppNotesToCrashReport("MoreJunk"); @@ -45,8 +46,9 @@ function run_test() { }, function(mdump, extra) { Assert.equal(extra.TestKey, "TestValue"); - Assert.equal(extra["\u2665"], "\u{1F4A9}"); + Assert.equal(extra.TestUnicode, "\u{1F4A9}"); Assert.equal(extra.Notes, "JunkMoreJunk"); + Assert.equal(extra["Add-ons"], "test%40mozilla.org:0.1"); const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; Assert.ok("TelemetrySessionId" in extra, "The TelemetrySessionId field is present in the extra file"); diff --git a/toolkit/crashreporter/test/unit/test_oom_annotation_windows.js b/toolkit/crashreporter/test/unit/test_oom_annotation_windows.js index 11b8f47d8151..bde75ca97174 100644 --- a/toolkit/crashreporter/test/unit/test_oom_annotation_windows.js +++ b/toolkit/crashreporter/test/unit/test_oom_annotation_windows.js @@ -7,10 +7,10 @@ function run_test() { do_crash( function() { crashType = CrashTestUtils.CRASH_OOM; - crashReporter.annotateCrashReport("TestingOOMCrash", "Yes"); + crashReporter.annotateCrashReport("TestKey", "Yes"); }, function(mdump, extra) { - Assert.equal(extra.TestingOOMCrash, "Yes"); + Assert.equal(extra.TestKey, "Yes"); Assert.ok("OOMAllocationSize" in extra); Assert.ok(Number(extra.OOMAllocationSize) > 0); Assert.ok("SystemMemoryUsePercentage" in extra); diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 8c1249871088..536cc7bd9fa6 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -1235,7 +1235,40 @@ NS_IMETHODIMP nsXULAppInfo::AnnotateCrashReport(const nsACString& key, const nsACString& data) { - return CrashReporter::AnnotateCrashReport(key, data); + CrashReporter::Annotation annotation; + + if (!AnnotationFromString(annotation, PromiseFlatCString(key).get())) { + return NS_ERROR_INVALID_ARG; + } + + return CrashReporter::AnnotateCrashReport(annotation, data); +} + +NS_IMETHODIMP +nsXULAppInfo::RemoveCrashReportAnnotation(const nsACString& key) +{ + CrashReporter::Annotation annotation; + + if (!AnnotationFromString(annotation, PromiseFlatCString(key).get())) { + return NS_ERROR_INVALID_ARG; + } + + return CrashReporter::RemoveCrashReportAnnotation(annotation); +} + +NS_IMETHODIMP +nsXULAppInfo::IsAnnotationWhitelistedForPing(const nsACString& aValue, + bool* aIsWhitelisted) +{ + CrashReporter::Annotation annotation; + + if (!AnnotationFromString(annotation, PromiseFlatCString(aValue).get())) { + return NS_ERROR_INVALID_ARG; + } + + *aIsWhitelisted = CrashReporter::IsAnnotationWhitelistedForPing(annotation); + + return NS_OK; } NS_IMETHODIMP @@ -3390,39 +3423,39 @@ XREMain::XRE_mainInit(bool* aExitFlag) CrashReporter::SetServerURL(nsDependentCString(mAppData->crashReporterURL)); // We overwrite this once we finish starting up. - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("StartupCrash"), - NS_LITERAL_CSTRING("1")); + CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::StartupCrash, + true); // pass some basic info from the app data if (mAppData->vendor) - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Vendor"), + CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::Vendor, nsDependentCString(mAppData->vendor)); if (mAppData->name) - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProductName"), + CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::ProductName, nsDependentCString(mAppData->name)); if (mAppData->ID) - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ProductID"), + CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::ProductID, nsDependentCString(mAppData->ID)); if (mAppData->version) - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("Version"), + CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::Version, nsDependentCString(mAppData->version)); if (mAppData->buildID) - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("BuildID"), + CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::BuildID, nsDependentCString(mAppData->buildID)); nsDependentCString releaseChannel(NS_STRINGIFY(MOZ_UPDATE_CHANNEL)); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ReleaseChannel"), - releaseChannel); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::ReleaseChannel, releaseChannel); #ifdef MOZ_LINKER - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("CrashAddressLikelyWrong"), - IsSignalHandlingBroken() ? NS_LITERAL_CSTRING("1") - : NS_LITERAL_CSTRING("0")); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::CrashAddressLikelyWrong, + IsSignalHandlingBroken()); #endif #ifdef XP_WIN nsAutoString appInitDLLs; if (widget::WinUtils::GetAppInitDLLs(appInitDLLs)) { - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AppInitDLLs"), + CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AppInitDLLs, NS_ConvertUTF16toUTF8(appInitDLLs)); } #endif @@ -3583,16 +3616,15 @@ XREMain::XRE_mainInit(bool* aExitFlag) } if (cpuUpdateRevision > 0) { - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("CPUMicrocodeVersion"), - nsPrintfCString("0x%x", - cpuUpdateRevision)); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::CPUMicrocodeVersion, + nsPrintfCString("0x%x", cpuUpdateRevision)); } } #endif - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("SafeMode"), - gSafeMode ? NS_LITERAL_CSTRING("1") : - NS_LITERAL_CSTRING("0")); + CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::SafeMode, + gSafeMode); // Handle --no-remote and --new-instance command line arguments. Setup // the environment to better accommodate other components and various @@ -3715,8 +3747,9 @@ static void AnnotateSystemManufacturer() hr = classObject->Get(L"Manufacturer", 0, &value, 0, 0); if (SUCCEEDED(hr) && V_VT(&value) == VT_BSTR) { - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("BIOS_Manufacturer"), - NS_ConvertUTF16toUTF8(V_BSTR(&value))); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::BIOS_Manufacturer, + NS_ConvertUTF16toUTF8(V_BSTR(&value))); } VariantClear(&value); @@ -4360,7 +4393,7 @@ void AddSandboxAnnotations() levelString.AppendInt(level); CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("ContentSandboxLevel"), levelString); + CrashReporter::Annotation::ContentSandboxLevel, levelString); // Include whether or not this instance is capable of content sandboxing bool sandboxCapable = false; @@ -4376,8 +4409,7 @@ void AddSandboxAnnotations() #endif CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("ContentSandboxCapable"), - sandboxCapable ? NS_LITERAL_CSTRING("1") : NS_LITERAL_CSTRING("0")); + CrashReporter::Annotation::ContentSandboxCapable, sandboxCapable); } #endif /* MOZ_CONTENT_SANDBOX */ @@ -4431,16 +4463,18 @@ XREMain::XRE_mainRun() nsAutoCString sval; rv = defaultPrefBranch->GetCharPref("app.update.channel", sval); if (NS_SUCCEEDED(rv)) { - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("ReleaseChannel"), - sval); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::ReleaseChannel, sval); } } } // Needs to be set after xpcom initialization. - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("FramePoisonBase"), - nsPrintfCString("%.16" PRIu64, uint64_t(gMozillaPoisonBase))); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("FramePoisonSize"), - nsPrintfCString("%" PRIu32, uint32_t(gMozillaPoisonSize))); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::FramePoisonBase, + nsPrintfCString("%.16" PRIu64, uint64_t(gMozillaPoisonBase))); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::FramePoisonSize, + uint32_t(gMozillaPoisonSize)); bool includeContextHeap = Preferences::GetBool("toolkit.crashreporter.include_context_heap", false); @@ -4599,7 +4633,8 @@ XREMain::XRE_mainRun() nsCString userAgentLocale; LocaleService::GetInstance()->GetAppLocaleAsLangTag(userAgentLocale); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("useragent_locale"), userAgentLocale); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::useragent_locale, userAgentLocale); appStartup->GetShuttingDown(&mShuttingDown); @@ -4695,8 +4730,8 @@ XREMain::XRE_mainRun() (void)appStartup->DoneStartingUp(); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("StartupCrash"), - NS_LITERAL_CSTRING("0")); + CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::StartupCrash, + false); appStartup->GetShuttingDown(&mShuttingDown); } @@ -4753,7 +4788,7 @@ XREMain::XRE_mainRun() flagsString.AppendInt(sandboxInfo.AsInteger()); CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("ContentSandboxCapabilities"), flagsString); + CrashReporter::Annotation::ContentSandboxCapabilities, flagsString); #endif /* MOZ_SANDBOX && XP_LINUX */ #if defined(MOZ_CONTENT_SANDBOX) diff --git a/toolkit/xre/nsEmbedFunctions.cpp b/toolkit/xre/nsEmbedFunctions.cpp index 3873f0171a2d..f37af2790f13 100644 --- a/toolkit/xre/nsEmbedFunctions.cpp +++ b/toolkit/xre/nsEmbedFunctions.cpp @@ -325,10 +325,8 @@ AddContentSandboxLevelAnnotation() { if (XRE_GetProcessType() == GeckoProcessType_Content) { int level = GetEffectiveContentSandboxLevel(); - nsAutoCString levelString; - levelString.AppendInt(level); CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("ContentSandboxLevel"), levelString); + CrashReporter::Annotation::ContentSandboxLevel, level); } } #endif /* MOZ_CONTENT_SANDBOX */ diff --git a/widget/android/GfxInfo.cpp b/widget/android/GfxInfo.cpp index 6670693b4308..f1ed6fc27d3d 100644 --- a/widget/android/GfxInfo.cpp +++ b/widget/android/GfxInfo.cpp @@ -348,19 +348,12 @@ GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active) void GfxInfo::AddCrashReportAnnotations() { - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterVendorID"), + CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterVendorID, mGLStrings->Vendor()); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterDeviceID"), + CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterDeviceID, mGLStrings->Renderer()); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterDriverVersion"), - mGLStrings->Version()); - - /* Add an App Note for now so that we get the data immediately. These - * can go away after we store the above in the socorro db */ - nsAutoCString note; - note.AppendPrintf("AdapterDescription: '%s'\n", mAdapterDescription.get()); - - CrashReporter::AppendAppNotesToCrashReport(note); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::AdapterDriverVersion, mGLStrings->Version()); } const nsTArray& diff --git a/widget/android/jni/Utils.cpp b/widget/android/jni/Utils.cpp index f8b7f4f4ca3e..0ac18b6cdbf6 100644 --- a/widget/android/jni/Utils.cpp +++ b/widget/android/jni/Utils.cpp @@ -204,8 +204,8 @@ bool ReportException(JNIEnv* aEnv, jthrowable aExc, jstring aStack) bool result = true; result &= NS_SUCCEEDED(CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("JavaStackTrace"), - String::Ref::From(aStack)->ToCString())); + CrashReporter::Annotation::JavaStackTrace, + String::Ref::From(aStack)->ToCString())); auto appNotes = java::GeckoAppShell::GetAppNotes(); if (NS_WARN_IF(aEnv->ExceptionCheck())) { diff --git a/widget/android/nsAppShell.cpp b/widget/android/nsAppShell.cpp index ef0bd94a68e5..bfbfc19fc173 100644 --- a/widget/android/nsAppShell.cpp +++ b/widget/android/nsAppShell.cpp @@ -9,13 +9,11 @@ #include "base/message_loop.h" #include "base/task.h" #include "mozilla/Hal.h" -#include "nsExceptionHandler.h" #include "nsIScreen.h" #include "nsIScreenManager.h" #include "nsWindow.h" #include "nsThreadUtils.h" #include "nsICommandLineRunner.h" -#include "nsICrashReporter.h" #include "nsIObserverService.h" #include "nsIAppStartup.h" #include "nsIGeolocationProvider.h" diff --git a/widget/cocoa/GfxInfo.mm b/widget/cocoa/GfxInfo.mm index 1b0d87e8796b..65cd0b2657ba 100644 --- a/widget/cocoa/GfxInfo.mm +++ b/widget/cocoa/GfxInfo.mm @@ -283,21 +283,12 @@ GfxInfo::AddCrashReportAnnotations() GetAdapterDriverVersion(driverVersion); CopyUTF16toUTF8(driverVersion, narrowDriverVersion); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterVendorID"), + CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterVendorID, narrowVendorID); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterDeviceID"), + CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterDeviceID, narrowDeviceID); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterDriverVersion"), - narrowDriverVersion); - /* Add an App Note for now so that we get the data immediately. These - * can go away after we store the above in the socorro db */ - nsAutoCString note; - /* AppendPrintf only supports 32 character strings, mrghh. */ - note.AppendLiteral("AdapterVendorID: "); - note.Append(narrowVendorID); - note.AppendLiteral(", AdapterDeviceID: "); - note.Append(narrowDeviceID); - CrashReporter::AppendAppNotesToCrashReport(note); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::AdapterDriverVersion, narrowDriverVersion); } // We don't support checking driver versions on Mac. diff --git a/widget/windows/GfxInfo.cpp b/widget/windows/GfxInfo.cpp index a616cefe610c..56131c931dd1 100644 --- a/widget/windows/GfxInfo.cpp +++ b/widget/windows/GfxInfo.cpp @@ -893,35 +893,24 @@ GfxInfo::AddCrashReportAnnotations() GetAdapterSubsysID(subsysID); CopyUTF16toUTF8(subsysID, narrowSubsysID); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterVendorID"), + CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterVendorID, narrowVendorID); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterDeviceID"), + CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterDeviceID, narrowDeviceID); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterDriverVersion"), - narrowDriverVersion); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AdapterSubsysID"), + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::AdapterDriverVersion, narrowDriverVersion); + CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::AdapterSubsysID, narrowSubsysID); - /* Add an App Note for now so that we get the data immediately. These - * can go away after we store the above in the socorro db */ + /* Add an App Note, this contains extra information. */ nsAutoCString note; - /* AppendPrintf only supports 32 character strings, mrghh. */ - note.AppendLiteral("AdapterVendorID: "); - note.Append(narrowVendorID); - note.AppendLiteral(", AdapterDeviceID: "); - note.Append(narrowDeviceID); - note.AppendLiteral(", AdapterSubsysID: "); - note.Append(narrowSubsysID); - note.AppendLiteral(", AdapterDriverVersion: "); - note.Append(NS_LossyConvertUTF16toASCII(driverVersion)); + // TODO: We should probably convert this into a proper annotation if (vendorID == GfxDriverInfo::GetDeviceVendor(VendorAll)) { /* if we didn't find a valid vendorID lets append the mDeviceID string to try to find out why */ - note.AppendLiteral(", "); LossyAppendUTF16toASCII(mDeviceID[mActiveGPUIndex], note); note.AppendLiteral(", "); LossyAppendUTF16toASCII(mDeviceKeyDebug, note); - LossyAppendUTF16toASCII(mDeviceKeyDebug, note); } note.AppendLiteral("\n"); diff --git a/xpcom/base/AvailableMemoryTracker.cpp b/xpcom/base/AvailableMemoryTracker.cpp index a0ab7af09b7c..b7cbd9b485b1 100644 --- a/xpcom/base/AvailableMemoryTracker.cpp +++ b/xpcom/base/AvailableMemoryTracker.cpp @@ -10,7 +10,6 @@ #include "nsExceptionHandler.h" #include "nsIMemoryReporter.h" #include "nsMemoryPressure.h" -#include "nsPrintfCString.h" #endif #include "nsIObserver.h" @@ -151,8 +150,8 @@ nsAvailableMemoryWatcher::IsCommitSpaceLow(const MEMORYSTATUSEX& aStat) (aStat.ullAvailPageFile < kLowCommitSpaceThreshold)) { sNumLowCommitSpaceEvents++; CrashReporter::AnnotateCrashReport( - NS_LITERAL_CSTRING("LowCommitSpaceEvents"), - nsPrintfCString("%" PRIu32, uint32_t(sNumLowCommitSpaceEvents))); + CrashReporter::Annotation::LowCommitSpaceEvents, + uint32_t(sNumLowCommitSpaceEvents)); return true; } diff --git a/xpcom/base/CycleCollectedJSRuntime.cpp b/xpcom/base/CycleCollectedJSRuntime.cpp index 784e7a011c1e..821b59c3bac9 100644 --- a/xpcom/base/CycleCollectedJSRuntime.cpp +++ b/xpcom/base/CycleCollectedJSRuntime.cpp @@ -1473,19 +1473,35 @@ CycleCollectedJSRuntime::FinalizeDeferredThings(CycleCollectedJSContext::Deferre } } +const char* +CycleCollectedJSRuntime::OOMStateToString(const OOMState aOomState) const +{ + switch (aOomState) { + case OOMState::OK: + return "OK"; + case OOMState::Reporting: + return "Reporting"; + case OOMState::Reported: + return "Reported"; + case OOMState::Recovered: + return "Recovered"; + default: + MOZ_ASSERT_UNREACHABLE("OOMState holds an invalid value"); + return "Unknown"; + } +} + void CycleCollectedJSRuntime::AnnotateAndSetOutOfMemory(OOMState* aStatePtr, OOMState aNewState) { *aStatePtr = aNewState; - CrashReporter::AnnotateCrashReport(aStatePtr == &mOutOfMemoryState - ? NS_LITERAL_CSTRING("JSOutOfMemory") - : NS_LITERAL_CSTRING("JSLargeAllocationFailure"), - aNewState == OOMState::Reporting - ? NS_LITERAL_CSTRING("Reporting") - : aNewState == OOMState::Reported - ? NS_LITERAL_CSTRING("Reported") - : NS_LITERAL_CSTRING("Recovered")); + CrashReporter::Annotation annotation = (aStatePtr == &mOutOfMemoryState) + ? CrashReporter::Annotation::JSOutOfMemory + : CrashReporter::Annotation::JSLargeAllocationFailure; + + CrashReporter::AnnotateCrashReport( + annotation, nsDependentCString(OOMStateToString(aNewState))); } void diff --git a/xpcom/base/CycleCollectedJSRuntime.h b/xpcom/base/CycleCollectedJSRuntime.h index a057cb996469..70b1c106fce0 100644 --- a/xpcom/base/CycleCollectedJSRuntime.h +++ b/xpcom/base/CycleCollectedJSRuntime.h @@ -237,6 +237,8 @@ public: Recovered }; + const char* OOMStateToString(const OOMState aOomState) const; + void SetLargeAllocationFailure(OOMState aNewState); void AnnotateAndSetOutOfMemory(OOMState* aStatePtr, OOMState aNewState); diff --git a/xpcom/base/nsCycleCollector.cpp b/xpcom/base/nsCycleCollector.cpp index 040331c7aede..2a53ce713a56 100644 --- a/xpcom/base/nsCycleCollector.cpp +++ b/xpcom/base/nsCycleCollector.cpp @@ -675,7 +675,8 @@ PtrInfo::AnnotatedReleaseAssert(bool aCondition, const char* aMessage) piName = mParticipant->ClassName(); } nsPrintfCString msg("%s, for class %s", aMessage, piName); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("CycleCollector"), msg); + CrashReporter::AnnotateCrashReport(CrashReporter::Annotation::CycleCollector, + msg); MOZ_CRASH(); } diff --git a/xpcom/base/nsDebugImpl.cpp b/xpcom/base/nsDebugImpl.cpp index aceebecf27f5..f3d9af29607e 100644 --- a/xpcom/base/nsDebugImpl.cpp +++ b/xpcom/base/nsDebugImpl.cpp @@ -409,8 +409,9 @@ NS_DebugBreak(uint32_t aSeverity, const char* aStr, const char* aExpr, note += nonPIDBuf.buffer; note += ")"; CrashReporter::AppendAppNotesToCrashReport(note); - CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("AbortMessage"), - nsDependentCString(nonPIDBuf.buffer)); + CrashReporter::AnnotateCrashReport( + CrashReporter::Annotation::AbortMessage, + nsDependentCString(nonPIDBuf.buffer)); } #if defined(DEBUG) && defined(_WIN32) diff --git a/xpcom/system/nsICrashReporter.idl b/xpcom/system/nsICrashReporter.idl index 63350a821b69..4834fc327657 100644 --- a/xpcom/system/nsICrashReporter.idl +++ b/xpcom/system/nsICrashReporter.idl @@ -76,17 +76,40 @@ interface nsICrashReporter : nsISupports * Add some extra data to be submitted with a crash report. * * @param key - * Name of the data to be added. + * Name of a known crash annotation constant. * @param data * Data to be added. * * @throw NS_ERROR_NOT_INITIALIZED if crash reporting not initialized - * @throw NS_ERROR_INVALID_ARG if key or data contain invalid characters. - * Invalid characters for key are '=' and - * '\n'. Invalid character for data is '\0'. + * @throw NS_ERROR_INVALID_ARG if key contains an invalid value or data + * contains invalid characters. Invalid + * character for data is '\0'. */ void annotateCrashReport(in AUTF8String key, in AUTF8String data); + /** + * Remove a crash report annotation. + * + * @param key + * Name of a known crash annotation constant. + * + * @throw NS_ERROR_NOT_INITIALIZED if crash reporting not initialized + * @throw NS_ERROR_INVALID_ARG if key contains an invalid value. + */ + void removeCrashReportAnnotation(in AUTF8String key); + + /** + * Checks if an annotation is whitelisted for inclusion in the crash ping. + * + * @param key + * Name of a known crash annotation constant. + * + * @return True if the specified value is a valid annotation and can be + included in the crash ping, false otherwise. + * @throw NS_ERROR_INVALID_ARG if key contains an invalid value. + */ + boolean isAnnotationWhitelistedForPing(in ACString value); + /** * Append some data to the "Notes" field, to be submitted with a crash report. * Unlike annotateCrashReport, this method will append to existing data. @@ -121,7 +144,7 @@ interface nsICrashReporter : nsISupports * @param aExceptionInfo EXCEPTION_INFO* provided by Window's SEH */ [noscript] void writeMinidumpForException(in voidPtr aExceptionInfo); - + /** * Append note containing an Obj-C exception's info. *