bool MinidumpGenerator::WriteMinidump()

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;
}