1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/crashreporter/nsExceptionHandler.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,3127 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsExceptionHandler.h" 1.10 +#include "nsDataHashtable.h" 1.11 +#include "mozilla/ArrayUtils.h" 1.12 +#include "mozilla/dom/CrashReporterChild.h" 1.13 +#include "mozilla/Services.h" 1.14 +#include "nsIObserverService.h" 1.15 +#include "mozilla/unused.h" 1.16 + 1.17 +#include "nsThreadUtils.h" 1.18 +#include "nsXULAppAPI.h" 1.19 + 1.20 +#if defined(XP_WIN32) 1.21 +#ifdef WIN32_LEAN_AND_MEAN 1.22 +#undef WIN32_LEAN_AND_MEAN 1.23 +#endif 1.24 + 1.25 +#include "nsXULAppAPI.h" 1.26 +#include "nsIXULAppInfo.h" 1.27 +#include "nsIWindowsRegKey.h" 1.28 +#include "client/windows/crash_generation/client_info.h" 1.29 +#include "client/windows/crash_generation/crash_generation_server.h" 1.30 +#include "client/windows/handler/exception_handler.h" 1.31 +#include <dbghelp.h> 1.32 +#include <string.h> 1.33 +#include "nsDirectoryServiceUtils.h" 1.34 + 1.35 +#include "nsWindowsDllInterceptor.h" 1.36 +#elif defined(XP_MACOSX) 1.37 +#include "client/mac/crash_generation/client_info.h" 1.38 +#include "client/mac/crash_generation/crash_generation_server.h" 1.39 +#include "client/mac/handler/exception_handler.h" 1.40 +#include <string> 1.41 +#include <Carbon/Carbon.h> 1.42 +#include <CoreFoundation/CoreFoundation.h> 1.43 +#include <crt_externs.h> 1.44 +#include <fcntl.h> 1.45 +#include <mach/mach.h> 1.46 +#include <sys/types.h> 1.47 +#include <spawn.h> 1.48 +#include <unistd.h> 1.49 +#include "mac_utils.h" 1.50 +#elif defined(XP_LINUX) 1.51 +#include "nsIINIParser.h" 1.52 +#include "common/linux/linux_libc_support.h" 1.53 +#include "third_party/lss/linux_syscall_support.h" 1.54 +#include "client/linux/crash_generation/client_info.h" 1.55 +#include "client/linux/crash_generation/crash_generation_server.h" 1.56 +#include "client/linux/handler/exception_handler.h" 1.57 +#include <fcntl.h> 1.58 +#include <sys/types.h> 1.59 +#include <unistd.h> 1.60 +#elif defined(XP_SOLARIS) 1.61 +#include "client/solaris/handler/exception_handler.h" 1.62 +#include <fcntl.h> 1.63 +#include <sys/types.h> 1.64 +#include <unistd.h> 1.65 +#else 1.66 +#error "Not yet implemented for this platform" 1.67 +#endif // defined(XP_WIN32) 1.68 + 1.69 +#ifdef MOZ_CRASHREPORTER_INJECTOR 1.70 +#include "InjectCrashReporter.h" 1.71 +using mozilla::InjectCrashRunnable; 1.72 +#endif 1.73 + 1.74 +#include <stdlib.h> 1.75 +#include <time.h> 1.76 +#include <prenv.h> 1.77 +#include <prio.h> 1.78 +#include <prmem.h> 1.79 +#include "mozilla/Mutex.h" 1.80 +#include "nsDebug.h" 1.81 +#include "nsCRT.h" 1.82 +#include "nsIFile.h" 1.83 +#include "prprf.h" 1.84 +#include <map> 1.85 +#include <vector> 1.86 + 1.87 +#include "mozilla/IOInterposer.h" 1.88 +#include "mozilla/mozalloc_oom.h" 1.89 +#include "mozilla/WindowsDllBlocklist.h" 1.90 + 1.91 +#if defined(XP_MACOSX) 1.92 +CFStringRef reporterClientAppID = CFSTR("org.mozilla.crashreporter"); 1.93 +#endif 1.94 +#if defined(MOZ_WIDGET_ANDROID) 1.95 +#include "common/linux/file_id.h" 1.96 +#endif 1.97 + 1.98 +using google_breakpad::CrashGenerationServer; 1.99 +using google_breakpad::ClientInfo; 1.100 +#ifdef XP_LINUX 1.101 +using google_breakpad::MinidumpDescriptor; 1.102 +#endif 1.103 +using namespace mozilla; 1.104 +using mozilla::dom::CrashReporterChild; 1.105 +using mozilla::dom::PCrashReporterChild; 1.106 + 1.107 +namespace CrashReporter { 1.108 + 1.109 +#ifdef XP_WIN32 1.110 +typedef wchar_t XP_CHAR; 1.111 +typedef std::wstring xpstring; 1.112 +#define CONVERT_XP_CHAR_TO_UTF16(x) x 1.113 +#define XP_STRLEN(x) wcslen(x) 1.114 +#define my_strlen strlen 1.115 +#define CRASH_REPORTER_FILENAME "crashreporter.exe" 1.116 +#define PATH_SEPARATOR "\\" 1.117 +#define XP_PATH_SEPARATOR L"\\" 1.118 +// sort of arbitrary, but MAX_PATH is kinda small 1.119 +#define XP_PATH_MAX 4096 1.120 +// "<reporter path>" "<minidump path>" 1.121 +#define CMDLINE_SIZE ((XP_PATH_MAX * 2) + 6) 1.122 +#ifdef _USE_32BIT_TIME_T 1.123 +#define XP_TTOA(time, buffer, base) ltoa(time, buffer, base) 1.124 +#else 1.125 +#define XP_TTOA(time, buffer, base) _i64toa(time, buffer, base) 1.126 +#endif 1.127 +#define XP_STOA(size, buffer, base) _ui64toa(size, buffer, base) 1.128 +#else 1.129 +typedef char XP_CHAR; 1.130 +typedef std::string xpstring; 1.131 +#define CONVERT_XP_CHAR_TO_UTF16(x) NS_ConvertUTF8toUTF16(x) 1.132 +#define CRASH_REPORTER_FILENAME "crashreporter" 1.133 +#define PATH_SEPARATOR "/" 1.134 +#define XP_PATH_SEPARATOR "/" 1.135 +#define XP_PATH_MAX PATH_MAX 1.136 +#ifdef XP_LINUX 1.137 +#define XP_STRLEN(x) my_strlen(x) 1.138 +#define XP_TTOA(time, buffer, base) my_inttostring(time, buffer, sizeof(buffer)) 1.139 +#define XP_STOA(size, buffer, base) my_inttostring(size, buffer, sizeof(buffer)) 1.140 +#else 1.141 +#define XP_STRLEN(x) strlen(x) 1.142 +#define XP_TTOA(time, buffer, base) sprintf(buffer, "%ld", time) 1.143 +#define XP_STOA(size, buffer, base) sprintf(buffer, "%zu", size) 1.144 +#define my_strlen strlen 1.145 +#define sys_close close 1.146 +#define sys_fork fork 1.147 +#define sys_open open 1.148 +#define sys_write write 1.149 +#endif 1.150 +#endif // XP_WIN32 1.151 + 1.152 +static const XP_CHAR dumpFileExtension[] = {'.', 'd', 'm', 'p', 1.153 + '\0'}; // .dmp 1.154 +static const XP_CHAR extraFileExtension[] = {'.', 'e', 'x', 't', 1.155 + 'r', 'a', '\0'}; // .extra 1.156 + 1.157 +static const char kCrashMainID[] = "crash.main.1\n"; 1.158 + 1.159 +static google_breakpad::ExceptionHandler* gExceptionHandler = nullptr; 1.160 + 1.161 +static XP_CHAR* pendingDirectory; 1.162 +static XP_CHAR* crashReporterPath; 1.163 + 1.164 +// Where crash events should go. 1.165 +static XP_CHAR* eventsDirectory; 1.166 + 1.167 +// If this is false, we don't launch the crash reporter 1.168 +static bool doReport = true; 1.169 + 1.170 +// If this is true, we don't have a crash reporter 1.171 +static bool headlessClient = false; 1.172 + 1.173 +// if this is true, we pass the exception on to the OS crash reporter 1.174 +static bool showOSCrashReporter = false; 1.175 + 1.176 +// The time of the last recorded crash, as a time_t value. 1.177 +static time_t lastCrashTime = 0; 1.178 +// The pathname of a file to store the crash time in 1.179 +static XP_CHAR lastCrashTimeFilename[XP_PATH_MAX] = {0}; 1.180 + 1.181 +// A marker file to hold the path to the last dump written, which 1.182 +// will be checked on startup. 1.183 +static XP_CHAR crashMarkerFilename[XP_PATH_MAX] = {0}; 1.184 + 1.185 +// Whether we've already looked for the marker file. 1.186 +static bool lastRunCrashID_checked = false; 1.187 +// The minidump ID contained in the marker file. 1.188 +static nsString* lastRunCrashID = nullptr; 1.189 + 1.190 +#if defined(MOZ_WIDGET_ANDROID) 1.191 +// on Android 4.2 and above there is a user serial number associated 1.192 +// with the current process that gets lost when we fork so we need to 1.193 +// explicitly pass it to am 1.194 +static char* androidUserSerial = nullptr; 1.195 +#endif 1.196 + 1.197 +// these are just here for readability 1.198 +static const char kCrashTimeParameter[] = "CrashTime="; 1.199 +static const int kCrashTimeParameterLen = sizeof(kCrashTimeParameter)-1; 1.200 + 1.201 +static const char kTimeSinceLastCrashParameter[] = "SecondsSinceLastCrash="; 1.202 +static const int kTimeSinceLastCrashParameterLen = 1.203 + sizeof(kTimeSinceLastCrashParameter)-1; 1.204 + 1.205 +static const char kSysMemoryParameter[] = "SystemMemoryUsePercentage="; 1.206 +static const int kSysMemoryParameterLen = sizeof(kSysMemoryParameter)-1; 1.207 + 1.208 +static const char kTotalVirtualMemoryParameter[] = "TotalVirtualMemory="; 1.209 +static const int kTotalVirtualMemoryParameterLen = 1.210 + sizeof(kTotalVirtualMemoryParameter)-1; 1.211 + 1.212 +static const char kAvailableVirtualMemoryParameter[] = "AvailableVirtualMemory="; 1.213 +static const int kAvailableVirtualMemoryParameterLen = 1.214 + sizeof(kAvailableVirtualMemoryParameter)-1; 1.215 + 1.216 +static const char kOOMAllocationSizeParameter[] = "OOMAllocationSize="; 1.217 +static const int kOOMAllocationSizeParameterLen = 1.218 + sizeof(kOOMAllocationSizeParameter)-1; 1.219 + 1.220 +static const char kTotalPageFileParameter[] = "TotalPageFile="; 1.221 +static const int kTotalPageFileParameterLen = 1.222 + sizeof(kTotalPageFileParameter)-1; 1.223 + 1.224 +static const char kAvailablePageFileParameter[] = "AvailablePageFile="; 1.225 +static const int kAvailablePageFileParameterLen = 1.226 + sizeof(kAvailablePageFileParameter)-1; 1.227 + 1.228 +static const char kTotalPhysicalMemoryParameter[] = "TotalPhysicalMemory="; 1.229 +static const int kTotalPhysicalMemoryParameterLen = 1.230 + sizeof(kTotalPhysicalMemoryParameter)-1; 1.231 + 1.232 +static const char kAvailablePhysicalMemoryParameter[] = "AvailablePhysicalMemory="; 1.233 +static const int kAvailablePhysicalMemoryParameterLen = 1.234 + sizeof(kAvailablePhysicalMemoryParameter)-1; 1.235 + 1.236 +static const char kIsGarbageCollectingParameter[] = "IsGarbageCollecting="; 1.237 +static const int kIsGarbageCollectingParameterLen = 1.238 + sizeof(kIsGarbageCollectingParameter)-1; 1.239 + 1.240 +static const char kEventLoopNestingLevelParameter[] = "EventLoopNestingLevel="; 1.241 +static const int kEventLoopNestingLevelParameterLen = 1.242 + sizeof(kEventLoopNestingLevelParameter)-1; 1.243 + 1.244 +#ifdef XP_WIN 1.245 +static const char kBreakpadReserveAddressParameter[] = "BreakpadReserveAddress="; 1.246 +static const int kBreakpadReserveAddressParameterLen = 1.247 + sizeof(kBreakpadReserveAddressParameter)-1; 1.248 + 1.249 +static const char kBreakpadReserveSizeParameter[] = "BreakpadReserveSize="; 1.250 +static const int kBreakpadReserveSizeParameterLen = 1.251 + sizeof(kBreakpadReserveSizeParameter)-1; 1.252 +#endif 1.253 + 1.254 +// this holds additional data sent via the API 1.255 +static Mutex* crashReporterAPILock; 1.256 +static Mutex* notesFieldLock; 1.257 +static AnnotationTable* crashReporterAPIData_Hash; 1.258 +static nsCString* crashReporterAPIData = nullptr; 1.259 +static nsCString* notesField = nullptr; 1.260 +static bool isGarbageCollecting; 1.261 +static uint32_t eventloopNestingLevel = 0; 1.262 + 1.263 +// Avoid a race during application termination. 1.264 +static Mutex* dumpSafetyLock; 1.265 +static bool isSafeToDump = false; 1.266 + 1.267 +// OOP crash reporting 1.268 +static CrashGenerationServer* crashServer; // chrome process has this 1.269 + 1.270 +# if defined(XP_WIN) || defined(XP_MACOSX) 1.271 +// If crash reporting is disabled, we hand out this "null" pipe to the 1.272 +// child process and don't attempt to connect to a parent server. 1.273 +static const char kNullNotifyPipe[] = "-"; 1.274 +static char* childCrashNotifyPipe; 1.275 + 1.276 +# elif defined(XP_LINUX) 1.277 +static int serverSocketFd = -1; 1.278 +static int clientSocketFd = -1; 1.279 +static const int kMagicChildCrashReportFd = 4; 1.280 + 1.281 +# endif 1.282 + 1.283 +// |dumpMapLock| must protect all access to |pidToMinidump|. 1.284 +static Mutex* dumpMapLock; 1.285 +struct ChildProcessData : public nsUint32HashKey 1.286 +{ 1.287 + ChildProcessData(KeyTypePointer aKey) 1.288 + : nsUint32HashKey(aKey) 1.289 + , sequence(0) 1.290 +#ifdef MOZ_CRASHREPORTER_INJECTOR 1.291 + , callback(nullptr) 1.292 +#endif 1.293 + { } 1.294 + 1.295 + nsCOMPtr<nsIFile> minidump; 1.296 + // Each crashing process is assigned an increasing sequence number to 1.297 + // indicate which process crashed first. 1.298 + uint32_t sequence; 1.299 +#ifdef MOZ_CRASHREPORTER_INJECTOR 1.300 + InjectorCrashCallback* callback; 1.301 +#endif 1.302 +}; 1.303 + 1.304 +typedef nsTHashtable<ChildProcessData> ChildMinidumpMap; 1.305 +static ChildMinidumpMap* pidToMinidump; 1.306 +static uint32_t crashSequence; 1.307 +static bool OOPInitialized(); 1.308 + 1.309 +#ifdef MOZ_CRASHREPORTER_INJECTOR 1.310 +static nsIThread* sInjectorThread; 1.311 + 1.312 +class ReportInjectedCrash : public nsRunnable 1.313 +{ 1.314 +public: 1.315 + ReportInjectedCrash(uint32_t pid) : mPID(pid) { } 1.316 + 1.317 + NS_IMETHOD Run(); 1.318 + 1.319 +private: 1.320 + uint32_t mPID; 1.321 +}; 1.322 +#endif // MOZ_CRASHREPORTER_INJECTOR 1.323 + 1.324 +// Crashreporter annotations that we don't send along in subprocess 1.325 +// reports 1.326 +static const char* kSubprocessBlacklist[] = { 1.327 + "FramePoisonBase", 1.328 + "FramePoisonSize", 1.329 + "StartupTime", 1.330 + "URL" 1.331 +}; 1.332 + 1.333 +// If annotations are attempted before the crash reporter is enabled, 1.334 +// they queue up here. 1.335 +class DelayedNote; 1.336 +nsTArray<nsAutoPtr<DelayedNote> >* gDelayedAnnotations; 1.337 + 1.338 +#if defined(XP_WIN) 1.339 +// the following are used to prevent other DLLs reverting the last chance 1.340 +// exception handler to the windows default. Any attempt to change the 1.341 +// unhandled exception filter or to reset it is ignored and our crash 1.342 +// reporter is loaded instead (in case it became unloaded somehow) 1.343 +typedef LPTOP_LEVEL_EXCEPTION_FILTER (WINAPI *SetUnhandledExceptionFilter_func) 1.344 + (LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter); 1.345 +static SetUnhandledExceptionFilter_func stub_SetUnhandledExceptionFilter = 0; 1.346 +static LPTOP_LEVEL_EXCEPTION_FILTER previousUnhandledExceptionFilter = nullptr; 1.347 +static WindowsDllInterceptor gKernel32Intercept; 1.348 +static bool gBlockUnhandledExceptionFilter = true; 1.349 + 1.350 +static void NotePreviousUnhandledExceptionFilter() 1.351 +{ 1.352 + // Set a dummy value to get the previous filter, then restore 1.353 + previousUnhandledExceptionFilter = SetUnhandledExceptionFilter(nullptr); 1.354 + SetUnhandledExceptionFilter(previousUnhandledExceptionFilter); 1.355 +} 1.356 + 1.357 +static LPTOP_LEVEL_EXCEPTION_FILTER WINAPI 1.358 +patched_SetUnhandledExceptionFilter (LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter) 1.359 +{ 1.360 + if (!gBlockUnhandledExceptionFilter) { 1.361 + // don't intercept 1.362 + return stub_SetUnhandledExceptionFilter(lpTopLevelExceptionFilter); 1.363 + } 1.364 + 1.365 + if (lpTopLevelExceptionFilter == previousUnhandledExceptionFilter) { 1.366 + // OK to swap back and forth between the previous filter 1.367 + previousUnhandledExceptionFilter = 1.368 + stub_SetUnhandledExceptionFilter(lpTopLevelExceptionFilter); 1.369 + return previousUnhandledExceptionFilter; 1.370 + } 1.371 + 1.372 + // intercept attempts to change the filter 1.373 + return nullptr; 1.374 +} 1.375 + 1.376 +/** 1.377 + * Reserve some VM space. In the event that we crash because VM space is 1.378 + * being leaked without leaking memory, freeing this space before taking 1.379 + * the minidump will allow us to collect a minidump. 1.380 + * 1.381 + * This size is bigger than xul.dll plus some extra for MinidumpWriteDump 1.382 + * allocations. 1.383 + */ 1.384 +static const SIZE_T kReserveSize = 0x2800000; // 40 MB 1.385 +static void* gBreakpadReservedVM; 1.386 +#endif 1.387 + 1.388 +#ifdef XP_MACOSX 1.389 +static cpu_type_t pref_cpu_types[2] = { 1.390 +#if defined(__i386__) 1.391 + CPU_TYPE_X86, 1.392 +#elif defined(__x86_64__) 1.393 + CPU_TYPE_X86_64, 1.394 +#elif defined(__ppc__) 1.395 + CPU_TYPE_POWERPC, 1.396 +#endif 1.397 + CPU_TYPE_ANY }; 1.398 + 1.399 +static posix_spawnattr_t spawnattr; 1.400 +#endif 1.401 + 1.402 +#if defined(MOZ_WIDGET_ANDROID) 1.403 +// Android builds use a custom library loader, 1.404 +// so the embedding will provide a list of shared 1.405 +// libraries that are mapped into anonymous mappings. 1.406 +typedef struct { 1.407 + std::string name; 1.408 + uintptr_t start_address; 1.409 + size_t length; 1.410 + size_t file_offset; 1.411 +} mapping_info; 1.412 +static std::vector<mapping_info> library_mappings; 1.413 +typedef std::map<uint32_t,google_breakpad::MappingList> MappingMap; 1.414 +#endif 1.415 + 1.416 +#ifdef XP_LINUX 1.417 +inline void 1.418 +my_inttostring(intmax_t t, char* buffer, size_t buffer_length) 1.419 +{ 1.420 + my_memset(buffer, 0, buffer_length); 1.421 + my_uitos(buffer, t, my_uint_len(t)); 1.422 +} 1.423 +#endif 1.424 + 1.425 +#ifdef XP_WIN 1.426 +static void 1.427 +CreateFileFromPath(const xpstring& path, nsIFile** file) 1.428 +{ 1.429 + NS_NewLocalFile(nsDependentString(path.c_str()), false, file); 1.430 +} 1.431 +#else 1.432 +static void 1.433 +CreateFileFromPath(const xpstring& path, nsIFile** file) 1.434 +{ 1.435 + NS_NewNativeLocalFile(nsDependentCString(path.c_str()), false, file); 1.436 +} 1.437 +#endif 1.438 + 1.439 +static XP_CHAR* 1.440 +Concat(XP_CHAR* str, const XP_CHAR* toAppend, int* size) 1.441 +{ 1.442 + int appendLen = XP_STRLEN(toAppend); 1.443 + if (appendLen >= *size) appendLen = *size - 1; 1.444 + 1.445 + memcpy(str, toAppend, appendLen * sizeof(XP_CHAR)); 1.446 + str += appendLen; 1.447 + *str = '\0'; 1.448 + *size -= appendLen; 1.449 + 1.450 + return str; 1.451 +} 1.452 + 1.453 +static size_t gOOMAllocationSize = 0; 1.454 + 1.455 +void AnnotateOOMAllocationSize(size_t size) 1.456 +{ 1.457 + gOOMAllocationSize = size; 1.458 +} 1.459 + 1.460 +bool MinidumpCallback( 1.461 +#ifdef XP_LINUX 1.462 + const MinidumpDescriptor& descriptor, 1.463 +#else 1.464 + const XP_CHAR* dump_path, 1.465 + const XP_CHAR* minidump_id, 1.466 +#endif 1.467 + void* context, 1.468 +#ifdef XP_WIN32 1.469 + EXCEPTION_POINTERS* exinfo, 1.470 + MDRawAssertionInfo* assertion, 1.471 +#endif 1.472 + bool succeeded) 1.473 +{ 1.474 + bool returnValue = showOSCrashReporter ? false : succeeded; 1.475 + 1.476 + static XP_CHAR minidumpPath[XP_PATH_MAX]; 1.477 + int size = XP_PATH_MAX; 1.478 + XP_CHAR* p; 1.479 +#ifndef XP_LINUX 1.480 + p = Concat(minidumpPath, dump_path, &size); 1.481 + p = Concat(p, XP_PATH_SEPARATOR, &size); 1.482 + p = Concat(p, minidump_id, &size); 1.483 + Concat(p, dumpFileExtension, &size); 1.484 +#else 1.485 + Concat(minidumpPath, descriptor.path(), &size); 1.486 +#endif 1.487 + 1.488 + static XP_CHAR extraDataPath[XP_PATH_MAX]; 1.489 + size = XP_PATH_MAX; 1.490 +#ifndef XP_LINUX 1.491 + p = Concat(extraDataPath, dump_path, &size); 1.492 + p = Concat(p, XP_PATH_SEPARATOR, &size); 1.493 + p = Concat(p, minidump_id, &size); 1.494 +#else 1.495 + p = Concat(extraDataPath, descriptor.path(), &size); 1.496 + // Skip back past the .dmp extension. 1.497 + p -= 4; 1.498 +#endif 1.499 + Concat(p, extraFileExtension, &size); 1.500 + 1.501 + if (headlessClient) { 1.502 + // Leave a marker indicating that there was a crash. 1.503 +#if defined(XP_WIN32) 1.504 + HANDLE hFile = CreateFile(crashMarkerFilename, GENERIC_WRITE, 0, 1.505 + nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 1.506 + nullptr); 1.507 + if(hFile != INVALID_HANDLE_VALUE) { 1.508 + DWORD nBytes; 1.509 + WriteFile(hFile, minidumpPath, 2*wcslen(minidumpPath), &nBytes, nullptr); 1.510 + CloseHandle(hFile); 1.511 + } 1.512 +#elif defined(XP_UNIX) 1.513 + int fd = sys_open(crashMarkerFilename, 1.514 + O_WRONLY | O_CREAT | O_TRUNC, 1.515 + 0600); 1.516 + if (fd != -1) { 1.517 + unused << sys_write(fd, minidumpPath, my_strlen(minidumpPath)); 1.518 + sys_close(fd); 1.519 + } 1.520 +#endif 1.521 + } 1.522 + 1.523 + char oomAllocationSizeBuffer[32]; 1.524 + int oomAllocationSizeBufferLen = 0; 1.525 + if (gOOMAllocationSize) { 1.526 + XP_STOA(gOOMAllocationSize, oomAllocationSizeBuffer, 10); 1.527 + oomAllocationSizeBufferLen = my_strlen(oomAllocationSizeBuffer); 1.528 + } 1.529 + 1.530 + // calculate time since last crash (if possible), and store 1.531 + // the time of this crash. 1.532 + time_t crashTime; 1.533 +#ifdef XP_LINUX 1.534 + struct kernel_timeval tv; 1.535 + sys_gettimeofday(&tv, nullptr); 1.536 + crashTime = tv.tv_sec; 1.537 +#else 1.538 + crashTime = time(nullptr); 1.539 +#endif 1.540 + time_t timeSinceLastCrash = 0; 1.541 + // stringified versions of the above 1.542 + char crashTimeString[32]; 1.543 + int crashTimeStringLen = 0; 1.544 + char timeSinceLastCrashString[32]; 1.545 + int timeSinceLastCrashStringLen = 0; 1.546 + 1.547 + XP_TTOA(crashTime, crashTimeString, 10); 1.548 + crashTimeStringLen = my_strlen(crashTimeString); 1.549 + if (lastCrashTime != 0) { 1.550 + timeSinceLastCrash = crashTime - lastCrashTime; 1.551 + XP_TTOA(timeSinceLastCrash, timeSinceLastCrashString, 10); 1.552 + timeSinceLastCrashStringLen = my_strlen(timeSinceLastCrashString); 1.553 + } 1.554 + // write crash time to file 1.555 + if (lastCrashTimeFilename[0] != 0) { 1.556 +#if defined(XP_WIN32) 1.557 + HANDLE hFile = CreateFile(lastCrashTimeFilename, GENERIC_WRITE, 0, 1.558 + nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 1.559 + nullptr); 1.560 + if(hFile != INVALID_HANDLE_VALUE) { 1.561 + DWORD nBytes; 1.562 + WriteFile(hFile, crashTimeString, crashTimeStringLen, &nBytes, nullptr); 1.563 + CloseHandle(hFile); 1.564 + } 1.565 +#elif defined(XP_UNIX) 1.566 + int fd = sys_open(lastCrashTimeFilename, 1.567 + O_WRONLY | O_CREAT | O_TRUNC, 1.568 + 0600); 1.569 + if (fd != -1) { 1.570 + unused << sys_write(fd, crashTimeString, crashTimeStringLen); 1.571 + sys_close(fd); 1.572 + } 1.573 +#endif 1.574 + } 1.575 + 1.576 + // Write crash event file. 1.577 + 1.578 + // Minidump IDs are UUIDs (36) + NULL. 1.579 + static char id_ascii[37]; 1.580 +#ifdef XP_LINUX 1.581 + const char * index = strrchr(descriptor.path(), '/'); 1.582 + MOZ_ASSERT(index); 1.583 + MOZ_ASSERT(strlen(index) == 1 + 36 + 4); // "/" + UUID + ".dmp" 1.584 + for (uint32_t i = 0; i < 36; i++) { 1.585 + id_ascii[i] = *(index + 1 + i); 1.586 + } 1.587 +#else 1.588 + MOZ_ASSERT(XP_STRLEN(minidump_id) == 36); 1.589 + for (uint32_t i = 0; i < 36; i++) { 1.590 + id_ascii[i] = *((char *)(minidump_id + i)); 1.591 + } 1.592 +#endif 1.593 + 1.594 + if (eventsDirectory) { 1.595 + static XP_CHAR crashEventPath[XP_PATH_MAX]; 1.596 + int size = XP_PATH_MAX; 1.597 + XP_CHAR* p; 1.598 + p = Concat(crashEventPath, eventsDirectory, &size); 1.599 + p = Concat(p, XP_PATH_SEPARATOR, &size); 1.600 +#ifdef XP_LINUX 1.601 + p = Concat(p, id_ascii, &size); 1.602 +#else 1.603 + p = Concat(p, minidump_id, &size); 1.604 +#endif 1.605 + 1.606 +#if defined(XP_WIN32) 1.607 + HANDLE hFile = CreateFile(crashEventPath, GENERIC_WRITE, 0, 1.608 + nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 1.609 + nullptr); 1.610 + if (hFile != INVALID_HANDLE_VALUE) { 1.611 + DWORD nBytes; 1.612 + WriteFile(hFile, kCrashMainID, sizeof(kCrashMainID) - 1, &nBytes, 1.613 + nullptr); 1.614 + WriteFile(hFile, crashTimeString, crashTimeStringLen, &nBytes, nullptr); 1.615 + WriteFile(hFile, "\n", 1, &nBytes, nullptr); 1.616 + WriteFile(hFile, id_ascii, strlen(id_ascii), &nBytes, nullptr); 1.617 + CloseHandle(hFile); 1.618 + } 1.619 +#elif defined(XP_UNIX) 1.620 + int fd = sys_open(crashEventPath, 1.621 + O_WRONLY | O_CREAT | O_TRUNC, 1.622 + 0600); 1.623 + if (fd != -1) { 1.624 + unused << sys_write(fd, kCrashMainID, sizeof(kCrashMainID) - 1); 1.625 + unused << sys_write(fd, crashTimeString, crashTimeStringLen); 1.626 + unused << sys_write(fd, "\n", 1); 1.627 + unused << sys_write(fd, id_ascii, strlen(id_ascii)); 1.628 + sys_close(fd); 1.629 + } 1.630 +#endif 1.631 + } 1.632 + 1.633 +#if defined(XP_WIN32) 1.634 + if (!crashReporterAPIData->IsEmpty()) { 1.635 + // write out API data 1.636 + HANDLE hFile = CreateFile(extraDataPath, GENERIC_WRITE, 0, 1.637 + nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 1.638 + nullptr); 1.639 + if(hFile != INVALID_HANDLE_VALUE) { 1.640 + DWORD nBytes; 1.641 + WriteFile(hFile, crashReporterAPIData->get(), 1.642 + crashReporterAPIData->Length(), &nBytes, nullptr); 1.643 + WriteFile(hFile, kCrashTimeParameter, kCrashTimeParameterLen, 1.644 + &nBytes, nullptr); 1.645 + WriteFile(hFile, crashTimeString, crashTimeStringLen, &nBytes, nullptr); 1.646 + WriteFile(hFile, "\n", 1, &nBytes, nullptr); 1.647 + if (timeSinceLastCrash != 0) { 1.648 + WriteFile(hFile, kTimeSinceLastCrashParameter, 1.649 + kTimeSinceLastCrashParameterLen, &nBytes, nullptr); 1.650 + WriteFile(hFile, timeSinceLastCrashString, timeSinceLastCrashStringLen, 1.651 + &nBytes, nullptr); 1.652 + WriteFile(hFile, "\n", 1, &nBytes, nullptr); 1.653 + } 1.654 + if (isGarbageCollecting) { 1.655 + WriteFile(hFile, kIsGarbageCollectingParameter, kIsGarbageCollectingParameterLen, 1.656 + &nBytes, nullptr); 1.657 + WriteFile(hFile, isGarbageCollecting ? "1" : "0", 1, &nBytes, nullptr); 1.658 + WriteFile(hFile, "\n", 1, &nBytes, nullptr); 1.659 + } 1.660 + 1.661 + char buffer[128]; 1.662 + int bufferLen; 1.663 + 1.664 + if (eventloopNestingLevel > 0) { 1.665 + WriteFile(hFile, kEventLoopNestingLevelParameter, kEventLoopNestingLevelParameterLen, 1.666 + &nBytes, nullptr); 1.667 + _ultoa(eventloopNestingLevel, buffer, 10); 1.668 + WriteFile(hFile, buffer, strlen(buffer), &nBytes, nullptr); 1.669 + WriteFile(hFile, "\n", 1, &nBytes, nullptr); 1.670 + } 1.671 + 1.672 + if (gBreakpadReservedVM) { 1.673 + WriteFile(hFile, kBreakpadReserveAddressParameter, kBreakpadReserveAddressParameterLen, &nBytes, nullptr); 1.674 + _ui64toa(uintptr_t(gBreakpadReservedVM), buffer, 10); 1.675 + WriteFile(hFile, buffer, strlen(buffer), &nBytes, nullptr); 1.676 + WriteFile(hFile, "\n", 1, &nBytes, nullptr); 1.677 + WriteFile(hFile, kBreakpadReserveSizeParameter, kBreakpadReserveSizeParameterLen, &nBytes, nullptr); 1.678 + _ui64toa(kReserveSize, buffer, 10); 1.679 + WriteFile(hFile, buffer, strlen(buffer), &nBytes, nullptr); 1.680 + WriteFile(hFile, "\n", 1, &nBytes, nullptr); 1.681 + } 1.682 + 1.683 +#ifdef HAS_DLL_BLOCKLIST 1.684 + DllBlocklist_WriteNotes(hFile); 1.685 +#endif 1.686 + 1.687 + // Try to get some information about memory. 1.688 + MEMORYSTATUSEX statex; 1.689 + statex.dwLength = sizeof(statex); 1.690 + if (GlobalMemoryStatusEx(&statex)) { 1.691 + 1.692 +#define WRITE_STATEX_FIELD(field, paramName, conversionFunc) \ 1.693 + WriteFile(hFile, k##paramName##Parameter, \ 1.694 + k##paramName##ParameterLen, &nBytes, nullptr); \ 1.695 + conversionFunc(statex.field, buffer, 10); \ 1.696 + bufferLen = strlen(buffer); \ 1.697 + WriteFile(hFile, buffer, bufferLen, &nBytes, nullptr); \ 1.698 + WriteFile(hFile, "\n", 1, &nBytes, nullptr); 1.699 + 1.700 + WRITE_STATEX_FIELD(dwMemoryLoad, SysMemory, ltoa); 1.701 + WRITE_STATEX_FIELD(ullTotalVirtual, TotalVirtualMemory, _ui64toa); 1.702 + WRITE_STATEX_FIELD(ullAvailVirtual, AvailableVirtualMemory, _ui64toa); 1.703 + WRITE_STATEX_FIELD(ullTotalPageFile, TotalPageFile, _ui64toa); 1.704 + WRITE_STATEX_FIELD(ullAvailPageFile, AvailablePageFile, _ui64toa); 1.705 + WRITE_STATEX_FIELD(ullTotalPhys, TotalPhysicalMemory, _ui64toa); 1.706 + WRITE_STATEX_FIELD(ullAvailPhys, AvailablePhysicalMemory, _ui64toa); 1.707 + 1.708 +#undef WRITE_STATEX_FIELD 1.709 + } 1.710 + 1.711 + if (oomAllocationSizeBufferLen) { 1.712 + WriteFile(hFile, kOOMAllocationSizeParameter, 1.713 + kOOMAllocationSizeParameterLen, &nBytes, nullptr); 1.714 + WriteFile(hFile, oomAllocationSizeBuffer, oomAllocationSizeBufferLen, 1.715 + &nBytes, nullptr); 1.716 + WriteFile(hFile, "\n", 1, &nBytes, nullptr); 1.717 + } 1.718 + CloseHandle(hFile); 1.719 + } 1.720 + } 1.721 + 1.722 + if (!doReport) { 1.723 + return returnValue; 1.724 + } 1.725 + 1.726 + XP_CHAR cmdLine[CMDLINE_SIZE]; 1.727 + size = CMDLINE_SIZE; 1.728 + p = Concat(cmdLine, L"\"", &size); 1.729 + p = Concat(p, crashReporterPath, &size); 1.730 + p = Concat(p, L"\" \"", &size); 1.731 + p = Concat(p, minidumpPath, &size); 1.732 + Concat(p, L"\"", &size); 1.733 + 1.734 + STARTUPINFO si; 1.735 + PROCESS_INFORMATION pi; 1.736 + 1.737 + ZeroMemory(&si, sizeof(si)); 1.738 + si.cb = sizeof(si); 1.739 + si.dwFlags = STARTF_USESHOWWINDOW; 1.740 + si.wShowWindow = SW_SHOWNORMAL; 1.741 + ZeroMemory(&pi, sizeof(pi)); 1.742 + 1.743 + if (CreateProcess(nullptr, (LPWSTR)cmdLine, nullptr, nullptr, FALSE, 0, 1.744 + nullptr, nullptr, &si, &pi)) { 1.745 + CloseHandle( pi.hProcess ); 1.746 + CloseHandle( pi.hThread ); 1.747 + } 1.748 + // we're not really in a position to do anything if the CreateProcess fails 1.749 + TerminateProcess(GetCurrentProcess(), 1); 1.750 +#elif defined(XP_UNIX) 1.751 + if (!crashReporterAPIData->IsEmpty()) { 1.752 + // write out API data 1.753 + int fd = sys_open(extraDataPath, 1.754 + O_WRONLY | O_CREAT | O_TRUNC, 1.755 + 0666); 1.756 + 1.757 + if (fd != -1) { 1.758 + // not much we can do in case of error 1.759 + unused << sys_write(fd, crashReporterAPIData->get(), 1.760 + crashReporterAPIData->Length()); 1.761 + unused << sys_write(fd, kCrashTimeParameter, kCrashTimeParameterLen); 1.762 + unused << sys_write(fd, crashTimeString, crashTimeStringLen); 1.763 + unused << sys_write(fd, "\n", 1); 1.764 + if (timeSinceLastCrash != 0) { 1.765 + unused << sys_write(fd, kTimeSinceLastCrashParameter, 1.766 + kTimeSinceLastCrashParameterLen); 1.767 + unused << sys_write(fd, timeSinceLastCrashString, 1.768 + timeSinceLastCrashStringLen); 1.769 + unused << sys_write(fd, "\n", 1); 1.770 + } 1.771 + if (isGarbageCollecting) { 1.772 + unused << sys_write(fd, kIsGarbageCollectingParameter, kIsGarbageCollectingParameterLen); 1.773 + unused << sys_write(fd, isGarbageCollecting ? "1" : "0", 1); 1.774 + unused << sys_write(fd, "\n", 1); 1.775 + } 1.776 + if (eventloopNestingLevel > 0) { 1.777 + unused << sys_write(fd, kEventLoopNestingLevelParameter, kEventLoopNestingLevelParameterLen); 1.778 + char buffer[16]; 1.779 + XP_TTOA(eventloopNestingLevel, buffer, 10); 1.780 + unused << sys_write(fd, buffer, my_strlen(buffer)); 1.781 + unused << sys_write(fd, "\n", 1); 1.782 + } 1.783 + if (oomAllocationSizeBufferLen) { 1.784 + unused << sys_write(fd, kOOMAllocationSizeParameter, 1.785 + kOOMAllocationSizeParameterLen); 1.786 + unused << sys_write(fd, oomAllocationSizeBuffer, 1.787 + oomAllocationSizeBufferLen); 1.788 + unused << sys_write(fd, "\n", 1); 1.789 + } 1.790 + sys_close(fd); 1.791 + } 1.792 + } 1.793 + 1.794 + if (!doReport) { 1.795 + return returnValue; 1.796 + } 1.797 + 1.798 +#ifdef XP_MACOSX 1.799 + char* const my_argv[] = { 1.800 + crashReporterPath, 1.801 + minidumpPath, 1.802 + nullptr 1.803 + }; 1.804 + 1.805 + char **env = nullptr; 1.806 + char ***nsEnv = _NSGetEnviron(); 1.807 + if (nsEnv) 1.808 + env = *nsEnv; 1.809 + int result = posix_spawnp(nullptr, 1.810 + my_argv[0], 1.811 + nullptr, 1.812 + &spawnattr, 1.813 + my_argv, 1.814 + env); 1.815 + 1.816 + if (result != 0) 1.817 + return false; 1.818 + 1.819 +#else // !XP_MACOSX 1.820 + pid_t pid = sys_fork(); 1.821 + 1.822 + if (pid == -1) 1.823 + return false; 1.824 + else if (pid == 0) { 1.825 +#if !defined(MOZ_WIDGET_ANDROID) 1.826 + // need to clobber this, as libcurl might load NSS, 1.827 + // and we want it to load the system NSS. 1.828 + unsetenv("LD_LIBRARY_PATH"); 1.829 + unused << execl(crashReporterPath, 1.830 + crashReporterPath, minidumpPath, (char*)0); 1.831 +#else 1.832 + // Invoke the reportCrash activity using am 1.833 + if (androidUserSerial) { 1.834 + unused << execlp("/system/bin/am", 1.835 + "/system/bin/am", 1.836 + "start", 1.837 + "--user", androidUserSerial, 1.838 + "-a", "org.mozilla.gecko.reportCrash", 1.839 + "-n", crashReporterPath, 1.840 + "--es", "minidumpPath", minidumpPath, 1.841 + (char*)0); 1.842 + } else { 1.843 + unused << execlp("/system/bin/am", 1.844 + "/system/bin/am", 1.845 + "start", 1.846 + "-a", "org.mozilla.gecko.reportCrash", 1.847 + "-n", crashReporterPath, 1.848 + "--es", "minidumpPath", minidumpPath, 1.849 + (char*)0); 1.850 + } 1.851 +#endif 1.852 + _exit(1); 1.853 + } 1.854 +#endif // XP_MACOSX 1.855 +#endif // XP_UNIX 1.856 + 1.857 + return returnValue; 1.858 +} 1.859 + 1.860 +#ifdef XP_WIN 1.861 +static void 1.862 +ReserveBreakpadVM() 1.863 +{ 1.864 + if (!gBreakpadReservedVM) { 1.865 + gBreakpadReservedVM = VirtualAlloc(nullptr, kReserveSize, MEM_RESERVE, 1.866 + PAGE_NOACCESS); 1.867 + } 1.868 +} 1.869 + 1.870 +static void 1.871 +FreeBreakpadVM() 1.872 +{ 1.873 + if (gBreakpadReservedVM) { 1.874 + VirtualFree(gBreakpadReservedVM, 0, MEM_RELEASE); 1.875 + } 1.876 +} 1.877 + 1.878 +/** 1.879 + * Filters out floating point exceptions which are handled by nsSigHandlers.cpp 1.880 + * and should not be handled as crashes. 1.881 + * 1.882 + * Also calls FreeBreakpadVM if appropriate. 1.883 + */ 1.884 +static bool FPEFilter(void* context, EXCEPTION_POINTERS* exinfo, 1.885 + MDRawAssertionInfo* assertion) 1.886 +{ 1.887 + if (!exinfo) { 1.888 + mozilla::IOInterposer::Disable(); 1.889 + FreeBreakpadVM(); 1.890 + return true; 1.891 + } 1.892 + 1.893 + PEXCEPTION_RECORD e = (PEXCEPTION_RECORD)exinfo->ExceptionRecord; 1.894 + switch (e->ExceptionCode) { 1.895 + case STATUS_FLOAT_DENORMAL_OPERAND: 1.896 + case STATUS_FLOAT_DIVIDE_BY_ZERO: 1.897 + case STATUS_FLOAT_INEXACT_RESULT: 1.898 + case STATUS_FLOAT_INVALID_OPERATION: 1.899 + case STATUS_FLOAT_OVERFLOW: 1.900 + case STATUS_FLOAT_STACK_CHECK: 1.901 + case STATUS_FLOAT_UNDERFLOW: 1.902 + case STATUS_FLOAT_MULTIPLE_FAULTS: 1.903 + case STATUS_FLOAT_MULTIPLE_TRAPS: 1.904 + return false; // Don't write minidump, continue exception search 1.905 + } 1.906 + mozilla::IOInterposer::Disable(); 1.907 + FreeBreakpadVM(); 1.908 + return true; 1.909 +} 1.910 +#endif // XP_WIN 1.911 + 1.912 +static bool ShouldReport() 1.913 +{ 1.914 + // this environment variable prevents us from launching 1.915 + // the crash reporter client 1.916 + const char *envvar = PR_GetEnv("MOZ_CRASHREPORTER_NO_REPORT"); 1.917 + if (envvar && *envvar) { 1.918 + return false; 1.919 + } 1.920 + 1.921 + envvar = PR_GetEnv("MOZ_CRASHREPORTER_FULLDUMP"); 1.922 + if (envvar && *envvar) { 1.923 + return false; 1.924 + } 1.925 + 1.926 + return true; 1.927 +} 1.928 + 1.929 +namespace { 1.930 + bool Filter(void* context) { 1.931 + mozilla::IOInterposer::Disable(); 1.932 + return true; 1.933 + } 1.934 +} 1.935 + 1.936 + 1.937 +nsresult SetExceptionHandler(nsIFile* aXREDirectory, 1.938 + bool force/*=false*/) 1.939 +{ 1.940 + if (gExceptionHandler) 1.941 + return NS_ERROR_ALREADY_INITIALIZED; 1.942 + 1.943 +#if !defined(DEBUG) || defined(MOZ_WIDGET_GONK) 1.944 + // In non-debug builds, enable the crash reporter by default, and allow 1.945 + // disabling it with the MOZ_CRASHREPORTER_DISABLE environment variable. 1.946 + // Also enable it by default in debug gonk builds as it is difficult to 1.947 + // set environment on startup. 1.948 + const char *envvar = PR_GetEnv("MOZ_CRASHREPORTER_DISABLE"); 1.949 + if (envvar && *envvar && !force) 1.950 + return NS_OK; 1.951 +#else 1.952 + // In debug builds, disable the crash reporter by default, and allow to 1.953 + // enable it with the MOZ_CRASHREPORTER environment variable. 1.954 + const char *envvar = PR_GetEnv("MOZ_CRASHREPORTER"); 1.955 + if ((!envvar || !*envvar) && !force) 1.956 + return NS_OK; 1.957 +#endif 1.958 + 1.959 +#if defined(MOZ_WIDGET_GONK) 1.960 + doReport = false; 1.961 + headlessClient = true; 1.962 +#elif defined(XP_WIN) 1.963 + if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Desktop) { 1.964 + doReport = ShouldReport(); 1.965 + } else { 1.966 + doReport = false; 1.967 + headlessClient = true; 1.968 + } 1.969 +#else 1.970 + // this environment variable prevents us from launching 1.971 + // the crash reporter client 1.972 + doReport = ShouldReport(); 1.973 +#endif 1.974 + 1.975 + // allocate our strings 1.976 + crashReporterAPIData = new nsCString(); 1.977 + NS_ENSURE_TRUE(crashReporterAPIData, NS_ERROR_OUT_OF_MEMORY); 1.978 + 1.979 + NS_ASSERTION(!crashReporterAPILock, "Shouldn't have a lock yet"); 1.980 + crashReporterAPILock = new Mutex("crashReporterAPILock"); 1.981 + NS_ASSERTION(!notesFieldLock, "Shouldn't have a lock yet"); 1.982 + notesFieldLock = new Mutex("notesFieldLock"); 1.983 + 1.984 + crashReporterAPIData_Hash = 1.985 + new nsDataHashtable<nsCStringHashKey,nsCString>(); 1.986 + NS_ENSURE_TRUE(crashReporterAPIData_Hash, NS_ERROR_OUT_OF_MEMORY); 1.987 + 1.988 + notesField = new nsCString(); 1.989 + NS_ENSURE_TRUE(notesField, NS_ERROR_OUT_OF_MEMORY); 1.990 + 1.991 + if (!headlessClient) { 1.992 + // locate crashreporter executable 1.993 + nsCOMPtr<nsIFile> exePath; 1.994 + nsresult rv = aXREDirectory->Clone(getter_AddRefs(exePath)); 1.995 + NS_ENSURE_SUCCESS(rv, rv); 1.996 + 1.997 +#if defined(XP_MACOSX) 1.998 + exePath->Append(NS_LITERAL_STRING("crashreporter.app")); 1.999 + exePath->Append(NS_LITERAL_STRING("Contents")); 1.1000 + exePath->Append(NS_LITERAL_STRING("MacOS")); 1.1001 +#endif 1.1002 + 1.1003 + exePath->AppendNative(NS_LITERAL_CSTRING(CRASH_REPORTER_FILENAME)); 1.1004 + 1.1005 +#ifdef XP_WIN32 1.1006 + nsString crashReporterPath_temp; 1.1007 + 1.1008 + exePath->GetPath(crashReporterPath_temp); 1.1009 + crashReporterPath = reinterpret_cast<wchar_t*>(ToNewUnicode(crashReporterPath_temp)); 1.1010 +#elif !defined(__ANDROID__) 1.1011 + nsCString crashReporterPath_temp; 1.1012 + 1.1013 + exePath->GetNativePath(crashReporterPath_temp); 1.1014 + crashReporterPath = ToNewCString(crashReporterPath_temp); 1.1015 +#else 1.1016 + // On Android, we launch using the application package name 1.1017 + // instead of a filename, so use ANDROID_PACKAGE_NAME to do that here. 1.1018 + nsCString package(ANDROID_PACKAGE_NAME "/org.mozilla.gecko.CrashReporter"); 1.1019 + crashReporterPath = ToNewCString(package); 1.1020 +#endif 1.1021 + } 1.1022 + 1.1023 + // get temp path to use for minidump path 1.1024 +#if defined(XP_WIN32) 1.1025 + nsString tempPath; 1.1026 + 1.1027 + // first figure out buffer size 1.1028 + int pathLen = GetTempPath(0, nullptr); 1.1029 + if (pathLen == 0) 1.1030 + return NS_ERROR_FAILURE; 1.1031 + 1.1032 + tempPath.SetLength(pathLen); 1.1033 + GetTempPath(pathLen, (LPWSTR)tempPath.BeginWriting()); 1.1034 +#elif defined(XP_MACOSX) 1.1035 + nsCString tempPath; 1.1036 + FSRef fsRef; 1.1037 + OSErr err = FSFindFolder(kUserDomain, kTemporaryFolderType, 1.1038 + kCreateFolder, &fsRef); 1.1039 + if (err != noErr) 1.1040 + return NS_ERROR_FAILURE; 1.1041 + 1.1042 + char path[PATH_MAX]; 1.1043 + OSStatus status = FSRefMakePath(&fsRef, (UInt8*)path, PATH_MAX); 1.1044 + if (status != noErr) 1.1045 + return NS_ERROR_FAILURE; 1.1046 + 1.1047 + tempPath = path; 1.1048 + 1.1049 +#elif defined(__ANDROID__) 1.1050 + // GeckoAppShell or Gonk's init.rc sets this in the environment 1.1051 + const char *tempenv = PR_GetEnv("TMPDIR"); 1.1052 + if (!tempenv) 1.1053 + return NS_ERROR_FAILURE; 1.1054 + nsCString tempPath(tempenv); 1.1055 +#elif defined(XP_UNIX) 1.1056 + // we assume it's always /tmp on unix systems 1.1057 + nsCString tempPath = NS_LITERAL_CSTRING("/tmp/"); 1.1058 +#else 1.1059 +#error "Implement this for your platform" 1.1060 +#endif 1.1061 + 1.1062 +#ifdef XP_MACOSX 1.1063 + // Initialize spawn attributes, since this calls malloc. 1.1064 + if (posix_spawnattr_init(&spawnattr) != 0) { 1.1065 + return NS_ERROR_FAILURE; 1.1066 + } 1.1067 + 1.1068 + // Set spawn attributes. 1.1069 + size_t attr_count = ArrayLength(pref_cpu_types); 1.1070 + size_t attr_ocount = 0; 1.1071 + if (posix_spawnattr_setbinpref_np(&spawnattr, 1.1072 + attr_count, 1.1073 + pref_cpu_types, 1.1074 + &attr_ocount) != 0 || 1.1075 + attr_ocount != attr_count) { 1.1076 + posix_spawnattr_destroy(&spawnattr); 1.1077 + return NS_ERROR_FAILURE; 1.1078 + } 1.1079 +#endif 1.1080 + 1.1081 +#ifdef XP_WIN32 1.1082 + ReserveBreakpadVM(); 1.1083 + 1.1084 + MINIDUMP_TYPE minidump_type = MiniDumpNormal; 1.1085 + 1.1086 + // Try to determine what version of dbghelp.dll we're using. 1.1087 + // MinidumpWithFullMemoryInfo is only available in 6.1.x or newer. 1.1088 + 1.1089 + DWORD version_size = GetFileVersionInfoSizeW(L"dbghelp.dll", nullptr); 1.1090 + if (version_size > 0) { 1.1091 + std::vector<BYTE> buffer(version_size); 1.1092 + if (GetFileVersionInfoW(L"dbghelp.dll", 1.1093 + 0, 1.1094 + version_size, 1.1095 + &buffer[0])) { 1.1096 + UINT len; 1.1097 + VS_FIXEDFILEINFO* file_info; 1.1098 + VerQueryValue(&buffer[0], L"\\", (void**)&file_info, &len); 1.1099 + WORD major = HIWORD(file_info->dwFileVersionMS), 1.1100 + minor = LOWORD(file_info->dwFileVersionMS), 1.1101 + revision = HIWORD(file_info->dwFileVersionLS); 1.1102 + if (major > 6 || (major == 6 && minor > 1) || 1.1103 + (major == 6 && minor == 1 && revision >= 7600)) { 1.1104 + minidump_type = MiniDumpWithFullMemoryInfo; 1.1105 + } 1.1106 + } 1.1107 + } 1.1108 + 1.1109 + const char* e = PR_GetEnv("MOZ_CRASHREPORTER_FULLDUMP"); 1.1110 + if (e && *e) { 1.1111 + minidump_type = MiniDumpWithFullMemory; 1.1112 + } 1.1113 +#endif // XP_WIN32 1.1114 + 1.1115 +#ifdef MOZ_WIDGET_ANDROID 1.1116 + androidUserSerial = getenv("MOZ_ANDROID_USER_SERIAL_NUMBER"); 1.1117 +#endif 1.1118 + 1.1119 + // Initialize the flag and mutex used to avoid dump processing 1.1120 + // once browser termination has begun. 1.1121 + NS_ASSERTION(!dumpSafetyLock, "Shouldn't have a lock yet"); 1.1122 + // Do not deallocate this lock while it is still possible for 1.1123 + // isSafeToDump to be tested on another thread. 1.1124 + dumpSafetyLock = new Mutex("dumpSafetyLock"); 1.1125 + MutexAutoLock lock(*dumpSafetyLock); 1.1126 + isSafeToDump = true; 1.1127 + 1.1128 + // now set the exception handler 1.1129 +#ifdef XP_LINUX 1.1130 + MinidumpDescriptor descriptor(tempPath.get()); 1.1131 +#endif 1.1132 + 1.1133 +#ifdef XP_WIN 1.1134 + NotePreviousUnhandledExceptionFilter(); 1.1135 +#endif 1.1136 + 1.1137 + gExceptionHandler = new google_breakpad:: 1.1138 + ExceptionHandler( 1.1139 +#ifdef XP_LINUX 1.1140 + descriptor, 1.1141 +#else 1.1142 + tempPath.get(), 1.1143 +#endif 1.1144 + 1.1145 +#ifdef XP_WIN 1.1146 + FPEFilter, 1.1147 +#else 1.1148 + Filter, 1.1149 +#endif 1.1150 + MinidumpCallback, 1.1151 + nullptr, 1.1152 +#ifdef XP_WIN32 1.1153 + google_breakpad::ExceptionHandler::HANDLER_ALL, 1.1154 + minidump_type, 1.1155 + (const wchar_t*) nullptr, 1.1156 + nullptr); 1.1157 +#else 1.1158 + true 1.1159 +#ifdef XP_MACOSX 1.1160 + , nullptr 1.1161 +#endif 1.1162 +#ifdef XP_LINUX 1.1163 + , -1 1.1164 +#endif 1.1165 + ); 1.1166 +#endif // XP_WIN32 1.1167 + 1.1168 + if (!gExceptionHandler) 1.1169 + return NS_ERROR_OUT_OF_MEMORY; 1.1170 + 1.1171 +#ifdef XP_WIN 1.1172 + gExceptionHandler->set_handle_debug_exceptions(true); 1.1173 + 1.1174 + // protect the crash reporter from being unloaded 1.1175 + gBlockUnhandledExceptionFilter = true; 1.1176 + gKernel32Intercept.Init("kernel32.dll"); 1.1177 + bool ok = gKernel32Intercept.AddHook("SetUnhandledExceptionFilter", 1.1178 + reinterpret_cast<intptr_t>(patched_SetUnhandledExceptionFilter), 1.1179 + (void**) &stub_SetUnhandledExceptionFilter); 1.1180 + 1.1181 +#ifdef DEBUG 1.1182 + if (!ok) 1.1183 + printf_stderr ("SetUnhandledExceptionFilter hook failed; crash reporter is vulnerable.\n"); 1.1184 +#endif 1.1185 +#endif 1.1186 + 1.1187 + // store application start time 1.1188 + char timeString[32]; 1.1189 + time_t startupTime = time(nullptr); 1.1190 + XP_TTOA(startupTime, timeString, 10); 1.1191 + AnnotateCrashReport(NS_LITERAL_CSTRING("StartupTime"), 1.1192 + nsDependentCString(timeString)); 1.1193 + 1.1194 +#if defined(XP_MACOSX) 1.1195 + // On OS X, many testers like to see the OS crash reporting dialog 1.1196 + // since it offers immediate stack traces. We allow them to set 1.1197 + // a default to pass exceptions to the OS handler. 1.1198 + Boolean keyExistsAndHasValidFormat = false; 1.1199 + Boolean prefValue = ::CFPreferencesGetAppBooleanValue(CFSTR("OSCrashReporter"), 1.1200 + kCFPreferencesCurrentApplication, 1.1201 + &keyExistsAndHasValidFormat); 1.1202 + if (keyExistsAndHasValidFormat) 1.1203 + showOSCrashReporter = prefValue; 1.1204 +#endif 1.1205 + 1.1206 +#if defined(MOZ_WIDGET_ANDROID) 1.1207 + for (unsigned int i = 0; i < library_mappings.size(); i++) { 1.1208 + u_int8_t guid[sizeof(MDGUID)]; 1.1209 + google_breakpad::FileID::ElfFileIdentifierFromMappedFile((void const *)library_mappings[i].start_address, guid); 1.1210 + gExceptionHandler->AddMappingInfo(library_mappings[i].name, 1.1211 + guid, 1.1212 + library_mappings[i].start_address, 1.1213 + library_mappings[i].length, 1.1214 + library_mappings[i].file_offset); 1.1215 + } 1.1216 +#endif 1.1217 + 1.1218 + mozalloc_set_oom_abort_handler(AnnotateOOMAllocationSize); 1.1219 + 1.1220 + return NS_OK; 1.1221 +} 1.1222 + 1.1223 +bool GetEnabled() 1.1224 +{ 1.1225 + return gExceptionHandler != nullptr; 1.1226 +} 1.1227 + 1.1228 +bool GetMinidumpPath(nsAString& aPath) 1.1229 +{ 1.1230 + if (!gExceptionHandler) 1.1231 + return false; 1.1232 + 1.1233 +#ifndef XP_LINUX 1.1234 + aPath = CONVERT_XP_CHAR_TO_UTF16(gExceptionHandler->dump_path().c_str()); 1.1235 +#else 1.1236 + aPath = CONVERT_XP_CHAR_TO_UTF16( 1.1237 + gExceptionHandler->minidump_descriptor().directory().c_str()); 1.1238 +#endif 1.1239 + return true; 1.1240 +} 1.1241 + 1.1242 +nsresult SetMinidumpPath(const nsAString& aPath) 1.1243 +{ 1.1244 + if (!gExceptionHandler) 1.1245 + return NS_ERROR_NOT_INITIALIZED; 1.1246 + 1.1247 +#ifdef XP_WIN32 1.1248 + gExceptionHandler->set_dump_path(char16ptr_t(aPath.BeginReading())); 1.1249 +#elif defined(XP_LINUX) 1.1250 + gExceptionHandler->set_minidump_descriptor( 1.1251 + MinidumpDescriptor(NS_ConvertUTF16toUTF8(aPath).BeginReading())); 1.1252 +#else 1.1253 + gExceptionHandler->set_dump_path(NS_ConvertUTF16toUTF8(aPath).BeginReading()); 1.1254 +#endif 1.1255 + return NS_OK; 1.1256 +} 1.1257 + 1.1258 +static nsresult 1.1259 +WriteDataToFile(nsIFile* aFile, const nsACString& data) 1.1260 +{ 1.1261 + PRFileDesc* fd; 1.1262 + nsresult rv = aFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE, 00600, &fd); 1.1263 + NS_ENSURE_SUCCESS(rv, rv); 1.1264 + 1.1265 + rv = NS_OK; 1.1266 + if (PR_Write(fd, data.Data(), data.Length()) == -1) { 1.1267 + rv = NS_ERROR_FAILURE; 1.1268 + } 1.1269 + PR_Close(fd); 1.1270 + return rv; 1.1271 +} 1.1272 + 1.1273 +static nsresult 1.1274 +GetFileContents(nsIFile* aFile, nsACString& data) 1.1275 +{ 1.1276 + PRFileDesc* fd; 1.1277 + nsresult rv = aFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd); 1.1278 + NS_ENSURE_SUCCESS(rv, rv); 1.1279 + 1.1280 + rv = NS_OK; 1.1281 + int32_t filesize = PR_Available(fd); 1.1282 + if (filesize <= 0) { 1.1283 + rv = NS_ERROR_FILE_NOT_FOUND; 1.1284 + } 1.1285 + else { 1.1286 + data.SetLength(filesize); 1.1287 + if (PR_Read(fd, data.BeginWriting(), filesize) == -1) { 1.1288 + rv = NS_ERROR_FAILURE; 1.1289 + } 1.1290 + } 1.1291 + PR_Close(fd); 1.1292 + return rv; 1.1293 +} 1.1294 + 1.1295 +// Function typedef for initializing a piece of data that we 1.1296 +// don't already have. 1.1297 +typedef nsresult (*InitDataFunc)(nsACString&); 1.1298 + 1.1299 +// Attempt to read aFile's contents into aContents, if aFile 1.1300 +// does not exist, create it and initialize its contents 1.1301 +// by calling aInitFunc for the data. 1.1302 +static nsresult 1.1303 +GetOrInit(nsIFile* aDir, const nsACString& filename, 1.1304 + nsACString& aContents, InitDataFunc aInitFunc) 1.1305 +{ 1.1306 + bool exists; 1.1307 + 1.1308 + nsCOMPtr<nsIFile> dataFile; 1.1309 + nsresult rv = aDir->Clone(getter_AddRefs(dataFile)); 1.1310 + NS_ENSURE_SUCCESS(rv, rv); 1.1311 + 1.1312 + rv = dataFile->AppendNative(filename); 1.1313 + NS_ENSURE_SUCCESS(rv, rv); 1.1314 + 1.1315 + rv = dataFile->Exists(&exists); 1.1316 + NS_ENSURE_SUCCESS(rv, rv); 1.1317 + 1.1318 + if (!exists) { 1.1319 + if (aInitFunc) { 1.1320 + // get the initial value and write it to the file 1.1321 + rv = aInitFunc(aContents); 1.1322 + NS_ENSURE_SUCCESS(rv, rv); 1.1323 + rv = WriteDataToFile(dataFile, aContents); 1.1324 + } 1.1325 + else { 1.1326 + // didn't pass in an init func 1.1327 + rv = NS_ERROR_FAILURE; 1.1328 + } 1.1329 + } 1.1330 + else { 1.1331 + // just get the file's contents 1.1332 + rv = GetFileContents(dataFile, aContents); 1.1333 + } 1.1334 + 1.1335 + return rv; 1.1336 +} 1.1337 + 1.1338 +// Init the "install time" data. We're taking an easy way out here 1.1339 +// and just setting this to "the time when this version was first run". 1.1340 +static nsresult 1.1341 +InitInstallTime(nsACString& aInstallTime) 1.1342 +{ 1.1343 + time_t t = time(nullptr); 1.1344 + char buf[16]; 1.1345 + sprintf(buf, "%ld", t); 1.1346 + aInstallTime = buf; 1.1347 + 1.1348 + return NS_OK; 1.1349 +} 1.1350 + 1.1351 +// Ensure a directory exists and create it if missing. 1.1352 +static nsresult 1.1353 +EnsureDirectoryExists(nsIFile* dir) 1.1354 +{ 1.1355 + nsresult rv = dir->Create(nsIFile::DIRECTORY_TYPE, 0700); 1.1356 + 1.1357 + if (NS_WARN_IF(NS_FAILED(rv) && rv != NS_ERROR_FILE_ALREADY_EXISTS)) { 1.1358 + return rv; 1.1359 + } 1.1360 + 1.1361 + return NS_OK; 1.1362 +} 1.1363 + 1.1364 +// Annotate the crash report with a Unique User ID and time 1.1365 +// since install. Also do some prep work for recording 1.1366 +// time since last crash, which must be calculated at 1.1367 +// crash time. 1.1368 +// If any piece of data doesn't exist, initialize it first. 1.1369 +nsresult SetupExtraData(nsIFile* aAppDataDirectory, 1.1370 + const nsACString& aBuildID) 1.1371 +{ 1.1372 + nsCOMPtr<nsIFile> dataDirectory; 1.1373 + nsresult rv = aAppDataDirectory->Clone(getter_AddRefs(dataDirectory)); 1.1374 + NS_ENSURE_SUCCESS(rv, rv); 1.1375 + 1.1376 + rv = dataDirectory->AppendNative(NS_LITERAL_CSTRING("Crash Reports")); 1.1377 + NS_ENSURE_SUCCESS(rv, rv); 1.1378 + 1.1379 + EnsureDirectoryExists(dataDirectory); 1.1380 + 1.1381 +#if defined(XP_WIN32) 1.1382 + nsAutoString dataDirEnv(NS_LITERAL_STRING("MOZ_CRASHREPORTER_DATA_DIRECTORY=")); 1.1383 + 1.1384 + nsAutoString dataDirectoryPath; 1.1385 + rv = dataDirectory->GetPath(dataDirectoryPath); 1.1386 + NS_ENSURE_SUCCESS(rv, rv); 1.1387 + 1.1388 + dataDirEnv.Append(dataDirectoryPath); 1.1389 + 1.1390 + _wputenv(dataDirEnv.get()); 1.1391 +#else 1.1392 + // Save this path in the environment for the crash reporter application. 1.1393 + nsAutoCString dataDirEnv("MOZ_CRASHREPORTER_DATA_DIRECTORY="); 1.1394 + 1.1395 + nsAutoCString dataDirectoryPath; 1.1396 + rv = dataDirectory->GetNativePath(dataDirectoryPath); 1.1397 + NS_ENSURE_SUCCESS(rv, rv); 1.1398 + 1.1399 + dataDirEnv.Append(dataDirectoryPath); 1.1400 + 1.1401 + char* env = ToNewCString(dataDirEnv); 1.1402 + NS_ENSURE_TRUE(env, NS_ERROR_OUT_OF_MEMORY); 1.1403 + 1.1404 + PR_SetEnv(env); 1.1405 +#endif 1.1406 + 1.1407 + nsAutoCString data; 1.1408 + if(NS_SUCCEEDED(GetOrInit(dataDirectory, 1.1409 + NS_LITERAL_CSTRING("InstallTime") + aBuildID, 1.1410 + data, InitInstallTime))) 1.1411 + AnnotateCrashReport(NS_LITERAL_CSTRING("InstallTime"), data); 1.1412 + 1.1413 + // this is a little different, since we can't init it with anything, 1.1414 + // since it's stored at crash time, and we can't annotate the 1.1415 + // crash report with the stored value, since we really want 1.1416 + // (now - LastCrash), so we just get a value if it exists, 1.1417 + // and store it in a time_t value. 1.1418 + if(NS_SUCCEEDED(GetOrInit(dataDirectory, NS_LITERAL_CSTRING("LastCrash"), 1.1419 + data, nullptr))) { 1.1420 + lastCrashTime = (time_t)atol(data.get()); 1.1421 + } 1.1422 + 1.1423 + // not really the best place to init this, but I have the path I need here 1.1424 + nsCOMPtr<nsIFile> lastCrashFile; 1.1425 + rv = dataDirectory->Clone(getter_AddRefs(lastCrashFile)); 1.1426 + NS_ENSURE_SUCCESS(rv, rv); 1.1427 + 1.1428 + rv = lastCrashFile->AppendNative(NS_LITERAL_CSTRING("LastCrash")); 1.1429 + NS_ENSURE_SUCCESS(rv, rv); 1.1430 + memset(lastCrashTimeFilename, 0, sizeof(lastCrashTimeFilename)); 1.1431 + 1.1432 +#if defined(XP_WIN32) 1.1433 + nsAutoString filename; 1.1434 + rv = lastCrashFile->GetPath(filename); 1.1435 + NS_ENSURE_SUCCESS(rv, rv); 1.1436 + 1.1437 + if (filename.Length() < XP_PATH_MAX) 1.1438 + wcsncpy(lastCrashTimeFilename, filename.get(), filename.Length()); 1.1439 +#else 1.1440 + nsAutoCString filename; 1.1441 + rv = lastCrashFile->GetNativePath(filename); 1.1442 + NS_ENSURE_SUCCESS(rv, rv); 1.1443 + 1.1444 + if (filename.Length() < XP_PATH_MAX) 1.1445 + strncpy(lastCrashTimeFilename, filename.get(), filename.Length()); 1.1446 +#endif 1.1447 + 1.1448 + if (headlessClient) { 1.1449 + nsCOMPtr<nsIFile> markerFile; 1.1450 + rv = dataDirectory->Clone(getter_AddRefs(markerFile)); 1.1451 + NS_ENSURE_SUCCESS(rv, rv); 1.1452 + 1.1453 + rv = markerFile->AppendNative(NS_LITERAL_CSTRING("LastCrashFilename")); 1.1454 + NS_ENSURE_SUCCESS(rv, rv); 1.1455 + memset(crashMarkerFilename, 0, sizeof(crashMarkerFilename)); 1.1456 + 1.1457 +#if defined(XP_WIN32) 1.1458 + nsAutoString markerFilename; 1.1459 + rv = markerFile->GetPath(markerFilename); 1.1460 + NS_ENSURE_SUCCESS(rv, rv); 1.1461 + 1.1462 + if (markerFilename.Length() < XP_PATH_MAX) 1.1463 + wcsncpy(crashMarkerFilename, markerFilename.get(), 1.1464 + markerFilename.Length()); 1.1465 +#else 1.1466 + nsAutoCString markerFilename; 1.1467 + rv = markerFile->GetNativePath(markerFilename); 1.1468 + NS_ENSURE_SUCCESS(rv, rv); 1.1469 + 1.1470 + if (markerFilename.Length() < XP_PATH_MAX) 1.1471 + strncpy(crashMarkerFilename, markerFilename.get(), 1.1472 + markerFilename.Length()); 1.1473 +#endif 1.1474 + } 1.1475 + 1.1476 + return NS_OK; 1.1477 +} 1.1478 + 1.1479 +static void OOPDeinit(); 1.1480 + 1.1481 +nsresult UnsetExceptionHandler() 1.1482 +{ 1.1483 + if (isSafeToDump) { 1.1484 + MutexAutoLock lock(*dumpSafetyLock); 1.1485 + isSafeToDump = false; 1.1486 + } 1.1487 + 1.1488 +#ifdef XP_WIN 1.1489 + // allow SetUnhandledExceptionFilter 1.1490 + gBlockUnhandledExceptionFilter = false; 1.1491 +#endif 1.1492 + 1.1493 + delete gExceptionHandler; 1.1494 + 1.1495 + // do this here in the unlikely case that we succeeded in allocating 1.1496 + // our strings but failed to allocate gExceptionHandler. 1.1497 + delete crashReporterAPIData_Hash; 1.1498 + crashReporterAPIData_Hash = nullptr; 1.1499 + 1.1500 + delete crashReporterAPILock; 1.1501 + crashReporterAPILock = nullptr; 1.1502 + 1.1503 + delete notesFieldLock; 1.1504 + notesFieldLock = nullptr; 1.1505 + 1.1506 + delete crashReporterAPIData; 1.1507 + crashReporterAPIData = nullptr; 1.1508 + 1.1509 + delete notesField; 1.1510 + notesField = nullptr; 1.1511 + 1.1512 + delete lastRunCrashID; 1.1513 + lastRunCrashID = nullptr; 1.1514 + 1.1515 + if (pendingDirectory) { 1.1516 + NS_Free(pendingDirectory); 1.1517 + pendingDirectory = nullptr; 1.1518 + } 1.1519 + 1.1520 + if (crashReporterPath) { 1.1521 + NS_Free(crashReporterPath); 1.1522 + crashReporterPath = nullptr; 1.1523 + } 1.1524 + 1.1525 + if (eventsDirectory) { 1.1526 + NS_Free(eventsDirectory); 1.1527 + eventsDirectory = nullptr; 1.1528 + } 1.1529 + 1.1530 +#ifdef XP_MACOSX 1.1531 + posix_spawnattr_destroy(&spawnattr); 1.1532 +#endif 1.1533 + 1.1534 + if (!gExceptionHandler) 1.1535 + return NS_ERROR_NOT_INITIALIZED; 1.1536 + 1.1537 + gExceptionHandler = nullptr; 1.1538 + 1.1539 + OOPDeinit(); 1.1540 + 1.1541 + delete dumpSafetyLock; 1.1542 + dumpSafetyLock = nullptr; 1.1543 + 1.1544 + return NS_OK; 1.1545 +} 1.1546 + 1.1547 +static void ReplaceChar(nsCString& str, const nsACString& character, 1.1548 + const nsACString& replacement) 1.1549 +{ 1.1550 + nsCString::const_iterator start, end; 1.1551 + 1.1552 + str.BeginReading(start); 1.1553 + str.EndReading(end); 1.1554 + 1.1555 + while (FindInReadable(character, start, end)) { 1.1556 + int32_t pos = end.size_backward(); 1.1557 + str.Replace(pos - 1, 1, replacement); 1.1558 + 1.1559 + str.BeginReading(start); 1.1560 + start.advance(pos + replacement.Length() - 1); 1.1561 + str.EndReading(end); 1.1562 + } 1.1563 +} 1.1564 + 1.1565 +static bool DoFindInReadable(const nsACString& str, const nsACString& value) 1.1566 +{ 1.1567 + nsACString::const_iterator start, end; 1.1568 + str.BeginReading(start); 1.1569 + str.EndReading(end); 1.1570 + 1.1571 + return FindInReadable(value, start, end); 1.1572 +} 1.1573 + 1.1574 +static PLDHashOperator EnumerateEntries(const nsACString& key, 1.1575 + nsCString entry, 1.1576 + void* userData) 1.1577 +{ 1.1578 + crashReporterAPIData->Append(key + NS_LITERAL_CSTRING("=") + entry + 1.1579 + NS_LITERAL_CSTRING("\n")); 1.1580 + return PL_DHASH_NEXT; 1.1581 +} 1.1582 + 1.1583 +// This function is miscompiled with MSVC 2005/2008 when PGO is on. 1.1584 +#ifdef _MSC_VER 1.1585 +#pragma optimize("", off) 1.1586 +#endif 1.1587 +static nsresult 1.1588 +EscapeAnnotation(const nsACString& key, const nsACString& data, nsCString& escapedData) 1.1589 +{ 1.1590 + if (DoFindInReadable(key, NS_LITERAL_CSTRING("=")) || 1.1591 + DoFindInReadable(key, NS_LITERAL_CSTRING("\n"))) 1.1592 + return NS_ERROR_INVALID_ARG; 1.1593 + 1.1594 + if (DoFindInReadable(data, NS_LITERAL_CSTRING("\0"))) 1.1595 + return NS_ERROR_INVALID_ARG; 1.1596 + 1.1597 + escapedData = data; 1.1598 + 1.1599 + // escape backslashes 1.1600 + ReplaceChar(escapedData, NS_LITERAL_CSTRING("\\"), 1.1601 + NS_LITERAL_CSTRING("\\\\")); 1.1602 + // escape newlines 1.1603 + ReplaceChar(escapedData, NS_LITERAL_CSTRING("\n"), 1.1604 + NS_LITERAL_CSTRING("\\n")); 1.1605 + return NS_OK; 1.1606 +} 1.1607 +#ifdef _MSC_VER 1.1608 +#pragma optimize("", on) 1.1609 +#endif 1.1610 + 1.1611 +class DelayedNote 1.1612 +{ 1.1613 + public: 1.1614 + DelayedNote(const nsACString& aKey, const nsACString& aData) 1.1615 + : mKey(aKey), mData(aData), mType(Annotation) {} 1.1616 + 1.1617 + DelayedNote(const nsACString& aData) 1.1618 + : mData(aData), mType(AppNote) {} 1.1619 + 1.1620 + void Run() 1.1621 + { 1.1622 + if (mType == Annotation) { 1.1623 + AnnotateCrashReport(mKey, mData); 1.1624 + } else { 1.1625 + AppendAppNotesToCrashReport(mData); 1.1626 + } 1.1627 + } 1.1628 + 1.1629 + private: 1.1630 + nsCString mKey; 1.1631 + nsCString mData; 1.1632 + enum AnnotationType { Annotation, AppNote } mType; 1.1633 +}; 1.1634 + 1.1635 +static void 1.1636 +EnqueueDelayedNote(DelayedNote* aNote) 1.1637 +{ 1.1638 + if (!gDelayedAnnotations) { 1.1639 + gDelayedAnnotations = new nsTArray<nsAutoPtr<DelayedNote> >(); 1.1640 + } 1.1641 + gDelayedAnnotations->AppendElement(aNote); 1.1642 +} 1.1643 + 1.1644 +nsresult AnnotateCrashReport(const nsACString& key, const nsACString& data) 1.1645 +{ 1.1646 + if (!GetEnabled()) 1.1647 + return NS_ERROR_NOT_INITIALIZED; 1.1648 + 1.1649 + nsCString escapedData; 1.1650 + nsresult rv = EscapeAnnotation(key, data, escapedData); 1.1651 + if (NS_FAILED(rv)) 1.1652 + return rv; 1.1653 + 1.1654 + if (XRE_GetProcessType() != GeckoProcessType_Default) { 1.1655 + if (!NS_IsMainThread()) { 1.1656 + NS_ERROR("Cannot call AnnotateCrashReport in child processes from non-main thread."); 1.1657 + return NS_ERROR_FAILURE; 1.1658 + } 1.1659 + PCrashReporterChild* reporter = CrashReporterChild::GetCrashReporter(); 1.1660 + if (!reporter) { 1.1661 + EnqueueDelayedNote(new DelayedNote(key, data)); 1.1662 + return NS_OK; 1.1663 + } 1.1664 + if (!reporter->SendAnnotateCrashReport(nsCString(key), escapedData)) 1.1665 + return NS_ERROR_FAILURE; 1.1666 + return NS_OK; 1.1667 + } 1.1668 + 1.1669 + MutexAutoLock lock(*crashReporterAPILock); 1.1670 + 1.1671 + crashReporterAPIData_Hash->Put(key, escapedData); 1.1672 + 1.1673 + // now rebuild the file contents 1.1674 + crashReporterAPIData->Truncate(0); 1.1675 + crashReporterAPIData_Hash->EnumerateRead(EnumerateEntries, 1.1676 + crashReporterAPIData); 1.1677 + 1.1678 + return NS_OK; 1.1679 +} 1.1680 + 1.1681 +nsresult SetGarbageCollecting(bool collecting) 1.1682 +{ 1.1683 + if (!GetEnabled()) 1.1684 + return NS_ERROR_NOT_INITIALIZED; 1.1685 + 1.1686 + isGarbageCollecting = collecting; 1.1687 + 1.1688 + return NS_OK; 1.1689 +} 1.1690 + 1.1691 +void SetEventloopNestingLevel(uint32_t level) 1.1692 +{ 1.1693 + eventloopNestingLevel = level; 1.1694 +} 1.1695 + 1.1696 +nsresult AppendAppNotesToCrashReport(const nsACString& data) 1.1697 +{ 1.1698 + if (!GetEnabled()) 1.1699 + return NS_ERROR_NOT_INITIALIZED; 1.1700 + 1.1701 + if (DoFindInReadable(data, NS_LITERAL_CSTRING("\0"))) 1.1702 + return NS_ERROR_INVALID_ARG; 1.1703 + 1.1704 + if (XRE_GetProcessType() != GeckoProcessType_Default) { 1.1705 + if (!NS_IsMainThread()) { 1.1706 + NS_ERROR("Cannot call AnnotateCrashReport in child processes from non-main thread."); 1.1707 + return NS_ERROR_FAILURE; 1.1708 + } 1.1709 + PCrashReporterChild* reporter = CrashReporterChild::GetCrashReporter(); 1.1710 + if (!reporter) { 1.1711 + EnqueueDelayedNote(new DelayedNote(data)); 1.1712 + return NS_OK; 1.1713 + } 1.1714 + 1.1715 + // Since we don't go through AnnotateCrashReport in the parent process, 1.1716 + // we must ensure that the data is escaped and valid before the parent 1.1717 + // sees it. 1.1718 + nsCString escapedData; 1.1719 + nsresult rv = EscapeAnnotation(NS_LITERAL_CSTRING("Notes"), data, escapedData); 1.1720 + if (NS_FAILED(rv)) 1.1721 + return rv; 1.1722 + 1.1723 + if (!reporter->SendAppendAppNotes(escapedData)) 1.1724 + return NS_ERROR_FAILURE; 1.1725 + return NS_OK; 1.1726 + } 1.1727 + 1.1728 + MutexAutoLock lock(*notesFieldLock); 1.1729 + 1.1730 + notesField->Append(data); 1.1731 + return AnnotateCrashReport(NS_LITERAL_CSTRING("Notes"), *notesField); 1.1732 +} 1.1733 + 1.1734 +// Returns true if found, false if not found. 1.1735 +bool GetAnnotation(const nsACString& key, nsACString& data) 1.1736 +{ 1.1737 + if (!gExceptionHandler) 1.1738 + return false; 1.1739 + 1.1740 + nsAutoCString entry; 1.1741 + if (!crashReporterAPIData_Hash->Get(key, &entry)) 1.1742 + return false; 1.1743 + 1.1744 + data = entry; 1.1745 + return true; 1.1746 +} 1.1747 + 1.1748 +nsresult RegisterAppMemory(void* ptr, size_t length) 1.1749 +{ 1.1750 + if (!GetEnabled()) 1.1751 + return NS_ERROR_NOT_INITIALIZED; 1.1752 + 1.1753 +#if defined(XP_LINUX) || defined(XP_WIN32) 1.1754 + gExceptionHandler->RegisterAppMemory(ptr, length); 1.1755 + return NS_OK; 1.1756 +#else 1.1757 + return NS_ERROR_NOT_IMPLEMENTED; 1.1758 +#endif 1.1759 +} 1.1760 + 1.1761 +nsresult UnregisterAppMemory(void* ptr) 1.1762 +{ 1.1763 + if (!GetEnabled()) 1.1764 + return NS_ERROR_NOT_INITIALIZED; 1.1765 + 1.1766 +#if defined(XP_LINUX) || defined(XP_WIN32) 1.1767 + gExceptionHandler->UnregisterAppMemory(ptr); 1.1768 + return NS_OK; 1.1769 +#else 1.1770 + return NS_ERROR_NOT_IMPLEMENTED; 1.1771 +#endif 1.1772 +} 1.1773 + 1.1774 +bool GetServerURL(nsACString& aServerURL) 1.1775 +{ 1.1776 + if (!gExceptionHandler) 1.1777 + return false; 1.1778 + 1.1779 + return GetAnnotation(NS_LITERAL_CSTRING("ServerURL"), aServerURL); 1.1780 +} 1.1781 + 1.1782 +nsresult SetServerURL(const nsACString& aServerURL) 1.1783 +{ 1.1784 + // store server URL with the API data 1.1785 + // the client knows to handle this specially 1.1786 + return AnnotateCrashReport(NS_LITERAL_CSTRING("ServerURL"), 1.1787 + aServerURL); 1.1788 +} 1.1789 + 1.1790 +nsresult 1.1791 +SetRestartArgs(int argc, char** argv) 1.1792 +{ 1.1793 + if (!gExceptionHandler) 1.1794 + return NS_OK; 1.1795 + 1.1796 + int i; 1.1797 + nsAutoCString envVar; 1.1798 + char *env; 1.1799 + char *argv0 = getenv("MOZ_APP_LAUNCHER"); 1.1800 + for (i = 0; i < argc; i++) { 1.1801 + envVar = "MOZ_CRASHREPORTER_RESTART_ARG_"; 1.1802 + envVar.AppendInt(i); 1.1803 + envVar += "="; 1.1804 + if (argv0 && i == 0) { 1.1805 + // Is there a request to suppress default binary launcher? 1.1806 + envVar += argv0; 1.1807 + } else { 1.1808 + envVar += argv[i]; 1.1809 + } 1.1810 + 1.1811 + // PR_SetEnv() wants the string to be available for the lifetime 1.1812 + // of the app, so dup it here 1.1813 + env = ToNewCString(envVar); 1.1814 + if (!env) 1.1815 + return NS_ERROR_OUT_OF_MEMORY; 1.1816 + 1.1817 + PR_SetEnv(env); 1.1818 + } 1.1819 + 1.1820 + // make sure the arg list is terminated 1.1821 + envVar = "MOZ_CRASHREPORTER_RESTART_ARG_"; 1.1822 + envVar.AppendInt(i); 1.1823 + envVar += "="; 1.1824 + 1.1825 + // PR_SetEnv() wants the string to be available for the lifetime 1.1826 + // of the app, so dup it here 1.1827 + env = ToNewCString(envVar); 1.1828 + if (!env) 1.1829 + return NS_ERROR_OUT_OF_MEMORY; 1.1830 + 1.1831 + PR_SetEnv(env); 1.1832 + 1.1833 + // make sure we save the info in XUL_APP_FILE for the reporter 1.1834 + const char *appfile = PR_GetEnv("XUL_APP_FILE"); 1.1835 + if (appfile && *appfile) { 1.1836 + envVar = "MOZ_CRASHREPORTER_RESTART_XUL_APP_FILE="; 1.1837 + envVar += appfile; 1.1838 + env = ToNewCString(envVar); 1.1839 + PR_SetEnv(env); 1.1840 + } 1.1841 + 1.1842 + return NS_OK; 1.1843 +} 1.1844 + 1.1845 +#ifdef XP_WIN32 1.1846 +nsresult WriteMinidumpForException(EXCEPTION_POINTERS* aExceptionInfo) 1.1847 +{ 1.1848 + if (!gExceptionHandler) 1.1849 + return NS_ERROR_NOT_INITIALIZED; 1.1850 + 1.1851 + return gExceptionHandler->WriteMinidumpForException(aExceptionInfo) ? NS_OK : NS_ERROR_FAILURE; 1.1852 +} 1.1853 +#endif 1.1854 + 1.1855 +#ifdef XP_LINUX 1.1856 +bool WriteMinidumpForSigInfo(int signo, siginfo_t* info, void* uc) 1.1857 +{ 1.1858 + return gExceptionHandler->HandleSignal(signo, info, uc); 1.1859 +} 1.1860 +#endif 1.1861 + 1.1862 +#ifdef XP_MACOSX 1.1863 +nsresult AppendObjCExceptionInfoToAppNotes(void *inException) 1.1864 +{ 1.1865 + nsAutoCString excString; 1.1866 + GetObjCExceptionInfo(inException, excString); 1.1867 + AppendAppNotesToCrashReport(excString); 1.1868 + return NS_OK; 1.1869 +} 1.1870 +#endif 1.1871 + 1.1872 +/* 1.1873 + * Combined code to get/set the crash reporter submission pref on 1.1874 + * different platforms. 1.1875 + */ 1.1876 +static nsresult PrefSubmitReports(bool* aSubmitReports, bool writePref) 1.1877 +{ 1.1878 + nsresult rv; 1.1879 +#if defined(XP_WIN32) 1.1880 + /* 1.1881 + * NOTE! This needs to stay in sync with the preference checking code 1.1882 + * in toolkit/crashreporter/client/crashreporter_win.cpp 1.1883 + */ 1.1884 + nsCOMPtr<nsIXULAppInfo> appinfo = 1.1885 + do_GetService("@mozilla.org/xre/app-info;1", &rv); 1.1886 + NS_ENSURE_SUCCESS(rv, rv); 1.1887 + 1.1888 + nsAutoCString appVendor, appName; 1.1889 + rv = appinfo->GetVendor(appVendor); 1.1890 + NS_ENSURE_SUCCESS(rv, rv); 1.1891 + rv = appinfo->GetName(appName); 1.1892 + NS_ENSURE_SUCCESS(rv, rv); 1.1893 + 1.1894 + nsCOMPtr<nsIWindowsRegKey> regKey 1.1895 + (do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv)); 1.1896 + NS_ENSURE_SUCCESS(rv, rv); 1.1897 + 1.1898 + nsAutoCString regPath; 1.1899 + 1.1900 + regPath.AppendLiteral("Software\\"); 1.1901 + 1.1902 + // We need to ensure the registry keys are created so we can properly 1.1903 + // write values to it 1.1904 + 1.1905 + // Create appVendor key 1.1906 + if(!appVendor.IsEmpty()) { 1.1907 + regPath.Append(appVendor); 1.1908 + regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, 1.1909 + NS_ConvertUTF8toUTF16(regPath), 1.1910 + nsIWindowsRegKey::ACCESS_SET_VALUE); 1.1911 + regPath.AppendLiteral("\\"); 1.1912 + } 1.1913 + 1.1914 + // Create appName key 1.1915 + regPath.Append(appName); 1.1916 + regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, 1.1917 + NS_ConvertUTF8toUTF16(regPath), 1.1918 + nsIWindowsRegKey::ACCESS_SET_VALUE); 1.1919 + regPath.AppendLiteral("\\"); 1.1920 + 1.1921 + // Create Crash Reporter key 1.1922 + regPath.AppendLiteral("Crash Reporter"); 1.1923 + regKey->Create(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, 1.1924 + NS_ConvertUTF8toUTF16(regPath), 1.1925 + nsIWindowsRegKey::ACCESS_SET_VALUE); 1.1926 + 1.1927 + // If we're saving the pref value, just write it to ROOT_KEY_CURRENT_USER 1.1928 + // and we're done. 1.1929 + if (writePref) { 1.1930 + rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, 1.1931 + NS_ConvertUTF8toUTF16(regPath), 1.1932 + nsIWindowsRegKey::ACCESS_SET_VALUE); 1.1933 + NS_ENSURE_SUCCESS(rv, rv); 1.1934 + 1.1935 + uint32_t value = *aSubmitReports ? 1 : 0; 1.1936 + rv = regKey->WriteIntValue(NS_LITERAL_STRING("SubmitCrashReport"), value); 1.1937 + regKey->Close(); 1.1938 + return rv; 1.1939 + } 1.1940 + 1.1941 + // We're reading the pref value, so we need to first look under 1.1942 + // ROOT_KEY_LOCAL_MACHINE to see if it's set there, and then fall back to 1.1943 + // ROOT_KEY_CURRENT_USER. If it's not set in either place, the pref defaults 1.1944 + // to "true". 1.1945 + uint32_t value; 1.1946 + rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE, 1.1947 + NS_ConvertUTF8toUTF16(regPath), 1.1948 + nsIWindowsRegKey::ACCESS_QUERY_VALUE); 1.1949 + if (NS_SUCCEEDED(rv)) { 1.1950 + rv = regKey->ReadIntValue(NS_LITERAL_STRING("SubmitCrashReport"), &value); 1.1951 + regKey->Close(); 1.1952 + if (NS_SUCCEEDED(rv)) { 1.1953 + *aSubmitReports = !!value; 1.1954 + return NS_OK; 1.1955 + } 1.1956 + } 1.1957 + 1.1958 + rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER, 1.1959 + NS_ConvertUTF8toUTF16(regPath), 1.1960 + nsIWindowsRegKey::ACCESS_QUERY_VALUE); 1.1961 + if (NS_FAILED(rv)) { 1.1962 + *aSubmitReports = true; 1.1963 + return NS_OK; 1.1964 + } 1.1965 + 1.1966 + rv = regKey->ReadIntValue(NS_LITERAL_STRING("SubmitCrashReport"), &value); 1.1967 + // default to true on failure 1.1968 + if (NS_FAILED(rv)) { 1.1969 + value = 1; 1.1970 + rv = NS_OK; 1.1971 + } 1.1972 + regKey->Close(); 1.1973 + 1.1974 + *aSubmitReports = !!value; 1.1975 + return NS_OK; 1.1976 +#elif defined(XP_MACOSX) 1.1977 + rv = NS_OK; 1.1978 + if (writePref) { 1.1979 + CFPropertyListRef cfValue = (CFPropertyListRef)(*aSubmitReports ? kCFBooleanTrue : kCFBooleanFalse); 1.1980 + ::CFPreferencesSetAppValue(CFSTR("submitReport"), 1.1981 + cfValue, 1.1982 + reporterClientAppID); 1.1983 + if (!::CFPreferencesAppSynchronize(reporterClientAppID)) 1.1984 + rv = NS_ERROR_FAILURE; 1.1985 + } 1.1986 + else { 1.1987 + *aSubmitReports = true; 1.1988 + Boolean keyExistsAndHasValidFormat = false; 1.1989 + Boolean prefValue = ::CFPreferencesGetAppBooleanValue(CFSTR("submitReport"), 1.1990 + reporterClientAppID, 1.1991 + &keyExistsAndHasValidFormat); 1.1992 + if (keyExistsAndHasValidFormat) 1.1993 + *aSubmitReports = !!prefValue; 1.1994 + } 1.1995 + return rv; 1.1996 +#elif defined(XP_UNIX) 1.1997 + /* 1.1998 + * NOTE! This needs to stay in sync with the preference checking code 1.1999 + * in toolkit/crashreporter/client/crashreporter_linux.cpp 1.2000 + */ 1.2001 + nsCOMPtr<nsIFile> reporterINI; 1.2002 + rv = NS_GetSpecialDirectory("UAppData", getter_AddRefs(reporterINI)); 1.2003 + NS_ENSURE_SUCCESS(rv, rv); 1.2004 + reporterINI->AppendNative(NS_LITERAL_CSTRING("Crash Reports")); 1.2005 + reporterINI->AppendNative(NS_LITERAL_CSTRING("crashreporter.ini")); 1.2006 + 1.2007 + bool exists; 1.2008 + rv = reporterINI->Exists(&exists); 1.2009 + NS_ENSURE_SUCCESS(rv, rv); 1.2010 + if (!exists) { 1.2011 + if (!writePref) { 1.2012 + // If reading the pref, default to true if .ini doesn't exist. 1.2013 + *aSubmitReports = true; 1.2014 + return NS_OK; 1.2015 + } 1.2016 + // Create the file so the INI processor can write to it. 1.2017 + rv = reporterINI->Create(nsIFile::NORMAL_FILE_TYPE, 0600); 1.2018 + NS_ENSURE_SUCCESS(rv, rv); 1.2019 + } 1.2020 + 1.2021 + nsCOMPtr<nsIINIParserFactory> iniFactory = 1.2022 + do_GetService("@mozilla.org/xpcom/ini-processor-factory;1", &rv); 1.2023 + NS_ENSURE_SUCCESS(rv, rv); 1.2024 + 1.2025 + nsCOMPtr<nsIINIParser> iniParser; 1.2026 + rv = iniFactory->CreateINIParser(reporterINI, 1.2027 + getter_AddRefs(iniParser)); 1.2028 + NS_ENSURE_SUCCESS(rv, rv); 1.2029 + 1.2030 + // If we're writing the pref, just set and we're done. 1.2031 + if (writePref) { 1.2032 + nsCOMPtr<nsIINIParserWriter> iniWriter = do_QueryInterface(iniParser); 1.2033 + NS_ENSURE_TRUE(iniWriter, NS_ERROR_FAILURE); 1.2034 + 1.2035 + rv = iniWriter->SetString(NS_LITERAL_CSTRING("Crash Reporter"), 1.2036 + NS_LITERAL_CSTRING("SubmitReport"), 1.2037 + *aSubmitReports ? NS_LITERAL_CSTRING("1") : 1.2038 + NS_LITERAL_CSTRING("0")); 1.2039 + NS_ENSURE_SUCCESS(rv, rv); 1.2040 + rv = iniWriter->WriteFile(nullptr, 0); 1.2041 + return rv; 1.2042 + } 1.2043 + 1.2044 + nsAutoCString submitReportValue; 1.2045 + rv = iniParser->GetString(NS_LITERAL_CSTRING("Crash Reporter"), 1.2046 + NS_LITERAL_CSTRING("SubmitReport"), 1.2047 + submitReportValue); 1.2048 + 1.2049 + // Default to "true" if the pref can't be found. 1.2050 + if (NS_FAILED(rv)) 1.2051 + *aSubmitReports = true; 1.2052 + else if (submitReportValue.EqualsASCII("0")) 1.2053 + *aSubmitReports = false; 1.2054 + else 1.2055 + *aSubmitReports = true; 1.2056 + 1.2057 + return NS_OK; 1.2058 +#else 1.2059 + return NS_ERROR_NOT_IMPLEMENTED; 1.2060 +#endif 1.2061 +} 1.2062 + 1.2063 +nsresult GetSubmitReports(bool* aSubmitReports) 1.2064 +{ 1.2065 + return PrefSubmitReports(aSubmitReports, false); 1.2066 +} 1.2067 + 1.2068 +nsresult SetSubmitReports(bool aSubmitReports) 1.2069 +{ 1.2070 + nsresult rv; 1.2071 + 1.2072 + nsCOMPtr<nsIObserverService> obsServ = 1.2073 + mozilla::services::GetObserverService(); 1.2074 + if (!obsServ) { 1.2075 + return NS_ERROR_FAILURE; 1.2076 + } 1.2077 + 1.2078 + rv = PrefSubmitReports(&aSubmitReports, true); 1.2079 + if (NS_FAILED(rv)) { 1.2080 + return rv; 1.2081 + } 1.2082 + 1.2083 + obsServ->NotifyObservers(nullptr, "submit-reports-pref-changed", nullptr); 1.2084 + return NS_OK; 1.2085 +} 1.2086 + 1.2087 +void 1.2088 +UpdateCrashEventsDir() 1.2089 +{ 1.2090 + nsCOMPtr<nsIFile> eventsDir; 1.2091 + 1.2092 + // We prefer the following locations in order: 1.2093 + // 1.2094 + // 1. If environment variable is present, use it. We don't expect 1.2095 + // the environment variable except for tests and other atypical setups. 1.2096 + // 2. Inside the profile directory. 1.2097 + // 3. Inside the user application data directory (no profile available). 1.2098 + // 4. A temporary directory (setup likely is invalid / application is buggy). 1.2099 + const char *env = PR_GetEnv("CRASHES_EVENTS_DIR"); 1.2100 + if (env) { 1.2101 + eventsDir = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID); 1.2102 + if (!eventsDir) { 1.2103 + return; 1.2104 + } 1.2105 + eventsDir->InitWithNativePath(nsDependentCString(env)); 1.2106 + EnsureDirectoryExists(eventsDir); 1.2107 + } else { 1.2108 + nsresult rv = NS_GetSpecialDirectory("ProfD", getter_AddRefs(eventsDir)); 1.2109 + if (NS_SUCCEEDED(rv)) { 1.2110 + eventsDir->Append(NS_LITERAL_STRING("crashes")); 1.2111 + EnsureDirectoryExists(eventsDir); 1.2112 + eventsDir->Append(NS_LITERAL_STRING("events")); 1.2113 + EnsureDirectoryExists(eventsDir); 1.2114 + } else { 1.2115 + rv = NS_GetSpecialDirectory("UAppData", getter_AddRefs(eventsDir)); 1.2116 + if (NS_SUCCEEDED(rv)) { 1.2117 + eventsDir->Append(NS_LITERAL_STRING("Crash Reports")); 1.2118 + EnsureDirectoryExists(eventsDir); 1.2119 + eventsDir->Append(NS_LITERAL_STRING("events")); 1.2120 + EnsureDirectoryExists(eventsDir); 1.2121 + } else { 1.2122 + NS_WARNING("Couldn't get the user appdata directory. Crash events may not be produced."); 1.2123 + return; 1.2124 + } 1.2125 + } 1.2126 + } 1.2127 + 1.2128 +#ifdef XP_WIN 1.2129 + nsString path; 1.2130 + eventsDir->GetPath(path); 1.2131 + eventsDirectory = reinterpret_cast<wchar_t*>(ToNewUnicode(path)); 1.2132 +#else 1.2133 + nsCString path; 1.2134 + eventsDir->GetNativePath(path); 1.2135 + eventsDirectory = ToNewCString(path); 1.2136 +#endif 1.2137 +} 1.2138 + 1.2139 +bool GetCrashEventsDir(nsAString& aPath) 1.2140 +{ 1.2141 + if (!eventsDirectory) { 1.2142 + return false; 1.2143 + } 1.2144 + 1.2145 + aPath = CONVERT_XP_CHAR_TO_UTF16(eventsDirectory); 1.2146 + return true; 1.2147 +} 1.2148 + 1.2149 +static void 1.2150 +FindPendingDir() 1.2151 +{ 1.2152 + if (pendingDirectory) 1.2153 + return; 1.2154 + 1.2155 + nsCOMPtr<nsIFile> pendingDir; 1.2156 + nsresult rv = NS_GetSpecialDirectory("UAppData", getter_AddRefs(pendingDir)); 1.2157 + if (NS_FAILED(rv)) { 1.2158 + NS_WARNING("Couldn't get the user appdata directory, crash dumps will go in an unusual location"); 1.2159 + } 1.2160 + else { 1.2161 + pendingDir->Append(NS_LITERAL_STRING("Crash Reports")); 1.2162 + pendingDir->Append(NS_LITERAL_STRING("pending")); 1.2163 + 1.2164 +#ifdef XP_WIN 1.2165 + nsString path; 1.2166 + pendingDir->GetPath(path); 1.2167 + pendingDirectory = reinterpret_cast<wchar_t*>(ToNewUnicode(path)); 1.2168 +#else 1.2169 + nsCString path; 1.2170 + pendingDir->GetNativePath(path); 1.2171 + pendingDirectory = ToNewCString(path); 1.2172 +#endif 1.2173 + } 1.2174 +} 1.2175 + 1.2176 +// The "pending" dir is Crash Reports/pending, from which minidumps 1.2177 +// can be submitted. Because this method may be called off the main thread, 1.2178 +// we store the pending directory as a path. 1.2179 +static bool 1.2180 +GetPendingDir(nsIFile** dir) 1.2181 +{ 1.2182 + MOZ_ASSERT(OOPInitialized()); 1.2183 + if (!pendingDirectory) { 1.2184 + return false; 1.2185 + } 1.2186 + 1.2187 + nsCOMPtr<nsIFile> pending = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID); 1.2188 + if (!pending) { 1.2189 + NS_WARNING("Can't set up pending directory during shutdown."); 1.2190 + return false; 1.2191 + } 1.2192 +#ifdef XP_WIN 1.2193 + pending->InitWithPath(nsDependentString(pendingDirectory)); 1.2194 +#else 1.2195 + pending->InitWithNativePath(nsDependentCString(pendingDirectory)); 1.2196 +#endif 1.2197 + pending.swap(*dir); 1.2198 + return true; 1.2199 +} 1.2200 + 1.2201 +// The "limbo" dir is where minidumps go to wait for something else to 1.2202 +// use them. If we're |ShouldReport()|, then the "something else" is 1.2203 +// a minidump submitter, and they're coming from the 1.2204 +// Crash Reports/pending/ dir. Otherwise, we don't know what the 1.2205 +// "somthing else" is, but the minidumps stay in [profile]/minidumps/ 1.2206 +// limbo. 1.2207 +static bool 1.2208 +GetMinidumpLimboDir(nsIFile** dir) 1.2209 +{ 1.2210 + if (ShouldReport()) { 1.2211 + return GetPendingDir(dir); 1.2212 + } 1.2213 + else { 1.2214 +#ifndef XP_LINUX 1.2215 + CreateFileFromPath(gExceptionHandler->dump_path(), dir); 1.2216 +#else 1.2217 + CreateFileFromPath(gExceptionHandler->minidump_descriptor().directory(), 1.2218 + dir); 1.2219 +#endif 1.2220 + return nullptr != *dir; 1.2221 + } 1.2222 +} 1.2223 + 1.2224 +bool 1.2225 +GetMinidumpForID(const nsAString& id, nsIFile** minidump) 1.2226 +{ 1.2227 + if (!GetMinidumpLimboDir(minidump)) 1.2228 + return false; 1.2229 + (*minidump)->Append(id + NS_LITERAL_STRING(".dmp")); 1.2230 + return true; 1.2231 +} 1.2232 + 1.2233 +bool 1.2234 +GetIDFromMinidump(nsIFile* minidump, nsAString& id) 1.2235 +{ 1.2236 + if (NS_SUCCEEDED(minidump->GetLeafName(id))) { 1.2237 + id.Replace(id.Length() - 4, 4, NS_LITERAL_STRING("")); 1.2238 + return true; 1.2239 + } 1.2240 + return false; 1.2241 +} 1.2242 + 1.2243 +bool 1.2244 +GetExtraFileForID(const nsAString& id, nsIFile** extraFile) 1.2245 +{ 1.2246 + if (!GetMinidumpLimboDir(extraFile)) 1.2247 + return false; 1.2248 + (*extraFile)->Append(id + NS_LITERAL_STRING(".extra")); 1.2249 + return true; 1.2250 +} 1.2251 + 1.2252 +bool 1.2253 +GetExtraFileForMinidump(nsIFile* minidump, nsIFile** extraFile) 1.2254 +{ 1.2255 + nsAutoString leafName; 1.2256 + nsresult rv = minidump->GetLeafName(leafName); 1.2257 + if (NS_FAILED(rv)) 1.2258 + return false; 1.2259 + 1.2260 + nsCOMPtr<nsIFile> extraF; 1.2261 + rv = minidump->Clone(getter_AddRefs(extraF)); 1.2262 + if (NS_FAILED(rv)) 1.2263 + return false; 1.2264 + 1.2265 + leafName.Replace(leafName.Length() - 3, 3, 1.2266 + NS_LITERAL_STRING("extra")); 1.2267 + rv = extraF->SetLeafName(leafName); 1.2268 + if (NS_FAILED(rv)) 1.2269 + return false; 1.2270 + 1.2271 + *extraFile = nullptr; 1.2272 + extraF.swap(*extraFile); 1.2273 + return true; 1.2274 +} 1.2275 + 1.2276 +bool 1.2277 +AppendExtraData(const nsAString& id, const AnnotationTable& data) 1.2278 +{ 1.2279 + nsCOMPtr<nsIFile> extraFile; 1.2280 + if (!GetExtraFileForID(id, getter_AddRefs(extraFile))) 1.2281 + return false; 1.2282 + return AppendExtraData(extraFile, data); 1.2283 +} 1.2284 + 1.2285 +//----------------------------------------------------------------------------- 1.2286 +// Helpers for AppendExtraData() 1.2287 +// 1.2288 +struct Blacklist { 1.2289 + Blacklist() : mItems(nullptr), mLen(0) { } 1.2290 + Blacklist(const char** items, int len) : mItems(items), mLen(len) { } 1.2291 + 1.2292 + bool Contains(const nsACString& key) const { 1.2293 + for (int i = 0; i < mLen; ++i) 1.2294 + if (key.EqualsASCII(mItems[i])) 1.2295 + return true; 1.2296 + return false; 1.2297 + } 1.2298 + 1.2299 + const char** mItems; 1.2300 + const int mLen; 1.2301 +}; 1.2302 + 1.2303 +struct EnumerateAnnotationsContext { 1.2304 + const Blacklist& blacklist; 1.2305 + PRFileDesc* fd; 1.2306 +}; 1.2307 + 1.2308 +static void 1.2309 +WriteAnnotation(PRFileDesc* fd, const nsACString& key, const nsACString& value) 1.2310 +{ 1.2311 + PR_Write(fd, key.BeginReading(), key.Length()); 1.2312 + PR_Write(fd, "=", 1); 1.2313 + PR_Write(fd, value.BeginReading(), value.Length()); 1.2314 + PR_Write(fd, "\n", 1); 1.2315 +} 1.2316 + 1.2317 +static PLDHashOperator 1.2318 +EnumerateAnnotations(const nsACString& key, 1.2319 + nsCString entry, 1.2320 + void* userData) 1.2321 +{ 1.2322 + EnumerateAnnotationsContext* ctx = 1.2323 + static_cast<EnumerateAnnotationsContext*>(userData); 1.2324 + const Blacklist& blacklist = ctx->blacklist; 1.2325 + 1.2326 + // skip entries in the blacklist 1.2327 + if (blacklist.Contains(key)) 1.2328 + return PL_DHASH_NEXT; 1.2329 + 1.2330 + WriteAnnotation(ctx->fd, key, entry); 1.2331 + 1.2332 + return PL_DHASH_NEXT; 1.2333 +} 1.2334 + 1.2335 +static bool 1.2336 +WriteExtraData(nsIFile* extraFile, 1.2337 + const AnnotationTable& data, 1.2338 + const Blacklist& blacklist, 1.2339 + bool writeCrashTime=false, 1.2340 + bool truncate=false) 1.2341 +{ 1.2342 + PRFileDesc* fd; 1.2343 + int truncOrAppend = truncate ? PR_TRUNCATE : PR_APPEND; 1.2344 + nsresult rv = 1.2345 + extraFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | truncOrAppend, 1.2346 + 0600, &fd); 1.2347 + if (NS_FAILED(rv)) 1.2348 + return false; 1.2349 + 1.2350 + EnumerateAnnotationsContext ctx = { blacklist, fd }; 1.2351 + data.EnumerateRead(EnumerateAnnotations, &ctx); 1.2352 + 1.2353 + if (writeCrashTime) { 1.2354 + time_t crashTime = time(nullptr); 1.2355 + char crashTimeString[32]; 1.2356 + XP_TTOA(crashTime, crashTimeString, 10); 1.2357 + 1.2358 + WriteAnnotation(fd, 1.2359 + nsDependentCString("CrashTime"), 1.2360 + nsDependentCString(crashTimeString)); 1.2361 + } 1.2362 + 1.2363 + PR_Close(fd); 1.2364 + return true; 1.2365 +} 1.2366 + 1.2367 +bool 1.2368 +AppendExtraData(nsIFile* extraFile, const AnnotationTable& data) 1.2369 +{ 1.2370 + return WriteExtraData(extraFile, data, Blacklist()); 1.2371 +} 1.2372 + 1.2373 + 1.2374 +static bool 1.2375 +WriteExtraForMinidump(nsIFile* minidump, 1.2376 + const Blacklist& blacklist, 1.2377 + nsIFile** extraFile) 1.2378 +{ 1.2379 + nsCOMPtr<nsIFile> extra; 1.2380 + if (!GetExtraFileForMinidump(minidump, getter_AddRefs(extra))) 1.2381 + return false; 1.2382 + 1.2383 + if (!WriteExtraData(extra, *crashReporterAPIData_Hash, 1.2384 + blacklist, 1.2385 + true /*write crash time*/, 1.2386 + true /*truncate*/)) 1.2387 + return false; 1.2388 + 1.2389 + *extraFile = nullptr; 1.2390 + extra.swap(*extraFile); 1.2391 + 1.2392 + return true; 1.2393 +} 1.2394 + 1.2395 +// It really only makes sense to call this function when 1.2396 +// ShouldReport() is true. 1.2397 +static bool 1.2398 +MoveToPending(nsIFile* dumpFile, nsIFile* extraFile) 1.2399 +{ 1.2400 + nsCOMPtr<nsIFile> pendingDir; 1.2401 + if (!GetPendingDir(getter_AddRefs(pendingDir))) 1.2402 + return false; 1.2403 + 1.2404 + if (NS_FAILED(dumpFile->MoveTo(pendingDir, EmptyString()))) { 1.2405 + return false; 1.2406 + } 1.2407 + 1.2408 + if (extraFile && NS_FAILED(extraFile->MoveTo(pendingDir, EmptyString()))) { 1.2409 + return false; 1.2410 + } 1.2411 + 1.2412 + return true; 1.2413 +} 1.2414 + 1.2415 +static void 1.2416 +OnChildProcessDumpRequested(void* aContext, 1.2417 +#ifdef XP_MACOSX 1.2418 + const ClientInfo& aClientInfo, 1.2419 + const xpstring& aFilePath 1.2420 +#else 1.2421 + const ClientInfo* aClientInfo, 1.2422 + const xpstring* aFilePath 1.2423 +#endif 1.2424 + ) 1.2425 +{ 1.2426 + nsCOMPtr<nsIFile> minidump; 1.2427 + nsCOMPtr<nsIFile> extraFile; 1.2428 + 1.2429 + // Hold the mutex until the current dump request is complete, to 1.2430 + // prevent UnsetExceptionHandler() from pulling the rug out from 1.2431 + // under us. 1.2432 + MutexAutoLock lock(*dumpSafetyLock); 1.2433 + if (!isSafeToDump) 1.2434 + return; 1.2435 + 1.2436 + CreateFileFromPath( 1.2437 +#ifdef XP_MACOSX 1.2438 + aFilePath, 1.2439 +#else 1.2440 + *aFilePath, 1.2441 +#endif 1.2442 + getter_AddRefs(minidump)); 1.2443 + 1.2444 + if (!WriteExtraForMinidump(minidump, 1.2445 + Blacklist(kSubprocessBlacklist, 1.2446 + ArrayLength(kSubprocessBlacklist)), 1.2447 + getter_AddRefs(extraFile))) 1.2448 + return; 1.2449 + 1.2450 + if (ShouldReport()) 1.2451 + MoveToPending(minidump, extraFile); 1.2452 + 1.2453 + { 1.2454 + uint32_t pid = 1.2455 +#ifdef XP_MACOSX 1.2456 + aClientInfo.pid(); 1.2457 +#else 1.2458 + aClientInfo->pid(); 1.2459 +#endif 1.2460 + 1.2461 +#ifdef MOZ_CRASHREPORTER_INJECTOR 1.2462 + bool runCallback; 1.2463 +#endif 1.2464 + { 1.2465 + MutexAutoLock lock(*dumpMapLock); 1.2466 + ChildProcessData* pd = pidToMinidump->PutEntry(pid); 1.2467 + MOZ_ASSERT(!pd->minidump); 1.2468 + pd->minidump = minidump; 1.2469 + pd->sequence = ++crashSequence; 1.2470 +#ifdef MOZ_CRASHREPORTER_INJECTOR 1.2471 + runCallback = nullptr != pd->callback; 1.2472 +#endif 1.2473 + } 1.2474 +#ifdef MOZ_CRASHREPORTER_INJECTOR 1.2475 + if (runCallback) 1.2476 + NS_DispatchToMainThread(new ReportInjectedCrash(pid)); 1.2477 +#endif 1.2478 + } 1.2479 +} 1.2480 + 1.2481 +static bool 1.2482 +OOPInitialized() 1.2483 +{ 1.2484 + return pidToMinidump != nullptr; 1.2485 +} 1.2486 + 1.2487 +#ifdef XP_MACOSX 1.2488 +static bool ChildFilter(void *context) { 1.2489 + mozilla::IOInterposer::Disable(); 1.2490 + return true; 1.2491 +} 1.2492 +#endif 1.2493 + 1.2494 +void 1.2495 +OOPInit() 1.2496 +{ 1.2497 + if (OOPInitialized()) 1.2498 + return; 1.2499 + 1.2500 + MOZ_ASSERT(NS_IsMainThread()); 1.2501 + 1.2502 + NS_ABORT_IF_FALSE(gExceptionHandler != nullptr, 1.2503 + "attempt to initialize OOP crash reporter before in-process crashreporter!"); 1.2504 + 1.2505 +#if defined(XP_WIN) 1.2506 + childCrashNotifyPipe = 1.2507 + PR_smprintf("\\\\.\\pipe\\gecko-crash-server-pipe.%i", 1.2508 + static_cast<int>(::GetCurrentProcessId())); 1.2509 + 1.2510 + const std::wstring dumpPath = gExceptionHandler->dump_path(); 1.2511 + crashServer = new CrashGenerationServer( 1.2512 + NS_ConvertASCIItoUTF16(childCrashNotifyPipe).get(), 1.2513 + nullptr, // default security attributes 1.2514 + nullptr, nullptr, // we don't care about process connect here 1.2515 + OnChildProcessDumpRequested, nullptr, 1.2516 + nullptr, nullptr, // we don't care about process exit here 1.2517 + nullptr, nullptr, // we don't care about upload request here 1.2518 + true, // automatically generate dumps 1.2519 + &dumpPath); 1.2520 + 1.2521 +#elif defined(XP_LINUX) 1.2522 + if (!CrashGenerationServer::CreateReportChannel(&serverSocketFd, 1.2523 + &clientSocketFd)) 1.2524 + NS_RUNTIMEABORT("can't create crash reporter socketpair()"); 1.2525 + 1.2526 + const std::string dumpPath = 1.2527 + gExceptionHandler->minidump_descriptor().directory(); 1.2528 + crashServer = new CrashGenerationServer( 1.2529 + serverSocketFd, 1.2530 + OnChildProcessDumpRequested, nullptr, 1.2531 + nullptr, nullptr, // we don't care about process exit here 1.2532 + true, 1.2533 + &dumpPath); 1.2534 + 1.2535 +#elif defined(XP_MACOSX) 1.2536 + childCrashNotifyPipe = 1.2537 + PR_smprintf("gecko-crash-server-pipe.%i", 1.2538 + static_cast<int>(getpid())); 1.2539 + const std::string dumpPath = gExceptionHandler->dump_path(); 1.2540 + 1.2541 + crashServer = new CrashGenerationServer( 1.2542 + childCrashNotifyPipe, 1.2543 + ChildFilter, 1.2544 + nullptr, 1.2545 + OnChildProcessDumpRequested, nullptr, 1.2546 + nullptr, nullptr, 1.2547 + true, // automatically generate dumps 1.2548 + dumpPath); 1.2549 +#endif 1.2550 + 1.2551 + if (!crashServer->Start()) 1.2552 + NS_RUNTIMEABORT("can't start crash reporter server()"); 1.2553 + 1.2554 + pidToMinidump = new ChildMinidumpMap(); 1.2555 + 1.2556 + dumpMapLock = new Mutex("CrashReporter::dumpMapLock"); 1.2557 + 1.2558 + FindPendingDir(); 1.2559 + UpdateCrashEventsDir(); 1.2560 +} 1.2561 + 1.2562 +static void 1.2563 +OOPDeinit() 1.2564 +{ 1.2565 + if (!OOPInitialized()) { 1.2566 + NS_WARNING("OOPDeinit() without successful OOPInit()"); 1.2567 + return; 1.2568 + } 1.2569 + 1.2570 +#ifdef MOZ_CRASHREPORTER_INJECTOR 1.2571 + if (sInjectorThread) { 1.2572 + sInjectorThread->Shutdown(); 1.2573 + NS_RELEASE(sInjectorThread); 1.2574 + } 1.2575 +#endif 1.2576 + 1.2577 + delete crashServer; 1.2578 + crashServer = nullptr; 1.2579 + 1.2580 + delete dumpMapLock; 1.2581 + dumpMapLock = nullptr; 1.2582 + 1.2583 + delete pidToMinidump; 1.2584 + pidToMinidump = nullptr; 1.2585 + 1.2586 +#if defined(XP_WIN) 1.2587 + PR_Free(childCrashNotifyPipe); 1.2588 + childCrashNotifyPipe = nullptr; 1.2589 +#endif 1.2590 +} 1.2591 + 1.2592 +#if defined(XP_WIN) || defined(XP_MACOSX) 1.2593 +// Parent-side API for children 1.2594 +const char* 1.2595 +GetChildNotificationPipe() 1.2596 +{ 1.2597 + if (!GetEnabled()) 1.2598 + return kNullNotifyPipe; 1.2599 + 1.2600 + MOZ_ASSERT(OOPInitialized()); 1.2601 + 1.2602 + return childCrashNotifyPipe; 1.2603 +} 1.2604 +#endif 1.2605 + 1.2606 +#ifdef MOZ_CRASHREPORTER_INJECTOR 1.2607 +void 1.2608 +InjectCrashReporterIntoProcess(DWORD processID, InjectorCrashCallback* cb) 1.2609 +{ 1.2610 + if (!GetEnabled()) 1.2611 + return; 1.2612 + 1.2613 + if (!OOPInitialized()) 1.2614 + OOPInit(); 1.2615 + 1.2616 + if (!sInjectorThread) { 1.2617 + if (NS_FAILED(NS_NewThread(&sInjectorThread))) 1.2618 + return; 1.2619 + } 1.2620 + 1.2621 + { 1.2622 + MutexAutoLock lock(*dumpMapLock); 1.2623 + ChildProcessData* pd = pidToMinidump->PutEntry(processID); 1.2624 + MOZ_ASSERT(!pd->minidump && !pd->callback); 1.2625 + pd->callback = cb; 1.2626 + } 1.2627 + 1.2628 + nsCOMPtr<nsIRunnable> r = new InjectCrashRunnable(processID); 1.2629 + sInjectorThread->Dispatch(r, nsIEventTarget::DISPATCH_NORMAL); 1.2630 +} 1.2631 + 1.2632 +NS_IMETHODIMP 1.2633 +ReportInjectedCrash::Run() 1.2634 +{ 1.2635 + // Crash reporting may have been disabled after this method was dispatched 1.2636 + if (!OOPInitialized()) 1.2637 + return NS_OK; 1.2638 + 1.2639 + InjectorCrashCallback* cb; 1.2640 + { 1.2641 + MutexAutoLock lock(*dumpMapLock); 1.2642 + ChildProcessData* pd = pidToMinidump->GetEntry(mPID); 1.2643 + if (!pd || !pd->callback) 1.2644 + return NS_OK; 1.2645 + 1.2646 + MOZ_ASSERT(pd->minidump); 1.2647 + 1.2648 + cb = pd->callback; 1.2649 + } 1.2650 + 1.2651 + cb->OnCrash(mPID); 1.2652 + return NS_OK; 1.2653 +} 1.2654 + 1.2655 +void 1.2656 +UnregisterInjectorCallback(DWORD processID) 1.2657 +{ 1.2658 + if (!OOPInitialized()) 1.2659 + return; 1.2660 + 1.2661 + MutexAutoLock lock(*dumpMapLock); 1.2662 + pidToMinidump->RemoveEntry(processID); 1.2663 +} 1.2664 + 1.2665 +#endif // MOZ_CRASHREPORTER_INJECTOR 1.2666 + 1.2667 +bool 1.2668 +CheckForLastRunCrash() 1.2669 +{ 1.2670 + if (lastRunCrashID) 1.2671 + return true; 1.2672 + 1.2673 + // The exception handler callback leaves the filename of the 1.2674 + // last minidump in a known file. 1.2675 + nsCOMPtr<nsIFile> lastCrashFile; 1.2676 + CreateFileFromPath(crashMarkerFilename, 1.2677 + getter_AddRefs(lastCrashFile)); 1.2678 + 1.2679 + bool exists; 1.2680 + if (NS_FAILED(lastCrashFile->Exists(&exists)) || !exists) { 1.2681 + return false; 1.2682 + } 1.2683 + 1.2684 + nsAutoCString lastMinidump_contents; 1.2685 + if (NS_FAILED(GetFileContents(lastCrashFile, lastMinidump_contents))) { 1.2686 + return false; 1.2687 + } 1.2688 + lastCrashFile->Remove(false); 1.2689 + 1.2690 +#ifdef XP_WIN 1.2691 + // Ugly but effective. 1.2692 + nsDependentString lastMinidump( 1.2693 + reinterpret_cast<const char16_t*>(lastMinidump_contents.get())); 1.2694 +#else 1.2695 + nsAutoCString lastMinidump = lastMinidump_contents; 1.2696 +#endif 1.2697 + nsCOMPtr<nsIFile> lastMinidumpFile; 1.2698 + CreateFileFromPath(lastMinidump.get(), 1.2699 + getter_AddRefs(lastMinidumpFile)); 1.2700 + 1.2701 + if (!lastMinidumpFile || NS_FAILED(lastMinidumpFile->Exists(&exists)) || !exists) { 1.2702 + return false; 1.2703 + } 1.2704 + 1.2705 + nsCOMPtr<nsIFile> lastExtraFile; 1.2706 + if (!GetExtraFileForMinidump(lastMinidumpFile, 1.2707 + getter_AddRefs(lastExtraFile))) { 1.2708 + return false; 1.2709 + } 1.2710 + 1.2711 + FindPendingDir(); 1.2712 + 1.2713 + // Move {dump,extra} to pending folder 1.2714 + if (!MoveToPending(lastMinidumpFile, lastExtraFile)) { 1.2715 + return false; 1.2716 + } 1.2717 + 1.2718 + lastRunCrashID = new nsString(); 1.2719 + return GetIDFromMinidump(lastMinidumpFile, *lastRunCrashID); 1.2720 +} 1.2721 + 1.2722 +bool 1.2723 +GetLastRunCrashID(nsAString& id) 1.2724 +{ 1.2725 + if (!lastRunCrashID_checked) { 1.2726 + CheckForLastRunCrash(); 1.2727 + lastRunCrashID_checked = true; 1.2728 + } 1.2729 + 1.2730 + if (!lastRunCrashID) { 1.2731 + return false; 1.2732 + } 1.2733 + 1.2734 + id = *lastRunCrashID; 1.2735 + return true; 1.2736 +} 1.2737 + 1.2738 +#if defined(XP_WIN) 1.2739 +// Child-side API 1.2740 +bool 1.2741 +SetRemoteExceptionHandler(const nsACString& crashPipe) 1.2742 +{ 1.2743 + // crash reporting is disabled 1.2744 + if (crashPipe.Equals(kNullNotifyPipe)) 1.2745 + return true; 1.2746 + 1.2747 + NS_ABORT_IF_FALSE(!gExceptionHandler, "crash client already init'd"); 1.2748 + 1.2749 + gExceptionHandler = new google_breakpad:: 1.2750 + ExceptionHandler(L"", 1.2751 + FPEFilter, 1.2752 + nullptr, // no minidump callback 1.2753 + nullptr, // no callback context 1.2754 + google_breakpad::ExceptionHandler::HANDLER_ALL, 1.2755 + MiniDumpNormal, 1.2756 + NS_ConvertASCIItoUTF16(crashPipe).get(), 1.2757 + nullptr); 1.2758 +#ifdef XP_WIN 1.2759 + gExceptionHandler->set_handle_debug_exceptions(true); 1.2760 +#endif 1.2761 + 1.2762 + // we either do remote or nothing, no fallback to regular crash reporting 1.2763 + return gExceptionHandler->IsOutOfProcess(); 1.2764 +} 1.2765 + 1.2766 +//-------------------------------------------------- 1.2767 +#elif defined(XP_LINUX) 1.2768 + 1.2769 +// Parent-side API for children 1.2770 +bool 1.2771 +CreateNotificationPipeForChild(int* childCrashFd, int* childCrashRemapFd) 1.2772 +{ 1.2773 + if (!GetEnabled()) { 1.2774 + *childCrashFd = -1; 1.2775 + *childCrashRemapFd = -1; 1.2776 + return true; 1.2777 + } 1.2778 + 1.2779 + MOZ_ASSERT(OOPInitialized()); 1.2780 + 1.2781 + *childCrashFd = clientSocketFd; 1.2782 + *childCrashRemapFd = kMagicChildCrashReportFd; 1.2783 + 1.2784 + return true; 1.2785 +} 1.2786 + 1.2787 +// Child-side API 1.2788 +bool 1.2789 +SetRemoteExceptionHandler() 1.2790 +{ 1.2791 + NS_ABORT_IF_FALSE(!gExceptionHandler, "crash client already init'd"); 1.2792 + 1.2793 +#ifndef XP_LINUX 1.2794 + xpstring path = ""; 1.2795 +#else 1.2796 + // MinidumpDescriptor requires a non-empty path. 1.2797 + google_breakpad::MinidumpDescriptor path("."); 1.2798 +#endif 1.2799 + gExceptionHandler = new google_breakpad:: 1.2800 + ExceptionHandler(path, 1.2801 + nullptr, // no filter callback 1.2802 + nullptr, // no minidump callback 1.2803 + nullptr, // no callback context 1.2804 + true, // install signal handlers 1.2805 + kMagicChildCrashReportFd); 1.2806 + 1.2807 + if (gDelayedAnnotations) { 1.2808 + for (uint32_t i = 0; i < gDelayedAnnotations->Length(); i++) { 1.2809 + gDelayedAnnotations->ElementAt(i)->Run(); 1.2810 + } 1.2811 + delete gDelayedAnnotations; 1.2812 + } 1.2813 + 1.2814 + // we either do remote or nothing, no fallback to regular crash reporting 1.2815 + return gExceptionHandler->IsOutOfProcess(); 1.2816 +} 1.2817 + 1.2818 +//-------------------------------------------------- 1.2819 +#elif defined(XP_MACOSX) 1.2820 +// Child-side API 1.2821 +bool 1.2822 +SetRemoteExceptionHandler(const nsACString& crashPipe) 1.2823 +{ 1.2824 + // crash reporting is disabled 1.2825 + if (crashPipe.Equals(kNullNotifyPipe)) 1.2826 + return true; 1.2827 + 1.2828 + NS_ABORT_IF_FALSE(!gExceptionHandler, "crash client already init'd"); 1.2829 + 1.2830 + gExceptionHandler = new google_breakpad:: 1.2831 + ExceptionHandler("", 1.2832 + Filter, 1.2833 + nullptr, // no minidump callback 1.2834 + nullptr, // no callback context 1.2835 + true, // install signal handlers 1.2836 + crashPipe.BeginReading()); 1.2837 + 1.2838 + // we either do remote or nothing, no fallback to regular crash reporting 1.2839 + return gExceptionHandler->IsOutOfProcess(); 1.2840 +} 1.2841 +#endif // XP_WIN 1.2842 + 1.2843 + 1.2844 +bool 1.2845 +TakeMinidumpForChild(uint32_t childPid, nsIFile** dump, uint32_t* aSequence) 1.2846 +{ 1.2847 + if (!GetEnabled()) 1.2848 + return false; 1.2849 + 1.2850 + MutexAutoLock lock(*dumpMapLock); 1.2851 + 1.2852 + ChildProcessData* pd = pidToMinidump->GetEntry(childPid); 1.2853 + if (!pd) 1.2854 + return false; 1.2855 + 1.2856 + NS_IF_ADDREF(*dump = pd->minidump); 1.2857 + if (aSequence) { 1.2858 + *aSequence = pd->sequence; 1.2859 + } 1.2860 + 1.2861 + pidToMinidump->RemoveEntry(childPid); 1.2862 + 1.2863 + return !!*dump; 1.2864 +} 1.2865 + 1.2866 +//----------------------------------------------------------------------------- 1.2867 +// CreatePairedMinidumps() and helpers 1.2868 +// 1.2869 + 1.2870 +void 1.2871 +RenameAdditionalHangMinidump(nsIFile* minidump, nsIFile* childMinidump, 1.2872 + const nsACString& name) 1.2873 +{ 1.2874 + nsCOMPtr<nsIFile> directory; 1.2875 + childMinidump->GetParent(getter_AddRefs(directory)); 1.2876 + if (!directory) 1.2877 + return; 1.2878 + 1.2879 + nsAutoCString leafName; 1.2880 + childMinidump->GetNativeLeafName(leafName); 1.2881 + 1.2882 + // turn "<id>.dmp" into "<id>-<name>.dmp 1.2883 + leafName.Insert(NS_LITERAL_CSTRING("-") + name, leafName.Length() - 4); 1.2884 + 1.2885 + minidump->MoveToNative(directory, leafName); 1.2886 +} 1.2887 + 1.2888 +static bool 1.2889 +PairedDumpCallback( 1.2890 +#ifdef XP_LINUX 1.2891 + const MinidumpDescriptor& descriptor, 1.2892 +#else 1.2893 + const XP_CHAR* dump_path, 1.2894 + const XP_CHAR* minidump_id, 1.2895 +#endif 1.2896 + void* context, 1.2897 +#ifdef XP_WIN32 1.2898 + EXCEPTION_POINTERS* /*unused*/, 1.2899 + MDRawAssertionInfo* /*unused*/, 1.2900 +#endif 1.2901 + bool succeeded) 1.2902 +{ 1.2903 + nsCOMPtr<nsIFile>& minidump = *static_cast< nsCOMPtr<nsIFile>* >(context); 1.2904 + 1.2905 + xpstring dump; 1.2906 +#ifdef XP_LINUX 1.2907 + dump = descriptor.path(); 1.2908 +#else 1.2909 + dump = dump_path; 1.2910 + dump += XP_PATH_SEPARATOR; 1.2911 + dump += minidump_id; 1.2912 + dump += dumpFileExtension; 1.2913 +#endif 1.2914 + 1.2915 + CreateFileFromPath(dump, getter_AddRefs(minidump)); 1.2916 + return true; 1.2917 +} 1.2918 + 1.2919 +static bool 1.2920 +PairedDumpCallbackExtra( 1.2921 +#ifdef XP_LINUX 1.2922 + const MinidumpDescriptor& descriptor, 1.2923 +#else 1.2924 + const XP_CHAR* dump_path, 1.2925 + const XP_CHAR* minidump_id, 1.2926 +#endif 1.2927 + void* context, 1.2928 +#ifdef XP_WIN32 1.2929 + EXCEPTION_POINTERS* /*unused*/, 1.2930 + MDRawAssertionInfo* /*unused*/, 1.2931 +#endif 1.2932 + bool succeeded) 1.2933 +{ 1.2934 + PairedDumpCallback( 1.2935 +#ifdef XP_LINUX 1.2936 + descriptor, 1.2937 +#else 1.2938 + dump_path, minidump_id, 1.2939 +#endif 1.2940 + context, 1.2941 +#ifdef XP_WIN32 1.2942 + nullptr, nullptr, 1.2943 +#endif 1.2944 + succeeded); 1.2945 + 1.2946 + nsCOMPtr<nsIFile>& minidump = *static_cast< nsCOMPtr<nsIFile>* >(context); 1.2947 + 1.2948 + nsCOMPtr<nsIFile> extra; 1.2949 + return WriteExtraForMinidump(minidump, Blacklist(), getter_AddRefs(extra)); 1.2950 +} 1.2951 + 1.2952 +ThreadId 1.2953 +CurrentThreadId() 1.2954 +{ 1.2955 +#if defined(XP_WIN) 1.2956 + return ::GetCurrentThreadId(); 1.2957 +#elif defined(XP_LINUX) 1.2958 + return sys_gettid(); 1.2959 +#elif defined(XP_MACOSX) 1.2960 + // Just return an index, since Mach ports can't be directly serialized 1.2961 + thread_act_port_array_t threads_for_task; 1.2962 + mach_msg_type_number_t thread_count; 1.2963 + 1.2964 + if (task_threads(mach_task_self(), &threads_for_task, &thread_count)) 1.2965 + return -1; 1.2966 + 1.2967 + for (unsigned int i = 0; i < thread_count; ++i) { 1.2968 + if (threads_for_task[i] == mach_thread_self()) 1.2969 + return i; 1.2970 + } 1.2971 + abort(); 1.2972 +#else 1.2973 +# error "Unsupported platform" 1.2974 +#endif 1.2975 +} 1.2976 + 1.2977 +#ifdef XP_MACOSX 1.2978 +static mach_port_t 1.2979 +GetChildThread(ProcessHandle childPid, ThreadId childBlamedThread) 1.2980 +{ 1.2981 + mach_port_t childThread = MACH_PORT_NULL; 1.2982 + thread_act_port_array_t threads_for_task; 1.2983 + mach_msg_type_number_t thread_count; 1.2984 + 1.2985 + if (task_threads(childPid, &threads_for_task, &thread_count) 1.2986 + == KERN_SUCCESS && childBlamedThread < thread_count) { 1.2987 + childThread = threads_for_task[childBlamedThread]; 1.2988 + } 1.2989 + 1.2990 + return childThread; 1.2991 +} 1.2992 +#endif 1.2993 + 1.2994 +bool 1.2995 +CreatePairedMinidumps(ProcessHandle childPid, 1.2996 + ThreadId childBlamedThread, 1.2997 + nsIFile** childDump) 1.2998 +{ 1.2999 + if (!GetEnabled()) 1.3000 + return false; 1.3001 + 1.3002 +#ifdef XP_MACOSX 1.3003 + mach_port_t childThread = GetChildThread(childPid, childBlamedThread); 1.3004 +#else 1.3005 + ThreadId childThread = childBlamedThread; 1.3006 +#endif 1.3007 + 1.3008 + xpstring dump_path; 1.3009 +#ifndef XP_LINUX 1.3010 + dump_path = gExceptionHandler->dump_path(); 1.3011 +#else 1.3012 + dump_path = gExceptionHandler->minidump_descriptor().directory(); 1.3013 +#endif 1.3014 + 1.3015 + // dump the child 1.3016 + nsCOMPtr<nsIFile> childMinidump; 1.3017 + if (!google_breakpad::ExceptionHandler::WriteMinidumpForChild( 1.3018 + childPid, 1.3019 + childThread, 1.3020 + dump_path, 1.3021 + PairedDumpCallbackExtra, 1.3022 + static_cast<void*>(&childMinidump))) 1.3023 + return false; 1.3024 + 1.3025 + nsCOMPtr<nsIFile> childExtra; 1.3026 + GetExtraFileForMinidump(childMinidump, getter_AddRefs(childExtra)); 1.3027 + 1.3028 + // dump the parent 1.3029 + nsCOMPtr<nsIFile> parentMinidump; 1.3030 + if (!google_breakpad::ExceptionHandler::WriteMinidump( 1.3031 + dump_path, 1.3032 +#ifdef XP_MACOSX 1.3033 + true, // write exception stream 1.3034 +#endif 1.3035 + PairedDumpCallback, 1.3036 + static_cast<void*>(&parentMinidump))) { 1.3037 + 1.3038 + childMinidump->Remove(false); 1.3039 + childExtra->Remove(false); 1.3040 + 1.3041 + return false; 1.3042 + } 1.3043 + 1.3044 + // success 1.3045 + RenameAdditionalHangMinidump(parentMinidump, childMinidump, 1.3046 + NS_LITERAL_CSTRING("browser")); 1.3047 + 1.3048 + if (ShouldReport()) { 1.3049 + MoveToPending(childMinidump, childExtra); 1.3050 + MoveToPending(parentMinidump, nullptr); 1.3051 + } 1.3052 + 1.3053 + childMinidump.forget(childDump); 1.3054 + 1.3055 + return true; 1.3056 +} 1.3057 + 1.3058 +bool 1.3059 +CreateAdditionalChildMinidump(ProcessHandle childPid, 1.3060 + ThreadId childBlamedThread, 1.3061 + nsIFile* parentMinidump, 1.3062 + const nsACString& name) 1.3063 +{ 1.3064 + if (!GetEnabled()) 1.3065 + return false; 1.3066 + 1.3067 +#ifdef XP_MACOSX 1.3068 + mach_port_t childThread = GetChildThread(childPid, childBlamedThread); 1.3069 +#else 1.3070 + ThreadId childThread = childBlamedThread; 1.3071 +#endif 1.3072 + 1.3073 + xpstring dump_path; 1.3074 +#ifndef XP_LINUX 1.3075 + dump_path = gExceptionHandler->dump_path(); 1.3076 +#else 1.3077 + dump_path = gExceptionHandler->minidump_descriptor().directory(); 1.3078 +#endif 1.3079 + 1.3080 + // dump the child 1.3081 + nsCOMPtr<nsIFile> childMinidump; 1.3082 + if (!google_breakpad::ExceptionHandler::WriteMinidumpForChild( 1.3083 + childPid, 1.3084 + childThread, 1.3085 + dump_path, 1.3086 + PairedDumpCallback, 1.3087 + static_cast<void*>(&childMinidump))) { 1.3088 + return false; 1.3089 + } 1.3090 + 1.3091 + RenameAdditionalHangMinidump(childMinidump, parentMinidump, name); 1.3092 + 1.3093 + return true; 1.3094 +} 1.3095 + 1.3096 +bool 1.3097 +UnsetRemoteExceptionHandler() 1.3098 +{ 1.3099 + delete gExceptionHandler; 1.3100 + gExceptionHandler = nullptr; 1.3101 + return true; 1.3102 +} 1.3103 + 1.3104 +#if defined(MOZ_WIDGET_ANDROID) 1.3105 +void AddLibraryMapping(const char* library_name, 1.3106 + uintptr_t start_address, 1.3107 + size_t mapping_length, 1.3108 + size_t file_offset) 1.3109 +{ 1.3110 + if (!gExceptionHandler) { 1.3111 + mapping_info info; 1.3112 + info.name = library_name; 1.3113 + info.start_address = start_address; 1.3114 + info.length = mapping_length; 1.3115 + info.file_offset = file_offset; 1.3116 + library_mappings.push_back(info); 1.3117 + } 1.3118 + else { 1.3119 + u_int8_t guid[sizeof(MDGUID)]; 1.3120 + google_breakpad::FileID::ElfFileIdentifierFromMappedFile((void const *)start_address, guid); 1.3121 + gExceptionHandler->AddMappingInfo(library_name, 1.3122 + guid, 1.3123 + start_address, 1.3124 + mapping_length, 1.3125 + file_offset); 1.3126 + } 1.3127 +} 1.3128 +#endif 1.3129 + 1.3130 +} // namespace CrashReporter