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.

584 lines
16 KiB

  1. #include "precomp.h"
  2. #include <crash.h>
  3. #include "Debugger.h"
  4. #include "UserDumpp.h"
  5. #define MEM_SIZE (64*1024)
  6. //
  7. // Private data structure used for communcating
  8. // crash dump data to the callback function.
  9. //
  10. typedef struct _CRASH_DUMP_INFO
  11. {
  12. PPROCESS_INFO pProcess;
  13. EXCEPTION_DEBUG_INFO* ExceptionInfo;
  14. DWORD MemoryCount;
  15. DWORD_PTR Address;
  16. PUCHAR MemoryData;
  17. MEMORY_BASIC_INFORMATION mbi;
  18. SIZE_T MbiOffset;
  19. SIZE_T MbiRemaining;
  20. PTHREAD_INFO pCurrentThread;
  21. IMAGEHLP_MODULE mi;
  22. PCRASH_MODULE CrashModule;
  23. } CRASH_DUMP_INFO, *PCRASH_DUMP_INFO;
  24. //
  25. // Local function prototypes
  26. //
  27. DWORD_PTR GetTeb( HANDLE hThread )
  28. {
  29. NTSTATUS Status;
  30. THREAD_BASIC_INFORMATION ThreadBasicInfo;
  31. DWORD_PTR Address = 0;
  32. Status = NtQueryInformationThread( hThread,
  33. ThreadBasicInformation,
  34. &ThreadBasicInfo,
  35. sizeof( ThreadBasicInfo ),
  36. NULL );
  37. if ( NT_SUCCESS(Status) )
  38. {
  39. Address = (DWORD_PTR)ThreadBasicInfo.TebBaseAddress;
  40. }
  41. return Address;
  42. }
  43. BOOL
  44. CrashDumpCallback(
  45. IN DWORD DataType, // requested data type
  46. OUT PVOID* DumpData, // pointer to a pointer to the data
  47. OUT LPDWORD DumpDataLength, // pointer to the data length
  48. IN OUT PVOID cdi // private data
  49. )
  50. /*++
  51. Return: TRUE on success, FALSE otherwise.
  52. Desc: This function is the callback used by crashlib.
  53. Its purpose is to provide data to CreateUserDump()
  54. for writting to the crashdump file.
  55. --*/
  56. {
  57. PCRASH_DUMP_INFO CrashdumpInfo = (PCRASH_DUMP_INFO)cdi;
  58. switch ( DataType )
  59. {
  60. case DMP_DEBUG_EVENT:
  61. *DumpData = &CrashdumpInfo->pProcess->DebugEvent;
  62. *DumpDataLength = sizeof(DEBUG_EVENT);
  63. break;
  64. case DMP_THREAD_STATE:
  65. {
  66. static CRASH_THREAD CrashThread;
  67. PTHREAD_INFO pCurrentThread;
  68. *DumpData = &CrashThread;
  69. if ( CrashdumpInfo->pCurrentThread == NULL )
  70. {
  71. pCurrentThread = CrashdumpInfo->pProcess->pFirstThreadInfo;
  72. }
  73. else
  74. {
  75. pCurrentThread = CrashdumpInfo->pCurrentThread->pNext;
  76. }
  77. CrashdumpInfo->pCurrentThread = pCurrentThread;
  78. if ( pCurrentThread == NULL )
  79. {
  80. return FALSE;
  81. }
  82. ZeroMemory(&CrashThread, sizeof(CrashThread));
  83. CrashThread.ThreadId = pCurrentThread->dwThreadId;
  84. CrashThread.SuspendCount = SuspendThread(pCurrentThread->hThread);
  85. if ( CrashThread.SuspendCount != (DWORD)-1 )
  86. {
  87. ResumeThread(pCurrentThread->hThread);
  88. }
  89. CrashThread.PriorityClass = GetPriorityClass(CrashdumpInfo->pProcess->hProcess);
  90. CrashThread.Priority = GetThreadPriority(pCurrentThread->hThread);
  91. CrashThread.Teb = GetTeb(pCurrentThread->hThread);
  92. *DumpDataLength = sizeof(CRASH_THREAD);
  93. break;
  94. }
  95. case DMP_MEMORY_BASIC_INFORMATION:
  96. while ( TRUE )
  97. {
  98. CrashdumpInfo->Address += CrashdumpInfo->mbi.RegionSize;
  99. if ( !VirtualQueryEx(CrashdumpInfo->pProcess->hProcess,
  100. (LPVOID)CrashdumpInfo->Address,
  101. &CrashdumpInfo->mbi,
  102. sizeof(MEMORY_BASIC_INFORMATION)) )
  103. {
  104. return FALSE;
  105. }
  106. if ( (CrashdumpInfo->mbi.Protect & PAGE_GUARD) ||
  107. (CrashdumpInfo->mbi.Protect & PAGE_NOACCESS) )
  108. {
  109. continue;
  110. }
  111. if ( (CrashdumpInfo->mbi.State & MEM_FREE) ||
  112. (CrashdumpInfo->mbi.State & MEM_RESERVE) )
  113. {
  114. continue;
  115. }
  116. break;
  117. }
  118. *DumpData = &CrashdumpInfo->mbi;
  119. *DumpDataLength = sizeof(MEMORY_BASIC_INFORMATION);
  120. break;
  121. case DMP_THREAD_CONTEXT:
  122. {
  123. PTHREAD_INFO pCurrentThread;
  124. if ( CrashdumpInfo->pCurrentThread == NULL )
  125. {
  126. pCurrentThread = CrashdumpInfo->pProcess->pFirstThreadInfo;
  127. }
  128. else
  129. {
  130. pCurrentThread = CrashdumpInfo->pCurrentThread->pNext;
  131. }
  132. CrashdumpInfo->pCurrentThread = pCurrentThread;
  133. if ( pCurrentThread == NULL )
  134. {
  135. return FALSE;
  136. }
  137. *DumpData = &CrashdumpInfo->pCurrentThread->Context;
  138. *DumpDataLength = sizeof(CONTEXT);
  139. break;
  140. }
  141. case DMP_MODULE:
  142. if ( CrashdumpInfo->mi.BaseOfImage == 0 )
  143. {
  144. return FALSE;
  145. }
  146. CrashdumpInfo->CrashModule->BaseOfImage = CrashdumpInfo->mi.BaseOfImage;
  147. CrashdumpInfo->CrashModule->SizeOfImage = CrashdumpInfo->mi.ImageSize;
  148. CrashdumpInfo->CrashModule->ImageNameLength = strlen(CrashdumpInfo->mi.ImageName) + 1;
  149. strcpy( CrashdumpInfo->CrashModule->ImageName, CrashdumpInfo->mi.ImageName );
  150. *DumpData = CrashdumpInfo->CrashModule;
  151. *DumpDataLength = sizeof(CRASH_MODULE) + CrashdumpInfo->CrashModule->ImageNameLength;
  152. if ( !SymGetModuleInfo(CrashdumpInfo->pProcess->hProcess,
  153. (DWORD_PTR)-1,
  154. &CrashdumpInfo->mi) )
  155. {
  156. CrashdumpInfo->mi.BaseOfImage = 0;
  157. }
  158. break;
  159. case DMP_MEMORY_DATA:
  160. if ( !CrashdumpInfo->MemoryCount )
  161. {
  162. CrashdumpInfo->Address = 0;
  163. CrashdumpInfo->MbiOffset = 0;
  164. CrashdumpInfo->MbiRemaining = 0;
  165. ZeroMemory( &CrashdumpInfo->mbi, sizeof(MEMORY_BASIC_INFORMATION) );
  166. CrashdumpInfo->MemoryData = (PUCHAR)VirtualAlloc(NULL,
  167. MEM_SIZE,
  168. MEM_COMMIT,
  169. PAGE_READWRITE);
  170. }
  171. if ( !CrashdumpInfo->MbiRemaining )
  172. {
  173. while ( TRUE )
  174. {
  175. CrashdumpInfo->Address += CrashdumpInfo->mbi.RegionSize;
  176. if ( !VirtualQueryEx(CrashdumpInfo->pProcess->hProcess,
  177. (LPVOID)CrashdumpInfo->Address,
  178. &CrashdumpInfo->mbi,
  179. sizeof(MEMORY_BASIC_INFORMATION)) )
  180. {
  181. if ( CrashdumpInfo->MemoryData )
  182. {
  183. VirtualFree(CrashdumpInfo->MemoryData, MEM_SIZE, MEM_RELEASE);
  184. }
  185. return FALSE;
  186. }
  187. if ( (CrashdumpInfo->mbi.Protect & PAGE_GUARD) ||
  188. (CrashdumpInfo->mbi.Protect & PAGE_NOACCESS) )
  189. {
  190. continue;
  191. }
  192. if ( (CrashdumpInfo->mbi.State & MEM_FREE) ||
  193. (CrashdumpInfo->mbi.State & MEM_RESERVE) )
  194. {
  195. continue;
  196. }
  197. CrashdumpInfo->MbiOffset = 0;
  198. CrashdumpInfo->MbiRemaining = CrashdumpInfo->mbi.RegionSize;
  199. CrashdumpInfo->MemoryCount += 1;
  200. break;
  201. }
  202. }
  203. *DumpDataLength = (DWORD)__min( CrashdumpInfo->MbiRemaining, MEM_SIZE );
  204. CrashdumpInfo->MbiRemaining -= *DumpDataLength;
  205. ReadProcessMemory(CrashdumpInfo->pProcess->hProcess,
  206. (PUCHAR)((DWORD_PTR)CrashdumpInfo->mbi.BaseAddress + CrashdumpInfo->MbiOffset),
  207. CrashdumpInfo->MemoryData,
  208. *DumpDataLength,
  209. NULL);
  210. *DumpData = CrashdumpInfo->MemoryData;
  211. CrashdumpInfo->MbiOffset += *DumpDataLength;
  212. break;
  213. }
  214. return TRUE;
  215. }
  216. BOOL
  217. CreateUserDump(
  218. IN LPTSTR pszFileName,
  219. IN PDBGHELP_CREATE_USER_DUMP_CALLBACK DmpCallback,
  220. IN PVOID lpv
  221. )
  222. /*++
  223. Return: TRUE on success, FALSE otherwise.
  224. Desc: Creates the dump file.
  225. --*/
  226. {
  227. #if 0
  228. OSVERSIONINFOW OsVersion = {0};
  229. USERMODE_CRASHDUMP_HEADER DumpHeader = {0};
  230. DWORD cb;
  231. HANDLE hFile = INVALID_HANDLE_VALUE;
  232. BOOL rval;
  233. PVOID DumpData;
  234. DWORD DumpDataLength;
  235. SECURITY_ATTRIBUTES SecAttrib;
  236. SECURITY_DESCRIPTOR SecDescript;
  237. //
  238. // Create a DACL that allows all access to the directory.
  239. //
  240. SecAttrib.nLength = sizeof(SECURITY_ATTRIBUTES);
  241. SecAttrib.lpSecurityDescriptor = &SecDescript;
  242. SecAttrib.bInheritHandle = FALSE;
  243. InitializeSecurityDescriptor(&SecDescript, SECURITY_DESCRIPTOR_REVISION);
  244. SetSecurityDescriptorDacl(&SecDescript, TRUE, NULL, FALSE);
  245. hFile = CreateFile(pszFileName,
  246. GENERIC_READ | GENERIC_WRITE,
  247. 0,
  248. &SecAttrib,
  249. CREATE_ALWAYS,
  250. FILE_ATTRIBUTE_NORMAL,
  251. NULL);
  252. if ( hFile == NULL || hFile == INVALID_HANDLE_VALUE )
  253. {
  254. return FALSE;
  255. }
  256. //
  257. // Write out an empty header.
  258. //
  259. if ( !WriteFile(hFile, &DumpHeader, sizeof(DumpHeader), &cb, NULL) )
  260. {
  261. goto bad_file;
  262. }
  263. //
  264. // Write the debug event.
  265. //
  266. DumpHeader.DebugEventOffset = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
  267. DmpCallback(DMP_DEBUG_EVENT, &DumpData, &DumpDataLength, lpv);
  268. if ( !WriteFile(hFile, DumpData, sizeof(DEBUG_EVENT), &cb, NULL) )
  269. {
  270. goto bad_file;
  271. }
  272. //
  273. // Write the memory map.
  274. //
  275. DumpHeader.MemoryRegionOffset = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
  276. do
  277. {
  278. __try {
  279. rval = DmpCallback(DMP_MEMORY_BASIC_INFORMATION,
  280. &DumpData,
  281. &DumpDataLength,
  282. lpv);
  283. } __except (EXCEPTION_EXECUTE_HANDLER) {
  284. rval = FALSE;
  285. }
  286. if ( rval )
  287. {
  288. DumpHeader.MemoryRegionCount += 1;
  289. if ( !WriteFile(hFile, DumpData, sizeof(MEMORY_BASIC_INFORMATION), &cb, NULL) )
  290. {
  291. goto bad_file;
  292. }
  293. }
  294. } while ( rval );
  295. //
  296. // Write the thread contexts.
  297. //
  298. DumpHeader.ThreadOffset = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
  299. do
  300. {
  301. __try {
  302. rval = DmpCallback(DMP_THREAD_CONTEXT,
  303. &DumpData,
  304. &DumpDataLength,
  305. lpv);
  306. } __except (EXCEPTION_EXECUTE_HANDLER) {
  307. rval = FALSE;
  308. }
  309. if ( rval )
  310. {
  311. if ( !WriteFile(hFile, DumpData, DumpDataLength, &cb, NULL) )
  312. {
  313. goto bad_file;
  314. }
  315. DumpHeader.ThreadCount += 1;
  316. }
  317. } while ( rval );
  318. //
  319. // Write the thread states.
  320. //
  321. DumpHeader.ThreadStateOffset = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
  322. do
  323. {
  324. __try {
  325. rval = DmpCallback(DMP_THREAD_STATE,
  326. &DumpData,
  327. &DumpDataLength,
  328. lpv);
  329. } __except (EXCEPTION_EXECUTE_HANDLER) {
  330. rval = FALSE;
  331. }
  332. if ( rval )
  333. {
  334. if ( !WriteFile(hFile, DumpData, sizeof(CRASH_THREAD), &cb, NULL) )
  335. {
  336. goto bad_file;
  337. }
  338. }
  339. } while ( rval );
  340. //
  341. // Write the module table.
  342. //
  343. DumpHeader.ModuleOffset = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
  344. do
  345. {
  346. __try {
  347. rval = DmpCallback(DMP_MODULE,
  348. &DumpData,
  349. &DumpDataLength,
  350. lpv);
  351. } __except (EXCEPTION_EXECUTE_HANDLER) {
  352. rval = FALSE;
  353. }
  354. if ( rval )
  355. {
  356. if ( !WriteFile(hFile,
  357. DumpData,
  358. sizeof(CRASH_MODULE) + ((PCRASH_MODULE)DumpData)->ImageNameLength,
  359. &cb,
  360. NULL) )
  361. {
  362. goto bad_file;
  363. }
  364. DumpHeader.ModuleCount += 1;
  365. }
  366. } while ( rval );
  367. //
  368. // Write the virtual memory
  369. //
  370. DumpHeader.DataOffset = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
  371. do
  372. {
  373. __try {
  374. rval = DmpCallback(DMP_MEMORY_DATA,
  375. &DumpData,
  376. &DumpDataLength,
  377. lpv);
  378. } __except (EXCEPTION_EXECUTE_HANDLER) {
  379. rval = FALSE;
  380. }
  381. if ( rval )
  382. {
  383. if ( !WriteFile(hFile, DumpData, DumpDataLength, &cb, NULL) )
  384. {
  385. goto bad_file;
  386. }
  387. }
  388. } while ( rval );
  389. //
  390. // The VersionInfo is optional.
  391. //
  392. DumpHeader.VersionInfoOffset = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
  393. //
  394. // re-write the dump header with some valid data.
  395. //
  396. GetVersionEx(&OsVersion);
  397. DumpHeader.Signature = USERMODE_CRASHDUMP_SIGNATURE;
  398. DumpHeader.MajorVersion = OsVersion.dwMajorVersion;
  399. DumpHeader.MinorVersion = OsVersion.dwMinorVersion;
  400. #if defined(_X86_)
  401. DumpHeader.MachineImageType = IMAGE_FILE_MACHINE_I386;
  402. DumpHeader.ValidDump = USERMODE_CRASHDUMP_VALID_DUMP32;
  403. #elif defined(_AMD64_)
  404. DumpHeader.MachineImageType = IMAGE_FILE_MACHINE_AMD64;
  405. DumpHeader.ValidDump = USERMODE_CRASHDUMP_VALID_DUMP64;
  406. #elif defined(_IA64_)
  407. DumpHeader.MachineImageType = IMAGE_FILE_MACHINE_IA64;
  408. DumpHeader.ValidDump = USERMODE_CRASHDUMP_VALID_DUMP64;
  409. #else
  410. #error "No Target Architecture"
  411. #endif
  412. SetFilePointer(hFile, 0, 0, FILE_BEGIN);
  413. if ( !WriteFile(hFile, &DumpHeader, sizeof(DumpHeader), &cb, NULL) )
  414. {
  415. goto bad_file;
  416. }
  417. CloseHandle(hFile);
  418. return TRUE;
  419. bad_file:
  420. CloseHandle(hFile);
  421. DeleteFile(pszFileName);
  422. #endif
  423. return FALSE;
  424. }
  425. BOOL
  426. GenerateUserModeDump(
  427. LPTSTR pszFileName,
  428. PPROCESS_INFO pProcess,
  429. LPEXCEPTION_DEBUG_INFO ed
  430. )
  431. {
  432. CRASH_DUMP_INFO CrashdumpInfo = {0};
  433. BOOL bRet;
  434. PTHREAD_INFO pThread;
  435. CrashdumpInfo.mi.SizeOfStruct = sizeof(CrashdumpInfo.mi);
  436. CrashdumpInfo.pProcess = pProcess;
  437. CrashdumpInfo.ExceptionInfo = ed;
  438. //
  439. // Get the thread context for all the threads.
  440. //
  441. pThread = pProcess->pFirstThreadInfo;
  442. while ( pThread != NULL )
  443. {
  444. pThread->Context.ContextFlags = CONTEXT_FULL;
  445. GetThreadContext(pThread->hThread, &pThread->Context);
  446. pThread = pThread->pNext;
  447. }
  448. //
  449. // Get first entry in the module list.
  450. //
  451. if ( !SymInitialize(pProcess->hProcess, NULL, FALSE) )
  452. {
  453. return FALSE;
  454. }
  455. if ( !SymGetModuleInfo(pProcess->hProcess, 0, &CrashdumpInfo.mi) )
  456. {
  457. return FALSE;
  458. }
  459. CrashdumpInfo.CrashModule = (PCRASH_MODULE)LocalAlloc(LPTR, 4096);
  460. bRet = CreateUserDump(pszFileName, CrashDumpCallback, &CrashdumpInfo);
  461. LocalFree(CrashdumpInfo.CrashModule);
  462. return bRet;
  463. }