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
|