diff options
Diffstat (limited to 'src/client/mac/handler/exception_handler.cc')
-rw-r--r-- | src/client/mac/handler/exception_handler.cc | 98 |
1 files changed, 68 insertions, 30 deletions
diff --git a/src/client/mac/handler/exception_handler.cc b/src/client/mac/handler/exception_handler.cc index e540df23..8f87dd83 100644 --- a/src/client/mac/handler/exception_handler.cc +++ b/src/client/mac/handler/exception_handler.cc @@ -133,6 +133,7 @@ ExceptionHandler::ExceptionHandler(const string &dump_path, filter_(filter), callback_(callback), callback_context_(callback_context), + directCallback_(NULL), handler_thread_(NULL), handler_port_(0), previous_(NULL), @@ -146,6 +147,27 @@ ExceptionHandler::ExceptionHandler(const string &dump_path, Setup(install_handler); } +// special constructor if we want to bypass minidump writing and +// simply get a callback with the exception information +ExceptionHandler::ExceptionHandler(DirectCallback callback, + void *callback_context, + bool install_handler) + : dump_path_(), + filter_(NULL), + callback_(NULL), + callback_context_(callback_context), + directCallback_(callback), + handler_thread_(NULL), + handler_port_(0), + previous_(NULL), + installed_exception_handler_(false), + is_in_teardown_(false), + last_minidump_write_result_(false), + use_minidump_write_mutex_(false) { + MinidumpGenerator::GatherSystemInformation(); + Setup(install_handler); +} + ExceptionHandler::~ExceptionHandler() { Teardown(); } @@ -186,36 +208,47 @@ bool ExceptionHandler::WriteMinidumpWithException(int exception_type, int exception_code, mach_port_t thread_name) { bool result = false; - string minidump_id; - - // Putting the MinidumpGenerator in its own context will ensure that the - // destructor is executed, closing the newly created minidump file. - if (!dump_path_.empty()) { - MinidumpGenerator md; - if (exception_type && exception_code) { - // If this is a real exception, give the filter (if any) a chance to - // decided if this should be sent - if (filter_ && !filter_(callback_context_)) - return false; - md.SetExceptionInformation(exception_type, exception_code, thread_name); + if (directCallback_) { + if (directCallback_(callback_context_, + exception_type, + exception_code, + thread_name) ) { + if (exception_type && exception_code) + exit(exception_type); } + } else { + string minidump_id; + + // Putting the MinidumpGenerator in its own context will ensure that the + // destructor is executed, closing the newly created minidump file. + if (!dump_path_.empty()) { + MinidumpGenerator md; + if (exception_type && exception_code) { + // If this is a real exception, give the filter (if any) a chance to + // decided if this should be sent + if (filter_ && !filter_(callback_context_)) + return false; + + md.SetExceptionInformation(exception_type, exception_code, thread_name); + } - result = md.Write(next_minidump_path_c_); - } + result = md.Write(next_minidump_path_c_); + } - // Call user specified callback (if any) - if (callback_) { - // If the user callback returned true and we're handling an exception - // (rather than just writing out the file), then we should exit without - // forwarding the exception to the next handler. - if (callback_(dump_path_c_, next_minidump_id_c_, callback_context_, - result)) { - if (exception_type && exception_code) - exit(exception_type); + // Call user specified callback (if any) + if (callback_) { + // If the user callback returned true and we're handling an exception + // (rather than just writing out the file), then we should exit without + // forwarding the exception to the next handler. + if (callback_(dump_path_c_, next_minidump_id_c_, callback_context_, + result)) { + if (exception_type && exception_code) + exit(exception_type); + } } } - + return result; } @@ -326,14 +359,11 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) { MACH_RCV_MSG | MACH_RCV_LARGE, 0, sizeof(receive), self->handler_port_, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); - if (result == KERN_SUCCESS) { // Uninstall our handler so that we don't get in a loop if the process of // writing out a minidump causes an exception. However, if the exception // was caused by a fork'd process, don't uninstall things if (receive.task.name == mach_task_self()) - self->UninstallHandler(); - // If the actual exception code is zero, then we're calling this handler // in a way that indicates that we want to either exit this thread or // generate a minidump @@ -342,6 +372,8 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) { // to avoid misleading stacks. If appropriate they will be resumed // afterwards. if (!receive.exception) { + self->UninstallHandler(false); + if (self->is_in_teardown_) return NULL; @@ -356,6 +388,8 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) { if (self->use_minidump_write_mutex_) pthread_mutex_unlock(&self->minidump_write_mutex_); } else { + self->UninstallHandler(true); + // When forking a child process with the exception handler installed, // if the child crashes, it will send the exception back to the parent // process. The check for task == self_task() ensures that only @@ -419,7 +453,7 @@ bool ExceptionHandler::InstallHandler() { return installed_exception_handler_; } -bool ExceptionHandler::UninstallHandler() { +bool ExceptionHandler::UninstallHandler(bool in_exception) { kern_return_t result = KERN_SUCCESS; if (installed_exception_handler_) { @@ -435,7 +469,11 @@ bool ExceptionHandler::UninstallHandler() { return false; } - delete previous_; + // this delete should NOT happen if an exception just occurred! + if (!in_exception) { + delete previous_; + } + previous_ = NULL; installed_exception_handler_ = false; } @@ -479,7 +517,7 @@ bool ExceptionHandler::Teardown() { kern_return_t result = KERN_SUCCESS; is_in_teardown_ = true; - if (!UninstallHandler()) + if (!UninstallHandler(false)) return false; // Send an empty message so that the handler_thread exits |