diff options
Diffstat (limited to 'src/client/windows/crash_generation/minidump_generator.cc')
-rw-r--r-- | src/client/windows/crash_generation/minidump_generator.cc | 325 |
1 files changed, 147 insertions, 178 deletions
diff --git a/src/client/windows/crash_generation/minidump_generator.cc b/src/client/windows/crash_generation/minidump_generator.cc index 652c1c9a..22e8d365 100644 --- a/src/client/windows/crash_generation/minidump_generator.cc +++ b/src/client/windows/crash_generation/minidump_generator.cc @@ -243,10 +243,33 @@ ULONG CALLBACK HandleTraceData::RecordHandleOperations( namespace google_breakpad { -MinidumpGenerator::MinidumpGenerator(const wstring& dump_path) +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), rpcrt4_module_(NULL), dump_path_(dump_path), + 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_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), write_dump_(NULL), create_uuid_(NULL) { InitializeCriticalSection(&module_load_sync_); @@ -254,6 +277,14 @@ MinidumpGenerator::MinidumpGenerator(const wstring& dump_path) } 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_); } @@ -266,141 +297,10 @@ MinidumpGenerator::~MinidumpGenerator() { DeleteCriticalSection(&module_load_sync_); } -bool MinidumpGenerator::WriteMinidump(HANDLE process_handle, - DWORD process_id, - DWORD thread_id, - DWORD requesting_thread_id, - EXCEPTION_POINTERS* exception_pointers, - MDRawAssertionInfo* assert_info, - MINIDUMP_TYPE dump_type, - bool is_client_pointers, - wstring* dump_path) { - // Just call the full WriteMinidump with NULL as the full_dump_path. - return this->WriteMinidump(process_handle, process_id, thread_id, - requesting_thread_id, exception_pointers, - assert_info, dump_type, is_client_pointers, - dump_path, NULL); -} - -bool MinidumpGenerator::WriteMinidump(HANDLE process_handle, - DWORD process_id, - DWORD thread_id, - DWORD requesting_thread_id, - EXCEPTION_POINTERS* exception_pointers, - MDRawAssertionInfo* assert_info, - MINIDUMP_TYPE dump_type, - bool is_client_pointers, - wstring* dump_path, - wstring* full_dump_path) { - wstring dump_file_path; - if (!GenerateDumpFilePath(&dump_file_path)) { - return false; - } - - // If the client requests a full memory dump, we will write a normal mini - // dump and a full memory dump. Both dump files use the same uuid as file - // name prefix. - bool full_memory_dump = (dump_type & MiniDumpWithFullMemory) != 0; - wstring full_dump_file_path; - if (full_memory_dump) { - full_dump_file_path.assign(dump_file_path); - full_dump_file_path.resize(full_dump_file_path.size() - 4); // strip .dmp - full_dump_file_path.append(TEXT("-full.dmp")); - } - - HANDLE 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; - } - - HANDLE full_dump_file = INVALID_HANDLE_VALUE; - if (full_memory_dump) { - 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) { - CloseHandle(dump_file); - return false; - } - } - - bool result = WriteMinidump(process_handle, - process_id, - thread_id, - requesting_thread_id, - exception_pointers, - assert_info, - dump_type, - is_client_pointers, - dump_file, - full_dump_file); - - // Store the path of the dump file in the out parameter if dump generation - // succeeded. - if (result && dump_path) { - *dump_path = dump_file_path; - } - if (result && full_memory_dump && full_dump_path) { - *full_dump_path = full_dump_file_path; - } - - CloseHandle(dump_file); - if (full_dump_file != INVALID_HANDLE_VALUE) - CloseHandle(full_dump_file); - - return result; -} - -bool MinidumpGenerator::WriteMinidump(HANDLE process_handle, - DWORD process_id, - DWORD thread_id, - DWORD requesting_thread_id, - EXCEPTION_POINTERS* exception_pointers, - MDRawAssertionInfo* assert_info, - MINIDUMP_TYPE dump_type, - bool is_client_pointers, - HANDLE dump_file, - HANDLE full_dump_file) { - return WriteMinidump(process_handle, - process_id, - thread_id, - requesting_thread_id, - exception_pointers, - assert_info, - dump_type, - is_client_pointers, - dump_file, - full_dump_file, - NULL); -} - -bool MinidumpGenerator::WriteMinidump( - HANDLE process_handle, - DWORD process_id, - DWORD thread_id, - DWORD requesting_thread_id, - EXCEPTION_POINTERS* exception_pointers, - MDRawAssertionInfo* assert_info, - MINIDUMP_TYPE dump_type, - bool is_client_pointers, - HANDLE dump_file, - HANDLE full_dump_file, - MINIDUMP_USER_STREAM_INFORMATION* additional_streams) { - bool full_memory_dump = (dump_type & MiniDumpWithFullMemory) != 0; - if (dump_file == INVALID_HANDLE_VALUE || - (full_memory_dump && full_dump_file == INVALID_HANDLE_VALUE)) { +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; } @@ -414,11 +314,11 @@ bool MinidumpGenerator::WriteMinidump( // Setup the exception information object only if it's a dump // due to an exception. - if (exception_pointers) { + 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; + 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 @@ -428,17 +328,17 @@ bool MinidumpGenerator::WriteMinidump( // 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) { + 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; + 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; + 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; @@ -449,29 +349,33 @@ bool MinidumpGenerator::WriteMinidump( user_streams.UserStreamCount = 1; user_streams.UserStreamArray = user_stream_array.get(); - MDRawAssertionInfo* actual_assert_info = assert_info; + MDRawAssertionInfo* actual_assert_info = assert_info_; MDRawAssertionInfo client_assert_info = {0}; - if (assert_info) { + if (assert_info_) { // If the assertion info object lives in the client process, // read the memory of the client process. - if (is_client_pointers) { + if (is_client_pointers_) { SIZE_T bytes_read = 0; - if (!ReadProcessMemory(process_handle, - assert_info, + if (!ReadProcessMemory(process_handle_, + assert_info_, &client_assert_info, sizeof(client_assert_info), &bytes_read)) { - CloseHandle(dump_file); - if (full_dump_file != INVALID_HANDLE_VALUE) - CloseHandle(full_dump_file); + 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)) { - CloseHandle(dump_file); - if (full_dump_file != INVALID_HANDLE_VALUE) - CloseHandle(full_dump_file); + 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; } @@ -484,16 +388,16 @@ bool MinidumpGenerator::WriteMinidump( ++user_streams.UserStreamCount; } - if (additional_streams) { + if (additional_streams_) { for (size_t i = 0; - i < additional_streams->UserStreamCount; + i < additional_streams_->UserStreamCount; i++, user_streams.UserStreamCount++) { user_stream_array[user_streams.UserStreamCount].Type = - additional_streams->UserStreamArray[i].Type; + additional_streams_->UserStreamArray[i].Type; user_stream_array[user_streams.UserStreamCount].BufferSize = - additional_streams->UserStreamArray[i].BufferSize; + additional_streams_->UserStreamArray[i].BufferSize; user_stream_array[user_streams.UserStreamCount].Buffer = - additional_streams->UserStreamArray[i].Buffer; + additional_streams_->UserStreamArray[i].Buffer; } } @@ -501,12 +405,14 @@ bool MinidumpGenerator::WriteMinidump( // 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)) { - CloseHandle(dump_file); - if (full_dump_file != INVALID_HANDLE_VALUE) - CloseHandle(full_dump_file); + 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; } } @@ -514,12 +420,12 @@ bool MinidumpGenerator::WriteMinidump( 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)) + process_handle_, + process_id_, + full_dump_file_, + static_cast<MINIDUMP_TYPE>((dump_type_ & (~MiniDumpNormal)) | MiniDumpWithHandleData), - exception_pointers ? &dump_exception_info : NULL, + exception_pointers_ ? &dump_exception_info : NULL, &user_streams, NULL) != FALSE; } @@ -531,18 +437,81 @@ bool MinidumpGenerator::WriteMinidump( } bool result_minidump = write_dump( - process_handle, - process_id, - dump_file, - static_cast<MINIDUMP_TYPE>((dump_type & (~MiniDumpWithFullMemory)) + process_handle_, + process_id_, + dump_file_, + static_cast<MINIDUMP_TYPE>((dump_type_ & (~MiniDumpWithFullMemory)) | MiniDumpNormal), - exception_pointers ? &dump_exception_info : NULL, + exception_pointers_ ? &dump_exception_info : NULL, &user_streams, - NULL) != FALSE; + 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_) { |