diff options
Diffstat (limited to 'toolkit/crashreporter/google-breakpad/src/client/windows/handler')
4 files changed, 0 insertions, 1658 deletions
diff --git a/toolkit/crashreporter/google-breakpad/src/client/windows/handler/exception_handler.cc b/toolkit/crashreporter/google-breakpad/src/client/windows/handler/exception_handler.cc deleted file mode 100644 index 1f7b19f9a..000000000 --- a/toolkit/crashreporter/google-breakpad/src/client/windows/handler/exception_handler.cc +++ /dev/null @@ -1,1073 +0,0 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include <objbase.h> - -#include <algorithm> -#include <cassert> -#include <cstdio> - -#include "common/windows/string_utils-inl.h" - -#include "client/windows/common/ipc_protocol.h" -#include "client/windows/handler/exception_handler.h" -#include "common/windows/guid_string.h" - -namespace google_breakpad { - -// This is passed as the context to the MinidumpWriteDump callback. -typedef struct { - AppMemoryList::const_iterator iter; - AppMemoryList::const_iterator end; -} MinidumpCallbackContext; - -vector<ExceptionHandler*>* ExceptionHandler::handler_stack_ = NULL; -LONG ExceptionHandler::handler_stack_index_ = 0; -CRITICAL_SECTION ExceptionHandler::handler_stack_critical_section_; -volatile LONG ExceptionHandler::instance_count_ = 0; - -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, - const CustomClientInfo* custom_info) { - Initialize(dump_path, - filter, - callback, - callback_context, - handler_types, - dump_type, - pipe_name, - NULL, // pipe_handle - NULL, // crash_generation_client - custom_info); -} - -ExceptionHandler::ExceptionHandler(const wstring& dump_path, - FilterCallback filter, - MinidumpCallback callback, - void* callback_context, - int handler_types, - MINIDUMP_TYPE dump_type, - HANDLE pipe_handle, - const CustomClientInfo* custom_info) { - Initialize(dump_path, - filter, - callback, - callback_context, - handler_types, - dump_type, - NULL, // pipe_name - pipe_handle, - NULL, // crash_generation_client - custom_info); -} - -ExceptionHandler::ExceptionHandler( - const wstring& dump_path, - FilterCallback filter, - MinidumpCallback callback, - void* callback_context, - int handler_types, - CrashGenerationClient* crash_generation_client) { - // The dump_type, pipe_name and custom_info that are passed in to Initialize() - // are not used. The ones set in crash_generation_client are used instead. - Initialize(dump_path, - filter, - callback, - callback_context, - handler_types, - MiniDumpNormal, // dump_type - not used - NULL, // pipe_name - not used - NULL, // pipe_handle - crash_generation_client, - NULL); // custom_info - not used -} - -ExceptionHandler::ExceptionHandler(const wstring &dump_path, - FilterCallback filter, - MinidumpCallback callback, - void* callback_context, - int handler_types) { - Initialize(dump_path, - filter, - callback, - callback_context, - handler_types, - MiniDumpNormal, - NULL, // pipe_name - NULL, // pipe_handle - NULL, // crash_generation_client - NULL); // custom_info -} - -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, - HANDLE pipe_handle, - CrashGenerationClient* crash_generation_client, - const CustomClientInfo* custom_info) { - LONG instance_count = InterlockedIncrement(&instance_count_); - 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 - previous_pch_ = NULL; - handler_thread_ = NULL; - is_shutdown_ = false; - 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; - consume_invalid_handle_exceptions_ = false; - - // Attempt to use out-of-process if user has specified a pipe or a - // crash generation client. - scoped_ptr<CrashGenerationClient> client; - if (crash_generation_client) { - client.reset(crash_generation_client); - } else if (pipe_name) { - client.reset( - new CrashGenerationClient(pipe_name, dump_type_, custom_info)); - } else if (pipe_handle) { - client.reset( - new CrashGenerationClient(pipe_handle, dump_type_, custom_info)); - } - - if (client.get() != NULL) { - // 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()); - } - } - - 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); - assert(handler_start_semaphore_ != NULL); - - handler_finish_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL); - assert(handler_finish_semaphore_ != NULL); - - // Don't attempt to create the thread if we could not create the semaphores. - if (handler_finish_semaphore_ != NULL && handler_start_semaphore_ != NULL) { - DWORD thread_id; - const int kExceptionHandlerThreadInitialStackSize = 64 * 1024; - handler_thread_ = CreateThread(NULL, // lpThreadAttributes - kExceptionHandlerThreadInitialStackSize, - ExceptionHandlerThreadMain, - this, // lpParameter - 0, // dwCreationFlags - &thread_id); - assert(handler_thread_ != NULL); - } - - dbghelp_module_ = LoadLibrary(L"dbghelp.dll"); - if (dbghelp_module_) { - minidump_write_dump_ = reinterpret_cast<MiniDumpWriteDump_type>( - GetProcAddress(dbghelp_module_, "MiniDumpWriteDump")); - } - - // 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); - } - - // Reserve one element for the instruction memory - AppMemory instruction_memory; - instruction_memory.ptr = NULL; - instruction_memory.length = 0; - app_memory_info_.push_back(instruction_memory); - - // There is a race condition here. If the first instance has not yet - // initialized the critical section, the second (and later) instances may - // try to use uninitialized critical section object. The feature of multiple - // instances in one module is not used much, so leave it as is for now. - // One way to solve this in the current design (that is, keeping the static - // handler stack) is to use spin locks with volatile bools to synchronize - // the handler stack. This works only if the compiler guarantees to generate - // cache coherent code for volatile. - // TODO(munjal): Fix this in a better way by changing the design if possible. - - // Lazy initialization of the handler_stack_critical_section_ - if (instance_count == 1) { - InitializeCriticalSection(&handler_stack_critical_section_); - } - - if (handler_types != HANDLER_NONE) { - EnterCriticalSection(&handler_stack_critical_section_); - - // 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_->push_back(this); - - if (handler_types & HANDLER_EXCEPTION) - previous_filter_ = SetUnhandledExceptionFilter(HandleException); - -#if _MSC_VER >= 1400 // MSVC 2005/8 - if (handler_types & HANDLER_INVALID_PARAMETER) - previous_iph_ = _set_invalid_parameter_handler(HandleInvalidParameter); -#endif // _MSC_VER >= 1400 - - if (handler_types & HANDLER_PURECALL) - previous_pch_ = _set_purecall_handler(HandlePureVirtualCall); - - LeaveCriticalSection(&handler_stack_critical_section_); - } -} - -ExceptionHandler::~ExceptionHandler() { - if (dbghelp_module_) { - FreeLibrary(dbghelp_module_); - } - - if (rpcrt4_module_) { - FreeLibrary(rpcrt4_module_); - } - - if (handler_types_ != HANDLER_NONE) { - EnterCriticalSection(&handler_stack_critical_section_); - - if (handler_types_ & HANDLER_EXCEPTION) - SetUnhandledExceptionFilter(previous_filter_); - -#if _MSC_VER >= 1400 // MSVC 2005/8 - if (handler_types_ & HANDLER_INVALID_PARAMETER) - _set_invalid_parameter_handler(previous_iph_); -#endif // _MSC_VER >= 1400 - - if (handler_types_ & HANDLER_PURECALL) - _set_purecall_handler(previous_pch_); - - if (handler_stack_->back() == this) { - handler_stack_->pop_back(); - } else { - // 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"); - vector<ExceptionHandler*>::iterator iterator = handler_stack_->begin(); - while (iterator != handler_stack_->end()) { - if (*iterator == this) { - iterator = handler_stack_->erase(iterator); - } else { - ++iterator; - } - } - } - - if (handler_stack_->empty()) { - // When destroying the last ExceptionHandler that installed a handler, - // clean up the handler stack. - delete handler_stack_; - handler_stack_ = NULL; - } - - LeaveCriticalSection(&handler_stack_critical_section_); - } - - // Some of the objects were only initialized if out of process - // registration was not done. - if (!IsOutOfProcess()) { -#ifdef BREAKPAD_NO_TERMINATE_THREAD - // Clean up the handler thread and synchronization primitives. The handler - // thread is either waiting on the semaphore to handle a crash or it is - // handling a crash. Coming out of the wait is fast but wait more in the - // eventuality a crash is handled. This compilation option results in a - // deadlock if the exception handler is destroyed while executing code - // inside DllMain. - is_shutdown_ = true; - ReleaseSemaphore(handler_start_semaphore_, 1, NULL); - const int kWaitForHandlerThreadMs = 60000; - WaitForSingleObject(handler_thread_, kWaitForHandlerThreadMs); -#else - TerminateThread(handler_thread_, 1); -#endif // BREAKPAD_NO_TERMINATE_THREAD - - CloseHandle(handler_thread_); - handler_thread_ = NULL; - DeleteCriticalSection(&handler_critical_section_); - CloseHandle(handler_start_semaphore_); - CloseHandle(handler_finish_semaphore_); - } - - // There is a race condition in the code below: if this instance is - // deleting the static critical section and a new instance of the class - // is created, then there is a possibility that the critical section be - // initialized while the same critical section is being deleted. Given the - // usage pattern for the code, this race condition is unlikely to hit, but it - // is a race condition nonetheless. - if (InterlockedDecrement(&instance_count_) == 0) { - DeleteCriticalSection(&handler_stack_critical_section_); - } -} - -bool ExceptionHandler::RequestUpload(DWORD crash_id) { - return crash_generation_client_->RequestUpload(crash_id); -} - -// static -DWORD ExceptionHandler::ExceptionHandlerThreadMain(void* lpParameter) { - ExceptionHandler* self = reinterpret_cast<ExceptionHandler *>(lpParameter); - assert(self); - assert(self->handler_start_semaphore_ != NULL); - assert(self->handler_finish_semaphore_ != NULL); - - while (true) { - if (WaitForSingleObject(self->handler_start_semaphore_, INFINITE) == - WAIT_OBJECT_0) { - // Perform the requested action. - if (self->is_shutdown_) { - // The instance of the exception handler is being destroyed. - break; - } else { - self->handler_return_value_ = - self->WriteMinidumpWithException(self->requesting_thread_id_, - self->exception_info_, - self->assertion_); - } - - // Allow the requesting thread to proceed. - ReleaseSemaphore(self->handler_finish_semaphore_, 1, NULL); - } - } - - // This statement is not reached when the thread is unconditionally - // terminated by the ExceptionHandler destructor. - return 0; -} - -// HandleException and HandleInvalidParameter must create an -// AutoExceptionHandler object to maintain static state and to determine which -// ExceptionHandler instance to use. The constructor locates the correct -// instance, and makes it available through get_handler(). The destructor -// restores the state in effect prior to allocating the AutoExceptionHandler. -class AutoExceptionHandler { - public: - AutoExceptionHandler() { - // Increment handler_stack_index_ so that if another Breakpad handler is - // registered using this same HandleException function, and it needs to be - // called while this handler is running (either because this handler - // declines to handle the exception, or an exception occurs during - // handling), HandleException will find the appropriate ExceptionHandler - // object in handler_stack_ to deliver the exception to. - // - // Because handler_stack_ is addressed in reverse (as |size - index|), - // preincrementing handler_stack_index_ avoids needing to subtract 1 from - // the argument to |at|. - // - // The index is maintained instead of popping elements off of the handler - // stack and pushing them at the end of this method. This avoids ruining - // the order of elements in the stack in the event that some other thread - // decides to manipulate the handler stack (such as creating a new - // ExceptionHandler object) while an exception is being handled. - EnterCriticalSection(&ExceptionHandler::handler_stack_critical_section_); - handler_ = ExceptionHandler::handler_stack_->at( - ExceptionHandler::handler_stack_->size() - - ++ExceptionHandler::handler_stack_index_); - - // In case another exception occurs while this handler is doing its thing, - // it should be delivered to the previous filter. - SetUnhandledExceptionFilter(handler_->previous_filter_); -#if _MSC_VER >= 1400 // MSVC 2005/8 - _set_invalid_parameter_handler(handler_->previous_iph_); -#endif // _MSC_VER >= 1400 - _set_purecall_handler(handler_->previous_pch_); - } - - ~AutoExceptionHandler() { - // Put things back the way they were before entering this handler. - SetUnhandledExceptionFilter(ExceptionHandler::HandleException); -#if _MSC_VER >= 1400 // MSVC 2005/8 - _set_invalid_parameter_handler(ExceptionHandler::HandleInvalidParameter); -#endif // _MSC_VER >= 1400 - _set_purecall_handler(ExceptionHandler::HandlePureVirtualCall); - - --ExceptionHandler::handler_stack_index_; - LeaveCriticalSection(&ExceptionHandler::handler_stack_critical_section_); - } - - ExceptionHandler* get_handler() const { return handler_; } - - private: - ExceptionHandler* handler_; -}; - -// static -LONG ExceptionHandler::HandleException(EXCEPTION_POINTERS* exinfo) { - AutoExceptionHandler auto_exception_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, - // allowing something else to handle the breakpoint without incurring the - // overhead transitioning to and from the handler thread. This behavior - // can be overridden by calling ExceptionHandler::set_handle_debug_exceptions. - DWORD code = exinfo->ExceptionRecord->ExceptionCode; - LONG action; - bool is_debug_exception = (code == EXCEPTION_BREAKPOINT) || - (code == EXCEPTION_SINGLE_STEP); - - if (code == EXCEPTION_INVALID_HANDLE && - current_handler->consume_invalid_handle_exceptions_) { - return EXCEPTION_CONTINUE_EXECUTION; - } - - 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 - // above, or it was passed to the handler, which decided not to handle it. - // This could be because the filter callback didn't want it, because - // minidump writing failed for some reason, or because the post-minidump - // callback function indicated failure. Give the previous handler a - // chance to do something with the exception. If there is no previous - // handler, return EXCEPTION_CONTINUE_SEARCH, which will allow a debugger - // or native "crashed" dialog to handle the exception. - if (current_handler->previous_filter_) { - action = current_handler->previous_filter_(exinfo); - } else { - action = EXCEPTION_CONTINUE_SEARCH; - } - } - - return action; -} - -#if _MSC_VER >= 1400 // MSVC 2005/8 -// static -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(); - - MDRawAssertionInfo assertion; - memset(&assertion, 0, sizeof(assertion)); - _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), - sizeof(assertion.function) / sizeof(assertion.function[0]), - _TRUNCATE, L"%s", function); - _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; - - // Make up an exception record for the current thread and CPU context - // to make it possible for the crash processor to classify these - // as do regular crashes, and to make it humane for developers to - // analyze them. - EXCEPTION_RECORD exception_record = {}; - CONTEXT exception_context = {}; - EXCEPTION_POINTERS exception_ptrs = { &exception_record, &exception_context }; - - ::RtlCaptureContext(&exception_context); - - exception_record.ExceptionCode = STATUS_INVALID_PARAMETER; - - // We store pointers to the the expression and function strings, - // and the line as exception parameters to make them easy to - // access by the developer on the far side. - exception_record.NumberParameters = 3; - exception_record.ExceptionInformation[0] = - reinterpret_cast<ULONG_PTR>(&assertion.expression); - exception_record.ExceptionInformation[1] = - reinterpret_cast<ULONG_PTR>(&assertion.file); - exception_record.ExceptionInformation[2] = assertion.line; - - 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(), - &exception_ptrs, - &assertion); - } else { - success = current_handler->WriteMinidumpOnHandlerThread(&exception_ptrs, - &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); - } 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 - // function, but now, since this function is no longer registered (and in - // fact, no function at all is registered), this will result in the - // default code path being taken: _CRT_DEBUGGER_HOOK and _invoke_watson. - // Use _invalid_parameter where it exists (in _DEBUG builds) as it passes - // more information through. In non-debug builds, it is not available, - // so fall back to using _invalid_parameter_noinfo. See invarg.c in the - // CRT source. -#ifdef _DEBUG - _invalid_parameter(expression, function, file, line, reserved); -#else // _DEBUG - _invalid_parameter_noinfo(); -#endif // _DEBUG - } - } - - // The handler either took care of the invalid parameter problem itself, - // or passed it on to another handler. "Swallow" it by exiting, paralleling - // the behavior of "swallowing" exceptions. - exit(0); -} -#endif // _MSC_VER >= 1400 - -// static -void ExceptionHandler::HandlePureVirtualCall() { - // This is an pure virtual function call, not an exception. It's safe to - // play with sprintf here. - AutoExceptionHandler auto_exception_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; - - // Make up an exception record for the current thread and CPU context - // to make it possible for the crash processor to classify these - // as do regular crashes, and to make it humane for developers to - // analyze them. - EXCEPTION_RECORD exception_record = {}; - CONTEXT exception_context = {}; - EXCEPTION_POINTERS exception_ptrs = { &exception_record, &exception_context }; - - ::RtlCaptureContext(&exception_context); - - exception_record.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION; - - // We store pointers to the the expression and function strings, - // and the line as exception parameters to make them easy to - // access by the developer on the far side. - exception_record.NumberParameters = 3; - exception_record.ExceptionInformation[0] = - reinterpret_cast<ULONG_PTR>(&assertion.expression); - exception_record.ExceptionInformation[1] = - reinterpret_cast<ULONG_PTR>(&assertion.file); - exception_record.ExceptionInformation[2] = assertion.line; - - 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(), - &exception_ptrs, - &assertion); - } else { - success = current_handler->WriteMinidumpOnHandlerThread(&exception_ptrs, - &assertion); - } - - if (!success) { - if (current_handler->previous_pch_) { - // The handler didn't fully handle the exception. Give it to the - // previous purecall handler. - current_handler->previous_pch_(); - } else { - // If there's no previous handler, return and let _purecall handle it. - // This will just put up an assertion dialog. - return; - } - } - - // The handler either took care of the invalid parameter problem itself, - // or passed it on to another handler. "Swallow" it by exiting, paralleling - // the behavior of "swallowing" exceptions. - exit(0); -} - -bool ExceptionHandler::WriteMinidumpOnHandlerThread( - EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion) { - EnterCriticalSection(&handler_critical_section_); - - // There isn't much we can do if the handler thread - // was not successfully created. - if (handler_thread_ == NULL) { - LeaveCriticalSection(&handler_critical_section_); - return false; - } - - // The handler thread should only be created when the semaphores are valid. - assert(handler_start_semaphore_ != NULL); - assert(handler_finish_semaphore_ != NULL); - - // Set up data to be passed in to the handler thread. - requesting_thread_id_ = GetCurrentThreadId(); - exception_info_ = exinfo; - assertion_ = assertion; - - // This causes the handler thread to call WriteMinidumpWithException. - ReleaseSemaphore(handler_start_semaphore_, 1, NULL); - - // Wait until WriteMinidumpWithException is done and collect its return value. - WaitForSingleObject(handler_finish_semaphore_, INFINITE); - bool status = handler_return_value_; - - // Clean up. - requesting_thread_id_ = 0; - exception_info_ = NULL; - assertion_ = NULL; - - LeaveCriticalSection(&handler_critical_section_); - - return status; -} - -bool ExceptionHandler::WriteMinidump() { - // Make up an exception record for the current thread and CPU context - // to make it possible for the crash processor to classify these - // as do regular crashes, and to make it humane for developers to - // analyze them. - EXCEPTION_RECORD exception_record = {}; - CONTEXT exception_context = {}; - EXCEPTION_POINTERS exception_ptrs = { &exception_record, &exception_context }; - - ::RtlCaptureContext(&exception_context); - exception_record.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION; - - return WriteMinidumpForException(&exception_ptrs); -} - -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; -} - -// static -bool ExceptionHandler::WriteMinidump(const wstring &dump_path, - MinidumpCallback callback, - void* callback_context, - MINIDUMP_TYPE dump_type) { - ExceptionHandler handler(dump_path, NULL, callback, callback_context, - HANDLER_NONE, dump_type, (HANDLE)NULL, NULL); - return handler.WriteMinidump(); -} - -// static -bool ExceptionHandler::WriteMinidumpForChild(HANDLE child, - DWORD child_blamed_thread, - const wstring& dump_path, - MinidumpCallback callback, - void* callback_context, - MINIDUMP_TYPE dump_type) { - EXCEPTION_RECORD ex; - CONTEXT ctx; - EXCEPTION_POINTERS exinfo = { NULL, NULL }; - // As documented on MSDN, on failure SuspendThread returns (DWORD) -1 - const DWORD kFailedToSuspendThread = static_cast<DWORD>(-1); - DWORD last_suspend_count = kFailedToSuspendThread; - HANDLE child_thread_handle = OpenThread(THREAD_GET_CONTEXT | - THREAD_QUERY_INFORMATION | - THREAD_SUSPEND_RESUME, - FALSE, - child_blamed_thread); - // This thread may have died already, so not opening the handle is a - // non-fatal error. - if (child_thread_handle != NULL) { - last_suspend_count = SuspendThread(child_thread_handle); - if (last_suspend_count != kFailedToSuspendThread) { - ctx.ContextFlags = CONTEXT_ALL; - if (GetThreadContext(child_thread_handle, &ctx)) { - memset(&ex, 0, sizeof(ex)); - ex.ExceptionCode = EXCEPTION_BREAKPOINT; -#if defined(_M_IX86) - ex.ExceptionAddress = reinterpret_cast<PVOID>(ctx.Eip); -#elif defined(_M_X64) - ex.ExceptionAddress = reinterpret_cast<PVOID>(ctx.Rip); -#endif - exinfo.ExceptionRecord = &ex; - exinfo.ContextRecord = &ctx; - } - } - } - - ExceptionHandler handler(dump_path, NULL, callback, callback_context, - HANDLER_NONE, dump_type, (HANDLE)NULL, NULL); - bool success = handler.WriteMinidumpWithExceptionForProcess( - child_blamed_thread, - exinfo.ExceptionRecord ? &exinfo : NULL, - NULL, child, false); - - if (last_suspend_count != kFailedToSuspendThread) { - ResumeThread(child_thread_handle); - } - - CloseHandle(child_thread_handle); - - if (callback) { - success = callback(handler.dump_path_c_, handler.next_minidump_id_c_, - callback_context, NULL, NULL, success); - } - - return success; -} - -bool ExceptionHandler::WriteMinidumpWithException( - DWORD requesting_thread_id, - 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 - // HandleException to call any previous handler or return - // EXCEPTION_CONTINUE_SEARCH on the exception thread, allowing it to appear - // as though this handler were not present at all. - if (filter_ && !filter_(callback_context_, exinfo, assertion)) { - return false; - } - - bool success = false; - if (IsOutOfProcess()) { - success = crash_generation_client_->RequestDump(exinfo, assertion); - } else { - success = WriteMinidumpWithExceptionForProcess(requesting_thread_id, - exinfo, - assertion, - GetCurrentProcess(), - true); - } - - 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); - } - - return success; -} - -// static -BOOL CALLBACK ExceptionHandler::MinidumpWriteDumpCallback( - PVOID context, - const PMINIDUMP_CALLBACK_INPUT callback_input, - PMINIDUMP_CALLBACK_OUTPUT callback_output) { - switch (callback_input->CallbackType) { - case MemoryCallback: { - MinidumpCallbackContext* callback_context = - reinterpret_cast<MinidumpCallbackContext*>(context); - if (callback_context->iter == callback_context->end) - return FALSE; - - // Include the specified memory region. - callback_output->MemoryBase = callback_context->iter->ptr; - callback_output->MemorySize = callback_context->iter->length; - callback_context->iter++; - return TRUE; - } - - // Include all modules. - case IncludeModuleCallback: - case ModuleCallback: - return TRUE; - - // Include all threads. - case IncludeThreadCallback: - case ThreadCallback: - return TRUE; - - // Stop receiving cancel callbacks. - case CancelCallback: - callback_output->CheckCancel = FALSE; - callback_output->Cancel = FALSE; - return TRUE; - } - // Ignore other callback types. - return FALSE; -} - -bool ExceptionHandler::WriteMinidumpWithExceptionForProcess( - DWORD requesting_thread_id, - EXCEPTION_POINTERS* exinfo, - MDRawAssertionInfo* assertion, - HANDLE process, - bool write_requester_stream) { - 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; - - // Leave room in user_stream_array for possible breakpad and - // assertion info streams. - MINIDUMP_USER_STREAM user_stream_array[2]; - MINIDUMP_USER_STREAM_INFORMATION user_streams; - user_streams.UserStreamCount = 0; - user_streams.UserStreamArray = user_stream_array; - - if (write_requester_stream) { - // 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; - - int index = user_streams.UserStreamCount; - user_stream_array[index].Type = MD_BREAKPAD_INFO_STREAM; - user_stream_array[index].BufferSize = sizeof(breakpad_info); - user_stream_array[index].Buffer = &breakpad_info; - ++user_streams.UserStreamCount; - } - - if (assertion) { - int index = user_streams.UserStreamCount; - user_stream_array[index].Type = MD_ASSERTION_INFO_STREAM; - user_stream_array[index].BufferSize = sizeof(MDRawAssertionInfo); - user_stream_array[index].Buffer = assertion; - ++user_streams.UserStreamCount; - } - - // Older versions of DbgHelp.dll don't correctly put the memory around - // the faulting instruction pointer into the minidump. This - // callback will ensure that it gets included. - if (exinfo) { - // Find a memory region of 256 bytes centered on the - // faulting instruction pointer. - const ULONG64 instruction_pointer = -#if defined(_M_IX86) - exinfo->ContextRecord->Eip; -#elif defined(_M_AMD64) - exinfo->ContextRecord->Rip; -#else -#error Unsupported platform -#endif - - MEMORY_BASIC_INFORMATION info; - if (VirtualQueryEx(process, - reinterpret_cast<LPCVOID>(instruction_pointer), - &info, - sizeof(MEMORY_BASIC_INFORMATION)) != 0 && - info.State == MEM_COMMIT) { - // Attempt to get 128 bytes before and after the instruction - // pointer, but settle for whatever's available up to the - // boundaries of the memory region. - const ULONG64 kIPMemorySize = 256; - ULONG64 base = - (std::max)(reinterpret_cast<ULONG64>(info.BaseAddress), - instruction_pointer - (kIPMemorySize / 2)); - ULONG64 end_of_range = - (std::min)(instruction_pointer + (kIPMemorySize / 2), - reinterpret_cast<ULONG64>(info.BaseAddress) - + info.RegionSize); - ULONG size = static_cast<ULONG>(end_of_range - base); - - AppMemory& elt = app_memory_info_.front(); - elt.ptr = base; - elt.length = size; - } - } - - MinidumpCallbackContext context; - context.iter = app_memory_info_.begin(); - context.end = app_memory_info_.end(); - - // Skip the reserved element if there was no instruction memory - if (context.iter->ptr == 0) { - context.iter++; - } - - MINIDUMP_CALLBACK_INFORMATION callback; - callback.CallbackRoutine = MinidumpWriteDumpCallback; - callback.CallbackParam = reinterpret_cast<void*>(&context); - - // The explicit comparison to TRUE avoids a warning (C4800). - success = (minidump_write_dump_(process, - GetProcessId(process), - dump_file, - dump_type_, - exinfo ? &except_info : NULL, - &user_streams, - &callback) == TRUE); - - CloseHandle(dump_file); - } - } - - return success; -} - -void ExceptionHandler::UpdateNextID() { - assert(uuid_create_); - UUID id = {0}; - if (uuid_create_) { - uuid_create_(&id); - } - next_minidump_id_ = GUIDString::GUIDToWString(&id); - next_minidump_id_c_ = next_minidump_id_.c_str(); - - wchar_t minidump_path[MAX_PATH]; - swprintf(minidump_path, MAX_PATH, L"%s\\%s.dmp", - dump_path_c_, next_minidump_id_c_); - - // remove when VC++7.1 is no longer supported - minidump_path[MAX_PATH - 1] = L'\0'; - - next_minidump_path_ = minidump_path; - next_minidump_path_c_ = next_minidump_path_.c_str(); -} - -void ExceptionHandler::RegisterAppMemory(void* ptr, size_t length) { - AppMemoryList::iterator iter = - std::find(app_memory_info_.begin(), app_memory_info_.end(), ptr); - if (iter != app_memory_info_.end()) { - // Don't allow registering the same pointer twice. - return; - } - - AppMemory app_memory; - app_memory.ptr = reinterpret_cast<ULONG64>(ptr); - app_memory.length = static_cast<ULONG>(length); - app_memory_info_.push_back(app_memory); -} - -void ExceptionHandler::UnregisterAppMemory(void* ptr) { - AppMemoryList::iterator iter = - std::find(app_memory_info_.begin(), app_memory_info_.end(), ptr); - if (iter != app_memory_info_.end()) { - app_memory_info_.erase(iter); - } -} - -} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/client/windows/handler/exception_handler.gyp b/toolkit/crashreporter/google-breakpad/src/client/windows/handler/exception_handler.gyp deleted file mode 100644 index c5733277d..000000000 --- a/toolkit/crashreporter/google-breakpad/src/client/windows/handler/exception_handler.gyp +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright 2010 Google Inc. All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: -# -# * Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# * Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following disclaimer -# in the documentation and/or other materials provided with the -# distribution. -# * Neither the name of Google Inc. nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -{ - 'includes': [ - '../../../build/common.gypi', - ], - 'targets': [ - { - 'target_name': 'exception_handler', - 'type': 'static_library', - 'sources': [ - "exception_handler.cc", - "exception_handler.h", - ], - 'dependencies': [ - '../breakpad_client.gyp:common', - '../crash_generation/crash_generation.gyp:crash_generation_server', - ] - }, - ], -} diff --git a/toolkit/crashreporter/google-breakpad/src/client/windows/handler/exception_handler.h b/toolkit/crashreporter/google-breakpad/src/client/windows/handler/exception_handler.h deleted file mode 100644 index 11babe513..000000000 --- a/toolkit/crashreporter/google-breakpad/src/client/windows/handler/exception_handler.h +++ /dev/null @@ -1,524 +0,0 @@ -// Copyright (c) 2006, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// ExceptionHandler can write a minidump file when an exception occurs, -// or when WriteMinidump() is called explicitly by your program. -// -// To have the exception handler write minidumps when an uncaught exception -// (crash) occurs, you should create an instance early in the execution -// of your program, and keep it around for the entire time you want to -// have crash handling active (typically, until shutdown). -// -// If you want to write minidumps without installing the exception handler, -// you can create an ExceptionHandler with install_handler set to false, -// then call WriteMinidump. You can also use this technique if you want to -// use different minidump callbacks for different call sites. -// -// In either case, a callback function is called when a minidump is written, -// which receives the unqiue id of the minidump. The caller can use this -// id to collect and write additional application state, and to launch an -// external crash-reporting application. -// -// It is important that creation and destruction of ExceptionHandler objects -// be nested cleanly, when using install_handler = true. -// Avoid the following pattern: -// ExceptionHandler *e = new ExceptionHandler(...); -// ExceptionHandler *f = new ExceptionHandler(...); -// delete e; -// This will put the exception filter stack into an inconsistent state. - -#ifndef CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__ -#define CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__ - -#include <stdlib.h> -#include <windows.h> -#include <dbghelp.h> -#include <rpc.h> - -#pragma warning(push) -// Disable exception handler warnings. -#pragma warning(disable:4530) - -#include <list> -#include <string> -#include <vector> - -#include "client/windows/common/ipc_protocol.h" -#include "client/windows/crash_generation/crash_generation_client.h" -#include "common/scoped_ptr.h" -#include "google_breakpad/common/minidump_format.h" - -namespace google_breakpad { - -using std::vector; -using std::wstring; - -// These entries store a list of memory regions that the client wants included -// in the minidump. -struct AppMemory { - ULONG64 ptr; - ULONG length; - - bool operator==(const struct AppMemory& other) const { - return ptr == other.ptr; - } - - bool operator==(const void* other) const { - return ptr == reinterpret_cast<ULONG64>(other); - } -}; -typedef std::list<AppMemory> AppMemoryList; - -class ExceptionHandler { - public: - // A callback function to run before Breakpad performs any substantial - // processing of an exception. A FilterCallback is called before writing - // a minidump. context is the parameter supplied by the user as - // callback_context when the handler was created. exinfo points to the - // exception record, if any; assertion points to assertion information, - // if any. - // - // If a FilterCallback returns true, Breakpad will continue processing, - // 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); - - // A callback function to run after the minidump has been written. - // minidump_id is a unique id for the dump, so the minidump - // file is <dump_path>\<minidump_id>.dmp. context is the parameter supplied - // by the user as callback_context when the handler was created. exinfo - // points to the exception record, or NULL if no exception occurred. - // succeeded indicates whether a minidump file was successfully written. - // assertion points to information about an assertion if the handler was - // invoked by an assertion. - // - // If an exception occurred and the callback returns true, Breakpad will treat - // the exception as fully-handled, suppressing any other handlers from being - // notified of the exception. If the callback returns false, Breakpad will - // treat the exception as unhandled, and allow another handler to handle it. - // If there are no other handlers, Breakpad will report the exception to the - // system as unhandled, allowing a debugger or native crash dialog the - // opportunity to handle the exception. Most callback implementations - // 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). - // - // 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 - // any. Use HANDLER_NONE for an ExceptionHandler that remains idle, - // without catching any failures on its own. This type of handler may - // still be triggered by calling WriteMinidump. Otherwise, use a - // combination of the other HANDLER_ values, or HANDLER_ALL to install - // all handlers. - enum HandlerType { - HANDLER_NONE = 0, - HANDLER_EXCEPTION = 1 << 0, // SetUnhandledExceptionFilter - HANDLER_INVALID_PARAMETER = 1 << 1, // _set_invalid_parameter_handler - HANDLER_PURECALL = 1 << 2, // _set_purecall_handler - HANDLER_ALL = HANDLER_EXCEPTION | - HANDLER_INVALID_PARAMETER | - HANDLER_PURECALL - }; - - // Creates a new ExceptionHandler instance to handle writing minidumps. - // Before writing a minidump, the optional filter callback will be called. - // Its return value determines whether or not Breakpad should write a - // 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, - FilterCallback filter, - MinidumpCallback callback, - void* callback_context, - int handler_types); - - // Creates a new ExceptionHandler 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, - const CustomClientInfo* custom_info); - - // As above, creates a new ExceptionHandler instance to perform - // out-of-process dump generation if the given pipe_handle is not NULL. - ExceptionHandler(const wstring& dump_path, - FilterCallback filter, - MinidumpCallback callback, - void* callback_context, - int handler_types, - MINIDUMP_TYPE dump_type, - HANDLE pipe_handle, - const CustomClientInfo* custom_info); - - // ExceptionHandler that ENSURES out-of-process dump generation. Expects a - // crash generation client that is already registered with a crash generation - // server. Takes ownership of the passed-in crash_generation_client. - // - // Usage example: - // crash_generation_client = new CrashGenerationClient(..); - // if (crash_generation_client->Register()) { - // // Registration with the crash generation server succeeded. - // // Out-of-process dump generation is guaranteed. - // g_handler = new ExceptionHandler(.., crash_generation_client, ..); - // return true; - // } - ExceptionHandler(const wstring& dump_path, - FilterCallback filter, - MinidumpCallback callback, - void* callback_context, - int handler_types, - CrashGenerationClient* crash_generation_client); - - ~ExceptionHandler(); - - // Get and set the minidump path. - wstring dump_path() const { return dump_path_; } - void set_dump_path(const wstring &dump_path) { - dump_path_ = dump_path; - dump_path_c_ = dump_path_.c_str(); - UpdateNextID(); // Necessary to put dump_path_ in next_minidump_path_. - } - - // Requests that a previously reported crash be uploaded. - bool RequestUpload(DWORD crash_id); - - // Writes a minidump immediately. This can be used to capture the - // execution state independently of a crash. Returns true on success. - bool WriteMinidump(); - - // Writes a minidump immediately, with the user-supplied exception - // information. - 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, - MINIDUMP_TYPE dump_type = MiniDumpNormal); - - // Write a minidump of |child| immediately. This can be used to - // capture the execution state of |child| independently of a crash. - // Pass a meaningful |child_blamed_thread| to make that thread in - // the child process the one from which a crash signature is - // extracted. - static bool WriteMinidumpForChild(HANDLE child, - DWORD child_blamed_thread, - const wstring& dump_path, - MinidumpCallback callback, - void* callback_context, - MINIDUMP_TYPE dump_type = MiniDumpNormal); - - // Get the thread ID of the thread requesting the dump (either the exception - // thread or any other thread that called WriteMinidump directly). This - // may be useful if you want to include additional thread state in your - // dumps. - DWORD get_requesting_thread_id() const { return requesting_thread_id_; } - - // Controls behavior of EXCEPTION_BREAKPOINT and EXCEPTION_SINGLE_STEP. - bool get_handle_debug_exceptions() const { return handle_debug_exceptions_; } - void set_handle_debug_exceptions(bool handle_debug_exceptions) { - handle_debug_exceptions_ = handle_debug_exceptions; - } - - // Controls behavior of EXCEPTION_INVALID_HANDLE. - bool get_consume_invalid_handle_exceptions() const { - return consume_invalid_handle_exceptions_; - } - void set_consume_invalid_handle_exceptions( - bool consume_invalid_handle_exceptions) { - consume_invalid_handle_exceptions_ = consume_invalid_handle_exceptions; - } - - // Returns whether out-of-process dump generation is used or not. - bool IsOutOfProcess() const { return crash_generation_client_.get() != NULL; } - - // Calling RegisterAppMemory(p, len) causes len bytes starting - // at address p to be copied to the minidump when a crash happens. - void RegisterAppMemory(void* ptr, size_t length); - void UnregisterAppMemory(void* ptr); - - 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, - HANDLE pipe_handle, - CrashGenerationClient* crash_generation_client, - const CustomClientInfo* custom_info); - - // Function pointer type for MiniDumpWriteDump, which is looked up - // dynamically. - typedef BOOL (WINAPI *MiniDumpWriteDump_type)( - HANDLE hProcess, - DWORD dwPid, - HANDLE hFile, - MINIDUMP_TYPE DumpType, - CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, - CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, - CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam); - - // Function pointer type for UuidCreate, which is looked up dynamically. - typedef RPC_STATUS (RPC_ENTRY *UuidCreate_type)(UUID* Uuid); - - // Runs the main loop for the exception handler thread. - 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); - -#if _MSC_VER >= 1400 // MSVC 2005/8 - // This function will be called by some CRT functions when they detect - // that they were passed an invalid parameter. Note that in _DEBUG builds, - // 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, - unsigned int line, - uintptr_t reserved); -#endif // _MSC_VER >= 1400 - - // This function will be called by the CRT when a pure virtual - // function is called. - static void HandlePureVirtualCall(); - - // This is called on the exception thread or on another thread that - // the user wishes to produce a dump from. It calls - // WriteMinidumpWithException on the handler thread, avoiding stack - // overflows and inconsistent dumps due to writing the dump from - // the exception thread. If the dump is requested as a result of an - // exception, exinfo contains exception information, otherwise, it - // 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); - - // This function is called on the handler thread. It calls into - // WriteMinidumpWithExceptionForProcess() with a handle to the - // current process. requesting_thread_id is the ID of the thread - // that requested the dump. If the dump is requested as a result of - // an exception, exinfo contains exception information, otherwise, - // it is NULL. - bool WriteMinidumpWithException(DWORD requesting_thread_id, - EXCEPTION_POINTERS* exinfo, - MDRawAssertionInfo* assertion); - - // This function is used as a callback when calling MinidumpWriteDump, - // in order to add additional memory regions to the dump. - static BOOL CALLBACK MinidumpWriteDumpCallback( - PVOID context, - const PMINIDUMP_CALLBACK_INPUT callback_input, - PMINIDUMP_CALLBACK_OUTPUT callback_output); - - // 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 that requested the dump, if that information is - // meaningful. If the dump is requested as a result of an - // exception, exinfo contains exception information, otherwise, it - // is NULL. process is the one that will be dumped. If - // requesting_thread_id is meaningful and should be added to the - // minidump, write_requester_stream is |true|. - bool WriteMinidumpWithExceptionForProcess(DWORD requesting_thread_id, - EXCEPTION_POINTERS* exinfo, - MDRawAssertionInfo* assertion, - HANDLE process, - bool write_requester_stream); - - // 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_. - void UpdateNextID(); - - FilterCallback filter_; - MinidumpCallback callback_; - 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. - wstring dump_path_; - - // The basename of the next minidump to be written, without the extension. - wstring next_minidump_id_; - - // The full pathname of the next minidump to be written, including the file - // extension. - wstring next_minidump_path_; - - // Pointers to C-string representations of the above. These are set when - // the above wstring versions are set in order to avoid calling c_str during - // an exception, as c_str may attempt to allocate heap memory. These - // 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_; - - HMODULE dbghelp_module_; - MiniDumpWriteDump_type minidump_write_dump_; - MINIDUMP_TYPE dump_type_; - - HMODULE rpcrt4_module_; - UuidCreate_type uuid_create_; - - // Tracks the handler types that were installed according to the - // handler_types constructor argument. - int handler_types_; - - // When installed_handler_ is true, previous_filter_ is the unhandled - // exception filter that was set prior to installing ExceptionHandler as - // the unhandled exception filter and pointing it to |this|. NULL indicates - // that there is no previous unhandled exception filter. - LPTOP_LEVEL_EXCEPTION_FILTER previous_filter_; - -#if _MSC_VER >= 1400 // MSVC 2005/8 - // Beginning in VC 8, the CRT provides an invalid parameter handler that will - // be called when some CRT functions are passed invalid parameters. In - // earlier CRTs, the same conditions would cause unexpected behavior or - // crashes. - _invalid_parameter_handler previous_iph_; -#endif // _MSC_VER >= 1400 - - // The CRT allows you to override the default handler for pure - // virtual function calls. - _purecall_handler previous_pch_; - - // The exception handler thread. - HANDLE handler_thread_; - - // True if the exception handler is being destroyed. - // Starting with MSVC 2005, Visual C has stronger guarantees on volatile vars. - // It has release semantics on write and acquire semantics on reads. - // See the msdn documentation. - volatile bool is_shutdown_; - - // The critical section enforcing the requirement that only one exception be - // handled by a handler at a time. - CRITICAL_SECTION handler_critical_section_; - - // Semaphores used to move exception handling between the exception thread - // and the handler thread. handler_start_semaphore_ is signalled by the - // exception thread to wake up the handler thread when an exception occurs. - // handler_finish_semaphore_ is signalled by the handler thread to wake up - // the exception thread when handling is complete. - HANDLE handler_start_semaphore_; - HANDLE handler_finish_semaphore_; - - // The next 2 fields contain data passed from the requesting thread to - // the handler thread. - - // The thread ID of the thread requesting the dump (either the exception - // thread or any other thread that called WriteMinidump directly). - DWORD requesting_thread_id_; - - // 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_; - - // 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_; - - // The return value of the handler, passed from the handler thread back to - // the requesting thread. - bool handler_return_value_; - - // If true, the handler will intercept EXCEPTION_BREAKPOINT and - // EXCEPTION_SINGLE_STEP exceptions. Leave this false (the default) - // to not interfere with debuggers. - bool handle_debug_exceptions_; - - // If true, the handler will consume any EXCEPTION_INVALID_HANDLE exceptions. - // Leave this false (the default) to handle these exceptions as normal. - bool consume_invalid_handle_exceptions_; - - // Callers can request additional memory regions to be included in - // the dump. - AppMemoryList app_memory_info_; - - // A stack of ExceptionHandler objects that have installed unhandled - // exception filters. This vector is used by HandleException to determine - // 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_; - - // 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 - // means the next-to-last entry, and so on. This is used by HandleException - // to support multiple stacked Breakpad handlers. - static LONG handler_stack_index_; - - // handler_stack_critical_section_ guards operations on handler_stack_ and - // handler_stack_index_. The critical section is initialized by the - // first instance of the class and destroyed by the last instance of it. - static CRITICAL_SECTION handler_stack_critical_section_; - - // The number of instances of this class. - static volatile LONG instance_count_; - - // disallow copy ctor and operator= - explicit ExceptionHandler(const ExceptionHandler &); - void operator=(const ExceptionHandler &); -}; - -} // namespace google_breakpad - -#pragma warning(pop) - -#endif // CLIENT_WINDOWS_HANDLER_EXCEPTION_HANDLER_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/client/windows/handler/objs.mozbuild b/toolkit/crashreporter/google-breakpad/src/client/windows/handler/objs.mozbuild deleted file mode 100644 index 6cabb09b7..000000000 --- a/toolkit/crashreporter/google-breakpad/src/client/windows/handler/objs.mozbuild +++ /dev/null @@ -1,14 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -lobjs_handler = [ - 'exception_handler.cc', -] - -subdir = 'toolkit/crashreporter/google-breakpad/src/client/windows/handler' -objs_handler = [ - '/%s/%s' % (subdir, s) for s in lobjs_handler -] |