CrashReporterHost.cpp (7319B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "CrashReporterHost.h" 8 #include "CrashReporter/CrashReporterInitArgs.h" 9 #include "mozilla/dom/Promise.h" 10 #include "mozilla/Sprintf.h" 11 #include "mozilla/SyncRunnable.h" 12 #include "mozilla/glean/IpcMetrics.h" 13 #include "nsServiceManagerUtils.h" 14 #include "nsICrashService.h" 15 #include "nsXULAppAPI.h" 16 #include "nsIFile.h" 17 18 #if defined(XP_LINUX) && defined(MOZ_CRASHREPORTER) && \ 19 defined(MOZ_OXIDIZED_BREAKPAD) 20 # include "mozilla/toolkit/crashreporter/rust_minidump_writer_linux_ffi_generated.h" 21 #endif // defined(XP_LINUX) && defined(MOZ_CRASHREPORTER) && 22 // defined(MOZ_OXIDIZED_BREAKPAD) 23 24 namespace mozilla::ipc { 25 26 CrashReporterHost::CrashReporterHost( 27 GeckoProcessType aProcessType, base::ProcessId aPid, 28 const CrashReporter::CrashReporterInitArgs& aInitArgs) 29 : mProcessType(aProcessType), 30 mPid(aPid), 31 mThreadId(aInitArgs.threadId()), 32 mStartTime(::time(nullptr)), 33 mFinalized(false) { 34 #if defined(XP_LINUX) && defined(MOZ_CRASHREPORTER) && \ 35 defined(MOZ_OXIDIZED_BREAKPAD) 36 const CrashReporter::AuxvInfo& ipdlAuxvInfo = aInitArgs.auxvInfo(); 37 DirectAuxvDumpInfo auxvInfo = {}; 38 auxvInfo.program_header_count = ipdlAuxvInfo.programHeaderCount(); 39 auxvInfo.program_header_address = ipdlAuxvInfo.programHeaderAddress(); 40 auxvInfo.linux_gate_address = ipdlAuxvInfo.linuxGateAddress(); 41 auxvInfo.entry_address = ipdlAuxvInfo.entryAddress(); 42 CrashReporter::RegisterChildAuxvInfo(mPid, auxvInfo); 43 #endif // defined(XP_LINUX) && defined(MOZ_CRASHREPORTER) && 44 // defined(MOZ_OXIDIZED_BREAKPAD) 45 } 46 47 CrashReporterHost::~CrashReporterHost() { 48 #if defined(XP_LINUX) && defined(MOZ_CRASHREPORTER) && \ 49 defined(MOZ_OXIDIZED_BREAKPAD) 50 CrashReporter::UnregisterChildAuxvInfo(mPid); 51 #endif // defined(XP_LINUX) && defined(MOZ_CRASHREPORTER) && 52 // defined(MOZ_OXIDIZED_BREAKPAD) 53 } 54 55 bool CrashReporterHost::GenerateCrashReport() { 56 if (!TakeCrashedChildMinidump()) { 57 return false; 58 } 59 60 FinalizeCrashReport(); 61 RecordCrash(mProcessType, nsICrashService::CRASH_TYPE_CRASH, mDumpID); 62 return true; 63 } 64 65 RefPtr<nsIFile> CrashReporterHost::TakeCrashedChildMinidump() { 66 CrashReporter::AnnotationTable annotations; 67 MOZ_ASSERT(!HasMinidump()); 68 69 RefPtr<nsIFile> crashDump; 70 if (!CrashReporter::TakeMinidumpForChild(mPid, getter_AddRefs(crashDump), 71 annotations)) { 72 return nullptr; 73 } 74 if (!AdoptMinidump(crashDump, annotations)) { 75 return nullptr; 76 } 77 return crashDump; 78 } 79 80 bool CrashReporterHost::AdoptMinidump(nsIFile* aFile, 81 const AnnotationTable& aAnnotations) { 82 if (!CrashReporter::GetIDFromMinidump(aFile, mDumpID)) { 83 return false; 84 } 85 86 MergeCrashAnnotations(mExtraAnnotations, aAnnotations); 87 return true; 88 } 89 90 void CrashReporterHost::FinalizeCrashReport() { 91 MOZ_ASSERT(!mFinalized); 92 MOZ_ASSERT(HasMinidump()); 93 94 mExtraAnnotations[CrashReporter::Annotation::ProcessType] = ProcessType(); 95 96 char startTime[32]; 97 SprintfLiteral(startTime, "%lld", static_cast<long long>(mStartTime)); 98 mExtraAnnotations[CrashReporter::Annotation::StartupTime] = 99 nsDependentCString(startTime); 100 101 CrashReporter::WriteExtraFile(mDumpID, mExtraAnnotations); 102 mFinalized = true; 103 } 104 105 void CrashReporterHost::DeleteCrashReport() { 106 if (mFinalized && HasMinidump()) { 107 CrashReporter::DeleteMinidumpFilesForID(mDumpID, Some(u"browser"_ns)); 108 } 109 } 110 111 const char* CrashReporterHost::ProcessType() const { 112 return XRE_ChildProcessTypeToAnnotation(mProcessType); 113 } 114 115 /* static */ 116 void CrashReporterHost::RecordCrash(GeckoProcessType aProcessType, 117 int32_t aCrashType, 118 const nsString& aChildDumpID) { 119 if (!NS_IsMainThread()) { 120 RefPtr<Runnable> runnable = NS_NewRunnableFunction( 121 "ipc::CrashReporterHost::RecordCrash", [&]() -> void { 122 CrashReporterHost::RecordCrash(aProcessType, aCrashType, 123 aChildDumpID); 124 }); 125 RefPtr<nsIThread> mainThread = do_GetMainThread(); 126 SyncRunnable::DispatchToThread(mainThread, runnable); 127 return; 128 } 129 130 RecordCrashWithTelemetry(aProcessType, aCrashType); 131 NotifyCrashService(aProcessType, aCrashType, aChildDumpID); 132 } 133 134 /* static */ 135 void CrashReporterHost::RecordCrashWithTelemetry(GeckoProcessType aProcessType, 136 int32_t aCrashType) { 137 nsCString key; 138 139 switch (aProcessType) { 140 #define GECKO_PROCESS_TYPE(enum_value, enum_name, string_name, proc_typename, \ 141 process_bin_type, procinfo_typename, \ 142 webidl_typename, allcaps_name) \ 143 case GeckoProcessType_##enum_name: \ 144 key.AssignLiteral(string_name); \ 145 break; 146 #include "mozilla/GeckoProcessTypes.h" 147 #undef GECKO_PROCESS_TYPE 148 // We can't really hit this, thanks to the above switch, but having it 149 // here will placate the compiler. 150 default: 151 MOZ_ASSERT_UNREACHABLE("unknown process type"); 152 } 153 154 glean::subprocess::crashes_with_dump.Get(key).Add(1); 155 } 156 157 /* static */ 158 void CrashReporterHost::NotifyCrashService(GeckoProcessType aProcessType, 159 int32_t aCrashType, 160 const nsString& aChildDumpID) { 161 MOZ_ASSERT(!aChildDumpID.IsEmpty()); 162 163 nsCOMPtr<nsICrashService> crashService = 164 do_GetService("@mozilla.org/crashservice;1"); 165 if (!crashService) { 166 return; 167 } 168 169 int32_t processType; 170 171 switch (aProcessType) { 172 case GeckoProcessType_IPDLUnitTest: 173 case GeckoProcessType_Default: 174 NS_ERROR("unknown process type"); 175 return; 176 default: 177 processType = (int)aProcessType; 178 break; 179 } 180 181 RefPtr<dom::Promise> promise; 182 crashService->AddCrash(processType, aCrashType, aChildDumpID, 183 getter_AddRefs(promise)); 184 } 185 186 void CrashReporterHost::AddAnnotationBool(CrashReporter::Annotation aKey, 187 bool aValue) { 188 MOZ_ASSERT(TypeOfAnnotation(aKey) == CrashReporter::AnnotationType::Boolean, 189 "Wrong annotation type"); 190 mExtraAnnotations[aKey] = aValue ? "1"_ns : "0"_ns; 191 } 192 193 void CrashReporterHost::AddAnnotationU32(CrashReporter::Annotation aKey, 194 uint32_t aValue) { 195 MOZ_ASSERT(TypeOfAnnotation(aKey) == CrashReporter::AnnotationType::U32, 196 "Wrong annotation type"); 197 nsAutoCString valueString; 198 valueString.AppendInt(aValue); 199 mExtraAnnotations[aKey] = valueString; 200 } 201 202 void CrashReporterHost::AddAnnotationNSCString(CrashReporter::Annotation aKey, 203 const nsACString& aValue) { 204 MOZ_ASSERT(TypeOfAnnotation(aKey) == CrashReporter::AnnotationType::String, 205 "Wrong annotation type"); 206 mExtraAnnotations[aKey] = aValue; 207 } 208 209 } // namespace mozilla::ipc