xref: /aosp_15_r20/external/google-breakpad/src/client/mac/handler/exception_handler.h (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
1 // Copyright 2006 Google LLC
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 //     * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 //     * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 //     * Neither the name of Google LLC nor the names of its
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 // exception_handler.h:  MacOS exception handler
30 // This class can install a Mach exception port handler to trap most common
31 // programming errors.  If an exception occurs, a minidump file will be
32 // generated which contains detailed information about the process and the
33 // exception.
34 
35 #ifndef CLIENT_MAC_HANDLER_EXCEPTION_HANDLER_H__
36 #define CLIENT_MAC_HANDLER_EXCEPTION_HANDLER_H__
37 
38 #include <mach/mach.h>
39 #include <TargetConditionals.h>
40 
41 #include <string>
42 
43 #include "client/mac/handler/ucontext_compat.h"
44 #include "common/scoped_ptr.h"
45 
46 #if !TARGET_OS_IPHONE
47 #include "client/mac/crash_generation/crash_generation_client.h"
48 #endif
49 
50 namespace google_breakpad {
51 
52 using std::string;
53 
54 struct ExceptionParameters;
55 
56 enum HandlerThreadMessage {
57   // Message ID telling the handler thread to write a dump.
58   kWriteDumpMessage = 0,
59   // Message ID telling the handler thread to write a dump and include
60   // an exception stream.
61   kWriteDumpWithExceptionMessage = 1,
62   // Message ID telling the handler thread to quit.
63   kShutdownMessage = 2
64 };
65 
66 class ExceptionHandler {
67  public:
68   // A callback function to run before Breakpad performs any substantial
69   // processing of an exception.  A FilterCallback is called before writing
70   // a minidump.  context is the parameter supplied by the user as
71   // callback_context when the handler was created.
72   //
73   // If a FilterCallback returns true, Breakpad will continue processing,
74   // attempting to write a minidump.  If a FilterCallback returns false, Breakpad
75   // will immediately report the exception as unhandled without writing a
76   // minidump, allowing another handler the opportunity to handle it.
77   typedef bool (*FilterCallback)(void* context);
78 
79   // A callback function to run after the minidump has been written.
80   // |minidump_id| is a unique id for the dump, so the minidump
81   // file is <dump_dir>/<minidump_id>.dmp.
82   // |context| is the value passed into the constructor.
83   // |succeeded| indicates whether a minidump file was successfully written.
84   // Return true if the exception was fully handled and breakpad should exit.
85   // Return false to allow any other exception handlers to process the
86   // exception.
87   typedef bool (*MinidumpCallback)(const char* dump_dir,
88                                    const char* minidump_id,
89                                    void* context, bool succeeded);
90 
91   // A callback function which will be called directly if an exception occurs.
92   // This bypasses the minidump file writing and simply gives the client
93   // the exception information.
94   typedef bool (*DirectCallback)(void* context,
95                                  int exception_type,
96                                  int exception_code,
97                                  int exception_subcode,
98                                  mach_port_t thread_name);
99 
100   // Creates a new ExceptionHandler instance to handle writing minidumps.
101   // Minidump files will be written to dump_path, and the optional callback
102   // is called after writing the dump file, as described above.
103   // If install_handler is true, then a minidump will be written whenever
104   // an unhandled exception occurs.  If it is false, minidumps will only
105   // be written when WriteMinidump is called.
106   // If port_name is non-NULL, attempt to perform out-of-process dump generation
107   // If port_name is NULL, in-process dump generation will be used.
108   ExceptionHandler(const string& dump_path,
109                    FilterCallback filter, MinidumpCallback callback,
110                    void* callback_context, bool install_handler,
111                    const char* port_name);
112 
113   // A special constructor if we want to bypass minidump writing and
114   // simply get a callback with the exception information.
115   ExceptionHandler(DirectCallback callback,
116                    void* callback_context,
117                    bool install_handler);
118 
119   ~ExceptionHandler();
120 
121   // Get and set the minidump path.
dump_path()122   string dump_path() const { return dump_path_; }
set_dump_path(const string & dump_path)123   void set_dump_path(const string& dump_path) {
124     dump_path_ = dump_path;
125     dump_path_c_ = dump_path_.c_str();
126     UpdateNextID();  // Necessary to put dump_path_ in next_minidump_path_.
127   }
128 
129   // Writes a minidump immediately.  This can be used to capture the
130   // execution state independently of a crash.  Returns true on success.
WriteMinidump()131   bool WriteMinidump() {
132     return WriteMinidump(false);
133   }
134 
135   bool WriteMinidump(bool write_exception_stream);
136 
137   // Convenience form of WriteMinidump which does not require an
138   // ExceptionHandler instance.
WriteMinidump(const string & dump_path,MinidumpCallback callback,void * callback_context)139   static bool WriteMinidump(const string& dump_path, MinidumpCallback callback,
140                             void* callback_context) {
141     return WriteMinidump(dump_path, false, callback, callback_context);
142   }
143 
144   static bool WriteMinidump(const string& dump_path,
145                             bool write_exception_stream,
146                             MinidumpCallback callback,
147                             void* callback_context);
148 
149   // Write a minidump of child immediately. This can be used to capture
150   // the execution state of a child process independently of a crash.
151   static bool WriteMinidumpForChild(mach_port_t child,
152                                     mach_port_t child_blamed_thread,
153                                     const std::string& dump_path,
154                                     MinidumpCallback callback,
155                                     void* callback_context);
156 
157   // Returns whether out-of-process dump generation is used or not.
IsOutOfProcess()158   bool IsOutOfProcess() const {
159 #if TARGET_OS_IPHONE
160     return false;
161 #else
162     return crash_generation_client_.get() != NULL;
163 #endif
164   }
165 
166  private:
167   // Install the mach exception handler
168   bool InstallHandler();
169 
170   // Uninstall the mach exception handler (if any)
171   bool UninstallHandler(bool in_exception);
172 
173   // Setup the handler thread, and if |install_handler| is true, install the
174   // mach exception port handler
175   bool Setup(bool install_handler);
176 
177   // Uninstall the mach exception handler (if any) and terminate the helper
178   // thread
179   bool Teardown();
180 
181   // Send a mach message to the exception handler.  Return true on
182   // success, false otherwise.
183   bool SendMessageToHandlerThread(HandlerThreadMessage message_id);
184 
185   // All minidump writing goes through this one routine.
186   // |task_context| can be NULL. If not, it will be used to retrieve the
187   // context of the current thread, instead of using |thread_get_state|.
188   bool WriteMinidumpWithException(int exception_type,
189                                   int exception_code,
190                                   int exception_subcode,
191                                   breakpad_ucontext_t* task_context,
192                                   mach_port_t thread_name,
193                                   bool exit_after_write,
194                                   bool report_current_thread);
195 
196   // When installed, this static function will be call from a newly created
197   // pthread with |this| as the argument
198   static void* WaitForMessage(void* exception_handler_class);
199 
200   // Signal handler for SIGABRT.
201   static void SignalHandler(int sig, siginfo_t* info, void* uc);
202 
203   // disallow copy ctor and operator=
204   explicit ExceptionHandler(const ExceptionHandler&);
205   void operator=(const ExceptionHandler&);
206 
207   // Generates a new ID and stores it in next_minidump_id_, and stores the
208   // path of the next minidump to be written in next_minidump_path_.
209   void UpdateNextID();
210 
211   // These functions will suspend/resume all threads except for the
212   // reporting thread
213   bool SuspendThreads();
214   bool ResumeThreads();
215 
216   // The destination directory for the minidump
217   string dump_path_;
218 
219   // The basename of the next minidump w/o extension
220   string next_minidump_id_;
221 
222   // The full path to the next minidump to be written, including extension
223   string next_minidump_path_;
224 
225   // Pointers to the UTF-8 versions of above
226   const char* dump_path_c_;
227   const char* next_minidump_id_c_;
228   const char* next_minidump_path_c_;
229 
230   // The callback function and pointer to be passed back after the minidump
231   // has been written
232   FilterCallback filter_;
233   MinidumpCallback callback_;
234   void* callback_context_;
235 
236   // The callback function to be passed back when we don't want a minidump
237   // file to be written
238   DirectCallback directCallback_;
239 
240   // The thread that is created for the handler
241   pthread_t handler_thread_;
242 
243   // The port that is waiting on an exception message to be sent, if the
244   // handler is installed
245   mach_port_t handler_port_;
246 
247   // These variables save the previous exception handler's data so that it
248   // can be re-installed when this handler is uninstalled
249   ExceptionParameters* previous_;
250 
251   // True, if we've installed the exception handler
252   bool installed_exception_handler_;
253 
254   // True, if we're in the process of uninstalling the exception handler and
255   // the thread.
256   bool is_in_teardown_;
257 
258   // Save the last result of the last minidump
259   bool last_minidump_write_result_;
260 
261   // A mutex for use when writing out a minidump that was requested on a
262   // thread other than the exception handler.
263   pthread_mutex_t minidump_write_mutex_;
264 
265   // True, if we're using the mutext to indicate when mindump writing occurs
266   bool use_minidump_write_mutex_;
267 
268   // Old signal handler for SIGABRT. Used to be able to restore it when
269   // uninstalling.
270   scoped_ptr<struct sigaction> old_handler_;
271 
272 #if !TARGET_OS_IPHONE
273   // Client for out-of-process dump generation.
274   scoped_ptr<CrashGenerationClient> crash_generation_client_;
275 #endif
276 };
277 
278 }  // namespace google_breakpad
279 
280 #endif  // CLIENT_MAC_HANDLER_EXCEPTION_HANDLER_H__
281