summaryrefslogtreecommitdiffstats
path: root/toolkit/crashreporter/nsExceptionHandler.h
blob: d79996244a4eb2027b5d195da1f575e2d3940d28 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// This header has two implementations, the real one in nsExceptionHandler.cpp
// and a dummy in nsDummyExceptionHandler.cpp. The latter is used in builds
// configured with --disable-crashreporter. If you add or remove a function
// from this header you must update both implementations otherwise you'll break
// builds that disable the crash reporter.

#ifndef nsExceptionHandler_h__
#define nsExceptionHandler_h__

#include "mozilla/Assertions.h"
#include "mozilla/EnumeratedArray.h"
#include "mozilla/Maybe.h"

#include "CrashAnnotations.h"

#include <stddef.h>
#include <stdint.h>
#include "nsError.h"
#include "nsString.h"
#include "nsXULAppAPI.h"
#include "prio.h"

#if defined(XP_WIN)
#  ifdef WIN32_LEAN_AND_MEAN
#    undef WIN32_LEAN_AND_MEAN
#  endif
#  include <windows.h>
#endif

#if defined(XP_MACOSX)
#  include <mach/mach.h>
#endif

#if defined(XP_LINUX)
#  include <signal.h>
#endif

class nsIFile;

namespace CrashReporter {

using mozilla::Maybe;
using mozilla::Nothing;

/**
 * Returns true if the crash reporter is using the dummy implementation.
 */
static inline bool IsDummy() {
#ifdef MOZ_CRASHREPORTER
  return false;
#else
  return true;
#endif
}

nsresult SetExceptionHandler(nsIFile* aXREDirectory, bool force = false);
nsresult UnsetExceptionHandler();

/**
 * Tell the crash reporter to recalculate where crash events files should go.
 * SetCrashEventsDir is used before XPCOM is initialized from the startup
 * code.
 *
 * UpdateCrashEventsDir uses the directory service to re-set the
 * crash event directory based on the current profile.
 *
 * 1. If environment variable is present, use it. We don't expect
 *    the environment variable except for tests and other atypical setups.
 * 2. <profile>/crashes/events
 * 3. <UAppData>/Crash Reports/events
 */
void SetUserAppDataDirectory(nsIFile* aDir);
void SetProfileDirectory(nsIFile* aDir);
void UpdateCrashEventsDir();
void SetMemoryReportFile(nsIFile* aFile);
nsresult GetDefaultMemoryReportFile(nsIFile** aFile);

/**
 * Get the path where crash event files should be written.
 */
bool GetCrashEventsDir(nsAString& aPath);

bool GetEnabled();
bool GetServerURL(nsACString& aServerURL);
nsresult SetServerURL(const nsACString& aServerURL);
bool GetMinidumpPath(nsAString& aPath);
nsresult SetMinidumpPath(const nsAString& aPath);

// These functions are thread safe and can be called in both the parent and
// child processes. Annotations added in the main process will be included in
// child process crashes too unless the child process sets its own annotations.
// If it does the child-provided annotation overrides the one set in the parent.
nsresult AnnotateCrashReport(Annotation key, bool data);
nsresult AnnotateCrashReport(Annotation key, int data);
nsresult AnnotateCrashReport(Annotation key, unsigned int data);
nsresult AnnotateCrashReport(Annotation key, const nsACString& data);
nsresult AppendToCrashReportAnnotation(Annotation key, const nsACString& data);
nsresult RemoveCrashReportAnnotation(Annotation key);
nsresult AppendAppNotesToCrashReport(const nsACString& data);

// RAII class for setting a crash annotation during a limited scope of time.
// Will reset the named annotation to its previous value when destroyed.
//
// This type's behavior is identical to that of AnnotateCrashReport().
class MOZ_RAII AutoAnnotateCrashReport final {
 public:
  AutoAnnotateCrashReport(Annotation key, bool data);
  AutoAnnotateCrashReport(Annotation key, int data);
  AutoAnnotateCrashReport(Annotation key, unsigned int data);
  AutoAnnotateCrashReport(Annotation key, const nsACString& data);
  ~AutoAnnotateCrashReport();

#ifdef MOZ_CRASHREPORTER
 private:
  Annotation mKey;
  nsCString mPrevious;
#endif
};

void AnnotateOOMAllocationSize(size_t size);
void AnnotateTexturesSize(size_t size);
nsresult SetGarbageCollecting(bool collecting);
void SetEventloopNestingLevel(uint32_t level);
void SetMinidumpAnalysisAllThreads();
void ClearInactiveStateStart();
void SetInactiveStateStart();

nsresult SetRestartArgs(int argc, char** argv);
nsresult SetupExtraData(nsIFile* aAppDataDirectory, const nsACString& aBuildID);
// Registers an additional memory region to be included in the minidump
nsresult RegisterAppMemory(void* ptr, size_t length);
nsresult UnregisterAppMemory(void* ptr);

// Include heap regions of the crash context.
void SetIncludeContextHeap(bool aValue);

void GetAnnotation(uint32_t childPid, Annotation annotation,
                   nsACString& outStr);

// Functions for working with minidumps and .extras
typedef mozilla::EnumeratedArray<Annotation, Annotation::Count, nsCString>
    AnnotationTable;
void DeleteMinidumpFilesForID(
    const nsAString& aId,
    const Maybe<nsString>& aAdditionalMinidump = Nothing());
bool GetMinidumpForID(const nsAString& id, nsIFile** minidump,
                      const Maybe<nsString>& aAdditionalMinidump = Nothing());
bool GetIDFromMinidump(nsIFile* minidump, nsAString& id);
bool GetExtraFileForID(const nsAString& id, nsIFile** extraFile);
bool GetExtraFileForMinidump(nsIFile* minidump, nsIFile** extraFile);
bool WriteExtraFile(const nsAString& id, const AnnotationTable& annotations);

/**
 * Copies the non-empty annotations in the source table to the destination
 * overwriting the corresponding entries.
 */
void MergeCrashAnnotations(AnnotationTable& aDst, const AnnotationTable& aSrc);

#ifdef XP_WIN
nsresult WriteMinidumpForException(EXCEPTION_POINTERS* aExceptionInfo);
#endif
#ifdef XP_LINUX
bool WriteMinidumpForSigInfo(int signo, siginfo_t* info, void* uc);
#endif
#ifdef XP_MACOSX
nsresult AppendObjCExceptionInfoToAppNotes(void* inException);
#endif
nsresult GetSubmitReports(bool* aSubmitReport);
nsresult SetSubmitReports(bool aSubmitReport);

#ifdef XP_WIN
// This data is stored in the parent process, there is one copy for each child
// process. The mChildPid and mMinidumpFile fields are filled by the WER runtime
// exception module when the associated child process crashes.
struct WindowsErrorReportingData {
  // PID of the child process that crashed.
  DWORD mChildPid;
  // Filename of the generated minidump; this is not a 0-terminated string
  char mMinidumpFile[40];
};
#endif  // XP_WIN

// Out-of-process crash reporter API.

// Initializes out-of-process crash reporting. This method must be called
// before the platform-specific notification pipe APIs are called. If called
// from off the main thread, this method will synchronously proxy to the main
// thread.
void OOPInit();

// Return true if a dump was found for |childPid|, and return the
// path in |dump|.  The caller owns the last reference to |dump| if it
// is non-nullptr. The annotations for the crash will be stored in
// |aAnnotations|. The sequence parameter will be filled with an ordinal
// indicating which remote process crashed first.
bool TakeMinidumpForChild(uint32_t childPid, nsIFile** dump,
                          AnnotationTable& aAnnotations,
                          uint32_t* aSequence = nullptr);

/**
 * If a dump was found for |childPid| then write a minimal .extra file to
 * complete it and remove it from the list of pending crash dumps. It's
 * required to call this method after a non-main process crash if the crash
 * report could not be finalized via the CrashReporterHost (for example because
 * it wasn't instanced yet).
 *
 * @param aChildPid The pid of the crashed child process
 * @param aType The type of the crashed process
 * @param aDumpId A string that will be filled with the dump ID
 */
[[nodiscard]] bool FinalizeOrphanedMinidump(uint32_t aChildPid,
                                            GeckoProcessType aType,
                                            nsString* aDumpId = nullptr);

#if defined(XP_WIN)
typedef HANDLE ProcessHandle;
typedef DWORD ProcessId;
typedef DWORD ThreadId;
typedef HANDLE FileHandle;
const FileHandle kInvalidFileHandle = INVALID_HANDLE_VALUE;
#elif defined(XP_MACOSX)
typedef task_t ProcessHandle;
typedef pid_t ProcessId;
typedef mach_port_t ThreadId;
typedef int FileHandle;
const FileHandle kInvalidFileHandle = -1;
#else
typedef int ProcessHandle;
typedef pid_t ProcessId;
typedef int ThreadId;
typedef int FileHandle;
const FileHandle kInvalidFileHandle = -1;
#endif

#if !defined(XP_WIN)
FileHandle GetAnnotationTimeCrashFd();
#endif
void RegisterChildCrashAnnotationFileDescriptor(ProcessId aProcess,
                                                PRFileDesc* aFd);
void DeregisterChildCrashAnnotationFileDescriptor(ProcessId aProcess);

// Return the current thread's ID.
//
// XXX: this is a somewhat out-of-place interface to expose through
// crashreporter, but it takes significant work to call sys_gettid()
// correctly on Linux and breakpad has already jumped through those
// hoops for us.
ThreadId CurrentThreadId();

/*
 * Take a minidump of the target process and pair it with a new minidump of the
 * calling process and thread. The caller will own both dumps after this call.
 * If this function fails it will attempt to delete any files that were created.
 *
 * The .extra information created will not include an 'additional_minidumps'
 * annotation.
 *
 * @param aTargetPid The target process for the minidump.
 * @param aTargetBlamedThread The target thread for the minidump.
 * @param aIncomingPairName The name to apply to the paired dump the caller
 *   passes in.
 * @param aTargetDumpOut The target minidump file paired up with the new one.
 * @param aTargetAnnotations The crash annotations of the target process.
 * @return bool indicating success or failure
 */
bool CreateMinidumpsAndPair(ProcessHandle aTargetPid,
                            ThreadId aTargetBlamedThread,
                            const nsACString& aIncomingPairName,
                            AnnotationTable& aTargetAnnotations,
                            nsIFile** aTargetDumpOut);

#if defined(XP_WIN) || defined(XP_MACOSX)
// Parent-side API for children
const char* GetChildNotificationPipe();

#  ifdef MOZ_CRASHREPORTER_INJECTOR
// Inject a crash report client into an arbitrary process, and inform the
// callback object when it crashes. Parent process only.

class InjectorCrashCallback {
 public:
  InjectorCrashCallback() {}

