diff options
Diffstat (limited to 'src/client/windows/handler')
-rw-r--r-- | src/client/windows/handler/exception_handler.cc | 422 | ||||
-rw-r--r-- | src/client/windows/handler/exception_handler.h | 92 |
2 files changed, 336 insertions, 178 deletions
diff --git a/src/client/windows/handler/exception_handler.cc b/src/client/windows/handler/exception_handler.cc index cd1d7f26..fc678a91 100644 --- a/src/client/windows/handler/exception_handler.cc +++ b/src/client/windows/handler/exception_handler.cc @@ -41,80 +41,127 @@ namespace google_breakpad { static const int kExceptionHandlerThreadInitialStackSize = 64 * 1024; -vector<ExceptionHandler *> *ExceptionHandler::handler_stack_ = NULL; +vector<ExceptionHandler*>* ExceptionHandler::handler_stack_ = NULL; LONG ExceptionHandler::handler_stack_index_ = 0; CRITICAL_SECTION ExceptionHandler::handler_stack_critical_section_; bool ExceptionHandler::handler_stack_critical_section_initialized_ = false; +ExceptionHandler::ExceptionHandler(const wstring& dump_path, + FilterCallback filter, + MinidumpCallback callback, + void* callback_context, + int handler_types, + MINIDUMP_TYPE dump_type, + const wchar_t* pipe_name) { + Initialize(dump_path, + filter, + callback, + callback_context, + handler_types, + dump_type, + pipe_name); +} + ExceptionHandler::ExceptionHandler(const wstring &dump_path, FilterCallback filter, MinidumpCallback callback, - void *callback_context, - int handler_types) - : filter_(filter), - callback_(callback), - callback_context_(callback_context), - dump_path_(), - next_minidump_id_(), - next_minidump_path_(), - dump_path_c_(), - next_minidump_id_c_(NULL), - next_minidump_path_c_(NULL), - dbghelp_module_(NULL), - minidump_write_dump_(NULL), - rpcrt4_module_(NULL), - uuid_create_(NULL), - handler_types_(handler_types), - previous_filter_(NULL), - previous_pch_(NULL), - handler_thread_(0), - handler_critical_section_(), - handler_start_semaphore_(NULL), - handler_finish_semaphore_(NULL), - requesting_thread_id_(0), - exception_info_(NULL), - assertion_(NULL), - handler_return_value_(false), - handle_debug_exceptions_(false) { + void* callback_context, + int handler_types) { + Initialize(dump_path, + filter, + callback, + callback_context, + handler_types, + MiniDumpNormal, + NULL); +} + +void ExceptionHandler::Initialize(const wstring& dump_path, + FilterCallback filter, + MinidumpCallback callback, + void* callback_context, + int handler_types, + MINIDUMP_TYPE dump_type, + const wchar_t* pipe_name) { + filter_ = filter; + callback_ = callback; + callback_context_ = callback_context; + dump_path_c_ = NULL; + next_minidump_id_c_ = NULL; + next_minidump_path_c_ = NULL; + dbghelp_module_ = NULL; + minidump_write_dump_ = NULL; + dump_type_ = dump_type; + rpcrt4_module_ = NULL; + uuid_create_ = NULL; + handler_types_ = handler_types; + previous_filter_ = NULL; #if _MSC_VER >= 1400 // MSVC 2005/8 previous_iph_ = NULL; #endif // _MSC_VER >= 1400 - - // Set synchronization primitives and the handler thread. Each - // ExceptionHandler object gets its own handler thread because that's the - // only way to reliably guarantee sufficient stack space in an exception, - // and it allows an easy way to get a snapshot of the requesting thread's - // context outside of an exception. - InitializeCriticalSection(&handler_critical_section_); - handler_start_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL); - handler_finish_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL); - - DWORD thread_id; - handler_thread_ = CreateThread(NULL, // lpThreadAttributes - kExceptionHandlerThreadInitialStackSize, - ExceptionHandlerThreadMain, - this, // lpParameter - 0, // dwCreationFlags - &thread_id); - - dbghelp_module_ = LoadLibrary(L"dbghelp.dll"); - if (dbghelp_module_) { - minidump_write_dump_ = reinterpret_cast<MiniDumpWriteDump_type>( - GetProcAddress(dbghelp_module_, "MiniDumpWriteDump")); + previous_pch_ = NULL; + handler_thread_ = NULL; + handler_start_semaphore_ = NULL; + handler_finish_semaphore_ = NULL; + requesting_thread_id_ = 0; + exception_info_ = NULL; + assertion_ = NULL; + handler_return_value_ = false; + handle_debug_exceptions_ = false; + + // Attempt to use out-of-process if user has specified pipe name. + if (pipe_name != NULL) { + scoped_ptr<CrashGenerationClient> client( + new CrashGenerationClient(pipe_name, dump_type_)); + + // If successful in registering with the monitoring process, + // there is no need to setup in-process crash generation. + if (client->Register()) { + crash_generation_client_.reset(client.release()); + } } - // Load this library dynamically to not affect existing projects. Most - // projects don't link against this directly, it's usually dynamically - // loaded by dependent code. - rpcrt4_module_ = LoadLibrary(L"rpcrt4.dll"); - if (rpcrt4_module_) { - uuid_create_ = reinterpret_cast<UuidCreate_type>( - GetProcAddress(rpcrt4_module_, "UuidCreate")); - } + if (!IsOutOfProcess()) { + // Either client did not ask for out-of-process crash generation + // or registration with the server process failed. In either case, + // setup to do in-process crash generation. + + // Set synchronization primitives and the handler thread. Each + // ExceptionHandler object gets its own handler thread because that's the + // only way to reliably guarantee sufficient stack space in an exception, + // and it allows an easy way to get a snapshot of the requesting thread's + // context outside of an exception. + InitializeCriticalSection(&handler_critical_section_); + handler_start_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL); + handler_finish_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL); + + DWORD thread_id; + handler_thread_ = CreateThread(NULL, // lpThreadAttributes + kExceptionHandlerThreadInitialStackSize, + ExceptionHandlerThreadMain, + this, // lpParameter + 0, // dwCreationFlags + &thread_id); + + dbghelp_module_ = LoadLibrary(L"dbghelp.dll"); + if (dbghelp_module_) { + minidump_write_dump_ = reinterpret_cast<MiniDumpWriteDump_type>( + GetProcAddress(dbghelp_module_, "MiniDumpWriteDump")); + } - // set_dump_path calls UpdateNextID. This sets up all of the path and id - // strings, and their equivalent c_str pointers. - set_dump_path(dump_path); + // Load this library dynamically to not affect existing projects. Most + // projects don't link against this directly, it's usually dynamically + // loaded by dependent code. + rpcrt4_module_ = LoadLibrary(L"rpcrt4.dll"); + if (rpcrt4_module_) { + uuid_create_ = reinterpret_cast<UuidCreate_type>( + GetProcAddress(rpcrt4_module_, "UuidCreate")); + } + + // set_dump_path calls UpdateNextID. This sets up all of the path and id + // strings, and their equivalent c_str pointers. + set_dump_path(dump_path); + } if (handler_types != HANDLER_NONE) { if (!handler_stack_critical_section_initialized_) { @@ -127,7 +174,7 @@ ExceptionHandler::ExceptionHandler(const wstring &dump_path, // The first time an ExceptionHandler that installs a handler is // created, set up the handler stack. if (!handler_stack_) { - handler_stack_ = new vector<ExceptionHandler *>(); + handler_stack_ = new vector<ExceptionHandler*>(); } handler_stack_->push_back(this); @@ -175,7 +222,7 @@ ExceptionHandler::~ExceptionHandler() { // TODO(mmentovai): use advapi32!ReportEvent to log the warning to the // system's application event log. fprintf(stderr, "warning: removing Breakpad handler out of order\n"); - for (vector<ExceptionHandler *>::iterator iterator = + for (vector<ExceptionHandler*>::iterator iterator = handler_stack_->begin(); iterator != handler_stack_->end(); ++iterator) { @@ -195,16 +242,20 @@ ExceptionHandler::~ExceptionHandler() { LeaveCriticalSection(&handler_stack_critical_section_); } - // Clean up the handler thread and synchronization primitives. - TerminateThread(handler_thread_, 1); - DeleteCriticalSection(&handler_critical_section_); - CloseHandle(handler_start_semaphore_); - CloseHandle(handler_finish_semaphore_); + // Some of the objects were only initialized if out of process + // registration was not done. + if (!IsOutOfProcess()) { + // Clean up the handler thread and synchronization primitives. + TerminateThread(handler_thread_, 1); + DeleteCriticalSection(&handler_critical_section_); + CloseHandle(handler_start_semaphore_); + CloseHandle(handler_finish_semaphore_); + } } // static -DWORD ExceptionHandler::ExceptionHandlerThreadMain(void *lpParameter) { - ExceptionHandler *self = reinterpret_cast<ExceptionHandler *>(lpParameter); +DWORD ExceptionHandler::ExceptionHandlerThreadMain(void* lpParameter) { + ExceptionHandler* self = reinterpret_cast<ExceptionHandler *>(lpParameter); assert(self); while (true) { @@ -276,16 +327,16 @@ class AutoExceptionHandler { LeaveCriticalSection(&ExceptionHandler::handler_stack_critical_section_); } - ExceptionHandler *get_handler() const { return handler_; } + ExceptionHandler* get_handler() const { return handler_; } private: - ExceptionHandler *handler_; + ExceptionHandler* handler_; }; // static -LONG ExceptionHandler::HandleException(EXCEPTION_POINTERS *exinfo) { +LONG ExceptionHandler::HandleException(EXCEPTION_POINTERS* exinfo) { AutoExceptionHandler auto_exception_handler; - ExceptionHandler *current_handler = auto_exception_handler.get_handler(); + ExceptionHandler* current_handler = auto_exception_handler.get_handler(); // Ignore EXCEPTION_BREAKPOINT and EXCEPTION_SINGLE_STEP exceptions. This // logic will short-circuit before calling WriteMinidumpOnHandlerThread, @@ -296,15 +347,35 @@ LONG ExceptionHandler::HandleException(EXCEPTION_POINTERS *exinfo) { LONG action; bool is_debug_exception = (code == EXCEPTION_BREAKPOINT) || (code == EXCEPTION_SINGLE_STEP); - if ((!is_debug_exception || current_handler->get_handle_debug_exceptions()) && - current_handler->WriteMinidumpOnHandlerThread(exinfo, NULL)) { - // The handler fully handled the exception. Returning - // EXCEPTION_EXECUTE_HANDLER indicates this to the system, and usually - // results in the applicaiton being terminated. - // - // Note: If the application was launched from within the Cygwin - // environment, returning EXCEPTION_EXECUTE_HANDLER seems to cause the - // application to be restarted. + + bool success = false; + + if (!is_debug_exception || + current_handler->get_handle_debug_exceptions()) { + // If out-of-proc crash handler client is available, we have to use that + // to generate dump and we cannot fall back on in-proc dump generation + // because we never prepared for an in-proc dump generation + + // In case of out-of-process dump generation, directly call + // WriteMinidumpWithException since there is no separate thread running. + if (current_handler->IsOutOfProcess()) { + success = current_handler->WriteMinidumpWithException( + GetCurrentThreadId(), + exinfo, + NULL); + } else { + success = current_handler->WriteMinidumpOnHandlerThread(exinfo, NULL); + } + } + + // The handler fully handled the exception. Returning + // EXCEPTION_EXECUTE_HANDLER indicates this to the system, and usually + // results in the application being terminated. + // + // Note: If the application was launched from within the Cygwin + // environment, returning EXCEPTION_EXECUTE_HANDLER seems to cause the + // application to be restarted. + if (success) { action = EXCEPTION_EXECUTE_HANDLER; } else { // There was an exception, it was a breakpoint or something else ignored @@ -327,35 +398,51 @@ LONG ExceptionHandler::HandleException(EXCEPTION_POINTERS *exinfo) { #if _MSC_VER >= 1400 // MSVC 2005/8 // static -void ExceptionHandler::HandleInvalidParameter(const wchar_t *expression, - const wchar_t *function, - const wchar_t *file, +void ExceptionHandler::HandleInvalidParameter(const wchar_t* expression, + const wchar_t* function, + const wchar_t* file, unsigned int line, uintptr_t reserved) { // This is an invalid parameter, not an exception. It's safe to play with // sprintf here. AutoExceptionHandler auto_exception_handler; - ExceptionHandler *current_handler = auto_exception_handler.get_handler(); + ExceptionHandler* current_handler = auto_exception_handler.get_handler(); MDRawAssertionInfo assertion; memset(&assertion, 0, sizeof(assertion)); - _snwprintf_s(reinterpret_cast<wchar_t *>(assertion.expression), + _snwprintf_s(reinterpret_cast<wchar_t*>(assertion.expression), sizeof(assertion.expression) / sizeof(assertion.expression[0]), _TRUNCATE, L"%s", expression); - _snwprintf_s(reinterpret_cast<wchar_t *>(assertion.function), + _snwprintf_s(reinterpret_cast<wchar_t*>(assertion.function), sizeof(assertion.function) / sizeof(assertion.function[0]), _TRUNCATE, L"%s", function); - _snwprintf_s(reinterpret_cast<wchar_t *>(assertion.file), + _snwprintf_s(reinterpret_cast<wchar_t*>(assertion.file), sizeof(assertion.file) / sizeof(assertion.file[0]), _TRUNCATE, L"%s", file); assertion.line = line; assertion.type = MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER; - if (!current_handler->WriteMinidumpOnHandlerThread(NULL, &assertion)) { + bool success = false; + // In case of out-of-process dump generation, directly call + // WriteMinidumpWithException since there is no separate thread running. + if (current_handler->IsOutOfProcess()) { + success = current_handler->WriteMinidumpWithException( + GetCurrentThreadId(), + NULL, + &assertion); + } else { + success = current_handler->WriteMinidumpOnHandlerThread(NULL, &assertion); + } + + if (!success) { if (current_handler->previous_iph_) { // The handler didn't fully handle the exception. Give it to the // previous invalid parameter handler. - current_handler->previous_iph_(expression, function, file, line, reserved); + current_handler->previous_iph_(expression, + function, + file, + line, + reserved); } else { // If there's no previous handler, pass the exception back in to the // invalid parameter handler's core. That's the routine that called this @@ -384,13 +471,26 @@ void ExceptionHandler::HandleInvalidParameter(const wchar_t *expression, // static void ExceptionHandler::HandlePureVirtualCall() { AutoExceptionHandler auto_exception_handler; - ExceptionHandler *current_handler = auto_exception_handler.get_handler(); + ExceptionHandler* current_handler = auto_exception_handler.get_handler(); MDRawAssertionInfo assertion; memset(&assertion, 0, sizeof(assertion)); assertion.type = MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL; - if (!current_handler->WriteMinidumpOnHandlerThread(NULL, &assertion)) { + bool success = false; + // In case of out-of-process dump generation, directly call + // WriteMinidumpWithException since there is no separate thread running. + + if (current_handler->IsOutOfProcess()) { + success = current_handler->WriteMinidumpWithException( + GetCurrentThreadId(), + NULL, + &assertion); + } else { + success = current_handler->WriteMinidumpOnHandlerThread(NULL, &assertion); + } + + if (!success) { if (current_handler->previous_pch_) { // The handler didn't fully handle the exception. Give it to the // previous purecall handler. @@ -409,7 +509,7 @@ void ExceptionHandler::HandlePureVirtualCall() { } bool ExceptionHandler::WriteMinidumpOnHandlerThread( - EXCEPTION_POINTERS *exinfo, MDRawAssertionInfo *assertion) { + EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion) { EnterCriticalSection(&handler_critical_section_); // Set up data to be passed in to the handler thread. @@ -438,7 +538,15 @@ bool ExceptionHandler::WriteMinidump() { return WriteMinidumpForException(NULL); } -bool ExceptionHandler::WriteMinidumpForException(EXCEPTION_POINTERS *exinfo) { +bool ExceptionHandler::WriteMinidumpForException(EXCEPTION_POINTERS* exinfo) { + // In case of out-of-process dump generation, directly call + // WriteMinidumpWithException since there is no separate thread running. + if (IsOutOfProcess()) { + return WriteMinidumpWithException(GetCurrentThreadId(), + exinfo, + NULL); + } + bool success = WriteMinidumpOnHandlerThread(exinfo, NULL); UpdateNextID(); return success; @@ -447,7 +555,7 @@ bool ExceptionHandler::WriteMinidumpForException(EXCEPTION_POINTERS *exinfo) { // static bool ExceptionHandler::WriteMinidump(const wstring &dump_path, MinidumpCallback callback, - void *callback_context) { + void* callback_context) { ExceptionHandler handler(dump_path, NULL, callback, callback_context, HANDLER_NONE); return handler.WriteMinidump(); @@ -455,8 +563,8 @@ bool ExceptionHandler::WriteMinidump(const wstring &dump_path, bool ExceptionHandler::WriteMinidumpWithException( DWORD requesting_thread_id, - EXCEPTION_POINTERS *exinfo, - MDRawAssertionInfo *assertion) { + EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion) { // Give user code a chance to approve or prevent writing a minidump. If the // filter returns false, don't handle the exception at all. If this method // was called as a result of an exception, returning false will cause @@ -468,63 +576,77 @@ bool ExceptionHandler::WriteMinidumpWithException( } bool success = false; - if (minidump_write_dump_) { - HANDLE dump_file = CreateFile(next_minidump_path_c_, - GENERIC_WRITE, - 0, // no sharing - NULL, - CREATE_NEW, // fail if exists - FILE_ATTRIBUTE_NORMAL, - NULL); - if (dump_file != INVALID_HANDLE_VALUE) { - MINIDUMP_EXCEPTION_INFORMATION except_info; - except_info.ThreadId = requesting_thread_id; - except_info.ExceptionPointers = exinfo; - except_info.ClientPointers = FALSE; - - // Add an MDRawBreakpadInfo stream to the minidump, to provide additional - // information about the exception handler to the Breakpad processor. The - // information will help the processor determine which threads are - // relevant. The Breakpad processor does not require this information but - // can function better with Breakpad-generated dumps when it is present. - // The native debugger is not harmed by the presence of this information. - MDRawBreakpadInfo breakpad_info; - breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID | - MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID; - breakpad_info.dump_thread_id = GetCurrentThreadId(); - breakpad_info.requesting_thread_id = requesting_thread_id; - - // Leave room in user_stream_array for a possible assertion info stream. - MINIDUMP_USER_STREAM user_stream_array[2]; - user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM; - user_stream_array[0].BufferSize = sizeof(breakpad_info); - user_stream_array[0].Buffer = &breakpad_info; - - MINIDUMP_USER_STREAM_INFORMATION user_streams; - user_streams.UserStreamCount = 1; - user_streams.UserStreamArray = user_stream_array; - - if (assertion) { - user_stream_array[1].Type = MD_ASSERTION_INFO_STREAM; - user_stream_array[1].BufferSize = sizeof(MDRawAssertionInfo); - user_stream_array[1].Buffer = assertion; - ++user_streams.UserStreamCount; - } + if (IsOutOfProcess()) { + // Use the EXCEPTION_POINTERS overload for RequestDump if + // both exinfo and assertion are NULL. + if (!assertion) { + success = crash_generation_client_->RequestDump(exinfo); + } else { + success = crash_generation_client_->RequestDump(assertion); + } + } else { + if (minidump_write_dump_) { + HANDLE dump_file = CreateFile(next_minidump_path_c_, + GENERIC_WRITE, + 0, // no sharing + NULL, + CREATE_NEW, // fail if exists + FILE_ATTRIBUTE_NORMAL, + NULL); + if (dump_file != INVALID_HANDLE_VALUE) { + MINIDUMP_EXCEPTION_INFORMATION except_info; + except_info.ThreadId = requesting_thread_id; + except_info.ExceptionPointers = exinfo; + except_info.ClientPointers = FALSE; + + // Add an MDRawBreakpadInfo stream to the minidump, to provide additional + // information about the exception handler to the Breakpad processor. The + // information will help the processor determine which threads are + // relevant. The Breakpad processor does not require this information but + // can function better with Breakpad-generated dumps when it is present. + // The native debugger is not harmed by the presence of this information. + MDRawBreakpadInfo breakpad_info; + breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID | + MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID; + breakpad_info.dump_thread_id = GetCurrentThreadId(); + breakpad_info.requesting_thread_id = requesting_thread_id; + + // Leave room in user_stream_array for a possible assertion info stream. + MINIDUMP_USER_STREAM user_stream_array[2]; + user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM; + user_stream_array[0].BufferSize = sizeof(breakpad_info); + user_stream_array[0].Buffer = &breakpad_info; + + MINIDUMP_USER_STREAM_INFORMATION user_streams; + user_streams.UserStreamCount = 1; + user_streams.UserStreamArray = user_stream_array; + + if (assertion) { + user_stream_array[1].Type = MD_ASSERTION_INFO_STREAM; + user_stream_array[1].BufferSize = sizeof(MDRawAssertionInfo); + user_stream_array[1].Buffer = assertion; + ++user_streams.UserStreamCount; + } - // The explicit comparison to TRUE avoids a warning (C4800). - success = (minidump_write_dump_(GetCurrentProcess(), - GetCurrentProcessId(), - dump_file, - MiniDumpNormal, - exinfo ? &except_info : NULL, - &user_streams, - NULL) == TRUE); + // The explicit comparison to TRUE avoids a warning (C4800). + success = (minidump_write_dump_(GetCurrentProcess(), + GetCurrentProcessId(), + dump_file, + dump_type_, + exinfo ? &except_info : NULL, + &user_streams, + NULL) == TRUE); - CloseHandle(dump_file); + CloseHandle(dump_file); + } } } if (callback_) { + // TODO(munjal): In case of out-of-process dump generation, both + // dump_path_c_ and next_minidump_id_ will be NULL. For out-of-process + // scenario, the server process ends up creating the dump path and dump + // id so they are not known to the client. success = callback_(dump_path_c_, next_minidump_id_c_, callback_context_, exinfo, assertion, success); } diff --git a/src/client/windows/handler/exception_handler.h b/src/client/windows/handler/exception_handler.h index fc9af326..870025fb 100644 --- a/src/client/windows/handler/exception_handler.h +++ b/src/client/windows/handler/exception_handler.h @@ -68,7 +68,9 @@ #include <string> #include <vector> +#include "client/windows/crash_generation/crash_generation_client.h" #include "google_breakpad/common/minidump_format.h" +#include "processor/scoped_ptr.h" namespace google_breakpad { @@ -88,8 +90,8 @@ class ExceptionHandler { // attempting to write a minidump. If a FilterCallback returns false, Breakpad // will immediately report the exception as unhandled without writing a // minidump, allowing another handler the opportunity to handle it. - typedef bool (*FilterCallback)(void *context, EXCEPTION_POINTERS *exinfo, - MDRawAssertionInfo *assertion); + typedef bool (*FilterCallback)(void* context, EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion); // A callback function to run after the minidump has been written. // minidump_id is a unique id for the dump, so the minidump @@ -110,11 +112,16 @@ class ExceptionHandler { // should normally return the value of |succeeded|, or when they wish to // not report an exception of handled, false. Callbacks will rarely want to // return true directly (unless |succeeded| is true). - typedef bool (*MinidumpCallback)(const wchar_t *dump_path, - const wchar_t *minidump_id, - void *context, - EXCEPTION_POINTERS *exinfo, - MDRawAssertionInfo *assertion, + // + // For out-of-process dump generation, dump path and minidump ID will always + // be NULL. In case of out-of-process dump generation, the dump path and + // minidump id are controlled by the server process and are not communicated + // back to the crashing process. + typedef bool (*MinidumpCallback)(const wchar_t* dump_path, + const wchar_t* minidump_id, + void* context, + EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion, bool succeeded); // HandlerType specifies which types of handlers should be installed, if @@ -139,11 +146,25 @@ class ExceptionHandler { // minidump. Minidump files will be written to dump_path, and the optional // callback is called after writing the dump file, as described above. // handler_types specifies the types of handlers that should be installed. - ExceptionHandler(const wstring &dump_path, + ExceptionHandler(const wstring& dump_path, FilterCallback filter, MinidumpCallback callback, - void *callback_context, + void* callback_context, int handler_types); + + // Creates a new ExcetpionHandler instance that can attempt to perform + // out-of-process dump generation if pipe_name is not NULL. If pipe_name is + // NULL, or if out-of-process dump generation registration step fails, + // in-process dump generation will be used. This also allows specifying + // the dump type to generate. + ExceptionHandler(const wstring& dump_path, + FilterCallback filter, + MinidumpCallback callback, + void* callback_context, + int handler_types, + MINIDUMP_TYPE dump_type, + const wchar_t* pipe_name); + ~ExceptionHandler(); // Get and set the minidump path. @@ -160,12 +181,12 @@ class ExceptionHandler { // Writes a minidump immediately, with the user-supplied exception // information. - bool WriteMinidumpForException(EXCEPTION_POINTERS *exinfo); + bool WriteMinidumpForException(EXCEPTION_POINTERS* exinfo); // Convenience form of WriteMinidump which does not require an // ExceptionHandler instance. static bool WriteMinidump(const wstring &dump_path, - MinidumpCallback callback, void *callback_context); + MinidumpCallback callback, void* callback_context); // Get the thread ID of the thread requesting the dump (either the exception // thread or any other thread that called WriteMinidump directly). This @@ -179,9 +200,21 @@ class ExceptionHandler { handle_debug_exceptions_ = handle_debug_exceptions; } + // Returns whether out-of-process dump generation is used or not. + bool IsOutOfProcess() const { return crash_generation_client_.get() != NULL; } + private: friend class AutoExceptionHandler; + // Initializes the instance with given values. + void Initialize(const wstring& dump_path, + FilterCallback filter, + MinidumpCallback callback, + void* callback_context, + int handler_types, + MINIDUMP_TYPE dump_type, + const wchar_t* pipe_name); + // Function pointer type for MiniDumpWriteDump, which is looked up // dynamically. typedef BOOL (WINAPI *MiniDumpWriteDump_type)( @@ -194,14 +227,14 @@ class ExceptionHandler { CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam); // Function pointer type for UuidCreate, which is looked up dynamically. - typedef RPC_STATUS (RPC_ENTRY *UuidCreate_type)(UUID *Uuid); + typedef RPC_STATUS (RPC_ENTRY *UuidCreate_type)(UUID* Uuid); // Runs the main loop for the exception handler thread. - static DWORD WINAPI ExceptionHandlerThreadMain(void *lpParameter); + static DWORD WINAPI ExceptionHandlerThreadMain(void* lpParameter); // Called on the exception thread when an unhandled exception occurs. // Signals the exception handler thread to handle the exception. - static LONG WINAPI HandleException(EXCEPTION_POINTERS *exinfo); + static LONG WINAPI HandleException(EXCEPTION_POINTERS* exinfo); #if _MSC_VER >= 1400 // MSVC 2005/8 // This function will be called by some CRT functions when they detect @@ -209,9 +242,9 @@ class ExceptionHandler { // the CRT may display an assertion dialog before calling this function, // and the function will not be called unless the assertion dialog is // dismissed by clicking "Ignore." - static void HandleInvalidParameter(const wchar_t *expression, - const wchar_t *function, - const wchar_t *file, + static void HandleInvalidParameter(const wchar_t* expression, + const wchar_t* function, + const wchar_t* file, unsigned int line, uintptr_t reserved); #endif // _MSC_VER >= 1400 @@ -229,8 +262,8 @@ class ExceptionHandler { // is NULL. If the dump is requested as a result of an assertion // (such as an invalid parameter being passed to a CRT function), // assertion contains data about the assertion, otherwise, it is NULL. - bool WriteMinidumpOnHandlerThread(EXCEPTION_POINTERS *exinfo, - MDRawAssertionInfo *assertion); + bool WriteMinidumpOnHandlerThread(EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion); // This function does the actual writing of a minidump. It is called // on the handler thread. requesting_thread_id is the ID of the thread @@ -238,8 +271,8 @@ class ExceptionHandler { // an exception, exinfo contains exception information, otherwise, // it is NULL. bool WriteMinidumpWithException(DWORD requesting_thread_id, - EXCEPTION_POINTERS *exinfo, - MDRawAssertionInfo *assertion); + EXCEPTION_POINTERS* exinfo, + MDRawAssertionInfo* assertion); // Generates a new ID and stores it in next_minidump_id_, and stores the // path of the next minidump to be written in next_minidump_path_. @@ -247,7 +280,9 @@ class ExceptionHandler { FilterCallback filter_; MinidumpCallback callback_; - void *callback_context_; + void* callback_context_; + + scoped_ptr<CrashGenerationClient> crash_generation_client_; // The directory in which a minidump will be written, set by the dump_path // argument to the constructor, or set_dump_path. @@ -266,12 +301,13 @@ class ExceptionHandler { // pointers are not owned by the ExceptionHandler object, but their lifetimes // should be equivalent to the lifetimes of the associated wstring, provided // that the wstrings are not altered. - const wchar_t *dump_path_c_; - const wchar_t *next_minidump_id_c_; - const wchar_t *next_minidump_path_c_; + const wchar_t* dump_path_c_; + const wchar_t* next_minidump_id_c_; + const wchar_t* next_minidump_path_c_; HMODULE dbghelp_module_; MiniDumpWriteDump_type minidump_write_dump_; + MINIDUMP_TYPE dump_type_; HMODULE rpcrt4_module_; UuidCreate_type uuid_create_; @@ -322,11 +358,11 @@ class ExceptionHandler { // The exception info passed to the exception handler on the exception // thread, if an exception occurred. NULL for user-requested dumps. - EXCEPTION_POINTERS *exception_info_; + EXCEPTION_POINTERS* exception_info_; // If the handler is invoked due to an assertion, this will contain a // pointer to the assertion information. It is NULL at other times. - MDRawAssertionInfo *assertion_; + MDRawAssertionInfo* assertion_; // The return value of the handler, passed from the handler thread back to // the requesting thread. @@ -342,7 +378,7 @@ class ExceptionHandler { // which ExceptionHandler object to route an exception to. When an // ExceptionHandler is created with install_handler true, it will append // itself to this list. - static vector<ExceptionHandler *> *handler_stack_; + static vector<ExceptionHandler*>* handler_stack_; // The index of the ExceptionHandler in handler_stack_ that will handle the // next exception. Note that 0 means the last entry in handler_stack_, 1 |