Source code of Windows XP (NT5)
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.

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