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.

745 lines
22 KiB

  1. //-----------------------------------------------------------------------
  2. // @doc
  3. //
  4. // @module convert crash dump to triage dump for crash dump utilities
  5. //
  6. // Copyright 1999 Microsoft Corporation. All Rights Reserved
  7. //
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <time.h>
  12. #include <tchar.h>
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <nturtl.h>
  16. #include <windows.h>
  17. #include <triage.h>
  18. #include <crash.h>
  19. #include <ntiodump.h>
  20. #define NOEXTAPI
  21. #include "wdbgexts.h"
  22. #include "ntdbg.h"
  23. inline ALIGN_8(unsigned offset)
  24. {
  25. return (offset + 7) & 0xfffffff8;
  26. }
  27. typedef struct _MI_TRIAGE_STORAGE
  28. {
  29. ULONG Version;
  30. ULONG Size;
  31. ULONG MmSpecialPoolTag;
  32. ULONG MiTriageActionTaken;
  33. ULONG MmVerifyDriverLevel;
  34. ULONG KernelVerifier;
  35. ULONG_PTR MmMaximumNonPagedPool;
  36. ULONG_PTR MmAllocatedNonPagedPool;
  37. ULONG_PTR PagedPoolMaximum;
  38. ULONG_PTR PagedPoolAllocated;
  39. ULONG_PTR CommittedPages;
  40. ULONG_PTR CommittedPagesPeak;
  41. ULONG_PTR CommitLimitMaximum;
  42. } MI_TRIAGE_STORAGE, *PMI_TRIAGE_STORAGE;
  43. KDDEBUGGER_DATA64 g_DebuggerData;
  44. extern PKDDEBUGGER_DATA64 blocks[];
  45. #define ExtractValue(NAME, val) { \
  46. if (!g_DebuggerData.NAME) { \
  47. val = 0; \
  48. printf("g_DebuggerData.NAME is NULL"); \
  49. } else { \
  50. DmpReadMemory(g_DebuggerData.NAME, &(val), sizeof(val)); \
  51. } \
  52. }
  53. //BUGBUG
  54. #define PAGE_SHIFT 12
  55. #define PAGE_SIZE 0x1000
  56. #define ALIGN_DOWN_POINTER(address, type) \
  57. ((PVOID)((ULONG_PTR)(address) & ~((ULONG_PTR)sizeof(type) - 1)))
  58. #define ALIGN_UP_POINTER(address, type) \
  59. (ALIGN_DOWN_POINTER(((ULONG_PTR)(address) + sizeof(type) - 1), type))
  60. const MAX_UNLOADED_NAME_LENGTH = 12;
  61. typedef struct _DUMP_UNLOADED_DRIVERS
  62. {
  63. UNICODE_STRING Name;
  64. WCHAR DriverName[MAX_UNLOADED_NAME_LENGTH];
  65. PVOID StartAddress;
  66. PVOID EndAddress;
  67. } DUMP_UNLOADED_DRIVERS, *PDUMP_UNLOADED_DRIVERS;
  68. class CCrashDumpWrapper
  69. {
  70. public:
  71. // @cmember constructor
  72. CCrashDumpWrapper() { }
  73. ~CCrashDumpWrapper() {}
  74. unsigned GetCallStackSize();
  75. unsigned GetDriverCount(PULONG cbNames);
  76. void WriteDriverList(BYTE *pb, unsigned offset, unsigned stringOffset);
  77. void WriteCurrentProcess(BYTE *pb, ULONG offset);
  78. void WriteUnloadedDrivers(BYTE *pb, ULONG offset);
  79. void WriteMmTriageInformation(BYTE *pb, ULONG offset);
  80. };
  81. BOOL g_fVerbose;
  82. PDUMP_HEADER m_pHeader;
  83. PX86_CONTEXT m_pcontext;
  84. PEXCEPTION_RECORD m_pexception;
  85. const unsigned MAX_TRIAGE_STACK_SIZE = 16 * 1024;
  86. extern "C" {
  87. // processor block. We fill this in and it is accessed by crashlib
  88. PVOID KiProcessors[MAXIMUM_PROCESSORS];
  89. // ignored but needed for linking
  90. ULONG KiPcrBaseAddress = 0;
  91. }
  92. #define MI_UNLOADED_DRIVERS 50
  93. typedef struct _UNLOADED_DRIVERS {
  94. UNICODE_STRING Name;
  95. PVOID StartAddress;
  96. PVOID EndAddress;
  97. LARGE_INTEGER CurrentTime;
  98. } UNLOADED_DRIVERS, *PUNLOADED_DRIVERS;
  99. VOID
  100. GetCurrentThread(LPBYTE pthread)
  101. {
  102. // get current processor
  103. unsigned iProcessor = DmpGetCurrentProcessor();
  104. // get KPCRB for current processor
  105. PX86_PARTIAL_KPRCB pkprcb = (PX86_PARTIAL_KPRCB)(KiProcessors[iProcessor]);
  106. ULONG64 threadAddr = 0;
  107. // read current thread pointer from KPCRB
  108. DmpReadMemory((ULONG64) &pkprcb->CurrentThread, &threadAddr, sizeof(ULONG));
  109. // read current thread
  110. DmpReadMemory(threadAddr, pthread, X86_ETHREAD_SIZE);
  111. }
  112. unsigned CCrashDumpWrapper::GetDriverCount(PULONG cbNames)
  113. {
  114. LIST_ENTRY le;
  115. PLIST_ENTRY pleNext;
  116. PLDR_DATA_TABLE_ENTRY pdte;
  117. LDR_DATA_TABLE_ENTRY dte;
  118. unsigned cModules = 0;
  119. *cbNames = 0;
  120. // first entry is pointed to by the the PsLoadedModuleList field in the dump header
  121. LIST_ENTRY *pleHead = (PLIST_ENTRY) m_pHeader->PsLoadedModuleList;
  122. // read list element
  123. if (!DmpReadMemory((ULONG64) pleHead, (PVOID) &le, sizeof(LIST_ENTRY)))
  124. {
  125. printf("Could not read base of PsLoadedModuleList");
  126. }
  127. // obtain pointer to next list element
  128. pleNext = le.Flink;
  129. if (pleNext == NULL)
  130. {
  131. printf("PsLoadedModuleList is empty");
  132. }
  133. // while next list element is not pointer to headed
  134. while(pleNext != pleHead)
  135. {
  136. // obtain pointerr to loader entry
  137. pdte = CONTAINING_RECORD
  138. (
  139. pleNext,
  140. LDR_DATA_TABLE_ENTRY,
  141. InLoadOrderLinks
  142. );
  143. // read loader entry
  144. if (!DmpReadMemory((ULONG64) pdte, (PVOID) &dte, sizeof(dte)))
  145. {
  146. printf("memory read failed addr=0x%08x", (ULONG)(ULONG_PTR) pdte);
  147. }
  148. // compute length of module name
  149. *cbNames += ALIGN_8((dte.BaseDllName.Length + 1) * sizeof(WCHAR) + sizeof(DUMP_STRING));
  150. // get pointer to next loader entry
  151. pleNext = dte.InLoadOrderLinks.Flink;
  152. // if name is not null then this is a valid entry
  153. if (dte.BaseDllName.Length >= 0 && dte.BaseDllName.Buffer != NULL)
  154. cModules++;
  155. if (cModules > 10000)
  156. {
  157. printf("PsLoadedModuleList is empty");
  158. exit(-1);
  159. }
  160. }
  161. // return # of modules
  162. return cModules;
  163. }
  164. unsigned CCrashDumpWrapper::GetCallStackSize()
  165. {
  166. BYTE thread[X86_ETHREAD_SIZE];
  167. // get current thread
  168. GetCurrentThread(thread);
  169. // if kernel stack is not resident, then we can't do anything
  170. //if (!thread.Tcb.KernelStackResident)
  171. // return 0;
  172. // obtain stack base from thread
  173. ULONG StackBase = ((X86_THREAD *)(&thread[0]))->InitialStack;
  174. // obtain top of stack from register ESP
  175. ULONG_PTR StackPtr = m_pcontext->Esp;
  176. // make sure pointers make sense
  177. if (StackBase < StackPtr)
  178. {
  179. printf("Stack base pointer is invalid StackBase = %08x, esp=%08x", StackBase, StackPtr);
  180. return MAX_TRIAGE_STACK_SIZE;
  181. }
  182. // return stack size limited by max triage stack size (16K)
  183. return min((ULONG) StackBase - (ULONG) StackPtr, MAX_TRIAGE_STACK_SIZE);
  184. }
  185. void CCrashDumpWrapper::WriteDriverList(
  186. BYTE *pb,
  187. unsigned offset,
  188. unsigned stringOffset
  189. )
  190. {
  191. PLIST_ENTRY pleNext;
  192. PLDR_DATA_TABLE_ENTRY pdte;
  193. PDUMP_DRIVER_ENTRY pdde;
  194. PDUMP_STRING pds;
  195. PDUMP_STRING pdsInitial;
  196. LIST_ENTRY le;
  197. LDR_DATA_TABLE_ENTRY dte;
  198. ULONG i = 0;
  199. // pointer to first driver entry to write out
  200. pdde = (PDUMP_DRIVER_ENTRY) (pb + offset);
  201. // pointer to first module name to write out
  202. pds = (PDUMP_STRING) (pb + stringOffset);
  203. pdsInitial = pds;
  204. // obtain pointer to list head from dump header
  205. PLIST_ENTRY pleHead = (PLIST_ENTRY) m_pHeader->PsLoadedModuleList;
  206. // read in list head
  207. if (!DmpReadMemory((ULONG64) pleHead, &le, sizeof(le)))
  208. {
  209. printf("Could not read base of the PsModuleList");
  210. }
  211. // get pointer to first link
  212. pleNext = le.Flink;
  213. while (pleNext != pleHead)
  214. {
  215. // obtain pointer to loader entry
  216. pdte = CONTAINING_RECORD(pleNext,
  217. LDR_DATA_TABLE_ENTRY,
  218. InLoadOrderLinks
  219. );
  220. // read in loader entry
  221. if (!DmpReadMemory((ULONG64) pdte, (PVOID) &dte, sizeof(dte)))
  222. {
  223. printf("memory read failed addr=0x%08x", (DWORD)(ULONG_PTR) pdte);
  224. }
  225. // Build the entry in the string pool. We guarantee all strings are
  226. // NULL terminated as well as length prefixed.
  227. pds->Length = dte.BaseDllName.Length / 2;
  228. if (!DmpReadMemory((ULONG64) dte.BaseDllName.Buffer,
  229. pds->Buffer,
  230. pds->Length * sizeof (WCHAR)))
  231. {
  232. printf("memory read failed addr=0x%08x", (DWORD)(ULONG_PTR) dte.BaseDllName.Buffer);
  233. }
  234. // null terminate string
  235. pds->Buffer[pds->Length] = '\0';
  236. // read in loader entry
  237. memcpy(&pdde->LdrEntry, &dte, sizeof(pdde->LdrEntry));
  238. // replace pointer to string
  239. pdde->DriverNameOffset = (ULONG)((ULONG_PTR) pds - (ULONG_PTR) pb);
  240. // get pointer to next string
  241. pds = (PDUMP_STRING) ALIGN_UP_POINTER(((LPBYTE) pds) + sizeof(DUMP_STRING) +
  242. sizeof(WCHAR) * (pds->Length + 1),
  243. ULONGLONG);
  244. // extract timestamp and image size
  245. IMAGE_DOS_HEADER hdr;
  246. IMAGE_NT_HEADERS nthdr;
  247. unsigned cb;
  248. cb = DmpReadMemory((ULONG64) dte.DllBase, &hdr, sizeof(hdr));
  249. if (cb == sizeof(IMAGE_DOS_HEADER) &&
  250. hdr.e_magic == IMAGE_DOS_SIGNATURE &&
  251. (hdr.e_lfanew & 3) == 0)
  252. {
  253. cb = DmpReadMemory((ULONG64) dte.DllBase + hdr.e_lfanew, &nthdr, sizeof(nthdr));
  254. if (cb == sizeof(IMAGE_NT_HEADERS) &&
  255. nthdr.Signature == IMAGE_NT_SIGNATURE)
  256. {
  257. // repoace next link with link date timestap and image size
  258. pdde->LdrEntry.TimeDateStamp = nthdr.FileHeader.TimeDateStamp;
  259. pdde->LdrEntry.SizeOfImage = nthdr.OptionalHeader.SizeOfImage;
  260. }
  261. }
  262. pleNext = dte.InLoadOrderLinks.Flink;
  263. pdde = (PDUMP_DRIVER_ENTRY)(((PUCHAR) pdde) + sizeof(*pdde));
  264. }
  265. }
  266. void CCrashDumpWrapper::WriteCurrentProcess(BYTE *pb, ULONG offset)
  267. {
  268. BYTE thread[X86_ETHREAD_SIZE];
  269. // get current htread
  270. GetCurrentThread(thread);
  271. // read process from pointer from thread
  272. DmpReadMemory((DWORD) ((X86_THREAD *)(&thread[0]))->ApcState.Process,
  273. pb + offset,
  274. X86_NT5_EPROCESS_SIZE);
  275. // validate type of object
  276. //if (process.Pcb.Header.Type != ProcessObject)
  277. //{
  278. // printf("Current process object type is incorrect. The symbols are probably wrong.");
  279. //}
  280. }
  281. void CCrashDumpWrapper::WriteUnloadedDrivers(BYTE *pb, ULONG offset)
  282. {
  283. ULONG64 addr;
  284. ULONG i;
  285. ULONG Index;
  286. UNLOADED_DRIVERS *pud;
  287. UNLOADED_DRIVERS ud;
  288. PDUMP_UNLOADED_DRIVERS pdud;
  289. PVOID pvMiUnloadedDrivers;
  290. ULONG ulMiLastUnloadedDriver;
  291. // find location of unloaded drivers
  292. if (!(addr = g_DebuggerData.MmUnloadedDrivers))
  293. {
  294. // if can't be found then no unloaded drivers
  295. *(PULONG) (pb + offset) = 0;
  296. return;
  297. }
  298. else
  299. // read in pointer to start of unloaded drivers
  300. DmpReadMemory(addr, &pvMiUnloadedDrivers, sizeof(PVOID));
  301. // try finding symbol indicating offset of last unloaded driver
  302. if (!(addr = g_DebuggerData.MmLastUnloadedDriver))
  303. {
  304. // if not found, then no unloaded drivers
  305. *(PULONG) (pb + offset) = 0;
  306. return;
  307. }
  308. else
  309. // read in offset of last unloaded driver
  310. DmpReadMemory(addr, &ulMiLastUnloadedDriver, sizeof(ULONG));
  311. if (pvMiUnloadedDrivers == NULL)
  312. {
  313. // if unloaded driver pointer is null, then no unloaded drivers
  314. *(PULONG)(pb + offset) = 0;
  315. return;
  316. }
  317. // point to last unloaded drivers
  318. pdud = (PDUMP_UNLOADED_DRIVERS)((PULONG)(pb + offset) + 1);
  319. PUNLOADED_DRIVERS rgud = (PUNLOADED_DRIVERS) pvMiUnloadedDrivers;
  320. //
  321. // Write the list with the most recently unloaded driver first to the
  322. // least recently unloaded driver last.
  323. //
  324. Index = ulMiLastUnloadedDriver - 1;
  325. for (i = 0; i < MI_UNLOADED_DRIVERS; i += 1)
  326. {
  327. if (Index >= MI_UNLOADED_DRIVERS)
  328. Index = MI_UNLOADED_DRIVERS - 1;
  329. // read in unloaded driver
  330. if (!DmpReadMemory((ULONG64) &rgud[Index], &ud, sizeof(ud)))
  331. {
  332. printf("can't read memory from %08x", (ULONG)(ULONG_PTR)(&rgud[Index]));
  333. }
  334. // copy name lengths
  335. pdud->Name.MaximumLength = ud.Name.MaximumLength;
  336. pdud->Name.Length = ud.Name.Length;
  337. if (ud.Name.Buffer == NULL)
  338. break;
  339. // copy start and end address
  340. pdud->StartAddress = ud.StartAddress;
  341. pdud->EndAddress = ud.EndAddress;
  342. // restrict name length and maximum name length to 12 characters
  343. if (pdud->Name.Length > MAX_UNLOADED_NAME_LENGTH * 2)
  344. pdud->Name.Length = MAX_UNLOADED_NAME_LENGTH * 2;
  345. if (pdud->Name.MaximumLength > MAX_UNLOADED_NAME_LENGTH * 2)
  346. pdud->Name.MaximumLength = MAX_UNLOADED_NAME_LENGTH * 2;
  347. // setup pointer to driver name and read it in
  348. pdud->Name.Buffer = pdud->DriverName;
  349. if (!DmpReadMemory((ULONG64) ud.Name.Buffer,
  350. pdud->Name.Buffer,
  351. pdud->Name.MaximumLength))
  352. {
  353. printf("cannot read memory at address %08x", (ULONG)(ULONG64)(ud.Name.Buffer));
  354. }
  355. // move to previous driver
  356. pdud += 1;
  357. Index -= 1;
  358. }
  359. // number of drivers in the list
  360. *(PULONG) (pb + offset) = i;
  361. }
  362. void CCrashDumpWrapper::WriteMmTriageInformation(BYTE *pb, ULONG offset)
  363. {
  364. MI_TRIAGE_STORAGE TriageInformation;
  365. ULONG64 pMmVerifierData;
  366. ULONG64 pvMmPagedPoolInfo;
  367. ULONG_PTR cbNonPagedPool;
  368. ULONG_PTR cbPagedPool;
  369. // version information
  370. TriageInformation.Version = 1;
  371. // size information
  372. TriageInformation.Size = sizeof(MI_TRIAGE_STORAGE);
  373. // get special pool tag
  374. ExtractValue(MmSpecialPoolTag, TriageInformation.MmSpecialPoolTag);
  375. // get triage action taken
  376. ExtractValue(MmTriageActionTaken, TriageInformation.MiTriageActionTaken);
  377. pMmVerifierData = g_DebuggerData.MmVerifierData;
  378. // read in verifier level
  379. // BUGBUG - should not read internal data structures in MM
  380. //if (pMmVerifierData)
  381. // DmpReadMemory(
  382. // (ULONG64) &((MM_DRIVER_VERIFIER_DATA *) pMmVerifierData)->Level,
  383. // &TriageInformation.MmVerifyDriverLevel,
  384. // sizeof(TriageInformation.MmVerifyDriverLevel));
  385. //else
  386. TriageInformation.MmVerifyDriverLevel = 0;
  387. // read in verifier
  388. ExtractValue(KernelVerifier, TriageInformation.KernelVerifier);
  389. // read non paged pool info
  390. ExtractValue(MmMaximumNonPagedPoolInBytes, cbNonPagedPool);
  391. TriageInformation.MmMaximumNonPagedPool = cbNonPagedPool >> PAGE_SHIFT;
  392. ExtractValue(MmAllocatedNonPagedPool, TriageInformation.MmAllocatedNonPagedPool);
  393. // read paged pool info
  394. ExtractValue(MmSizeOfPagedPoolInBytes, cbPagedPool);
  395. TriageInformation.PagedPoolMaximum = cbPagedPool >> PAGE_SHIFT;
  396. pvMmPagedPoolInfo = g_DebuggerData.MmPagedPoolInformation;
  397. // BUGBUG - should not read internal data structures in MM
  398. //if (pvMmPagedPoolInfo)
  399. // DmpReadMemory(
  400. // (ULONG64) &((MM_PAGED_POOL_INFO *) pvMmPagedPoolInfo)->AllocatedPagedPool,
  401. // &TriageInformation.PagedPoolAllocated,
  402. // sizeof(TriageInformation.PagedPoolAllocated));
  403. //else
  404. TriageInformation.PagedPoolAllocated = 0;
  405. // read committed pages info
  406. ExtractValue(MmTotalCommittedPages, TriageInformation.CommittedPages);
  407. ExtractValue(MmPeakCommitment, TriageInformation.CommittedPagesPeak);
  408. ExtractValue(MmTotalCommitLimitMaximum, TriageInformation.CommitLimitMaximum);
  409. memcpy(pb + offset, &TriageInformation, sizeof(TriageInformation));
  410. }
  411. //-------------------------------------------------------------------
  412. // @mfunc initialize the triage dump header from a full or kernel
  413. // dump
  414. //
  415. void InitTriageDumpHeader(
  416. TRIAGE_DUMP *ptdh, // out | triage dump header
  417. CCrashDumpWrapper &wrapper // in | wrapper for dump extraction functions
  418. )
  419. {
  420. ULONG cbNames;
  421. // copy build number
  422. ExtractValue(CmNtCSDVersion, ptdh->ServicePackBuild);
  423. // set size of dump to 64K
  424. ptdh->SizeOfDump = TRIAGE_DUMP_SIZE;
  425. // valid offset is last DWORD in tiage dump
  426. ptdh->ValidOffset = TRIAGE_DUMP_SIZE - sizeof(ULONG);
  427. // context offset is fixed position on first page
  428. ptdh->ContextOffset = FIELD_OFFSET (DUMP_HEADER, ContextRecord);
  429. // exception offset is fixed position on first page
  430. ptdh->ExceptionOffset = FIELD_OFFSET (DUMP_HEADER, Exception);
  431. // starting offset in triage dump follows the triage dump header
  432. unsigned offset = ALIGN_8(PAGE_SIZE + sizeof(TRIAGE_DUMP));
  433. // mm information is first
  434. ptdh->MmOffset = offset;
  435. // mm information is fixed size structure
  436. offset += ALIGN_8(sizeof(MI_TRIAGE_STORAGE));
  437. // unloaded module list is next
  438. ptdh->UnloadedDriversOffset = offset;
  439. offset += sizeof(ULONG) + MI_UNLOADED_DRIVERS * sizeof(DUMP_UNLOADED_DRIVERS);
  440. // processor control block is next
  441. ptdh->PrcbOffset = offset;
  442. offset += ALIGN_8(X86_NT5_KPRCB_SIZE);
  443. // current process is next
  444. ptdh->ProcessOffset = offset;
  445. offset += ALIGN_8(X86_NT5_EPROCESS_SIZE);
  446. // current thread is next
  447. ptdh->ThreadOffset = offset;
  448. offset += ALIGN_8(X86_ETHREAD_SIZE);
  449. // call stack is next
  450. ptdh->CallStackOffset = offset;
  451. ptdh->SizeOfCallStack = wrapper.GetCallStackSize();
  452. ptdh->TopOfStack = m_pcontext->Esp;
  453. offset += ALIGN_8(ptdh->SizeOfCallStack); // Offset of Driver List
  454. // loaded driver list is next
  455. ptdh->DriverListOffset = offset;
  456. ptdh->DriverCount = wrapper.GetDriverCount(&cbNames);
  457. offset += ALIGN_8(ptdh->DriverCount * sizeof(DUMP_DRIVER_ENTRY));
  458. ptdh->StringPoolOffset = offset;
  459. ptdh->StringPoolSize = (ULONG) cbNames;
  460. ptdh->BrokenDriverOffset = 0;
  461. // all options are enabled
  462. ptdh->TriageOptions = 0xffffffff;
  463. }
  464. //------------------------------------------------------------------------
  465. // @func convert a full or kernel dump to a triage dump
  466. //
  467. extern "C"
  468. BOOL
  469. DoConversion(
  470. LPSTR szInputDumpFile, // full or kernel dump
  471. HANDLE OutputDumpFile // triage dump file
  472. )
  473. {
  474. PDUMP_HEADER pNewHeader;
  475. ULONG64 addr;
  476. ULONG i;
  477. //
  478. // Open the full dump files
  479. // crash dump wrapper has extraction functions for full dump
  480. //
  481. if (!DmpInitialize(szInputDumpFile, (PCONTEXT *)&m_pcontext, &m_pexception, (PVOID *)&m_pHeader))
  482. {
  483. return 0;
  484. }
  485. //
  486. // Lets determine what version of the dump file we are looking at.
  487. // Read the appropriate data block based on that.
  488. //
  489. if (!m_pHeader) {
  490. return FALSE;
  491. }
  492. if ((m_pHeader->KdDebuggerDataBlock) &&
  493. (m_pHeader->KdDebuggerDataBlock != 'EGAP'))
  494. {
  495. DmpReadMemory((ULONG64)(m_pHeader->KdDebuggerDataBlock),
  496. &g_DebuggerData,
  497. sizeof(g_DebuggerData));
  498. } else {
  499. for (i=0; i<32; i++)
  500. {
  501. if (blocks[i]->PsLoadedModuleList == m_pHeader->PsLoadedModuleList)
  502. {
  503. g_DebuggerData = *(blocks[i]);
  504. break;
  505. }
  506. }
  507. if (i == 32) {
  508. return 0;
  509. }
  510. }
  511. CCrashDumpWrapper wrapper;
  512. if (addr = g_DebuggerData.KiProcessorBlock)
  513. {
  514. DmpReadMemory(addr, KiProcessors, sizeof(PVOID) * MAXIMUM_PROCESSORS);
  515. // validate dump file and throw if invalid
  516. DmpValidateDumpFile(1);
  517. // allocate block to hold triage dump
  518. pNewHeader = (PDUMP_HEADER) malloc(TRIAGE_DUMP_SIZE);
  519. if (pNewHeader) {
  520. // copy in first page (common between all dumps)
  521. memcpy(pNewHeader, m_pHeader, PAGE_SIZE);
  522. // set dump type to triage dump
  523. pNewHeader->DumpType = DUMP_TYPE_TRIAGE;
  524. // triage dump header begins on second page
  525. TRIAGE_DUMP *ptdh = (TRIAGE_DUMP *) ((BYTE *) pNewHeader + PAGE_SIZE);
  526. // setup triage dump header
  527. InitTriageDumpHeader(ptdh, wrapper);
  528. // write unloaded drivers
  529. wrapper.WriteUnloadedDrivers((PBYTE)pNewHeader, ptdh->UnloadedDriversOffset);
  530. // write mm information
  531. wrapper.WriteMmTriageInformation((PBYTE)pNewHeader, ptdh->MmOffset);
  532. // write stack
  533. if (ptdh->SizeOfCallStack > 0)
  534. DmpReadMemory(ptdh->TopOfStack,
  535. ((PBYTE)pNewHeader) + ptdh->CallStackOffset,
  536. ptdh->SizeOfCallStack);
  537. // write thread
  538. GetCurrentThread((PBYTE)pNewHeader + ptdh->ThreadOffset);
  539. // write process
  540. wrapper.WriteCurrentProcess((PBYTE)pNewHeader, ptdh->ProcessOffset);
  541. // write processor control block (KPRCB)
  542. DmpReadMemory((ULONG64) KiProcessors[DmpGetCurrentProcessor()],
  543. ((PBYTE)pNewHeader) + ptdh->PrcbOffset,
  544. X86_NT5_KPRCB_SIZE);
  545. // write loaded driver list
  546. wrapper.WriteDriverList((PBYTE)pNewHeader, ptdh->DriverListOffset, ptdh->StringPoolOffset);
  547. // end of triage dump validated
  548. ((ULONG *) pNewHeader)[TRIAGE_DUMP_SIZE/sizeof(ULONG) - 1] = TRIAGE_DUMP_VALID;
  549. ULONG cbWritten;
  550. if (!WriteFile(OutputDumpFile,
  551. pNewHeader,
  552. TRIAGE_DUMP_SIZE,
  553. &cbWritten,
  554. NULL
  555. ))
  556. {
  557. printf("Write to minidump file failed for reason %08x.\n",
  558. GetLastError());
  559. return 0;
  560. }
  561. if (cbWritten != TRIAGE_DUMP_SIZE)
  562. {
  563. printf("Write to minidump failed because disk is full.\n");
  564. return 0;
  565. }
  566. }
  567. }
  568. else
  569. {
  570. // not much we can do without the processor block
  571. printf("Cannot load KiProcessorBlock");
  572. }
  573. DmpUnInitialize();
  574. return 1;
  575. }