LCOV - code coverage report
Current view: directory - toolkit/crashreporter - nsExceptionHandler.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 664 220 33.1 %
Date: 2012-06-02 Functions: 63 22 34.9 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Mozilla Breakpad integration
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is
      18                 :  * Ted Mielczarek <ted.mielczarek@gmail.com>
      19                 :  * Portions created by the Initial Developer are Copyright (C) 2006
      20                 :  * the Initial Developer. All Rights Reserved.
      21                 :  *
      22                 :  * Contributor(s):
      23                 :  *  Josh Aas <josh@mozilla.com>
      24                 :  *  Justin Dolske <dolske@mozilla.com>
      25                 :  *
      26                 :  * Alternatively, the contents of this file may be used under the terms of
      27                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      28                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      30                 :  * of those above. If you wish to allow use of your version of this file only
      31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      32                 :  * use your version of this file under the terms of the MPL, indicate your
      33                 :  * decision by deleting the provisions above and replace them with the notice
      34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      35                 :  * the provisions above, a recipient may use your version of this file under
      36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      37                 :  *
      38                 :  * ***** END LICENSE BLOCK ***** */
      39                 : 
      40                 : #include "mozilla/dom/CrashReporterChild.h"
      41                 : #include "mozilla/Services.h"
      42                 : #include "nsIObserverService.h"
      43                 : #include "mozilla/Util.h"
      44                 : 
      45                 : #include "nsXULAppAPI.h"
      46                 : 
      47                 : #include "nsExceptionHandler.h"
      48                 : #include "nsThreadUtils.h"
      49                 : 
      50                 : #if defined(XP_WIN32)
      51                 : #ifdef WIN32_LEAN_AND_MEAN
      52                 : #undef WIN32_LEAN_AND_MEAN
      53                 : #endif
      54                 : 
      55                 : #include "nsIWindowsRegKey.h"
      56                 : #include "client/windows/crash_generation/crash_generation_server.h"
      57                 : #include "client/windows/handler/exception_handler.h"
      58                 : #include <DbgHelp.h>
      59                 : #include <string.h>
      60                 : #elif defined(XP_MACOSX)
      61                 : #include "client/mac/crash_generation/client_info.h"
      62                 : #include "client/mac/crash_generation/crash_generation_server.h"
      63                 : #include "client/mac/handler/exception_handler.h"
      64                 : #include <string>
      65                 : #include <Carbon/Carbon.h>
      66                 : #include <CoreFoundation/CoreFoundation.h>
      67                 : #include <crt_externs.h>
      68                 : #include <fcntl.h>
      69                 : #include <mach/mach.h>
      70                 : #include <sys/types.h>
      71                 : #include <spawn.h>
      72                 : #include <unistd.h>
      73                 : #include "mac_utils.h"
      74                 : #elif defined(XP_LINUX)
      75                 : #include "nsDirectoryServiceUtils.h"
      76                 : #include "nsDirectoryServiceDefs.h"
      77                 : #include "nsIINIParser.h"
      78                 : #include "common/linux/linux_libc_support.h"
      79                 : #include "common/linux/linux_syscall_support.h"
      80                 : #include "client/linux/crash_generation/client_info.h"
      81                 : #include "client/linux/crash_generation/crash_generation_server.h"
      82                 : #include "client/linux/handler/exception_handler.h"
      83                 : #include "client/linux/minidump_writer/linux_dumper.h"
      84                 : #include "client/linux/minidump_writer/minidump_writer.h"
      85                 : #include <fcntl.h>
      86                 : #include <sys/types.h>
      87                 : #include <unistd.h>
      88                 : #elif defined(XP_SOLARIS)
      89                 : #include "client/solaris/handler/exception_handler.h"
      90                 : #include <fcntl.h>
      91                 : #include <sys/types.h>
      92                 : #include <unistd.h>
      93                 : #else
      94                 : #error "Not yet implemented for this platform"
      95                 : #endif // defined(XP_WIN32)
      96                 : 
      97                 : #include <stdlib.h>
      98                 : #include <time.h>
      99                 : #include <prenv.h>
     100                 : #include <prio.h>
     101                 : #include <prmem.h>
     102                 : #include "mozilla/Mutex.h"
     103                 : #include "nsDebug.h"
     104                 : #include "nsCRT.h"
     105                 : #include "nsILocalFile.h"
     106                 : #include "nsIFileStreams.h"
     107                 : #include "nsInterfaceHashtable.h"
     108                 : #include "prprf.h"
     109                 : #include "nsIXULAppInfo.h"
     110                 : #include <map>
     111                 : #include <vector>
     112                 : 
     113                 : #include "mozilla/mozalloc_oom.h"
     114                 : 
     115                 : #if defined(XP_MACOSX)
     116                 : CFStringRef reporterClientAppID = CFSTR("org.mozilla.crashreporter");
     117                 : #endif
     118                 : 
     119                 : #include "nsIUUIDGenerator.h"
     120                 : 
     121                 : using google_breakpad::CrashGenerationServer;
     122                 : using google_breakpad::ClientInfo;
     123                 : using namespace mozilla;
     124                 : using mozilla::dom::CrashReporterChild;
     125                 : using mozilla::dom::PCrashReporterChild;
     126                 : 
     127                 : namespace CrashReporter {
     128                 : 
     129                 : #ifdef XP_WIN32
     130                 : typedef wchar_t XP_CHAR;
     131                 : typedef std::wstring xpstring;
     132                 : #define CONVERT_UTF16_TO_XP_CHAR(x) x
     133                 : #define CONVERT_XP_CHAR_TO_UTF16(x) x
     134                 : #define XP_STRLEN(x) wcslen(x)
     135                 : #define my_strlen strlen
     136                 : #define CRASH_REPORTER_FILENAME "crashreporter.exe"
     137                 : #define PATH_SEPARATOR "\\"
     138                 : #define XP_PATH_SEPARATOR L"\\"
     139                 : // sort of arbitrary, but MAX_PATH is kinda small
     140                 : #define XP_PATH_MAX 4096
     141                 : // "<reporter path>" "<minidump path>"
     142                 : #define CMDLINE_SIZE ((XP_PATH_MAX * 2) + 6)
     143                 : #ifdef _USE_32BIT_TIME_T
     144                 : #define XP_TTOA(time, buffer, base) ltoa(time, buffer, base)
     145                 : #else
     146                 : #define XP_TTOA(time, buffer, base) _i64toa(time, buffer, base)
     147                 : #endif
     148                 : #define XP_STOA(size, buffer, base) _ui64toa(size, buffer, base)
     149                 : #else
     150                 : typedef char XP_CHAR;
     151                 : typedef std::string xpstring;
     152                 : #define CONVERT_UTF16_TO_XP_CHAR(x) NS_ConvertUTF16toUTF8(x)
     153                 : #define CONVERT_XP_CHAR_TO_UTF16(x) NS_ConvertUTF8toUTF16(x)
     154                 : #define CRASH_REPORTER_FILENAME "crashreporter"
     155                 : #define PATH_SEPARATOR "/"
     156                 : #define XP_PATH_SEPARATOR "/"
     157                 : #define XP_PATH_MAX PATH_MAX
     158                 : #ifdef XP_LINUX
     159                 : #define XP_STRLEN(x) my_strlen(x)
     160                 : #define XP_TTOA(time, buffer, base) my_inttostring(time, buffer, sizeof(buffer))
     161                 : #define XP_STOA(size, buffer, base) my_inttostring(size, buffer, sizeof(buffer))
     162                 : #else
     163                 : #define XP_STRLEN(x) strlen(x)
     164                 : #define XP_TTOA(time, buffer, base) sprintf(buffer, "%ld", time)
     165                 : #define XP_STOA(size, buffer, base) sprintf(buffer, "%zu", size)
     166                 : #define my_strlen strlen
     167                 : #define sys_close close
     168                 : #define sys_fork fork
     169                 : #define sys_open open
     170                 : #define sys_write write
     171                 : #endif
     172                 : #endif // XP_WIN32
     173                 : 
     174                 : static const XP_CHAR dumpFileExtension[] = {'.', 'd', 'm', 'p',
     175                 :                                             '\0'}; // .dmp
     176                 : static const XP_CHAR extraFileExtension[] = {'.', 'e', 'x', 't',
     177                 :                                              'r', 'a', '\0'}; // .extra
     178                 : 
     179                 : static google_breakpad::ExceptionHandler* gExceptionHandler = nsnull;
     180                 : 
     181                 : static XP_CHAR* crashReporterPath;
     182                 : 
     183                 : // if this is false, we don't launch the crash reporter
     184                 : static bool doReport = true;
     185                 : 
     186                 : // if this is true, we pass the exception on to the OS crash reporter
     187                 : static bool showOSCrashReporter = false;
     188                 : 
     189                 : // The time of the last recorded crash, as a time_t value.
     190                 : static time_t lastCrashTime = 0;
     191                 : // The pathname of a file to store the crash time in
     192                 : static XP_CHAR lastCrashTimeFilename[XP_PATH_MAX] = {0};
     193                 : 
     194                 : // these are just here for readability
     195                 : static const char kCrashTimeParameter[] = "CrashTime=";
     196                 : static const int kCrashTimeParameterLen = sizeof(kCrashTimeParameter)-1;
     197                 : 
     198                 : static const char kTimeSinceLastCrashParameter[] = "SecondsSinceLastCrash=";
     199                 : static const int kTimeSinceLastCrashParameterLen =
     200                 :                                      sizeof(kTimeSinceLastCrashParameter)-1;
     201                 : 
     202                 : static const char kSysMemoryParameter[] = "SystemMemoryUsePercentage=";
     203                 : static const int kSysMemoryParameterLen = sizeof(kSysMemoryParameter)-1;
     204                 : 
     205                 : static const char kTotalVirtualMemoryParameter[] = "TotalVirtualMemory=";
     206                 : static const int kTotalVirtualMemoryParameterLen =
     207                 :   sizeof(kTotalVirtualMemoryParameter)-1;
     208                 : 
     209                 : static const char kAvailableVirtualMemoryParameter[] = "AvailableVirtualMemory=";
     210                 : static const int kAvailableVirtualMemoryParameterLen =
     211                 :   sizeof(kAvailableVirtualMemoryParameter)-1;
     212                 : 
     213                 : static const char kOOMAllocationSizeParameter[] = "OOMAllocationSize=";
     214                 : static const int kOOMAllocationSizeParameterLen =
     215                 :   sizeof(kOOMAllocationSizeParameter)-1;
     216                 : 
     217                 : static const char kAvailablePageFileParameter[] = "AvailablePageFile=";
     218                 : static const int kAvailablePageFileParameterLen =
     219                 :   sizeof(kAvailablePageFileParameter)-1;
     220                 : 
     221                 : static const char kAvailablePhysicalMemoryParameter[] = "AvailablePhysicalMemory=";
     222                 : static const int kAvailablePhysicalMemoryParameterLen =
     223                 :   sizeof(kAvailablePhysicalMemoryParameter)-1;
     224                 : 
     225                 : // this holds additional data sent via the API
     226                 : static Mutex* crashReporterAPILock;
     227                 : static Mutex* notesFieldLock;
     228                 : static AnnotationTable* crashReporterAPIData_Hash;
     229                 : static nsCString* crashReporterAPIData = nsnull;
     230                 : static nsCString* notesField = nsnull;
     231                 : 
     232                 : // OOP crash reporting
     233                 : static CrashGenerationServer* crashServer; // chrome process has this
     234                 : 
     235                 : #  if defined(XP_WIN) || defined(XP_MACOSX)
     236                 : // If crash reporting is disabled, we hand out this "null" pipe to the
     237                 : // child process and don't attempt to connect to a parent server.
     238                 : static const char kNullNotifyPipe[] = "-";
     239                 : static char* childCrashNotifyPipe;
     240                 : 
     241                 : #  elif defined(XP_LINUX)
     242                 : static int serverSocketFd = -1;
     243                 : static int clientSocketFd = -1;
     244                 : static const int kMagicChildCrashReportFd = 4;
     245                 : 
     246                 : #  endif
     247                 : 
     248                 : // |dumpMapLock| must protect all access to |pidToMinidump|.
     249                 : static Mutex* dumpMapLock;
     250                 : typedef nsInterfaceHashtable<nsUint32HashKey, nsILocalFile> ChildMinidumpMap;
     251                 : static ChildMinidumpMap* pidToMinidump;
     252                 : 
     253                 : // Crashreporter annotations that we don't send along in subprocess
     254                 : // reports
     255                 : static const char* kSubprocessBlacklist[] = {
     256                 :   "FramePoisonBase",
     257                 :   "FramePoisonSize",
     258                 :   "StartupTime",
     259                 :   "URL"
     260                 : };
     261                 : 
     262                 : // If annotations are attempted before the crash reporter is enabled,
     263                 : // they queue up here.
     264                 : class DelayedNote;
     265                 : nsTArray<nsAutoPtr<DelayedNote> >* gDelayedAnnotations;
     266                 : 
     267                 : #ifdef XP_MACOSX
     268                 : static cpu_type_t pref_cpu_types[2] = {
     269                 : #if defined(__i386__)
     270                 :                                  CPU_TYPE_X86,
     271                 : #elif defined(__x86_64__)
     272                 :                                  CPU_TYPE_X86_64,
     273                 : #elif defined(__ppc__)
     274                 :                                  CPU_TYPE_POWERPC,
     275                 : #endif
     276                 :                                  CPU_TYPE_ANY };
     277                 : 
     278                 : static posix_spawnattr_t spawnattr;
     279                 : #endif
     280                 : 
     281                 : #if defined(__ANDROID__)
     282                 : // Android builds use a custom library loader,
     283                 : // so the embedding will provide a list of shared
     284                 : // libraries that are mapped into anonymous mappings.
     285                 : typedef struct {
     286                 :   std::string name;
     287                 :   std::string debug_id;
     288                 :   uintptr_t   start_address;
     289                 :   size_t      length;
     290                 :   size_t      file_offset;
     291                 : } mapping_info;
     292                 : static std::vector<mapping_info> library_mappings;
     293                 : typedef std::map<PRUint32,google_breakpad::MappingList> MappingMap;
     294                 : static MappingMap child_library_mappings;
     295                 : 
     296                 : void FileIDToGUID(const char* file_id, u_int8_t guid[sizeof(MDGUID)])
     297                 : {
     298                 :   for (int i = 0; i < sizeof(MDGUID); i++) {
     299                 :     int c;
     300                 :     sscanf(file_id, "%02X", &c);
     301                 :     guid[i] = (u_int8_t)(c & 0xFF);
     302                 :     file_id += 2;
     303                 :   }
     304                 :   // GUIDs are stored in network byte order.
     305                 :   uint32_t* data1 = reinterpret_cast<uint32_t*>(guid);
     306                 :   *data1 = htonl(*data1);
     307                 :   uint16_t* data2 = reinterpret_cast<uint16_t*>(guid + 4);
     308                 :   *data2 = htons(*data2);
     309                 :   uint16_t* data3 = reinterpret_cast<uint16_t*>(guid + 6);
     310                 :   *data3 = htons(*data3);
     311                 : }
     312                 : #endif
     313                 : 
     314                 : #ifdef XP_LINUX
     315                 : inline void
     316            1408 : my_inttostring(intmax_t t, char* buffer, size_t buffer_length)
     317                 : {
     318            1408 :   my_memset(buffer, 0, buffer_length);
     319            1408 :   my_itos(buffer, t, my_int_len(t));
     320            1408 : }
     321                 : #endif
     322                 : 
     323                 : #ifdef XP_WIN
     324                 : static void
     325                 : CreateFileFromPath(const xpstring& path, nsILocalFile** file)
     326                 : {
     327                 :   NS_NewLocalFile(nsDependentString(path.c_str()), false, file);
     328                 : }
     329                 : #else
     330                 : static void
     331               0 : CreateFileFromPath(const xpstring& path, nsILocalFile** file)
     332                 : {
     333               0 :   NS_NewNativeLocalFile(nsDependentCString(path.c_str()), false, file);
     334               0 : }
     335                 : #endif
     336                 : 
     337                 : static XP_CHAR*
     338               0 : Concat(XP_CHAR* str, const XP_CHAR* toAppend, int* size)
     339                 : {
     340               0 :   int appendLen = XP_STRLEN(toAppend);
     341               0 :   if (appendLen >= *size) appendLen = *size - 1;
     342                 : 
     343               0 :   memcpy(str, toAppend, appendLen * sizeof(XP_CHAR));
     344               0 :   str += appendLen;
     345               0 :   *str = '\0';
     346               0 :   *size -= appendLen;
     347                 : 
     348               0 :   return str;
     349                 : }
     350                 : 
     351                 : static size_t gOOMAllocationSize = 0;
     352                 : 
     353               0 : void AnnotateOOMAllocationSize(size_t size)
     354                 : {
     355               0 :   gOOMAllocationSize = size;
     356               0 : }
     357                 : 
     358               0 : bool MinidumpCallback(const XP_CHAR* dump_path,
     359                 :                       const XP_CHAR* minidump_id,
     360                 :                       void* context,
     361                 : #ifdef XP_WIN32
     362                 :                       EXCEPTION_POINTERS* exinfo,
     363                 :                       MDRawAssertionInfo* assertion,
     364                 : #endif
     365                 :                       bool succeeded)
     366                 : {
     367               0 :   bool returnValue = showOSCrashReporter ? false : succeeded;
     368                 : 
     369                 :   static XP_CHAR minidumpPath[XP_PATH_MAX];
     370               0 :   int size = XP_PATH_MAX;
     371               0 :   XP_CHAR* p = Concat(minidumpPath, dump_path, &size);
     372               0 :   p = Concat(p, XP_PATH_SEPARATOR, &size);
     373               0 :   p = Concat(p, minidump_id, &size);
     374               0 :   Concat(p, dumpFileExtension, &size);
     375                 : 
     376                 :   static XP_CHAR extraDataPath[XP_PATH_MAX];
     377               0 :   size = XP_PATH_MAX;
     378               0 :   p = Concat(extraDataPath, dump_path, &size);
     379               0 :   p = Concat(p, XP_PATH_SEPARATOR, &size);
     380               0 :   p = Concat(p, minidump_id, &size);
     381               0 :   Concat(p, extraFileExtension, &size);
     382                 : 
     383                 :   char oomAllocationSizeBuffer[32];
     384               0 :   int oomAllocationSizeBufferLen = 0;
     385               0 :   if (gOOMAllocationSize) {
     386               0 :     XP_STOA(gOOMAllocationSize, oomAllocationSizeBuffer, 10);
     387               0 :     oomAllocationSizeBufferLen = my_strlen(oomAllocationSizeBuffer);
     388                 :   }
     389                 : 
     390                 :   // calculate time since last crash (if possible), and store
     391                 :   // the time of this crash.
     392                 :   time_t crashTime;
     393                 : #ifdef XP_LINUX
     394                 :   struct kernel_timeval tv;
     395               0 :   sys_gettimeofday(&tv, NULL);
     396               0 :   crashTime = tv.tv_sec;
     397                 : #else
     398                 :   crashTime = time(NULL);
     399                 : #endif
     400               0 :   time_t timeSinceLastCrash = 0;
     401                 :   // stringified versions of the above
     402                 :   char crashTimeString[32];
     403               0 :   int crashTimeStringLen = 0;
     404                 :   char timeSinceLastCrashString[32];
     405               0 :   int timeSinceLastCrashStringLen = 0;
     406                 : 
     407               0 :   XP_TTOA(crashTime, crashTimeString, 10);
     408               0 :   crashTimeStringLen = my_strlen(crashTimeString);
     409               0 :   if (lastCrashTime != 0) {
     410               0 :     timeSinceLastCrash = crashTime - lastCrashTime;
     411               0 :     XP_TTOA(timeSinceLastCrash, timeSinceLastCrashString, 10);
     412               0 :     timeSinceLastCrashStringLen = my_strlen(timeSinceLastCrashString);
     413                 :   }
     414                 :   // write crash time to file
     415               0 :   if (lastCrashTimeFilename[0] != 0) {
     416                 : #if defined(XP_WIN32)
     417                 :     HANDLE hFile = CreateFile(lastCrashTimeFilename, GENERIC_WRITE, 0,
     418                 :                               NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
     419                 :                               NULL);
     420                 :     if(hFile != INVALID_HANDLE_VALUE) {
     421                 :       DWORD nBytes;
     422                 :       WriteFile(hFile, crashTimeString, crashTimeStringLen, &nBytes, NULL);
     423                 :       CloseHandle(hFile);
     424                 :     }
     425                 : #elif defined(XP_UNIX)
     426                 :     int fd = sys_open(lastCrashTimeFilename,
     427                 :                       O_WRONLY | O_CREAT | O_TRUNC,
     428               0 :                       0600);
     429               0 :     if (fd != -1) {
     430               0 :       ssize_t ignored = sys_write(fd, crashTimeString, crashTimeStringLen);
     431                 :       (void)ignored;
     432               0 :       sys_close(fd);
     433                 :     }
     434                 : #endif
     435                 :   }
     436                 : 
     437                 : #if defined(XP_WIN32)
     438                 :   XP_CHAR cmdLine[CMDLINE_SIZE];
     439                 :   size = CMDLINE_SIZE;
     440                 :   p = Concat(cmdLine, L"\"", &size);
     441                 :   p = Concat(p, crashReporterPath, &size);
     442                 :   p = Concat(p, L"\" \"", &size);
     443                 :   p = Concat(p, minidumpPath, &size);
     444                 :   Concat(p, L"\"", &size);
     445                 : 
     446                 :   if (!crashReporterAPIData->IsEmpty()) {
     447                 :     // write out API data
     448                 :     HANDLE hFile = CreateFile(extraDataPath, GENERIC_WRITE, 0,
     449                 :                               NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL,
     450                 :                               NULL);
     451                 :     if(hFile != INVALID_HANDLE_VALUE) {
     452                 :       DWORD nBytes;
     453                 :       WriteFile(hFile, crashReporterAPIData->get(),
     454                 :                 crashReporterAPIData->Length(), &nBytes, NULL);
     455                 :       WriteFile(hFile, kCrashTimeParameter, kCrashTimeParameterLen,
     456                 :                 &nBytes, NULL);
     457                 :       WriteFile(hFile, crashTimeString, crashTimeStringLen, &nBytes, NULL);
     458                 :       WriteFile(hFile, "\n", 1, &nBytes, NULL);
     459                 :       if (timeSinceLastCrash != 0) {
     460                 :         WriteFile(hFile, kTimeSinceLastCrashParameter,
     461                 :                   kTimeSinceLastCrashParameterLen, &nBytes, NULL);
     462                 :         WriteFile(hFile, timeSinceLastCrashString, timeSinceLastCrashStringLen,
     463                 :                   &nBytes, NULL);
     464                 :         WriteFile(hFile, "\n", 1, &nBytes, NULL);
     465                 :       }
     466                 : 
     467                 :       // Try to get some information about memory.
     468                 :       MEMORYSTATUSEX statex;
     469                 :       statex.dwLength = sizeof(statex);
     470                 :       if (GlobalMemoryStatusEx(&statex)) {
     471                 :         char buffer[128];
     472                 :         int bufferLen;
     473                 : 
     474                 : #define WRITE_STATEX_FIELD(field, paramName, conversionFunc)  \
     475                 :         WriteFile(hFile, k##paramName##Parameter,             \
     476                 :                   k##paramName##ParameterLen, &nBytes, NULL); \
     477                 :         conversionFunc(statex.field, buffer, 10);             \
     478                 :         bufferLen = strlen(buffer);                           \
     479                 :         WriteFile(hFile, buffer, bufferLen, &nBytes, NULL);   \
     480                 :         WriteFile(hFile, "\n", 1, &nBytes, NULL);
     481                 : 
     482                 :         WRITE_STATEX_FIELD(dwMemoryLoad, SysMemory, ltoa);
     483                 :         WRITE_STATEX_FIELD(ullTotalVirtual, TotalVirtualMemory, _ui64toa);
     484                 :         WRITE_STATEX_FIELD(ullAvailVirtual, AvailableVirtualMemory, _ui64toa);
     485                 :         WRITE_STATEX_FIELD(ullAvailPageFile, AvailablePageFile, _ui64toa);
     486                 :         WRITE_STATEX_FIELD(ullAvailPhys, AvailablePhysicalMemory, _ui64toa);
     487                 : 
     488                 : #undef WRITE_STATEX_FIELD
     489                 :       }
     490                 : 
     491                 :       if (oomAllocationSizeBufferLen) {
     492                 :         WriteFile(hFile, kOOMAllocationSizeParameter,
     493                 :                   kOOMAllocationSizeParameterLen, &nBytes, NULL);
     494                 :         WriteFile(hFile, oomAllocationSizeBuffer, oomAllocationSizeBufferLen,
     495                 :                   &nBytes, NULL);
     496                 :         WriteFile(hFile, "\n", 1, &nBytes, NULL);
     497                 :       }
     498                 :       CloseHandle(hFile);
     499                 :     }
     500                 :   }
     501                 : 
     502                 :   if (!doReport) {
     503                 :     return returnValue;
     504                 :   }
     505                 : 
     506                 :   STARTUPINFO si;
     507                 :   PROCESS_INFORMATION pi;
     508                 : 
     509                 :   ZeroMemory(&si, sizeof(si));
     510                 :   si.cb = sizeof(si);
     511                 :   si.dwFlags = STARTF_USESHOWWINDOW;
     512                 :   si.wShowWindow = SW_SHOWNORMAL;
     513                 :   ZeroMemory(&pi, sizeof(pi));
     514                 : 
     515                 :   if (CreateProcess(NULL, (LPWSTR)cmdLine, NULL, NULL, FALSE, 0,
     516                 :                     NULL, NULL, &si, &pi)) {
     517                 :     CloseHandle( pi.hProcess );
     518                 :     CloseHandle( pi.hThread );
     519                 :   }
     520                 :   // we're not really in a position to do anything if the CreateProcess fails
     521                 :   TerminateProcess(GetCurrentProcess(), 1);
     522                 : #elif defined(XP_UNIX)
     523               0 :   if (!crashReporterAPIData->IsEmpty()) {
     524                 :     // write out API data
     525                 :     int fd = sys_open(extraDataPath,
     526                 :                       O_WRONLY | O_CREAT | O_TRUNC,
     527               0 :                       0666);
     528                 : 
     529               0 :     if (fd != -1) {
     530                 :       // not much we can do in case of error
     531               0 :       ssize_t ignored = sys_write(fd, crashReporterAPIData->get(),
     532               0 :                                   crashReporterAPIData->Length());
     533               0 :       ignored = sys_write(fd, kCrashTimeParameter, kCrashTimeParameterLen);
     534               0 :       ignored = sys_write(fd, crashTimeString, crashTimeStringLen);
     535               0 :       ignored = sys_write(fd, "\n", 1);
     536               0 :       if (timeSinceLastCrash != 0) {
     537                 :         ignored = sys_write(fd, kTimeSinceLastCrashParameter,
     538               0 :                         kTimeSinceLastCrashParameterLen);
     539                 :         ignored = sys_write(fd, timeSinceLastCrashString,
     540               0 :                         timeSinceLastCrashStringLen);
     541               0 :         ignored = sys_write(fd, "\n", 1);
     542                 :       }
     543               0 :       if (oomAllocationSizeBufferLen) {
     544                 :         sys_write(fd, kOOMAllocationSizeParameter,
     545               0 :                   kOOMAllocationSizeParameterLen);
     546               0 :         sys_write(fd, oomAllocationSizeBuffer, oomAllocationSizeBufferLen);
     547               0 :         sys_write(fd, "\n", 1);
     548                 :       }        
     549               0 :       sys_close(fd);
     550                 :     }
     551                 :   }
     552                 : 
     553               0 :   if (!doReport) {
     554               0 :     return returnValue;
     555                 :   }
     556                 : 
     557                 : #ifdef XP_MACOSX
     558                 :   char* const my_argv[] = {
     559                 :     crashReporterPath,
     560                 :     minidumpPath,
     561                 :     NULL
     562                 :   };
     563                 : 
     564                 :   char **env = NULL;
     565                 :   char ***nsEnv = _NSGetEnviron();
     566                 :   if (nsEnv)
     567                 :     env = *nsEnv;
     568                 :   int result = posix_spawnp(NULL,
     569                 :                             my_argv[0],
     570                 :                             NULL,
     571                 :                             &spawnattr,
     572                 :                             my_argv,
     573                 :                             env);
     574                 : 
     575                 :   if (result != 0)
     576                 :     return false;
     577                 : 
     578                 : #else // !XP_MACOSX
     579               0 :   pid_t pid = sys_fork();
     580                 : 
     581               0 :   if (pid == -1)
     582               0 :     return false;
     583               0 :   else if (pid == 0) {
     584                 : #if !defined(__ANDROID__)
     585                 :     // need to clobber this, as libcurl might load NSS,
     586                 :     // and we want it to load the system NSS.
     587               0 :     unsetenv("LD_LIBRARY_PATH");
     588                 :     (void) execl(crashReporterPath,
     589               0 :                  crashReporterPath, minidumpPath, (char*)0);
     590                 : #else
     591                 :     // Invoke the reportCrash activity using am
     592                 :     (void) execlp("/system/bin/am",
     593                 :                  "/system/bin/am",
     594                 :                  "start",
     595                 :                  "-a", "org.mozilla.gecko.reportCrash",
     596                 :                  "-n", crashReporterPath,
     597                 :                  "--es", "minidumpPath", minidumpPath,
     598                 :                  (char*)0);
     599                 : #endif
     600               0 :     _exit(1);
     601                 :   }
     602                 : #endif // XP_MACOSX
     603                 : #endif // XP_UNIX
     604                 : 
     605               0 :  return returnValue;
     606                 : }
     607                 : 
     608                 : #ifdef XP_WIN
     609                 : /**
     610                 :  * Filters out floating point exceptions which are handled by nsSigHandlers.cpp
     611                 :  * and should not be handled as crashes.
     612                 :  */
     613                 : static bool FPEFilter(void* context, EXCEPTION_POINTERS* exinfo,
     614                 :                       MDRawAssertionInfo* assertion)
     615                 : {
     616                 :   if (!exinfo)
     617                 :     return true;
     618                 : 
     619                 :   PEXCEPTION_RECORD e = (PEXCEPTION_RECORD)exinfo->ExceptionRecord;
     620                 :   switch (e->ExceptionCode) {
     621                 :     case STATUS_FLOAT_DENORMAL_OPERAND:
     622                 :     case STATUS_FLOAT_DIVIDE_BY_ZERO:
     623                 :     case STATUS_FLOAT_INEXACT_RESULT:
     624                 :     case STATUS_FLOAT_INVALID_OPERATION:
     625                 :     case STATUS_FLOAT_OVERFLOW:
     626                 :     case STATUS_FLOAT_STACK_CHECK:
     627                 :     case STATUS_FLOAT_UNDERFLOW:
     628                 :     case STATUS_FLOAT_MULTIPLE_FAULTS:
     629                 :     case STATUS_FLOAT_MULTIPLE_TRAPS:
     630                 :       return false; // Don't write minidump, continue exception search
     631                 :   }
     632                 :   return true;
     633                 : }
     634                 : #endif // XP_WIN
     635                 : 
     636            1408 : static bool ShouldReport()
     637                 : {
     638                 :   // this environment variable prevents us from launching
     639                 :   // the crash reporter client
     640            1408 :   const char *envvar = PR_GetEnv("MOZ_CRASHREPORTER_NO_REPORT");
     641            1408 :   return !(envvar && *envvar);
     642                 : }
     643                 : 
     644            1408 : nsresult SetExceptionHandler(nsILocalFile* aXREDirectory,
     645                 :                              bool force/*=false*/)
     646                 : {
     647                 :   nsresult rv;
     648                 : 
     649            1408 :   if (gExceptionHandler)
     650               0 :     return NS_ERROR_ALREADY_INITIALIZED;
     651                 : 
     652            1408 :   const char *envvar = PR_GetEnv("MOZ_CRASHREPORTER_DISABLE");
     653            1408 :   if (envvar && *envvar && !force)
     654               0 :     return NS_OK;
     655                 : 
     656                 :   // this environment variable prevents us from launching
     657                 :   // the crash reporter client
     658            1408 :   doReport = ShouldReport();
     659                 : 
     660                 :   // allocate our strings
     661            1408 :   crashReporterAPIData = new nsCString();
     662            1408 :   NS_ENSURE_TRUE(crashReporterAPIData, NS_ERROR_OUT_OF_MEMORY);
     663                 : 
     664            1408 :   NS_ASSERTION(!crashReporterAPILock, "Shouldn't have a lock yet");
     665            1408 :   crashReporterAPILock = new Mutex("crashReporterAPILock");
     666            1408 :   NS_ASSERTION(!notesFieldLock, "Shouldn't have a lock yet");
     667            1408 :   notesFieldLock = new Mutex("notesFieldLock");
     668                 : 
     669                 :   crashReporterAPIData_Hash =
     670            1408 :     new nsDataHashtable<nsCStringHashKey,nsCString>();
     671            1408 :   NS_ENSURE_TRUE(crashReporterAPIData_Hash, NS_ERROR_OUT_OF_MEMORY);
     672                 : 
     673            1408 :   rv = crashReporterAPIData_Hash->Init();
     674            1408 :   NS_ENSURE_SUCCESS(rv, rv);
     675                 : 
     676            1408 :   notesField = new nsCString();
     677            1408 :   NS_ENSURE_TRUE(notesField, NS_ERROR_OUT_OF_MEMORY);
     678                 : 
     679                 :   // locate crashreporter executable
     680            2816 :   nsCOMPtr<nsIFile> exePath;
     681            1408 :   rv = aXREDirectory->Clone(getter_AddRefs(exePath));
     682            1408 :   NS_ENSURE_SUCCESS(rv, rv);
     683                 : 
     684                 : #if defined(XP_MACOSX)
     685                 :   exePath->Append(NS_LITERAL_STRING("crashreporter.app"));
     686                 :   exePath->Append(NS_LITERAL_STRING("Contents"));
     687                 :   exePath->Append(NS_LITERAL_STRING("MacOS"));
     688                 : #endif
     689                 : 
     690            1408 :   exePath->AppendNative(NS_LITERAL_CSTRING(CRASH_REPORTER_FILENAME));
     691                 : 
     692                 : #ifdef XP_WIN32
     693                 :   nsString crashReporterPath_temp;
     694                 :   exePath->GetPath(crashReporterPath_temp);
     695                 : 
     696                 :   crashReporterPath = ToNewUnicode(crashReporterPath_temp);
     697                 : #elif !defined(__ANDROID__)
     698            2816 :   nsCString crashReporterPath_temp;
     699            1408 :   exePath->GetNativePath(crashReporterPath_temp);
     700                 : 
     701            1408 :   crashReporterPath = ToNewCString(crashReporterPath_temp);
     702                 : #else
     703                 :   // On Android, we launch using the application package name
     704                 :   // instead of a filename, so use ANDROID_PACKAGE_NAME to do that here.
     705                 :   //TODO: don't hardcode org.mozilla here, so other vendors can
     706                 :   // ship XUL apps with different package names on Android?
     707                 :   nsCString package(ANDROID_PACKAGE_NAME "/.CrashReporter");
     708                 :   crashReporterPath = ToNewCString(package);
     709                 : #endif
     710                 : 
     711                 :   // get temp path to use for minidump path
     712                 : #if defined(XP_WIN32)
     713                 :   nsString tempPath;
     714                 : 
     715                 :   // first figure out buffer size
     716                 :   int pathLen = GetTempPath(0, NULL);
     717                 :   if (pathLen == 0)
     718                 :     return NS_ERROR_FAILURE;
     719                 : 
     720                 :   tempPath.SetLength(pathLen);
     721                 :   GetTempPath(pathLen, (LPWSTR)tempPath.BeginWriting());
     722                 : #elif defined(XP_MACOSX)
     723                 :   nsCString tempPath;
     724                 :   FSRef fsRef;
     725                 :   OSErr err = FSFindFolder(kUserDomain, kTemporaryFolderType,
     726                 :                            kCreateFolder, &fsRef);
     727                 :   if (err != noErr)
     728                 :     return NS_ERROR_FAILURE;
     729                 : 
     730                 :   char path[PATH_MAX];
     731                 :   OSStatus status = FSRefMakePath(&fsRef, (UInt8*)path, PATH_MAX);
     732                 :   if (status != noErr)
     733                 :     return NS_ERROR_FAILURE;
     734                 : 
     735                 :   tempPath = path;
     736                 : 
     737                 : #elif defined(__ANDROID__)
     738                 :   // GeckoAppShell sets this in the environment
     739                 :   const char *tempenv = PR_GetEnv("TMPDIR");
     740                 :   if (!tempenv)
     741                 :     return NS_ERROR_FAILURE;
     742                 :   nsCString tempPath(tempenv);
     743                 : 
     744                 : #elif defined(XP_UNIX)
     745                 :   // we assume it's always /tmp on unix systems
     746            2816 :   nsCString tempPath = NS_LITERAL_CSTRING("/tmp/");
     747                 : #else
     748                 : #error "Implement this for your platform"
     749                 : #endif
     750                 : 
     751                 : #ifdef XP_MACOSX
     752                 :   // Initialize spawn attributes, since this calls malloc.
     753                 :   if (posix_spawnattr_init(&spawnattr) != 0) {
     754                 :     return NS_ERROR_FAILURE;
     755                 :   }
     756                 : 
     757                 :   // Set spawn attributes.
     758                 :   size_t attr_count = ArrayLength(pref_cpu_types);
     759                 :   size_t attr_ocount = 0;
     760                 :   if (posix_spawnattr_setbinpref_np(&spawnattr,
     761                 :                                     attr_count,
     762                 :                                     pref_cpu_types,
     763                 :                                     &attr_ocount) != 0 ||
     764                 :       attr_ocount != attr_count) {
     765                 :     posix_spawnattr_destroy(&spawnattr);
     766                 :     return NS_ERROR_FAILURE;
     767                 :   }
     768                 : #endif
     769                 : 
     770                 : #ifdef XP_WIN32
     771                 :   MINIDUMP_TYPE minidump_type = MiniDumpNormal;
     772                 : 
     773                 :   // Try to determine what version of dbghelp.dll we're using.
     774                 :   // MinidumpWithFullMemoryInfo is only available in 6.1.x or newer.
     775                 : 
     776                 :   DWORD version_size = GetFileVersionInfoSizeW(L"dbghelp.dll", NULL);
     777                 :   if (version_size > 0) {
     778                 :     std::vector<BYTE> buffer(version_size);
     779                 :     if (GetFileVersionInfoW(L"dbghelp.dll",
     780                 :                             0,
     781                 :                             version_size,
     782                 :                             &buffer[0])) {
     783                 :       UINT len;
     784                 :       VS_FIXEDFILEINFO* file_info;
     785                 :       VerQueryValue(&buffer[0], L"\\", (void**)&file_info, &len);
     786                 :       WORD major = HIWORD(file_info->dwFileVersionMS),
     787                 :            minor = LOWORD(file_info->dwFileVersionMS),
     788                 :            revision = HIWORD(file_info->dwFileVersionLS);
     789                 :       if (major > 6 || (major == 6 && minor > 1) ||
     790                 :           (major == 6 && minor == 1 && revision >= 7600)) {
     791                 :         minidump_type = MiniDumpWithFullMemoryInfo;
     792                 :       }
     793                 :     }
     794                 :   }
     795                 : #endif // XP_WIN32
     796                 : 
     797                 :   // now set the exception handler
     798                 :   gExceptionHandler = new google_breakpad::
     799                 :     ExceptionHandler(tempPath.get(),
     800                 : #ifdef XP_WIN
     801                 :                      FPEFilter,
     802                 : #else
     803                 :                      nsnull,
     804                 : #endif
     805                 :                      MinidumpCallback,
     806                 :                      nsnull,
     807                 : #if defined(XP_WIN32)
     808                 :                      google_breakpad::ExceptionHandler::HANDLER_ALL,
     809                 :                      minidump_type,
     810                 :                      NULL,
     811                 :                      NULL);
     812                 : #else
     813                 :                      true
     814                 : #if defined(XP_MACOSX)
     815                 :                        , NULL
     816                 : #endif
     817            2816 :                       );
     818                 : #endif // XP_WIN32
     819                 : 
     820            1408 :   if (!gExceptionHandler)
     821               0 :     return NS_ERROR_OUT_OF_MEMORY;
     822                 : 
     823                 : #ifdef XP_WIN
     824                 :   gExceptionHandler->set_handle_debug_exceptions(true);
     825                 : #endif
     826                 : 
     827                 :   // store application start time
     828                 :   char timeString[32];
     829            1408 :   time_t startupTime = time(NULL);
     830            1408 :   XP_TTOA(startupTime, timeString, 10);
     831            1408 :   AnnotateCrashReport(NS_LITERAL_CSTRING("StartupTime"),
     832            2816 :                       nsDependentCString(timeString));
     833                 : 
     834                 : #if defined(XP_MACOSX)
     835                 :   // On OS X, many testers like to see the OS crash reporting dialog
     836                 :   // since it offers immediate stack traces.  We allow them to set
     837                 :   // a default to pass exceptions to the OS handler.
     838                 :   Boolean keyExistsAndHasValidFormat = false;
     839                 :   Boolean prefValue = ::CFPreferencesGetAppBooleanValue(CFSTR("OSCrashReporter"),
     840                 :                                                         kCFPreferencesCurrentApplication,
     841                 :                                                         &keyExistsAndHasValidFormat);
     842                 :   if (keyExistsAndHasValidFormat)
     843                 :     showOSCrashReporter = prefValue;
     844                 : #endif
     845                 : 
     846                 : #if defined(__ANDROID__)
     847                 :   for (unsigned int i = 0; i < library_mappings.size(); i++) {
     848                 :     u_int8_t guid[sizeof(MDGUID)];
     849                 :     FileIDToGUID(library_mappings[i].debug_id.c_str(), guid);
     850                 :     gExceptionHandler->AddMappingInfo(library_mappings[i].name,
     851                 :                                       guid,
     852                 :                                       library_mappings[i].start_address,
     853                 :                                       library_mappings[i].length,
     854                 :                                       library_mappings[i].file_offset);
     855                 :   }
     856                 : #endif
     857                 : 
     858            1408 :   mozalloc_set_oom_abort_handler(AnnotateOOMAllocationSize);
     859                 : 
     860            1408 :   return NS_OK;
     861                 : }
     862                 : 
     863            8569 : bool GetEnabled()
     864                 : {
     865            8569 :   return gExceptionHandler != nsnull;
     866                 : }
     867                 : 
     868               0 : bool GetMinidumpPath(nsAString& aPath)
     869                 : {
     870               0 :   if (!gExceptionHandler)
     871               0 :     return false;
     872                 : 
     873               0 :   aPath = CONVERT_XP_CHAR_TO_UTF16(gExceptionHandler->dump_path().c_str());
     874               0 :   return true;
     875                 : }
     876                 : 
     877            1386 : nsresult SetMinidumpPath(const nsAString& aPath)
     878                 : {
     879            1386 :   if (!gExceptionHandler)
     880               0 :     return NS_ERROR_NOT_INITIALIZED;
     881                 : 
     882            1386 :   gExceptionHandler->set_dump_path(CONVERT_UTF16_TO_XP_CHAR(aPath).BeginReading());
     883                 : 
     884            1386 :   return NS_OK;
     885                 : }
     886                 : 
     887                 : static nsresult
     888               1 : WriteDataToFile(nsIFile* aFile, const nsACString& data)
     889                 : {
     890               2 :   nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(aFile);
     891               1 :   NS_ENSURE_TRUE(localFile, NS_ERROR_FAILURE);
     892                 : 
     893                 :   PRFileDesc* fd;
     894               1 :   nsresult rv = localFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE, 00600,
     895               1 :                                             &fd);
     896               1 :   NS_ENSURE_SUCCESS(rv, rv);
     897                 : 
     898               1 :   rv = NS_OK;
     899               1 :   if (PR_Write(fd, data.Data(), data.Length()) == -1) {
     900               0 :     rv = NS_ERROR_FAILURE;
     901                 :   }
     902               1 :   PR_Close(fd);
     903               1 :   return rv;
     904                 : }
     905                 : 
     906                 : static nsresult
     907              43 : GetFileContents(nsIFile* aFile, nsACString& data)
     908                 : {
     909              86 :   nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(aFile);
     910              43 :   NS_ENSURE_TRUE(localFile, NS_ERROR_FAILURE);
     911                 : 
     912                 :   PRFileDesc* fd;
     913              43 :   nsresult rv = localFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fd);
     914              43 :   NS_ENSURE_SUCCESS(rv, rv);
     915                 : 
     916              43 :   rv = NS_OK;
     917              43 :   PRInt32 filesize = PR_Available(fd);
     918              43 :   if (filesize <= 0) {
     919               0 :     rv = NS_ERROR_FILE_NOT_FOUND;
     920                 :   }
     921                 :   else {
     922              43 :     data.SetLength(filesize);
     923              43 :     if (PR_Read(fd, data.BeginWriting(), filesize) == -1) {
     924               0 :       rv = NS_ERROR_FAILURE;
     925                 :     }
     926                 :   }
     927              43 :   PR_Close(fd);
     928              43 :   return rv;
     929                 : }
     930                 : 
     931                 : // Function typedef for initializing a piece of data that we
     932                 : // don't already have.
     933                 : typedef nsresult (*InitDataFunc)(nsACString&);
     934                 : 
     935                 : // Attempt to read aFile's contents into aContents, if aFile
     936                 : // does not exist, create it and initialize its contents
     937                 : // by calling aInitFunc for the data.
     938                 : static nsresult
     939              44 : GetOrInit(nsIFile* aDir, const nsACString& filename,
     940                 :           nsACString& aContents, InitDataFunc aInitFunc)
     941                 : {
     942                 :   bool exists;
     943                 : 
     944              88 :   nsCOMPtr<nsIFile> dataFile;
     945              44 :   nsresult rv = aDir->Clone(getter_AddRefs(dataFile));
     946              44 :   NS_ENSURE_SUCCESS(rv, rv);
     947                 : 
     948              44 :   rv = dataFile->AppendNative(filename);
     949              44 :   NS_ENSURE_SUCCESS(rv, rv);
     950                 : 
     951              44 :   rv = dataFile->Exists(&exists);
     952              44 :   NS_ENSURE_SUCCESS(rv, rv);
     953                 : 
     954              44 :   if (!exists) {
     955               1 :     if (aInitFunc) {
     956                 :       // get the initial value and write it to the file
     957               1 :       rv = aInitFunc(aContents);
     958               1 :       NS_ENSURE_SUCCESS(rv, rv);
     959               1 :       rv = WriteDataToFile(dataFile, aContents);
     960                 :     }
     961                 :     else {
     962                 :       // didn't pass in an init func
     963               0 :       rv = NS_ERROR_FAILURE;
     964                 :     }
     965                 :   }
     966                 :   else {
     967                 :     // just get the file's contents
     968              43 :     rv = GetFileContents(dataFile, aContents);
     969                 :   }
     970                 : 
     971              44 :   return rv;
     972                 : }
     973                 : 
     974                 : // Init the "install time" data.  We're taking an easy way out here
     975                 : // and just setting this to "the time when this version was first run".
     976                 : static nsresult
     977               1 : InitInstallTime(nsACString& aInstallTime)
     978                 : {
     979               1 :   time_t t = time(NULL);
     980                 :   char buf[16];
     981               1 :   sprintf(buf, "%ld", t);
     982               1 :   aInstallTime = buf;
     983                 : 
     984               1 :   return NS_OK;
     985                 : }
     986                 : 
     987                 : // Annotate the crash report with a Unique User ID and time
     988                 : // since install.  Also do some prep work for recording
     989                 : // time since last crash, which must be calculated at
     990                 : // crash time.
     991                 : // If any piece of data doesn't exist, initialize it first.
     992              22 : nsresult SetupExtraData(nsILocalFile* aAppDataDirectory,
     993                 :                         const nsACString& aBuildID)
     994                 : {
     995              44 :   nsCOMPtr<nsIFile> dataDirectory;
     996              22 :   nsresult rv = aAppDataDirectory->Clone(getter_AddRefs(dataDirectory));
     997              22 :   NS_ENSURE_SUCCESS(rv, rv);
     998                 : 
     999              22 :   rv = dataDirectory->AppendNative(NS_LITERAL_CSTRING("Crash Reports"));
    1000              22 :   NS_ENSURE_SUCCESS(rv, rv);
    1001                 : 
    1002                 :   bool exists;
    1003              22 :   rv = dataDirectory->Exists(&exists);
    1004              22 :   NS_ENSURE_SUCCESS(rv, rv);
    1005                 : 
    1006              22 :   if (!exists) {
    1007               0 :     rv = dataDirectory->Create(nsIFile::DIRECTORY_TYPE, 0700);
    1008               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1009                 :   }
    1010                 : 
    1011                 : #if defined(XP_WIN32)
    1012                 :   nsAutoString dataDirEnv(NS_LITERAL_STRING("MOZ_CRASHREPORTER_DATA_DIRECTORY="));
    1013                 : 
    1014                 :   nsAutoString dataDirectoryPath;
    1015                 :   rv = dataDirectory->GetPath(dataDirectoryPath);
    1016                 :   NS_ENSURE_SUCCESS(rv, rv);
    1017                 : 
    1018                 :   dataDirEnv.Append(dataDirectoryPath);
    1019                 : 
    1020                 :   _wputenv(dataDirEnv.get());
    1021                 : #else
    1022                 :   // Save this path in the environment for the crash reporter application.
    1023              44 :   nsCAutoString dataDirEnv("MOZ_CRASHREPORTER_DATA_DIRECTORY=");
    1024                 : 
    1025              44 :   nsCAutoString dataDirectoryPath;
    1026              22 :   rv = dataDirectory->GetNativePath(dataDirectoryPath);
    1027              22 :   NS_ENSURE_SUCCESS(rv, rv);
    1028                 : 
    1029              22 :   dataDirEnv.Append(dataDirectoryPath);
    1030                 : 
    1031              22 :   char* env = ToNewCString(dataDirEnv);
    1032              22 :   NS_ENSURE_TRUE(env, NS_ERROR_OUT_OF_MEMORY);
    1033                 : 
    1034              22 :   PR_SetEnv(env);
    1035                 : #endif
    1036                 : 
    1037              44 :   nsCAutoString data;
    1038              22 :   if(NS_SUCCEEDED(GetOrInit(dataDirectory,
    1039                 :                             NS_LITERAL_CSTRING("InstallTime") + aBuildID,
    1040                 :                             data, InitInstallTime)))
    1041              22 :     AnnotateCrashReport(NS_LITERAL_CSTRING("InstallTime"), data);
    1042                 : 
    1043                 :   // this is a little different, since we can't init it with anything,
    1044                 :   // since it's stored at crash time, and we can't annotate the
    1045                 :   // crash report with the stored value, since we really want
    1046                 :   // (now - LastCrash), so we just get a value if it exists,
    1047                 :   // and store it in a time_t value.
    1048              22 :   if(NS_SUCCEEDED(GetOrInit(dataDirectory, NS_LITERAL_CSTRING("LastCrash"),
    1049                 :                             data, NULL))) {
    1050              22 :     lastCrashTime = (time_t)atol(data.get());
    1051                 :   }
    1052                 : 
    1053                 :   // not really the best place to init this, but I have the path I need here
    1054              44 :   nsCOMPtr<nsIFile> lastCrashFile;
    1055              22 :   rv = dataDirectory->Clone(getter_AddRefs(lastCrashFile));
    1056              22 :   NS_ENSURE_SUCCESS(rv, rv);
    1057                 : 
    1058              22 :   rv = lastCrashFile->AppendNative(NS_LITERAL_CSTRING("LastCrash"));
    1059              22 :   NS_ENSURE_SUCCESS(rv, rv);
    1060              22 :   memset(lastCrashTimeFilename, 0, sizeof(lastCrashTimeFilename));
    1061                 : 
    1062                 : #if defined(XP_WIN32)
    1063                 :   nsAutoString filename;
    1064                 :   rv = lastCrashFile->GetPath(filename);
    1065                 :   NS_ENSURE_SUCCESS(rv, rv);
    1066                 : 
    1067                 :   if (filename.Length() < XP_PATH_MAX)
    1068                 :     wcsncpy(lastCrashTimeFilename, filename.get(), filename.Length());
    1069                 : #else
    1070              44 :   nsCAutoString filename;
    1071              22 :   rv = lastCrashFile->GetNativePath(filename);
    1072              22 :   NS_ENSURE_SUCCESS(rv, rv);
    1073                 : 
    1074              22 :   if (filename.Length() < XP_PATH_MAX)
    1075              22 :     strncpy(lastCrashTimeFilename, filename.get(), filename.Length());
    1076                 : #endif
    1077                 : 
    1078              22 :   return NS_OK;
    1079                 : }
    1080                 : 
    1081                 : static void OOPDeinit();
    1082                 : 
    1083            1386 : nsresult UnsetExceptionHandler()
    1084                 : {
    1085            1386 :   delete gExceptionHandler;
    1086                 : 
    1087                 :   // do this here in the unlikely case that we succeeded in allocating
    1088                 :   // our strings but failed to allocate gExceptionHandler.
    1089            1386 :   delete crashReporterAPIData_Hash;
    1090            1386 :   crashReporterAPIData_Hash = nsnull;
    1091                 : 
    1092            1386 :   delete crashReporterAPILock;
    1093            1386 :   crashReporterAPILock = nsnull;
    1094                 : 
    1095            1386 :   delete notesFieldLock;
    1096            1386 :   notesFieldLock = nsnull;
    1097                 : 
    1098            1386 :   delete crashReporterAPIData;
    1099            1386 :   crashReporterAPIData = nsnull;
    1100                 : 
    1101            1386 :   delete notesField;
    1102            1386 :   notesField = nsnull;
    1103                 : 
    1104            1386 :   if (crashReporterPath) {
    1105            1386 :     NS_Free(crashReporterPath);
    1106            1386 :     crashReporterPath = nsnull;
    1107                 :   }
    1108                 : 
    1109                 : #ifdef XP_MACOSX
    1110                 :   posix_spawnattr_destroy(&spawnattr);
    1111                 : #endif
    1112                 : 
    1113            1386 :   if (!gExceptionHandler)
    1114               0 :     return NS_ERROR_NOT_INITIALIZED;
    1115                 : 
    1116            1386 :   gExceptionHandler = nsnull;
    1117                 : 
    1118            1386 :   OOPDeinit();
    1119                 : 
    1120            1386 :   return NS_OK;
    1121                 : }
    1122                 : 
    1123            3168 : static void ReplaceChar(nsCString& str, const nsACString& character,
    1124                 :                         const nsACString& replacement)
    1125                 : {
    1126            3168 :   nsCString::const_iterator start, end;
    1127                 : 
    1128            3168 :   str.BeginReading(start);
    1129            3168 :   str.EndReading(end);
    1130                 : 
    1131            6336 :   while (FindInReadable(character, start, end)) {
    1132               0 :     PRInt32 pos = end.size_backward();
    1133               0 :     str.Replace(pos - 1, 1, replacement);
    1134                 : 
    1135               0 :     str.BeginReading(start);
    1136               0 :     start.advance(pos + replacement.Length() - 1);
    1137               0 :     str.EndReading(end);
    1138                 :   }
    1139            3168 : }
    1140                 : 
    1141            4752 : static bool DoFindInReadable(const nsACString& str, const nsACString& value)
    1142                 : {
    1143            4752 :   nsACString::const_iterator start, end;
    1144            4752 :   str.BeginReading(start);
    1145            4752 :   str.EndReading(end);
    1146                 : 
    1147            4752 :   return FindInReadable(value, start, end);
    1148                 : }
    1149                 : 
    1150            2376 : static PLDHashOperator EnumerateEntries(const nsACString& key,
    1151                 :                                         nsCString entry,
    1152                 :                                         void* userData)
    1153                 : {
    1154            4752 :   crashReporterAPIData->Append(key + NS_LITERAL_CSTRING("=") + entry +
    1155            7128 :                                NS_LITERAL_CSTRING("\n"));
    1156            2376 :   return PL_DHASH_NEXT;
    1157                 : }
    1158                 : 
    1159                 : // This function is miscompiled with MSVC 2005/2008 when PGO is on.
    1160                 : #ifdef _MSC_VER
    1161                 : #pragma optimize("", off)
    1162                 : #endif
    1163                 : static nsresult
    1164            1584 : EscapeAnnotation(const nsACString& key, const nsACString& data, nsCString& escapedData)
    1165                 : {
    1166            6336 :   if (DoFindInReadable(key, NS_LITERAL_CSTRING("=")) ||
    1167            4752 :       DoFindInReadable(key, NS_LITERAL_CSTRING("\n")))
    1168               0 :     return NS_ERROR_INVALID_ARG;
    1169                 : 
    1170            1584 :   if (DoFindInReadable(data, NS_LITERAL_CSTRING("\0")))
    1171               0 :     return NS_ERROR_INVALID_ARG;
    1172                 : 
    1173            1584 :   escapedData = data;
    1174                 : 
    1175                 :   // escape backslashes
    1176            1584 :   ReplaceChar(escapedData, NS_LITERAL_CSTRING("\\"),
    1177            3168 :               NS_LITERAL_CSTRING("\\\\"));
    1178                 :   // escape newlines
    1179            1584 :   ReplaceChar(escapedData, NS_LITERAL_CSTRING("\n"),
    1180            3168 :               NS_LITERAL_CSTRING("\\n"));
    1181            1584 :   return NS_OK;
    1182                 : }
    1183                 : #ifdef _MSC_VER
    1184                 : #pragma optimize("", on)
    1185                 : #endif
    1186                 : 
    1187                 : class DelayedNote
    1188               0 : {
    1189                 :  public:
    1190               0 :   DelayedNote(const nsACString& aKey, const nsACString& aData)
    1191               0 :   : mKey(aKey), mData(aData), mType(Annotation) {}
    1192                 : 
    1193               0 :   DelayedNote(const nsACString& aData)
    1194               0 :   : mData(aData), mType(AppNote) {}
    1195                 : 
    1196               0 :   void Run()
    1197                 :   {
    1198               0 :     if (mType == Annotation) {
    1199               0 :       AnnotateCrashReport(mKey, mData);
    1200                 :     } else {
    1201               0 :       AppendAppNotesToCrashReport(mData);
    1202                 :     }
    1203               0 :   }
    1204                 :   
    1205                 :  private:
    1206                 :   nsCString mKey;
    1207                 :   nsCString mData;
    1208                 :   enum AnnotationType { Annotation, AppNote } mType;
    1209                 : };
    1210                 : 
    1211                 : static void
    1212               0 : EnqueueDelayedNote(DelayedNote* aNote)
    1213                 : {
    1214               0 :   if (!gDelayedAnnotations) {
    1215               0 :     gDelayedAnnotations = new nsTArray<nsAutoPtr<DelayedNote> >();
    1216                 :   }
    1217               0 :   gDelayedAnnotations->AppendElement(aNote);
    1218               0 : }
    1219                 : 
    1220            1584 : nsresult AnnotateCrashReport(const nsACString& key, const nsACString& data)
    1221                 : {
    1222            1584 :   if (!GetEnabled())
    1223               0 :     return NS_ERROR_NOT_INITIALIZED;
    1224                 : 
    1225            3168 :   nsCString escapedData;
    1226            1584 :   nsresult rv = EscapeAnnotation(key, data, escapedData);
    1227            1584 :   if (NS_FAILED(rv))
    1228               0 :     return rv;
    1229                 : 
    1230            1584 :   if (XRE_GetProcessType() != GeckoProcessType_Default) {
    1231               0 :     if (!NS_IsMainThread()) {
    1232               0 :       NS_ERROR("Cannot call AnnotateCrashReport in child processes from non-main thread.");
    1233               0 :       return NS_ERROR_FAILURE;
    1234                 :     }
    1235               0 :     PCrashReporterChild* reporter = CrashReporterChild::GetCrashReporter();
    1236               0 :     if (!reporter) {
    1237               0 :       EnqueueDelayedNote(new DelayedNote(key, data));
    1238               0 :       return NS_OK;
    1239                 :     }
    1240               0 :     if (!reporter->SendAnnotateCrashReport(nsCString(key), escapedData))
    1241               0 :       return NS_ERROR_FAILURE;
    1242               0 :     return NS_OK;
    1243                 :   }
    1244                 : 
    1245            3168 :   MutexAutoLock lock(*crashReporterAPILock);
    1246                 : 
    1247            1584 :   rv = crashReporterAPIData_Hash->Put(key, escapedData);
    1248            1584 :   NS_ENSURE_SUCCESS(rv, rv);
    1249                 : 
    1250                 :   // now rebuild the file contents
    1251            1584 :   crashReporterAPIData->Truncate(0);
    1252                 :   crashReporterAPIData_Hash->EnumerateRead(EnumerateEntries,
    1253            1584 :                                            crashReporterAPIData);
    1254                 : 
    1255            1584 :   return NS_OK;
    1256                 : }
    1257                 : 
    1258               0 : nsresult AppendAppNotesToCrashReport(const nsACString& data)
    1259                 : {
    1260               0 :   if (!GetEnabled())
    1261               0 :     return NS_ERROR_NOT_INITIALIZED;
    1262                 : 
    1263               0 :   if (DoFindInReadable(data, NS_LITERAL_CSTRING("\0")))
    1264               0 :     return NS_ERROR_INVALID_ARG;
    1265                 : 
    1266               0 :   if (XRE_GetProcessType() != GeckoProcessType_Default) {
    1267               0 :     if (!NS_IsMainThread()) {
    1268               0 :       NS_ERROR("Cannot call AnnotateCrashReport in child processes from non-main thread.");
    1269               0 :       return NS_ERROR_FAILURE;
    1270                 :     }
    1271               0 :     PCrashReporterChild* reporter = CrashReporterChild::GetCrashReporter();
    1272               0 :     if (!reporter) {
    1273               0 :       EnqueueDelayedNote(new DelayedNote(data));
    1274               0 :       return NS_OK;
    1275                 :     }
    1276                 : 
    1277                 :     // Since we don't go through AnnotateCrashReport in the parent process,
    1278                 :     // we must ensure that the data is escaped and valid before the parent
    1279                 :     // sees it.
    1280               0 :     nsCString escapedData;
    1281               0 :     nsresult rv = EscapeAnnotation(NS_LITERAL_CSTRING("Notes"), data, escapedData);
    1282               0 :     if (NS_FAILED(rv))
    1283               0 :       return rv;
    1284                 : 
    1285               0 :     if (!reporter->SendAppendAppNotes(escapedData))
    1286               0 :       return NS_ERROR_FAILURE;
    1287               0 :     return NS_OK;
    1288                 :   }
    1289                 : 
    1290               0 :   MutexAutoLock lock(*notesFieldLock);
    1291                 : 
    1292               0 :   notesField->Append(data);
    1293               0 :   return AnnotateCrashReport(NS_LITERAL_CSTRING("Notes"), *notesField);
    1294                 : }
    1295                 : 
    1296                 : // Returns true if found, false if not found.
    1297               0 : bool GetAnnotation(const nsACString& key, nsACString& data)
    1298                 : {
    1299               0 :   if (!gExceptionHandler)
    1300               0 :     return false;
    1301                 : 
    1302               0 :   nsCAutoString entry;
    1303               0 :   if (!crashReporterAPIData_Hash->Get(key, &entry))
    1304               0 :     return false;
    1305                 : 
    1306               0 :   data = entry;
    1307               0 :   return true;
    1308                 : }
    1309                 : 
    1310            4212 : nsresult RegisterAppMemory(void* ptr, size_t length)
    1311                 : {
    1312            4212 :   if (!GetEnabled())
    1313            4212 :     return NS_ERROR_NOT_INITIALIZED;
    1314                 : 
    1315                 : #if defined(XP_LINUX) || defined(XP_WIN32)
    1316               0 :   gExceptionHandler->RegisterAppMemory(ptr, length);
    1317               0 :   return NS_OK;
    1318                 : #else
    1319                 :   return NS_ERROR_NOT_IMPLEMENTED;
    1320                 : #endif
    1321                 : }
    1322                 : 
    1323               0 : nsresult UnregisterAppMemory(void* ptr)
    1324                 : {
    1325               0 :   if (!GetEnabled())
    1326               0 :     return NS_ERROR_NOT_INITIALIZED;
    1327                 : 
    1328                 : #if defined(XP_LINUX) || defined(XP_WIN32)
    1329               0 :   gExceptionHandler->UnregisterAppMemory(ptr);
    1330               0 :   return NS_OK;
    1331                 : #else
    1332                 :   return NS_ERROR_NOT_IMPLEMENTED;
    1333                 : #endif
    1334                 : }
    1335                 : 
    1336               0 : bool GetServerURL(nsACString& aServerURL)
    1337                 : {
    1338               0 :   if (!gExceptionHandler)
    1339               0 :     return false;
    1340                 : 
    1341               0 :   return GetAnnotation(NS_LITERAL_CSTRING("ServerURL"), aServerURL);
    1342                 : }
    1343                 : 
    1344              22 : nsresult SetServerURL(const nsACString& aServerURL)
    1345                 : {
    1346                 :   // store server URL with the API data
    1347                 :   // the client knows to handle this specially
    1348              22 :   return AnnotateCrashReport(NS_LITERAL_CSTRING("ServerURL"),
    1349              22 :                              aServerURL);
    1350                 : }
    1351                 : 
    1352                 : nsresult
    1353              22 : SetRestartArgs(int argc, char** argv)
    1354                 : {
    1355              22 :   if (!gExceptionHandler)
    1356               0 :     return NS_OK;
    1357                 : 
    1358                 :   int i;
    1359              44 :   nsCAutoString envVar;
    1360                 :   char *env;
    1361             134 :   for (i = 0; i < argc; i++) {
    1362             112 :     envVar = "MOZ_CRASHREPORTER_RESTART_ARG_";
    1363             112 :     envVar.AppendInt(i);
    1364             112 :     envVar += "=";
    1365                 : #if defined(XP_UNIX) && !defined(XP_MACOSX)
    1366                 :     // we'd like to run the script around the binary
    1367                 :     // instead of the binary itself, so remove the -bin
    1368                 :     // if it exists on the first argument
    1369             112 :     int arg_len = 0;
    1370             156 :     if (i == 0 &&
    1371              22 :         (arg_len = strlen(argv[i])) > 4 &&
    1372              22 :         strcmp(argv[i] + arg_len - 4, "-bin") == 0) {
    1373              22 :       envVar.Append(argv[i], arg_len - 4);
    1374                 :     } else
    1375                 : #endif
    1376                 :     {
    1377              90 :       envVar += argv[i];
    1378                 :     }
    1379                 : 
    1380                 :     // PR_SetEnv() wants the string to be available for the lifetime
    1381                 :     // of the app, so dup it here
    1382             112 :     env = ToNewCString(envVar);
    1383             112 :     if (!env)
    1384               0 :       return NS_ERROR_OUT_OF_MEMORY;
    1385                 : 
    1386             112 :     PR_SetEnv(env);
    1387                 :   }
    1388                 : 
    1389                 :   // make sure the arg list is terminated
    1390              22 :   envVar = "MOZ_CRASHREPORTER_RESTART_ARG_";
    1391              22 :   envVar.AppendInt(i);
    1392              22 :   envVar += "=";
    1393                 : 
    1394                 :   // PR_SetEnv() wants the string to be available for the lifetime
    1395                 :   // of the app, so dup it here
    1396              22 :   env = ToNewCString(envVar);
    1397              22 :   if (!env)
    1398               0 :     return NS_ERROR_OUT_OF_MEMORY;
    1399                 : 
    1400              22 :   PR_SetEnv(env);
    1401                 : 
    1402                 :   // make sure we save the info in XUL_APP_FILE for the reporter
    1403              22 :   const char *appfile = PR_GetEnv("XUL_APP_FILE");
    1404              22 :   if (appfile && *appfile) {
    1405               0 :     envVar = "MOZ_CRASHREPORTER_RESTART_XUL_APP_FILE=";
    1406               0 :     envVar += appfile;
    1407               0 :     env = ToNewCString(envVar);
    1408               0 :     PR_SetEnv(env);
    1409                 :   }
    1410                 : 
    1411              22 :   return NS_OK;
    1412                 : }
    1413                 : 
    1414                 : #ifdef XP_WIN32
    1415                 : nsresult WriteMinidumpForException(EXCEPTION_POINTERS* aExceptionInfo)
    1416                 : {
    1417                 :   if (!gExceptionHandler)
    1418                 :     return NS_ERROR_NOT_INITIALIZED;
    1419                 : 
    1420                 :   return gExceptionHandler->WriteMinidumpForException(aExceptionInfo) ? NS_OK : NS_ERROR_FAILURE;
    1421                 : }
    1422                 : #endif
    1423                 : 
    1424                 : #ifdef XP_MACOSX
    1425                 : nsresult AppendObjCExceptionInfoToAppNotes(void *inException)
    1426                 : {
    1427                 :   nsCAutoString excString;
    1428                 :   GetObjCExceptionInfo(inException, excString);
    1429                 :   AppendAppNotesToCrashReport(excString);
    1430                 :   return NS_OK;
    1431                 : }
    1432                 : #endif
    1433                 : 
    1434                 : /*
    1435                 :  * Combined code to get/set the crash reporter submission pref on
    1436                 :  * different platforms.
    1437                 :  */
    1438               0 : static nsresult PrefSubmitReports(bool* aSubmitReports, bool writePref)
    1439                 : {
    1440                 :   nsresult rv;
    1441                 : #if defined(XP_WIN32)
    1442                 :   /*
    1443                 :    * NOTE! This needs to stay in sync with the preference checking code
    1444                 :    *       in toolkit/crashreporter/client/crashreporter_win.cpp
    1445                 :    */
    1446                 :   nsCOMPtr<nsIXULAppInfo> appinfo =
    1447                 :     do_GetService("@mozilla.org/xre/app-info;1", &rv);
    1448                 :   NS_ENSURE_SUCCESS(rv, rv);
    1449                 : 
    1450                 :   nsCAutoString appVendor, appName;
    1451                 :   rv = appinfo->GetVendor(appVendor);
    1452                 :   NS_ENSURE_SUCCESS(rv, rv);
    1453                 :   rv = appinfo->GetName(appName);
    1454                 :   NS_ENSURE_SUCCESS(rv, rv);
    1455                 : 
    1456                 :   nsCOMPtr<nsIWindowsRegKey> regKey
    1457                 :     (do_CreateInstance("@mozilla.org/windows-registry-key;1", &rv));
    1458                 :   NS_ENSURE_SUCCESS(rv, rv);
    1459                 : 
    1460                 :   nsCAutoString regPath;
    1461                 : 
    1462                 :   regPath.AppendLiteral("Software\\");
    1463                 :   if(!appVendor.IsEmpty()) {
    1464                 :     regPath.Append(appVendor);
    1465                 :     regPath.AppendLiteral("\\");
    1466                 :   }
    1467                 :   regPath.Append(appName);
    1468                 :   regPath.AppendLiteral("\\Crash Reporter");
    1469                 : 
    1470                 :   // If we're saving the pref value, just write it to ROOT_KEY_CURRENT_USER
    1471                 :   // and we're done.
    1472                 :   if (writePref) {
    1473                 :     rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
    1474                 :                       NS_ConvertUTF8toUTF16(regPath),
    1475                 :                       nsIWindowsRegKey::ACCESS_SET_VALUE);
    1476                 :     NS_ENSURE_SUCCESS(rv, rv);
    1477                 : 
    1478                 :     PRUint32 value = *aSubmitReports ? 1 : 0;
    1479                 :     rv = regKey->WriteIntValue(NS_LITERAL_STRING("SubmitCrashReport"), value);
    1480                 :     regKey->Close();
    1481                 :     return rv;
    1482                 :   }
    1483                 : 
    1484                 :   // We're reading the pref value, so we need to first look under
    1485                 :   // ROOT_KEY_LOCAL_MACHINE to see if it's set there, and then fall back to
    1486                 :   // ROOT_KEY_CURRENT_USER. If it's not set in either place, the pref defaults
    1487                 :   // to "true".
    1488                 :   PRUint32 value;
    1489                 :   rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_LOCAL_MACHINE,
    1490                 :                     NS_ConvertUTF8toUTF16(regPath),
    1491                 :                     nsIWindowsRegKey::ACCESS_QUERY_VALUE);
    1492                 :   if (NS_SUCCEEDED(rv)) {
    1493                 :     rv = regKey->ReadIntValue(NS_LITERAL_STRING("SubmitCrashReport"), &value);
    1494                 :     regKey->Close();
    1495                 :     if (NS_SUCCEEDED(rv)) {
    1496                 :       *aSubmitReports = !!value;
    1497                 :       return NS_OK;
    1498                 :     }
    1499                 :   }
    1500                 : 
    1501                 :   rv = regKey->Open(nsIWindowsRegKey::ROOT_KEY_CURRENT_USER,
    1502                 :                     NS_ConvertUTF8toUTF16(regPath),
    1503                 :                     nsIWindowsRegKey::ACCESS_QUERY_VALUE);
    1504                 :   if (NS_FAILED(rv)) {
    1505                 :     *aSubmitReports = true;
    1506                 :     return NS_OK;
    1507                 :   }
    1508                 :   
    1509                 :   rv = regKey->ReadIntValue(NS_LITERAL_STRING("SubmitCrashReport"), &value);
    1510                 :   // default to true on failure
    1511                 :   if (NS_FAILED(rv)) {
    1512                 :     value = 1;
    1513                 :     rv = NS_OK;
    1514                 :   }
    1515                 :   regKey->Close();
    1516                 : 
    1517                 :   *aSubmitReports = !!value;
    1518                 :   return NS_OK;
    1519                 : #elif defined(XP_MACOSX)
    1520                 :   rv = NS_OK;
    1521                 :   if (writePref) {
    1522                 :     CFPropertyListRef cfValue = (CFPropertyListRef)(*aSubmitReports ? kCFBooleanTrue : kCFBooleanFalse);
    1523                 :     ::CFPreferencesSetAppValue(CFSTR("submitReport"),
    1524                 :                                cfValue,
    1525                 :                                reporterClientAppID);
    1526                 :     if (!::CFPreferencesAppSynchronize(reporterClientAppID))
    1527                 :       rv = NS_ERROR_FAILURE;
    1528                 :   }
    1529                 :   else {
    1530                 :     *aSubmitReports = true;
    1531                 :     Boolean keyExistsAndHasValidFormat = false;
    1532                 :     Boolean prefValue = ::CFPreferencesGetAppBooleanValue(CFSTR("submitReport"),
    1533                 :                                                           reporterClientAppID,
    1534                 :                                                           &keyExistsAndHasValidFormat);
    1535                 :     if (keyExistsAndHasValidFormat)
    1536                 :       *aSubmitReports = !!prefValue;
    1537                 :   }
    1538                 :   return rv;
    1539                 : #elif defined(XP_UNIX)
    1540                 :   /*
    1541                 :    * NOTE! This needs to stay in sync with the preference checking code
    1542                 :    *       in toolkit/crashreporter/client/crashreporter_linux.cpp
    1543                 :    */
    1544               0 :   nsCOMPtr<nsIFile> reporterINI;
    1545               0 :   rv = NS_GetSpecialDirectory("UAppData", getter_AddRefs(reporterINI));
    1546               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1547               0 :   reporterINI->AppendNative(NS_LITERAL_CSTRING("Crash Reports"));
    1548               0 :   reporterINI->AppendNative(NS_LITERAL_CSTRING("crashreporter.ini"));
    1549                 : 
    1550                 :   bool exists;
    1551               0 :   rv = reporterINI->Exists(&exists);
    1552               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1553               0 :   if (!exists) {
    1554               0 :     if (!writePref) {
    1555                 :         // If reading the pref, default to true if .ini doesn't exist.
    1556               0 :         *aSubmitReports = true;
    1557               0 :         return NS_OK;
    1558                 :     }
    1559                 :     // Create the file so the INI processor can write to it.
    1560               0 :     rv = reporterINI->Create(nsIFile::NORMAL_FILE_TYPE, 0600);
    1561               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1562                 :   }
    1563                 : 
    1564                 :   nsCOMPtr<nsIINIParserFactory> iniFactory =
    1565               0 :     do_GetService("@mozilla.org/xpcom/ini-processor-factory;1", &rv);
    1566               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1567                 : 
    1568               0 :   nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(reporterINI);
    1569               0 :   NS_ENSURE_TRUE(localFile, NS_ERROR_FAILURE);
    1570               0 :   nsCOMPtr<nsIINIParser> iniParser;
    1571               0 :   rv = iniFactory->CreateINIParser(localFile,
    1572               0 :                                    getter_AddRefs(iniParser));
    1573               0 :   NS_ENSURE_SUCCESS(rv, rv);
    1574                 : 
    1575                 :   // If we're writing the pref, just set and we're done.
    1576               0 :   if (writePref) {
    1577               0 :     nsCOMPtr<nsIINIParserWriter> iniWriter = do_QueryInterface(iniParser);
    1578               0 :     NS_ENSURE_TRUE(iniWriter, NS_ERROR_FAILURE);
    1579                 : 
    1580               0 :     rv = iniWriter->SetString(NS_LITERAL_CSTRING("Crash Reporter"),
    1581               0 :                               NS_LITERAL_CSTRING("SubmitReport"),
    1582               0 :                               *aSubmitReports ?  NS_LITERAL_CSTRING("1") :
    1583               0 :                                                  NS_LITERAL_CSTRING("0"));
    1584               0 :     NS_ENSURE_SUCCESS(rv, rv);
    1585               0 :     rv = iniWriter->WriteFile(NULL);
    1586               0 :     return rv;
    1587                 :   }
    1588                 :   
    1589               0 :   nsCAutoString submitReportValue;
    1590               0 :   rv = iniParser->GetString(NS_LITERAL_CSTRING("Crash Reporter"),
    1591               0 :                             NS_LITERAL_CSTRING("SubmitReport"),
    1592               0 :                             submitReportValue);
    1593                 : 
    1594                 :   // Default to "true" if the pref can't be found.
    1595               0 :   if (NS_FAILED(rv))
    1596               0 :     *aSubmitReports = true;
    1597               0 :   else if (submitReportValue.EqualsASCII("0"))
    1598               0 :     *aSubmitReports = false;
    1599                 :   else
    1600               0 :     *aSubmitReports = true;
    1601                 : 
    1602               0 :   return NS_OK;
    1603                 : #else
    1604                 :   return NS_ERROR_NOT_IMPLEMENTED;
    1605                 : #endif
    1606                 : }
    1607                 : 
    1608               0 : nsresult GetSubmitReports(bool* aSubmitReports)
    1609                 : {
    1610               0 :     return PrefSubmitReports(aSubmitReports, false);
    1611                 : }
    1612                 : 
    1613               0 : nsresult SetSubmitReports(bool aSubmitReports)
    1614                 : {
    1615                 :     nsresult rv;
    1616                 : 
    1617                 :     nsCOMPtr<nsIObserverService> obsServ =
    1618               0 :       mozilla::services::GetObserverService();
    1619               0 :     if (!obsServ) {
    1620               0 :       return NS_ERROR_FAILURE;
    1621                 :     }
    1622                 : 
    1623               0 :     rv = PrefSubmitReports(&aSubmitReports, true);
    1624               0 :     if (NS_FAILED(rv)) {
    1625               0 :       return rv;
    1626                 :     }
    1627                 : 
    1628               0 :     obsServ->NotifyObservers(nsnull, "submit-reports-pref-changed", nsnull);
    1629               0 :     return NS_OK;
    1630                 : }
    1631                 : 
    1632                 : // The "pending" dir is Crash Reports/pending, from which minidumps
    1633                 : // can be submitted
    1634                 : static bool
    1635               0 : GetPendingDir(nsILocalFile** dir)
    1636                 : {
    1637                 :   nsCOMPtr<nsIProperties> dirSvc =
    1638               0 :     do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
    1639               0 :   if (!dirSvc)
    1640               0 :     return false;
    1641               0 :   nsCOMPtr<nsILocalFile> pendingDir;
    1642               0 :   if (NS_FAILED(dirSvc->Get("UAppData",
    1643                 :                             NS_GET_IID(nsILocalFile),
    1644                 :                             getter_AddRefs(pendingDir))) ||
    1645               0 :       NS_FAILED(pendingDir->Append(NS_LITERAL_STRING("Crash Reports"))) ||
    1646               0 :       NS_FAILED(pendingDir->Append(NS_LITERAL_STRING("pending"))))
    1647               0 :     return false;
    1648               0 :   *dir = NULL;
    1649               0 :   pendingDir.swap(*dir);
    1650               0 :   return true;
    1651                 : }
    1652                 : 
    1653                 : // The "limbo" dir is where minidumps go to wait for something else to
    1654                 : // use them.  If we're |ShouldReport()|, then the "something else" is
    1655                 : // a minidump submitter, and they're coming from the 
    1656                 : // Crash Reports/pending/ dir.  Otherwise, we don't know what the
    1657                 : // "somthing else" is, but the minidumps stay in [profile]/minidumps/
    1658                 : // limbo.
    1659                 : static bool
    1660               0 : GetMinidumpLimboDir(nsILocalFile** dir)
    1661                 : {
    1662               0 :   if (ShouldReport()) {
    1663               0 :     return GetPendingDir(dir);
    1664                 :   }
    1665                 :   else {
    1666               0 :     CreateFileFromPath(gExceptionHandler->dump_path(), dir);
    1667               0 :     return NULL != *dir;
    1668                 :   }
    1669                 : }
    1670                 : 
    1671                 : bool
    1672               0 : GetMinidumpForID(const nsAString& id, nsILocalFile** minidump)
    1673                 : {
    1674               0 :   if (!GetMinidumpLimboDir(minidump))
    1675               0 :     return false;
    1676               0 :   (*minidump)->Append(id + NS_LITERAL_STRING(".dmp")); 
    1677               0 :   return true;
    1678                 : }
    1679                 : 
    1680                 : bool
    1681               0 : GetIDFromMinidump(nsILocalFile* minidump, nsAString& id)
    1682                 : {
    1683               0 :   if (NS_SUCCEEDED(minidump->GetLeafName(id))) {
    1684               0 :     id.Replace(id.Length() - 4, 4, NS_LITERAL_STRING(""));
    1685               0 :     return true;
    1686                 :   }
    1687               0 :   return false;
    1688                 : }
    1689                 : 
    1690                 : bool
    1691               0 : GetExtraFileForID(const nsAString& id, nsILocalFile** extraFile)
    1692                 : {
    1693               0 :   if (!GetMinidumpLimboDir(extraFile))
    1694               0 :     return false;
    1695               0 :   (*extraFile)->Append(id + NS_LITERAL_STRING(".extra"));
    1696               0 :   return true;
    1697                 : }
    1698                 : 
    1699                 : bool
    1700               0 : GetExtraFileForMinidump(nsILocalFile* minidump, nsILocalFile** extraFile)
    1701                 : {
    1702               0 :   nsAutoString leafName;
    1703               0 :   nsresult rv = minidump->GetLeafName(leafName);
    1704               0 :   if (NS_FAILED(rv))
    1705               0 :     return false;
    1706                 : 
    1707               0 :   nsCOMPtr<nsIFile> extraF;
    1708               0 :   rv = minidump->Clone(getter_AddRefs(extraF));
    1709               0 :   if (NS_FAILED(rv))
    1710               0 :     return false;
    1711                 : 
    1712               0 :   nsCOMPtr<nsILocalFile> extra = do_QueryInterface(extraF);
    1713               0 :   if (!extra)
    1714               0 :     return false;
    1715                 : 
    1716               0 :   leafName.Replace(leafName.Length() - 3, 3,
    1717               0 :                    NS_LITERAL_STRING("extra"));
    1718               0 :   rv = extra->SetLeafName(leafName);
    1719               0 :   if (NS_FAILED(rv))
    1720               0 :     return false;
    1721                 : 
    1722               0 :   *extraFile = NULL;
    1723               0 :   extra.swap(*extraFile);
    1724               0 :   return true;
    1725                 : }
    1726                 : 
    1727                 : bool
    1728               0 : AppendExtraData(const nsAString& id, const AnnotationTable& data)
    1729                 : {
    1730               0 :   nsCOMPtr<nsILocalFile> extraFile;
    1731               0 :   if (!GetExtraFileForID(id, getter_AddRefs(extraFile)))
    1732               0 :     return false;
    1733               0 :   return AppendExtraData(extraFile, data);
    1734                 : }
    1735                 : 
    1736                 : //-----------------------------------------------------------------------------
    1737                 : // Helpers for AppendExtraData()
    1738                 : //
    1739                 : struct Blacklist {
    1740               0 :   Blacklist() : mItems(NULL), mLen(0) { }
    1741               0 :   Blacklist(const char** items, int len) : mItems(items), mLen(len) { }
    1742                 : 
    1743               0 :   bool Contains(const nsACString& key) const {
    1744               0 :     for (int i = 0; i < mLen; ++i)
    1745               0 :       if (key.EqualsASCII(mItems[i]))
    1746               0 :         return true;
    1747               0 :     return false;
    1748                 :   }
    1749                 : 
    1750                 :   const char** mItems;
    1751                 :   const int mLen;
    1752                 : };
    1753                 : 
    1754                 : struct EnumerateAnnotationsContext {
    1755                 :   const Blacklist& blacklist;
    1756                 :   PRFileDesc* fd;
    1757                 : };
    1758                 : 
    1759                 : static void
    1760               0 : WriteAnnotation(PRFileDesc* fd, const nsACString& key, const nsACString& value)
    1761                 : {
    1762               0 :   PR_Write(fd, key.BeginReading(), key.Length());
    1763               0 :   PR_Write(fd, "=", 1);
    1764               0 :   PR_Write(fd, value.BeginReading(), value.Length());
    1765               0 :   PR_Write(fd, "\n", 1);
    1766               0 : }
    1767                 : 
    1768                 : static PLDHashOperator
    1769               0 : EnumerateAnnotations(const nsACString& key,
    1770                 :                      nsCString entry,
    1771                 :                      void* userData)
    1772                 : {
    1773                 :   EnumerateAnnotationsContext* ctx =
    1774               0 :     static_cast<EnumerateAnnotationsContext*>(userData);
    1775               0 :   const Blacklist& blacklist = ctx->blacklist;
    1776                 : 
    1777                 :   // skip entries in the blacklist
    1778               0 :   if (blacklist.Contains(key))
    1779               0 :       return PL_DHASH_NEXT;
    1780                 : 
    1781               0 :   WriteAnnotation(ctx->fd, key, entry);
    1782                 : 
    1783               0 :   return PL_DHASH_NEXT;
    1784                 : }
    1785                 : 
    1786                 : static bool
    1787               0 : WriteExtraData(nsILocalFile* extraFile,
    1788                 :                const AnnotationTable& data,
    1789                 :                const Blacklist& blacklist,
    1790                 :                bool writeCrashTime=false,
    1791                 :                bool truncate=false)
    1792                 : {
    1793                 :   PRFileDesc* fd;
    1794               0 :   PRIntn truncOrAppend = truncate ? PR_TRUNCATE : PR_APPEND;
    1795                 :   nsresult rv = 
    1796                 :     extraFile->OpenNSPRFileDesc(PR_WRONLY | PR_CREATE_FILE | truncOrAppend,
    1797               0 :                                 0600, &fd);
    1798               0 :   if (NS_FAILED(rv))
    1799               0 :     return false;
    1800                 : 
    1801               0 :   EnumerateAnnotationsContext ctx = { blacklist, fd };
    1802               0 :   data.EnumerateRead(EnumerateAnnotations, &ctx);
    1803                 : 
    1804               0 :   if (writeCrashTime) {
    1805               0 :     time_t crashTime = time(NULL);
    1806                 :     char crashTimeString[32];
    1807               0 :     XP_TTOA(crashTime, crashTimeString, 10);
    1808                 : 
    1809                 :     WriteAnnotation(fd,
    1810               0 :                     nsDependentCString("CrashTime"),
    1811               0 :                     nsDependentCString(crashTimeString));
    1812                 :   }
    1813                 : 
    1814               0 :   PR_Close(fd);
    1815               0 :   return true;
    1816                 : }
    1817                 : 
    1818                 : bool
    1819               0 : AppendExtraData(nsILocalFile* extraFile, const AnnotationTable& data)
    1820                 : {
    1821               0 :   return WriteExtraData(extraFile, data, Blacklist());
    1822                 : }
    1823                 : 
    1824                 : 
    1825                 : static bool
    1826               0 : WriteExtraForMinidump(nsILocalFile* minidump,
    1827                 :                       const Blacklist& blacklist,
    1828                 :                       nsILocalFile** extraFile)
    1829                 : {
    1830               0 :   nsCOMPtr<nsILocalFile> extra;
    1831               0 :   if (!GetExtraFileForMinidump(minidump, getter_AddRefs(extra)))
    1832               0 :     return false;
    1833                 : 
    1834               0 :   if (!WriteExtraData(extra, *crashReporterAPIData_Hash,
    1835                 :                       blacklist,
    1836                 :                       true /*write crash time*/,
    1837               0 :                       true /*truncate*/))
    1838               0 :     return false;
    1839                 : 
    1840               0 :   *extraFile = NULL;
    1841               0 :   extra.swap(*extraFile);
    1842                 : 
    1843               0 :   return true;
    1844                 : }
    1845                 : 
    1846                 : // It really only makes sense to call this function when
    1847                 : // ShouldReport() is true.
    1848                 : static bool
    1849               0 : MoveToPending(nsIFile* dumpFile, nsIFile* extraFile)
    1850                 : {
    1851               0 :   nsCOMPtr<nsILocalFile> pendingDir;
    1852               0 :   if (!GetPendingDir(getter_AddRefs(pendingDir)))
    1853               0 :     return false;
    1854                 : 
    1855               0 :   return NS_SUCCEEDED(dumpFile->MoveTo(pendingDir, EmptyString())) &&
    1856               0 :     NS_SUCCEEDED(extraFile->MoveTo(pendingDir, EmptyString()));
    1857                 : }
    1858                 : 
    1859                 : static void
    1860               0 : OnChildProcessDumpRequested(void* aContext,
    1861                 : #ifdef XP_MACOSX
    1862                 :                             const ClientInfo& aClientInfo,
    1863                 :                             const xpstring& aFilePath
    1864                 : #else
    1865                 :                             const ClientInfo* aClientInfo,
    1866                 :                             const xpstring* aFilePath
    1867                 : #endif
    1868                 :                             )
    1869                 : {
    1870               0 :   nsCOMPtr<nsILocalFile> minidump;
    1871               0 :   nsCOMPtr<nsILocalFile> extraFile;
    1872                 : 
    1873                 :   CreateFileFromPath(
    1874                 : #ifdef XP_MACOSX
    1875                 :                      aFilePath,
    1876                 : #else
    1877                 :                      *aFilePath,
    1878                 : #endif
    1879               0 :                      getter_AddRefs(minidump));
    1880                 : 
    1881                 : #if defined(__ANDROID__)
    1882                 :   // Do dump generation here since the CrashGenerationServer doesn't
    1883                 :   // have access to the library mappings.
    1884                 :   MappingMap::const_iterator iter = 
    1885                 :     child_library_mappings.find(aClientInfo->pid_);
    1886                 :   google_breakpad::AppMemoryList a;
    1887                 :   if (iter == child_library_mappings.end()) {
    1888                 :     NS_WARNING("No library mappings found for child, can't write minidump!");
    1889                 :     return;
    1890                 :   }
    1891                 : 
    1892                 :   if (!google_breakpad::WriteMinidump(aFilePath->c_str(),
    1893                 :                                       aClientInfo->pid_,
    1894                 :                                       aClientInfo->crash_context,
    1895                 :                                       aClientInfo->crash_context_size,
    1896                 :                                       iter->second,
    1897                 :                                       a))
    1898                 :     return;
    1899                 : #endif
    1900                 : 
    1901               0 :   if (!WriteExtraForMinidump(minidump,
    1902                 :                              Blacklist(kSubprocessBlacklist,
    1903               0 :                                        ArrayLength(kSubprocessBlacklist)),
    1904               0 :                              getter_AddRefs(extraFile)))
    1905                 :     return;
    1906                 : 
    1907               0 :   if (ShouldReport())
    1908               0 :     MoveToPending(minidump, extraFile);
    1909                 : 
    1910                 :   {
    1911                 :     PRUint32 pid =
    1912                 : #ifdef XP_MACOSX
    1913                 :       aClientInfo.pid();
    1914                 : #else
    1915               0 :       aClientInfo->pid();
    1916                 : #endif
    1917                 : 
    1918               0 :     MutexAutoLock lock(*dumpMapLock);
    1919               0 :     pidToMinidump->Put(pid, minidump);
    1920                 :   }
    1921                 : }
    1922                 : 
    1923                 : static bool
    1924            1386 : OOPInitialized()
    1925                 : {
    1926            1386 :   return pidToMinidump != NULL;
    1927                 : }
    1928                 : 
    1929                 : static void
    1930               0 : OOPInit()
    1931                 : {
    1932               0 :   NS_ABORT_IF_FALSE(!OOPInitialized(),
    1933                 :                     "OOP crash reporter initialized more than once!");
    1934               0 :   NS_ABORT_IF_FALSE(gExceptionHandler != NULL,
    1935                 :                     "attempt to initialize OOP crash reporter before in-process crashreporter!");
    1936                 : 
    1937                 : #if defined(XP_WIN)
    1938                 :   childCrashNotifyPipe =
    1939                 :     PR_smprintf("\\\\.\\pipe\\gecko-crash-server-pipe.%i",
    1940                 :                 static_cast<int>(::GetCurrentProcessId()));
    1941                 : 
    1942                 :   const std::wstring dumpPath = gExceptionHandler->dump_path();
    1943                 :   crashServer = new CrashGenerationServer(
    1944                 :     NS_ConvertASCIItoUTF16(childCrashNotifyPipe).get(),
    1945                 :     NULL,                       // default security attributes
    1946                 :     NULL, NULL,                 // we don't care about process connect here
    1947                 :     OnChildProcessDumpRequested, NULL,
    1948                 :     NULL, NULL,                 // we don't care about process exit here
    1949                 :     true,                       // automatically generate dumps
    1950                 :     &dumpPath);
    1951                 : 
    1952                 : #elif defined(XP_LINUX)
    1953               0 :   if (!CrashGenerationServer::CreateReportChannel(&serverSocketFd,
    1954               0 :                                                   &clientSocketFd))
    1955               0 :     NS_RUNTIMEABORT("can't create crash reporter socketpair()");
    1956                 : 
    1957               0 :   const std::string dumpPath = gExceptionHandler->dump_path();
    1958               0 :   bool generateDumps = true;
    1959                 : #if defined(__ANDROID__)
    1960                 :   // On Android, the callback will do dump generation, since it needs
    1961                 :   // to pass the library mappings.
    1962                 :   generateDumps = false;
    1963                 : #endif
    1964                 :   crashServer = new CrashGenerationServer(
    1965                 :     serverSocketFd,
    1966                 :     OnChildProcessDumpRequested, NULL,
    1967                 :     NULL, NULL,                 // we don't care about process exit here
    1968                 :     generateDumps,
    1969               0 :     &dumpPath);
    1970                 : 
    1971                 : #elif defined(XP_MACOSX)
    1972                 :   childCrashNotifyPipe =
    1973                 :     PR_smprintf("gecko-crash-server-pipe.%i",
    1974                 :                 static_cast<int>(getpid()));
    1975                 :   const std::string dumpPath = gExceptionHandler->dump_path();
    1976                 : 
    1977                 :   crashServer = new CrashGenerationServer(
    1978                 :     childCrashNotifyPipe,
    1979                 :     OnChildProcessDumpRequested, NULL,
    1980                 :     NULL, NULL,
    1981                 :     true, // automatically generate dumps
    1982                 :     dumpPath);
    1983                 : #endif
    1984                 : 
    1985               0 :   if (!crashServer->Start())
    1986               0 :     NS_RUNTIMEABORT("can't start crash reporter server()");
    1987                 : 
    1988               0 :   pidToMinidump = new ChildMinidumpMap();
    1989               0 :   pidToMinidump->Init();
    1990                 : 
    1991               0 :   dumpMapLock = new Mutex("CrashReporter::dumpMapLock");
    1992               0 : }
    1993                 : 
    1994                 : static void
    1995            1386 : OOPDeinit()
    1996                 : {
    1997            1386 :   if (!OOPInitialized()) {
    1998            1386 :     NS_WARNING("OOPDeinit() without successful OOPInit()");
    1999            1386 :     return;
    2000                 :   }
    2001                 : 
    2002               0 :   delete crashServer;
    2003               0 :   crashServer = NULL;
    2004                 : 
    2005               0 :   delete dumpMapLock;
    2006               0 :   dumpMapLock = NULL;
    2007                 : 
    2008               0 :   delete pidToMinidump;
    2009               0 :   pidToMinidump = NULL;
    2010                 : 
    2011                 : #if defined(XP_WIN)
    2012                 :   PR_Free(childCrashNotifyPipe);
    2013                 :   childCrashNotifyPipe = NULL;
    2014                 : #endif
    2015                 : }
    2016                 : 
    2017                 : #if defined(XP_WIN) || defined(XP_MACOSX)
    2018                 : // Parent-side API for children
    2019                 : const char*
    2020                 : GetChildNotificationPipe()
    2021                 : {
    2022                 :   if (!GetEnabled())
    2023                 :     return kNullNotifyPipe;
    2024                 : 
    2025                 :   if (!OOPInitialized())
    2026                 :     OOPInit();
    2027                 : 
    2028                 :   return childCrashNotifyPipe;
    2029                 : }
    2030                 : #endif
    2031                 : 
    2032                 : #if defined(XP_WIN)
    2033                 : // Child-side API
    2034                 : bool
    2035                 : SetRemoteExceptionHandler(const nsACString& crashPipe)
    2036                 : {
    2037                 :   // crash reporting is disabled
    2038                 :   if (crashPipe.Equals(kNullNotifyPipe))
    2039                 :     return true;
    2040                 : 
    2041                 :   NS_ABORT_IF_FALSE(!gExceptionHandler, "crash client already init'd");
    2042                 : 
    2043                 :   gExceptionHandler = new google_breakpad::
    2044                 :     ExceptionHandler(L"",
    2045                 :                      FPEFilter,
    2046                 :                      NULL,    // no minidump callback
    2047                 :                      NULL,    // no callback context
    2048                 :                      google_breakpad::ExceptionHandler::HANDLER_ALL,
    2049                 :                      MiniDumpNormal,
    2050                 :                      NS_ConvertASCIItoUTF16(crashPipe).BeginReading(),
    2051                 :                      NULL);
    2052                 : #ifdef XP_WIN
    2053                 :   gExceptionHandler->set_handle_debug_exceptions(true);
    2054                 : #endif
    2055                 : 
    2056                 :   // we either do remote or nothing, no fallback to regular crash reporting
    2057                 :   return gExceptionHandler->IsOutOfProcess();
    2058                 : }
    2059                 : 
    2060                 : //--------------------------------------------------
    2061                 : #elif defined(XP_LINUX)
    2062                 : 
    2063                 : // Parent-side API for children
    2064                 : bool
    2065               0 : CreateNotificationPipeForChild(int* childCrashFd, int* childCrashRemapFd)
    2066                 : {
    2067               0 :   if (!GetEnabled()) {
    2068               0 :     *childCrashFd = -1;
    2069               0 :     *childCrashRemapFd = -1;
    2070               0 :     return true;
    2071                 :   }
    2072                 : 
    2073               0 :   if (!OOPInitialized())
    2074               0 :     OOPInit();
    2075                 : 
    2076               0 :   *childCrashFd = clientSocketFd;
    2077               0 :   *childCrashRemapFd = kMagicChildCrashReportFd;
    2078                 : 
    2079               0 :   return true;
    2080                 : }
    2081                 : 
    2082                 : // Child-side API
    2083                 : bool
    2084               1 : SetRemoteExceptionHandler()
    2085                 : {
    2086               1 :   NS_ABORT_IF_FALSE(!gExceptionHandler, "crash client already init'd");
    2087                 : 
    2088                 :   gExceptionHandler = new google_breakpad::
    2089                 :     ExceptionHandler("",
    2090                 :                      NULL,    // no filter callback
    2091                 :                      NULL,    // no minidump callback
    2092                 :                      NULL,    // no callback context
    2093                 :                      true,    // install signal handlers
    2094               2 :                      kMagicChildCrashReportFd);
    2095                 : 
    2096               1 :   if (gDelayedAnnotations) {
    2097               0 :     for (PRUint32 i = 0; i < gDelayedAnnotations->Length(); i++) {
    2098               0 :       gDelayedAnnotations->ElementAt(i)->Run();
    2099                 :     }
    2100               0 :     delete gDelayedAnnotations;
    2101                 :   }
    2102                 : 
    2103                 :   // we either do remote or nothing, no fallback to regular crash reporting
    2104               1 :   return gExceptionHandler->IsOutOfProcess();
    2105                 : }
    2106                 : 
    2107                 : //--------------------------------------------------
    2108                 : #elif defined(XP_MACOSX)
    2109                 : // Child-side API
    2110                 : bool
    2111                 : SetRemoteExceptionHandler(const nsACString& crashPipe)
    2112                 : {
    2113                 :   // crash reporting is disabled
    2114                 :   if (crashPipe.Equals(kNullNotifyPipe))
    2115                 :     return true;
    2116                 : 
    2117                 :   NS_ABORT_IF_FALSE(!gExceptionHandler, "crash client already init'd");
    2118                 : 
    2119                 :   gExceptionHandler = new google_breakpad::
    2120                 :     ExceptionHandler("",
    2121                 :                      NULL,    // no filter callback
    2122                 :                      NULL,    // no minidump callback
    2123                 :                      NULL,    // no callback context
    2124                 :                      true,    // install signal handlers
    2125                 :                      crashPipe.BeginReading());
    2126                 : 
    2127                 :   // we either do remote or nothing, no fallback to regular crash reporting
    2128                 :   return gExceptionHandler->IsOutOfProcess();
    2129                 : }
    2130                 : #endif  // XP_WIN
    2131                 : 
    2132                 : 
    2133                 : bool
    2134               0 : TakeMinidumpForChild(PRUint32 childPid, nsILocalFile** dump)
    2135                 : {
    2136               0 :   if (!GetEnabled())
    2137               0 :     return false;
    2138                 : 
    2139               0 :   MutexAutoLock lock(*dumpMapLock);
    2140                 : 
    2141               0 :   nsCOMPtr<nsILocalFile> d;
    2142               0 :   bool found = pidToMinidump->Get(childPid, getter_AddRefs(d));
    2143               0 :   if (found)
    2144               0 :     pidToMinidump->Remove(childPid);
    2145                 : 
    2146               0 :   *dump = NULL;
    2147               0 :   d.swap(*dump);
    2148                 : 
    2149               0 :   return found;
    2150                 : }
    2151                 : 
    2152                 : //-----------------------------------------------------------------------------
    2153                 : // CreatePairedMinidumps() and helpers
    2154                 : //
    2155                 : struct PairedDumpContext {
    2156                 :   nsCOMPtr<nsILocalFile>* minidump;
    2157                 :   nsCOMPtr<nsILocalFile>* extra;
    2158                 :   const Blacklist& blacklist;
    2159                 : };
    2160                 : 
    2161                 : static bool
    2162               0 : PairedDumpCallback(const XP_CHAR* dump_path,
    2163                 :                    const XP_CHAR* minidump_id,
    2164                 :                    void* context,
    2165                 : #ifdef XP_WIN32
    2166                 :                    EXCEPTION_POINTERS* /*unused*/,
    2167                 :                    MDRawAssertionInfo* /*unused*/,
    2168                 : #endif
    2169                 :                    bool succeeded)
    2170                 : {
    2171               0 :   PairedDumpContext* ctx = static_cast<PairedDumpContext*>(context);
    2172               0 :   nsCOMPtr<nsILocalFile>& minidump = *ctx->minidump;
    2173               0 :   nsCOMPtr<nsILocalFile>& extra = *ctx->extra;
    2174               0 :   const Blacklist& blacklist = ctx->blacklist;
    2175                 : 
    2176               0 :   xpstring dump(dump_path);
    2177               0 :   dump += XP_PATH_SEPARATOR;
    2178               0 :   dump += minidump_id;
    2179               0 :   dump += dumpFileExtension;
    2180                 : 
    2181               0 :   CreateFileFromPath(dump, getter_AddRefs(minidump));
    2182               0 :   return WriteExtraForMinidump(minidump, blacklist, getter_AddRefs(extra));
    2183                 : }
    2184                 : 
    2185                 : ThreadId
    2186               0 : CurrentThreadId()
    2187                 : {
    2188                 : #if defined(XP_WIN)
    2189                 :   return ::GetCurrentThreadId();
    2190                 : #elif defined(XP_LINUX)
    2191               0 :   return sys_gettid();
    2192                 : #elif defined(XP_MACOSX)
    2193                 :   // Just return an index, since Mach ports can't be directly serialized
    2194                 :   thread_act_port_array_t   threads_for_task;
    2195                 :   mach_msg_type_number_t    thread_count;
    2196                 : 
    2197                 :   if (task_threads(mach_task_self(), &threads_for_task, &thread_count))
    2198                 :     return -1;
    2199                 : 
    2200                 :   for (unsigned int i = 0; i < thread_count; ++i) {
    2201                 :     if (threads_for_task[i] == mach_thread_self())
    2202                 :       return i;
    2203                 :   }
    2204                 :   abort();
    2205                 : #else
    2206                 : #  error "Unsupported platform"
    2207                 : #endif
    2208                 : }
    2209                 : 
    2210                 : bool
    2211               0 : CreatePairedMinidumps(ProcessHandle childPid,
    2212                 :                       ThreadId childBlamedThread,
    2213                 :                       nsAString* pairGUID,
    2214                 :                       nsILocalFile** childDump,
    2215                 :                       nsILocalFile** parentDump)
    2216                 : {
    2217               0 :   if (!GetEnabled())
    2218               0 :     return false;
    2219                 : 
    2220                 :   // create the UUID for the hang dump as a pair
    2221                 :   nsresult rv;
    2222                 :   nsCOMPtr<nsIUUIDGenerator> uuidgen =
    2223               0 :     do_GetService("@mozilla.org/uuid-generator;1", &rv);
    2224               0 :   NS_ENSURE_SUCCESS(rv, false);  
    2225                 : 
    2226                 :   nsID id;
    2227               0 :   rv = uuidgen->GenerateUUIDInPlace(&id);
    2228               0 :   NS_ENSURE_SUCCESS(rv, false);
    2229                 :   
    2230                 :   char chars[NSID_LENGTH];
    2231               0 :   id.ToProvidedString(chars);
    2232               0 :   CopyASCIItoUTF16(chars, *pairGUID);
    2233                 : 
    2234                 :   // trim off braces
    2235               0 :   pairGUID->Cut(0, 1);
    2236               0 :   pairGUID->Cut(pairGUID->Length()-1, 1);
    2237                 : 
    2238                 : #ifdef XP_MACOSX
    2239                 :   mach_port_t childThread = MACH_PORT_NULL;
    2240                 :   thread_act_port_array_t   threads_for_task;
    2241                 :   mach_msg_type_number_t    thread_count;
    2242                 : 
    2243                 :   if (task_threads(childPid, &threads_for_task, &thread_count)
    2244                 :       == KERN_SUCCESS && childBlamedThread < thread_count) {
    2245                 :     childThread = threads_for_task[childBlamedThread];
    2246                 :   }
    2247                 : #else
    2248               0 :   ThreadId childThread = childBlamedThread;
    2249                 : #endif
    2250                 : 
    2251                 :   // dump the child
    2252               0 :   nsCOMPtr<nsILocalFile> childMinidump;
    2253               0 :   nsCOMPtr<nsILocalFile> childExtra;
    2254                 :   Blacklist childBlacklist(kSubprocessBlacklist,
    2255               0 :                            ArrayLength(kSubprocessBlacklist));
    2256                 :   PairedDumpContext childCtx =
    2257               0 :     { &childMinidump, &childExtra, childBlacklist };
    2258               0 :   if (!google_breakpad::ExceptionHandler::WriteMinidumpForChild(
    2259                 :          childPid,
    2260                 :          childThread,
    2261               0 :          gExceptionHandler->dump_path(),
    2262                 :          PairedDumpCallback,
    2263               0 :          &childCtx))
    2264               0 :     return false;
    2265                 : 
    2266                 :   // dump the parent
    2267               0 :   nsCOMPtr<nsILocalFile> parentMinidump;
    2268               0 :   nsCOMPtr<nsILocalFile> parentExtra;
    2269                 :   // nothing's blacklisted for this process
    2270               0 :   Blacklist parentBlacklist;
    2271                 :   PairedDumpContext parentCtx =
    2272               0 :     { &parentMinidump, &parentExtra, parentBlacklist };
    2273               0 :   if (!google_breakpad::ExceptionHandler::WriteMinidump(
    2274               0 :          gExceptionHandler->dump_path(),
    2275                 :          true,                  // write exception stream
    2276                 :          PairedDumpCallback,
    2277               0 :          &parentCtx))
    2278               0 :     return false;
    2279                 : 
    2280                 :   // success
    2281               0 :   if (ShouldReport()) {
    2282               0 :     MoveToPending(childMinidump, childExtra);
    2283               0 :     MoveToPending(parentMinidump, parentExtra);
    2284                 :   }
    2285                 : 
    2286               0 :   *childDump = NULL;
    2287               0 :   *parentDump = NULL;
    2288               0 :   childMinidump.swap(*childDump);
    2289               0 :   parentMinidump.swap(*parentDump);
    2290                 : 
    2291               0 :   return true;
    2292                 : }
    2293                 : 
    2294                 : bool
    2295               0 : UnsetRemoteExceptionHandler()
    2296                 : {
    2297               0 :   delete gExceptionHandler;
    2298               0 :   gExceptionHandler = NULL;
    2299               0 :   return true;
    2300                 : }
    2301                 : 
    2302                 : #if defined(__ANDROID__)
    2303                 : void AddLibraryMapping(const char* library_name,
    2304                 :                        const char* file_id,
    2305                 :                        uintptr_t   start_address,
    2306                 :                        size_t      mapping_length,
    2307                 :                        size_t      file_offset)
    2308                 : {
    2309                 :   if (!gExceptionHandler) {
    2310                 :     mapping_info info;
    2311                 :     info.name = library_name;
    2312                 :     info.debug_id = file_id;
    2313                 :     info.start_address = start_address;
    2314                 :     info.length = mapping_length;
    2315                 :     info.file_offset = file_offset;
    2316                 :     library_mappings.push_back(info);
    2317                 :   }
    2318                 :   else {
    2319                 :     u_int8_t guid[sizeof(MDGUID)];
    2320                 :     FileIDToGUID(file_id, guid);
    2321                 :     gExceptionHandler->AddMappingInfo(library_name,
    2322                 :                                       guid,
    2323                 :                                       start_address,
    2324                 :                                       mapping_length,
    2325                 :                                       file_offset);
    2326                 :   }
    2327                 : }
    2328                 : 
    2329                 : void AddLibraryMappingForChild(PRUint32    childPid,
    2330                 :                                const char* library_name,
    2331                 :                                const char* file_id,
    2332                 :                                uintptr_t   start_address,
    2333                 :                                size_t      mapping_length,
    2334                 :                                size_t      file_offset)
    2335                 : {
    2336                 :   if (child_library_mappings.find(childPid) == child_library_mappings.end())
    2337                 :     child_library_mappings[childPid] = google_breakpad::MappingList();
    2338                 :   google_breakpad::MappingInfo info;
    2339                 :   info.start_addr = start_address;
    2340                 :   info.size = mapping_length;
    2341                 :   info.offset = file_offset;
    2342                 :   strcpy(info.name, library_name);
    2343                 :  
    2344                 :   std::pair<google_breakpad::MappingInfo, u_int8_t[sizeof(MDGUID)]> mapping;
    2345                 :   mapping.first = info;
    2346                 :   u_int8_t guid[sizeof(MDGUID)];
    2347                 :   FileIDToGUID(file_id, guid);
    2348                 :   memcpy(mapping.second, guid, sizeof(MDGUID));
    2349                 :   child_library_mappings[childPid].push_back(mapping);
    2350                 : }
    2351                 : 
    2352                 : void RemoveLibraryMappingsForChild(PRUint32 childPid)
    2353                 : {
    2354                 :   MappingMap::iterator iter = child_library_mappings.find(childPid);
    2355                 :   if (iter != child_library_mappings.end())
    2356                 :     child_library_mappings.erase(iter);
    2357                 : }
    2358                 : #endif
    2359                 : 
    2360                 : } // namespace CrashReporter

Generated by: LCOV version 1.7