Line data Source code
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 "nsExceptionHandler.h"
8 :
9 : #include "nsAppDirectoryServiceDefs.h"
10 : #include "nsDirectoryServiceDefs.h"
11 : #include "nsDirectoryService.h"
12 : #include "nsDataHashtable.h"
13 : #include "mozilla/ArrayUtils.h"
14 : #include "mozilla/Services.h"
15 : #include "nsIObserverService.h"
16 : #include "mozilla/Unused.h"
17 : #include "mozilla/Printf.h"
18 : #include "mozilla/Sprintf.h"
19 : #include "mozilla/SyncRunnable.h"
20 : #include "mozilla/TimeStamp.h"
21 : #include "mozilla/ipc/CrashReporterClient.h"
22 :
23 : #include "nsThreadUtils.h"
24 : #include "nsXULAppAPI.h"
25 : #include "jsfriendapi.h"
26 : #include "ThreadAnnotation.h"
27 :
28 : #ifdef XP_WIN
29 : #include "mozilla/TlsAllocationTracker.h"
30 : #endif
31 :
32 : #if defined(XP_WIN32)
33 : #ifdef WIN32_LEAN_AND_MEAN
34 : #undef WIN32_LEAN_AND_MEAN
35 : #endif
36 :
37 : #include "nsXULAppAPI.h"
38 : #include "nsIXULAppInfo.h"
39 : #include "nsIWindowsRegKey.h"
40 : #include "breakpad-client/windows/crash_generation/client_info.h"
41 : #include "breakpad-client/windows/crash_generation/crash_generation_server.h"
42 : #include "breakpad-client/windows/handler/exception_handler.h"
43 : #include <dbghelp.h>
44 : #include <string.h>
45 : #include "nsDirectoryServiceUtils.h"
46 :
47 : #include "nsWindowsDllInterceptor.h"
48 : #elif defined(XP_MACOSX)
49 : #include "breakpad-client/mac/crash_generation/client_info.h"
50 : #include "breakpad-client/mac/crash_generation/crash_generation_server.h"
51 : #include "breakpad-client/mac/handler/exception_handler.h"
52 : #include <string>
53 : #include <Carbon/Carbon.h>
54 : #include <CoreFoundation/CoreFoundation.h>
55 : #include <crt_externs.h>
56 : #include <fcntl.h>
57 : #include <mach/mach.h>
58 : #include <sys/types.h>
59 : #include <spawn.h>
60 : #include <unistd.h>
61 : #include "mac_utils.h"
62 : #elif defined(XP_LINUX)
63 : #include "nsIINIParser.h"
64 : #include "common/linux/linux_libc_support.h"
65 : #include "third_party/lss/linux_syscall_support.h"
66 : #include "breakpad-client/linux/crash_generation/client_info.h"
67 : #include "breakpad-client/linux/crash_generation/crash_generation_server.h"
68 : #include "breakpad-client/linux/handler/exception_handler.h"
69 : #include "common/linux/eintr_wrapper.h"
70 : #include <fcntl.h>
71 : #include <sys/types.h>
72 : #include <sys/wait.h>
73 : #include <unistd.h>
74 : #else
75 : #error "Not yet implemented for this platform"
76 : #endif // defined(XP_WIN32)
77 :
78 : #ifdef MOZ_CRASHREPORTER_INJECTOR
79 : #include "InjectCrashReporter.h"
80 : using mozilla::InjectCrashRunnable;
81 : #endif
82 :
83 : #include <stdlib.h>
84 : #include <time.h>
85 : #include <prenv.h>
86 : #include <prio.h>
87 : #include "mozilla/Mutex.h"
88 : #include "nsDebug.h"
89 : #include "nsCRT.h"
90 : #include "nsIFile.h"
91 : #include <map>
92 : #include <vector>
93 :
94 : #include "mozilla/double-conversion.h"
95 : #include "mozilla/IOInterposer.h"
96 : #include "mozilla/mozalloc_oom.h"
97 : #include "mozilla/WindowsDllBlocklist.h"
98 :
99 : #if defined(XP_MACOSX)
100 : CFStringRef reporterClientAppID = CFSTR("org.mozilla.crashreporter");
101 : #endif
102 : #if defined(MOZ_WIDGET_ANDROID)
103 : #include "common/linux/file_id.h"
104 : #endif
105 :
106 : using google_breakpad::CrashGenerationServer;
107 : using google_breakpad::ClientInfo;
108 : #ifdef XP_LINUX
109 : using google_breakpad::MinidumpDescriptor;
110 : #endif
111 : #if defined(MOZ_WIDGET_ANDROID)
112 : using google_breakpad::auto_wasteful_vector;
113 : using google_breakpad::FileID;
114 : using google_breakpad::PageAllocator;
115 : #endif
116 : using namespace mozilla;
117 : using mozilla::ipc::CrashReporterClient;
118 :
119 : // From toolkit/library/rust/shared/lib.rs
120 : extern "C" {
121 : void install_rust_panic_hook();
122 : bool get_rust_panic_reason(char** reason, size_t* length);
123 : }
124 :
125 :
126 : namespace CrashReporter {
127 :
128 : #ifdef XP_WIN32
129 : typedef wchar_t XP_CHAR;
130 : typedef std::wstring xpstring;
131 : #define XP_TEXT(x) L##x
132 : #define CONVERT_XP_CHAR_TO_UTF16(x) x
133 : #define XP_STRLEN(x) wcslen(x)
134 : #define my_strlen strlen
135 : #define CRASH_REPORTER_FILENAME "crashreporter.exe"
136 : #define MINIDUMP_ANALYZER_FILENAME "minidump-analyzer.exe"
137 : #define PATH_SEPARATOR "\\"
138 : #define XP_PATH_SEPARATOR L"\\"
139 : #define XP_PATH_SEPARATOR_CHAR L'\\'
140 : #define XP_PATH_MAX (MAX_PATH + 1)
141 : // "<reporter path>" "<minidump path>"
142 : #define CMDLINE_SIZE ((XP_PATH_MAX * 2) + 6)
143 : #ifdef _USE_32BIT_TIME_T
144 : #define XP_TTOA(time, buffer, base) ltoa(time, buffer, base)
145 : #else
146 : #define XP_TTOA(time, buffer, base) _i64toa(time, buffer, base)
147 : #endif
148 : #define XP_STOA(size, buffer, base) _ui64toa(size, buffer, base)
149 : #else
150 : typedef char XP_CHAR;
151 : typedef std::string xpstring;
152 : #define XP_TEXT(x) x
153 : #define CONVERT_XP_CHAR_TO_UTF16(x) NS_ConvertUTF8toUTF16(x)
154 : #define CRASH_REPORTER_FILENAME "crashreporter"
155 : #define MINIDUMP_ANALYZER_FILENAME "minidump-analyzer"
156 : #define PATH_SEPARATOR "/"
157 : #define XP_PATH_SEPARATOR "/"
158 : #define XP_PATH_SEPARATOR_CHAR '/'
159 : #define XP_PATH_MAX PATH_MAX
160 : #ifdef XP_LINUX
161 : #define XP_STRLEN(x) my_strlen(x)
162 : #define XP_TTOA(time, buffer, base) my_inttostring(time, buffer, sizeof(buffer))
163 : #define XP_STOA(size, buffer, base) my_inttostring(size, buffer, sizeof(buffer))
164 : #else
165 : #define XP_STRLEN(x) strlen(x)
166 : #define XP_TTOA(time, buffer, base) sprintf(buffer, "%ld", time)
167 : #define XP_STOA(size, buffer, base) sprintf(buffer, "%zu", (size_t) size)
168 : #define my_strlen strlen
169 : #define sys_close close
170 : #define sys_fork fork
171 : #define sys_open open
172 : #define sys_read read
173 : #define sys_write write
174 : #endif
175 : #endif // XP_WIN32
176 :
177 : #if defined(__GNUC__)
178 : #define MAYBE_UNUSED __attribute__((unused))
179 : #else
180 : #define MAYBE_UNUSED
181 : #endif // defined(__GNUC__)
182 :
183 : #ifndef XP_LINUX
184 : static const XP_CHAR dumpFileExtension[] = XP_TEXT(".dmp");
185 : #endif
186 :
187 : static const XP_CHAR childCrashAnnotationBaseName[] = XP_TEXT("GeckoChildCrash");
188 : static const XP_CHAR extraFileExtension[] = XP_TEXT(".extra");
189 : static const XP_CHAR memoryReportExtension[] = XP_TEXT(".memory.json.gz");
190 : static xpstring *defaultMemoryReportPath = nullptr;
191 :
192 : static const char kCrashMainID[] = "crash.main.2\n";
193 :
194 : static google_breakpad::ExceptionHandler* gExceptionHandler = nullptr;
195 :
196 : static XP_CHAR* pendingDirectory;
197 : static XP_CHAR* crashReporterPath;
198 : static XP_CHAR* memoryReportPath;
199 : #ifdef XP_MACOSX
200 : static XP_CHAR* libraryPath; // Path where the NSS library is
201 : #endif // XP_MACOSX
202 :
203 : // Where crash events should go.
204 : static XP_CHAR* eventsDirectory;
205 : static char* eventsEnv = nullptr;
206 :
207 : // The current telemetry session ID to write to the event file
208 : static char* currentSessionId = nullptr;
209 :
210 : // If this is false, we don't launch the crash reporter
211 : static bool doReport = true;
212 :
213 : // If this is true, we don't have a crash reporter
214 : static bool headlessClient = false;
215 :
216 : // if this is true, we pass the exception on to the OS crash reporter
217 : static bool showOSCrashReporter = false;
218 :
219 : // The time of the last recorded crash, as a time_t value.
220 : static time_t lastCrashTime = 0;
221 : // The pathname of a file to store the crash time in
222 : static XP_CHAR lastCrashTimeFilename[XP_PATH_MAX] = {0};
223 :
224 : // A marker file to hold the path to the last dump written, which
225 : // will be checked on startup.
226 : static XP_CHAR crashMarkerFilename[XP_PATH_MAX] = {0};
227 :
228 : // Whether we've already looked for the marker file.
229 : static bool lastRunCrashID_checked = false;
230 : // The minidump ID contained in the marker file.
231 : static nsString* lastRunCrashID = nullptr;
232 :
233 : #if defined(MOZ_WIDGET_ANDROID)
234 : // on Android 4.2 and above there is a user serial number associated
235 : // with the current process that gets lost when we fork so we need to
236 : // explicitly pass it to am
237 : static char* androidUserSerial = nullptr;
238 : #endif
239 :
240 : // these are just here for readability
241 : static const char kTimeSinceLastCrashParameter[] = "SecondsSinceLastCrash=";
242 : static const int kTimeSinceLastCrashParameterLen =
243 : sizeof(kTimeSinceLastCrashParameter)-1;
244 :
245 : // this holds additional data sent via the API
246 : static Mutex* crashReporterAPILock;
247 : static Mutex* notesFieldLock;
248 : static AnnotationTable* crashReporterAPIData_Hash;
249 : static nsCString* crashReporterAPIData = nullptr;
250 : static nsCString* crashEventAPIData = nullptr;
251 : static nsCString* notesField = nullptr;
252 : static bool isGarbageCollecting;
253 : static uint32_t eventloopNestingLevel = 0;
254 :
255 : // Avoid a race during application termination.
256 : static Mutex* dumpSafetyLock;
257 : static bool isSafeToDump = false;
258 :
259 : // Whether to include heap regions of the crash context.
260 : static bool sIncludeContextHeap = false;
261 :
262 : // OOP crash reporting
263 : static CrashGenerationServer* crashServer; // chrome process has this
264 :
265 : static std::terminate_handler oldTerminateHandler = nullptr;
266 :
267 : #if (defined(XP_MACOSX) || defined(XP_WIN))
268 : // This field is valid in both chrome and content processes.
269 : static xpstring* childProcessTmpDir = nullptr;
270 : #endif
271 :
272 : # if defined(XP_WIN) || defined(XP_MACOSX)
273 : // If crash reporting is disabled, we hand out this "null" pipe to the
274 : // child process and don't attempt to connect to a parent server.
275 : static const char kNullNotifyPipe[] = "-";
276 : static char* childCrashNotifyPipe;
277 :
278 : # elif defined(XP_LINUX)
279 : static int serverSocketFd = -1;
280 : static int clientSocketFd = -1;
281 : static int gMagicChildCrashReportFd =
282 : # if defined(MOZ_WIDGET_ANDROID)
283 : // On android the fd is set at the time of child creation.
284 : -1
285 : # else
286 : 4
287 : # endif // defined(MOZ_WIDGET_ANDROID)
288 : ;
289 : # endif
290 :
291 : // |dumpMapLock| must protect all access to |pidToMinidump|.
292 : static Mutex* dumpMapLock;
293 0 : struct ChildProcessData : public nsUint32HashKey
294 : {
295 0 : explicit ChildProcessData(KeyTypePointer aKey)
296 0 : : nsUint32HashKey(aKey)
297 0 : , sequence(0)
298 : #ifdef MOZ_CRASHREPORTER_INJECTOR
299 : , callback(nullptr)
300 : #endif
301 0 : { }
302 :
303 : nsCOMPtr<nsIFile> minidump;
304 : // Each crashing process is assigned an increasing sequence number to
305 : // indicate which process crashed first.
306 : uint32_t sequence;
307 : #ifdef MOZ_CRASHREPORTER_INJECTOR
308 : InjectorCrashCallback* callback;
309 : #endif
310 : };
311 :
312 : typedef nsTHashtable<ChildProcessData> ChildMinidumpMap;
313 : static ChildMinidumpMap* pidToMinidump;
314 : static uint32_t crashSequence;
315 : static bool OOPInitialized();
316 :
317 : static nsIThread* sMinidumpWriterThread;
318 :
319 : #ifdef MOZ_CRASHREPORTER_INJECTOR
320 : static nsIThread* sInjectorThread;
321 :
322 : class ReportInjectedCrash : public Runnable
323 : {
324 : public:
325 : explicit ReportInjectedCrash(uint32_t pid) : Runnable("ReportInjectedCrash"), mPID(pid) { }
326 :
327 : NS_IMETHOD Run();
328 :
329 : private:
330 : uint32_t mPID;
331 : };
332 : #endif // MOZ_CRASHREPORTER_INJECTOR
333 :
334 : // Crashreporter annotations that we don't send along in subprocess reports.
335 : static const char* kSubprocessBlacklist[] = {
336 : "FramePoisonBase",
337 : "FramePoisonSize",
338 : "StartupCrash",
339 : "StartupTime",
340 : "URL"
341 : };
342 :
343 : // If annotations are attempted before the crash reporter is enabled,
344 : // they queue up here.
345 : class DelayedNote;
346 : nsTArray<nsAutoPtr<DelayedNote> >* gDelayedAnnotations;
347 :
348 : #if defined(XP_WIN)
349 : // the following are used to prevent other DLLs reverting the last chance
350 : // exception handler to the windows default. Any attempt to change the
351 : // unhandled exception filter or to reset it is ignored and our crash
352 : // reporter is loaded instead (in case it became unloaded somehow)
353 : typedef LPTOP_LEVEL_EXCEPTION_FILTER (WINAPI *SetUnhandledExceptionFilter_func)
354 : (LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter);
355 : static SetUnhandledExceptionFilter_func stub_SetUnhandledExceptionFilter = 0;
356 : static LPTOP_LEVEL_EXCEPTION_FILTER previousUnhandledExceptionFilter = nullptr;
357 : static WindowsDllInterceptor gKernel32Intercept;
358 : static bool gBlockUnhandledExceptionFilter = true;
359 :
360 : static LPTOP_LEVEL_EXCEPTION_FILTER GetUnhandledExceptionFilter()
361 : {
362 : // Set a dummy value to get the current filter, then restore
363 : LPTOP_LEVEL_EXCEPTION_FILTER current = SetUnhandledExceptionFilter(nullptr);
364 : SetUnhandledExceptionFilter(current);
365 : return current;
366 : }
367 :
368 : static LPTOP_LEVEL_EXCEPTION_FILTER WINAPI
369 : patched_SetUnhandledExceptionFilter (LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter)
370 : {
371 : if (!gBlockUnhandledExceptionFilter) {
372 : // don't intercept
373 : return stub_SetUnhandledExceptionFilter(lpTopLevelExceptionFilter);
374 : }
375 :
376 : if (lpTopLevelExceptionFilter == previousUnhandledExceptionFilter) {
377 : // OK to swap back and forth between the previous filter
378 : previousUnhandledExceptionFilter =
379 : stub_SetUnhandledExceptionFilter(lpTopLevelExceptionFilter);
380 : return previousUnhandledExceptionFilter;
381 : }
382 :
383 : // intercept attempts to change the filter
384 : return nullptr;
385 : }
386 :
387 : #ifdef _WIN64
388 : static LPTOP_LEVEL_EXCEPTION_FILTER sUnhandledExceptionFilter = nullptr;
389 :
390 : static long
391 : JitExceptionHandler(void *exceptionRecord, void *context)
392 : {
393 : EXCEPTION_POINTERS pointers = {
394 : (PEXCEPTION_RECORD)exceptionRecord,
395 : (PCONTEXT)context
396 : };
397 : return sUnhandledExceptionFilter(&pointers);
398 : }
399 :
400 : static void
401 : SetJitExceptionHandler()
402 : {
403 : sUnhandledExceptionFilter = GetUnhandledExceptionFilter();
404 : if (sUnhandledExceptionFilter)
405 : js::SetJitExceptionHandler(JitExceptionHandler);
406 : }
407 : #endif
408 :
409 : /**
410 : * Reserve some VM space. In the event that we crash because VM space is
411 : * being leaked without leaking memory, freeing this space before taking
412 : * the minidump will allow us to collect a minidump.
413 : *
414 : * This size is bigger than xul.dll plus some extra for MinidumpWriteDump
415 : * allocations.
416 : */
417 : static const SIZE_T kReserveSize = 0x4000000; // 64 MB
418 : static void* gBreakpadReservedVM;
419 : #endif
420 :
421 : #if defined(MOZ_WIDGET_ANDROID)
422 : // Android builds use a custom library loader,
423 : // so the embedding will provide a list of shared
424 : // libraries that are mapped into anonymous mappings.
425 : typedef struct {
426 : std::string name;
427 : uintptr_t start_address;
428 : size_t length;
429 : size_t file_offset;
430 : } mapping_info;
431 : static std::vector<mapping_info> library_mappings;
432 : typedef std::map<uint32_t,google_breakpad::MappingList> MappingMap;
433 : #endif
434 : }
435 :
436 : // Format a non-negative double to a string, without using C-library functions,
437 : // which need to be avoided (.e.g. bug 1240160, comment 10). Leave the utility
438 : // non-file static so that we can gtest it. Return false if we failed to
439 : // get the formatting done correctly.
440 0 : bool SimpleNoCLibDtoA(double aValue, char* aBuffer, int aBufferLength)
441 : {
442 : // aBufferLength is the size of the buffer. Be paranoid.
443 0 : aBuffer[aBufferLength-1] = '\0';
444 :
445 0 : if (aValue < 0) {
446 0 : return false;
447 : }
448 :
449 : int length, point, i;
450 : bool sign;
451 0 : bool ok = true;
452 : double_conversion::DoubleToStringConverter::DoubleToAscii(
453 : aValue,
454 : double_conversion::DoubleToStringConverter::SHORTEST,
455 : 8,
456 : aBuffer,
457 : aBufferLength,
458 : &sign,
459 : &length,
460 0 : &point);
461 :
462 : // length does not account for the 0 terminator.
463 0 : if (length > point && (length+1) < (aBufferLength-1)) {
464 : // We have to insert a decimal point. Not worried about adding a leading zero
465 : // in the < 1 (point == 0) case.
466 0 : aBuffer[length+1] = '\0';
467 0 : for (i=length; i>point; i-=1) {
468 0 : aBuffer[i] = aBuffer[i-1];
469 : }
470 0 : aBuffer[i] = '.'; // Not worried about locales
471 0 : } else if (length < point) {
472 : // Trailing zeros scenario
473 0 : for (i=length; i<point; i+=1) {
474 0 : if (i >= aBufferLength-2) {
475 0 : ok = false;
476 : }
477 0 : aBuffer[i] = '0';
478 : }
479 0 : aBuffer[i] = '\0';
480 : }
481 0 : return ok;
482 : }
483 :
484 : namespace CrashReporter {
485 :
486 : #ifdef XP_LINUX
487 : inline void
488 0 : my_inttostring(intmax_t t, char* buffer, size_t buffer_length)
489 : {
490 0 : my_memset(buffer, 0, buffer_length);
491 0 : my_uitos(buffer, t, my_uint_len(t));
492 0 : }
493 : #endif
494 :
495 : #ifdef XP_WIN
496 : static void
497 : CreateFileFromPath(const xpstring& path, nsIFile** file)
498 : {
499 : NS_NewLocalFile(nsDependentString(path.c_str()), false, file);
500 : }
501 :
502 : static void
503 : CreateFileFromPath(const wchar_t* path, nsIFile** file)
504 : {
505 : CreateFileFromPath(std::wstring(path), file);
506 : }
507 :
508 : static xpstring*
509 : CreatePathFromFile(nsIFile* file)
510 : {
511 : nsAutoString path;
512 : nsresult rv = file->GetPath(path);
513 : if (NS_FAILED(rv)) {
514 : return nullptr;
515 : }
516 : return new xpstring(static_cast<wchar_t*>(path.get()), path.Length());
517 : }
518 : #else
519 : static void
520 0 : CreateFileFromPath(const xpstring& path, nsIFile** file)
521 : {
522 0 : NS_NewNativeLocalFile(nsDependentCString(path.c_str()), false, file);
523 0 : }
524 :
525 : MAYBE_UNUSED static xpstring*
526 2 : CreatePathFromFile(nsIFile* file)
527 : {
528 4 : nsAutoCString path;
529 2 : nsresult rv = file->GetNativePath(path);
530 2 : if (NS_FAILED(rv)) {
531 0 : return nullptr;
532 : }
533 4 : return new xpstring(path.get(), path.Length());
534 : }
535 : #endif
536 :
537 : static XP_CHAR*
538 0 : Concat(XP_CHAR* str, const XP_CHAR* toAppend, size_t* size)
539 : {
540 0 : size_t appendLen = XP_STRLEN(toAppend);
541 0 : if (appendLen >= *size) {
542 0 : appendLen = *size - 1;
543 : }
544 :
545 0 : memcpy(str, toAppend, appendLen * sizeof(XP_CHAR));
546 0 : str += appendLen;
547 0 : *str = '\0';
548 0 : *size -= appendLen;
549 :
550 0 : return str;
551 : }
552 :
553 : static size_t gOOMAllocationSize = 0;
554 :
555 0 : void AnnotateOOMAllocationSize(size_t size)
556 : {
557 0 : gOOMAllocationSize = size;
558 0 : }
559 :
560 : static size_t gTexturesSize = 0;
561 :
562 0 : void AnnotateTexturesSize(size_t size)
563 : {
564 0 : gTexturesSize = size;
565 0 : }
566 :
567 : static size_t gNumOfPendingIPC = 0;
568 : static uint32_t gTopPendingIPCCount = 0;
569 : static const char* gTopPendingIPCName = nullptr;
570 : static uint32_t gTopPendingIPCType = 0;
571 :
572 0 : void AnnotatePendingIPC(size_t aNumOfPendingIPC,
573 : uint32_t aTopPendingIPCCount,
574 : const char* aTopPendingIPCName,
575 : uint32_t aTopPendingIPCType)
576 : {
577 0 : gNumOfPendingIPC = aNumOfPendingIPC;
578 0 : gTopPendingIPCCount = aTopPendingIPCCount;
579 0 : gTopPendingIPCName = aTopPendingIPCName;
580 0 : gTopPendingIPCType = aTopPendingIPCType;
581 0 : }
582 :
583 : #ifndef XP_WIN
584 : // Like Windows CopyFile for *nix
585 0 : bool copy_file(const char* from, const char* to)
586 : {
587 0 : const int kBufSize = 4096;
588 0 : int fdfrom = sys_open(from, O_RDONLY, 0);
589 0 : if (fdfrom < 0) {
590 0 : return false;
591 : }
592 :
593 0 : bool ok = false;
594 :
595 0 : int fdto = sys_open(to, O_WRONLY | O_CREAT, 0666);
596 0 : if (fdto < 0) {
597 0 : sys_close(fdfrom);
598 0 : return false;
599 : }
600 :
601 : char buf[kBufSize];
602 : while (true) {
603 0 : int r = sys_read(fdfrom, buf, kBufSize);
604 0 : if (r == 0) {
605 0 : ok = true;
606 0 : break;
607 : }
608 0 : if (r < 0) {
609 0 : break;
610 : }
611 0 : char* wbuf = buf;
612 0 : while (r) {
613 0 : int w = sys_write(fdto, wbuf, r);
614 0 : if (w > 0) {
615 0 : r -= w;
616 0 : wbuf += w;
617 0 : } else if (errno != EINTR) {
618 0 : break;
619 : }
620 : }
621 0 : if (r) {
622 0 : break;
623 : }
624 0 : }
625 :
626 0 : sys_close(fdfrom);
627 0 : sys_close(fdto);
628 :
629 0 : return ok;
630 : }
631 : #endif
632 :
633 : #ifdef XP_WIN
634 :
635 : class PlatformWriter
636 : {
637 : public:
638 : PlatformWriter()
639 : : mHandle(INVALID_HANDLE_VALUE)
640 : { }
641 :
642 : explicit PlatformWriter(const wchar_t* path)
643 : : PlatformWriter()
644 : {
645 : Open(path);
646 : }
647 :
648 : ~PlatformWriter() {
649 : if (Valid()) {
650 : CloseHandle(mHandle);
651 : }
652 : }
653 :
654 : void Open(const wchar_t* path) {
655 : mHandle = CreateFile(path, GENERIC_WRITE, 0,
656 : nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
657 : nullptr);
658 : }
659 :
660 : bool Valid() {
661 : return mHandle != INVALID_HANDLE_VALUE;
662 : }
663 :
664 : void WriteBuffer(const char* buffer, size_t len)
665 : {
666 : if (!Valid()) {
667 : return;
668 : }
669 : DWORD nBytes;
670 : WriteFile(mHandle, buffer, len, &nBytes, nullptr);
671 : }
672 :
673 : HANDLE Handle() {
674 : return mHandle;
675 : }
676 :
677 : private:
678 : HANDLE mHandle;
679 : };
680 :
681 : #elif defined(XP_UNIX)
682 :
683 : class PlatformWriter
684 : {
685 : public:
686 0 : PlatformWriter()
687 0 : : mFD(-1)
688 0 : { }
689 :
690 0 : explicit PlatformWriter(const char* path)
691 0 : : PlatformWriter()
692 : {
693 0 : Open(path);
694 0 : }
695 :
696 0 : ~PlatformWriter() {
697 0 : if (Valid()) {
698 0 : sys_close(mFD);
699 : }
700 0 : }
701 :
702 0 : void Open(const char* path) {
703 0 : mFD = sys_open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
704 0 : }
705 :
706 0 : bool Valid() {
707 0 : return mFD != -1;
708 : }
709 :
710 0 : void WriteBuffer(const char* buffer, size_t len) {
711 0 : if (!Valid()) {
712 0 : return;
713 : }
714 0 : Unused << sys_write(mFD, buffer, len);
715 : }
716 :
717 : private:
718 : int mFD;
719 : };
720 :
721 : #else
722 : #error "Need implementation of PlatformWrite for this platform"
723 : #endif
724 :
725 : template<int N>
726 : void
727 0 : WriteLiteral(PlatformWriter& pw, const char (&str)[N])
728 : {
729 0 : pw.WriteBuffer(str, N - 1);
730 0 : }
731 :
732 : static void
733 0 : WriteString(PlatformWriter& pw, const char* str) {
734 : #ifdef XP_LINUX
735 0 : size_t len = my_strlen(str);
736 : #else
737 : size_t len = strlen(str);
738 : #endif
739 :
740 0 : pw.WriteBuffer(str, len);
741 0 : }
742 :
743 : template<int N>
744 : static void
745 0 : WriteAnnotation(PlatformWriter& pw, const char (&name)[N],
746 : const char* value) {
747 0 : WriteLiteral(pw, name);
748 0 : WriteLiteral(pw, "=");
749 0 : WriteString(pw, value);
750 0 : WriteLiteral(pw, "\n");
751 0 : };
752 :
753 : /**
754 : * If minidump_id is null, we assume that dump_path contains the full
755 : * dump file path.
756 : */
757 : static void
758 0 : OpenAPIData(PlatformWriter& aWriter,
759 : const XP_CHAR* dump_path, const XP_CHAR* minidump_id = nullptr
760 : )
761 : {
762 : static XP_CHAR extraDataPath[XP_PATH_MAX];
763 0 : size_t size = XP_PATH_MAX;
764 : XP_CHAR* p;
765 0 : if (minidump_id) {
766 0 : p = Concat(extraDataPath, dump_path, &size);
767 0 : p = Concat(p, XP_PATH_SEPARATOR, &size);
768 0 : p = Concat(p, minidump_id, &size);
769 : } else {
770 0 : p = Concat(extraDataPath, dump_path, &size);
771 : // Skip back past the .dmp extension, if any.
772 0 : if (*(p - 4) == XP_TEXT('.')) {
773 0 : p -= 4;
774 0 : size += 4;
775 : }
776 : }
777 0 : Concat(p, extraFileExtension, &size);
778 0 : aWriter.Open(extraDataPath);
779 0 : }
780 :
781 : #ifdef XP_WIN
782 : void
783 : WriteGlobalMemoryStatus(PlatformWriter* apiData, PlatformWriter* eventFile)
784 : {
785 : char buffer[128];
786 :
787 : // Try to get some information about memory.
788 : MEMORYSTATUSEX statex;
789 : statex.dwLength = sizeof(statex);
790 : if (GlobalMemoryStatusEx(&statex)) {
791 :
792 : #define WRITE_STATEX_FIELD(field, name, conversionFunc) \
793 : conversionFunc(statex.field, buffer, 10); \
794 : if (apiData) { \
795 : WriteAnnotation(*apiData, name, buffer); \
796 : } \
797 : if (eventFile) { \
798 : WriteAnnotation(*eventFile, name, buffer); \
799 : }
800 :
801 : WRITE_STATEX_FIELD(dwMemoryLoad, "SystemMemoryUsePercentage", ltoa);
802 : WRITE_STATEX_FIELD(ullTotalVirtual, "TotalVirtualMemory", _ui64toa);
803 : WRITE_STATEX_FIELD(ullAvailVirtual, "AvailableVirtualMemory", _ui64toa);
804 : WRITE_STATEX_FIELD(ullTotalPageFile, "TotalPageFile", _ui64toa);
805 : WRITE_STATEX_FIELD(ullAvailPageFile, "AvailablePageFile", _ui64toa);
806 : WRITE_STATEX_FIELD(ullTotalPhys, "TotalPhysicalMemory", _ui64toa);
807 : WRITE_STATEX_FIELD(ullAvailPhys, "AvailablePhysicalMemory", _ui64toa);
808 :
809 : #undef WRITE_STATEX_FIELD
810 : }
811 : }
812 : #endif
813 :
814 : #if !defined(MOZ_WIDGET_ANDROID)
815 :
816 : /**
817 : * Launches the program specified in aProgramPath with aMinidumpPath as its
818 : * sole argument.
819 : *
820 : * @param aProgramPath The path of the program to be launched
821 : * @param aMinidumpPath The path of the minidump file, passed as an argument
822 : * to the launched program
823 : */
824 : static bool
825 0 : LaunchProgram(const XP_CHAR* aProgramPath, const XP_CHAR* aMinidumpPath)
826 : {
827 : #ifdef XP_WIN
828 : XP_CHAR cmdLine[CMDLINE_SIZE];
829 : XP_CHAR* p;
830 :
831 : size_t size = CMDLINE_SIZE;
832 : p = Concat(cmdLine, L"\"", &size);
833 : p = Concat(p, aProgramPath, &size);
834 : p = Concat(p, L"\" \"", &size);
835 : p = Concat(p, aMinidumpPath, &size);
836 : Concat(p, L"\"", &size);
837 :
838 : PROCESS_INFORMATION pi = {};
839 : STARTUPINFO si = {};
840 : si.cb = sizeof(si);
841 :
842 : // If CreateProcess() fails don't do anything
843 : if (CreateProcess(nullptr, (LPWSTR)cmdLine, nullptr, nullptr, FALSE,
844 : NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW,
845 : nullptr, nullptr, &si, &pi)) {
846 : CloseHandle(pi.hProcess);
847 : CloseHandle(pi.hThread);
848 : }
849 : #elif defined(XP_UNIX)
850 0 : pid_t pid = sys_fork();
851 :
852 0 : if (pid == -1) {
853 0 : return false;
854 0 : } else if (pid == 0) {
855 : #ifdef XP_LINUX
856 : // need to clobber this, as libcurl might load NSS,
857 : // and we want it to load the system NSS.
858 0 : unsetenv("LD_LIBRARY_PATH");
859 : #else // XP_MACOSX
860 : // Needed to locate NSS and its dependencies
861 : setenv("DYLD_LIBRARY_PATH", libraryPath, /* overwrite */ 1);
862 : #endif
863 0 : Unused << execl(aProgramPath,
864 : aProgramPath, aMinidumpPath, (char*)0);
865 0 : _exit(1);
866 : }
867 : #endif // XP_UNIX
868 :
869 0 : return true;
870 : }
871 :
872 : #else
873 :
874 : /**
875 : * Launch the crash reporter activity on Android
876 : *
877 : * @param aProgramPath The path of the program to be launched
878 : * @param aMinidumpPath The path to the crash minidump file
879 : * @param aSucceeded True if the minidump was obtained successfully
880 : */
881 :
882 : static bool
883 : LaunchCrashReporterActivity(XP_CHAR* aProgramPath, XP_CHAR* aMinidumpPath,
884 : bool aSucceeded)
885 : {
886 : pid_t pid = sys_fork();
887 :
888 : if (pid == -1)
889 : return false;
890 : else if (pid == 0) {
891 : // Invoke the reportCrash activity using am
892 : if (androidUserSerial) {
893 : Unused << execlp("/system/bin/am",
894 : "/system/bin/am",
895 : "start",
896 : "--user", androidUserSerial,
897 : "-a", "org.mozilla.gecko.reportCrash",
898 : "-n", aProgramPath,
899 : "--es", "minidumpPath", aMinidumpPath,
900 : "--ez", "minidumpSuccess", aSucceeded ? "true" : "false",
901 : (char*)0);
902 : } else {
903 : Unused << execlp("/system/bin/am",
904 : "/system/bin/am",
905 : "start",
906 : "-a", "org.mozilla.gecko.reportCrash",
907 : "-n", aProgramPath,
908 : "--es", "minidumpPath", aMinidumpPath,
909 : "--ez", "minidumpSuccess", aSucceeded ? "true" : "false",
910 : (char*)0);
911 : }
912 : _exit(1);
913 :
914 : } else {
915 : // We need to wait on the 'am start' command above to finish, otherwise everything will
916 : // be killed by the ActivityManager as soon as the signal handler exits
917 : int status;
918 : Unused << HANDLE_EINTR(sys_waitpid(pid, &status, __WALL));
919 : }
920 :
921 : return true;
922 : }
923 :
924 : #endif
925 :
926 0 : bool MinidumpCallback(
927 : #ifdef XP_LINUX
928 : const MinidumpDescriptor& descriptor,
929 : #else
930 : const XP_CHAR* dump_path,
931 : const XP_CHAR* minidump_id,
932 : #endif
933 : void* context,
934 : #ifdef XP_WIN32
935 : EXCEPTION_POINTERS* exinfo,
936 : MDRawAssertionInfo* assertion,
937 : #endif
938 : bool succeeded)
939 : {
940 0 : bool returnValue = showOSCrashReporter ? false : succeeded;
941 :
942 : static XP_CHAR minidumpPath[XP_PATH_MAX];
943 0 : size_t size = XP_PATH_MAX;
944 : XP_CHAR* p;
945 : #ifndef XP_LINUX
946 : p = Concat(minidumpPath, dump_path, &size);
947 : p = Concat(p, XP_PATH_SEPARATOR, &size);
948 : p = Concat(p, minidump_id, &size);
949 : Concat(p, dumpFileExtension, &size);
950 : #else
951 0 : Concat(minidumpPath, descriptor.path(), &size);
952 : #endif
953 :
954 : static XP_CHAR memoryReportLocalPath[XP_PATH_MAX];
955 0 : size = XP_PATH_MAX;
956 : #ifndef XP_LINUX
957 : p = Concat(memoryReportLocalPath, dump_path, &size);
958 : p = Concat(p, XP_PATH_SEPARATOR, &size);
959 : p = Concat(p, minidump_id, &size);
960 : #else
961 0 : p = Concat(memoryReportLocalPath, descriptor.path(), &size);
962 : // Skip back past the .dmp extension
963 0 : p -= 4;
964 : #endif
965 0 : Concat(p, memoryReportExtension, &size);
966 :
967 0 : if (memoryReportPath) {
968 : #ifdef XP_WIN
969 : CopyFile(memoryReportPath, memoryReportLocalPath, false);
970 : #else
971 0 : copy_file(memoryReportPath, memoryReportLocalPath);
972 : #endif
973 : }
974 :
975 0 : if (headlessClient) {
976 : // Leave a marker indicating that there was a crash.
977 0 : PlatformWriter markerFile(crashMarkerFilename);
978 : #if defined(XP_WIN)
979 : markerFile.WriteBuffer(reinterpret_cast<const char*>(minidumpPath),
980 : 2*wcslen(minidumpPath));
981 : #elif defined(XP_UNIX)
982 0 : markerFile.WriteBuffer(minidumpPath, my_strlen(minidumpPath));
983 : #endif
984 : }
985 :
986 0 : char oomAllocationSizeBuffer[32] = "";
987 0 : if (gOOMAllocationSize) {
988 0 : XP_STOA(gOOMAllocationSize, oomAllocationSizeBuffer, 10);
989 : }
990 :
991 0 : char texturesSizeBuffer[32] = "";
992 0 : if (gTexturesSize) {
993 0 : XP_STOA(gTexturesSize, texturesSizeBuffer, 10);
994 : }
995 :
996 0 : char numOfPendingIPCBuffer[32] = "";
997 0 : char topPendingIPCCountBuffer[32] = "";
998 0 : char topPendingIPCTypeBuffer[11] = "0x";
999 0 : if (gNumOfPendingIPC) {
1000 0 : XP_STOA(gNumOfPendingIPC, numOfPendingIPCBuffer, 10);
1001 0 : if (gTopPendingIPCCount) {
1002 0 : XP_STOA(gTopPendingIPCCount, topPendingIPCCountBuffer, 10);
1003 : }
1004 0 : if (gTopPendingIPCType) {
1005 0 : XP_STOA(gTopPendingIPCType, &topPendingIPCTypeBuffer[2], 16);
1006 : }
1007 : }
1008 :
1009 : // calculate time since last crash (if possible), and store
1010 : // the time of this crash.
1011 : time_t crashTime;
1012 : #ifdef XP_LINUX
1013 : struct kernel_timeval tv;
1014 0 : sys_gettimeofday(&tv, nullptr);
1015 0 : crashTime = tv.tv_sec;
1016 : #else
1017 : crashTime = time(nullptr);
1018 : #endif
1019 0 : time_t timeSinceLastCrash = 0;
1020 : // stringified versions of the above
1021 : char crashTimeString[32];
1022 : char timeSinceLastCrashString[32];
1023 :
1024 0 : XP_TTOA(crashTime, crashTimeString, 10);
1025 0 : if (lastCrashTime != 0) {
1026 0 : timeSinceLastCrash = crashTime - lastCrashTime;
1027 0 : XP_TTOA(timeSinceLastCrash, timeSinceLastCrashString, 10);
1028 : }
1029 : // write crash time to file
1030 0 : if (lastCrashTimeFilename[0] != 0) {
1031 0 : PlatformWriter lastCrashFile(lastCrashTimeFilename);
1032 0 : WriteString(lastCrashFile, crashTimeString);
1033 : }
1034 :
1035 0 : double uptimeTS = (TimeStamp::NowLoRes() -
1036 0 : TimeStamp::ProcessCreation()).ToSecondsSigDigits();
1037 : char uptimeTSString[64];
1038 0 : SimpleNoCLibDtoA(uptimeTS, uptimeTSString, sizeof(uptimeTSString));
1039 :
1040 : // Write crash event file.
1041 :
1042 : // Minidump IDs are UUIDs (36) + NULL.
1043 : static char id_ascii[37];
1044 : #ifdef XP_LINUX
1045 0 : const char * index = strrchr(descriptor.path(), '/');
1046 0 : MOZ_ASSERT(index);
1047 0 : MOZ_ASSERT(strlen(index) == 1 + 36 + 4); // "/" + UUID + ".dmp"
1048 0 : for (uint32_t i = 0; i < 36; i++) {
1049 0 : id_ascii[i] = *(index + 1 + i);
1050 : }
1051 : #else
1052 : MOZ_ASSERT(XP_STRLEN(minidump_id) == 36);
1053 : for (uint32_t i = 0; i < 36; i++) {
1054 : id_ascii[i] = *((char *)(minidump_id + i));
1055 : }
1056 : #endif
1057 :
1058 : {
1059 0 : PlatformWriter apiData;
1060 0 : PlatformWriter eventFile;
1061 :
1062 0 : if (eventsDirectory) {
1063 : static XP_CHAR crashEventPath[XP_PATH_MAX];
1064 0 : size_t size = XP_PATH_MAX;
1065 : XP_CHAR* p;
1066 0 : p = Concat(crashEventPath, eventsDirectory, &size);
1067 0 : p = Concat(p, XP_PATH_SEPARATOR, &size);
1068 : #ifdef XP_LINUX
1069 0 : p = Concat(p, id_ascii, &size);
1070 : #else
1071 : p = Concat(p, minidump_id, &size);
1072 : #endif
1073 :
1074 0 : eventFile.Open(crashEventPath);
1075 0 : WriteLiteral(eventFile, kCrashMainID);
1076 0 : WriteString(eventFile, crashTimeString);
1077 0 : WriteLiteral(eventFile, "\n");
1078 0 : WriteString(eventFile, id_ascii);
1079 0 : WriteLiteral(eventFile, "\n");
1080 0 : if (crashEventAPIData) {
1081 0 : eventFile.WriteBuffer(crashEventAPIData->get(), crashEventAPIData->Length());
1082 : }
1083 : }
1084 :
1085 0 : if (!crashReporterAPIData->IsEmpty()) {
1086 : // write out API data
1087 : #ifdef XP_LINUX
1088 0 : OpenAPIData(apiData, descriptor.path());
1089 : #else
1090 : OpenAPIData(apiData, dump_path, minidump_id);
1091 : #endif
1092 0 : apiData.WriteBuffer(crashReporterAPIData->get(), crashReporterAPIData->Length());
1093 : }
1094 :
1095 0 : if (currentSessionId) {
1096 0 : WriteAnnotation(apiData, "TelemetrySessionId", currentSessionId);
1097 0 : WriteAnnotation(eventFile, "TelemetrySessionId", currentSessionId);
1098 : }
1099 :
1100 0 : WriteAnnotation(apiData, "CrashTime", crashTimeString);
1101 0 : WriteAnnotation(eventFile, "CrashTime", crashTimeString);
1102 :
1103 0 : WriteAnnotation(apiData, "UptimeTS", uptimeTSString);
1104 0 : WriteAnnotation(eventFile, "UptimeTS", uptimeTSString);
1105 :
1106 0 : if (timeSinceLastCrash != 0) {
1107 : WriteAnnotation(apiData, "SecondsSinceLastCrash",
1108 0 : timeSinceLastCrashString);
1109 : WriteAnnotation(eventFile, "SecondsSinceLastCrash",
1110 0 : timeSinceLastCrashString);
1111 : }
1112 0 : if (isGarbageCollecting) {
1113 0 : WriteAnnotation(apiData, "IsGarbageCollecting", "1");
1114 0 : WriteAnnotation(eventFile, "IsGarbageCollecting", "1");
1115 : }
1116 :
1117 : char buffer[128];
1118 :
1119 0 : if (eventloopNestingLevel > 0) {
1120 0 : XP_STOA(eventloopNestingLevel, buffer, 10);
1121 0 : WriteAnnotation(apiData, "EventLoopNestingLevel", buffer);
1122 0 : WriteAnnotation(eventFile, "EventLoopNestingLevel", buffer);
1123 : }
1124 :
1125 : #ifdef XP_WIN
1126 : if (gBreakpadReservedVM) {
1127 : _ui64toa(uintptr_t(gBreakpadReservedVM), buffer, 10);
1128 : WriteAnnotation(apiData, "BreakpadReserveAddress", buffer);
1129 : _ui64toa(kReserveSize, buffer, 10);
1130 : WriteAnnotation(apiData, "BreakpadReserveSize", buffer);
1131 : }
1132 :
1133 : #ifdef HAS_DLL_BLOCKLIST
1134 : if (apiData.Valid()) {
1135 : DllBlocklist_WriteNotes(apiData.Handle());
1136 : DllBlocklist_WriteNotes(eventFile.Handle());
1137 : }
1138 : #endif
1139 : WriteGlobalMemoryStatus(&apiData, &eventFile);
1140 : #endif // XP_WIN
1141 :
1142 : char* rust_panic_reason;
1143 : size_t rust_panic_len;
1144 0 : if (get_rust_panic_reason(&rust_panic_reason, &rust_panic_len)) {
1145 : // rust_panic_reason is not null-terminated.
1146 0 : WriteLiteral(apiData, "MozCrashReason=");
1147 0 : apiData.WriteBuffer(rust_panic_reason, rust_panic_len);
1148 0 : WriteLiteral(apiData, "\n");
1149 0 : WriteLiteral(eventFile, "MozCrashReason=");
1150 0 : eventFile.WriteBuffer(rust_panic_reason, rust_panic_len);
1151 0 : WriteLiteral(eventFile, "\n");
1152 0 : } else if (gMozCrashReason) {
1153 0 : WriteAnnotation(apiData, "MozCrashReason", gMozCrashReason);
1154 0 : WriteAnnotation(eventFile, "MozCrashReason", gMozCrashReason);
1155 : }
1156 :
1157 0 : if (oomAllocationSizeBuffer[0]) {
1158 0 : WriteAnnotation(apiData, "OOMAllocationSize", oomAllocationSizeBuffer);
1159 0 : WriteAnnotation(eventFile, "OOMAllocationSize", oomAllocationSizeBuffer);
1160 : }
1161 :
1162 0 : if (texturesSizeBuffer[0]) {
1163 0 : WriteAnnotation(apiData, "TextureUsage", texturesSizeBuffer);
1164 0 : WriteAnnotation(eventFile, "TextureUsage", texturesSizeBuffer);
1165 : }
1166 :
1167 0 : if (numOfPendingIPCBuffer[0]) {
1168 0 : WriteAnnotation(apiData, "NumberOfPendingIPC", numOfPendingIPCBuffer);
1169 0 : WriteAnnotation(eventFile, "NumberOfPendingIPC", numOfPendingIPCBuffer);
1170 0 : if (topPendingIPCCountBuffer[0]) {
1171 0 : WriteAnnotation(apiData, "TopPendingIPCCount", topPendingIPCCountBuffer);
1172 0 : WriteAnnotation(eventFile, "TopPendingIPCCount", topPendingIPCCountBuffer);
1173 : }
1174 0 : if (gTopPendingIPCName) {
1175 0 : WriteAnnotation(apiData, "TopPendingIPCName", gTopPendingIPCName);
1176 0 : WriteAnnotation(eventFile, "TopPendingIPCName", gTopPendingIPCName);
1177 : }
1178 0 : if (topPendingIPCTypeBuffer[2]) {
1179 0 : WriteAnnotation(apiData, "TopPendingIPCType", topPendingIPCTypeBuffer);
1180 0 : WriteAnnotation(eventFile, "TopPendingIPCType", topPendingIPCTypeBuffer);
1181 : }
1182 : }
1183 :
1184 0 : if (memoryReportPath) {
1185 0 : WriteLiteral(apiData, "ContainsMemoryReport=1\n");
1186 0 : WriteLiteral(eventFile, "ContainsMemoryReport=1\n");
1187 : }
1188 :
1189 : std::function<void(const char*)> getThreadAnnotationCB =
1190 0 : [&] (const char * aAnnotation) -> void {
1191 0 : if (aAnnotation) {
1192 0 : WriteLiteral(apiData, "ThreadIdNameMapping=");
1193 0 : WriteLiteral(eventFile, "ThreadIdNameMapping=");
1194 0 : WriteString(apiData, aAnnotation);
1195 0 : WriteString(eventFile, aAnnotation);
1196 0 : WriteLiteral(apiData, "\n");
1197 0 : WriteLiteral(eventFile, "\n");
1198 : }
1199 0 : };
1200 0 : GetFlatThreadAnnotation(getThreadAnnotationCB);
1201 : }
1202 :
1203 0 : if (!doReport) {
1204 : #ifdef XP_WIN
1205 : TerminateProcess(GetCurrentProcess(), 1);
1206 : #endif // XP_WIN
1207 0 : return returnValue;
1208 : }
1209 :
1210 : #if defined(MOZ_WIDGET_ANDROID) // Android
1211 : returnValue = LaunchCrashReporterActivity(crashReporterPath, minidumpPath,
1212 : succeeded);
1213 : #else // Windows, Mac, Linux, etc...
1214 0 : returnValue = LaunchProgram(crashReporterPath, minidumpPath);
1215 : #ifdef XP_WIN
1216 : TerminateProcess(GetCurrentProcess(), 1);
1217 : #endif
1218 : #endif
1219 :
1220 0 : return returnValue;
1221 : }
1222 :
1223 : #if defined(XP_MACOSX) || defined(__ANDROID__) || defined(XP_LINUX)
1224 : static size_t
1225 0 : EnsureTrailingSlash(XP_CHAR* aBuf, size_t aBufLen)
1226 : {
1227 0 : size_t len = XP_STRLEN(aBuf);
1228 0 : if ((len + 1) < aBufLen
1229 0 : && len > 0
1230 0 : && aBuf[len - 1] != XP_PATH_SEPARATOR_CHAR) {
1231 0 : aBuf[len] = XP_PATH_SEPARATOR_CHAR;
1232 0 : ++len;
1233 0 : aBuf[len] = 0;
1234 : }
1235 0 : return len;
1236 : }
1237 : #endif
1238 :
1239 : #if defined(XP_WIN32)
1240 :
1241 : static size_t
1242 : BuildTempPath(wchar_t* aBuf, size_t aBufLen)
1243 : {
1244 : // first figure out buffer size
1245 : DWORD pathLen = GetTempPath(0, nullptr);
1246 : if (pathLen == 0 || pathLen >= aBufLen) {
1247 : return 0;
1248 : }
1249 :
1250 : return GetTempPath(pathLen, aBuf);
1251 : }
1252 :
1253 : static size_t
1254 : BuildTempPath(char16_t* aBuf, size_t aBufLen)
1255 : {
1256 : return BuildTempPath(reinterpret_cast<wchar_t*>(aBuf), aBufLen);
1257 : }
1258 :
1259 : #elif defined(XP_MACOSX)
1260 :
1261 : static size_t
1262 : BuildTempPath(char* aBuf, size_t aBufLen)
1263 : {
1264 : if (aBufLen < PATH_MAX) {
1265 : return 0;
1266 : }
1267 :
1268 : FSRef fsRef;
1269 : OSErr err = FSFindFolder(kUserDomain, kTemporaryFolderType,
1270 : kCreateFolder, &fsRef);
1271 : if (err != noErr) {
1272 : return 0;
1273 : }
1274 :
1275 : OSStatus status = FSRefMakePath(&fsRef, (UInt8*)aBuf, PATH_MAX);
1276 : if (status != noErr) {
1277 : return 0;
1278 : }
1279 :
1280 : return EnsureTrailingSlash(aBuf, aBufLen);
1281 : }
1282 :
1283 : #elif defined(__ANDROID__)
1284 :
1285 : static size_t
1286 : BuildTempPath(char* aBuf, size_t aBufLen)
1287 : {
1288 : // GeckoAppShell or Gonk's init.rc sets this in the environment
1289 : const char *tempenv = PR_GetEnv("TMPDIR");
1290 : if (!tempenv) {
1291 : return false;
1292 : }
1293 : size_t size = aBufLen;
1294 : Concat(aBuf, tempenv, &size);
1295 : return EnsureTrailingSlash(aBuf, aBufLen);
1296 : }
1297 :
1298 : #elif defined(XP_UNIX)
1299 :
1300 : static size_t
1301 0 : BuildTempPath(char* aBuf, size_t aBufLen)
1302 : {
1303 0 : const char *tempenv = PR_GetEnv("TMPDIR");
1304 0 : const char *tmpPath = "/tmp/";
1305 0 : if (!tempenv) {
1306 0 : tempenv = tmpPath;
1307 : }
1308 0 : size_t size = aBufLen;
1309 0 : Concat(aBuf, tempenv, &size);
1310 0 : return EnsureTrailingSlash(aBuf, aBufLen);
1311 : }
1312 :
1313 : #else
1314 : #error "Implement this for your platform"
1315 : #endif
1316 :
1317 : template <typename CharT, size_t N>
1318 : static size_t
1319 0 : BuildTempPath(CharT (&aBuf)[N])
1320 : {
1321 : static_assert(N >= XP_PATH_MAX, "char array length is too small");
1322 0 : return BuildTempPath(&aBuf[0], N);
1323 : }
1324 :
1325 : template <typename PathStringT>
1326 : static bool
1327 0 : BuildTempPath(PathStringT& aResult)
1328 : {
1329 0 : aResult.SetLength(XP_PATH_MAX);
1330 0 : size_t actualLen = BuildTempPath(aResult.BeginWriting(), XP_PATH_MAX);
1331 0 : if (!actualLen) {
1332 0 : return false;
1333 : }
1334 0 : aResult.SetLength(actualLen);
1335 0 : return true;
1336 : }
1337 :
1338 : static void
1339 0 : PrepareChildExceptionTimeAnnotations()
1340 : {
1341 0 : MOZ_ASSERT(!XRE_IsParentProcess());
1342 : static XP_CHAR tempPath[XP_PATH_MAX] = {0};
1343 :
1344 : // Get the temp path
1345 0 : size_t charsAvailable = XP_PATH_MAX;
1346 0 : XP_CHAR* p = tempPath;
1347 : #if (defined(XP_MACOSX) || defined(XP_WIN))
1348 : if (!childProcessTmpDir || childProcessTmpDir->empty()) {
1349 : return;
1350 : }
1351 : p = Concat(p, childProcessTmpDir->c_str(), &charsAvailable);
1352 : // Ensure that this path ends with a path separator
1353 : if (p > tempPath && *(p - 1) != XP_PATH_SEPARATOR_CHAR) {
1354 : p = Concat(p, XP_PATH_SEPARATOR, &charsAvailable);
1355 : }
1356 : #else
1357 0 : size_t tempPathLen = BuildTempPath(tempPath);
1358 0 : if (!tempPathLen) {
1359 0 : return;
1360 : }
1361 0 : p += tempPathLen;
1362 0 : charsAvailable -= tempPathLen;
1363 : #endif
1364 :
1365 : // Generate and append the file name
1366 0 : p = Concat(p, childCrashAnnotationBaseName, &charsAvailable);
1367 0 : XP_CHAR pidBuffer[32] = XP_TEXT("");
1368 : #if defined(XP_WIN32)
1369 : _ui64tow(GetCurrentProcessId(), pidBuffer, 10);
1370 : #else
1371 0 : XP_STOA(getpid(), pidBuffer, 10);
1372 : #endif
1373 0 : p = Concat(p, pidBuffer, &charsAvailable);
1374 :
1375 : // Now open the file...
1376 0 : PlatformWriter apiData;
1377 0 : OpenAPIData(apiData, tempPath);
1378 :
1379 : // ...and write out any annotations. These must be escaped if necessary
1380 : // (but don't call EscapeAnnotation here, because it touches the heap).
1381 : #ifdef XP_WIN
1382 : WriteGlobalMemoryStatus(&apiData, nullptr);
1383 : #endif
1384 :
1385 0 : char oomAllocationSizeBuffer[32] = "";
1386 0 : if (gOOMAllocationSize) {
1387 0 : XP_STOA(gOOMAllocationSize, oomAllocationSizeBuffer, 10);
1388 : }
1389 :
1390 0 : if (oomAllocationSizeBuffer[0]) {
1391 0 : WriteAnnotation(apiData, "OOMAllocationSize", oomAllocationSizeBuffer);
1392 : }
1393 :
1394 0 : if (gMozCrashReason) {
1395 0 : WriteAnnotation(apiData, "MozCrashReason", gMozCrashReason);
1396 : }
1397 :
1398 0 : char numOfPendingIPCBuffer[32] = "";
1399 0 : char topPendingIPCCountBuffer[32] = "";
1400 0 : char topPendingIPCTypeBuffer[11] = "0x";
1401 0 : if (gNumOfPendingIPC) {
1402 0 : XP_STOA(gNumOfPendingIPC, numOfPendingIPCBuffer, 10);
1403 0 : if (gTopPendingIPCCount) {
1404 0 : XP_STOA(gTopPendingIPCCount, topPendingIPCCountBuffer, 10);
1405 : }
1406 0 : if (gTopPendingIPCType) {
1407 0 : XP_STOA(gTopPendingIPCType, &topPendingIPCTypeBuffer[2], 16);
1408 : }
1409 : }
1410 :
1411 0 : if (numOfPendingIPCBuffer[0]) {
1412 0 : WriteAnnotation(apiData, "NumberOfPendingIPC", numOfPendingIPCBuffer);
1413 0 : if (topPendingIPCCountBuffer[0]) {
1414 0 : WriteAnnotation(apiData, "TopPendingIPCCount", topPendingIPCCountBuffer);
1415 : }
1416 0 : if (gTopPendingIPCName) {
1417 0 : WriteAnnotation(apiData, "TopPendingIPCName", gTopPendingIPCName);
1418 : }
1419 0 : if (topPendingIPCTypeBuffer[2]) {
1420 0 : WriteAnnotation(apiData, "TopPendingIPCType", topPendingIPCTypeBuffer);
1421 : }
1422 : }
1423 :
1424 : #ifdef XP_WIN
1425 : const char* tlsAllocations = mozilla::GetTlsAllocationStacks();
1426 : if (tlsAllocations) {
1427 : WriteAnnotation(apiData, "TlsAllocations", tlsAllocations);
1428 : }
1429 : #endif
1430 :
1431 : std::function<void(const char*)> getThreadAnnotationCB =
1432 0 : [&] (const char * aAnnotation) -> void {
1433 0 : if (aAnnotation) {
1434 0 : WriteLiteral(apiData, "ThreadIdNameMapping=");
1435 0 : WriteString(apiData, aAnnotation);
1436 0 : WriteLiteral(apiData, "\n");
1437 : }
1438 0 : };
1439 0 : GetFlatThreadAnnotation(getThreadAnnotationCB);
1440 : }
1441 :
1442 : #ifdef XP_WIN
1443 : static void
1444 : ReserveBreakpadVM()
1445 : {
1446 : if (!gBreakpadReservedVM) {
1447 : gBreakpadReservedVM = VirtualAlloc(nullptr, kReserveSize, MEM_RESERVE,
1448 : PAGE_NOACCESS);
1449 : }
1450 : }
1451 :
1452 : static void
1453 : FreeBreakpadVM()
1454 : {
1455 : if (gBreakpadReservedVM) {
1456 : VirtualFree(gBreakpadReservedVM, 0, MEM_RELEASE);
1457 : }
1458 : }
1459 :
1460 : /**
1461 : * Filters out floating point exceptions which are handled by nsSigHandlers.cpp
1462 : * and should not be handled as crashes.
1463 : *
1464 : * Also calls FreeBreakpadVM if appropriate.
1465 : */
1466 : static bool FPEFilter(void* context, EXCEPTION_POINTERS* exinfo,
1467 : MDRawAssertionInfo* assertion)
1468 : {
1469 : if (!exinfo) {
1470 : mozilla::IOInterposer::Disable();
1471 : FreeBreakpadVM();
1472 : return true;
1473 : }
1474 :
1475 : PEXCEPTION_RECORD e = (PEXCEPTION_RECORD)exinfo->ExceptionRecord;
1476 : switch (e->ExceptionCode) {
1477 : case STATUS_FLOAT_DENORMAL_OPERAND:
1478 : case STATUS_FLOAT_DIVIDE_BY_ZERO:
1479 : case STATUS_FLOAT_INEXACT_RESULT:
1480 : case STATUS_FLOAT_INVALID_OPERATION:
1481 : case STATUS_FLOAT_OVERFLOW:
1482 : case STATUS_FLOAT_STACK_CHECK:
1483 : case STATUS_FLOAT_UNDERFLOW:
1484 : case STATUS_FLOAT_MULTIPLE_FAULTS:
1485 : case STATUS_FLOAT_MULTIPLE_TRAPS:
1486 : return false; // Don't write minidump, continue exception search
1487 : }
1488 : mozilla::IOInterposer::Disable();
1489 : FreeBreakpadVM();
1490 : return true;
1491 : }
1492 :
1493 : static bool
1494 : ChildFPEFilter(void* context, EXCEPTION_POINTERS* exinfo,
1495 : MDRawAssertionInfo* assertion)
1496 : {
1497 : bool result = FPEFilter(context, exinfo, assertion);
1498 : if (result) {
1499 : PrepareChildExceptionTimeAnnotations();
1500 : }
1501 : return result;
1502 : }
1503 :
1504 : MINIDUMP_TYPE GetMinidumpType()
1505 : {
1506 : MINIDUMP_TYPE minidump_type = MiniDumpWithFullMemoryInfo;
1507 :
1508 : #ifdef NIGHTLY_BUILD
1509 : // This is Nightly only because this doubles the size of minidumps based
1510 : // on the experimental data.
1511 : minidump_type = static_cast<MINIDUMP_TYPE>(minidump_type |
1512 : MiniDumpWithUnloadedModules |
1513 : MiniDumpWithProcessThreadData);
1514 : #endif
1515 :
1516 : const char* e = PR_GetEnv("MOZ_CRASHREPORTER_FULLDUMP");
1517 : if (e && *e) {
1518 : minidump_type = MiniDumpWithFullMemory;
1519 : }
1520 :
1521 : return minidump_type;
1522 : }
1523 :
1524 : #endif // XP_WIN
1525 :
1526 0 : static bool ShouldReport()
1527 : {
1528 : // this environment variable prevents us from launching
1529 : // the crash reporter client
1530 0 : const char *envvar = PR_GetEnv("MOZ_CRASHREPORTER_NO_REPORT");
1531 0 : if (envvar && *envvar) {
1532 0 : return false;
1533 : }
1534 :
1535 0 : envvar = PR_GetEnv("MOZ_CRASHREPORTER_FULLDUMP");
1536 0 : if (envvar && *envvar) {
1537 0 : return false;
1538 : }
1539 :
1540 0 : return true;
1541 : }
1542 :
1543 : static bool
1544 0 : Filter(void* context)
1545 : {
1546 0 : mozilla::IOInterposer::Disable();
1547 0 : return true;
1548 : }
1549 :
1550 : static bool
1551 0 : ChildFilter(void* context)
1552 : {
1553 0 : bool result = Filter(context);
1554 0 : if (result) {
1555 0 : PrepareChildExceptionTimeAnnotations();
1556 : }
1557 0 : return result;
1558 : }
1559 :
1560 0 : void TerminateHandler()
1561 : {
1562 0 : MOZ_CRASH("Unhandled exception");
1563 : }
1564 :
1565 : #if !defined(MOZ_WIDGET_ANDROID)
1566 :
1567 : // Locate the specified executable and store its path as a native string in
1568 : // the |aPathPtr| so we can later invoke it from within the exception handler.
1569 : static nsresult
1570 0 : LocateExecutable(nsIFile* aXREDirectory, const nsACString& aName,
1571 : nsAString& aPath)
1572 : {
1573 0 : nsCOMPtr<nsIFile> exePath;
1574 0 : nsresult rv = aXREDirectory->Clone(getter_AddRefs(exePath));
1575 0 : NS_ENSURE_SUCCESS(rv, rv);
1576 :
1577 : #ifdef XP_MACOSX
1578 : exePath->SetNativeLeafName(NS_LITERAL_CSTRING("MacOS"));
1579 : exePath->Append(NS_LITERAL_STRING("crashreporter.app"));
1580 : exePath->Append(NS_LITERAL_STRING("Contents"));
1581 : exePath->Append(NS_LITERAL_STRING("MacOS"));
1582 : #endif
1583 :
1584 0 : exePath->AppendNative(aName);
1585 0 : exePath->GetPath(aPath);
1586 0 : return NS_OK;
1587 : }
1588 :
1589 : #endif // !defined(MOZ_WIDGET_ANDROID)
1590 :
1591 1 : nsresult SetExceptionHandler(nsIFile* aXREDirectory,
1592 : bool force/*=false*/)
1593 : {
1594 1 : if (gExceptionHandler)
1595 0 : return NS_ERROR_ALREADY_INITIALIZED;
1596 :
1597 1 : install_rust_panic_hook();
1598 :
1599 : #if !defined(DEBUG) || defined(MOZ_WIDGET_GONK)
1600 : // In non-debug builds, enable the crash reporter by default, and allow
1601 : // disabling it with the MOZ_CRASHREPORTER_DISABLE environment variable.
1602 : // Also enable it by default in debug gonk builds as it is difficult to
1603 : // set environment on startup.
1604 : const char *envvar = PR_GetEnv("MOZ_CRASHREPORTER_DISABLE");
1605 : if (envvar && *envvar && !force)
1606 : return NS_OK;
1607 : #else
1608 : // In debug builds, disable the crash reporter by default, and allow to
1609 : // enable it with the MOZ_CRASHREPORTER environment variable.
1610 1 : const char *envvar = PR_GetEnv("MOZ_CRASHREPORTER");
1611 1 : if ((!envvar || !*envvar) && !force)
1612 1 : return NS_OK;
1613 : #endif
1614 :
1615 : #if defined(MOZ_WIDGET_GONK)
1616 : doReport = false;
1617 : headlessClient = true;
1618 : #elif defined(XP_WIN)
1619 : doReport = ShouldReport();
1620 : #else
1621 : // this environment variable prevents us from launching
1622 : // the crash reporter client
1623 0 : doReport = ShouldReport();
1624 : #endif
1625 :
1626 : // allocate our strings
1627 0 : crashReporterAPIData = new nsCString();
1628 0 : crashEventAPIData = new nsCString();
1629 :
1630 0 : NS_ASSERTION(!crashReporterAPILock, "Shouldn't have a lock yet");
1631 0 : crashReporterAPILock = new Mutex("crashReporterAPILock");
1632 0 : NS_ASSERTION(!notesFieldLock, "Shouldn't have a lock yet");
1633 0 : notesFieldLock = new Mutex("notesFieldLock");
1634 :
1635 0 : crashReporterAPIData_Hash =
1636 0 : new nsDataHashtable<nsCStringHashKey,nsCString>();
1637 0 : NS_ENSURE_TRUE(crashReporterAPIData_Hash, NS_ERROR_OUT_OF_MEMORY);
1638 :
1639 0 : notesField = new nsCString();
1640 0 : NS_ENSURE_TRUE(notesField, NS_ERROR_OUT_OF_MEMORY);
1641 :
1642 0 : if (!headlessClient) {
1643 : #if !defined(MOZ_WIDGET_ANDROID)
1644 : // Locate the crash reporter executable
1645 0 : nsAutoString crashReporterPath_temp;
1646 0 : nsresult rv = LocateExecutable(aXREDirectory,
1647 0 : NS_LITERAL_CSTRING(CRASH_REPORTER_FILENAME),
1648 0 : crashReporterPath_temp);
1649 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
1650 0 : return rv;
1651 : }
1652 :
1653 : #ifdef XP_MACOSX
1654 : nsCOMPtr<nsIFile> libPath;
1655 : rv = aXREDirectory->Clone(getter_AddRefs(libPath));
1656 : if (NS_WARN_IF(NS_FAILED(rv))) {
1657 : return rv;
1658 : }
1659 :
1660 : nsAutoString libraryPath_temp;
1661 : rv = libPath->GetPath(libraryPath_temp);
1662 : if (NS_WARN_IF(NS_FAILED(rv))) {
1663 : return rv;
1664 : }
1665 : #endif // XP_MACOSX
1666 :
1667 : #ifdef XP_WIN32
1668 : crashReporterPath =
1669 : reinterpret_cast<wchar_t*>(ToNewUnicode(crashReporterPath_temp));
1670 : #else
1671 0 : crashReporterPath = ToNewCString(crashReporterPath_temp);
1672 : #ifdef XP_MACOSX
1673 : libraryPath = ToNewCString(libraryPath_temp);
1674 : #endif
1675 : #endif // XP_WIN32
1676 : #else
1677 : // On Android, we launch using the application package name instead of a
1678 : // filename, so use the dynamically set MOZ_ANDROID_PACKAGE_NAME, or fall
1679 : // back to the static ANDROID_PACKAGE_NAME.
1680 : const char* androidPackageName = PR_GetEnv("MOZ_ANDROID_PACKAGE_NAME");
1681 : if (androidPackageName != nullptr) {
1682 : nsCString package(androidPackageName);
1683 : package.Append("/org.mozilla.gecko.CrashReporter");
1684 : crashReporterPath = ToNewCString(package);
1685 : } else {
1686 : nsCString package(ANDROID_PACKAGE_NAME "/org.mozilla.gecko.CrashReporter");
1687 : crashReporterPath = ToNewCString(package);
1688 : }
1689 : #endif // !defined(MOZ_WIDGET_ANDROID)
1690 : }
1691 :
1692 : // get temp path to use for minidump path
1693 : #if defined(XP_WIN32)
1694 : nsString tempPath;
1695 : #else
1696 0 : nsCString tempPath;
1697 : #endif
1698 0 : if (!BuildTempPath(tempPath)) {
1699 0 : return NS_ERROR_FAILURE;
1700 : }
1701 :
1702 : #ifdef XP_WIN32
1703 : ReserveBreakpadVM();
1704 : #endif // XP_WIN32
1705 :
1706 : #ifdef MOZ_WIDGET_ANDROID
1707 : androidUserSerial = getenv("MOZ_ANDROID_USER_SERIAL_NUMBER");
1708 : #endif
1709 :
1710 : // Initialize the flag and mutex used to avoid dump processing
1711 : // once browser termination has begun.
1712 0 : NS_ASSERTION(!dumpSafetyLock, "Shouldn't have a lock yet");
1713 : // Do not deallocate this lock while it is still possible for
1714 : // isSafeToDump to be tested on another thread.
1715 0 : dumpSafetyLock = new Mutex("dumpSafetyLock");
1716 0 : MutexAutoLock lock(*dumpSafetyLock);
1717 0 : isSafeToDump = true;
1718 :
1719 : // now set the exception handler
1720 : #ifdef XP_LINUX
1721 0 : MinidumpDescriptor descriptor(tempPath.get());
1722 : #endif
1723 :
1724 : #ifdef XP_WIN
1725 : previousUnhandledExceptionFilter = GetUnhandledExceptionFilter();
1726 : #endif
1727 :
1728 0 : gExceptionHandler = new google_breakpad::
1729 : ExceptionHandler(
1730 : #ifdef XP_LINUX
1731 : descriptor,
1732 : #elif defined(XP_WIN)
1733 : std::wstring(tempPath.get()),
1734 : #else
1735 : tempPath.get(),
1736 : #endif
1737 :
1738 : #ifdef XP_WIN
1739 : FPEFilter,
1740 : #else
1741 : Filter,
1742 : #endif
1743 : MinidumpCallback,
1744 : nullptr,
1745 : #ifdef XP_WIN32
1746 : google_breakpad::ExceptionHandler::HANDLER_ALL,
1747 : GetMinidumpType(),
1748 : (const wchar_t*) nullptr,
1749 : nullptr);
1750 : #else
1751 : true
1752 : #ifdef XP_MACOSX
1753 : , nullptr
1754 : #endif
1755 : #ifdef XP_LINUX
1756 : , -1
1757 : #endif
1758 0 : );
1759 : #endif // XP_WIN32
1760 :
1761 0 : if (!gExceptionHandler)
1762 0 : return NS_ERROR_OUT_OF_MEMORY;
1763 :
1764 : #ifdef XP_WIN
1765 : gExceptionHandler->set_handle_debug_exceptions(true);
1766 :
1767 : // Initially set sIncludeContextHeap to true for debugging startup crashes
1768 : // even if the controlling pref value is false.
1769 : SetIncludeContextHeap(true);
1770 : #ifdef _WIN64
1771 : // Tell JS about the new filter before we disable SetUnhandledExceptionFilter
1772 : SetJitExceptionHandler();
1773 : #endif
1774 :
1775 : // protect the crash reporter from being unloaded
1776 : gBlockUnhandledExceptionFilter = true;
1777 : gKernel32Intercept.Init("kernel32.dll");
1778 : bool ok = gKernel32Intercept.AddHook("SetUnhandledExceptionFilter",
1779 : reinterpret_cast<intptr_t>(patched_SetUnhandledExceptionFilter),
1780 : (void**) &stub_SetUnhandledExceptionFilter);
1781 :
1782 : #ifdef DEBUG
1783 : if (!ok)
1784 : printf_stderr ("SetUnhandledExceptionFilter hook failed; crash reporter is vulnerable.\n");
1785 : #endif
1786 : #endif
1787 :
1788 : // store application start time
1789 : char timeString[32];
1790 0 : time_t startupTime = time(nullptr);
1791 0 : XP_TTOA(startupTime, timeString, 10);
1792 0 : AnnotateCrashReport(NS_LITERAL_CSTRING("StartupTime"),
1793 0 : nsDependentCString(timeString));
1794 :
1795 : #if defined(XP_MACOSX)
1796 : // On OS X, many testers like to see the OS crash reporting dialog
1797 : // since it offers immediate stack traces. We allow them to set
1798 : // a default to pass exceptions to the OS handler.
1799 : Boolean keyExistsAndHasValidFormat = false;
1800 : Boolean prefValue = ::CFPreferencesGetAppBooleanValue(CFSTR("OSCrashReporter"),
1801 : kCFPreferencesCurrentApplication,
1802 : &keyExistsAndHasValidFormat);
1803 : if (keyExistsAndHasValidFormat)
1804 : showOSCrashReporter = prefValue;
1805 : #endif
1806 :
1807 : #if defined(MOZ_WIDGET_ANDROID)
1808 : for (unsigned int i = 0; i < library_mappings.size(); i++) {
1809 : PageAllocator allocator;
1810 : auto_wasteful_vector<uint8_t, sizeof(MDGUID)> guid(&allocator);
1811 : FileID::ElfFileIdentifierFromMappedFile(
1812 : (void const *)library_mappings[i].start_address, guid);
1813 : gExceptionHandler->AddMappingInfo(library_mappings[i].name,
1814 : guid.data(),
1815 : library_mappings[i].start_address,
1816 : library_mappings[i].length,
1817 : library_mappings[i].file_offset);
1818 : }
1819 : #endif
1820 :
1821 0 : mozalloc_set_oom_abort_handler(AnnotateOOMAllocationSize);
1822 :
1823 0 : oldTerminateHandler = std::set_terminate(&TerminateHandler);
1824 :
1825 0 : InitThreadAnnotation();
1826 :
1827 0 : return NS_OK;
1828 : }
1829 :
1830 68 : bool GetEnabled()
1831 : {
1832 68 : return gExceptionHandler != nullptr;
1833 : }
1834 :
1835 0 : bool GetMinidumpPath(nsAString& aPath)
1836 : {
1837 0 : if (!gExceptionHandler)
1838 0 : return false;
1839 :
1840 : #ifndef XP_LINUX
1841 : aPath = CONVERT_XP_CHAR_TO_UTF16(gExceptionHandler->dump_path().c_str());
1842 : #else
1843 0 : aPath = CONVERT_XP_CHAR_TO_UTF16(
1844 0 : gExceptionHandler->minidump_descriptor().directory().c_str());
1845 : #endif
1846 0 : return true;
1847 : }
1848 :
1849 1 : nsresult SetMinidumpPath(const nsAString& aPath)
1850 : {
1851 1 : if (!gExceptionHandler)
1852 1 : return NS_ERROR_NOT_INITIALIZED;
1853 :
1854 : #ifdef XP_WIN32
1855 : gExceptionHandler->set_dump_path(std::wstring(char16ptr_t(aPath.BeginReading())));
1856 : #elif defined(XP_LINUX)
1857 0 : gExceptionHandler->set_minidump_descriptor(
1858 0 : MinidumpDescriptor(NS_ConvertUTF16toUTF8(aPath).BeginReading()));
1859 : #else
1860 : gExceptionHandler->set_dump_path(NS_ConvertUTF16toUTF8(aPath).BeginReading());
1861 : #endif
1862 0 : return NS_OK;
1863 : }
1864 :
1865 : static nsresult
1866 0 : WriteDataToFile(nsIFile* aFile, const nsACString& data)
1867 : {
1868 : PRFileDesc* fd;
1869 0 : nsresult rv = aFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE, 00600, &fd);
1870 0 : NS_ENSURE_SUCCESS(rv, rv);
1871 :
1872 0 : rv = NS_OK;
1873 0 : if (PR_Write(fd, data.Data(), data.Length()) == -1) {
1874 0 : rv = NS_ERROR_FAILURE;
1875 : }
1876 0 : PR_Close(fd);
1877 0 : return rv;
1878 : }
1879 :
1880 : static nsresult
1881 2 : GetFileContents(nsIFile* aFile, nsACString& data)
1882 : {
1883 : PRFileDesc* fd;
1884 2 : nsresult rv = aFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
1885 2 : NS_ENSURE_SUCCESS(rv, rv);
1886 :
1887 2 : rv = NS_OK;
1888 2 : int32_t filesize = PR_Available(fd);
1889 2 : if (filesize <= 0) {
1890 0 : rv = NS_ERROR_FILE_NOT_FOUND;
1891 : }
1892 : else {
1893 2 : data.SetLength(filesize);
1894 2 : if (PR_Read(fd, data.BeginWriting(), filesize) == -1) {
1895 0 : rv = NS_ERROR_FAILURE;
1896 : }
1897 : }
1898 2 : PR_Close(fd);
1899 2 : return rv;
1900 : }
1901 :
1902 : // Function typedef for initializing a piece of data that we
1903 : // don't already have.
1904 : typedef nsresult (*InitDataFunc)(nsACString&);
1905 :
1906 : // Attempt to read aFile's contents into aContents, if aFile
1907 : // does not exist, create it and initialize its contents
1908 : // by calling aInitFunc for the data.
1909 : static nsresult
1910 2 : GetOrInit(nsIFile* aDir, const nsACString& filename,
1911 : nsACString& aContents, InitDataFunc aInitFunc)
1912 : {
1913 : bool exists;
1914 :
1915 4 : nsCOMPtr<nsIFile> dataFile;
1916 2 : nsresult rv = aDir->Clone(getter_AddRefs(dataFile));
1917 2 : NS_ENSURE_SUCCESS(rv, rv);
1918 :
1919 2 : rv = dataFile->AppendNative(filename);
1920 2 : NS_ENSURE_SUCCESS(rv, rv);
1921 :
1922 2 : rv = dataFile->Exists(&exists);
1923 2 : NS_ENSURE_SUCCESS(rv, rv);
1924 :
1925 2 : if (!exists) {
1926 0 : if (aInitFunc) {
1927 : // get the initial value and write it to the file
1928 0 : rv = aInitFunc(aContents);
1929 0 : NS_ENSURE_SUCCESS(rv, rv);
1930 0 : rv = WriteDataToFile(dataFile, aContents);
1931 : }
1932 : else {
1933 : // didn't pass in an init func
1934 0 : rv = NS_ERROR_FAILURE;
1935 : }
1936 : }
1937 : else {
1938 : // just get the file's contents
1939 2 : rv = GetFileContents(dataFile, aContents);
1940 : }
1941 :
1942 2 : return rv;
1943 : }
1944 :
1945 : // Init the "install time" data. We're taking an easy way out here
1946 : // and just setting this to "the time when this version was first run".
1947 : static nsresult
1948 0 : InitInstallTime(nsACString& aInstallTime)
1949 : {
1950 0 : time_t t = time(nullptr);
1951 : char buf[16];
1952 0 : SprintfLiteral(buf, "%ld", t);
1953 0 : aInstallTime = buf;
1954 :
1955 0 : return NS_OK;
1956 : }
1957 :
1958 : // Ensure a directory exists and create it if missing.
1959 : static nsresult
1960 6 : EnsureDirectoryExists(nsIFile* dir)
1961 : {
1962 6 : nsresult rv = dir->Create(nsIFile::DIRECTORY_TYPE, 0700);
1963 :
1964 6 : if (NS_WARN_IF(NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS)) {
1965 0 : return rv;
1966 : }
1967 :
1968 6 : return NS_OK;
1969 : }
1970 :
1971 : // Creates a directory that will be accessible by the crash reporter. The
1972 : // directory will live under Firefox default data directory and will use the
1973 : // specified name. The directory path will be passed to the crashreporter via
1974 : // the specified environment variable.
1975 : static nsresult
1976 2 : SetupCrashReporterDirectory(nsIFile* aAppDataDirectory,
1977 : const char* aDirName,
1978 : const XP_CHAR* aEnvVarName,
1979 : nsIFile** aDirectory = nullptr)
1980 : {
1981 4 : nsCOMPtr<nsIFile> directory;
1982 2 : nsresult rv = aAppDataDirectory->Clone(getter_AddRefs(directory));
1983 2 : NS_ENSURE_SUCCESS(rv, rv);
1984 :
1985 2 : rv = directory->AppendNative(nsDependentCString(aDirName));
1986 2 : NS_ENSURE_SUCCESS(rv, rv);
1987 :
1988 2 : EnsureDirectoryExists(directory);
1989 :
1990 4 : xpstring dirEnv(aEnvVarName);
1991 2 : dirEnv.append(XP_TEXT("="));
1992 :
1993 2 : xpstring* directoryPath = CreatePathFromFile(directory);
1994 :
1995 2 : if (!directoryPath) {
1996 0 : return NS_ERROR_FAILURE;
1997 : }
1998 :
1999 2 : dirEnv.append(*directoryPath);
2000 2 : delete directoryPath;
2001 :
2002 : #if defined(XP_WIN32)
2003 : _wputenv(dirEnv.c_str());
2004 : #else
2005 4 : XP_CHAR* str = new XP_CHAR[dirEnv.size() + 1];
2006 2 : strncpy(str, dirEnv.c_str(), dirEnv.size() + 1);
2007 : // |PR_SetEnv| requires str to leak.
2008 2 : PR_SetEnv(str);
2009 : #endif
2010 :
2011 2 : if (aDirectory) {
2012 1 : directory.forget(aDirectory);
2013 : }
2014 :
2015 2 : return NS_OK;
2016 : }
2017 :
2018 : // Annotate the crash report with a Unique User ID and time
2019 : // since install. Also do some prep work for recording
2020 : // time since last crash, which must be calculated at
2021 : // crash time.
2022 : // If any piece of data doesn't exist, initialize it first.
2023 1 : nsresult SetupExtraData(nsIFile* aAppDataDirectory,
2024 : const nsACString& aBuildID)
2025 : {
2026 2 : nsCOMPtr<nsIFile> dataDirectory;
2027 1 : nsresult rv = SetupCrashReporterDirectory(
2028 : aAppDataDirectory,
2029 : "Crash Reports",
2030 : XP_TEXT("MOZ_CRASHREPORTER_DATA_DIRECTORY"),
2031 2 : getter_AddRefs(dataDirectory)
2032 1 : );
2033 :
2034 1 : if (NS_WARN_IF(NS_FAILED(rv))) {
2035 0 : return rv;
2036 : }
2037 :
2038 : rv = SetupCrashReporterDirectory(
2039 : aAppDataDirectory,
2040 : "Pending Pings",
2041 : XP_TEXT("MOZ_CRASHREPORTER_PING_DIRECTORY")
2042 1 : );
2043 :
2044 1 : if (NS_WARN_IF(NS_FAILED(rv))) {
2045 0 : return rv;
2046 : }
2047 :
2048 2 : nsAutoCString data;
2049 1 : if(NS_SUCCEEDED(GetOrInit(dataDirectory,
2050 : NS_LITERAL_CSTRING("InstallTime") + aBuildID,
2051 : data, InitInstallTime)))
2052 1 : AnnotateCrashReport(NS_LITERAL_CSTRING("InstallTime"), data);
2053 :
2054 : // this is a little different, since we can't init it with anything,
2055 : // since it's stored at crash time, and we can't annotate the
2056 : // crash report with the stored value, since we really want
2057 : // (now - LastCrash), so we just get a value if it exists,
2058 : // and store it in a time_t value.
2059 1 : if(NS_SUCCEEDED(GetOrInit(dataDirectory, NS_LITERAL_CSTRING("LastCrash"),
2060 : data, nullptr))) {
2061 1 : lastCrashTime = (time_t)atol(data.get());
2062 : }
2063 :
2064 : // not really the best place to init this, but I have the path I need here
2065 2 : nsCOMPtr<nsIFile> lastCrashFile;
2066 1 : rv = dataDirectory->Clone(getter_AddRefs(lastCrashFile));
2067 1 : NS_ENSURE_SUCCESS(rv, rv);
2068 :
2069 1 : rv = lastCrashFile->AppendNative(NS_LITERAL_CSTRING("LastCrash"));
2070 1 : NS_ENSURE_SUCCESS(rv, rv);
2071 1 : memset(lastCrashTimeFilename, 0, sizeof(lastCrashTimeFilename));
2072 :
2073 : #if defined(XP_WIN32)
2074 : nsAutoString filename;
2075 : rv = lastCrashFile->GetPath(filename);
2076 : NS_ENSURE_SUCCESS(rv, rv);
2077 :
2078 : if (filename.Length() < XP_PATH_MAX)
2079 : wcsncpy(lastCrashTimeFilename, filename.get(), filename.Length());
2080 : #else
2081 2 : nsAutoCString filename;
2082 1 : rv = lastCrashFile->GetNativePath(filename);
2083 1 : NS_ENSURE_SUCCESS(rv, rv);
2084 :
2085 1 : if (filename.Length() < XP_PATH_MAX)
2086 1 : strncpy(lastCrashTimeFilename, filename.get(), filename.Length());
2087 : #endif
2088 :
2089 1 : if (headlessClient) {
2090 0 : nsCOMPtr<nsIFile> markerFile;
2091 0 : rv = dataDirectory->Clone(getter_AddRefs(markerFile));
2092 0 : NS_ENSURE_SUCCESS(rv, rv);
2093 :
2094 0 : rv = markerFile->AppendNative(NS_LITERAL_CSTRING("LastCrashFilename"));
2095 0 : NS_ENSURE_SUCCESS(rv, rv);
2096 0 : memset(crashMarkerFilename, 0, sizeof(crashMarkerFilename));
2097 :
2098 : #if defined(XP_WIN32)
2099 : nsAutoString markerFilename;
2100 : rv = markerFile->GetPath(markerFilename);
2101 : NS_ENSURE_SUCCESS(rv, rv);
2102 :
2103 : if (markerFilename.Length() < XP_PATH_MAX)
2104 : wcsncpy(crashMarkerFilename, markerFilename.get(),
2105 : markerFilename.Length());
2106 : #else
2107 0 : nsAutoCString markerFilename;
2108 0 : rv = markerFile->GetNativePath(markerFilename);
2109 0 : NS_ENSURE_SUCCESS(rv, rv);
2110 :
2111 0 : if (markerFilename.Length() < XP_PATH_MAX)
2112 0 : strncpy(crashMarkerFilename, markerFilename.get(),
2113 0 : markerFilename.Length());
2114 : #endif
2115 : }
2116 :
2117 1 : return NS_OK;
2118 : }
2119 :
2120 : static void OOPDeinit();
2121 :
2122 0 : nsresult UnsetExceptionHandler()
2123 : {
2124 0 : if (isSafeToDump) {
2125 0 : MutexAutoLock lock(*dumpSafetyLock);
2126 0 : isSafeToDump = false;
2127 : }
2128 :
2129 : #ifdef XP_WIN
2130 : // allow SetUnhandledExceptionFilter
2131 : gBlockUnhandledExceptionFilter = false;
2132 : #endif
2133 :
2134 0 : delete gExceptionHandler;
2135 :
2136 : // do this here in the unlikely case that we succeeded in allocating
2137 : // our strings but failed to allocate gExceptionHandler.
2138 0 : delete crashReporterAPIData_Hash;
2139 0 : crashReporterAPIData_Hash = nullptr;
2140 :
2141 0 : delete crashReporterAPILock;
2142 0 : crashReporterAPILock = nullptr;
2143 :
2144 0 : delete notesFieldLock;
2145 0 : notesFieldLock = nullptr;
2146 :
2147 0 : delete crashReporterAPIData;
2148 0 : crashReporterAPIData = nullptr;
2149 :
2150 0 : delete crashEventAPIData;
2151 0 : crashEventAPIData = nullptr;
2152 :
2153 0 : delete notesField;
2154 0 : notesField = nullptr;
2155 :
2156 0 : delete lastRunCrashID;
2157 0 : lastRunCrashID = nullptr;
2158 :
2159 0 : if (pendingDirectory) {
2160 0 : free(pendingDirectory);
2161 0 : pendingDirectory = nullptr;
2162 : }
2163 :
2164 0 : if (crashReporterPath) {
2165 0 : free(crashReporterPath);
2166 0 : crashReporterPath = nullptr;
2167 : }
2168 :
2169 : #ifdef XP_MACOSX
2170 : if (libraryPath) {
2171 : free(libraryPath);
2172 : libraryPath = nullptr;
2173 : }
2174 : #endif // XP_MACOSX
2175 :
2176 0 : if (eventsDirectory) {
2177 0 : free(eventsDirectory);
2178 0 : eventsDirectory = nullptr;
2179 : }
2180 :
2181 0 : if (currentSessionId) {
2182 0 : free(currentSessionId);
2183 0 : currentSessionId = nullptr;
2184 : }
2185 :
2186 0 : if (memoryReportPath) {
2187 0 : free(memoryReportPath);
2188 0 : memoryReportPath = nullptr;
2189 : }
2190 :
2191 0 : ShutdownThreadAnnotation();
2192 :
2193 0 : if (!gExceptionHandler)
2194 0 : return NS_ERROR_NOT_INITIALIZED;
2195 :
2196 0 : gExceptionHandler = nullptr;
2197 :
2198 0 : OOPDeinit();
2199 :
2200 0 : delete dumpSafetyLock;
2201 0 : dumpSafetyLock = nullptr;
2202 :
2203 0 : std::set_terminate(oldTerminateHandler);
2204 :
2205 0 : return NS_OK;
2206 : }
2207 :
2208 0 : static void ReplaceChar(nsCString& str, const nsACString& character,
2209 : const nsACString& replacement)
2210 : {
2211 0 : nsCString::const_iterator iter, end;
2212 :
2213 0 : str.BeginReading(iter);
2214 0 : str.EndReading(end);
2215 :
2216 0 : while (FindInReadable(character, iter, end)) {
2217 0 : nsCString::const_iterator start;
2218 0 : str.BeginReading(start);
2219 0 : int32_t pos = end - start;
2220 0 : str.Replace(pos - 1, 1, replacement);
2221 :
2222 0 : str.BeginReading(iter);
2223 0 : iter.advance(pos + replacement.Length() - 1);
2224 0 : str.EndReading(end);
2225 : }
2226 0 : }
2227 :
2228 : // This function is miscompiled with MSVC 2005/2008 when PGO is on.
2229 : #ifdef _MSC_VER
2230 : #pragma optimize("", off)
2231 : #endif
2232 : static nsresult
2233 0 : EscapeAnnotation(const nsACString& key, const nsACString& data, nsCString& escapedData)
2234 : {
2235 0 : if (FindInReadable(NS_LITERAL_CSTRING("="), key) ||
2236 0 : FindInReadable(NS_LITERAL_CSTRING("\n"), key))
2237 0 : return NS_ERROR_INVALID_ARG;
2238 :
2239 0 : if (FindInReadable(NS_LITERAL_CSTRING("\0"), data))
2240 0 : return NS_ERROR_INVALID_ARG;
2241 :
2242 0 : escapedData = data;
2243 :
2244 : // escape backslashes
2245 0 : ReplaceChar(escapedData, NS_LITERAL_CSTRING("\\"),
2246 0 : NS_LITERAL_CSTRING("\\\\"));
2247 : // escape newlines
2248 0 : ReplaceChar(escapedData, NS_LITERAL_CSTRING("\n"),
2249 0 : NS_LITERAL_CSTRING("\\n"));
2250 0 : return NS_OK;
2251 : }
2252 : #ifdef _MSC_VER
2253 : #pragma optimize("", on)
2254 : #endif
2255 :
2256 0 : class DelayedNote
2257 : {
2258 : public:
2259 0 : DelayedNote(const nsACString& aKey, const nsACString& aData)
2260 0 : : mKey(aKey), mData(aData), mType(Annotation) {}
2261 :
2262 0 : explicit DelayedNote(const nsACString& aData)
2263 0 : : mData(aData), mType(AppNote) {}
2264 :
2265 0 : void Run()
2266 : {
2267 0 : if (mType == Annotation) {
2268 0 : AnnotateCrashReport(mKey, mData);
2269 : } else {
2270 0 : AppendAppNotesToCrashReport(mData);
2271 : }
2272 0 : }
2273 :
2274 : private:
2275 : nsCString mKey;
2276 : nsCString mData;
2277 : enum AnnotationType { Annotation, AppNote } mType;
2278 : };
2279 :
2280 : static void
2281 0 : EnqueueDelayedNote(DelayedNote* aNote)
2282 : {
2283 0 : if (!gDelayedAnnotations) {
2284 0 : gDelayedAnnotations = new nsTArray<nsAutoPtr<DelayedNote> >();
2285 : }
2286 0 : gDelayedAnnotations->AppendElement(aNote);
2287 0 : }
2288 :
2289 : static void
2290 0 : RunAndCleanUpDelayedNotes()
2291 : {
2292 0 : if (gDelayedAnnotations) {
2293 0 : for (nsAutoPtr<DelayedNote>& note : *gDelayedAnnotations) {
2294 0 : note->Run();
2295 : }
2296 0 : delete gDelayedAnnotations;
2297 0 : gDelayedAnnotations = nullptr;
2298 : }
2299 0 : }
2300 :
2301 42 : nsresult AnnotateCrashReport(const nsACString& key, const nsACString& data)
2302 : {
2303 42 : if (!GetEnabled())
2304 42 : return NS_ERROR_NOT_INITIALIZED;
2305 :
2306 0 : nsCString escapedData;
2307 0 : nsresult rv = EscapeAnnotation(key, data, escapedData);
2308 0 : if (NS_FAILED(rv))
2309 0 : return rv;
2310 :
2311 0 : if (!XRE_IsParentProcess()) {
2312 : // The newer CrashReporterClient can be used from any thread.
2313 0 : if (RefPtr<CrashReporterClient> client = CrashReporterClient::GetSingleton()) {
2314 0 : client->AnnotateCrashReport(nsCString(key), escapedData);
2315 0 : return NS_OK;
2316 : }
2317 :
2318 : // EnqueueDelayedNote() can only be called on the main thread.
2319 0 : MOZ_RELEASE_ASSERT(NS_IsMainThread());
2320 :
2321 0 : EnqueueDelayedNote(new DelayedNote(key, data));
2322 0 : return NS_OK;
2323 : }
2324 :
2325 0 : MutexAutoLock lock(*crashReporterAPILock);
2326 :
2327 0 : crashReporterAPIData_Hash->Put(key, escapedData);
2328 :
2329 : // now rebuild the file contents
2330 0 : crashReporterAPIData->Truncate(0);
2331 0 : crashEventAPIData->Truncate(0);
2332 0 : for (auto it = crashReporterAPIData_Hash->Iter(); !it.Done(); it.Next()) {
2333 0 : const nsACString& key = it.Key();
2334 0 : nsCString entry = it.Data();
2335 0 : if (!entry.IsEmpty()) {
2336 0 : NS_NAMED_LITERAL_CSTRING(kEquals, "=");
2337 0 : NS_NAMED_LITERAL_CSTRING(kNewline, "\n");
2338 0 : nsAutoCString line = key + kEquals + entry + kNewline;
2339 :
2340 0 : crashReporterAPIData->Append(line);
2341 0 : crashEventAPIData->Append(line);
2342 : }
2343 : }
2344 :
2345 0 : return NS_OK;
2346 : }
2347 :
2348 0 : nsresult RemoveCrashReportAnnotation(const nsACString& key)
2349 : {
2350 0 : return AnnotateCrashReport(key, NS_LITERAL_CSTRING(""));
2351 : }
2352 :
2353 7 : nsresult SetGarbageCollecting(bool collecting)
2354 : {
2355 7 : if (!GetEnabled())
2356 7 : return NS_ERROR_NOT_INITIALIZED;
2357 :
2358 0 : isGarbageCollecting = collecting;
2359 :
2360 0 : return NS_OK;
2361 : }
2362 :
2363 2628 : void SetEventloopNestingLevel(uint32_t level)
2364 : {
2365 2628 : eventloopNestingLevel = level;
2366 2628 : }
2367 :
2368 11 : nsresult AppendAppNotesToCrashReport(const nsACString& data)
2369 : {
2370 11 : if (!GetEnabled())
2371 11 : return NS_ERROR_NOT_INITIALIZED;
2372 :
2373 0 : if (FindInReadable(NS_LITERAL_CSTRING("\0"), data))
2374 0 : return NS_ERROR_INVALID_ARG;
2375 :
2376 0 : if (!XRE_IsParentProcess()) {
2377 : // Since we don't go through AnnotateCrashReport in the parent process,
2378 : // we must ensure that the data is escaped and valid before the parent
2379 : // sees it.
2380 0 : nsCString escapedData;
2381 0 : nsresult rv = EscapeAnnotation(NS_LITERAL_CSTRING("Notes"), data, escapedData);
2382 0 : if (NS_FAILED(rv))
2383 0 : return rv;
2384 :
2385 0 : if (RefPtr<CrashReporterClient> client = CrashReporterClient::GetSingleton()) {
2386 0 : client->AppendAppNotes(escapedData);
2387 0 : return NS_OK;
2388 : }
2389 :
2390 : // EnqueueDelayedNote can only be called on the main thread.
2391 0 : MOZ_RELEASE_ASSERT(NS_IsMainThread());
2392 :
2393 0 : EnqueueDelayedNote(new DelayedNote(data));
2394 0 : return NS_OK;
2395 : }
2396 :
2397 0 : MutexAutoLock lock(*notesFieldLock);
2398 :
2399 0 : notesField->Append(data);
2400 0 : return AnnotateCrashReport(NS_LITERAL_CSTRING("Notes"), *notesField);
2401 : }
2402 :
2403 : // Returns true if found, false if not found.
2404 0 : bool GetAnnotation(const nsACString& key, nsACString& data)
2405 : {
2406 0 : if (!gExceptionHandler)
2407 0 : return false;
2408 :
2409 0 : nsAutoCString entry;
2410 0 : if (!crashReporterAPIData_Hash->Get(key, &entry))
2411 0 : return false;
2412 :
2413 0 : data = entry;
2414 0 : return true;
2415 : }
2416 :
2417 0 : nsresult RegisterAppMemory(void* ptr, size_t length)
2418 : {
2419 0 : if (!GetEnabled())
2420 0 : return NS_ERROR_NOT_INITIALIZED;
2421 :
2422 : #if defined(XP_LINUX) || defined(XP_WIN32)
2423 0 : gExceptionHandler->RegisterAppMemory(ptr, length);
2424 0 : return NS_OK;
2425 : #else
2426 : return NS_ERROR_NOT_IMPLEMENTED;
2427 : #endif
2428 : }
2429 :
2430 0 : nsresult UnregisterAppMemory(void* ptr)
2431 : {
2432 0 : if (!GetEnabled())
2433 0 : return NS_ERROR_NOT_INITIALIZED;
2434 :
2435 : #if defined(XP_LINUX) || defined(XP_WIN32)
2436 0 : gExceptionHandler->UnregisterAppMemory(ptr);
2437 0 : return NS_OK;
2438 : #else
2439 : return NS_ERROR_NOT_IMPLEMENTED;
2440 : #endif
2441 : }
2442 :
2443 1 : void SetIncludeContextHeap(bool aValue)
2444 : {
2445 1 : sIncludeContextHeap = aValue;
2446 :
2447 : #ifdef XP_WIN
2448 : if (gExceptionHandler) {
2449 : gExceptionHandler->set_include_context_heap(sIncludeContextHeap);
2450 : }
2451 : #endif
2452 1 : }
2453 :
2454 0 : bool GetServerURL(nsACString& aServerURL)
2455 : {
2456 0 : if (!gExceptionHandler)
2457 0 : return false;
2458 :
2459 0 : return GetAnnotation(NS_LITERAL_CSTRING("ServerURL"), aServerURL);
2460 : }
2461 :
2462 1 : nsresult SetServerURL(const nsACString& aServerURL)
2463 : {
2464 : // store server URL with the API data
2465 : // the client knows to handle this specially
2466 3 : return AnnotateCrashReport(NS_LITERAL_CSTRING("ServerURL"),
2467 3 : aServerURL);
2468 : }
2469 :
2470 : nsresult
2471 1 : SetRestartArgs(int argc, char** argv)
2472 : {
2473 1 : if (!gExceptionHandler)
2474 1 : return NS_OK;
2475 :
2476 : int i;
2477 0 : nsAutoCString envVar;
2478 : char *env;
2479 0 : char *argv0 = getenv("MOZ_APP_LAUNCHER");
2480 0 : for (i = 0; i < argc; i++) {
2481 0 : envVar = "MOZ_CRASHREPORTER_RESTART_ARG_";
2482 0 : envVar.AppendInt(i);
2483 0 : envVar += "=";
2484 0 : if (argv0 && i == 0) {
2485 : // Is there a request to suppress default binary launcher?
2486 0 : envVar += argv0;
2487 : } else {
2488 0 : envVar += argv[i];
2489 : }
2490 :
2491 : // PR_SetEnv() wants the string to be available for the lifetime
2492 : // of the app, so dup it here
2493 0 : env = ToNewCString(envVar);
2494 0 : if (!env)
2495 0 : return NS_ERROR_OUT_OF_MEMORY;
2496 :
2497 0 : PR_SetEnv(env);
2498 : }
2499 :
2500 : // make sure the arg list is terminated
2501 0 : envVar = "MOZ_CRASHREPORTER_RESTART_ARG_";
2502 0 : envVar.AppendInt(i);
2503 0 : envVar += "=";
2504 :
2505 : // PR_SetEnv() wants the string to be available for the lifetime
2506 : // of the app, so dup it here
2507 0 : env = ToNewCString(envVar);
2508 0 : if (!env)
2509 0 : return NS_ERROR_OUT_OF_MEMORY;
2510 :
2511 0 : PR_SetEnv(env);
2512 :
2513 : // make sure we save the info in XUL_APP_FILE for the reporter
2514 0 : const char *appfile = PR_GetEnv("XUL_APP_FILE");
2515 0 : if (appfile && *appfile) {
2516 0 : envVar = "MOZ_CRASHREPORTER_RESTART_XUL_APP_FILE=";
2517 0 : envVar += appfile;
2518 0 : env = ToNewCString(envVar);
2519 0 : PR_SetEnv(env);
2520 : }
2521 :
2522 0 : return NS_OK;
2523 : }
2524 :
2525 : #ifdef XP_WIN32
2526 : nsresult WriteMinidumpForException(EXCEPTION_POINTERS* aExceptionInfo)
2527 : {
2528 : if (!gExceptionHandler)
2529 : return NS_ERROR_NOT_INITIALIZED;
2530 :
2531 : return gExceptionHandler->WriteMinidumpForException(aExceptionInfo) ? NS_OK : NS_ERROR_FAILURE;
2532 : }
2533 : #endif
2534 :
2535 : #ifdef XP_LINUX
2536 0 : bool WriteMinidumpForSigInfo(int signo, siginfo_t* info, void* uc)
2537 : {
2538 0 : if (!gExceptionHandler) {
2539 : // Crash reporting is disabled.
2540 0 : return false;
2541 : }
2542 0 : return gExceptionHandler->HandleSignal(signo, info, uc);
2543 : }
2544 : #endif
2545 :
2546 : #ifdef XP_MACOSX
2547 : nsresult AppendObjCExceptionInfoToAppNotes(void *inException)
2548 : {
2549 : nsAutoCString excString;
2550 : GetObjCExceptionInfo(inException, excString);
2551 : AppendAppNotesToCrashReport(excString);
2552 : return NS_OK;
2553 : }
2554 : #endif
2555 :
2556 : /*
2557 : * Combined code to get/set the crash reporter submission pref on
2558 : * different platforms.
2559 : */
2560 0 : static nsresult PrefSubmitReports(bool* aSubmitReports, bool writePref)
2561 : {
2562 : nsresult rv;
2563 : #if defined(XP_WIN32)
2564 : /*
2565 : * NOTE! This needs to stay in sync with the preference checking code
2566 : * in toolkit/crashreporter/client/crashreporter_win.cpp
2567 : */
2568 : nsCOMPtr<nsIXULAppInfo> appinfo =
2569 : do_GetService("@mozilla.org/xre/app-info;1", &rv);
2570 : NS_ENSURE_SUCCESS(rv, rv);
2571 :
2572 : nsAutoCString appVendor, appName;
2573 : rv = appinfo->GetVendor(appVendor);
2574 : NS_ENSURE_SUCCESS(rv, rv);
2575 : rv = appinfo->GetName(appName);
2576 : NS_ENSURE_SUCCESS(rv, rv);
2577 :
2578 : nsCOMPtr<nsIWindowsRegKey> regKey
2579 : (do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv));
2580 : NS_ENSURE_SUCCESS(rv, rv);
2581 :
2582 : nsAutoCString regPath;
2583 :
2584 : regPath.AppendLiteral("Software\\");
2585 :
2586 : // We need to ensure the registry keys are created so we can properly
2587 : // write values to it
2588 :
2589 : // Create appVendor key
2590 : if(!appVendor.IsEmpty()) {
2591 : regPath.Append(appVendor);
2592 : regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
2593 : NS_ConvertUTF8toUTF16(regPath),
2594 : nsIWindowsRegKey::ACCESS_SET_VALUE);
2595 : regPath.Append('\\');
2596 : }
2597 :
2598 : // Create appName key
2599 : regPath.Append(appName);
2600 : regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
2601 : NS_ConvertUTF8toUTF16(regPath),
2602 : nsIWindowsRegKey::ACCESS_SET_VALUE);
2603 : regPath.Append('\\');
2604 :
2605 : // Create Crash Reporter key
2606 : regPath.AppendLiteral("Crash Reporter");
2607 : regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
2608 : NS_ConvertUTF8toUTF16(regPath),
2609 : nsIWindowsRegKey::ACCESS_SET_VALUE);
2610 :
2611 : // If we're saving the pref value, just write it to ROOT_KEY_CURRENT_USER
2612 : // and we're done.
2613 : if (writePref) {
2614 : rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
2615 : NS_ConvertUTF8toUTF16(regPath),
2616 : nsIWindowsRegKey::ACCESS_SET_VALUE);
2617 : NS_ENSURE_SUCCESS(rv, rv);
2618 :
2619 : uint32_t value = *aSubmitReports ? 1 : 0;
2620 : rv = regKey->WriteIntValue(NS_LITERAL_STRING("SubmitCrashReport"), value);
2621 : regKey->Close();
2622 : return rv;
2623 : }
2624 :
2625 : // We're reading the pref value, so we need to first look under
2626 : // ROOT_KEY_LOCAL_MACHINE to see if it's set there, and then fall back to
2627 : // ROOT_KEY_CURRENT_USER. If it's not set in either place, the pref defaults
2628 : // to "true".
2629 : uint32_t value;
2630 : rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,
2631 : NS_ConvertUTF8toUTF16(regPath),
2632 : nsIWindowsRegKey::ACCESS_QUERY_VALUE);
2633 : if (NS_SUCCEEDED(rv)) {
2634 : rv = regKey->ReadIntValue(NS_LITERAL_STRING("SubmitCrashReport"), &value);
2635 : regKey->Close();
2636 : if (NS_SUCCEEDED(rv)) {
2637 : *aSubmitReports = !!value;
2638 : return NS_OK;
2639 : }
2640 : }
2641 :
2642 : rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
2643 : NS_ConvertUTF8toUTF16(regPath),
2644 : nsIWindowsRegKey::ACCESS_QUERY_VALUE);
2645 : if (NS_FAILED(rv)) {
2646 : *aSubmitReports = true;
2647 : return NS_OK;
2648 : }
2649 :
2650 : rv = regKey->ReadIntValue(NS_LITERAL_STRING("SubmitCrashReport"), &value);
2651 : // default to true on failure
2652 : if (NS_FAILED(rv)) {
2653 : value = 1;
2654 : rv = NS_OK;
2655 : }
2656 : regKey->Close();
2657 :
2658 : *aSubmitReports = !!value;
2659 : return NS_OK;
2660 : #elif defined(XP_MACOSX)
2661 : rv = NS_OK;
2662 : if (writePref) {
2663 : CFPropertyListRef cfValue = (CFPropertyListRef)(*aSubmitReports ? kCFBooleanTrue : kCFBooleanFalse);
2664 : ::CFPreferencesSetAppValue(CFSTR("submitReport"),
2665 : cfValue,
2666 : reporterClientAppID);
2667 : if (!::CFPreferencesAppSynchronize(reporterClientAppID))
2668 : rv = NS_ERROR_FAILURE;
2669 : }
2670 : else {
2671 : *aSubmitReports = true;
2672 : Boolean keyExistsAndHasValidFormat = false;
2673 : Boolean prefValue = ::CFPreferencesGetAppBooleanValue(CFSTR("submitReport"),
2674 : reporterClientAppID,
2675 : &keyExistsAndHasValidFormat);
2676 : if (keyExistsAndHasValidFormat)
2677 : *aSubmitReports = !!prefValue;
2678 : }
2679 : return rv;
2680 : #elif defined(XP_UNIX)
2681 : /*
2682 : * NOTE! This needs to stay in sync with the preference checking code
2683 : * in toolkit/crashreporter/client/crashreporter_linux.cpp
2684 : */
2685 0 : nsCOMPtr<nsIFile> reporterINI;
2686 0 : rv = NS_GetSpecialDirectory("UAppData", getter_AddRefs(reporterINI));
2687 0 : NS_ENSURE_SUCCESS(rv, rv);
2688 0 : reporterINI->AppendNative(NS_LITERAL_CSTRING("Crash Reports"));
2689 0 : reporterINI->AppendNative(NS_LITERAL_CSTRING("crashreporter.ini"));
2690 :
2691 : bool exists;
2692 0 : rv = reporterINI->Exists(&exists);
2693 0 : NS_ENSURE_SUCCESS(rv, rv);
2694 0 : if (!exists) {
2695 0 : if (!writePref) {
2696 : // If reading the pref, default to true if .ini doesn't exist.
2697 0 : *aSubmitReports = true;
2698 0 : return NS_OK;
2699 : }
2700 : // Create the file so the INI processor can write to it.
2701 0 : rv = reporterINI->Create(nsIFile::NORMAL_FILE_TYPE, 0600);
2702 0 : NS_ENSURE_SUCCESS(rv, rv);
2703 : }
2704 :
2705 : nsCOMPtr<nsIINIParserFactory> iniFactory =
2706 0 : do_GetService("@mozilla.org/xpcom/ini-processor-factory;1", &rv);
2707 0 : NS_ENSURE_SUCCESS(rv, rv);
2708 :
2709 0 : nsCOMPtr<nsIINIParser> iniParser;
2710 0 : rv = iniFactory->CreateINIParser(reporterINI,
2711 0 : getter_AddRefs(iniParser));
2712 0 : NS_ENSURE_SUCCESS(rv, rv);
2713 :
2714 : // If we're writing the pref, just set and we're done.
2715 0 : if (writePref) {
2716 0 : nsCOMPtr<nsIINIParserWriter> iniWriter = do_QueryInterface(iniParser);
2717 0 : NS_ENSURE_TRUE(iniWriter, NS_ERROR_FAILURE);
2718 :
2719 0 : rv = iniWriter->SetString(NS_LITERAL_CSTRING("Crash Reporter"),
2720 0 : NS_LITERAL_CSTRING("SubmitReport"),
2721 0 : *aSubmitReports ? NS_LITERAL_CSTRING("1") :
2722 0 : NS_LITERAL_CSTRING("0"));
2723 0 : NS_ENSURE_SUCCESS(rv, rv);
2724 0 : rv = iniWriter->WriteFile(nullptr, 0);
2725 0 : return rv;
2726 : }
2727 :
2728 0 : nsAutoCString submitReportValue;
2729 0 : rv = iniParser->GetString(NS_LITERAL_CSTRING("Crash Reporter"),
2730 0 : NS_LITERAL_CSTRING("SubmitReport"),
2731 0 : submitReportValue);
2732 :
2733 : // Default to "true" if the pref can't be found.
2734 0 : if (NS_FAILED(rv))
2735 0 : *aSubmitReports = true;
2736 0 : else if (submitReportValue.EqualsASCII("0"))
2737 0 : *aSubmitReports = false;
2738 : else
2739 0 : *aSubmitReports = true;
2740 :
2741 0 : return NS_OK;
2742 : #else
2743 : return NS_ERROR_NOT_IMPLEMENTED;
2744 : #endif
2745 : }
2746 :
2747 0 : nsresult GetSubmitReports(bool* aSubmitReports)
2748 : {
2749 0 : return PrefSubmitReports(aSubmitReports, false);
2750 : }
2751 :
2752 0 : nsresult SetSubmitReports(bool aSubmitReports)
2753 : {
2754 : nsresult rv;
2755 :
2756 : nsCOMPtr<nsIObserverService> obsServ =
2757 0 : mozilla::services::GetObserverService();
2758 0 : if (!obsServ) {
2759 0 : return NS_ERROR_FAILURE;
2760 : }
2761 :
2762 0 : rv = PrefSubmitReports(&aSubmitReports, true);
2763 0 : if (NS_FAILED(rv)) {
2764 0 : return rv;
2765 : }
2766 :
2767 0 : obsServ->NotifyObservers(nullptr, "submit-reports-pref-changed", nullptr);
2768 0 : return NS_OK;
2769 : }
2770 :
2771 : static void
2772 2 : SetCrashEventsDir(nsIFile* aDir)
2773 : {
2774 4 : nsCOMPtr<nsIFile> eventsDir = aDir;
2775 :
2776 2 : const char *env = PR_GetEnv("CRASHES_EVENTS_DIR");
2777 2 : if (env && *env) {
2778 0 : NS_NewNativeLocalFile(nsDependentCString(env),
2779 0 : false, getter_AddRefs(eventsDir));
2780 0 : EnsureDirectoryExists(eventsDir);
2781 : }
2782 :
2783 2 : if (eventsDirectory) {
2784 1 : free(eventsDirectory);
2785 : }
2786 :
2787 : #ifdef XP_WIN
2788 : nsString path;
2789 : eventsDir->GetPath(path);
2790 : eventsDirectory = reinterpret_cast<wchar_t*>(ToNewUnicode(path));
2791 :
2792 : // Save the path in the environment for the crash reporter application.
2793 : nsAutoString eventsDirEnv(NS_LITERAL_STRING("MOZ_CRASHREPORTER_EVENTS_DIRECTORY="));
2794 : eventsDirEnv.Append(path);
2795 : _wputenv(eventsDirEnv.get());
2796 : #else
2797 4 : nsCString path;
2798 2 : eventsDir->GetNativePath(path);
2799 2 : eventsDirectory = ToNewCString(path);
2800 :
2801 : // Save the path in the environment for the crash reporter application.
2802 4 : nsAutoCString eventsDirEnv("MOZ_CRASHREPORTER_EVENTS_DIRECTORY=");
2803 2 : eventsDirEnv.Append(path);
2804 :
2805 : // PR_SetEnv() wants the string to be available for the lifetime
2806 : // of the app, so dup it here.
2807 2 : char* oldEventsEnv = eventsEnv;
2808 2 : eventsEnv = ToNewCString(eventsDirEnv);
2809 2 : PR_SetEnv(eventsEnv);
2810 :
2811 2 : if (oldEventsEnv) {
2812 1 : free(oldEventsEnv);
2813 : }
2814 : #endif
2815 2 : }
2816 :
2817 : void
2818 1 : SetProfileDirectory(nsIFile* aDir)
2819 : {
2820 2 : nsCOMPtr<nsIFile> dir;
2821 1 : aDir->Clone(getter_AddRefs(dir));
2822 :
2823 1 : dir->Append(NS_LITERAL_STRING("crashes"));
2824 1 : EnsureDirectoryExists(dir);
2825 1 : dir->Append(NS_LITERAL_STRING("events"));
2826 1 : EnsureDirectoryExists(dir);
2827 1 : SetCrashEventsDir(dir);
2828 1 : }
2829 :
2830 : void
2831 1 : SetUserAppDataDirectory(nsIFile* aDir)
2832 : {
2833 2 : nsCOMPtr<nsIFile> dir;
2834 1 : aDir->Clone(getter_AddRefs(dir));
2835 :
2836 1 : dir->Append(NS_LITERAL_STRING("Crash Reports"));
2837 1 : EnsureDirectoryExists(dir);
2838 1 : dir->Append(NS_LITERAL_STRING("events"));
2839 1 : EnsureDirectoryExists(dir);
2840 1 : SetCrashEventsDir(dir);
2841 1 : }
2842 :
2843 : void
2844 0 : UpdateCrashEventsDir()
2845 : {
2846 0 : const char *env = PR_GetEnv("CRASHES_EVENTS_DIR");
2847 0 : if (env && *env) {
2848 0 : SetCrashEventsDir(nullptr);
2849 : }
2850 :
2851 0 : nsCOMPtr<nsIFile> eventsDir;
2852 0 : nsresult rv = NS_GetSpecialDirectory("ProfD", getter_AddRefs(eventsDir));
2853 0 : if (NS_SUCCEEDED(rv)) {
2854 0 : SetProfileDirectory(eventsDir);
2855 0 : return;
2856 : }
2857 :
2858 0 : rv = NS_GetSpecialDirectory("UAppData", getter_AddRefs(eventsDir));
2859 0 : if (NS_SUCCEEDED(rv)) {
2860 0 : SetUserAppDataDirectory(eventsDir);
2861 0 : return;
2862 : }
2863 :
2864 0 : NS_WARNING("Couldn't get the user appdata directory. Crash events may not be produced.");
2865 : }
2866 :
2867 0 : bool GetCrashEventsDir(nsAString& aPath)
2868 : {
2869 0 : if (!eventsDirectory) {
2870 0 : return false;
2871 : }
2872 :
2873 0 : aPath = CONVERT_XP_CHAR_TO_UTF16(eventsDirectory);
2874 0 : return true;
2875 : }
2876 :
2877 : void
2878 0 : SetMemoryReportFile(nsIFile* aFile)
2879 : {
2880 0 : if (!gExceptionHandler) {
2881 0 : return;
2882 : }
2883 : #ifdef XP_WIN
2884 : nsString path;
2885 : aFile->GetPath(path);
2886 : memoryReportPath = reinterpret_cast<wchar_t*>(ToNewUnicode(path));
2887 : #else
2888 0 : nsCString path;
2889 0 : aFile->GetNativePath(path);
2890 0 : memoryReportPath = ToNewCString(path);
2891 : #endif
2892 : }
2893 :
2894 : nsresult
2895 0 : GetDefaultMemoryReportFile(nsIFile** aFile)
2896 : {
2897 0 : nsCOMPtr<nsIFile> defaultMemoryReportFile;
2898 0 : if (!defaultMemoryReportPath) {
2899 0 : nsresult rv = NS_GetSpecialDirectory(NS_APP_PROFILE_DIR_STARTUP,
2900 0 : getter_AddRefs(defaultMemoryReportFile));
2901 0 : if (NS_FAILED(rv)) {
2902 0 : return rv;
2903 : }
2904 0 : defaultMemoryReportFile->AppendNative(NS_LITERAL_CSTRING("memory-report.json.gz"));
2905 0 : defaultMemoryReportPath = CreatePathFromFile(defaultMemoryReportFile);
2906 0 : if (!defaultMemoryReportPath) {
2907 0 : return NS_ERROR_FAILURE;
2908 : }
2909 : } else {
2910 0 : CreateFileFromPath(*defaultMemoryReportPath,
2911 0 : getter_AddRefs(defaultMemoryReportFile));
2912 0 : if (!defaultMemoryReportFile) {
2913 0 : return NS_ERROR_FAILURE;
2914 : }
2915 : }
2916 0 : defaultMemoryReportFile.forget(aFile);
2917 0 : return NS_OK;
2918 : }
2919 :
2920 : void
2921 1 : SetTelemetrySessionId(const nsACString& id)
2922 : {
2923 1 : if (!gExceptionHandler) {
2924 1 : return;
2925 : }
2926 0 : if (currentSessionId) {
2927 0 : free(currentSessionId);
2928 : }
2929 0 : currentSessionId = ToNewCString(id);
2930 : }
2931 :
2932 : static void
2933 0 : FindPendingDir()
2934 : {
2935 0 : if (pendingDirectory)
2936 0 : return;
2937 :
2938 0 : nsCOMPtr<nsIFile> pendingDir;
2939 0 : nsresult rv = NS_GetSpecialDirectory("UAppData", getter_AddRefs(pendingDir));
2940 0 : if (NS_FAILED(rv)) {
2941 0 : NS_WARNING("Couldn't get the user appdata directory, crash dumps will go in an unusual location");
2942 : }
2943 : else {
2944 0 : pendingDir->Append(NS_LITERAL_STRING("Crash Reports"));
2945 0 : pendingDir->Append(NS_LITERAL_STRING("pending"));
2946 :
2947 : #ifdef XP_WIN
2948 : nsString path;
2949 : pendingDir->GetPath(path);
2950 : pendingDirectory = reinterpret_cast<wchar_t*>(ToNewUnicode(path));
2951 : #else
2952 0 : nsCString path;
2953 0 : pendingDir->GetNativePath(path);
2954 0 : pendingDirectory = ToNewCString(path);
2955 : #endif
2956 : }
2957 : }
2958 :
2959 : // The "pending" dir is Crash Reports/pending, from which minidumps
2960 : // can be submitted. Because this method may be called off the main thread,
2961 : // we store the pending directory as a path.
2962 : static bool
2963 0 : GetPendingDir(nsIFile** dir)
2964 : {
2965 : // MOZ_ASSERT(OOPInitialized());
2966 0 : if (!pendingDirectory) {
2967 0 : return false;
2968 : }
2969 :
2970 0 : nsCOMPtr<nsIFile> pending = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
2971 0 : if (!pending) {
2972 0 : NS_WARNING("Can't set up pending directory during shutdown.");
2973 0 : return false;
2974 : }
2975 : #ifdef XP_WIN
2976 : pending->InitWithPath(nsDependentString(pendingDirectory));
2977 : #else
2978 0 : pending->InitWithNativePath(nsDependentCString(pendingDirectory));
2979 : #endif
2980 0 : pending.swap(*dir);
2981 0 : return true;
2982 : }
2983 :
2984 : // The "limbo" dir is where minidumps go to wait for something else to
2985 : // use them. If we're |ShouldReport()|, then the "something else" is
2986 : // a minidump submitter, and they're coming from the
2987 : // Crash Reports/pending/ dir. Otherwise, we don't know what the
2988 : // "somthing else" is, but the minidumps stay in [profile]/minidumps/
2989 : // limbo.
2990 : static bool
2991 0 : GetMinidumpLimboDir(nsIFile** dir)
2992 : {
2993 0 : if (ShouldReport()) {
2994 0 : return GetPendingDir(dir);
2995 : }
2996 : else {
2997 : #ifndef XP_LINUX
2998 : CreateFileFromPath(gExceptionHandler->dump_path(), dir);
2999 : #else
3000 0 : CreateFileFromPath(gExceptionHandler->minidump_descriptor().directory(),
3001 0 : dir);
3002 : #endif
3003 0 : return nullptr != *dir;
3004 : }
3005 : }
3006 :
3007 : void
3008 0 : DeleteMinidumpFilesForID(const nsAString& id)
3009 : {
3010 0 : nsCOMPtr<nsIFile> minidumpFile;
3011 0 : if (GetMinidumpForID(id, getter_AddRefs(minidumpFile))) {
3012 0 : nsCOMPtr<nsIFile> childExtraFile;
3013 0 : GetExtraFileForMinidump(minidumpFile, getter_AddRefs(childExtraFile));
3014 0 : if (childExtraFile) {
3015 0 : childExtraFile->Remove(false);
3016 : }
3017 0 : minidumpFile->Remove(false);
3018 : }
3019 0 : }
3020 :
3021 : bool
3022 0 : GetMinidumpForID(const nsAString& id, nsIFile** minidump)
3023 : {
3024 0 : if (!GetMinidumpLimboDir(minidump)) {
3025 0 : return false;
3026 : }
3027 :
3028 0 : (*minidump)->Append(id + NS_LITERAL_STRING(".dmp"));
3029 :
3030 : bool exists;
3031 0 : if (NS_FAILED((*minidump)->Exists(&exists)) || !exists) {
3032 0 : return false;
3033 : }
3034 :
3035 0 : return true;
3036 : }
3037 :
3038 : bool
3039 0 : GetIDFromMinidump(nsIFile* minidump, nsAString& id)
3040 : {
3041 0 : if (minidump && NS_SUCCEEDED(minidump->GetLeafName(id))) {
3042 0 : id.Replace(id.Length() - 4, 4, NS_LITERAL_STRING(""));
3043 0 : return true;
3044 : }
3045 0 : return false;
3046 : }
3047 :
3048 : bool
3049 0 : GetExtraFileForID(const nsAString& id, nsIFile** extraFile)
3050 : {
3051 0 : if (!GetMinidumpLimboDir(extraFile)) {
3052 0 : return false;
3053 : }
3054 :
3055 0 : (*extraFile)->Append(id + NS_LITERAL_STRING(".extra"));
3056 :
3057 : bool exists;
3058 0 : if (NS_FAILED((*extraFile)->Exists(&exists)) || !exists) {
3059 0 : return false;
3060 : }
3061 :
3062 0 : return true;
3063 : }
3064 :
3065 : bool
3066 0 : GetExtraFileForMinidump(nsIFile* minidump, nsIFile** extraFile)
3067 : {
3068 0 : nsAutoString leafName;
3069 0 : nsresult rv = minidump->GetLeafName(leafName);
3070 0 : if (NS_FAILED(rv))
3071 0 : return false;
3072 :
3073 0 : nsCOMPtr<nsIFile> extraF;
3074 0 : rv = minidump->Clone(getter_AddRefs(extraF));
3075 0 : if (NS_FAILED(rv))
3076 0 : return false;
3077 :
3078 0 : leafName.Replace(leafName.Length() - 3, 3,
3079 0 : NS_LITERAL_STRING("extra"));
3080 0 : rv = extraF->SetLeafName(leafName);
3081 0 : if (NS_FAILED(rv))
3082 0 : return false;
3083 :
3084 0 : *extraFile = nullptr;
3085 0 : extraF.swap(*extraFile);
3086 0 : return true;
3087 : }
3088 :
3089 : bool
3090 0 : AppendExtraData(const nsAString& id, const AnnotationTable& data)
3091 : {
3092 0 : nsCOMPtr<nsIFile> extraFile;
3093 0 : if (!GetExtraFileForID(id, getter_AddRefs(extraFile)))
3094 0 : return false;
3095 0 : return AppendExtraData(extraFile, data);
3096 : }
3097 :
3098 : //-----------------------------------------------------------------------------
3099 : // Helpers for AppendExtraData()
3100 : //
3101 : struct Blacklist {
3102 0 : Blacklist() : mItems(nullptr), mLen(0) { }
3103 0 : Blacklist(const char** items, int len) : mItems(items), mLen(len) { }
3104 :
3105 0 : bool Contains(const nsACString& key) const {
3106 0 : for (int i = 0; i < mLen; ++i)
3107 0 : if (key.EqualsASCII(mItems[i]))
3108 0 : return true;
3109 0 : return false;
3110 : }
3111 :
3112 : const char** mItems;
3113 : const int mLen;
3114 : };
3115 :
3116 : static void
3117 0 : WriteAnnotation(PRFileDesc* fd, const nsACString& key, const nsACString& value)
3118 : {
3119 0 : PR_Write(fd, key.BeginReading(), key.Length());
3120 0 : PR_Write(fd, "=", 1);
3121 0 : PR_Write(fd, value.BeginReading(), value.Length());
3122 0 : PR_Write(fd, "\n", 1);
3123 0 : }
3124 :
3125 : template<int N>
3126 : void
3127 0 : WriteLiteral(PRFileDesc* fd, const char (&str)[N])
3128 : {
3129 0 : PR_Write(fd, str, N - 1);
3130 0 : }
3131 :
3132 : static bool
3133 0 : WriteExtraData(nsIFile* extraFile,
3134 : const AnnotationTable& data,
3135 : const Blacklist& blacklist,
3136 : bool writeCrashTime=false,
3137 : bool truncate=false)
3138 : {
3139 : PRFileDesc* fd;
3140 0 : int truncOrAppend = truncate ? PR_TRUNCATE : PR_APPEND;
3141 : nsresult rv =
3142 0 : extraFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | truncOrAppend,
3143 0 : 0600, &fd);
3144 0 : if (NS_FAILED(rv))
3145 0 : return false;
3146 :
3147 0 : for (auto iter = data.ConstIter(); !iter.Done(); iter.Next()) {
3148 : // Skip entries in the blacklist.
3149 0 : const nsACString& key = iter.Key();
3150 0 : if (blacklist.Contains(key)) {
3151 0 : continue;
3152 : }
3153 0 : WriteAnnotation(fd, key, iter.Data());
3154 : }
3155 :
3156 0 : if (writeCrashTime) {
3157 0 : time_t crashTime = time(nullptr);
3158 : char crashTimeString[32];
3159 0 : XP_TTOA(crashTime, crashTimeString, 10);
3160 :
3161 : WriteAnnotation(fd,
3162 0 : nsDependentCString("CrashTime"),
3163 0 : nsDependentCString(crashTimeString));
3164 :
3165 0 : double uptimeTS = (TimeStamp::NowLoRes() -
3166 0 : TimeStamp::ProcessCreation()).ToSecondsSigDigits();
3167 : char uptimeTSString[64];
3168 0 : SimpleNoCLibDtoA(uptimeTS, uptimeTSString, sizeof(uptimeTSString));
3169 :
3170 : WriteAnnotation(fd,
3171 0 : nsDependentCString("UptimeTS"),
3172 0 : nsDependentCString(uptimeTSString));
3173 : }
3174 :
3175 0 : if (memoryReportPath) {
3176 0 : WriteLiteral(fd, "ContainsMemoryReport=1\n");
3177 : }
3178 :
3179 0 : PR_Close(fd);
3180 0 : return true;
3181 : }
3182 :
3183 : bool
3184 0 : AppendExtraData(nsIFile* extraFile, const AnnotationTable& data)
3185 : {
3186 0 : return WriteExtraData(extraFile, data, Blacklist());
3187 : }
3188 :
3189 : static bool
3190 0 : GetExtraFileForChildPid(uint32_t aPid, nsIFile** aExtraFile)
3191 : {
3192 0 : MOZ_ASSERT(XRE_IsParentProcess());
3193 :
3194 0 : nsCOMPtr<nsIFile> extraFile;
3195 : nsresult rv;
3196 :
3197 : #if defined(XP_WIN) || defined(XP_MACOSX)
3198 : if (!childProcessTmpDir) {
3199 : return false;
3200 : }
3201 : CreateFileFromPath(*childProcessTmpDir, getter_AddRefs(extraFile));
3202 : if (!extraFile) {
3203 : return false;
3204 : }
3205 : #elif defined(XP_UNIX)
3206 0 : rv = NS_NewLocalFile(NS_LITERAL_STRING("/tmp"), false,
3207 0 : getter_AddRefs(extraFile));
3208 0 : if (NS_FAILED(rv)) {
3209 0 : return false;
3210 : }
3211 : #else
3212 : #error "Implement this for your platform"
3213 : #endif
3214 :
3215 0 : nsAutoString leafName;
3216 : #if defined(XP_WIN)
3217 : leafName.AppendPrintf("%S%u%S", childCrashAnnotationBaseName, aPid,
3218 : extraFileExtension);
3219 : #else
3220 : leafName.AppendPrintf("%s%u%s", childCrashAnnotationBaseName, aPid,
3221 0 : extraFileExtension);
3222 : #endif
3223 :
3224 0 : rv = extraFile->Append(leafName);
3225 0 : if (NS_FAILED(rv)) {
3226 0 : return false;
3227 : }
3228 :
3229 0 : extraFile.forget(aExtraFile);
3230 0 : return true;
3231 : }
3232 :
3233 : static bool
3234 0 : IsDataEscaped(char* aData)
3235 : {
3236 0 : if (strchr(aData, '\n')) {
3237 : // There should not be any newlines
3238 0 : return false;
3239 : }
3240 0 : char* pos = aData;
3241 0 : while ((pos = strchr(pos, '\\'))) {
3242 0 : if (*(pos + 1) != '\\') {
3243 0 : return false;
3244 : }
3245 : // Add 2 to account for the second pos
3246 0 : pos += 2;
3247 : }
3248 0 : return true;
3249 : }
3250 :
3251 : static void
3252 0 : ReadAndValidateExceptionTimeAnnotations(FILE*& aFd,
3253 : AnnotationTable& aAnnotations)
3254 : {
3255 : char line[0x1000];
3256 0 : while (fgets(line, sizeof(line), aFd)) {
3257 0 : char* data = strchr(line, '=');
3258 0 : if (!data) {
3259 : // bad data? Abort!
3260 0 : break;
3261 : }
3262 : // Move past the '='
3263 0 : *data = 0;
3264 0 : ++data;
3265 0 : size_t dataLen = strlen(data);
3266 : // Chop off any trailing newline
3267 0 : if (dataLen > 0 && data[dataLen - 1] == '\n') {
3268 0 : data[dataLen - 1] = 0;
3269 0 : --dataLen;
3270 : }
3271 : // There should not be any newlines in the key
3272 0 : if (strchr(line, '\n')) {
3273 0 : break;
3274 : }
3275 : // Data should have been escaped by the child
3276 0 : if (!IsDataEscaped(data)) {
3277 0 : break;
3278 : }
3279 : // Looks good, save the (line,data) pair
3280 0 : aAnnotations.Put(nsDependentCString(line),
3281 0 : nsDependentCString(data, dataLen));
3282 : }
3283 0 : }
3284 :
3285 : /**
3286 : * NOTE: One side effect of this function is that it deletes the
3287 : * GeckoChildCrash<pid>.extra file if it exists, once processed.
3288 : */
3289 : static bool
3290 0 : WriteExtraForMinidump(nsIFile* minidump,
3291 : uint32_t pid,
3292 : const Blacklist& blacklist,
3293 : nsIFile** extraFile)
3294 : {
3295 0 : nsCOMPtr<nsIFile> extra;
3296 0 : if (!GetExtraFileForMinidump(minidump, getter_AddRefs(extra))) {
3297 0 : return false;
3298 : }
3299 :
3300 0 : if (!WriteExtraData(extra, *crashReporterAPIData_Hash,
3301 : blacklist,
3302 : true /*write crash time*/,
3303 : true /*truncate*/)) {
3304 0 : return false;
3305 : }
3306 :
3307 0 : nsCOMPtr<nsIFile> exceptionTimeExtra;
3308 : FILE* fd;
3309 0 : if (pid && GetExtraFileForChildPid(pid, getter_AddRefs(exceptionTimeExtra)) &&
3310 0 : NS_SUCCEEDED(exceptionTimeExtra->OpenANSIFileDesc("r", &fd))) {
3311 0 : AnnotationTable exceptionTimeAnnotations;
3312 0 : ReadAndValidateExceptionTimeAnnotations(fd, exceptionTimeAnnotations);
3313 0 : fclose(fd);
3314 0 : if (!AppendExtraData(extra, exceptionTimeAnnotations)) {
3315 0 : return false;
3316 : }
3317 : }
3318 0 : if (exceptionTimeExtra) {
3319 0 : exceptionTimeExtra->Remove(false);
3320 : }
3321 :
3322 0 : extra.forget(extraFile);
3323 :
3324 0 : return true;
3325 : }
3326 :
3327 : // It really only makes sense to call this function when
3328 : // ShouldReport() is true.
3329 : // Uses dumpFile's filename to generate memoryReport's filename (same name with
3330 : // a different extension)
3331 : static bool
3332 0 : MoveToPending(nsIFile* dumpFile, nsIFile* extraFile, nsIFile* memoryReport)
3333 : {
3334 0 : nsCOMPtr<nsIFile> pendingDir;
3335 0 : if (!GetPendingDir(getter_AddRefs(pendingDir)))
3336 0 : return false;
3337 :
3338 0 : if (NS_FAILED(dumpFile->MoveTo(pendingDir, EmptyString()))) {
3339 0 : return false;
3340 : }
3341 :
3342 0 : if (extraFile && NS_FAILED(extraFile->MoveTo(pendingDir, EmptyString()))) {
3343 0 : return false;
3344 : }
3345 :
3346 0 : if (memoryReport) {
3347 0 : nsAutoString leafName;
3348 0 : nsresult rv = dumpFile->GetLeafName(leafName);
3349 0 : if (NS_FAILED(rv)) {
3350 0 : return false;
3351 : }
3352 : // Generate the correct memory report filename from the dumpFile's name
3353 0 : leafName.Replace(leafName.Length() - 4, 4,
3354 0 : static_cast<nsString>(CONVERT_XP_CHAR_TO_UTF16(memoryReportExtension)));
3355 0 : if (NS_FAILED(memoryReport->MoveTo(pendingDir, leafName))) {
3356 0 : return false;
3357 : }
3358 : }
3359 :
3360 0 : return true;
3361 : }
3362 :
3363 : static void
3364 0 : OnChildProcessDumpRequested(void* aContext,
3365 : #ifdef XP_MACOSX
3366 : const ClientInfo& aClientInfo,
3367 : const xpstring& aFilePath
3368 : #else
3369 : const ClientInfo* aClientInfo,
3370 : const xpstring* aFilePath
3371 : #endif
3372 : )
3373 : {
3374 0 : nsCOMPtr<nsIFile> minidump;
3375 0 : nsCOMPtr<nsIFile> extraFile;
3376 :
3377 : // Hold the mutex until the current dump request is complete, to
3378 : // prevent UnsetExceptionHandler() from pulling the rug out from
3379 : // under us.
3380 0 : MutexAutoLock lock(*dumpSafetyLock);
3381 0 : if (!isSafeToDump)
3382 0 : return;
3383 :
3384 0 : CreateFileFromPath(
3385 : #ifdef XP_MACOSX
3386 : aFilePath,
3387 : #else
3388 : *aFilePath,
3389 : #endif
3390 0 : getter_AddRefs(minidump));
3391 :
3392 : uint32_t pid =
3393 : #ifdef XP_MACOSX
3394 : aClientInfo.pid();
3395 : #else
3396 0 : aClientInfo->pid();
3397 : #endif
3398 :
3399 0 : if (!WriteExtraForMinidump(minidump, pid,
3400 0 : Blacklist(kSubprocessBlacklist,
3401 0 : ArrayLength(kSubprocessBlacklist)),
3402 0 : getter_AddRefs(extraFile)))
3403 0 : return;
3404 :
3405 0 : if (ShouldReport()) {
3406 0 : nsCOMPtr<nsIFile> memoryReport;
3407 0 : if (memoryReportPath) {
3408 0 : CreateFileFromPath(memoryReportPath, getter_AddRefs(memoryReport));
3409 0 : MOZ_ASSERT(memoryReport);
3410 : }
3411 0 : MoveToPending(minidump, extraFile, memoryReport);
3412 : }
3413 :
3414 : {
3415 :
3416 : #ifdef MOZ_CRASHREPORTER_INJECTOR
3417 : bool runCallback;
3418 : #endif
3419 : {
3420 0 : MutexAutoLock lock(*dumpMapLock);
3421 0 : ChildProcessData* pd = pidToMinidump->PutEntry(pid);
3422 0 : MOZ_ASSERT(!pd->minidump);
3423 0 : pd->minidump = minidump;
3424 0 : pd->sequence = ++crashSequence;
3425 : #ifdef MOZ_CRASHREPORTER_INJECTOR
3426 : runCallback = nullptr != pd->callback;
3427 : #endif
3428 : }
3429 : #ifdef MOZ_CRASHREPORTER_INJECTOR
3430 : if (runCallback)
3431 : NS_DispatchToMainThread(new ReportInjectedCrash(pid));
3432 : #endif
3433 : }
3434 : }
3435 :
3436 : static bool
3437 0 : OOPInitialized()
3438 : {
3439 0 : return pidToMinidump != nullptr;
3440 : }
3441 :
3442 : void
3443 0 : OOPInit()
3444 : {
3445 0 : class ProxyToMainThread : public Runnable
3446 : {
3447 : public:
3448 0 : ProxyToMainThread() : Runnable("nsExceptionHandler::ProxyToMainThread") {}
3449 0 : NS_IMETHOD Run() override {
3450 0 : OOPInit();
3451 0 : return NS_OK;
3452 : }
3453 : };
3454 0 : if (!NS_IsMainThread()) {
3455 : // This logic needs to run on the main thread
3456 0 : nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
3457 0 : mozilla::SyncRunnable::DispatchToThread(mainThread, new ProxyToMainThread());
3458 0 : return;
3459 : }
3460 :
3461 0 : if (OOPInitialized())
3462 0 : return;
3463 :
3464 0 : MOZ_ASSERT(NS_IsMainThread());
3465 :
3466 0 : MOZ_ASSERT(gExceptionHandler != nullptr,
3467 : "attempt to initialize OOP crash reporter before in-process crashreporter!");
3468 :
3469 : #if (defined(XP_WIN) || defined(XP_MACOSX))
3470 : nsCOMPtr<nsIFile> tmpDir;
3471 : # if defined(MOZ_CONTENT_SANDBOX)
3472 : nsresult rv = NS_GetSpecialDirectory(NS_APP_CONTENT_PROCESS_TEMP_DIR,
3473 : getter_AddRefs(tmpDir));
3474 : if (NS_FAILED(rv) && PR_GetEnv("XPCSHELL_TEST_PROFILE_DIR")) {
3475 : // Temporary hack for xpcshell, will be fixed in bug 1257098
3476 : rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpDir));
3477 : }
3478 : if (NS_SUCCEEDED(rv)) {
3479 : childProcessTmpDir = CreatePathFromFile(tmpDir);
3480 : }
3481 : # else
3482 : if (NS_SUCCEEDED(NS_GetSpecialDirectory(NS_OS_TEMP_DIR,
3483 : getter_AddRefs(tmpDir)))) {
3484 : childProcessTmpDir = CreatePathFromFile(tmpDir);
3485 : }
3486 : # endif // defined(MOZ_CONTENT_SANDBOX)
3487 : #endif // (defined(XP_WIN) || defined(XP_MACOSX))
3488 :
3489 : #if defined(XP_WIN)
3490 : childCrashNotifyPipe =
3491 : mozilla::Smprintf("\\\\.\\pipe\\gecko-crash-server-pipe.%i",
3492 : static_cast<int>(::GetCurrentProcessId())).release();
3493 :
3494 : const std::wstring dumpPath = gExceptionHandler->dump_path();
3495 : crashServer = new CrashGenerationServer(
3496 : std::wstring(NS_ConvertASCIItoUTF16(childCrashNotifyPipe).get()),
3497 : nullptr, // default security attributes
3498 : nullptr, nullptr, // we don't care about process connect here
3499 : OnChildProcessDumpRequested, nullptr,
3500 : nullptr, nullptr, // we don't care about process exit here
3501 : nullptr, nullptr, // we don't care about upload request here
3502 : true, // automatically generate dumps
3503 : &dumpPath);
3504 :
3505 : if (sIncludeContextHeap) {
3506 : crashServer->set_include_context_heap(sIncludeContextHeap);
3507 : }
3508 :
3509 : #elif defined(XP_LINUX)
3510 0 : if (!CrashGenerationServer::CreateReportChannel(&serverSocketFd,
3511 : &clientSocketFd))
3512 0 : MOZ_CRASH("can't create crash reporter socketpair()");
3513 :
3514 : const std::string dumpPath =
3515 0 : gExceptionHandler->minidump_descriptor().directory();
3516 0 : crashServer = new CrashGenerationServer(
3517 : serverSocketFd,
3518 : OnChildProcessDumpRequested, nullptr,
3519 : nullptr, nullptr, // we don't care about process exit here
3520 : true,
3521 0 : &dumpPath);
3522 :
3523 : #elif defined(XP_MACOSX)
3524 : childCrashNotifyPipe =
3525 : mozilla::Smprintf("gecko-crash-server-pipe.%i",
3526 : static_cast<int>(getpid())).release();
3527 : const std::string dumpPath = gExceptionHandler->dump_path();
3528 :
3529 : crashServer = new CrashGenerationServer(
3530 : childCrashNotifyPipe,
3531 : nullptr,
3532 : nullptr,
3533 : OnChildProcessDumpRequested, nullptr,
3534 : nullptr, nullptr,
3535 : true, // automatically generate dumps
3536 : dumpPath);
3537 : #endif
3538 :
3539 0 : if (!crashServer->Start())
3540 0 : MOZ_CRASH("can't start crash reporter server()");
3541 :
3542 0 : pidToMinidump = new ChildMinidumpMap();
3543 :
3544 0 : dumpMapLock = new Mutex("CrashReporter::dumpMapLock");
3545 :
3546 0 : FindPendingDir();
3547 0 : UpdateCrashEventsDir();
3548 : }
3549 :
3550 : static void
3551 0 : OOPDeinit()
3552 : {
3553 0 : if (!OOPInitialized()) {
3554 0 : NS_WARNING("OOPDeinit() without successful OOPInit()");
3555 0 : return;
3556 : }
3557 :
3558 : #ifdef MOZ_CRASHREPORTER_INJECTOR
3559 : if (sInjectorThread) {
3560 : sInjectorThread->Shutdown();
3561 : NS_RELEASE(sInjectorThread);
3562 : }
3563 : #endif
3564 :
3565 0 : if (sMinidumpWriterThread) {
3566 0 : sMinidumpWriterThread->Shutdown();
3567 0 : NS_RELEASE(sMinidumpWriterThread);
3568 : }
3569 :
3570 0 : delete crashServer;
3571 0 : crashServer = nullptr;
3572 :
3573 0 : delete dumpMapLock;
3574 0 : dumpMapLock = nullptr;
3575 :
3576 0 : delete pidToMinidump;
3577 0 : pidToMinidump = nullptr;
3578 :
3579 : #if defined(XP_WIN) || defined(XP_MACOSX)
3580 : mozilla::SmprintfFree(childCrashNotifyPipe);
3581 : childCrashNotifyPipe = nullptr;
3582 : #endif
3583 : }
3584 :
3585 : #if defined(XP_WIN) || defined(XP_MACOSX)
3586 : // Parent-side API for children
3587 : const char*
3588 : GetChildNotificationPipe()
3589 : {
3590 : if (!GetEnabled())
3591 : return kNullNotifyPipe;
3592 :
3593 : MOZ_ASSERT(OOPInitialized());
3594 :
3595 : return childCrashNotifyPipe;
3596 : }
3597 : #endif
3598 :
3599 : #ifdef MOZ_CRASHREPORTER_INJECTOR
3600 : void
3601 : InjectCrashReporterIntoProcess(DWORD processID, InjectorCrashCallback* cb)
3602 : {
3603 : if (!GetEnabled())
3604 : return;
3605 :
3606 : if (!OOPInitialized())
3607 : OOPInit();
3608 :
3609 : if (!sInjectorThread) {
3610 : if (NS_FAILED(NS_NewNamedThread("CrashRep Inject", &sInjectorThread)))
3611 : return;
3612 : }
3613 :
3614 : {
3615 : MutexAutoLock lock(*dumpMapLock);
3616 : ChildProcessData* pd = pidToMinidump->PutEntry(processID);
3617 : MOZ_ASSERT(!pd->minidump && !pd->callback);
3618 : pd->callback = cb;
3619 : }
3620 :
3621 : nsCOMPtr<nsIRunnable> r = new InjectCrashRunnable(processID);
3622 : sInjectorThread->Dispatch(r, nsIEventTarget::DISPATCH_NORMAL);
3623 : }
3624 :
3625 : NS_IMETHODIMP
3626 : ReportInjectedCrash::Run()
3627 : {
3628 : // Crash reporting may have been disabled after this method was dispatched
3629 : if (!OOPInitialized())
3630 : return NS_OK;
3631 :
3632 : InjectorCrashCallback* cb;
3633 : {
3634 : MutexAutoLock lock(*dumpMapLock);
3635 : ChildProcessData* pd = pidToMinidump->GetEntry(mPID);
3636 : if (!pd || !pd->callback)
3637 : return NS_OK;
3638 :
3639 : MOZ_ASSERT(pd->minidump);
3640 :
3641 : cb = pd->callback;
3642 : }
3643 :
3644 : cb->OnCrash(mPID);
3645 : return NS_OK;
3646 : }
3647 :
3648 : void
3649 : UnregisterInjectorCallback(DWORD processID)
3650 : {
3651 : if (!OOPInitialized())
3652 : return;
3653 :
3654 : MutexAutoLock lock(*dumpMapLock);
3655 : pidToMinidump->RemoveEntry(processID);
3656 : }
3657 :
3658 : #endif // MOZ_CRASHREPORTER_INJECTOR
3659 :
3660 : bool
3661 0 : CheckForLastRunCrash()
3662 : {
3663 0 : if (lastRunCrashID)
3664 0 : return true;
3665 :
3666 : // The exception handler callback leaves the filename of the
3667 : // last minidump in a known file.
3668 0 : nsCOMPtr<nsIFile> lastCrashFile;
3669 0 : CreateFileFromPath(crashMarkerFilename,
3670 0 : getter_AddRefs(lastCrashFile));
3671 :
3672 : bool exists;
3673 0 : if (NS_FAILED(lastCrashFile->Exists(&exists)) || !exists) {
3674 0 : return false;
3675 : }
3676 :
3677 0 : nsAutoCString lastMinidump_contents;
3678 0 : if (NS_FAILED(GetFileContents(lastCrashFile, lastMinidump_contents))) {
3679 0 : return false;
3680 : }
3681 0 : lastCrashFile->Remove(false);
3682 :
3683 : #ifdef XP_WIN
3684 : // Ugly but effective.
3685 : nsDependentString lastMinidump(
3686 : reinterpret_cast<const char16_t*>(lastMinidump_contents.get()));
3687 : #else
3688 0 : nsAutoCString lastMinidump = lastMinidump_contents;
3689 : #endif
3690 0 : nsCOMPtr<nsIFile> lastMinidumpFile;
3691 0 : CreateFileFromPath(lastMinidump.get(),
3692 0 : getter_AddRefs(lastMinidumpFile));
3693 :
3694 0 : if (!lastMinidumpFile || NS_FAILED(lastMinidumpFile->Exists(&exists)) || !exists) {
3695 0 : return false;
3696 : }
3697 :
3698 0 : nsCOMPtr<nsIFile> lastExtraFile;
3699 0 : if (!GetExtraFileForMinidump(lastMinidumpFile,
3700 0 : getter_AddRefs(lastExtraFile))) {
3701 0 : return false;
3702 : }
3703 :
3704 0 : nsCOMPtr<nsIFile> memoryReportFile;
3705 0 : nsresult rv = GetDefaultMemoryReportFile(getter_AddRefs(memoryReportFile));
3706 0 : if (NS_FAILED(rv) || NS_FAILED(memoryReportFile->Exists(&exists)) || !exists) {
3707 0 : memoryReportFile = nullptr;
3708 : }
3709 :
3710 0 : FindPendingDir();
3711 :
3712 : // Move {dump,extra,memory} to pending folder
3713 0 : if (!MoveToPending(lastMinidumpFile, lastExtraFile, memoryReportFile)) {
3714 0 : return false;
3715 : }
3716 :
3717 0 : lastRunCrashID = new nsString();
3718 0 : return GetIDFromMinidump(lastMinidumpFile, *lastRunCrashID);
3719 : }
3720 :
3721 : bool
3722 0 : GetLastRunCrashID(nsAString& id)
3723 : {
3724 0 : if (!lastRunCrashID_checked) {
3725 0 : CheckForLastRunCrash();
3726 0 : lastRunCrashID_checked = true;
3727 : }
3728 :
3729 0 : if (!lastRunCrashID) {
3730 0 : return false;
3731 : }
3732 :
3733 0 : id = *lastRunCrashID;
3734 0 : return true;
3735 : }
3736 :
3737 : #if defined(XP_WIN) || defined(XP_MACOSX)
3738 : void
3739 : InitChildProcessTmpDir()
3740 : {
3741 : MOZ_ASSERT(!XRE_IsParentProcess());
3742 : // When retrieved by the child process, this will always resolve to the
3743 : // correct directory regardless of sandbox level.
3744 : nsCOMPtr<nsIFile> tmpDir;
3745 : nsresult rv = NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(tmpDir));
3746 : if (NS_SUCCEEDED(rv)) {
3747 : childProcessTmpDir = CreatePathFromFile(tmpDir);
3748 : }
3749 : }
3750 : #endif // defined(XP_WIN) || defined(XP_MACOSX)
3751 :
3752 : #if defined(XP_WIN)
3753 : // Child-side API
3754 : bool
3755 : SetRemoteExceptionHandler(const nsACString& crashPipe)
3756 : {
3757 : // crash reporting is disabled
3758 : if (crashPipe.Equals(kNullNotifyPipe))
3759 : return true;
3760 :
3761 : MOZ_ASSERT(!gExceptionHandler, "crash client already init'd");
3762 :
3763 : gExceptionHandler = new google_breakpad::
3764 : ExceptionHandler(L"",
3765 : ChildFPEFilter,
3766 : nullptr, // no minidump callback
3767 : nullptr, // no callback context
3768 : google_breakpad::ExceptionHandler::HANDLER_ALL,
3769 : GetMinidumpType(),
3770 : NS_ConvertASCIItoUTF16(crashPipe).get(),
3771 : nullptr);
3772 : gExceptionHandler->set_handle_debug_exceptions(true);
3773 : RunAndCleanUpDelayedNotes();
3774 :
3775 : #ifdef _WIN64
3776 : SetJitExceptionHandler();
3777 : #endif
3778 :
3779 : mozalloc_set_oom_abort_handler(AnnotateOOMAllocationSize);
3780 :
3781 : oldTerminateHandler = std::set_terminate(&TerminateHandler);
3782 :
3783 : // we either do remote or nothing, no fallback to regular crash reporting
3784 : return gExceptionHandler->IsOutOfProcess();
3785 : }
3786 :
3787 : //--------------------------------------------------
3788 : #elif defined(XP_LINUX)
3789 :
3790 : // Parent-side API for children
3791 : bool
3792 2 : CreateNotificationPipeForChild(int* childCrashFd, int* childCrashRemapFd)
3793 : {
3794 2 : if (!GetEnabled()) {
3795 2 : *childCrashFd = -1;
3796 2 : *childCrashRemapFd = -1;
3797 2 : return true;
3798 : }
3799 :
3800 0 : MOZ_ASSERT(OOPInitialized());
3801 :
3802 0 : *childCrashFd = clientSocketFd;
3803 0 : *childCrashRemapFd = gMagicChildCrashReportFd;
3804 :
3805 0 : return true;
3806 : }
3807 :
3808 : // Child-side API
3809 : bool
3810 0 : SetRemoteExceptionHandler()
3811 : {
3812 0 : MOZ_ASSERT(!gExceptionHandler, "crash client already init'd");
3813 :
3814 : // MinidumpDescriptor requires a non-empty path.
3815 0 : google_breakpad::MinidumpDescriptor path(".");
3816 :
3817 0 : gExceptionHandler = new google_breakpad::
3818 : ExceptionHandler(path,
3819 : ChildFilter,
3820 : nullptr, // no minidump callback
3821 : nullptr, // no callback context
3822 : true, // install signal handlers
3823 0 : gMagicChildCrashReportFd);
3824 0 : RunAndCleanUpDelayedNotes();
3825 :
3826 0 : mozalloc_set_oom_abort_handler(AnnotateOOMAllocationSize);
3827 :
3828 0 : oldTerminateHandler = std::set_terminate(&TerminateHandler);
3829 :
3830 : // we either do remote or nothing, no fallback to regular crash reporting
3831 0 : return gExceptionHandler->IsOutOfProcess();
3832 : }
3833 :
3834 : //--------------------------------------------------
3835 : #elif defined(XP_MACOSX)
3836 : // Child-side API
3837 : bool
3838 : SetRemoteExceptionHandler(const nsACString& crashPipe)
3839 : {
3840 : // crash reporting is disabled
3841 : if (crashPipe.Equals(kNullNotifyPipe))
3842 : return true;
3843 :
3844 : MOZ_ASSERT(!gExceptionHandler, "crash client already init'd");
3845 :
3846 : gExceptionHandler = new google_breakpad::
3847 : ExceptionHandler("",
3848 : ChildFilter,
3849 : nullptr, // no minidump callback
3850 : nullptr, // no callback context
3851 : true, // install signal handlers
3852 : crashPipe.BeginReading());
3853 : RunAndCleanUpDelayedNotes();
3854 :
3855 : mozalloc_set_oom_abort_handler(AnnotateOOMAllocationSize);
3856 :
3857 : oldTerminateHandler = std::set_terminate(&TerminateHandler);
3858 :
3859 : // we either do remote or nothing, no fallback to regular crash reporting
3860 : return gExceptionHandler->IsOutOfProcess();
3861 : }
3862 : #endif // XP_WIN
3863 :
3864 :
3865 : bool
3866 0 : TakeMinidumpForChild(uint32_t childPid, nsIFile** dump, uint32_t* aSequence)
3867 : {
3868 0 : if (!GetEnabled())
3869 0 : return false;
3870 :
3871 0 : MutexAutoLock lock(*dumpMapLock);
3872 :
3873 0 : ChildProcessData* pd = pidToMinidump->GetEntry(childPid);
3874 0 : if (!pd)
3875 0 : return false;
3876 :
3877 0 : NS_IF_ADDREF(*dump = pd->minidump);
3878 0 : if (aSequence) {
3879 0 : *aSequence = pd->sequence;
3880 : }
3881 :
3882 0 : pidToMinidump->RemoveEntry(pd);
3883 :
3884 0 : return !!*dump;
3885 : }
3886 :
3887 : //-----------------------------------------------------------------------------
3888 : // CreatePairedMinidumps() and helpers
3889 : //
3890 :
3891 : void
3892 0 : RenameAdditionalHangMinidump(nsIFile* minidump, nsIFile* childMinidump,
3893 : const nsACString& name)
3894 : {
3895 0 : nsCOMPtr<nsIFile> directory;
3896 0 : childMinidump->GetParent(getter_AddRefs(directory));
3897 0 : if (!directory)
3898 0 : return;
3899 :
3900 0 : nsAutoCString leafName;
3901 0 : childMinidump->GetNativeLeafName(leafName);
3902 :
3903 : // turn "<id>.dmp" into "<id>-<name>.dmp
3904 0 : leafName.Insert(NS_LITERAL_CSTRING("-") + name, leafName.Length() - 4);
3905 :
3906 0 : if (NS_FAILED(minidump->MoveToNative(directory, leafName))) {
3907 0 : NS_WARNING("RenameAdditionalHangMinidump failed to move minidump.");
3908 : }
3909 : }
3910 :
3911 : static bool
3912 0 : PairedDumpCallback(
3913 : #ifdef XP_LINUX
3914 : const MinidumpDescriptor& descriptor,
3915 : #else
3916 : const XP_CHAR* dump_path,
3917 : const XP_CHAR* minidump_id,
3918 : #endif
3919 : void* context,
3920 : #ifdef XP_WIN32
3921 : EXCEPTION_POINTERS* /*unused*/,
3922 : MDRawAssertionInfo* /*unused*/,
3923 : #endif
3924 : bool succeeded)
3925 : {
3926 0 : nsCOMPtr<nsIFile>& minidump = *static_cast< nsCOMPtr<nsIFile>* >(context);
3927 :
3928 0 : xpstring dump;
3929 : #ifdef XP_LINUX
3930 0 : dump = descriptor.path();
3931 : #else
3932 : dump = dump_path;
3933 : dump += XP_PATH_SEPARATOR;
3934 : dump += minidump_id;
3935 : dump += dumpFileExtension;
3936 : #endif
3937 :
3938 0 : CreateFileFromPath(dump, getter_AddRefs(minidump));
3939 0 : return true;
3940 : }
3941 :
3942 : static bool
3943 0 : PairedDumpCallbackExtra(
3944 : #ifdef XP_LINUX
3945 : const MinidumpDescriptor& descriptor,
3946 : #else
3947 : const XP_CHAR* dump_path,
3948 : const XP_CHAR* minidump_id,
3949 : #endif
3950 : void* context,
3951 : #ifdef XP_WIN32
3952 : EXCEPTION_POINTERS* /*unused*/,
3953 : MDRawAssertionInfo* /*unused*/,
3954 : #endif
3955 : bool succeeded)
3956 : {
3957 0 : PairedDumpCallback(
3958 : #ifdef XP_LINUX
3959 : descriptor,
3960 : #else
3961 : dump_path, minidump_id,
3962 : #endif
3963 : context,
3964 : #ifdef XP_WIN32
3965 : nullptr, nullptr,
3966 : #endif
3967 0 : succeeded);
3968 :
3969 0 : nsCOMPtr<nsIFile>& minidump = *static_cast< nsCOMPtr<nsIFile>* >(context);
3970 :
3971 0 : nsCOMPtr<nsIFile> extra;
3972 0 : return WriteExtraForMinidump(minidump, 0, Blacklist(), getter_AddRefs(extra));
3973 : }
3974 :
3975 : ThreadId
3976 2 : CurrentThreadId()
3977 : {
3978 : #if defined(XP_WIN)
3979 : return ::GetCurrentThreadId();
3980 : #elif defined(XP_LINUX)
3981 2 : return sys_gettid();
3982 : #elif defined(XP_MACOSX)
3983 : // Just return an index, since Mach ports can't be directly serialized
3984 : thread_act_port_array_t threads_for_task;
3985 : mach_msg_type_number_t thread_count;
3986 :
3987 : if (task_threads(mach_task_self(), &threads_for_task, &thread_count))
3988 : return -1;
3989 :
3990 : for (unsigned int i = 0; i < thread_count; ++i) {
3991 : if (threads_for_task[i] == mach_thread_self())
3992 : return i;
3993 : }
3994 : abort();
3995 : #else
3996 : # error "Unsupported platform"
3997 : #endif
3998 : }
3999 :
4000 : #ifdef XP_MACOSX
4001 : static mach_port_t
4002 : GetChildThread(ProcessHandle childPid, ThreadId childBlamedThread)
4003 : {
4004 : mach_port_t childThread = MACH_PORT_NULL;
4005 : thread_act_port_array_t threads_for_task;
4006 : mach_msg_type_number_t thread_count;
4007 :
4008 : if (task_threads(childPid, &threads_for_task, &thread_count)
4009 : == KERN_SUCCESS && childBlamedThread < thread_count) {
4010 : childThread = threads_for_task[childBlamedThread];
4011 : }
4012 :
4013 : return childThread;
4014 : }
4015 : #endif
4016 :
4017 0 : bool TakeMinidump(nsIFile** aResult, bool aMoveToPending)
4018 : {
4019 0 : if (!GetEnabled())
4020 0 : return false;
4021 :
4022 0 : AutoIOInterposerDisable disableIOInterposition;
4023 :
4024 0 : xpstring dump_path;
4025 : #ifndef XP_LINUX
4026 : dump_path = gExceptionHandler->dump_path();
4027 : #else
4028 0 : dump_path = gExceptionHandler->minidump_descriptor().directory();
4029 : #endif
4030 :
4031 : // capture the dump
4032 0 : if (!google_breakpad::ExceptionHandler::WriteMinidump(
4033 : dump_path,
4034 : #ifdef XP_MACOSX
4035 : true,
4036 : #endif
4037 : PairedDumpCallback,
4038 : static_cast<void*>(aResult)
4039 : #ifdef XP_WIN32
4040 : , GetMinidumpType()
4041 : #endif
4042 : )) {
4043 0 : return false;
4044 : }
4045 :
4046 0 : if (aMoveToPending) {
4047 0 : MoveToPending(*aResult, nullptr, nullptr);
4048 : }
4049 0 : return true;
4050 : }
4051 :
4052 : inline void
4053 0 : InvokeCallback(bool aAsync,
4054 : std::function<void()>&& aCallback,
4055 : RefPtr<nsIThread>&& aCallbackThread)
4056 : {
4057 0 : if (aAsync) {
4058 0 : MOZ_ASSERT(!!aCallbackThread);
4059 0 : Unused << aCallbackThread->Dispatch(NS_NewRunnableFunction("CrashReporter::InvokeCallback",
4060 0 : Move(aCallback)),
4061 0 : NS_DISPATCH_SYNC);
4062 : } else {
4063 0 : aCallback();
4064 : }
4065 0 : }
4066 :
4067 : void
4068 0 : CreateMinidumpsAndPairInternal(ProcessHandle aTargetPid,
4069 : ThreadId aTargetBlamedThread,
4070 : nsCString aIncomingPairName,
4071 : nsCOMPtr<nsIFile> aIncomingDumpToPair,
4072 : nsIFile** aMainDumpOut,
4073 : std::function<void(bool)>&& aCallback,
4074 : RefPtr<nsIThread>&& aCallbackThread,
4075 : bool aAsync)
4076 : {
4077 0 : AutoIOInterposerDisable disableIOInterposition;
4078 :
4079 : #ifdef XP_MACOSX
4080 : mach_port_t targetThread = GetChildThread(aTargetPid, aTargetBlamedThread);
4081 : #else
4082 0 : ThreadId targetThread = aTargetBlamedThread;
4083 : #endif
4084 :
4085 0 : xpstring dump_path;
4086 : #ifndef XP_LINUX
4087 : dump_path = gExceptionHandler->dump_path();
4088 : #else
4089 0 : dump_path = gExceptionHandler->minidump_descriptor().directory();
4090 : #endif
4091 :
4092 0 : std::function<void()> runnable;
4093 : // dump the target
4094 0 : nsCOMPtr<nsIFile> targetMinidump;
4095 0 : if (!google_breakpad::ExceptionHandler::WriteMinidumpForChild(
4096 : aTargetPid,
4097 : targetThread,
4098 : dump_path,
4099 : PairedDumpCallbackExtra,
4100 : static_cast<void*>(&targetMinidump)
4101 : #ifdef XP_WIN32
4102 : , GetMinidumpType()
4103 : #endif
4104 : )) {
4105 0 : runnable = [&](){
4106 0 : aCallback(false);
4107 0 : };
4108 0 : InvokeCallback(aAsync, Move(runnable), Move(aCallbackThread));
4109 0 : return;
4110 : }
4111 :
4112 0 : nsCOMPtr<nsIFile> targetExtra;
4113 0 : GetExtraFileForMinidump(targetMinidump, getter_AddRefs(targetExtra));
4114 :
4115 : // If aIncomingDumpToPair isn't valid, create a dump of this process.
4116 0 : nsCOMPtr<nsIFile> incomingDump;
4117 0 : if (aIncomingDumpToPair == nullptr) {
4118 0 : if (!google_breakpad::ExceptionHandler::WriteMinidump(
4119 : dump_path,
4120 : #ifdef XP_MACOSX
4121 : true,
4122 : #endif
4123 : PairedDumpCallback,
4124 : static_cast<void*>(&incomingDump)
4125 : #ifdef XP_WIN32
4126 : , GetMinidumpType()
4127 : #endif
4128 : )) {
4129 0 : runnable = [&](){
4130 0 : targetMinidump->Remove(false);
4131 0 : targetExtra->Remove(false);
4132 0 : aCallback(false);
4133 0 : };
4134 0 : InvokeCallback(aAsync, Move(runnable), Move(aCallbackThread));
4135 0 : return;
4136 : }
4137 : } else {
4138 0 : incomingDump = aIncomingDumpToPair;
4139 : }
4140 :
4141 0 : runnable = [&](){
4142 0 : RenameAdditionalHangMinidump(incomingDump, targetMinidump, aIncomingPairName);
4143 :
4144 0 : if (ShouldReport()) {
4145 0 : MoveToPending(targetMinidump, targetExtra, nullptr);
4146 0 : MoveToPending(incomingDump, nullptr, nullptr);
4147 : }
4148 :
4149 0 : targetMinidump.forget(aMainDumpOut);
4150 0 : aIncomingPairName = nullptr; // Release the ptr on the main thread.
4151 :
4152 0 : aCallback(true);
4153 0 : };
4154 0 : InvokeCallback(aAsync, Move(runnable), Move(aCallbackThread));
4155 : }
4156 :
4157 : void
4158 0 : CreateMinidumpsAndPair(ProcessHandle aTargetPid,
4159 : ThreadId aTargetBlamedThread,
4160 : const nsACString& aIncomingPairName,
4161 : nsIFile* aIncomingDumpToPair,
4162 : nsIFile** aMainDumpOut,
4163 : std::function<void(bool)>&& aCallback,
4164 : bool aAsync)
4165 : {
4166 0 : if (!GetEnabled()) {
4167 0 : aCallback(false);
4168 0 : return;
4169 : }
4170 :
4171 0 : if (aAsync &&
4172 0 : !sMinidumpWriterThread &&
4173 0 : NS_FAILED(NS_NewNamedThread("Minidump Writer", &sMinidumpWriterThread))) {
4174 0 : aCallback(false);
4175 0 : return;
4176 : }
4177 :
4178 0 : nsCOMPtr<nsIFile> incomingDumpToPair = aIncomingDumpToPair;
4179 0 : nsCString incomingPairName(aIncomingPairName);
4180 0 : std::function<void(bool)> callback = Move(aCallback);
4181 : // Don't call do_GetCurrentThread() is this is called synchronously because
4182 : // 1. it's unnecessary, and 2. more importantly, it might create one if called
4183 : // from a native thread, and the thread will be leakded.
4184 0 : RefPtr<nsIThread> callbackThread = aAsync ? do_GetCurrentThread() : nullptr;
4185 :
4186 0 : std::function<void()> doDump = [=]() mutable {
4187 0 : CreateMinidumpsAndPairInternal(aTargetPid,
4188 0 : aTargetBlamedThread,
4189 : incomingPairName,
4190 : incomingDumpToPair,
4191 0 : aMainDumpOut,
4192 0 : Move(callback),
4193 0 : Move(callbackThread),
4194 0 : aAsync);
4195 0 : };
4196 :
4197 0 : if (aAsync) {
4198 0 : sMinidumpWriterThread->Dispatch(NS_NewRunnableFunction("CrashReporter::CreateMinidumpsAndPair",
4199 0 : Move(doDump)),
4200 0 : nsIEventTarget::DISPATCH_NORMAL);
4201 : } else {
4202 0 : doDump();
4203 : }
4204 : }
4205 :
4206 : bool
4207 0 : CreateAdditionalChildMinidump(ProcessHandle childPid,
4208 : ThreadId childBlamedThread,
4209 : nsIFile* parentMinidump,
4210 : const nsACString& name)
4211 : {
4212 0 : if (!GetEnabled())
4213 0 : return false;
4214 :
4215 : #ifdef XP_MACOSX
4216 : mach_port_t childThread = GetChildThread(childPid, childBlamedThread);
4217 : #else
4218 0 : ThreadId childThread = childBlamedThread;
4219 : #endif
4220 :
4221 0 : xpstring dump_path;
4222 : #ifndef XP_LINUX
4223 : dump_path = gExceptionHandler->dump_path();
4224 : #else
4225 0 : dump_path = gExceptionHandler->minidump_descriptor().directory();
4226 : #endif
4227 :
4228 : // dump the child
4229 0 : nsCOMPtr<nsIFile> childMinidump;
4230 0 : if (!google_breakpad::ExceptionHandler::WriteMinidumpForChild(
4231 : childPid,
4232 : childThread,
4233 : dump_path,
4234 : PairedDumpCallback,
4235 : static_cast<void*>(&childMinidump)
4236 : #ifdef XP_WIN32
4237 : , GetMinidumpType()
4238 : #endif
4239 : )) {
4240 0 : return false;
4241 : }
4242 :
4243 0 : RenameAdditionalHangMinidump(childMinidump, parentMinidump, name);
4244 :
4245 0 : return true;
4246 : }
4247 :
4248 : bool
4249 0 : UnsetRemoteExceptionHandler()
4250 : {
4251 0 : std::set_terminate(oldTerminateHandler);
4252 0 : delete gExceptionHandler;
4253 0 : gExceptionHandler = nullptr;
4254 0 : return true;
4255 : }
4256 :
4257 : #if defined(MOZ_WIDGET_ANDROID)
4258 : void SetNotificationPipeForChild(int childCrashFd)
4259 : {
4260 : gMagicChildCrashReportFd = childCrashFd;
4261 : }
4262 :
4263 : void AddLibraryMapping(const char* library_name,
4264 : uintptr_t start_address,
4265 : size_t mapping_length,
4266 : size_t file_offset)
4267 : {
4268 : if (!gExceptionHandler) {
4269 : mapping_info info;
4270 : info.name = library_name;
4271 : info.start_address = start_address;
4272 : info.length = mapping_length;
4273 : info.file_offset = file_offset;
4274 : library_mappings.push_back(info);
4275 : }
4276 : else {
4277 : PageAllocator allocator;
4278 : auto_wasteful_vector<uint8_t, sizeof(MDGUID)> guid(&allocator);
4279 : FileID::ElfFileIdentifierFromMappedFile((void const *)start_address, guid);
4280 : gExceptionHandler->AddMappingInfo(library_name,
4281 : guid.data(),
4282 : start_address,
4283 : mapping_length,
4284 : file_offset);
4285 : }
4286 : }
4287 : #endif
4288 :
4289 9 : } // namespace CrashReporter
|