diff options
Diffstat (limited to 'toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/minidump_generator.cc')
-rw-r--r-- | toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/minidump_generator.cc | 579 |
1 files changed, 0 insertions, 579 deletions
diff --git a/toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/minidump_generator.cc b/toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/minidump_generator.cc deleted file mode 100644 index 786c9b937..000000000 --- a/toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/minidump_generator.cc +++ /dev/null @@ -1,579 +0,0 @@ -// Copyright (c) 2008, 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 "client/windows/crash_generation/minidump_generator.h" - -#include <assert.h> -#include <avrfsdk.h> - -#include <algorithm> -#include <iterator> -#include <list> -#include <vector> - -#include "client/windows/common/auto_critical_section.h" -#include "common/scoped_ptr.h" -#include "common/windows/guid_string.h" - -using std::wstring; - -namespace { - -// A helper class used to collect handle operations data. Unlike -// |MiniDumpWithHandleData| it records the operations for a single handle value -// only, making it possible to include this information to a minidump. -class HandleTraceData { - public: - HandleTraceData(); - ~HandleTraceData(); - - // Collects the handle operations data and formats a user stream to be added - // to the minidump. - bool CollectHandleData(HANDLE process_handle, - EXCEPTION_POINTERS* exception_pointers); - - // Fills the user dump entry with a pointer to the collected handle operations - // data. Returns |true| if the entry was initialized successfully, or |false| - // if no trace data is available. - bool GetUserStream(MINIDUMP_USER_STREAM* user_stream); - - private: - // Reads the exception code from the client process's address space. - // This routine assumes that the client process's pointer width matches ours. - static bool ReadExceptionCode(HANDLE process_handle, - EXCEPTION_POINTERS* exception_pointers, - DWORD* exception_code); - - // Stores handle operations retrieved by VerifierEnumerateResource(). - static ULONG CALLBACK RecordHandleOperations(void* resource_description, - void* enumeration_context, - ULONG* enumeration_level); - - // Function pointer type for VerifierEnumerateResource, which is looked up - // dynamically. - typedef BOOL (WINAPI* VerifierEnumerateResourceType)( - HANDLE Process, - ULONG Flags, - ULONG ResourceType, - AVRF_RESOURCE_ENUMERATE_CALLBACK ResourceCallback, - PVOID EnumerationContext); - - // Handle to dynamically loaded verifier.dll. - HMODULE verifier_module_; - - // Pointer to the VerifierEnumerateResource function. - VerifierEnumerateResourceType enumerate_resource_; - - // Handle value to look for. - ULONG64 handle_; - - // List of handle operations for |handle_|. - std::list<AVRF_HANDLE_OPERATION> operations_; - - // Minidump stream data. - std::vector<char> stream_; -}; - -HandleTraceData::HandleTraceData() - : verifier_module_(NULL), - enumerate_resource_(NULL), - handle_(NULL) { -} - -HandleTraceData::~HandleTraceData() { - if (verifier_module_) { - FreeLibrary(verifier_module_); - } -} - -bool HandleTraceData::CollectHandleData( - HANDLE process_handle, - EXCEPTION_POINTERS* exception_pointers) { - DWORD exception_code; - if (!ReadExceptionCode(process_handle, exception_pointers, &exception_code)) { - return false; - } - - // Verify whether the execption is STATUS_INVALID_HANDLE. Do not record any - // handle information if it is a different exception to keep the minidump - // small. - if (exception_code != STATUS_INVALID_HANDLE) { - return true; - } - - // Load verifier!VerifierEnumerateResource() dynamically. - verifier_module_ = LoadLibrary(TEXT("verifier.dll")); - if (!verifier_module_) { - return false; - } - - enumerate_resource_ = reinterpret_cast<VerifierEnumerateResourceType>( - GetProcAddress(verifier_module_, "VerifierEnumerateResource")); - if (!enumerate_resource_) { - return false; - } - - // STATUS_INVALID_HANDLE does not provide the offending handle value in - // the exception parameters so we have to guess. At the moment we scan - // the handle operations trace looking for the last invalid handle operation - // and record only the operations for that handle value. - if (enumerate_resource_(process_handle, - 0, - AvrfResourceHandleTrace, - &RecordHandleOperations, - this) != ERROR_SUCCESS) { - // The handle tracing must have not been enabled. - return true; - } - - // Now that |handle_| is initialized, purge all irrelevant operations. - std::list<AVRF_HANDLE_OPERATION>::iterator i = operations_.begin(); - std::list<AVRF_HANDLE_OPERATION>::iterator i_end = operations_.end(); - while (i != i_end) { - if (i->Handle == handle_) { - ++i; - } else { - i = operations_.erase(i); - } - } - - // Convert the list of recorded operations to a minidump stream. - stream_.resize(sizeof(MINIDUMP_HANDLE_OPERATION_LIST) + - sizeof(AVRF_HANDLE_OPERATION) * operations_.size()); - - MINIDUMP_HANDLE_OPERATION_LIST* stream_data = - reinterpret_cast<MINIDUMP_HANDLE_OPERATION_LIST*>( - &stream_.front()); - stream_data->SizeOfHeader = sizeof(MINIDUMP_HANDLE_OPERATION_LIST); - stream_data->SizeOfEntry = sizeof(AVRF_HANDLE_OPERATION); - stream_data->NumberOfEntries = static_cast<ULONG32>(operations_.size()); - stream_data->Reserved = 0; - std::copy(operations_.begin(), - operations_.end(), -#ifdef _MSC_VER - stdext::checked_array_iterator<AVRF_HANDLE_OPERATION*>( - reinterpret_cast<AVRF_HANDLE_OPERATION*>(stream_data + 1), - operations_.size()) -#else - reinterpret_cast<AVRF_HANDLE_OPERATION*>(stream_data + 1) -#endif - ); - - return true; -} - -bool HandleTraceData::GetUserStream(MINIDUMP_USER_STREAM* user_stream) { - if (stream_.empty()) { - return false; - } else { - user_stream->Type = HandleOperationListStream; - user_stream->BufferSize = static_cast<ULONG>(stream_.size()); - user_stream->Buffer = &stream_.front(); - return true; - } -} - -bool HandleTraceData::ReadExceptionCode( - HANDLE process_handle, - EXCEPTION_POINTERS* exception_pointers, - DWORD* exception_code) { - EXCEPTION_POINTERS pointers; - if (!ReadProcessMemory(process_handle, - exception_pointers, - &pointers, - sizeof(pointers), - NULL)) { - return false; - } - - if (!ReadProcessMemory(process_handle, - pointers.ExceptionRecord, - exception_code, - sizeof(*exception_code), - NULL)) { - return false; - } - - return true; -} - -ULONG CALLBACK HandleTraceData::RecordHandleOperations( - void* resource_description, - void* enumeration_context, - ULONG* enumeration_level) { - AVRF_HANDLE_OPERATION* description = - reinterpret_cast<AVRF_HANDLE_OPERATION*>(resource_description); - HandleTraceData* self = - reinterpret_cast<HandleTraceData*>(enumeration_context); - - // Remember the last invalid handle operation. - if (description->OperationType == OperationDbBADREF) { - self->handle_ = description->Handle; - } - - // Record all handle operations. - self->operations_.push_back(*description); - - *enumeration_level = HeapEnumerationEverything; - return ERROR_SUCCESS; -} - -} // namespace - -namespace google_breakpad { - -MinidumpGenerator::MinidumpGenerator( - const std::wstring& dump_path, - const HANDLE process_handle, - const DWORD process_id, - const DWORD thread_id, - const DWORD requesting_thread_id, - EXCEPTION_POINTERS* exception_pointers, - MDRawAssertionInfo* assert_info, - const MINIDUMP_TYPE dump_type, - const bool is_client_pointers) - : dbghelp_module_(NULL), - write_dump_(NULL), - rpcrt4_module_(NULL), - create_uuid_(NULL), - process_handle_(process_handle), - process_id_(process_id), - thread_id_(thread_id), - requesting_thread_id_(requesting_thread_id), - exception_pointers_(exception_pointers), - assert_info_(assert_info), - dump_type_(dump_type), - is_client_pointers_(is_client_pointers), - dump_path_(dump_path), - dump_file_(INVALID_HANDLE_VALUE), - full_dump_file_(INVALID_HANDLE_VALUE), - dump_file_is_internal_(false), - full_dump_file_is_internal_(false), - additional_streams_(NULL), - callback_info_(NULL) { - InitializeCriticalSection(&module_load_sync_); - InitializeCriticalSection(&get_proc_address_sync_); -} - -MinidumpGenerator::~MinidumpGenerator() { - if (dump_file_is_internal_ && dump_file_ != INVALID_HANDLE_VALUE) { - CloseHandle(dump_file_); - } - - if (full_dump_file_is_internal_ && full_dump_file_ != INVALID_HANDLE_VALUE) { - CloseHandle(full_dump_file_); - } - - if (dbghelp_module_) { - FreeLibrary(dbghelp_module_); - } - - if (rpcrt4_module_) { - FreeLibrary(rpcrt4_module_); - } - - DeleteCriticalSection(&get_proc_address_sync_); - DeleteCriticalSection(&module_load_sync_); -} - -bool MinidumpGenerator::WriteMinidump() { - bool full_memory_dump = (dump_type_ & MiniDumpWithFullMemory) != 0; - if (dump_file_ == INVALID_HANDLE_VALUE || - (full_memory_dump && full_dump_file_ == INVALID_HANDLE_VALUE)) { - return false; - } - - MiniDumpWriteDumpType write_dump = GetWriteDump(); - if (!write_dump) { - return false; - } - - MINIDUMP_EXCEPTION_INFORMATION* dump_exception_pointers = NULL; - MINIDUMP_EXCEPTION_INFORMATION dump_exception_info; - - // Setup the exception information object only if it's a dump - // due to an exception. - if (exception_pointers_) { - dump_exception_pointers = &dump_exception_info; - dump_exception_info.ThreadId = thread_id_; - dump_exception_info.ExceptionPointers = exception_pointers_; - dump_exception_info.ClientPointers = is_client_pointers_; - } - - // 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 = {0}; - if (!is_client_pointers_) { - // Set the dump thread id and requesting thread id only in case of - // in-process dump generation. - breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID | - MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID; - breakpad_info.dump_thread_id = thread_id_; - breakpad_info.requesting_thread_id = requesting_thread_id_; - } - - int additional_streams_count = additional_streams_ ? - additional_streams_->UserStreamCount : 0; - scoped_array<MINIDUMP_USER_STREAM> user_stream_array( - new MINIDUMP_USER_STREAM[3 + additional_streams_count]); - 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.get(); - - MDRawAssertionInfo* actual_assert_info = assert_info_; - MDRawAssertionInfo client_assert_info = {{0}}; - - if (assert_info_) { - // If the assertion info object lives in the client process, - // read the memory of the client process. - if (is_client_pointers_) { - SIZE_T bytes_read = 0; - if (!ReadProcessMemory(process_handle_, - assert_info_, - &client_assert_info, - sizeof(client_assert_info), - &bytes_read)) { - if (dump_file_is_internal_) - CloseHandle(dump_file_); - if (full_dump_file_is_internal_ && - full_dump_file_ != INVALID_HANDLE_VALUE) - CloseHandle(full_dump_file_); - return false; - } - - if (bytes_read != sizeof(client_assert_info)) { - if (dump_file_is_internal_) - CloseHandle(dump_file_); - if (full_dump_file_is_internal_ && - full_dump_file_ != INVALID_HANDLE_VALUE) - CloseHandle(full_dump_file_); - return false; - } - - actual_assert_info = &client_assert_info; - } - - user_stream_array[1].Type = MD_ASSERTION_INFO_STREAM; - user_stream_array[1].BufferSize = sizeof(MDRawAssertionInfo); - user_stream_array[1].Buffer = actual_assert_info; - ++user_streams.UserStreamCount; - } - - if (additional_streams_) { - for (size_t i = 0; - i < additional_streams_->UserStreamCount; - i++, user_streams.UserStreamCount++) { - user_stream_array[user_streams.UserStreamCount].Type = - additional_streams_->UserStreamArray[i].Type; - user_stream_array[user_streams.UserStreamCount].BufferSize = - additional_streams_->UserStreamArray[i].BufferSize; - user_stream_array[user_streams.UserStreamCount].Buffer = - additional_streams_->UserStreamArray[i].Buffer; - } - } - - // If the process is terminated by STATUS_INVALID_HANDLE exception store - // the trace of operations for the offending handle value. Do nothing special - // if the client already requested the handle trace to be stored in the dump. - HandleTraceData handle_trace_data; - if (exception_pointers_ && (dump_type_ & MiniDumpWithHandleData) == 0) { - if (!handle_trace_data.CollectHandleData(process_handle_, - exception_pointers_)) { - if (dump_file_is_internal_) - CloseHandle(dump_file_); - if (full_dump_file_is_internal_ && - full_dump_file_ != INVALID_HANDLE_VALUE) - CloseHandle(full_dump_file_); - return false; - } - } - - bool result_full_memory = true; - if (full_memory_dump) { - result_full_memory = write_dump( - process_handle_, - process_id_, - full_dump_file_, - static_cast<MINIDUMP_TYPE>((dump_type_ & (~MiniDumpNormal)) - | MiniDumpWithHandleData), - exception_pointers_ ? &dump_exception_info : NULL, - &user_streams, - NULL) != FALSE; - } - - // Add handle operations trace stream to the minidump if it was collected. - if (handle_trace_data.GetUserStream( - &user_stream_array[user_streams.UserStreamCount])) { - ++user_streams.UserStreamCount; - } - - bool result_minidump = write_dump( - process_handle_, - process_id_, - dump_file_, - static_cast<MINIDUMP_TYPE>((dump_type_ & (~MiniDumpWithFullMemory)) - | MiniDumpNormal), - exception_pointers_ ? &dump_exception_info : NULL, - &user_streams, - callback_info_) != FALSE; - - return result_minidump && result_full_memory; -} - -bool MinidumpGenerator::GenerateDumpFile(wstring* dump_path) { - // The dump file was already set by handle or this function was previously - // called. - if (dump_file_ != INVALID_HANDLE_VALUE) { - return false; - } - - wstring dump_file_path; - if (!GenerateDumpFilePath(&dump_file_path)) { - return false; - } - - dump_file_ = CreateFile(dump_file_path.c_str(), - GENERIC_WRITE, - 0, - NULL, - CREATE_NEW, - FILE_ATTRIBUTE_NORMAL, - NULL); - if (dump_file_ == INVALID_HANDLE_VALUE) { - return false; - } - - dump_file_is_internal_ = true; - *dump_path = dump_file_path; - return true; -} - -bool MinidumpGenerator::GenerateFullDumpFile(wstring* full_dump_path) { - // A full minidump was not requested. - if ((dump_type_ & MiniDumpWithFullMemory) == 0) { - return false; - } - - // The dump file was already set by handle or this function was previously - // called. - if (full_dump_file_ != INVALID_HANDLE_VALUE) { - return false; - } - - wstring full_dump_file_path; - if (!GenerateDumpFilePath(&full_dump_file_path)) { - return false; - } - full_dump_file_path.resize(full_dump_file_path.size() - 4); // strip .dmp - full_dump_file_path.append(TEXT("-full.dmp")); - - full_dump_file_ = CreateFile(full_dump_file_path.c_str(), - GENERIC_WRITE, - 0, - NULL, - CREATE_NEW, - FILE_ATTRIBUTE_NORMAL, - NULL); - if (full_dump_file_ == INVALID_HANDLE_VALUE) { - return false; - } - - full_dump_file_is_internal_ = true; - *full_dump_path = full_dump_file_path; - return true; -} - -HMODULE MinidumpGenerator::GetDbghelpModule() { - AutoCriticalSection lock(&module_load_sync_); - if (!dbghelp_module_) { - dbghelp_module_ = LoadLibrary(TEXT("dbghelp.dll")); - } - - return dbghelp_module_; -} - -MinidumpGenerator::MiniDumpWriteDumpType MinidumpGenerator::GetWriteDump() { - AutoCriticalSection lock(&get_proc_address_sync_); - if (!write_dump_) { - HMODULE module = GetDbghelpModule(); - if (module) { - FARPROC proc = GetProcAddress(module, "MiniDumpWriteDump"); - write_dump_ = reinterpret_cast<MiniDumpWriteDumpType>(proc); - } - } - - return write_dump_; -} - -HMODULE MinidumpGenerator::GetRpcrt4Module() { - AutoCriticalSection lock(&module_load_sync_); - if (!rpcrt4_module_) { - rpcrt4_module_ = LoadLibrary(TEXT("rpcrt4.dll")); - } - - return rpcrt4_module_; -} - -MinidumpGenerator::UuidCreateType MinidumpGenerator::GetCreateUuid() { - AutoCriticalSection lock(&module_load_sync_); - if (!create_uuid_) { - HMODULE module = GetRpcrt4Module(); - if (module) { - FARPROC proc = GetProcAddress(module, "UuidCreate"); - create_uuid_ = reinterpret_cast<UuidCreateType>(proc); - } - } - - return create_uuid_; -} - -bool MinidumpGenerator::GenerateDumpFilePath(wstring* file_path) { - UUID id = {0}; - - UuidCreateType create_uuid = GetCreateUuid(); - if (!create_uuid) { - return false; - } - - create_uuid(&id); - wstring id_str = GUIDString::GUIDToWString(&id); - - *file_path = dump_path_ + TEXT("\\") + id_str + TEXT(".dmp"); - return true; -} - -} // namespace google_breakpad |