CLOSED TREE: TraceMonkey merge head. (a=blockers)
[mozilla-central.git] / toolkit / crashreporter / nsExceptionHandler.cpp
blob5346d2f7513f95612e00165e7ab2ee32182e4fdc
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is Mozilla Breakpad integration
17 * The Initial Developer of the Original Code is
18 * Ted Mielczarek <ted.mielczarek@gmail.com>
19 * Portions created by the Initial Developer are Copyright (C) 2006
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Josh Aas <josh@mozilla.com>
24 * Justin Dolske <dolske@mozilla.com>
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #include "nsExceptionHandler.h"
42 #if defined(XP_WIN32)
43 #ifdef WIN32_LEAN_AND_MEAN
44 #undef WIN32_LEAN_AND_MEAN
45 #endif
47 #include "nsIWindowsRegKey.h"
48 #if defined(MOZ_IPC)
49 # include "client/windows/crash_generation/crash_generation_server.h"
50 #endif
51 #include "client/windows/handler/exception_handler.h"
52 #include <DbgHelp.h>
53 #include <string.h>
54 #elif defined(XP_MACOSX)
55 #if defined(MOZ_IPC)
56 # include "client/mac/crash_generation/client_info.h"
57 # include "client/mac/crash_generation/crash_generation_server.h"
58 #endif
59 #include "client/mac/handler/exception_handler.h"
60 #include <string>
61 #include <Carbon/Carbon.h>
62 #include <CoreFoundation/CoreFoundation.h>
63 #include <crt_externs.h>
64 #include <fcntl.h>
65 #include <mach/mach.h>
66 #include <sys/types.h>
67 #include <spawn.h>
68 #include <unistd.h>
69 #include "mac_utils.h"
70 #elif defined(XP_LINUX)
71 #include "nsDirectoryServiceUtils.h"
72 #include "nsDirectoryServiceDefs.h"
73 #include "nsIINIParser.h"
74 #include "common/linux/linux_libc_support.h"
75 #include "common/linux/linux_syscall_support.h"
76 #if defined(MOZ_IPC)
77 # include "client/linux/crash_generation/client_info.h"
78 # include "client/linux/crash_generation/crash_generation_server.h"
79 #endif
80 #include "client/linux/handler/exception_handler.h"
81 #include "client/linux/minidump_writer/linux_dumper.h"
82 #include "client/linux/minidump_writer/minidump_writer.h"
83 #include <fcntl.h>
84 #include <sys/types.h>
85 #include <unistd.h>
86 #elif defined(XP_SOLARIS)
87 #include "client/solaris/handler/exception_handler.h"
88 #include <fcntl.h>
89 #include <sys/types.h>
90 #include <unistd.h>
91 #else
92 #error "Not yet implemented for this platform"
93 #endif // defined(XP_WIN32)
95 #include <stdlib.h>
96 #include <time.h>
97 #include <prenv.h>
98 #include <prio.h>
99 #include <prmem.h>
100 #include "mozilla/Mutex.h"
101 #include "nsDebug.h"
102 #include "nsCRT.h"
103 #include "nsILocalFile.h"
104 #include "nsIFileStreams.h"
105 #include "nsInterfaceHashtable.h"
106 #include "prprf.h"
107 #include "nsIXULAppInfo.h"
108 #include <map>
109 #include <vector>
111 #if defined(XP_MACOSX)
112 CFStringRef reporterClientAppID = CFSTR("org.mozilla.crashreporter");
113 #endif
115 #if defined(MOZ_IPC)
116 #include "nsIUUIDGenerator.h"
118 using google_breakpad::CrashGenerationServer;
119 using google_breakpad::ClientInfo;
120 using mozilla::Mutex;
121 using mozilla::MutexAutoLock;
122 #endif // MOZ_IPC
124 namespace CrashReporter {
126 #ifdef XP_WIN32
127 typedef wchar_t XP_CHAR;
128 typedef std::wstring xpstring;
129 #define CONVERT_UTF16_TO_XP_CHAR(x) x
130 #define CONVERT_XP_CHAR_TO_UTF16(x) x
131 #define XP_STRLEN(x) wcslen(x)
132 #define my_strlen strlen
133 #define CRASH_REPORTER_FILENAME "crashreporter.exe"
134 #define PATH_SEPARATOR "\\"
135 #define XP_PATH_SEPARATOR L"\\"
136 // sort of arbitrary, but MAX_PATH is kinda small
137 #define XP_PATH_MAX 4096
138 // "<reporter path>" "<minidump path>"
139 #define CMDLINE_SIZE ((XP_PATH_MAX * 2) + 6)
140 #ifdef _USE_32BIT_TIME_T
141 #define XP_TTOA(time, buffer, base) ltoa(time, buffer, base)
142 #else
143 #define XP_TTOA(time, buffer, base) _i64toa(time, buffer, base)
144 #endif
145 #else
146 typedef char XP_CHAR;
147 typedef std::string xpstring;
148 #define CONVERT_UTF16_TO_XP_CHAR(x) NS_ConvertUTF16toUTF8(x)
149 #define CONVERT_XP_CHAR_TO_UTF16(x) NS_ConvertUTF8toUTF16(x)
150 #define CRASH_REPORTER_FILENAME "crashreporter"
151 #define PATH_SEPARATOR "/"
152 #define XP_PATH_SEPARATOR "/"
153 #define XP_PATH_MAX PATH_MAX
154 #ifdef XP_LINUX
155 #define XP_STRLEN(x) my_strlen(x)
156 #define XP_TTOA(time, buffer, base) my_timetostring(time, buffer, sizeof(buffer))
157 #else
158 #define XP_STRLEN(x) strlen(x)
159 #define XP_TTOA(time, buffer, base) sprintf(buffer, "%ld", time)
160 #define my_strlen strlen
161 #define sys_close close
162 #define sys_fork fork
163 #define sys_open open
164 #define sys_write write
165 #endif
166 #endif // XP_WIN32
168 static const XP_CHAR dumpFileExtension[] = {'.', 'd', 'm', 'p',
169 '\0'}; // .dmp
170 static const XP_CHAR extraFileExtension[] = {'.', 'e', 'x', 't',
171 'r', 'a', '\0'}; // .extra
173 static google_breakpad::ExceptionHandler* gExceptionHandler = nsnull;
175 static XP_CHAR* crashReporterPath;
177 // if this is false, we don't launch the crash reporter
178 static bool doReport = true;
180 // if this is true, we pass the exception on to the OS crash reporter
181 static bool showOSCrashReporter = false;
183 // The time of the last recorded crash, as a time_t value.
184 static time_t lastCrashTime = 0;
185 // The pathname of a file to store the crash time in
186 static XP_CHAR lastCrashTimeFilename[XP_PATH_MAX] = {0};
188 // these are just here for readability
189 static const char kCrashTimeParameter[] = "CrashTime=";
190 static const int kCrashTimeParameterLen = sizeof(kCrashTimeParameter)-1;
192 static const char kTimeSinceLastCrashParameter[] = "SecondsSinceLastCrash=";
193 static const int kTimeSinceLastCrashParameterLen =
194 sizeof(kTimeSinceLastCrashParameter)-1;
196 static const char kSysMemoryParameter[] = "SystemMemoryUsePercentage=";
197 static const int kSysMemoryParameterLen = sizeof(kSysMemoryParameter)-1;
199 static const char kTotalVirtualMemoryParameter[] = "TotalVirtualMemory=";
200 static const int kTotalVirtualMemoryParameterLen =
201 sizeof(kTotalVirtualMemoryParameter)-1;
203 static const char kAvailableVirtualMemoryParameter[] = "AvailableVirtualMemory=";
204 static const int kAvailableVirtualMemoryParameterLen =
205 sizeof(kAvailableVirtualMemoryParameter)-1;
207 // this holds additional data sent via the API
208 static AnnotationTable* crashReporterAPIData_Hash;
209 static nsCString* crashReporterAPIData = nsnull;
210 static nsCString* notesField = nsnull;
212 #if defined(MOZ_IPC)
213 // OOP crash reporting
214 static CrashGenerationServer* crashServer; // chrome process has this
216 # if defined(XP_WIN) || defined(XP_MACOSX)
217 // If crash reporting is disabled, we hand out this "null" pipe to the
218 // child process and don't attempt to connect to a parent server.
219 static const char kNullNotifyPipe[] = "-";
220 static char* childCrashNotifyPipe;
222 # elif defined(XP_LINUX)
223 static int serverSocketFd = -1;
224 static int clientSocketFd = -1;
225 static const int kMagicChildCrashReportFd = 4;
227 # endif
229 // |dumpMapLock| must protect all access to |pidToMinidump|.
230 static Mutex* dumpMapLock;
231 typedef nsInterfaceHashtable<nsUint32HashKey, nsILocalFile> ChildMinidumpMap;
232 static ChildMinidumpMap* pidToMinidump;
234 // Crashreporter annotations that we don't send along in subprocess
235 // reports
236 static const char* kSubprocessBlacklist[] = {
237 "FramePoisonBase",
238 "FramePoisonSize",
239 "StartupTime",
240 "URL"
244 #endif // MOZ_IPC
246 #ifdef XP_MACOSX
247 static cpu_type_t pref_cpu_types[2] = {
248 #if defined(__i386__)
249 CPU_TYPE_X86,
250 #elif defined(__x86_64__)
251 CPU_TYPE_X86_64,
252 #elif defined(__ppc__)
253 CPU_TYPE_POWERPC,
254 #endif
255 CPU_TYPE_ANY };
257 static posix_spawnattr_t spawnattr;
258 #endif
260 #if defined(__ANDROID__)
261 // Android builds use a custom library loader,
262 // so the embedding will provide a list of shared
263 // libraries that are mapped into anonymous mappings.
264 typedef struct {
265 std::string name;
266 std::string debug_id;
267 uintptr_t start_address;
268 size_t length;
269 size_t file_offset;
270 } mapping_info;
271 static std::vector<mapping_info> library_mappings;
272 typedef std::map<PRUint32,google_breakpad::MappingList> MappingMap;
273 static MappingMap child_library_mappings;
275 void FileIDToGUID(const char* file_id, u_int8_t guid[sizeof(MDGUID)])
277 for (int i = 0; i < sizeof(MDGUID); i++) {
278 int c;
279 sscanf(file_id, "%02X", &c);
280 guid[i] = (u_int8_t)(c & 0xFF);
281 file_id += 2;
283 // GUIDs are stored in network byte order.
284 uint32_t* data1 = reinterpret_cast<uint32_t*>(guid);
285 *data1 = htonl(*data1);
286 uint16_t* data2 = reinterpret_cast<uint16_t*>(guid + 4);
287 *data2 = htons(*data2);
288 uint16_t* data3 = reinterpret_cast<uint16_t*>(guid + 6);
289 *data3 = htons(*data3);
291 #endif
293 #ifdef XP_LINUX
294 inline void
295 my_timetostring(time_t t, char* buffer, size_t buffer_length)
297 my_memset(buffer, 0, buffer_length);
298 my_itos(buffer, t, my_int_len(t));
300 #endif
302 #ifdef XP_WIN
303 static void
304 CreateFileFromPath(const xpstring& path, nsILocalFile** file)
306 NS_NewLocalFile(nsDependentString(path.c_str()), PR_FALSE, file);
308 #else
309 static void
310 CreateFileFromPath(const xpstring& path, nsILocalFile** file)
312 NS_NewNativeLocalFile(nsDependentCString(path.c_str()), PR_FALSE, file);
314 #endif
316 static XP_CHAR*
317 Concat(XP_CHAR* str, const XP_CHAR* toAppend, int* size)
319 int appendLen = XP_STRLEN(toAppend);
320 if (appendLen >= *size) appendLen = *size - 1;
322 memcpy(str, toAppend, appendLen * sizeof(XP_CHAR));
323 str += appendLen;
324 *str = '\0';
325 *size -= appendLen;
327 return str;
330 bool MinidumpCallback(const XP_CHAR* dump_path,
331 const XP_CHAR* minidump_id,
332 void* context,
333 #ifdef XP_WIN32
334 EXCEPTION_POINTERS* exinfo,
335 MDRawAssertionInfo* assertion,
336 #endif
337 bool succeeded)
339 bool returnValue = showOSCrashReporter ? false : succeeded;
341 static XP_CHAR minidumpPath[XP_PATH_MAX];
342 int size = XP_PATH_MAX;
343 XP_CHAR* p = Concat(minidumpPath, dump_path, &size);
344 p = Concat(p, XP_PATH_SEPARATOR, &size);
345 p = Concat(p, minidump_id, &size);
346 Concat(p, dumpFileExtension, &size);
348 static XP_CHAR extraDataPath[XP_PATH_MAX];
349 size = XP_PATH_MAX;
350 p = Concat(extraDataPath, dump_path, &size);
351 p = Concat(p, XP_PATH_SEPARATOR, &size);
352 p = Concat(p, minidump_id, &size);
353 Concat(p, extraFileExtension, &size);
355 // calculate time since last crash (if possible), and store
356 // the time of this crash.
357 time_t crashTime;
358 #ifdef XP_LINUX
359 struct kernel_timeval tv;
360 sys_gettimeofday(&tv, NULL);
361 crashTime = tv.tv_sec;
362 #else
363 crashTime = time(NULL);
364 #endif
365 time_t timeSinceLastCrash = 0;
366 // stringified versions of the above
367 char crashTimeString[32];
368 int crashTimeStringLen = 0;
369 char timeSinceLastCrashString[32];
370 int timeSinceLastCrashStringLen = 0;
372 XP_TTOA(crashTime, crashTimeString, 10);
373 crashTimeStringLen = my_strlen(crashTimeString);
374 if (lastCrashTime != 0) {
375 timeSinceLastCrash = crashTime - lastCrashTime;
376 XP_TTOA(timeSinceLastCrash, timeSinceLastCrashString, 10);
377 timeSinceLastCrashStringLen = my_strlen(timeSinceLastCrashString);
379 // write crash time to file
380 if (lastCrashTimeFilename[0] != 0) {
381 #if defined(XP_WIN32)
382 HANDLE hFile = CreateFile(lastCrashTimeFilename, GENERIC_WRITE, 0,
383 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
384 NULL);
385 if(hFile != INVALID_HANDLE_VALUE) {
386 DWORD nBytes;
387 WriteFile(hFile, crashTimeString, crashTimeStringLen, &nBytes, NULL);
388 CloseHandle(hFile);
390 #elif defined(XP_UNIX)
391 int fd = sys_open(lastCrashTimeFilename,
392 O_WRONLY | O_CREAT | O_TRUNC,
393 0600);
394 if (fd != -1) {
395 ssize_t ignored = sys_write(fd, crashTimeString, crashTimeStringLen);
396 (void)ignored;
397 sys_close(fd);
399 #endif
402 #if defined(XP_WIN32)
403 XP_CHAR cmdLine[CMDLINE_SIZE];
404 size = CMDLINE_SIZE;
405 p = Concat(cmdLine, L"\"", &size);
406 p = Concat(p, crashReporterPath, &size);
407 p = Concat(p, L"\" \"", &size);
408 p = Concat(p, minidumpPath, &size);
409 Concat(p, L"\"", &size);
411 if (!crashReporterAPIData->IsEmpty()) {
412 // write out API data
413 HANDLE hFile = CreateFile(extraDataPath, GENERIC_WRITE, 0,
414 NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
415 NULL);
416 if(hFile != INVALID_HANDLE_VALUE) {
417 DWORD nBytes;
418 WriteFile(hFile, crashReporterAPIData->get(),
419 crashReporterAPIData->Length(), &nBytes, NULL);
420 WriteFile(hFile, kCrashTimeParameter, kCrashTimeParameterLen,
421 &nBytes, NULL);
422 WriteFile(hFile, crashTimeString, crashTimeStringLen, &nBytes, NULL);
423 WriteFile(hFile, "\n", 1, &nBytes, NULL);
424 if (timeSinceLastCrash != 0) {
425 WriteFile(hFile, kTimeSinceLastCrashParameter,
426 kTimeSinceLastCrashParameterLen, &nBytes, NULL);
427 WriteFile(hFile, timeSinceLastCrashString, timeSinceLastCrashStringLen,
428 &nBytes, NULL);
429 WriteFile(hFile, "\n", 1, &nBytes, NULL);
431 // Try to get some information about memory.
432 MEMORYSTATUSEX statex;
433 statex.dwLength = sizeof(statex);
434 if (GlobalMemoryStatusEx(&statex)) {
435 char buffer[128];
436 int bufferLen;
437 WriteFile(hFile, kSysMemoryParameter,
438 kSysMemoryParameterLen, &nBytes, NULL);
439 ltoa(statex.dwMemoryLoad, buffer, 10);
440 bufferLen = strlen(buffer);
441 WriteFile(hFile, buffer, bufferLen,
442 &nBytes, NULL);
443 WriteFile(hFile, "\n", 1, &nBytes, NULL);
444 WriteFile(hFile, kTotalVirtualMemoryParameter,
445 kTotalVirtualMemoryParameterLen, &nBytes, NULL);
446 _ui64toa(statex.ullTotalVirtual, buffer, 10);
447 bufferLen = strlen(buffer);
448 WriteFile(hFile, buffer, bufferLen,
449 &nBytes, NULL);
450 WriteFile(hFile, "\n", 1, &nBytes, NULL);
451 WriteFile(hFile, kAvailableVirtualMemoryParameter,
452 kAvailableVirtualMemoryParameterLen, &nBytes, NULL);
453 _ui64toa(statex.ullAvailVirtual, buffer, 10);
454 bufferLen = strlen(buffer);
455 WriteFile(hFile, buffer, bufferLen,
456 &nBytes, NULL);
457 WriteFile(hFile, "\n", 1, &nBytes, NULL);
459 CloseHandle(hFile);
463 if (!doReport) {
464 return returnValue;
467 STARTUPINFO si;
468 PROCESS_INFORMATION pi;
470 ZeroMemory(&si, sizeof(si));
471 si.cb = sizeof(si);
472 si.dwFlags = STARTF_USESHOWWINDOW;
473 si.wShowWindow = SW_SHOWNORMAL;
474 ZeroMemory(&pi, sizeof(pi));
476 if (CreateProcess(NULL, (LPWSTR)cmdLine, NULL, NULL, FALSE, 0,
477 NULL, NULL, &si, &pi)) {
478 CloseHandle( pi.hProcess );
479 CloseHandle( pi.hThread );
481 // we're not really in a position to do anything if the CreateProcess fails
482 TerminateProcess(GetCurrentProcess(), 1);
483 #elif defined(XP_UNIX)
484 if (!crashReporterAPIData->IsEmpty()) {
485 // write out API data
486 int fd = sys_open(extraDataPath,
487 O_WRONLY | O_CREAT | O_TRUNC,
488 0666);
490 if (fd != -1) {
491 // not much we can do in case of error
492 ssize_t ignored = sys_write(fd, crashReporterAPIData->get(),
493 crashReporterAPIData->Length());
494 ignored = sys_write(fd, kCrashTimeParameter, kCrashTimeParameterLen);
495 ignored = sys_write(fd, crashTimeString, crashTimeStringLen);
496 ignored = sys_write(fd, "\n", 1);
497 if (timeSinceLastCrash != 0) {
498 ignored = sys_write(fd, kTimeSinceLastCrashParameter,
499 kTimeSinceLastCrashParameterLen);
500 ignored = sys_write(fd, timeSinceLastCrashString,
501 timeSinceLastCrashStringLen);
502 ignored = sys_write(fd, "\n", 1);
504 sys_close(fd);
508 if (!doReport) {
509 return returnValue;
512 #ifdef XP_MACOSX
513 char* const my_argv[] = {
514 crashReporterPath,
515 minidumpPath,
516 NULL
519 char **env = NULL;
520 char ***nsEnv = _NSGetEnviron();
521 if (nsEnv)
522 env = *nsEnv;
523 int result = posix_spawnp(NULL,
524 my_argv[0],
525 NULL,
526 &spawnattr,
527 my_argv,
528 env);
530 if (result != 0)
531 return false;
533 #else // !XP_MACOSX
534 pid_t pid = sys_fork();
536 if (pid == -1)
537 return false;
538 else if (pid == 0) {
539 #if !defined(__ANDROID__)
540 // need to clobber this, as libcurl might load NSS,
541 // and we want it to load the system NSS.
542 unsetenv("LD_LIBRARY_PATH");
543 (void) execl(crashReporterPath,
544 crashReporterPath, minidumpPath, (char*)0);
545 #else
546 // Invoke the reportCrash activity using am
547 (void) execlp("/system/bin/am",
548 "/system/bin/am",
549 "start",
550 "-a", "org.mozilla.gecko.reportCrash",
551 "-n", crashReporterPath,
552 "--es", "minidumpPath", minidumpPath,
553 (char*)0);
554 #endif
555 _exit(1);
557 #endif // XP_MACOSX
558 #endif // XP_UNIX
560 return returnValue;
563 #ifdef XP_WIN
565 * Filters out floating point exceptions which are handled by nsSigHandlers.cpp
566 * and should not be handled as crashes.
568 static bool FPEFilter(void* context, EXCEPTION_POINTERS* exinfo,
569 MDRawAssertionInfo* assertion)
571 if (!exinfo)
572 return true;
574 PEXCEPTION_RECORD e = (PEXCEPTION_RECORD)exinfo->ExceptionRecord;
575 switch (e->ExceptionCode) {
576 case STATUS_FLOAT_DENORMAL_OPERAND:
577 case STATUS_FLOAT_DIVIDE_BY_ZERO:
578 case STATUS_FLOAT_INEXACT_RESULT:
579 case STATUS_FLOAT_INVALID_OPERATION:
580 case STATUS_FLOAT_OVERFLOW:
581 case STATUS_FLOAT_STACK_CHECK:
582 case STATUS_FLOAT_UNDERFLOW:
583 case STATUS_FLOAT_MULTIPLE_FAULTS:
584 case STATUS_FLOAT_MULTIPLE_TRAPS:
585 return false; // Don't write minidump, continue exception search
587 return true;
589 #endif // XP_WIN
591 static bool ShouldReport()
593 // this environment variable prevents us from launching
594 // the crash reporter client
595 const char *envvar = PR_GetEnv("MOZ_CRASHREPORTER_NO_REPORT");
596 return !(envvar && *envvar);
599 nsresult SetExceptionHandler(nsILocalFile* aXREDirectory,
600 bool force/*=false*/)
602 nsresult rv;
604 if (gExceptionHandler)
605 return NS_ERROR_ALREADY_INITIALIZED;
607 const char *envvar = PR_GetEnv("MOZ_CRASHREPORTER_DISABLE");
608 if (envvar && *envvar && !force)
609 return NS_OK;
611 // this environment variable prevents us from launching
612 // the crash reporter client
613 doReport = ShouldReport();
615 // allocate our strings
616 crashReporterAPIData = new nsCString();
617 NS_ENSURE_TRUE(crashReporterAPIData, NS_ERROR_OUT_OF_MEMORY);
619 crashReporterAPIData_Hash =
620 new nsDataHashtable<nsCStringHashKey,nsCString>();
621 NS_ENSURE_TRUE(crashReporterAPIData_Hash, NS_ERROR_OUT_OF_MEMORY);
623 rv = crashReporterAPIData_Hash->Init();
624 NS_ENSURE_SUCCESS(rv, rv);
626 notesField = new nsCString();
627 NS_ENSURE_TRUE(notesField, NS_ERROR_OUT_OF_MEMORY);
629 // locate crashreporter executable
630 nsCOMPtr<nsIFile> exePath;
631 rv = aXREDirectory->Clone(getter_AddRefs(exePath));
632 NS_ENSURE_SUCCESS(rv, rv);
634 #if defined(XP_MACOSX)
635 exePath->Append(NS_LITERAL_STRING("crashreporter.app"));
636 exePath->Append(NS_LITERAL_STRING("Contents"));
637 exePath->Append(NS_LITERAL_STRING("MacOS"));
638 #endif
640 exePath->AppendNative(NS_LITERAL_CSTRING(CRASH_REPORTER_FILENAME));
642 #ifdef XP_WIN32
643 nsString crashReporterPath_temp;
644 exePath->GetPath(crashReporterPath_temp);
646 crashReporterPath = ToNewUnicode(crashReporterPath_temp);
647 #elif !defined(__ANDROID__)
648 nsCString crashReporterPath_temp;
649 exePath->GetNativePath(crashReporterPath_temp);
651 crashReporterPath = ToNewCString(crashReporterPath_temp);
652 #else
653 // On Android, we launch using the application package name
654 // instead of a filename, so use ANDROID_PACKAGE_NAME to do that here.
655 //TODO: don't hardcode org.mozilla here, so other vendors can
656 // ship XUL apps with different package names on Android?
657 nsCString package(ANDROID_PACKAGE_NAME "/.CrashReporter");
658 crashReporterPath = ToNewCString(package);
659 #endif
661 // get temp path to use for minidump path
662 #if defined(XP_WIN32)
663 nsString tempPath;
665 // first figure out buffer size
666 int pathLen = GetTempPath(0, NULL);
667 if (pathLen == 0)
668 return NS_ERROR_FAILURE;
670 tempPath.SetLength(pathLen);
671 GetTempPath(pathLen, (LPWSTR)tempPath.BeginWriting());
672 #elif defined(XP_MACOSX)
673 nsCString tempPath;
674 FSRef fsRef;
675 OSErr err = FSFindFolder(kUserDomain, kTemporaryFolderType,
676 kCreateFolder, &fsRef);
677 if (err != noErr)
678 return NS_ERROR_FAILURE;
680 char path[PATH_MAX];
681 OSStatus status = FSRefMakePath(&fsRef, (UInt8*)path, PATH_MAX);
682 if (status != noErr)
683 return NS_ERROR_FAILURE;
685 tempPath = path;
687 #elif defined(__ANDROID__)
688 // GeckoAppShell sets this in the environment
689 const char *tempenv = PR_GetEnv("TMPDIR");
690 if (!tempenv)
691 return NS_ERROR_FAILURE;
692 nsCString tempPath(tempenv);
694 #elif defined(XP_UNIX)
695 // we assume it's always /tmp on unix systems
696 nsCString tempPath = NS_LITERAL_CSTRING("/tmp/");
697 #else
698 #error "Implement this for your platform"
699 #endif
701 #ifdef XP_MACOSX
702 // Initialize spawn attributes, since this calls malloc.
703 if (posix_spawnattr_init(&spawnattr) != 0) {
704 return NS_ERROR_FAILURE;
707 // Set spawn attributes.
708 size_t attr_count = NS_ARRAY_LENGTH(pref_cpu_types);
709 size_t attr_ocount = 0;
710 if (posix_spawnattr_setbinpref_np(&spawnattr,
711 attr_count,
712 pref_cpu_types,
713 &attr_ocount) != 0 ||
714 attr_ocount != attr_count) {
715 posix_spawnattr_destroy(&spawnattr);
716 return NS_ERROR_FAILURE;
718 #endif
720 #ifdef XP_WIN32
721 MINIDUMP_TYPE minidump_type = MiniDumpNormal;
723 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
724 // Try to determine what version of dbghelp.dll we're using.
725 // MinidumpWithFullMemoryInfo is only available in 6.1.x or newer.
727 DWORD version_size = GetFileVersionInfoSizeW(L"dbghelp.dll", NULL);
728 if (version_size > 0) {
729 std::vector<BYTE> buffer(version_size);
730 if (GetFileVersionInfoW(L"dbghelp.dll",
732 version_size,
733 &buffer[0])) {
734 UINT len;
735 VS_FIXEDFILEINFO* file_info;
736 VerQueryValue(&buffer[0], L"\\", (void**)&file_info, &len);
737 WORD major = HIWORD(file_info->dwFileVersionMS),
738 minor = LOWORD(file_info->dwFileVersionMS),
739 revision = HIWORD(file_info->dwFileVersionLS);
740 if (major > 6 || (major == 6 && minor > 1) ||
741 (major == 6 && minor == 1 && revision >= 7600)) {
742 minidump_type = MiniDumpWithFullMemoryInfo;
746 #endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
747 #endif // XP_WIN32
749 // now set the exception handler
750 gExceptionHandler = new google_breakpad::
751 ExceptionHandler(tempPath.get(),
752 #ifdef XP_WIN
753 FPEFilter,
754 #else
755 nsnull,
756 #endif
757 MinidumpCallback,
758 nsnull,
759 #if defined(XP_WIN32)
760 google_breakpad::ExceptionHandler::HANDLER_ALL,
761 minidump_type,
762 NULL,
763 NULL);
764 #else
765 true
766 #if defined(XP_MACOSX)
767 , NULL
768 #endif
770 #endif // XP_WIN32
772 if (!gExceptionHandler)
773 return NS_ERROR_OUT_OF_MEMORY;
775 #ifdef XP_WIN
776 gExceptionHandler->set_handle_debug_exceptions(true);
777 #endif
779 // store application start time
780 char timeString[32];
781 time_t startupTime = time(NULL);
782 XP_TTOA(startupTime, timeString, 10);
783 AnnotateCrashReport(NS_LITERAL_CSTRING("StartupTime"),
784 nsDependentCString(timeString));
786 #if defined(XP_MACOSX)
787 // On OS X, many testers like to see the OS crash reporting dialog
788 // since it offers immediate stack traces. We allow them to set
789 // a default to pass exceptions to the OS handler.
790 Boolean keyExistsAndHasValidFormat = false;
791 Boolean prefValue = ::CFPreferencesGetAppBooleanValue(CFSTR("OSCrashReporter"),
792 kCFPreferencesCurrentApplication,
793 &keyExistsAndHasValidFormat);
794 if (keyExistsAndHasValidFormat)
795 showOSCrashReporter = prefValue;
796 #endif
798 #if defined(__ANDROID__)
799 for (unsigned int i = 0; i < library_mappings.size(); i++) {
800 u_int8_t guid[sizeof(MDGUID)];
801 FileIDToGUID(library_mappings[i].debug_id.c_str(), guid);
802 gExceptionHandler->AddMappingInfo(library_mappings[i].name,
803 guid,
804 library_mappings[i].start_address,
805 library_mappings[i].length,
806 library_mappings[i].file_offset);
808 #endif
810 return NS_OK;
813 bool GetEnabled()
815 return gExceptionHandler != nsnull && !gExceptionHandler->IsOutOfProcess();
818 bool GetMinidumpPath(nsAString& aPath)
820 if (!gExceptionHandler)
821 return false;
823 aPath = CONVERT_XP_CHAR_TO_UTF16(gExceptionHandler->dump_path().c_str());
824 return true;
827 nsresult SetMinidumpPath(const nsAString& aPath)
829 if (!gExceptionHandler)
830 return NS_ERROR_NOT_INITIALIZED;
832 gExceptionHandler->set_dump_path(CONVERT_UTF16_TO_XP_CHAR(aPath).BeginReading());
834 return NS_OK;
837 static nsresult
838 WriteDataToFile(nsIFile* aFile, const nsACString& data)
840 nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(aFile);
841 NS_ENSURE_TRUE(localFile, NS_ERROR_FAILURE);
843 PRFileDesc* fd;
844 nsresult rv = localFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE, 00600,
845 &fd);
846 NS_ENSURE_SUCCESS(rv, rv);
848 rv = NS_OK;
849 if (PR_Write(fd, data.Data(), data.Length()) == -1) {
850 rv = NS_ERROR_FAILURE;
852 PR_Close(fd);
853 return rv;
856 static nsresult
857 GetFileContents(nsIFile* aFile, nsACString& data)
859 nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(aFile);
860 NS_ENSURE_TRUE(localFile, NS_ERROR_FAILURE);
862 PRFileDesc* fd;
863 nsresult rv = localFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
864 NS_ENSURE_SUCCESS(rv, rv);
866 rv = NS_OK;
867 PRInt32 filesize = PR_Available(fd);
868 if (filesize <= 0) {
869 rv = NS_ERROR_FILE_NOT_FOUND;
871 else {
872 data.SetLength(filesize);
873 if (PR_Read(fd, data.BeginWriting(), filesize) == -1) {
874 rv = NS_ERROR_FAILURE;
877 PR_Close(fd);
878 return rv;
881 // Function typedef for initializing a piece of data that we
882 // don't already have.
883 typedef nsresult (*InitDataFunc)(nsACString&);
885 // Attempt to read aFile's contents into aContents, if aFile
886 // does not exist, create it and initialize its contents
887 // by calling aInitFunc for the data.
888 static nsresult
889 GetOrInit(nsIFile* aDir, const nsACString& filename,
890 nsACString& aContents, InitDataFunc aInitFunc)
892 PRBool exists;
894 nsCOMPtr<nsIFile> dataFile;
895 nsresult rv = aDir->Clone(getter_AddRefs(dataFile));
896 NS_ENSURE_SUCCESS(rv, rv);
898 rv = dataFile->AppendNative(filename);
899 NS_ENSURE_SUCCESS(rv, rv);
901 rv = dataFile->Exists(&exists);
902 NS_ENSURE_SUCCESS(rv, rv);
904 if (!exists) {
905 if (aInitFunc) {
906 // get the initial value and write it to the file
907 rv = aInitFunc(aContents);
908 NS_ENSURE_SUCCESS(rv, rv);
909 rv = WriteDataToFile(dataFile, aContents);
911 else {
912 // didn't pass in an init func
913 rv = NS_ERROR_FAILURE;
916 else {
917 // just get the file's contents
918 rv = GetFileContents(dataFile, aContents);
921 return rv;
924 // Init the "install time" data. We're taking an easy way out here
925 // and just setting this to "the time when this version was first run".
926 static nsresult
927 InitInstallTime(nsACString& aInstallTime)
929 time_t t = time(NULL);
930 char buf[16];
931 sprintf(buf, "%ld", t);
932 aInstallTime = buf;
934 return NS_OK;
937 // Annotate the crash report with a Unique User ID and time
938 // since install. Also do some prep work for recording
939 // time since last crash, which must be calculated at
940 // crash time.
941 // If any piece of data doesn't exist, initialize it first.
942 nsresult SetupExtraData(nsILocalFile* aAppDataDirectory,
943 const nsACString& aBuildID)
945 nsCOMPtr<nsIFile> dataDirectory;
946 nsresult rv = aAppDataDirectory->Clone(getter_AddRefs(dataDirectory));
947 NS_ENSURE_SUCCESS(rv, rv);
949 rv = dataDirectory->AppendNative(NS_LITERAL_CSTRING("Crash Reports"));
950 NS_ENSURE_SUCCESS(rv, rv);
952 PRBool exists;
953 rv = dataDirectory->Exists(&exists);
954 NS_ENSURE_SUCCESS(rv, rv);
956 if (!exists) {
957 rv = dataDirectory->Create(nsIFile::DIRECTORY_TYPE, 0700);
958 NS_ENSURE_SUCCESS(rv, rv);
961 #if defined(XP_WIN32)
962 nsAutoString dataDirEnv(NS_LITERAL_STRING("MOZ_CRASHREPORTER_DATA_DIRECTORY="));
964 nsAutoString dataDirectoryPath;
965 rv = dataDirectory->GetPath(dataDirectoryPath);
966 NS_ENSURE_SUCCESS(rv, rv);
968 dataDirEnv.Append(dataDirectoryPath);
970 _wputenv(dataDirEnv.get());
971 #else
972 // Save this path in the environment for the crash reporter application.
973 nsCAutoString dataDirEnv("MOZ_CRASHREPORTER_DATA_DIRECTORY=");
975 nsCAutoString dataDirectoryPath;
976 rv = dataDirectory->GetNativePath(dataDirectoryPath);
977 NS_ENSURE_SUCCESS(rv, rv);
979 dataDirEnv.Append(dataDirectoryPath);
981 char* env = ToNewCString(dataDirEnv);
982 NS_ENSURE_TRUE(env, NS_ERROR_OUT_OF_MEMORY);
984 PR_SetEnv(env);
985 #endif
987 nsCAutoString data;
988 if(NS_SUCCEEDED(GetOrInit(dataDirectory,
989 NS_LITERAL_CSTRING("InstallTime") + aBuildID,
990 data, InitInstallTime)))
991 AnnotateCrashReport(NS_LITERAL_CSTRING("InstallTime"), data);
993 // this is a little different, since we can't init it with anything,
994 // since it's stored at crash time, and we can't annotate the
995 // crash report with the stored value, since we really want
996 // (now - LastCrash), so we just get a value if it exists,
997 // and store it in a time_t value.
998 if(NS_SUCCEEDED(GetOrInit(dataDirectory, NS_LITERAL_CSTRING("LastCrash"),
999 data, NULL))) {
1000 lastCrashTime = (time_t)atol(data.get());
1003 // not really the best place to init this, but I have the path I need here
1004 nsCOMPtr<nsIFile> lastCrashFile;
1005 rv = dataDirectory->Clone(getter_AddRefs(lastCrashFile));
1006 NS_ENSURE_SUCCESS(rv, rv);
1008 rv = lastCrashFile->AppendNative(NS_LITERAL_CSTRING("LastCrash"));
1009 NS_ENSURE_SUCCESS(rv, rv);
1010 memset(lastCrashTimeFilename, 0, sizeof(lastCrashTimeFilename));
1012 #if defined(XP_WIN32)
1013 nsAutoString filename;
1014 rv = lastCrashFile->GetPath(filename);
1015 NS_ENSURE_SUCCESS(rv, rv);
1017 if (filename.Length() < XP_PATH_MAX)
1018 wcsncpy(lastCrashTimeFilename, filename.get(), filename.Length());
1019 #else
1020 nsCAutoString filename;
1021 rv = lastCrashFile->GetNativePath(filename);
1022 NS_ENSURE_SUCCESS(rv, rv);
1024 if (filename.Length() < XP_PATH_MAX)
1025 strncpy(lastCrashTimeFilename, filename.get(), filename.Length());
1026 #endif
1028 return NS_OK;
1031 static void OOPDeinit();
1033 nsresult UnsetExceptionHandler()
1035 delete gExceptionHandler;
1037 // do this here in the unlikely case that we succeeded in allocating
1038 // our strings but failed to allocate gExceptionHandler.
1039 if (crashReporterAPIData_Hash) {
1040 delete crashReporterAPIData_Hash;
1041 crashReporterAPIData_Hash = nsnull;
1044 if (crashReporterAPIData) {
1045 delete crashReporterAPIData;
1046 crashReporterAPIData = nsnull;
1049 if (notesField) {
1050 delete notesField;
1051 notesField = nsnull;
1054 if (crashReporterPath) {
1055 NS_Free(crashReporterPath);
1056 crashReporterPath = nsnull;
1059 #ifdef XP_MACOSX
1060 posix_spawnattr_destroy(&spawnattr);
1061 #endif
1063 if (!gExceptionHandler)
1064 return NS_ERROR_NOT_INITIALIZED;
1066 gExceptionHandler = nsnull;
1068 #ifdef MOZ_IPC
1069 OOPDeinit();
1070 #endif
1072 return NS_OK;
1075 static void ReplaceChar(nsCString& str, const nsACString& character,
1076 const nsACString& replacement)
1078 nsCString::const_iterator start, end;
1080 str.BeginReading(start);
1081 str.EndReading(end);
1083 while (FindInReadable(character, start, end)) {
1084 PRInt32 pos = end.size_backward();
1085 str.Replace(pos - 1, 1, replacement);
1087 str.BeginReading(start);
1088 start.advance(pos + replacement.Length() - 1);
1089 str.EndReading(end);
1093 static PRBool DoFindInReadable(const nsACString& str, const nsACString& value)
1095 nsACString::const_iterator start, end;
1096 str.BeginReading(start);
1097 str.EndReading(end);
1099 return FindInReadable(value, start, end);
1102 static PLDHashOperator EnumerateEntries(const nsACString& key,
1103 nsCString entry,
1104 void* userData)
1106 crashReporterAPIData->Append(key + NS_LITERAL_CSTRING("=") + entry +
1107 NS_LITERAL_CSTRING("\n"));
1108 return PL_DHASH_NEXT;
1111 nsresult AnnotateCrashReport(const nsACString& key, const nsACString& data)
1113 if (!GetEnabled())
1114 return NS_ERROR_NOT_INITIALIZED;
1116 if (DoFindInReadable(key, NS_LITERAL_CSTRING("=")) ||
1117 DoFindInReadable(key, NS_LITERAL_CSTRING("\n")))
1118 return NS_ERROR_INVALID_ARG;
1120 if (DoFindInReadable(data, NS_LITERAL_CSTRING("\0")))
1121 return NS_ERROR_INVALID_ARG;
1123 nsCString escapedData(data);
1125 // escape backslashes
1126 ReplaceChar(escapedData, NS_LITERAL_CSTRING("\\"),
1127 NS_LITERAL_CSTRING("\\\\"));
1128 // escape newlines
1129 ReplaceChar(escapedData, NS_LITERAL_CSTRING("\n"),
1130 NS_LITERAL_CSTRING("\\n"));
1132 nsresult rv = crashReporterAPIData_Hash->Put(key, escapedData);
1133 NS_ENSURE_SUCCESS(rv, rv);
1135 // now rebuild the file contents
1136 crashReporterAPIData->Truncate(0);
1137 crashReporterAPIData_Hash->EnumerateRead(EnumerateEntries,
1138 crashReporterAPIData);
1140 return NS_OK;
1143 nsresult AppendAppNotesToCrashReport(const nsACString& data)
1145 if (!GetEnabled())
1146 return NS_ERROR_NOT_INITIALIZED;
1148 if (DoFindInReadable(data, NS_LITERAL_CSTRING("\0")))
1149 return NS_ERROR_INVALID_ARG;
1151 notesField->Append(data);
1152 return AnnotateCrashReport(NS_LITERAL_CSTRING("Notes"), *notesField);
1155 // Returns true if found, false if not found.
1156 bool GetAnnotation(const nsACString& key, nsACString& data)
1158 if (!gExceptionHandler)
1159 return false;
1161 nsCAutoString entry;
1162 if (!crashReporterAPIData_Hash->Get(key, &entry))
1163 return false;
1165 data = entry;
1166 return true;
1169 bool GetServerURL(nsACString& aServerURL)
1171 if (!gExceptionHandler)
1172 return false;
1174 return GetAnnotation(NS_LITERAL_CSTRING("ServerURL"), aServerURL);
1177 nsresult SetServerURL(const nsACString& aServerURL)
1179 // store server URL with the API data
1180 // the client knows to handle this specially
1181 return AnnotateCrashReport(NS_LITERAL_CSTRING("ServerURL"),
1182 aServerURL);
1185 nsresult
1186 SetRestartArgs(int argc, char** argv)
1188 if (!gExceptionHandler)
1189 return NS_OK;
1191 int i;
1192 nsCAutoString envVar;
1193 char *env;
1194 for (i = 0; i < argc; i++) {
1195 envVar = "MOZ_CRASHREPORTER_RESTART_ARG_";
1196 envVar.AppendInt(i);
1197 envVar += "=";
1198 #if defined(XP_UNIX) && !defined(XP_MACOSX)
1199 // we'd like to run the script around the binary
1200 // instead of the binary itself, so remove the -bin
1201 // if it exists on the first argument
1202 int arg_len = 0;
1203 if (i == 0 &&
1204 (arg_len = strlen(argv[i])) > 4 &&
1205 strcmp(argv[i] + arg_len - 4, "-bin") == 0) {
1206 envVar.Append(argv[i], arg_len - 4);
1207 } else
1208 #endif
1210 envVar += argv[i];
1213 // PR_SetEnv() wants the string to be available for the lifetime
1214 // of the app, so dup it here
1215 env = ToNewCString(envVar);
1216 if (!env)
1217 return NS_ERROR_OUT_OF_MEMORY;
1219 PR_SetEnv(env);
1222 // make sure the arg list is terminated
1223 envVar = "MOZ_CRASHREPORTER_RESTART_ARG_";
1224 envVar.AppendInt(i);
1225 envVar += "=";
1227 // PR_SetEnv() wants the string to be available for the lifetime
1228 // of the app, so dup it here
1229 env = ToNewCString(envVar);
1230 if (!env)
1231 return NS_ERROR_OUT_OF_MEMORY;
1233 PR_SetEnv(env);
1235 // make sure we save the info in XUL_APP_FILE for the reporter
1236 const char *appfile = PR_GetEnv("XUL_APP_FILE");
1237 if (appfile && *appfile) {
1238 envVar = "MOZ_CRASHREPORTER_RESTART_XUL_APP_FILE=";
1239 envVar += appfile;
1240 env = ToNewCString(envVar);
1241 PR_SetEnv(env);
1244 return NS_OK;
1247 #ifdef XP_WIN32
1248 nsresult WriteMinidumpForException(EXCEPTION_POINTERS* aExceptionInfo)
1250 if (!gExceptionHandler)
1251 return NS_ERROR_NOT_INITIALIZED;
1253 return gExceptionHandler->WriteMinidumpForException(aExceptionInfo) ? NS_OK : NS_ERROR_FAILURE;
1255 #endif
1257 #ifdef XP_MACOSX
1258 nsresult AppendObjCExceptionInfoToAppNotes(void *inException)
1260 nsCAutoString excString;
1261 GetObjCExceptionInfo(inException, excString);
1262 AppendAppNotesToCrashReport(excString);
1263 return NS_OK;
1265 #endif
1268 * Combined code to get/set the crash reporter submission pref on
1269 * different platforms.
1271 static nsresult PrefSubmitReports(PRBool* aSubmitReports, bool writePref)
1273 nsresult rv;
1274 #if defined(XP_WIN32)
1276 * NOTE! This needs to stay in sync with the preference checking code
1277 * in toolkit/crashreporter/client/crashreporter_win.cpp
1279 nsCOMPtr<nsIXULAppInfo> appinfo =
1280 do_GetService("@mozilla.org/xre/app-info;1", &rv);
1281 NS_ENSURE_SUCCESS(rv, rv);
1283 nsCAutoString appVendor, appName;
1284 rv = appinfo->GetVendor(appVendor);
1285 NS_ENSURE_SUCCESS(rv, rv);
1286 rv = appinfo->GetName(appName);
1287 NS_ENSURE_SUCCESS(rv, rv);
1289 nsCOMPtr<nsIWindowsRegKey> regKey
1290 (do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv));
1291 NS_ENSURE_SUCCESS(rv, rv);
1293 nsCAutoString regPath;
1295 regPath.AppendLiteral("Software\\");
1296 if(!appVendor.IsEmpty()) {
1297 regPath.Append(appVendor);
1298 regPath.AppendLiteral("\\");
1300 regPath.Append(appName);
1301 regPath.AppendLiteral("\\Crash Reporter");
1303 // If we're saving the pref value, just write it to ROOT_KEY_CURRENT_USER
1304 // and we're done.
1305 if (writePref) {
1306 rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
1307 NS_ConvertUTF8toUTF16(regPath),
1308 nsIWindowsRegKey::ACCESS_SET_VALUE);
1309 NS_ENSURE_SUCCESS(rv, rv);
1311 PRUint32 value = *aSubmitReports ? 1 : 0;
1312 rv = regKey->WriteIntValue(NS_LITERAL_STRING("SubmitCrashReport"), value);
1313 regKey->Close();
1314 return rv;
1317 // We're reading the pref value, so we need to first look under
1318 // ROOT_KEY_LOCAL_MACHINE to see if it's set there, and then fall back to
1319 // ROOT_KEY_CURRENT_USER. If it's not set in either place, the pref defaults
1320 // to "true".
1321 PRUint32 value;
1322 rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,
1323 NS_ConvertUTF8toUTF16(regPath),
1324 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
1325 if (NS_SUCCEEDED(rv)) {
1326 rv = regKey->ReadIntValue(NS_LITERAL_STRING("SubmitCrashReport"), &value);
1327 regKey->Close();
1328 if (NS_SUCCEEDED(rv)) {
1329 *aSubmitReports = !!value;
1330 return NS_OK;
1334 rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
1335 NS_ConvertUTF8toUTF16(regPath),
1336 nsIWindowsRegKey::ACCESS_QUERY_VALUE);
1337 if (NS_FAILED(rv)) {
1338 *aSubmitReports = PR_TRUE;
1339 return NS_OK;
1342 rv = regKey->ReadIntValue(NS_LITERAL_STRING("SubmitCrashReport"), &value);
1343 // default to true on failure
1344 if (NS_FAILED(rv)) {
1345 value = 1;
1346 rv = NS_OK;
1348 regKey->Close();
1350 *aSubmitReports = !!value;
1351 return NS_OK;
1352 #elif defined(XP_MACOSX)
1353 rv = NS_OK;
1354 if (writePref) {
1355 CFPropertyListRef cfValue = (CFPropertyListRef)(*aSubmitReports ? kCFBooleanTrue : kCFBooleanFalse);
1356 ::CFPreferencesSetAppValue(CFSTR("submitReport"),
1357 cfValue,
1358 reporterClientAppID);
1359 if (!::CFPreferencesAppSynchronize(reporterClientAppID))
1360 rv = NS_ERROR_FAILURE;
1362 else {
1363 *aSubmitReports = PR_TRUE;
1364 Boolean keyExistsAndHasValidFormat = false;
1365 Boolean prefValue = ::CFPreferencesGetAppBooleanValue(CFSTR("submitReport"),
1366 reporterClientAppID,
1367 &keyExistsAndHasValidFormat);
1368 if (keyExistsAndHasValidFormat)
1369 *aSubmitReports = !!prefValue;
1371 return rv;
1372 #elif defined(XP_UNIX)
1374 * NOTE! This needs to stay in sync with the preference checking code
1375 * in toolkit/crashreporter/client/crashreporter_linux.cpp
1377 nsCOMPtr<nsIFile> reporterINI;
1378 rv = NS_GetSpecialDirectory("UAppData", getter_AddRefs(reporterINI));
1379 NS_ENSURE_SUCCESS(rv, rv);
1380 reporterINI->AppendNative(NS_LITERAL_CSTRING("Crash Reports"));
1381 reporterINI->AppendNative(NS_LITERAL_CSTRING("crashreporter.ini"));
1383 PRBool exists;
1384 rv = reporterINI->Exists(&exists);
1385 NS_ENSURE_SUCCESS(rv, rv);
1386 if (!exists) {
1387 if (!writePref) {
1388 // If reading the pref, default to true if .ini doesn't exist.
1389 *aSubmitReports = PR_TRUE;
1390 return NS_OK;
1392 // Create the file so the INI processor can write to it.
1393 rv = reporterINI->Create(nsIFile::NORMAL_FILE_TYPE, 0600);
1394 NS_ENSURE_SUCCESS(rv, rv);
1397 nsCOMPtr<nsIINIParserFactory> iniFactory =
1398 do_GetService("@mozilla.org/xpcom/ini-processor-factory;1", &rv);
1399 NS_ENSURE_SUCCESS(rv, rv);
1401 nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(reporterINI);
1402 NS_ENSURE_TRUE(localFile, NS_ERROR_FAILURE);
1403 nsCOMPtr<nsIINIParser> iniParser;
1404 rv = iniFactory->CreateINIParser(localFile,
1405 getter_AddRefs(iniParser));
1406 NS_ENSURE_SUCCESS(rv, rv);
1408 // If we're writing the pref, just set and we're done.
1409 if (writePref) {
1410 nsCOMPtr<nsIINIParserWriter> iniWriter = do_QueryInterface(iniParser);
1411 NS_ENSURE_TRUE(iniWriter, NS_ERROR_FAILURE);
1413 rv = iniWriter->SetString(NS_LITERAL_CSTRING("Crash Reporter"),
1414 NS_LITERAL_CSTRING("SubmitReport"),
1415 *aSubmitReports ? NS_LITERAL_CSTRING("1") :
1416 NS_LITERAL_CSTRING("0"));
1417 NS_ENSURE_SUCCESS(rv, rv);
1418 rv = iniWriter->WriteFile(NULL);
1419 return rv;
1422 nsCAutoString submitReportValue;
1423 rv = iniParser->GetString(NS_LITERAL_CSTRING("Crash Reporter"),
1424 NS_LITERAL_CSTRING("SubmitReport"),
1425 submitReportValue);
1427 // Default to "true" if the pref can't be found.
1428 if (NS_FAILED(rv))
1429 *aSubmitReports = PR_TRUE;
1430 else if (submitReportValue.EqualsASCII("0"))
1431 *aSubmitReports = PR_FALSE;
1432 else
1433 *aSubmitReports = PR_TRUE;
1435 return NS_OK;
1436 #else
1437 return NS_ERROR_NOT_IMPLEMENTED;
1438 #endif
1441 nsresult GetSubmitReports(PRBool* aSubmitReports)
1443 return PrefSubmitReports(aSubmitReports, false);
1446 nsresult SetSubmitReports(PRBool aSubmitReports)
1448 return PrefSubmitReports(&aSubmitReports, true);
1451 // The "pending" dir is Crash Reports/pending, from which minidumps
1452 // can be submitted
1453 static bool
1454 GetPendingDir(nsILocalFile** dir)
1456 nsCOMPtr<nsIProperties> dirSvc =
1457 do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
1458 if (!dirSvc)
1459 return false;
1460 nsCOMPtr<nsILocalFile> pendingDir;
1461 if (NS_FAILED(dirSvc->Get("UAppData",
1462 NS_GET_IID(nsILocalFile),
1463 getter_AddRefs(pendingDir))) ||
1464 NS_FAILED(pendingDir->Append(NS_LITERAL_STRING("Crash Reports"))) ||
1465 NS_FAILED(pendingDir->Append(NS_LITERAL_STRING("pending"))))
1466 return false;
1467 *dir = NULL;
1468 pendingDir.swap(*dir);
1469 return true;
1472 // The "limbo" dir is where minidumps go to wait for something else to
1473 // use them. If we're |ShouldReport()|, then the "something else" is
1474 // a minidump submitter, and they're coming from the
1475 // Crash Reports/pending/ dir. Otherwise, we don't know what the
1476 // "somthing else" is, but the minidumps stay in [profile]/minidumps/
1477 // limbo.
1478 static bool
1479 GetMinidumpLimboDir(nsILocalFile** dir)
1481 if (ShouldReport()) {
1482 return GetPendingDir(dir);
1484 else {
1485 CreateFileFromPath(gExceptionHandler->dump_path(), dir);
1486 return NULL != *dir;
1490 bool
1491 GetMinidumpForID(const nsAString& id, nsILocalFile** minidump)
1493 if (!GetMinidumpLimboDir(minidump))
1494 return false;
1495 (*minidump)->Append(id + NS_LITERAL_STRING(".dmp"));
1496 return true;
1499 bool
1500 GetIDFromMinidump(nsILocalFile* minidump, nsAString& id)
1502 if (NS_SUCCEEDED(minidump->GetLeafName(id))) {
1503 id.Replace(id.Length() - 4, 4, NS_LITERAL_STRING(""));
1504 return true;
1506 return false;
1509 bool
1510 GetExtraFileForID(const nsAString& id, nsILocalFile** extraFile)
1512 if (!GetMinidumpLimboDir(extraFile))
1513 return false;
1514 (*extraFile)->Append(id + NS_LITERAL_STRING(".extra"));
1515 return true;
1518 bool
1519 GetExtraFileForMinidump(nsILocalFile* minidump, nsILocalFile** extraFile)
1521 nsAutoString leafName;
1522 nsresult rv = minidump->GetLeafName(leafName);
1523 if (NS_FAILED(rv))
1524 return false;
1526 nsCOMPtr<nsIFile> extraF;
1527 rv = minidump->Clone(getter_AddRefs(extraF));
1528 if (NS_FAILED(rv))
1529 return false;
1531 nsCOMPtr<nsILocalFile> extra = do_QueryInterface(extraF);
1532 if (!extra)
1533 return false;
1535 leafName.Replace(leafName.Length() - 3, 3,
1536 NS_LITERAL_STRING("extra"));
1537 rv = extra->SetLeafName(leafName);
1538 if (NS_FAILED(rv))
1539 return false;
1541 *extraFile = NULL;
1542 extra.swap(*extraFile);
1543 return true;
1546 bool
1547 AppendExtraData(const nsAString& id, const AnnotationTable& data)
1549 nsCOMPtr<nsILocalFile> extraFile;
1550 if (!GetExtraFileForID(id, getter_AddRefs(extraFile)))
1551 return false;
1552 return AppendExtraData(extraFile, data);
1555 //-----------------------------------------------------------------------------
1556 // Helpers for AppendExtraData()
1558 struct Blacklist {
1559 Blacklist() : mItems(NULL), mLen(0) { }
1560 Blacklist(const char** items, int len) : mItems(items), mLen(len) { }
1562 bool Contains(const nsACString& key) const {
1563 for (int i = 0; i < mLen; ++i)
1564 if (key.EqualsASCII(mItems[i]))
1565 return true;
1566 return false;
1569 const char** mItems;
1570 const int mLen;
1573 struct EnumerateAnnotationsContext {
1574 const Blacklist& blacklist;
1575 PRFileDesc* fd;
1578 static void
1579 WriteAnnotation(PRFileDesc* fd, const nsACString& key, const nsACString& value)
1581 PR_Write(fd, key.BeginReading(), key.Length());
1582 PR_Write(fd, "=", 1);
1583 PR_Write(fd, value.BeginReading(), value.Length());
1584 PR_Write(fd, "\n", 1);
1587 static PLDHashOperator
1588 EnumerateAnnotations(const nsACString& key,
1589 nsCString entry,
1590 void* userData)
1592 EnumerateAnnotationsContext* ctx =
1593 static_cast<EnumerateAnnotationsContext*>(userData);
1594 const Blacklist& blacklist = ctx->blacklist;
1596 // skip entries in the blacklist
1597 if (blacklist.Contains(key))
1598 return PL_DHASH_NEXT;
1600 WriteAnnotation(ctx->fd, key, entry);
1602 return PL_DHASH_NEXT;
1605 static bool
1606 WriteExtraData(nsILocalFile* extraFile,
1607 const AnnotationTable& data,
1608 const Blacklist& blacklist,
1609 bool writeCrashTime=false,
1610 bool truncate=false)
1612 PRFileDesc* fd;
1613 PRIntn truncOrAppend = truncate ? PR_TRUNCATE : PR_APPEND;
1614 nsresult rv =
1615 extraFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | truncOrAppend,
1616 0600, &fd);
1617 if (NS_FAILED(rv))
1618 return false;
1620 EnumerateAnnotationsContext ctx = { blacklist, fd };
1621 data.EnumerateRead(EnumerateAnnotations, &ctx);
1623 if (writeCrashTime) {
1624 time_t crashTime = time(NULL);
1625 char crashTimeString[32];
1626 XP_TTOA(crashTime, crashTimeString, 10);
1628 WriteAnnotation(fd,
1629 nsDependentCString("CrashTime"),
1630 nsDependentCString(crashTimeString));
1633 PR_Close(fd);
1634 return true;
1637 bool
1638 AppendExtraData(nsILocalFile* extraFile, const AnnotationTable& data)
1640 return WriteExtraData(extraFile, data, Blacklist());
1644 #if defined(MOZ_IPC)
1646 static bool
1647 WriteExtraForMinidump(nsILocalFile* minidump,
1648 const Blacklist& blacklist,
1649 nsILocalFile** extraFile)
1651 nsCOMPtr<nsILocalFile> extra;
1652 if (!GetExtraFileForMinidump(minidump, getter_AddRefs(extra)))
1653 return false;
1655 if (!WriteExtraData(extra, *crashReporterAPIData_Hash,
1656 blacklist,
1657 true /*write crash time*/,
1658 true /*truncate*/))
1659 return false;
1661 *extraFile = NULL;
1662 extra.swap(*extraFile);
1664 return true;
1667 // It really only makes sense to call this function when
1668 // ShouldReport() is true.
1669 static bool
1670 MoveToPending(nsIFile* dumpFile, nsIFile* extraFile)
1672 nsCOMPtr<nsILocalFile> pendingDir;
1673 if (!GetPendingDir(getter_AddRefs(pendingDir)))
1674 return false;
1676 return NS_SUCCEEDED(dumpFile->MoveTo(pendingDir, EmptyString())) &&
1677 NS_SUCCEEDED(extraFile->MoveTo(pendingDir, EmptyString()));
1680 static void
1681 OnChildProcessDumpRequested(void* aContext,
1682 #ifdef XP_MACOSX
1683 const ClientInfo& aClientInfo,
1684 const xpstring& aFilePath
1685 #else
1686 const ClientInfo* aClientInfo,
1687 const xpstring* aFilePath
1688 #endif
1691 nsCOMPtr<nsILocalFile> minidump;
1692 nsCOMPtr<nsILocalFile> extraFile;
1694 CreateFileFromPath(
1695 #ifdef XP_MACOSX
1696 aFilePath,
1697 #else
1698 *aFilePath,
1699 #endif
1700 getter_AddRefs(minidump));
1702 #if defined(__ANDROID__)
1703 // Do dump generation here since the CrashGenerationServer doesn't
1704 // have access to the library mappings.
1705 MappingMap::const_iterator iter =
1706 child_library_mappings.find(aClientInfo->pid_);
1707 if (iter == child_library_mappings.end()) {
1708 NS_WARNING("No library mappings found for child, can't write minidump!");
1709 return;
1712 if (!google_breakpad::WriteMinidump(aFilePath->c_str(),
1713 aClientInfo->pid_,
1714 aClientInfo->crash_context,
1715 aClientInfo->crash_context_size,
1716 iter->second))
1717 return;
1718 #endif
1720 if (!WriteExtraForMinidump(minidump,
1721 Blacklist(kSubprocessBlacklist,
1722 NS_ARRAY_LENGTH(kSubprocessBlacklist)),
1723 getter_AddRefs(extraFile)))
1724 return;
1726 if (ShouldReport())
1727 MoveToPending(minidump, extraFile);
1730 PRUint32 pid =
1731 #ifdef XP_MACOSX
1732 aClientInfo.pid();
1733 #else
1734 aClientInfo->pid();
1735 #endif
1737 MutexAutoLock lock(*dumpMapLock);
1738 pidToMinidump->Put(pid, minidump);
1742 static bool
1743 OOPInitialized()
1745 return pidToMinidump != NULL;
1748 static void
1749 OOPInit()
1751 NS_ABORT_IF_FALSE(!OOPInitialized(),
1752 "OOP crash reporter initialized more than once!");
1753 NS_ABORT_IF_FALSE(gExceptionHandler != NULL,
1754 "attempt to initialize OOP crash reporter before in-process crashreporter!");
1756 #if defined(XP_WIN)
1757 childCrashNotifyPipe =
1758 PR_smprintf("\\\\.\\pipe\\gecko-crash-server-pipe.%i",
1759 static_cast<int>(::GetCurrentProcessId()));
1761 const std::wstring dumpPath = gExceptionHandler->dump_path();
1762 crashServer = new CrashGenerationServer(
1763 NS_ConvertASCIItoUTF16(childCrashNotifyPipe).get(),
1764 NULL, // default security attributes
1765 NULL, NULL, // we don't care about process connect here
1766 OnChildProcessDumpRequested, NULL,
1767 NULL, NULL, // we don't care about process exit here
1768 true, // automatically generate dumps
1769 &dumpPath);
1771 #elif defined(XP_LINUX)
1772 if (!CrashGenerationServer::CreateReportChannel(&serverSocketFd,
1773 &clientSocketFd))
1774 NS_RUNTIMEABORT("can't create crash reporter socketpair()");
1776 const std::string dumpPath = gExceptionHandler->dump_path();
1777 bool generateDumps = true;
1778 #if defined(__ANDROID__)
1779 // On Android, the callback will do dump generation, since it needs
1780 // to pass the library mappings.
1781 generateDumps = false;
1782 #endif
1783 crashServer = new CrashGenerationServer(
1784 serverSocketFd,
1785 OnChildProcessDumpRequested, NULL,
1786 NULL, NULL, // we don't care about process exit here
1787 generateDumps,
1788 &dumpPath);
1790 #elif defined(XP_MACOSX)
1791 childCrashNotifyPipe =
1792 PR_smprintf("gecko-crash-server-pipe.%i",
1793 static_cast<int>(getpid()));
1794 const std::string dumpPath = gExceptionHandler->dump_path();
1796 crashServer = new CrashGenerationServer(
1797 childCrashNotifyPipe,
1798 OnChildProcessDumpRequested, NULL,
1799 NULL, NULL,
1800 true, // automatically generate dumps
1801 dumpPath);
1802 #endif
1804 if (!crashServer->Start())
1805 NS_RUNTIMEABORT("can't start crash reporter server()");
1807 pidToMinidump = new ChildMinidumpMap();
1808 pidToMinidump->Init();
1810 dumpMapLock = new Mutex("CrashReporter::dumpMapLock");
1813 static void
1814 OOPDeinit()
1816 if (!OOPInitialized()) {
1817 NS_WARNING("OOPDeinit() without successful OOPInit()");
1818 return;
1821 delete crashServer;
1822 crashServer = NULL;
1824 delete dumpMapLock;
1825 dumpMapLock = NULL;
1827 delete pidToMinidump;
1828 pidToMinidump = NULL;
1830 #if defined(XP_WIN)
1831 PR_Free(childCrashNotifyPipe);
1832 childCrashNotifyPipe = NULL;
1833 #endif
1836 #if defined(XP_WIN) || defined(XP_MACOSX)
1837 // Parent-side API for children
1838 const char*
1839 GetChildNotificationPipe()
1841 if (!GetEnabled())
1842 return kNullNotifyPipe;
1844 if (!OOPInitialized())
1845 OOPInit();
1847 return childCrashNotifyPipe;
1849 #endif
1851 #if defined(XP_WIN)
1852 // Child-side API
1853 bool
1854 SetRemoteExceptionHandler(const nsACString& crashPipe)
1856 // crash reporting is disabled
1857 if (crashPipe.Equals(kNullNotifyPipe))
1858 return true;
1860 NS_ABORT_IF_FALSE(!gExceptionHandler, "crash client already init'd");
1862 gExceptionHandler = new google_breakpad::
1863 ExceptionHandler(L"",
1864 NULL, // no filter callback
1865 NULL, // no minidump callback
1866 NULL, // no callback context
1867 google_breakpad::ExceptionHandler::HANDLER_ALL,
1868 MiniDumpNormal,
1869 NS_ConvertASCIItoUTF16(crashPipe).BeginReading(),
1870 NULL);
1871 #ifdef XP_WIN
1872 gExceptionHandler->set_handle_debug_exceptions(true);
1873 #endif
1875 // we either do remote or nothing, no fallback to regular crash reporting
1876 return gExceptionHandler->IsOutOfProcess();
1879 //--------------------------------------------------
1880 #elif defined(XP_LINUX)
1882 // Parent-side API for children
1883 bool
1884 CreateNotificationPipeForChild(int* childCrashFd, int* childCrashRemapFd)
1886 if (!GetEnabled()) {
1887 *childCrashFd = -1;
1888 *childCrashRemapFd = -1;
1889 return true;
1892 if (!OOPInitialized())
1893 OOPInit();
1895 *childCrashFd = clientSocketFd;
1896 *childCrashRemapFd = kMagicChildCrashReportFd;
1898 return true;
1901 // Child-side API
1902 bool
1903 SetRemoteExceptionHandler()
1905 NS_ABORT_IF_FALSE(!gExceptionHandler, "crash client already init'd");
1907 gExceptionHandler = new google_breakpad::
1908 ExceptionHandler("",
1909 NULL, // no filter callback
1910 NULL, // no minidump callback
1911 NULL, // no callback context
1912 true, // install signal handlers
1913 kMagicChildCrashReportFd);
1915 // we either do remote or nothing, no fallback to regular crash reporting
1916 return gExceptionHandler->IsOutOfProcess();
1919 //--------------------------------------------------
1920 #elif defined(XP_MACOSX)
1921 // Child-side API
1922 bool
1923 SetRemoteExceptionHandler(const nsACString& crashPipe)
1925 // crash reporting is disabled
1926 if (crashPipe.Equals(kNullNotifyPipe))
1927 return true;
1929 NS_ABORT_IF_FALSE(!gExceptionHandler, "crash client already init'd");
1931 gExceptionHandler = new google_breakpad::
1932 ExceptionHandler("",
1933 NULL, // no filter callback
1934 NULL, // no minidump callback
1935 NULL, // no callback context
1936 true, // install signal handlers
1937 crashPipe.BeginReading());
1939 // we either do remote or nothing, no fallback to regular crash reporting
1940 return gExceptionHandler->IsOutOfProcess();
1942 #endif // XP_WIN
1945 bool
1946 TakeMinidumpForChild(PRUint32 childPid, nsILocalFile** dump)
1948 if (!GetEnabled())
1949 return false;
1951 MutexAutoLock lock(*dumpMapLock);
1953 nsCOMPtr<nsILocalFile> d;
1954 bool found = pidToMinidump->Get(childPid, getter_AddRefs(d));
1955 if (found)
1956 pidToMinidump->Remove(childPid);
1958 *dump = NULL;
1959 d.swap(*dump);
1961 return found;
1964 //-----------------------------------------------------------------------------
1965 // CreatePairedMinidumps() and helpers
1967 struct PairedDumpContext {
1968 nsCOMPtr<nsILocalFile>* minidump;
1969 nsCOMPtr<nsILocalFile>* extra;
1970 const Blacklist& blacklist;
1973 static bool
1974 PairedDumpCallback(const XP_CHAR* dump_path,
1975 const XP_CHAR* minidump_id,
1976 void* context,
1977 #ifdef XP_WIN32
1978 EXCEPTION_POINTERS* /*unused*/,
1979 MDRawAssertionInfo* /*unused*/,
1980 #endif
1981 bool succeeded)
1983 PairedDumpContext* ctx = static_cast<PairedDumpContext*>(context);
1984 nsCOMPtr<nsILocalFile>& minidump = *ctx->minidump;
1985 nsCOMPtr<nsILocalFile>& extra = *ctx->extra;
1986 const Blacklist& blacklist = ctx->blacklist;
1988 xpstring dump(dump_path);
1989 dump += XP_PATH_SEPARATOR;
1990 dump += minidump_id;
1991 dump += dumpFileExtension;
1993 CreateFileFromPath(dump, getter_AddRefs(minidump));
1994 return WriteExtraForMinidump(minidump, blacklist, getter_AddRefs(extra));
1997 ThreadId
1998 CurrentThreadId()
2000 #if defined(XP_WIN)
2001 return ::GetCurrentThreadId();
2002 #elif defined(XP_LINUX)
2003 return sys_gettid();
2004 #elif defined(XP_MACOSX)
2005 // Just return an index, since Mach ports can't be directly serialized
2006 thread_act_port_array_t threads_for_task;
2007 mach_msg_type_number_t thread_count;
2009 if (task_threads(mach_task_self(), &threads_for_task, &thread_count))
2010 return -1;
2012 for (unsigned int i = 0; i < thread_count; ++i) {
2013 if (threads_for_task[i] == mach_thread_self())
2014 return i;
2016 abort();
2017 #else
2018 # error "Unsupported platform"
2019 #endif
2022 bool
2023 CreatePairedMinidumps(ProcessHandle childPid,
2024 ThreadId childBlamedThread,
2025 nsAString* pairGUID,
2026 nsILocalFile** childDump,
2027 nsILocalFile** parentDump)
2029 if (!GetEnabled())
2030 return false;
2032 // create the UUID for the hang dump as a pair
2033 nsresult rv;
2034 nsCOMPtr<nsIUUIDGenerator> uuidgen =
2035 do_GetService("@mozilla.org/uuid-generator;1", &rv);
2036 NS_ENSURE_SUCCESS(rv, false);
2038 nsID id;
2039 rv = uuidgen->GenerateUUIDInPlace(&id);
2040 NS_ENSURE_SUCCESS(rv, false);
2042 char chars[NSID_LENGTH];
2043 id.ToProvidedString(chars);
2044 CopyASCIItoUTF16(chars, *pairGUID);
2046 // trim off braces
2047 pairGUID->Cut(0, 1);
2048 pairGUID->Cut(pairGUID->Length()-1, 1);
2050 #ifdef XP_MACOSX
2051 mach_port_t childThread = MACH_PORT_NULL;
2052 thread_act_port_array_t threads_for_task;
2053 mach_msg_type_number_t thread_count;
2055 if (task_threads(childPid, &threads_for_task, &thread_count)
2056 == KERN_SUCCESS && childBlamedThread < thread_count) {
2057 childThread = threads_for_task[childBlamedThread];
2059 #else
2060 ThreadId childThread = childBlamedThread;
2061 #endif
2063 // dump the child
2064 nsCOMPtr<nsILocalFile> childMinidump;
2065 nsCOMPtr<nsILocalFile> childExtra;
2066 Blacklist childBlacklist(kSubprocessBlacklist,
2067 NS_ARRAY_LENGTH(kSubprocessBlacklist));
2068 PairedDumpContext childCtx =
2069 { &childMinidump, &childExtra, childBlacklist };
2070 if (!google_breakpad::ExceptionHandler::WriteMinidumpForChild(
2071 childPid,
2072 childThread,
2073 gExceptionHandler->dump_path(),
2074 PairedDumpCallback,
2075 &childCtx))
2076 return false;
2078 // dump the parent
2079 nsCOMPtr<nsILocalFile> parentMinidump;
2080 nsCOMPtr<nsILocalFile> parentExtra;
2081 // nothing's blacklisted for this process
2082 Blacklist parentBlacklist;
2083 PairedDumpContext parentCtx =
2084 { &parentMinidump, &parentExtra, parentBlacklist };
2085 if (!google_breakpad::ExceptionHandler::WriteMinidump(
2086 gExceptionHandler->dump_path(),
2087 true, // write exception stream
2088 PairedDumpCallback,
2089 &parentCtx))
2090 return false;
2092 // success
2093 if (ShouldReport()) {
2094 MoveToPending(childMinidump, childExtra);
2095 MoveToPending(parentMinidump, parentExtra);
2098 *childDump = NULL;
2099 *parentDump = NULL;
2100 childMinidump.swap(*childDump);
2101 parentMinidump.swap(*parentDump);
2103 return true;
2106 bool
2107 UnsetRemoteExceptionHandler()
2109 delete gExceptionHandler;
2110 gExceptionHandler = NULL;
2111 return true;
2114 #endif // MOZ_IPC
2116 #if defined(__ANDROID__)
2117 void AddLibraryMapping(const char* library_name,
2118 const char* file_id,
2119 uintptr_t start_address,
2120 size_t mapping_length,
2121 size_t file_offset)
2123 if (!gExceptionHandler) {
2124 mapping_info info;
2125 info.name = library_name;
2126 info.debug_id = file_id;
2127 info.start_address = start_address;
2128 info.length = mapping_length;
2129 info.file_offset = file_offset;
2130 library_mappings.push_back(info);
2132 else {
2133 u_int8_t guid[sizeof(MDGUID)];
2134 FileIDToGUID(file_id, guid);
2135 gExceptionHandler->AddMappingInfo(library_name,
2136 guid,
2137 start_address,
2138 mapping_length,
2139 file_offset);
2143 #ifdef MOZ_IPC
2144 void AddLibraryMappingForChild(PRUint32 childPid,
2145 const char* library_name,
2146 const char* file_id,
2147 uintptr_t start_address,
2148 size_t mapping_length,
2149 size_t file_offset)
2151 if (child_library_mappings.find(childPid) == child_library_mappings.end())
2152 child_library_mappings[childPid] = google_breakpad::MappingList();
2153 google_breakpad::MappingInfo info;
2154 info.start_addr = start_address;
2155 info.size = mapping_length;
2156 info.offset = file_offset;
2157 strcpy(info.name, library_name);
2159 std::pair<google_breakpad::MappingInfo, u_int8_t[sizeof(MDGUID)]> mapping;
2160 mapping.first = info;
2161 u_int8_t guid[sizeof(MDGUID)];
2162 FileIDToGUID(file_id, guid);
2163 memcpy(mapping.second, guid, sizeof(MDGUID));
2164 child_library_mappings[childPid].push_back(mapping);
2167 void RemoveLibraryMappingsForChild(PRUint32 childPid)
2169 MappingMap::iterator iter = child_library_mappings.find(childPid);
2170 if (iter != child_library_mappings.end())
2171 child_library_mappings.erase(iter);
2173 #endif
2174 #endif
2176 } // namespace CrashReporter