DbgHelp教程4——Minidump自定义信息

MiniDumpWriteDump的MINIDUMP_TYPE可以控制往dump里面写入什么信息。不过MINIDUMP_TYPE只是一些固定的类型信息,比如内存、句柄、进程、线程信息,有时候为了定位问题,我们想收集一些其他的数据,然后写入到dump里面。恰好PMINIDUMP_USER_STREAM_INFORMATION参数可以做这个事情。

long WINAPI WriteDump(EXCEPTION_POINTERS *info) {
  HANDLE hDumpFile =
      CreateFile(L"mini.dmp", GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
                 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

  if (hDumpFile != INVALID_HANDLE_VALUE) {

    int minidump_type =
        MiniDumpNormal | MiniDumpWithDataSegs | MiniDumpWithHandleData;
    MINIDUMP_EXCEPTION_INFORMATION dump_exception_info;
    dump_exception_info.ExceptionPointers = info;
    dump_exception_info.ThreadId = GetCurrentThreadId();
    dump_exception_info.ClientPointers = TRUE;

    MINIDUMP_USER_STREAM_INFORMATION user_stream_infomation;
    const ULONG array_size = 10;
    user_stream_infomation.UserStreamCount = array_size;
    user_stream_infomation.UserStreamArray =
        new MINIDUMP_USER_STREAM[array_size];

    for (int i = 0; i < array_size; i++) {
      std::string s("test mimidump user stream infomation");
      char* buffer = new char[s.size() +1];
      memset(buffer, 0 , s.size() + 1);
      memcpy(buffer, s.c_str(), s.size() + 1);
      user_stream_infomation.UserStreamArray[i].Type = 0xfffff+i;
      user_stream_infomation.UserStreamArray[i].BufferSize = s.size() + 1;
      user_stream_infomation.UserStreamArray[i].Buffer = buffer;
    }

    MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hDumpFile,
                      static_cast<MINIDUMP_TYPE>(minidump_type),
                      &dump_exception_info, &user_stream_infomation, NULL);
  }

  return EXCEPTION_CONTINUE_SEARCH;
}

int _tmain(int argc, _TCHAR *argv[]) {

  SetUnhandledExceptionFilter(WriteDump);

  DbgHelpWrapper* p = nullptr;
  p->EnumAllLines();

  return 0;
}

MINIDUMP_USER_STREAM的Type值必须大于MINIDUMP_STREAM_TYPE::LastReservedStream,因为之前这些值都是保留的标准类型。

可惜的是Windbg不能直接读取MINIDUMP_USER_STREAM_INFORMATION的信息,我们只好通过MiniDumpReadDumpStream接口去读取dump里面的数据。

void ReadDump() {
  HANDLE hFile = CreateFile(L"mini.dmp", GENERIC_READ, FILE_SHARE_READ, NULL,
                            OPEN_EXISTING, 0, NULL);
  if ((NULL == hFile) || (INVALID_HANDLE_VALUE == hFile))
    return;

  HANDLE hMapFile = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
  if (NULL == hMapFile)
    return;

  PVOID pViewOfFile = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0);
  if (NULL == pViewOfFile)
    return;

  PMINIDUMP_DIRECTORY minidump_directory = NULL;
  PVOID stream_pointer = NULL;
  ULONG stream_size = 0;
  if (!MiniDumpReadDumpStream(pViewOfFile, 0xfffff+1, &minidump_directory,
                              &stream_pointer, &stream_size))
    return;

  std::string s((char*)stream_pointer);
  cout << s << endl;
}

根据MINIDUMP_STREAM_TYPE的描述,我们还可以从dump文件里面读取一些预置的信息,比如线程列表、模块列表、内存列表、异常信息、系统信息、句柄信息、函数表信息、等等。