in src/client/windows/crash_generation/minidump_generator.cc [307:457]
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;
}