|
|
/*++
Copyright (c) 1990-2000 Microsoft Corporation
Module Name:
userdump.c
Abstract:
This module implements full user-mode dump writing.
--*/
#include "private.h"
// hack to make it build
typedef ULONG UNICODE_STRING32; typedef ULONG UNICODE_STRING64;
#include <ntiodump.h>
DWORD_PTR DmppGetFilePointer( HANDLE hFile ) { #ifdef _WIN64
LONG dwHigh = 0;
return SetFilePointer(hFile, 0, &dwHigh, FILE_CURRENT) | ((DWORD_PTR)dwHigh << 32); #else
return SetFilePointer(hFile, 0, NULL, FILE_CURRENT); #endif
}
WCHAR * DmppGetHotFixString( ) { WCHAR *pszBigBuffer = NULL; HKEY hkey = 0;
//
// Get the hot fixes. Concat hotfixes into a list that looks like:
// "Qxxxx, Qxxxx, Qxxxx, Qxxxx"
//
RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix", 0, KEY_READ, &hkey);
if (hkey) { DWORD dwMaxKeyNameLen = 0; DWORD dwNumSubKeys = 0; WCHAR *pszNameBuffer = NULL; if (ERROR_SUCCESS != RegQueryInfoKeyW(hkey, // handle of key to query
NULL, // address of buffer for class string
NULL, // address of size of class string buffer
0, // reserved
&dwNumSubKeys, // address of buffer for number of subkeys
&dwMaxKeyNameLen, // address of buffer for longest subkey name length
NULL, // address of buffer for longest class string length
NULL, // address of buffer for number of value entries
NULL, // address of buffer for longest value name length
NULL, // address of buffer for longest value data length
NULL, // address of buffer for security descriptor length
NULL)) { // address of buffer for last write time);
pszNameBuffer = (WCHAR *) calloc(dwMaxKeyNameLen, sizeof(WCHAR)); pszBigBuffer = (WCHAR *) calloc(dwMaxKeyNameLen * dwNumSubKeys // Factor in the space required for each ", " between the hotfixes
+ (dwNumSubKeys -1) * 2, sizeof(WCHAR)); if (!pszNameBuffer || !pszBigBuffer) { if (pszBigBuffer) { free(pszBigBuffer); pszBigBuffer = NULL; } } else { DWORD dw; // So far so good, get each entry
for (dw=0; dw<dwNumSubKeys; dw++) { DWORD dwSize = dwMaxKeyNameLen; if (ERROR_SUCCESS == RegEnumKeyExW(hkey, dw, pszNameBuffer, &dwSize, 0, NULL, NULL, NULL)) {
// concat the list
wcscat(pszBigBuffer, pszNameBuffer); if (dw < dwNumSubKeys-1) { wcscat(pszBigBuffer, L", "); } } } } } if (pszNameBuffer) { free(pszNameBuffer); }
RegCloseKey(hkey); }
return pszBigBuffer; }
BOOL DbgHelpCreateUserDump( LPSTR CrashDumpName, PDBGHELP_CREATE_USER_DUMP_CALLBACK DmpCallback, PVOID lpv ) { UINT uSizeDumpFile; UINT uSizeUnicode; PWSTR pwszUnicode = NULL; BOOL b;
if (CrashDumpName) { uSizeDumpFile = strlen(CrashDumpName); uSizeUnicode = (uSizeDumpFile + 1) * sizeof(wchar_t); pwszUnicode = (PWSTR)calloc(uSizeUnicode, 1); if (!pwszUnicode) { return FALSE; } *pwszUnicode = UNICODE_NULL; if (*CrashDumpName) {
if (!MultiByteToWideChar(CP_ACP, MB_COMPOSITE, CrashDumpName, uSizeDumpFile, pwszUnicode, uSizeUnicode)) { // Error. Free the string, return NULL.
free(pwszUnicode); return FALSE; } } }
b = DbgHelpCreateUserDumpW(pwszUnicode, DmpCallback, lpv);
if (pwszUnicode) { free(pwszUnicode); } return b; }
BOOL DbgHelpCreateUserDumpW( LPWSTR CrashDumpName, PDBGHELP_CREATE_USER_DUMP_CALLBACK DmpCallback, PVOID lpv )
/*++
Routine Description:
Create a usermode dump file.
Arguments:
CrashDumpName - Supplies a name for the dump file.
DmpCallback - Supplies a pointer to a callback function pointer which will provide debugger service such as ReadMemory and GetContext.
lpv - Supplies private data which is sent to the callback functions.
Return Value:
TRUE - Success.
FALSE - Error.
--*/
{ OSVERSIONINFO OsVersion = {0}; USERMODE_CRASHDUMP_HEADER DumpHeader = {0}; DWORD cb; HANDLE hFile = INVALID_HANDLE_VALUE; BOOL rval; PVOID DumpData; DWORD DumpDataLength; SECURITY_ATTRIBUTES SecAttrib; SECURITY_DESCRIPTOR SecDescript;
if (CrashDumpName == NULL) { DmpCallback( DMP_DUMP_FILE_HANDLE, &hFile, &DumpDataLength, lpv ); } else { //
// Create a DACL that allows all access to the directory
//
SecAttrib.nLength = sizeof(SECURITY_ATTRIBUTES); SecAttrib.lpSecurityDescriptor = &SecDescript; SecAttrib.bInheritHandle = FALSE;
InitializeSecurityDescriptor(&SecDescript, SECURITY_DESCRIPTOR_REVISION); SetSecurityDescriptorDacl(&SecDescript, TRUE, NULL, FALSE);
hFile = CreateFileW( CrashDumpName, GENERIC_READ | GENERIC_WRITE, 0, &SecAttrib, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); }
if ((hFile == NULL) || (hFile == INVALID_HANDLE_VALUE)) { return FALSE; }
// Write out an empty header
if (!WriteFile( hFile, &DumpHeader, sizeof(DumpHeader), &cb, NULL )) { goto bad_file; }
//
// write the debug event
//
DumpHeader.DebugEventOffset = DmppGetFilePointer( hFile ); DmpCallback( DMP_DEBUG_EVENT, &DumpData, &DumpDataLength, lpv ); if (!WriteFile( hFile, DumpData, sizeof(DEBUG_EVENT), &cb, NULL )) { goto bad_file; }
//
// write the memory map
//
DumpHeader.MemoryRegionOffset = DmppGetFilePointer( hFile ); do { __try { rval = DmpCallback( DMP_MEMORY_BASIC_INFORMATION, &DumpData, &DumpDataLength, lpv ); } __except (EXCEPTION_EXECUTE_HANDLER) { rval = FALSE; } if (rval) { DumpHeader.MemoryRegionCount += 1; if (!WriteFile( hFile, DumpData, sizeof(MEMORY_BASIC_INFORMATION), &cb, NULL )) { goto bad_file; } } } while( rval );
//
// write the thread contexts
//
DumpHeader.ThreadOffset = DmppGetFilePointer( hFile ); do { __try { rval = DmpCallback( DMP_THREAD_CONTEXT, &DumpData, &DumpDataLength, lpv ); } __except (EXCEPTION_EXECUTE_HANDLER) { rval = FALSE; } if (rval) { if (!WriteFile( hFile, DumpData, DumpDataLength, &cb, NULL )) { goto bad_file; } DumpHeader.ThreadCount += 1; } } while( rval );
//
// write the thread states
//
DumpHeader.ThreadStateOffset = DmppGetFilePointer( hFile ); do { __try { rval = DmpCallback( DMP_THREAD_STATE, &DumpData, &DumpDataLength, lpv ); } __except (EXCEPTION_EXECUTE_HANDLER) { rval = FALSE; } if (rval) { if (!WriteFile( hFile, DumpData, sizeof(CRASH_THREAD), &cb, NULL )) { goto bad_file; } } } while( rval );
//
// write the module table
//
DumpHeader.ModuleOffset = DmppGetFilePointer( hFile ); do { __try { rval = DmpCallback( DMP_MODULE, &DumpData, &DumpDataLength, lpv ); } __except (EXCEPTION_EXECUTE_HANDLER) { rval = FALSE; } if (rval) { if (!WriteFile( hFile, DumpData, sizeof(CRASH_MODULE) + ((PCRASH_MODULE)DumpData)->ImageNameLength, &cb, NULL )) { goto bad_file; } DumpHeader.ModuleCount += 1; } } while( rval );
//
// write the virtual memory
//
DumpHeader.DataOffset = DmppGetFilePointer( hFile ); do { __try { rval = DmpCallback( DMP_MEMORY_DATA, &DumpData, &DumpDataLength, lpv ); } __except (EXCEPTION_EXECUTE_HANDLER) { rval = FALSE; } if (rval) { if (!WriteFile( hFile, DumpData, DumpDataLength, &cb, NULL )) { goto bad_file; } } } while( rval );
//
// VersionInfoOffset will be an offset into the dump file that will contain
// misc information about drwatson. The format of the information
// will be a series of NULL terminated strings with two zero
// terminating the multistring. The string will be UNICODE.
//
// FORMAT:
// This data refers to the specific data about Dr. Watson
// DRW: OS version: XX.XX
// OS version of headers
// DRW: build: XXXX
// Build number of Dr. Watson binary
// DRW: QFE: X
// QFE number of the Dr. Watson binary
// Refers to info describing the OS on which the app crashed,
// including Service pack, hotfixes, etc...
// CRASH: OS SP: X
// Service Pack number of the OS where the app AV'd (we
// already store the build number, but not the SP)
//
DumpHeader.VersionInfoOffset = DmppGetFilePointer( hFile );
OsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx( &OsVersion );
{ WCHAR szBuf[1024] = {0}; WCHAR * psz = szBuf; WCHAR * pszHotfixes;
wcscat(psz, L"DRW: OS version"); psz += wcslen(psz) +1; // Let the printf function convert it from ANSI to unicode
swprintf(psz, L"%S", VER_PRODUCTVERSION_STRING); psz += wcslen(psz) +1; wcscat(psz, L"DRW: build"); psz += wcslen(psz) +1; swprintf(psz, L"%d", (int) VER_PRODUCTBUILD); psz += wcslen(psz) +1;
wcscat(psz, L"DRW: QFE"); psz += wcslen(psz) +1; swprintf(psz, L"%d", (int) VER_PRODUCTBUILD_QFE); psz += wcslen(psz) +1;
wcscat(psz, L"CRASH: OS SP"); psz += wcslen(psz) +1; if (OsVersion.szCSDVersion[0]) { // Let the printf function convert it from ANSI to unicode
swprintf(psz, L"%S", OsVersion.szCSDVersion); } else { wcscat(psz, L"none"); } psz += wcslen(psz) +1;
wcscat(psz, L"CRASH: Hotfixes"); psz += wcslen(psz) +1; pszHotfixes = DmppGetHotFixString (); if (pszHotfixes) { wcscat(psz, pszHotfixes); free(pszHotfixes); } else { wcscat(psz, L"none"); } psz += wcslen(psz) +1;
// Include last terminating zero
psz++;
// Calc length of data. This should always fit in a ULONG.
DumpDataLength = (ULONG)((PBYTE) psz - (PBYTE) szBuf); if (!WriteFile( hFile, szBuf, DumpDataLength, &cb, NULL )) { goto bad_file; } }
//
// re-write the dump header with some valid data
//
DumpHeader.Signature = USERMODE_CRASHDUMP_SIGNATURE; DumpHeader.MajorVersion = OsVersion.dwMajorVersion; DumpHeader.MinorVersion = (OsVersion.dwMinorVersion & 0xffff) | (OsVersion.dwBuildNumber << 16); #if defined(_M_IX86)
DumpHeader.MachineImageType = IMAGE_FILE_MACHINE_I386; DumpHeader.ValidDump = USERMODE_CRASHDUMP_VALID_DUMP32; #elif defined(_M_IA64)
DumpHeader.MachineImageType = IMAGE_FILE_MACHINE_IA64; DumpHeader.ValidDump = USERMODE_CRASHDUMP_VALID_DUMP64; #elif defined(_M_AXP64)
DumpHeader.MachineImageType = IMAGE_FILE_MACHINE_AXP64; DumpHeader.ValidDump = USERMODE_CRASHDUMP_VALID_DUMP64; #elif defined(_M_ALPHA)
DumpHeader.MachineImageType = IMAGE_FILE_MACHINE_ALPHA; DumpHeader.ValidDump = USERMODE_CRASHDUMP_VALID_DUMP32; #elif defined(_M_AMD64)
DumpHeader.MachineImageType = IMAGE_FILE_MACHINE_AMD64; DumpHeader.ValidDump = USERMODE_CRASHDUMP_VALID_DUMP64; #else
#error( "unknown target machine" );
#endif
SetFilePointer( hFile, 0, 0, FILE_BEGIN ); if (!WriteFile( hFile, &DumpHeader, sizeof(DumpHeader), &cb, NULL )) { goto bad_file; }
//
// close the file
//
if (CrashDumpName) { CloseHandle( hFile ); } return TRUE;
bad_file:
if (CrashDumpName) { CloseHandle( hFile ); }
DeleteFileW( CrashDumpName );
return FALSE; }
|