Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

562 lines
16 KiB

  1. /*++
  2. Copyright (c) 1990-2000 Microsoft Corporation
  3. Module Name:
  4. userdump.c
  5. Abstract:
  6. This module implements full user-mode dump writing.
  7. --*/
  8. #include "private.h"
  9. // hack to make it build
  10. typedef ULONG UNICODE_STRING32;
  11. typedef ULONG UNICODE_STRING64;
  12. #include <ntiodump.h>
  13. #include <cmnutil.hpp>
  14. // This should match INVALID_SET_FILE_POINTER on 32-bit systems.
  15. #define DMPP_INVALID_OFFSET ((DWORD_PTR)-1)
  16. DWORD_PTR
  17. DmppGetFilePointer(
  18. HANDLE hFile
  19. )
  20. {
  21. #ifdef _WIN64
  22. LONG dwHigh = 0;
  23. DWORD dwLow;
  24. dwLow = SetFilePointer(hFile, 0, &dwHigh, FILE_CURRENT);
  25. if (dwLow == INVALID_SET_FILE_POINTER && GetLastError()) {
  26. return DMPP_INVALID_OFFSET;
  27. } else {
  28. return dwLow | ((DWORD_PTR)dwHigh << 32);
  29. }
  30. #else
  31. return SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
  32. #endif
  33. }
  34. BOOL
  35. DmppWriteAll(
  36. HANDLE hFile,
  37. LPVOID pBuffer,
  38. DWORD dwLength
  39. )
  40. {
  41. DWORD dwDone;
  42. if (!WriteFile(hFile, pBuffer, dwLength, &dwDone, NULL)) {
  43. return FALSE;
  44. }
  45. if (dwDone != dwLength) {
  46. SetLastError(ERROR_WRITE_FAULT);
  47. return FALSE;
  48. }
  49. return TRUE;
  50. }
  51. WCHAR *
  52. DmppGetHotFixString(
  53. )
  54. {
  55. WCHAR *pszBigBuffer = NULL;
  56. HKEY hkey = 0;
  57. //
  58. // Get the hot fixes. Concat hotfixes into a list that looks like:
  59. // "Qxxxx, Qxxxx, Qxxxx, Qxxxx"
  60. //
  61. RegOpenKeyExW(HKEY_LOCAL_MACHINE,
  62. L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Hotfix", 0, KEY_READ, &hkey);
  63. if (hkey) {
  64. DWORD dwMaxKeyNameLen = 0;
  65. DWORD dwNumSubKeys = 0;
  66. WCHAR *pszNameBuffer = NULL;
  67. if (ERROR_SUCCESS != RegQueryInfoKeyW(hkey, // handle of key to query
  68. NULL, // address of buffer for class string
  69. NULL, // address of size of class string buffer
  70. 0, // reserved
  71. &dwNumSubKeys, // address of buffer for number of subkeys
  72. &dwMaxKeyNameLen, // address of buffer for longest subkey name length
  73. NULL, // address of buffer for longest class string length
  74. NULL, // address of buffer for number of value entries
  75. NULL, // address of buffer for longest value name length
  76. NULL, // address of buffer for longest value data length
  77. NULL, // address of buffer for security descriptor length
  78. NULL)) { // address of buffer for last write time);
  79. pszNameBuffer = (WCHAR *) calloc(dwMaxKeyNameLen, sizeof(WCHAR));
  80. pszBigBuffer = (WCHAR *) calloc(dwMaxKeyNameLen * dwNumSubKeys
  81. // Factor in the space required for each ", " between the hotfixes
  82. + (dwNumSubKeys -1) * 2, sizeof(WCHAR));
  83. if (!pszNameBuffer || !pszBigBuffer) {
  84. if (pszBigBuffer) {
  85. free(pszBigBuffer);
  86. pszBigBuffer = NULL;
  87. }
  88. } else {
  89. DWORD dw;
  90. // So far so good, get each entry
  91. for (dw=0; dw<dwNumSubKeys; dw++) {
  92. DWORD dwSize = dwMaxKeyNameLen;
  93. if (ERROR_SUCCESS == RegEnumKeyExW(hkey,
  94. dw,
  95. pszNameBuffer,
  96. &dwSize,
  97. 0,
  98. NULL,
  99. NULL,
  100. NULL)) {
  101. // concat the list
  102. wcscat(pszBigBuffer, pszNameBuffer);
  103. if (dw < dwNumSubKeys-1) {
  104. wcscat(pszBigBuffer, L", ");
  105. }
  106. }
  107. }
  108. }
  109. }
  110. if (pszNameBuffer) {
  111. free(pszNameBuffer);
  112. }
  113. RegCloseKey(hkey);
  114. }
  115. return pszBigBuffer;
  116. }
  117. BOOL
  118. DbgHelpCreateUserDump(
  119. LPSTR CrashDumpName,
  120. PDBGHELP_CREATE_USER_DUMP_CALLBACK DmpCallback,
  121. PVOID lpv
  122. )
  123. {
  124. UINT uSizeDumpFile;
  125. UINT uSizeUnicode;
  126. PWSTR pwszUnicode = NULL;
  127. BOOL b;
  128. if (CrashDumpName) {
  129. uSizeDumpFile = strlen(CrashDumpName);
  130. uSizeUnicode = (uSizeDumpFile + 1) * sizeof(wchar_t);
  131. pwszUnicode = (PWSTR)calloc(uSizeUnicode, 1);
  132. if (!pwszUnicode) {
  133. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  134. return FALSE;
  135. }
  136. *pwszUnicode = UNICODE_NULL;
  137. if (*CrashDumpName) {
  138. if (!MultiByteToWideChar(CP_ACP, MB_COMPOSITE,
  139. CrashDumpName, uSizeDumpFile,
  140. pwszUnicode, uSizeUnicode))
  141. {
  142. // Error. Free the string, return NULL.
  143. free(pwszUnicode);
  144. return FALSE;
  145. }
  146. }
  147. }
  148. b = DbgHelpCreateUserDumpW(pwszUnicode, DmpCallback, lpv);
  149. if (pwszUnicode) {
  150. free(pwszUnicode);
  151. }
  152. return b;
  153. }
  154. BOOL
  155. DbgHelpCreateUserDumpW(
  156. LPWSTR CrashDumpName,
  157. PDBGHELP_CREATE_USER_DUMP_CALLBACK DmpCallback,
  158. PVOID lpv
  159. )
  160. /*++
  161. Routine Description:
  162. Create a usermode dump file.
  163. Arguments:
  164. CrashDumpName - Supplies a name for the dump file.
  165. DmpCallback - Supplies a pointer to a callback function pointer which
  166. will provide debugger service such as ReadMemory and GetContext.
  167. lpv - Supplies private data which is sent to the callback functions.
  168. Return Value:
  169. TRUE - Success.
  170. FALSE - Error.
  171. --*/
  172. {
  173. OSVERSIONINFO OsVersion = {0};
  174. USERMODE_CRASHDUMP_HEADER DumpHeader = {0};
  175. HANDLE hFile = INVALID_HANDLE_VALUE;
  176. BOOL rval;
  177. PVOID DumpData;
  178. DWORD DumpDataLength;
  179. #ifndef _WIN64
  180. C_ASSERT(DMPP_INVALID_OFFSET == INVALID_SET_FILE_POINTER);
  181. #endif
  182. if (CrashDumpName == NULL) {
  183. DmpCallback( DMP_DUMP_FILE_HANDLE, &hFile, &DumpDataLength, lpv );
  184. } else {
  185. //
  186. // This code used to create an explicit NULL DACL
  187. // security descriptor so that the resulting
  188. // dump file is all-access. This caused problems
  189. // with people and tools scanning the code for NULL DACL
  190. // usage. Rather than try to create a complicated
  191. // "correct" security descriptor, we just use no
  192. // descriptor and get default security. If the caller
  193. // desires specific security they can create their
  194. // own file and pass in the handle via DMP_DUMP_FILE_HANDLE.
  195. //
  196. hFile = CreateFileW(
  197. CrashDumpName,
  198. GENERIC_READ | GENERIC_WRITE,
  199. 0,
  200. NULL,
  201. CREATE_ALWAYS,
  202. FILE_ATTRIBUTE_NORMAL,
  203. NULL);
  204. }
  205. if ((hFile == NULL) || (hFile == INVALID_HANDLE_VALUE)) {
  206. return FALSE;
  207. }
  208. // Write out an empty header
  209. if (!DmppWriteAll( hFile, &DumpHeader, sizeof(DumpHeader) )) {
  210. goto bad_file;
  211. }
  212. //
  213. // write the debug event
  214. //
  215. DumpHeader.DebugEventOffset = DmppGetFilePointer( hFile );
  216. if (DumpHeader.DebugEventOffset == DMPP_INVALID_OFFSET) {
  217. goto bad_file;
  218. }
  219. DmpCallback( DMP_DEBUG_EVENT, &DumpData, &DumpDataLength, lpv );
  220. if (!DmppWriteAll( hFile, DumpData, sizeof(DEBUG_EVENT) )) {
  221. goto bad_file;
  222. }
  223. //
  224. // write the memory map
  225. //
  226. DumpHeader.MemoryRegionOffset = DmppGetFilePointer( hFile );
  227. if (DumpHeader.MemoryRegionOffset == DMPP_INVALID_OFFSET) {
  228. goto bad_file;
  229. }
  230. do {
  231. __try {
  232. rval = DmpCallback(
  233. DMP_MEMORY_BASIC_INFORMATION,
  234. &DumpData,
  235. &DumpDataLength,
  236. lpv
  237. );
  238. } __except (EXCEPTION_EXECUTE_HANDLER) {
  239. rval = FALSE;
  240. }
  241. if (rval) {
  242. DumpHeader.MemoryRegionCount += 1;
  243. if (!DmppWriteAll( hFile, DumpData, sizeof(MEMORY_BASIC_INFORMATION) )) {
  244. goto bad_file;
  245. }
  246. }
  247. } while( rval );
  248. //
  249. // write the thread contexts
  250. //
  251. DumpHeader.ThreadOffset = DmppGetFilePointer( hFile );
  252. if (DumpHeader.ThreadOffset == DMPP_INVALID_OFFSET) {
  253. goto bad_file;
  254. }
  255. do {
  256. __try {
  257. rval = DmpCallback(
  258. DMP_THREAD_CONTEXT,
  259. &DumpData,
  260. &DumpDataLength,
  261. lpv
  262. );
  263. } __except (EXCEPTION_EXECUTE_HANDLER) {
  264. rval = FALSE;
  265. }
  266. if (rval) {
  267. if (!DmppWriteAll( hFile, DumpData, DumpDataLength )) {
  268. goto bad_file;
  269. }
  270. DumpHeader.ThreadCount += 1;
  271. }
  272. } while( rval );
  273. //
  274. // write the thread states
  275. //
  276. DumpHeader.ThreadStateOffset = DmppGetFilePointer( hFile );
  277. if (DumpHeader.ThreadStateOffset == DMPP_INVALID_OFFSET) {
  278. goto bad_file;
  279. }
  280. do {
  281. __try {
  282. rval = DmpCallback(
  283. DMP_THREAD_STATE,
  284. &DumpData,
  285. &DumpDataLength,
  286. lpv
  287. );
  288. } __except (EXCEPTION_EXECUTE_HANDLER) {
  289. rval = FALSE;
  290. }
  291. if (rval) {
  292. if (!DmppWriteAll( hFile, DumpData, sizeof(CRASH_THREAD) )) {
  293. goto bad_file;
  294. }
  295. }
  296. } while( rval );
  297. //
  298. // write the module table
  299. //
  300. DumpHeader.ModuleOffset = DmppGetFilePointer( hFile );
  301. if (DumpHeader.ModuleOffset == DMPP_INVALID_OFFSET) {
  302. goto bad_file;
  303. }
  304. do {
  305. __try {
  306. rval = DmpCallback(
  307. DMP_MODULE,
  308. &DumpData,
  309. &DumpDataLength,
  310. lpv
  311. );
  312. } __except (EXCEPTION_EXECUTE_HANDLER) {
  313. rval = FALSE;
  314. }
  315. if (rval) {
  316. if (!DmppWriteAll(
  317. hFile,
  318. DumpData,
  319. sizeof(CRASH_MODULE) +
  320. ((PCRASH_MODULE)DumpData)->ImageNameLength
  321. )) {
  322. goto bad_file;
  323. }
  324. DumpHeader.ModuleCount += 1;
  325. }
  326. } while( rval );
  327. //
  328. // write the virtual memory
  329. //
  330. DumpHeader.DataOffset = DmppGetFilePointer( hFile );
  331. if (DumpHeader.DataOffset == DMPP_INVALID_OFFSET) {
  332. goto bad_file;
  333. }
  334. do {
  335. __try {
  336. rval = DmpCallback(
  337. DMP_MEMORY_DATA,
  338. &DumpData,
  339. &DumpDataLength,
  340. lpv
  341. );
  342. } __except (EXCEPTION_EXECUTE_HANDLER) {
  343. rval = FALSE;
  344. }
  345. if (rval) {
  346. if (!DmppWriteAll(
  347. hFile,
  348. DumpData,
  349. DumpDataLength
  350. )) {
  351. goto bad_file;
  352. }
  353. }
  354. } while( rval );
  355. //
  356. // VersionInfoOffset will be an offset into the dump file that will contain
  357. // misc information about drwatson. The format of the information
  358. // will be a series of NULL terminated strings with two zero
  359. // terminating the multistring. The string will be UNICODE.
  360. //
  361. // FORMAT:
  362. // This data refers to the specific data about Dr. Watson
  363. // DRW: OS version: XX.XX
  364. // OS version of headers
  365. // DRW: build: XXXX
  366. // Build number of Dr. Watson binary
  367. // DRW: QFE: X
  368. // QFE number of the Dr. Watson binary
  369. // Refers to info describing the OS on which the app crashed,
  370. // including Service pack, hotfixes, etc...
  371. // CRASH: OS SP: X
  372. // Service Pack number of the OS where the app AV'd (we
  373. // already store the build number, but not the SP)
  374. //
  375. DumpHeader.VersionInfoOffset = DmppGetFilePointer( hFile );
  376. if (DumpHeader.VersionInfoOffset == DMPP_INVALID_OFFSET) {
  377. goto bad_file;
  378. }
  379. OsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  380. if (!GetVersionEx( &OsVersion )) {
  381. goto bad_file;
  382. }
  383. {
  384. WCHAR szBuf[1024] = {0};
  385. WCHAR * psz = szBuf;
  386. ULONG Left = DIMA(szBuf) - 1;
  387. ULONG Len;
  388. WCHAR * pszHotfixes;
  389. #define ADVANCE() \
  390. Len = wcslen(psz) + 1; \
  391. if (Len <= Left) { psz += Len; Left -= Len; } else { Left = 0; }
  392. CatStringW(psz, L"DRW: OS version", Left);
  393. ADVANCE();
  394. // Let the printf function convert it from ANSI to unicode
  395. PrintStringW(psz, Left, L"%S", VER_PRODUCTVERSION_STRING);
  396. ADVANCE();
  397. CatStringW(psz, L"DRW: build", Left);
  398. ADVANCE();
  399. PrintStringW(psz, Left, L"%d", (int) VER_PRODUCTBUILD);
  400. ADVANCE();
  401. CatStringW(psz, L"DRW: QFE", Left);
  402. ADVANCE();
  403. PrintStringW(psz, Left, L"%d", (int) VER_PRODUCTBUILD_QFE);
  404. ADVANCE();
  405. CatStringW(psz, L"CRASH: OS SP", Left);
  406. ADVANCE();
  407. if (OsVersion.szCSDVersion[0]) {
  408. // Let the printf function convert it from ANSI to unicode
  409. PrintStringW(psz, Left, L"%S", OsVersion.szCSDVersion);
  410. } else {
  411. CatStringW(psz, L"none", Left);
  412. }
  413. ADVANCE();
  414. CatStringW(psz, L"CRASH: Hotfixes", Left);
  415. ADVANCE();
  416. pszHotfixes = DmppGetHotFixString ();
  417. if (pszHotfixes) {
  418. CatStringW(psz, pszHotfixes, Left);
  419. free(pszHotfixes);
  420. } else {
  421. CatStringW(psz, L"none", Left);
  422. }
  423. ADVANCE();
  424. // Include last terminating zero
  425. *psz++ = 0;
  426. // Calc length of data. This should always fit in a ULONG.
  427. DumpDataLength = (ULONG)((PBYTE) psz - (PBYTE) szBuf);
  428. if (!DmppWriteAll(
  429. hFile,
  430. szBuf,
  431. DumpDataLength
  432. )) {
  433. goto bad_file;
  434. }
  435. }
  436. //
  437. // re-write the dump header with some valid data
  438. //
  439. DumpHeader.Signature = USERMODE_CRASHDUMP_SIGNATURE;
  440. DumpHeader.MajorVersion = OsVersion.dwMajorVersion;
  441. DumpHeader.MinorVersion =
  442. (OsVersion.dwMinorVersion & 0xffff) |
  443. (OsVersion.dwBuildNumber << 16);
  444. #if defined(_M_IX86)
  445. DumpHeader.MachineImageType = IMAGE_FILE_MACHINE_I386;
  446. DumpHeader.ValidDump = USERMODE_CRASHDUMP_VALID_DUMP32;
  447. #elif defined(_M_IA64)
  448. DumpHeader.MachineImageType = IMAGE_FILE_MACHINE_IA64;
  449. DumpHeader.ValidDump = USERMODE_CRASHDUMP_VALID_DUMP64;
  450. #elif defined(_M_AXP64)
  451. DumpHeader.MachineImageType = IMAGE_FILE_MACHINE_AXP64;
  452. DumpHeader.ValidDump = USERMODE_CRASHDUMP_VALID_DUMP64;
  453. #elif defined(_M_ALPHA)
  454. DumpHeader.MachineImageType = IMAGE_FILE_MACHINE_ALPHA;
  455. DumpHeader.ValidDump = USERMODE_CRASHDUMP_VALID_DUMP32;
  456. #elif defined(_M_AMD64)
  457. DumpHeader.MachineImageType = IMAGE_FILE_MACHINE_AMD64;
  458. DumpHeader.ValidDump = USERMODE_CRASHDUMP_VALID_DUMP64;
  459. #else
  460. #error( "unknown target machine" );
  461. #endif
  462. if (SetFilePointer( hFile, 0, 0, FILE_BEGIN ) == INVALID_SET_FILE_POINTER) {
  463. goto bad_file;
  464. }
  465. if (!DmppWriteAll( hFile, &DumpHeader, sizeof(DumpHeader) )) {
  466. goto bad_file;
  467. }
  468. //
  469. // close the file
  470. //
  471. if (CrashDumpName)
  472. {
  473. CloseHandle( hFile );
  474. }
  475. return TRUE;
  476. bad_file:
  477. if (CrashDumpName)
  478. {
  479. CloseHandle( hFile );
  480. DeleteFileW( CrashDumpName );
  481. }
  482. return FALSE;
  483. }