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