1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 // This header has two implementations, the real one in nsExceptionHandler.cpp
7 // and a dummy in nsDummyExceptionHandler.cpp. The latter is used in builds
8 // configured with --disable-crashreporter. If you add or remove a function
9 // from this header you must update both implementations otherwise you'll break
10 // builds that disable the crash reporter.
11 
12 #ifndef nsExceptionHandler_h__
13 #define nsExceptionHandler_h__
14 
15 #include "mozilla/Assertions.h"
16 #include "mozilla/EnumeratedArray.h"
17 
18 #include "CrashAnnotations.h"
19 
20 #include <stddef.h>
21 #include <stdint.h>
22 #include "nsError.h"
23 #include "nsString.h"
24 #include "nsXULAppAPI.h"
25 #include "prio.h"
26 
27 #if defined(XP_WIN)
28 #  ifdef WIN32_LEAN_AND_MEAN
29 #    undef WIN32_LEAN_AND_MEAN
30 #  endif
31 #  include <windows.h>
32 #endif
33 
34 #if defined(XP_MACOSX)
35 #  include <mach/mach.h>
36 #endif
37 
38 #if defined(XP_LINUX)
39 #  include <signal.h>
40 #endif
41 
42 class nsIFile;
43 
44 namespace CrashReporter {
45 
46 /**
47  * Returns true if the crash reporter is using the dummy implementation.
48  */
IsDummy()49 static inline bool IsDummy() {
50 #ifdef MOZ_CRASHREPORTER
51   return false;
52 #else
53   return true;
54 #endif
55 }
56 
57 nsresult SetExceptionHandler(nsIFile* aXREDirectory, bool force = false);
58 nsresult UnsetExceptionHandler();
59 
60 /**
61  * Tell the crash reporter to recalculate where crash events files should go.
62  * SetCrashEventsDir is used before XPCOM is initialized from the startup
63  * code.
64  *
65  * UpdateCrashEventsDir uses the directory service to re-set the
66  * crash event directory based on the current profile.
67  *
68  * 1. If environment variable is present, use it. We don't expect
69  *    the environment variable except for tests and other atypical setups.
70  * 2. <profile>/crashes/events
71  * 3. <UAppData>/Crash Reports/events
72  */
73 void SetUserAppDataDirectory(nsIFile* aDir);
74 void SetProfileDirectory(nsIFile* aDir);
75 void UpdateCrashEventsDir();
76 void SetMemoryReportFile(nsIFile* aFile);
77 nsresult GetDefaultMemoryReportFile(nsIFile** aFile);
78 
79 /**
80  * Get the path where crash event files should be written.
81  */
82 bool GetCrashEventsDir(nsAString& aPath);
83 
84 bool GetEnabled();
85 bool GetServerURL(nsACString& aServerURL);
86 nsresult SetServerURL(const nsACString& aServerURL);
87 bool GetMinidumpPath(nsAString& aPath);
88 nsresult SetMinidumpPath(const nsAString& aPath);
89 
90 // These functions are thread safe and can be called in both the parent and
91 // child processes. Annotations added in the main process will be included in
92 // child process crashes too unless the child process sets its own annotations.
93 // If it does the child-provided annotation overrides the one set in the parent.
94 nsresult AnnotateCrashReport(Annotation key, bool data);
95 nsresult AnnotateCrashReport(Annotation key, int data);
96 nsresult AnnotateCrashReport(Annotation key, unsigned int data);
97 nsresult AnnotateCrashReport(Annotation key, const nsACString& data);
98 nsresult RemoveCrashReportAnnotation(Annotation key);
99 nsresult AppendAppNotesToCrashReport(const nsACString& data);
100 
101 // RAII class for setting a crash annotation during a limited scope of time.
102 // Will reset the named annotation to its previous value when destroyed.
103 //
104 // This type's behavior is identical to that of AnnotateCrashReport().
105 class MOZ_RAII AutoAnnotateCrashReport final {
106  public:
107   AutoAnnotateCrashReport(Annotation key, bool data);
108   AutoAnnotateCrashReport(Annotation key, int data);
109   AutoAnnotateCrashReport(Annotation key, unsigned int data);
110   AutoAnnotateCrashReport(Annotation key, const nsACString& data);
111   ~AutoAnnotateCrashReport();
112 
113 #ifdef MOZ_CRASHREPORTER
114  private:
115   Annotation mKey;
116   nsCString mPrevious;
117 #endif
118 };
119 
120 void AnnotateOOMAllocationSize(size_t size);
121 void AnnotateTexturesSize(size_t size);
122 nsresult SetGarbageCollecting(bool collecting);
123 void SetEventloopNestingLevel(uint32_t level);
124 void SetMinidumpAnalysisAllThreads();
125 
126 nsresult SetRestartArgs(int argc, char** argv);
127 nsresult SetupExtraData(nsIFile* aAppDataDirectory, const nsACString& aBuildID);
128 // Registers an additional memory region to be included in the minidump
129 nsresult RegisterAppMemory(void* ptr, size_t length);
130 nsresult UnregisterAppMemory(void* ptr);
131 
132 // Include heap regions of the crash context.
133 void SetIncludeContextHeap(bool aValue);
134 
135 void GetAnnotation(uint32_t childPid, Annotation annotation,
136                    nsACString& outStr);
137 
138 // Functions for working with minidumps and .extras
139 typedef mozilla::EnumeratedArray<Annotation, Annotation::Count, nsCString>
140     AnnotationTable;
141 void DeleteMinidumpFilesForID(const nsAString& id);
142 bool GetMinidumpForID(const nsAString& id, nsIFile** minidump);
143 bool GetIDFromMinidump(nsIFile* minidump, nsAString& id);
144 bool GetExtraFileForID(const nsAString& id, nsIFile** extraFile);
145 bool GetExtraFileForMinidump(nsIFile* minidump, nsIFile** extraFile);
146 bool WriteExtraFile(const nsAString& id, const AnnotationTable& annotations);
147 
148 /**
149  * Copies the non-empty annotations in the source table to the destination
150  * overwriting the corresponding entries.
151  */
152 void MergeCrashAnnotations(AnnotationTable& aDst, const AnnotationTable& aSrc);
153 
154 #ifdef XP_WIN
155 nsresult WriteMinidumpForException(EXCEPTION_POINTERS* aExceptionInfo);
156 #endif
157 #ifdef XP_LINUX
158 bool WriteMinidumpForSigInfo(int signo, siginfo_t* info, void* uc);
159 #endif
160 #ifdef XP_MACOSX
161 nsresult AppendObjCExceptionInfoToAppNotes(void* inException);
162 #endif
163 nsresult GetSubmitReports(bool* aSubmitReport);
164 nsresult SetSubmitReports(bool aSubmitReport);
165 
166 // Out-of-process crash reporter API.
167 
168 #ifdef XP_WIN
169 // This data is stored in the parent process, there is one copy for each child
170 // process. The mChildPid and mMinidumpFile fields are filled by the WER runtime
171 // exception module when the associated child process crashes.
172 struct WindowsErrorReportingData {
173   // Points to the WerNotifyProc function.
174   LPTHREAD_START_ROUTINE mWerNotifyProc;
175   // PID of the child process that crashed.
176   DWORD mChildPid;
177   // Filename of the generated minidump; this is not a 0-terminated string
178   char mMinidumpFile[40];
179   // OOM allocation size for the crash (ignore if zero)
180   size_t mOOMAllocationSize;
181 };
182 #endif  // XP_WIN
183 
184 // Initializes out-of-process crash reporting. This method must be called
185 // before the platform-specific notification pipe APIs are called. If called
186 // from off the main thread, this method will synchronously proxy to the main
187 // thread.
188 void OOPInit();
189 
190 // Return true if a dump was found for |childPid|, and return the
191 // path in |dump|.  The caller owns the last reference to |dump| if it
192 // is non-nullptr. The annotations for the crash will be stored in
193 // |aAnnotations|. The sequence parameter will be filled with an ordinal
194 // indicating which remote process crashed first.
195 bool TakeMinidumpForChild(uint32_t childPid, nsIFile** dump,
196                           AnnotationTable& aAnnotations,
197                           uint32_t* aSequence = nullptr);
198 
199 /**
200  * If a dump was found for |childPid| then write a minimal .extra file to
201  * complete it and remove it from the list of pending crash dumps. It's
202  * required to call this method after a non-main process crash if the crash
203  * report could not be finalized via the CrashReporterHost (for example because
204  * it wasn't instanced yet).
205  *
206  * @param aChildPid The pid of the crashed child process
207  * @param aType The type of the crashed process
208  * @param aDumpId A string that will be filled with the dump ID
209  */
210 [[nodiscard]] bool FinalizeOrphanedMinidump(uint32_t aChildPid,
211                                             GeckoProcessType aType,
212                                             nsString* aDumpId = nullptr);
213 
214 #if defined(XP_WIN)
215 typedef HANDLE ProcessHandle;
216 typedef DWORD ProcessId;
217 typedef DWORD ThreadId;
218 typedef HANDLE FileHandle;
219 const FileHandle kInvalidFileHandle = INVALID_HANDLE_VALUE;
220 #elif defined(XP_MACOSX)
221 typedef task_t ProcessHandle;
222 typedef pid_t ProcessId;
223 typedef mach_port_t ThreadId;
224 typedef int FileHandle;
225 const FileHandle kInvalidFileHandle = -1;
226 #else
227 typedef int ProcessHandle;
228 typedef pid_t ProcessId;
229 typedef int ThreadId;
230 typedef int FileHandle;
231 const FileHandle kInvalidFileHandle = -1;
232 #endif
233 
234 #if !defined(XP_WIN)
235 FileHandle GetAnnotationTimeCrashFd();
236 #endif
237 void RegisterChildCrashAnnotationFileDescriptor(ProcessId aProcess,
238                                                 PRFileDesc* aFd);
239 void DeregisterChildCrashAnnotationFileDescriptor(ProcessId aProcess);
240 
241 // Return the current thread's ID.
242 //
243 // XXX: this is a somewhat out-of-place interface to expose through
244 // crashreporter, but it takes significant work to call sys_gettid()
245 // correctly on Linux and breakpad has already jumped through those
246 // hoops for us.
247 ThreadId CurrentThreadId();
248 
249 /*
250  * Take a minidump of the target process and pair it with an incoming minidump
251  * provided by the caller or a new minidump of the calling process and thread.
252  * The caller will own both dumps after this call. If this function fails
253  * it will attempt to delete any files that were created.
254  *
255  * The .extra information created will not include an 'additional_minidumps'
256  * annotation.
257  *
258  * @param aTargetPid The target process for the minidump.
259  * @param aTargetBlamedThread The target thread for the minidump.
260  * @param aIncomingPairName The name to apply to the paired dump the caller
261  *   passes in.
262  * @param aIncomingDumpToPair Existing dump to pair with the new dump. if this
263  *   is null, TakeMinidumpAndPair will take a new minidump of the calling
264  *   process and thread and use it in aIncomingDumpToPairs place.
265  * @param aTargetDumpOut The target minidump file paired up with
266  *   aIncomingDumpToPair.
267  * @param aTargetAnnotations The crash annotations of the target process.
268  * @return bool indicating success or failure
269  */
270 bool CreateMinidumpsAndPair(ProcessHandle aTargetPid,
271                             ThreadId aTargetBlamedThread,
272                             const nsACString& aIncomingPairName,
273                             nsIFile* aIncomingDumpToPair,
274                             AnnotationTable& aTargetAnnotations,
275                             nsIFile** aTargetDumpOut);
276 
277 // Create an additional minidump for a child of a process which already has
278 // a minidump (|parentMinidump|).
279 // The resulting dump will get the id of the parent and use the |name| as
280 // an extension.
281 bool CreateAdditionalChildMinidump(ProcessHandle childPid,
282                                    ThreadId childBlamedThread,
283                                    nsIFile* parentMinidump,
284                                    const nsACString& name);
285 
286 #if defined(XP_WIN) || defined(XP_MACOSX)
287 // Parent-side API for children
288 const char* GetChildNotificationPipe();
289 
290 #  ifdef MOZ_CRASHREPORTER_INJECTOR
291 // Inject a crash report client into an arbitrary process, and inform the
292 // callback object when it crashes. Parent process only.
293 
294 class InjectorCrashCallback {
295  public:
InjectorCrashCallback()296   InjectorCrashCallback() {}
297 
298   /**
299    * Inform the callback of a crash. The client code should call
300    * TakeMinidumpForChild to remove it from the PID mapping table.
301    *
302    * The callback will not be fired if the client has already called
303    * TakeMinidumpForChild for this process ID.
304    */
305   virtual void OnCrash(DWORD processID) = 0;
306 };
307 
308 // This method implies OOPInit
309 void InjectCrashReporterIntoProcess(DWORD processID, InjectorCrashCallback* cb);
310 void UnregisterInjectorCallback(DWORD processID);
311 #  endif
312 #else
313 // Parent-side API for children
314 
315 // Set the outparams for crash reporter server's fd (|childCrashFd|)
316 // and the magic fd number it should be remapped to
317 // (|childCrashRemapFd|) before exec() in the child process.
318 // |SetRemoteExceptionHandler()| in the child process expects to find
319 // the server at |childCrashRemapFd|.  Return true if successful.
320 //
321 // If crash reporting is disabled, both outparams will be set to -1
322 // and |true| will be returned.
323 bool CreateNotificationPipeForChild(int* childCrashFd, int* childCrashRemapFd);
324 
325 #endif  // XP_WIN
326 
327 // Windows Error Reporting helper
328 #if defined(XP_WIN)
329 DWORD WINAPI WerNotifyProc(LPVOID aParameter);
330 #endif
331 
332 // Child-side API
333 bool SetRemoteExceptionHandler(
334     const char* aCrashPipe = nullptr,
335     FileHandle aCrashTimeAnnotationFile = kInvalidFileHandle);
336 bool UnsetRemoteExceptionHandler();
337 
338 #if defined(MOZ_WIDGET_ANDROID)
339 // Android creates child process as services so we must explicitly set
340 // the handle for the pipe since it can't get remapped to a default value.
341 void SetNotificationPipeForChild(FileHandle childCrashFd);
342 void SetCrashAnnotationPipeForChild(FileHandle childCrashAnnotationFd);
343 #endif
344 
345 // Annotates the crash report with the name of the calling thread.
346 void SetCurrentThreadName(const char* aName);
347 
348 }  // namespace CrashReporter
349 
350 #endif /* nsExceptionHandler_h__ */
351