exception_handler.h revision 662b6da59dd0218ea5496c085cb010d59f2b4219
1// Copyright (c) 2010 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#ifndef CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_ 31#define CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_ 32 33#include <vector> 34#include <string> 35 36#include <signal.h> 37#include <stdio.h> 38 39#include "client/linux/crash_generation/crash_generation_client.h" 40#include "processor/scoped_ptr.h" 41 42struct sigaction; 43 44namespace google_breakpad { 45 46class ExceptionHandler; 47 48// ExceptionHandler 49// 50// ExceptionHandler can write a minidump file when an exception occurs, 51// or when WriteMinidump() is called explicitly by your program. 52// 53// To have the exception handler write minidumps when an uncaught exception 54// (crash) occurs, you should create an instance early in the execution 55// of your program, and keep it around for the entire time you want to 56// have crash handling active (typically, until shutdown). 57// (NOTE): There should be only be one this kind of exception handler 58// object per process. 59// 60// If you want to write minidumps without installing the exception handler, 61// you can create an ExceptionHandler with install_handler set to false, 62// then call WriteMinidump. You can also use this technique if you want to 63// use different minidump callbacks for different call sites. 64// 65// In either case, a callback function is called when a minidump is written, 66// which receives the unqiue id of the minidump. The caller can use this 67// id to collect and write additional application state, and to launch an 68// external crash-reporting application. 69// 70// Caller should try to make the callbacks as crash-friendly as possible, 71// it should avoid use heap memory allocation as much as possible. 72class ExceptionHandler { 73 public: 74 // A callback function to run before Breakpad performs any substantial 75 // processing of an exception. A FilterCallback is called before writing 76 // a minidump. context is the parameter supplied by the user as 77 // callback_context when the handler was created. 78 // 79 // If a FilterCallback returns true, Breakpad will continue processing, 80 // attempting to write a minidump. If a FilterCallback returns false, 81 // Breakpad will immediately report the exception as unhandled without 82 // writing a minidump, allowing another handler the opportunity to handle it. 83 typedef bool (*FilterCallback)(void *context); 84 85 // A callback function to run after the minidump has been written. 86 // minidump_id is a unique id for the dump, so the minidump 87 // file is <dump_path>\<minidump_id>.dmp. context is the parameter supplied 88 // by the user as callback_context when the handler was created. succeeded 89 // indicates whether a minidump file was successfully written. 90 // 91 // If an exception occurred and the callback returns true, Breakpad will 92 // treat the exception as fully-handled, suppressing any other handlers from 93 // being notified of the exception. If the callback returns false, Breakpad 94 // will treat the exception as unhandled, and allow another handler to handle 95 // it. If there are no other handlers, Breakpad will report the exception to 96 // the system as unhandled, allowing a debugger or native crash dialog the 97 // opportunity to handle the exception. Most callback implementations 98 // should normally return the value of |succeeded|, or when they wish to 99 // not report an exception of handled, false. Callbacks will rarely want to 100 // return true directly (unless |succeeded| is true). 101 typedef bool (*MinidumpCallback)(const char *dump_path, 102 const char *minidump_id, 103 void *context, 104 bool succeeded); 105 106 // In certain cases, a user may wish to handle the generation of the minidump 107 // themselves. In this case, they can install a handler callback which is 108 // called when a crash has occured. If this function returns true, no other 109 // processing of occurs and the process will shortly be crashed. If this 110 // returns false, the normal processing continues. 111 typedef bool (*HandlerCallback)(const void* crash_context, 112 size_t crash_context_size, 113 void* context); 114 115 // Creates a new ExceptionHandler instance to handle writing minidumps. 116 // Before writing a minidump, the optional filter callback will be called. 117 // Its return value determines whether or not Breakpad should write a 118 // minidump. Minidump files will be written to dump_path, and the optional 119 // callback is called after writing the dump file, as described above. 120 // If install_handler is true, then a minidump will be written whenever 121 // an unhandled exception occurs. If it is false, minidumps will only 122 // be written when WriteMinidump is called. 123 ExceptionHandler(const std::string &dump_path, 124 FilterCallback filter, MinidumpCallback callback, 125 void *callback_context, 126 bool install_handler); 127 128 // Creates a new ExceptionHandler instance that can attempt to 129 // perform out-of-process dump generation if server_fd is valid. If 130 // server_fd is invalid, in-process dump generation will be 131 // used. See the above ctor for a description of the other 132 // parameters. 133 ExceptionHandler(const std::string& dump_path, 134 FilterCallback filter, MinidumpCallback callback, 135 void* callback_context, 136 bool install_handler, 137 const int server_fd); 138 139 ~ExceptionHandler(); 140 141 // Get and set the minidump path. 142 std::string dump_path() const { return dump_path_; } 143 void set_dump_path(const std::string &dump_path) { 144 dump_path_ = dump_path; 145 dump_path_c_ = dump_path_.c_str(); 146 UpdateNextID(); 147 } 148 149 void set_crash_handler(HandlerCallback callback) { 150 crash_handler_ = callback; 151 } 152 153 // Writes a minidump immediately. This can be used to capture the 154 // execution state independently of a crash. Returns true on success. 155 bool WriteMinidump(); 156 157 // Convenience form of WriteMinidump which does not require an 158 // ExceptionHandler instance. 159 static bool WriteMinidump(const std::string &dump_path, 160 MinidumpCallback callback, 161 void *callback_context); 162 163 // This structure is passed to minidump_writer.h:WriteMinidump via an opaque 164 // blob. It shouldn't be needed in any user code. 165 struct CrashContext { 166 siginfo_t siginfo; 167 pid_t tid; // the crashing thread. 168 struct ucontext context; 169#if !defined(__ARM_EABI__) 170 // #ifdef this out because FP state is not part of user ABI for Linux ARM. 171 struct _libc_fpstate float_state; 172#endif 173 }; 174 175 // Returns whether out-of-process dump generation is used or not. 176 bool IsOutOfProcess() const { 177 return crash_generation_client_.get() != NULL; 178 } 179 180 private: 181 void Init(const std::string &dump_path, 182 const int server_fd); 183 bool InstallHandlers(); 184 void UninstallHandlers(); 185 void PreresolveSymbols(); 186 bool GenerateDump(CrashContext *context); 187 void SendContinueSignalToChild(); 188 void WaitForContinueSignal(); 189 190 void UpdateNextID(); 191 static void SignalHandler(int sig, siginfo_t* info, void* uc); 192 bool HandleSignal(int sig, siginfo_t* info, void* uc); 193 static int ThreadEntry(void* arg); 194 bool DoDump(pid_t crashing_process, const void* context, 195 size_t context_size); 196 197 const FilterCallback filter_; 198 const MinidumpCallback callback_; 199 void* const callback_context_; 200 201 scoped_ptr<CrashGenerationClient> crash_generation_client_; 202 203 std::string dump_path_; 204 std::string next_minidump_path_; 205 std::string next_minidump_id_; 206 207 // Pointers to C-string representations of the above. These are set 208 // when the above are set so we can avoid calling c_str during 209 // an exception. 210 const char* dump_path_c_; 211 const char* next_minidump_path_c_; 212 const char* next_minidump_id_c_; 213 214 const bool handler_installed_; 215 void* signal_stack; // the handler stack. 216 HandlerCallback crash_handler_; 217 218 // The global exception handler stack. This is need becuase there may exist 219 // multiple ExceptionHandler instances in a process. Each will have itself 220 // registered in this stack. 221 static std::vector<ExceptionHandler*> *handler_stack_; 222 // The index of the handler that should handle the next exception. 223 static unsigned handler_stack_index_; 224 static pthread_mutex_t handler_stack_mutex_; 225 226 // A vector of the old signal handlers. 227 std::vector<std::pair<int, struct sigaction *> > old_handlers_; 228 229 // We need to explicitly enable ptrace of parent processes on some 230 // kernels, but we need to know the PID of the cloned process before we 231 // can do this. We create a pipe which we can use to block the 232 // cloned process after creating it, until we have explicitly enabled 233 // ptrace. This is used to store the file descriptors for the pipe 234 int fdes[2]; 235}; 236 237} // namespace google_breakpad 238 239#endif // CLIENT_LINUX_HANDLER_EXCEPTION_HANDLER_H_ 240