  /**
   * Inform the callback of a crash. The client code should call
   * TakeMinidumpForChild to remove it from the PID mapping table.
   *
   * The callback will not be fired if the client has already called
   * TakeMinidumpForChild for this process ID.
   */
  virtual void OnCrash(DWORD processID) = 0;
};

// This method implies OOPInit
void InjectCrashReporterIntoProcess(DWORD processID, InjectorCrashCallback* cb);
void UnregisterInjectorCallback(DWORD processID);
#  endif
#else
// Parent-side API for children

// Set the outparams for crash reporter server's fd (|childCrashFd|)
// and the magic fd number it should be remapped to
// (|childCrashRemapFd|) before exec() in the child process.
// |SetRemoteExceptionHandler()| in the child process expects to find
// the server at |childCrashRemapFd|.  Return true if successful.
//
// If crash reporting is disabled, both outparams will be set to -1
// and |true| will be returned.
bool CreateNotificationPipeForChild(int* childCrashFd, int* childCrashRemapFd);

#endif  // XP_WIN

// Child-side API
bool SetRemoteExceptionHandler(
    const char* aCrashPipe = nullptr,
    FileHandle aCrashTimeAnnotationFile = kInvalidFileHandle);
bool UnsetRemoteExceptionHandler(bool wasSet = true);

#if defined(MOZ_WIDGET_ANDROID)
// Android creates child process as services so we must explicitly set
// the handle for the pipe since it can't get remapped to a default value.
void SetNotificationPipeForChild(FileHandle childCrashFd);
void SetCrashAnnotationPipeForChild(FileHandle childCrashAnnotationFd);
#endif

}  // namespace CrashReporter

#endif /* nsExceptionHandler_h__ */