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.

7953 lines
230 KiB

  1. /*++
  2. Copyright (c) 1990-2002 Microsoft Corporation
  3. Module Name:
  4. dump.cpp
  5. Abstract:
  6. This module implements crashdump loading and analysis code
  7. Comments:
  8. There are five basic types of dumps:
  9. User-mode dumps - contains the context and address of the user-mode
  10. program plus all process memory.
  11. User-mode minidumps - contains just thread stacks for
  12. register and stack traces.
  13. Kernel-mode normal dump - contains the context and address space of
  14. the entire kernel at the time of crash.
  15. Kernel-mode summary dump - contains a subset of the kernel-mode
  16. memory plus optionally the user-mode address space.
  17. Kernel-mode triage dump - contains a very small dump with registers,
  18. current process kernel-mode context, current thread kernel-mode
  19. context and some processor information. This dump is very small
  20. (typically 64K) but is designed to contain enough information
  21. to be able to figure out what went wrong when the machine
  22. crashed.
  23. This module also implements the following functions:
  24. Retrieving a normal Kernel-Mode dump from a target machine using 1394
  25. and storing it locally in a crashdump file format
  26. --*/
  27. #include "ntsdp.hpp"
  28. #define DUMP_INITIAL_VIEW_SIZE (1024 * 1024)
  29. #define DUMP_MAXIMUM_VIEW_SIZE (256 * 1024 * 1024)
  30. typedef ULONG PFN_NUMBER32;
  31. ULONG g_DumpApiTypes[] =
  32. {
  33. DEBUG_DUMP_FILE_BASE,
  34. DEBUG_DUMP_FILE_PAGE_FILE_DUMP,
  35. };
  36. //
  37. // Page file dump file information.
  38. //
  39. #define DMPPF_IDENTIFIER "PAGE.DMP"
  40. #define DMPPF_PAGE_NOT_PRESENT 0xffffffff
  41. struct DMPPF_PAGE_FILE_INFO
  42. {
  43. ULONG Size;
  44. ULONG MaximumSize;
  45. };
  46. // Left to its own devices the compiler will add a
  47. // ULONG of padding at the end of this structure to
  48. // keep it an even ULONG64 multiple in size. Force
  49. // it to consider only the declared items.
  50. #pragma pack(4)
  51. struct DMPPF_FILE_HEADER
  52. {
  53. char Id[8];
  54. LARGE_INTEGER BootTime;
  55. ULONG PageData;
  56. DMPPF_PAGE_FILE_INFO PageFiles[16];
  57. };
  58. #pragma pack()
  59. // Set this value to track down page numbers and contents of a virtual address
  60. // in a dump file.
  61. // Initialized to an address no one will look for.
  62. ULONG64 g_DebugDump_VirtualAddress = 12344321;
  63. #define RtlCheckBit(BMH,BP) ((((BMH)->Buffer[(BP) / 32]) >> ((BP) % 32)) & 0x1)
  64. //
  65. // MM Triage information.
  66. //
  67. struct MM_TRIAGE_TRANSLATION
  68. {
  69. ULONG DebuggerDataOffset;
  70. ULONG Triage32Offset;
  71. ULONG Triage64Offset;
  72. ULONG PtrSize:1;
  73. };
  74. MM_TRIAGE_TRANSLATION g_MmTriageTranslations[] =
  75. {
  76. FIELD_OFFSET(KDDEBUGGER_DATA64, MmSpecialPoolTag),
  77. FIELD_OFFSET(DUMP_MM_STORAGE32, MmSpecialPoolTag),
  78. FIELD_OFFSET(DUMP_MM_STORAGE64, MmSpecialPoolTag),
  79. FALSE,
  80. FIELD_OFFSET(KDDEBUGGER_DATA64, MmTriageActionTaken),
  81. FIELD_OFFSET(DUMP_MM_STORAGE32, MiTriageActionTaken),
  82. FIELD_OFFSET(DUMP_MM_STORAGE64, MiTriageActionTaken),
  83. FALSE,
  84. FIELD_OFFSET(KDDEBUGGER_DATA64, KernelVerifier),
  85. FIELD_OFFSET(DUMP_MM_STORAGE32, KernelVerifier),
  86. FIELD_OFFSET(DUMP_MM_STORAGE64, KernelVerifier),
  87. FALSE,
  88. FIELD_OFFSET(KDDEBUGGER_DATA64, MmAllocatedNonPagedPool),
  89. FIELD_OFFSET(DUMP_MM_STORAGE32, MmAllocatedNonPagedPool),
  90. FIELD_OFFSET(DUMP_MM_STORAGE64, MmAllocatedNonPagedPool),
  91. TRUE,
  92. FIELD_OFFSET(KDDEBUGGER_DATA64, MmTotalCommittedPages),
  93. FIELD_OFFSET(DUMP_MM_STORAGE32, CommittedPages),
  94. FIELD_OFFSET(DUMP_MM_STORAGE64, CommittedPages),
  95. TRUE,
  96. FIELD_OFFSET(KDDEBUGGER_DATA64, MmPeakCommitment),
  97. FIELD_OFFSET(DUMP_MM_STORAGE32, CommittedPagesPeak),
  98. FIELD_OFFSET(DUMP_MM_STORAGE64, CommittedPagesPeak),
  99. TRUE,
  100. FIELD_OFFSET(KDDEBUGGER_DATA64, MmTotalCommitLimitMaximum),
  101. FIELD_OFFSET(DUMP_MM_STORAGE32, CommitLimitMaximum),
  102. FIELD_OFFSET(DUMP_MM_STORAGE64, CommitLimitMaximum),
  103. TRUE,
  104. #if 0
  105. // These MM triage fields are in pages while the corresponding
  106. // debugger data fields are in bytes. There's no way to
  107. // directly map one to the other.
  108. FIELD_OFFSET(KDDEBUGGER_DATA64, MmMaximumNonPagedPoolInBytes),
  109. FIELD_OFFSET(DUMP_MM_STORAGE32, MmMaximumNonPagedPool),
  110. FIELD_OFFSET(DUMP_MM_STORAGE64, MmMaximumNonPagedPool),
  111. TRUE,
  112. FIELD_OFFSET(KDDEBUGGER_DATA64, MmSizeOfPagedPoolInBytes),
  113. FIELD_OFFSET(DUMP_MM_STORAGE32, PagedPoolMaximum),
  114. FIELD_OFFSET(DUMP_MM_STORAGE64, PagedPoolMaximum),
  115. TRUE,
  116. #endif
  117. 0, 0, 0, 0, 0,
  118. };
  119. //
  120. // AddDumpInformationFile and OpenDumpFile work together
  121. // to establish the full set of files to use for a particular
  122. // dump target. As the files are given before the target
  123. // exists, they are collected in this global array until
  124. // the target takes them over.
  125. //
  126. ViewMappedFile g_PendingDumpInfoFiles[DUMP_INFO_COUNT];
  127. //----------------------------------------------------------------------------
  128. //
  129. // ViewMappedFile.
  130. //
  131. //----------------------------------------------------------------------------
  132. #define MAX_CLEAN_PAGE_RECORD 4
  133. ViewMappedFile::ViewMappedFile(void)
  134. {
  135. // No need to specialize this right now so just pick
  136. // up the global setting.
  137. m_CacheGranularity = g_SystemAllocGranularity;
  138. ResetCache();
  139. ResetFile();
  140. }
  141. ViewMappedFile::~ViewMappedFile(void)
  142. {
  143. Close();
  144. }
  145. void
  146. ViewMappedFile::ResetCache(void)
  147. {
  148. m_ActiveCleanPages = 0;
  149. InitializeListHead(&m_InFileOrderList);
  150. InitializeListHead(&m_InLRUOrderList);
  151. }
  152. void
  153. ViewMappedFile::ResetFile(void)
  154. {
  155. m_FileNameW = NULL;
  156. m_FileNameA = NULL;
  157. m_File = NULL;
  158. m_FileSize = 0;
  159. m_Map = NULL;
  160. m_MapBase = NULL;
  161. m_MapSize = 0;
  162. }
  163. void
  164. ViewMappedFile::EmptyCache(void)
  165. {
  166. PLIST_ENTRY Next;
  167. CacheRecord* CacheRec;
  168. Next = m_InFileOrderList.Flink;
  169. while (Next != &m_InFileOrderList)
  170. {
  171. CacheRec = CONTAINING_RECORD(Next, CacheRecord, InFileOrderList);
  172. Next = Next->Flink;
  173. UnmapViewOfFile(CacheRec->MappedAddress);
  174. free(CacheRec);
  175. }
  176. ResetCache();
  177. }
  178. ViewMappedFile::CacheRecord*
  179. ViewMappedFile::ReuseOldestCacheRecord(ULONG64 FileByteOffset)
  180. {
  181. CacheRecord* CacheRec;
  182. PLIST_ENTRY Next;
  183. PVOID MappedAddress;
  184. ULONG64 MapOffset;
  185. ULONG Size;
  186. MapOffset = FileByteOffset & ~((ULONG64)m_CacheGranularity - 1);
  187. if ((m_FileSize - MapOffset) < m_CacheGranularity)
  188. {
  189. Size = (ULONG)(m_FileSize - MapOffset);
  190. }
  191. else
  192. {
  193. Size = m_CacheGranularity;
  194. }
  195. MappedAddress = MapViewOfFile(m_Map, FILE_MAP_READ,
  196. (DWORD)(MapOffset >> 32),
  197. (DWORD)MapOffset, Size);
  198. if (MappedAddress == NULL)
  199. {
  200. return NULL;
  201. }
  202. Next = m_InLRUOrderList.Flink;
  203. CacheRec = CONTAINING_RECORD(Next, CacheRecord, InLRUOrderList);
  204. UnmapViewOfFile(CacheRec->MappedAddress);
  205. CacheRec->PageNumber = FileByteOffset / m_CacheGranularity;
  206. CacheRec->MappedAddress = MappedAddress;
  207. //
  208. // Move record to end of LRU
  209. //
  210. RemoveEntryList(Next);
  211. InsertTailList(&m_InLRUOrderList, Next);
  212. //
  213. // Move record to correct place in ordered list
  214. //
  215. RemoveEntryList(&CacheRec->InFileOrderList);
  216. Next = m_InFileOrderList.Flink;
  217. while (Next != &m_InFileOrderList)
  218. {
  219. CacheRecord* NextCacheRec;
  220. NextCacheRec = CONTAINING_RECORD(Next, CacheRecord, InFileOrderList);
  221. if (CacheRec->PageNumber < NextCacheRec->PageNumber)
  222. {
  223. break;
  224. }
  225. Next = Next->Flink;
  226. }
  227. InsertTailList(Next, &CacheRec->InFileOrderList);
  228. return CacheRec;
  229. }
  230. ViewMappedFile::CacheRecord*
  231. ViewMappedFile::FindCacheRecordForFileByteOffset(ULONG64 FileByteOffset)
  232. {
  233. CacheRecord* CacheRec;
  234. PLIST_ENTRY Next;
  235. ULONG64 PageNumber;
  236. PageNumber = FileByteOffset / m_CacheGranularity;
  237. Next = m_InFileOrderList.Flink;
  238. while (Next != &m_InFileOrderList)
  239. {
  240. CacheRec = CONTAINING_RECORD(Next, CacheRecord, InFileOrderList);
  241. if (CacheRec->PageNumber < PageNumber)
  242. {
  243. Next = Next->Flink;
  244. }
  245. else if (CacheRec->PageNumber == PageNumber)
  246. {
  247. if (!CacheRec->Locked)
  248. {
  249. RemoveEntryList(&CacheRec->InLRUOrderList);
  250. InsertTailList(&m_InLRUOrderList,
  251. &CacheRec->InLRUOrderList);
  252. }
  253. return CacheRec;
  254. }
  255. else
  256. {
  257. break;
  258. }
  259. }
  260. //
  261. // Can't find it in cache.
  262. //
  263. return NULL;
  264. }
  265. ViewMappedFile::CacheRecord*
  266. ViewMappedFile::CreateNewFileCacheRecord(ULONG64 FileByteOffset)
  267. {
  268. CacheRecord* CacheRec;
  269. CacheRecord* NextCacheRec;
  270. PLIST_ENTRY Next;
  271. ULONG64 MapOffset;
  272. ULONG Size;
  273. CacheRec = (CacheRecord*)malloc(sizeof(*CacheRec));
  274. if (CacheRec == NULL)
  275. {
  276. return NULL;
  277. }
  278. ZeroMemory(CacheRec, sizeof(*CacheRec));
  279. MapOffset = (FileByteOffset / m_CacheGranularity) *
  280. m_CacheGranularity;
  281. if ((m_FileSize - MapOffset) < m_CacheGranularity)
  282. {
  283. Size = (ULONG)(m_FileSize - MapOffset);
  284. }
  285. else
  286. {
  287. Size = m_CacheGranularity;
  288. }
  289. CacheRec->MappedAddress = MapViewOfFile(m_Map, FILE_MAP_READ,
  290. (DWORD)(MapOffset >> 32),
  291. (DWORD)MapOffset, Size);
  292. if (CacheRec->MappedAddress == NULL)
  293. {
  294. free(CacheRec);
  295. return NULL;
  296. }
  297. CacheRec->PageNumber = FileByteOffset / m_CacheGranularity;
  298. //
  299. // Insert new record in file order list
  300. //
  301. Next = m_InFileOrderList.Flink;
  302. while (Next != &m_InFileOrderList)
  303. {
  304. NextCacheRec = CONTAINING_RECORD(Next, CacheRecord, InFileOrderList);
  305. if (CacheRec->PageNumber < NextCacheRec->PageNumber)
  306. {
  307. break;
  308. }
  309. Next = Next->Flink;
  310. }
  311. InsertTailList(Next, &CacheRec->InFileOrderList);
  312. //
  313. // Insert new record at tail of LRU list
  314. //
  315. InsertTailList(&m_InLRUOrderList,
  316. &CacheRec->InLRUOrderList);
  317. return CacheRec;
  318. }
  319. PUCHAR
  320. ViewMappedFile::FileOffsetToMappedAddress(ULONG64 FileOffset,
  321. BOOL LockCacheRec,
  322. PULONG Avail)
  323. {
  324. CacheRecord* CacheRec;
  325. ULONG64 FileByteOffset;
  326. if (FileOffset == 0 || FileOffset >= m_FileSize)
  327. {
  328. return NULL;
  329. }
  330. // The base view covers the beginning of the file.
  331. if (FileOffset < m_MapSize)
  332. {
  333. *Avail = (ULONG)(m_MapSize - FileOffset);
  334. return (PUCHAR)m_MapBase + FileOffset;
  335. }
  336. FileByteOffset = FileOffset;
  337. CacheRec = FindCacheRecordForFileByteOffset(FileByteOffset);
  338. if (CacheRec == NULL)
  339. {
  340. if (m_ActiveCleanPages < MAX_CLEAN_PAGE_RECORD)
  341. {
  342. CacheRec = CreateNewFileCacheRecord(FileByteOffset);
  343. if (CacheRec)
  344. {
  345. m_ActiveCleanPages++;
  346. }
  347. }
  348. else
  349. {
  350. //
  351. // too many pages cached in
  352. // overwrite existing cache
  353. //
  354. CacheRec = ReuseOldestCacheRecord(FileByteOffset);
  355. }
  356. }
  357. if (CacheRec == NULL)
  358. {
  359. return NULL;
  360. }
  361. else
  362. {
  363. if (LockCacheRec && !CacheRec->Locked)
  364. {
  365. RemoveEntryList(&CacheRec->InLRUOrderList);
  366. CacheRec->Locked = TRUE;
  367. m_ActiveCleanPages--;
  368. }
  369. ULONG PageRemainder =
  370. (ULONG)(FileByteOffset & (m_CacheGranularity - 1));
  371. *Avail = m_CacheGranularity - PageRemainder;
  372. return ((PUCHAR)CacheRec->MappedAddress) + PageRemainder;
  373. }
  374. }
  375. ULONG
  376. ViewMappedFile::ReadFileOffset(ULONG64 Offset, PVOID Buffer, ULONG BufferSize)
  377. {
  378. ULONG Done = 0;
  379. ULONG Avail;
  380. PUCHAR Mapping;
  381. if (m_File == NULL)
  382. {
  383. // Information for this kind of file wasn't provided.
  384. return 0;
  385. }
  386. __try
  387. {
  388. while (BufferSize > 0)
  389. {
  390. Mapping = FileOffsetToMappedAddress(Offset, FALSE, &Avail);
  391. if (Mapping == NULL)
  392. {
  393. break;
  394. }
  395. if (Avail > BufferSize)
  396. {
  397. Avail = BufferSize;
  398. }
  399. memcpy(Buffer, Mapping, Avail);
  400. Offset += Avail;
  401. Buffer = (PUCHAR)Buffer + Avail;
  402. BufferSize -= Avail;
  403. Done += Avail;
  404. }
  405. }
  406. __except(MappingExceptionFilter(GetExceptionInformation()))
  407. {
  408. Done = 0;
  409. }
  410. return Done;
  411. }
  412. ULONG
  413. ViewMappedFile::WriteFileOffset(ULONG64 Offset, PVOID Buffer, ULONG BufferSize)
  414. {
  415. ULONG Done = 0;
  416. ULONG Avail;
  417. PUCHAR Mapping;
  418. ULONG Protect;
  419. if (m_File == NULL)
  420. {
  421. // Information for this kind of file wasn't provided.
  422. return 0;
  423. }
  424. __try
  425. {
  426. while (BufferSize > 0)
  427. {
  428. Mapping = FileOffsetToMappedAddress(Offset, TRUE, &Avail);
  429. if (Mapping == NULL)
  430. {
  431. break;
  432. }
  433. if (Avail > BufferSize)
  434. {
  435. Avail = BufferSize;
  436. }
  437. VirtualProtect(Mapping, Avail, PAGE_WRITECOPY, &Protect);
  438. memcpy(Mapping, Buffer, Avail);
  439. Offset += Avail;
  440. Buffer = (PUCHAR)Buffer + Avail;
  441. BufferSize -= Avail;
  442. Done += Avail;
  443. }
  444. }
  445. __except(MappingExceptionFilter(GetExceptionInformation()))
  446. {
  447. Done = 0;
  448. }
  449. return Done;
  450. }
  451. HRESULT
  452. ViewMappedFile::Open(PCWSTR FileName, ULONG64 FileHandle, ULONG InitialView)
  453. {
  454. HRESULT Status;
  455. // Pick up default cache size if necessary.
  456. if (!m_CacheGranularity)
  457. {
  458. m_CacheGranularity = g_SystemAllocGranularity;
  459. }
  460. if (((m_CacheGranularity - 1) & InitialView) ||
  461. m_File != NULL)
  462. {
  463. return E_INVALIDARG;
  464. }
  465. if (!FileName)
  466. {
  467. if (!FileHandle)
  468. {
  469. return E_INVALIDARG;
  470. }
  471. FileName = L"<HandleOnly>";
  472. }
  473. m_FileNameW = _wcsdup(FileName);
  474. if (!m_FileNameW)
  475. {
  476. return E_OUTOFMEMORY;
  477. }
  478. if ((Status = WideToAnsi(FileName, &m_FileNameA)) != S_OK)
  479. {
  480. return Status;
  481. }
  482. if (FileHandle)
  483. {
  484. m_File = OS_HANDLE(FileHandle);
  485. }
  486. else
  487. {
  488. // We have to share everything in order to be
  489. // able to reopen already-open temporary files
  490. // expanded from CABs as they are marked as
  491. // delete-on-close.
  492. m_File = CreateFileW(FileName,
  493. GENERIC_READ,
  494. FILE_SHARE_READ | FILE_SHARE_WRITE |
  495. FILE_SHARE_DELETE,
  496. NULL,
  497. OPEN_EXISTING,
  498. FILE_ATTRIBUTE_NORMAL,
  499. NULL);
  500. if ((!m_File || m_File == INVALID_HANDLE_VALUE) &&
  501. GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
  502. {
  503. //
  504. // ANSI-only platform. Try the ANSI name.
  505. //
  506. m_File = CreateFileA(m_FileNameA,
  507. GENERIC_READ,
  508. FILE_SHARE_READ | FILE_SHARE_WRITE |
  509. FILE_SHARE_DELETE,
  510. NULL,
  511. OPEN_EXISTING,
  512. FILE_ATTRIBUTE_NORMAL,
  513. NULL);
  514. }
  515. if (!m_File || m_File == INVALID_HANDLE_VALUE)
  516. {
  517. goto LastStatus;
  518. }
  519. }
  520. //
  521. // Get file size and map initial view.
  522. //
  523. ULONG SizeLow, SizeHigh;
  524. SizeLow = GetFileSize(m_File, &SizeHigh);
  525. m_FileSize = ((ULONG64)SizeHigh << 32) | SizeLow;
  526. m_Map = CreateFileMapping(m_File, NULL, PAGE_READONLY,
  527. 0, 0, NULL);
  528. if (m_Map == NULL)
  529. {
  530. goto LastStatus;
  531. }
  532. if (m_FileSize < InitialView)
  533. {
  534. InitialView = (ULONG)m_FileSize;
  535. }
  536. m_MapBase = MapViewOfFile(m_Map, FILE_MAP_READ, 0, 0,
  537. InitialView);
  538. if (m_MapBase == NULL)
  539. {
  540. goto LastStatus;
  541. }
  542. m_MapSize = InitialView;
  543. return S_OK;
  544. LastStatus:
  545. Status = WIN32_LAST_STATUS();
  546. Close();
  547. return Status;
  548. }
  549. void
  550. ViewMappedFile::Close(void)
  551. {
  552. EmptyCache();
  553. if (m_MapBase != NULL)
  554. {
  555. UnmapViewOfFile(m_MapBase);
  556. m_MapBase = NULL;
  557. }
  558. if (m_Map != NULL)
  559. {
  560. CloseHandle(m_Map);
  561. m_Map = NULL;
  562. }
  563. free(m_FileNameW);
  564. m_FileNameW = NULL;
  565. FreeAnsi(m_FileNameA);
  566. m_FileNameA = NULL;
  567. if (m_File != NULL && m_File != INVALID_HANDLE_VALUE)
  568. {
  569. CloseHandle(m_File);
  570. }
  571. m_File = NULL;
  572. m_FileSize = 0;
  573. m_MapSize = 0;
  574. }
  575. HRESULT
  576. ViewMappedFile::RemapInitial(ULONG MapSize)
  577. {
  578. if (MapSize > m_FileSize)
  579. {
  580. MapSize = (ULONG)m_FileSize;
  581. }
  582. UnmapViewOfFile(m_MapBase);
  583. m_MapBase = MapViewOfFile(m_Map, FILE_MAP_READ,
  584. 0, 0, MapSize);
  585. if (m_MapBase == NULL)
  586. {
  587. m_MapSize = 0;
  588. return WIN32_LAST_STATUS();
  589. }
  590. m_MapSize = MapSize;
  591. return S_OK;
  592. }
  593. void
  594. ViewMappedFile::Transfer(ViewMappedFile* To)
  595. {
  596. To->m_FileNameW = m_FileNameW;
  597. To->m_FileNameA = m_FileNameA;
  598. To->m_File = m_File;
  599. To->m_FileSize = m_FileSize;
  600. To->m_Map = m_Map;
  601. To->m_MapBase = m_MapBase;
  602. To->m_MapSize = m_MapSize;
  603. To->m_ActiveCleanPages = m_ActiveCleanPages;
  604. if (!IsListEmpty(&m_InFileOrderList))
  605. {
  606. To->m_InFileOrderList = m_InFileOrderList;
  607. }
  608. if (!IsListEmpty(&m_InLRUOrderList))
  609. {
  610. To->m_InLRUOrderList = m_InLRUOrderList;
  611. }
  612. ResetCache();
  613. ResetFile();
  614. }
  615. //----------------------------------------------------------------------------
  616. //
  617. // Initialization functions.
  618. //
  619. //----------------------------------------------------------------------------
  620. HRESULT
  621. AddDumpInfoFile(PCWSTR FileName, ULONG64 FileHandle,
  622. ULONG Index, ULONG InitialView)
  623. {
  624. HRESULT Status;
  625. ViewMappedFile* File = &g_PendingDumpInfoFiles[Index];
  626. if ((Status = File->Open(FileName, FileHandle, InitialView)) != S_OK)
  627. {
  628. return Status;
  629. }
  630. switch(Index)
  631. {
  632. case DUMP_INFO_PAGE_FILE:
  633. if (memcmp(File->m_MapBase, DMPPF_IDENTIFIER,
  634. sizeof(DMPPF_IDENTIFIER) - 1) != 0)
  635. {
  636. Status = HR_DATA_CORRUPT;
  637. File->Close();
  638. }
  639. break;
  640. }
  641. return Status;
  642. }
  643. DumpTargetInfo*
  644. NewDumpTargetInfo(ULONG DumpType)
  645. {
  646. switch(DumpType)
  647. {
  648. case DTYPE_KERNEL_SUMMARY32:
  649. return new KernelSummary32DumpTargetInfo;
  650. case DTYPE_KERNEL_SUMMARY64:
  651. return new KernelSummary64DumpTargetInfo;
  652. case DTYPE_KERNEL_TRIAGE32:
  653. return new KernelTriage32DumpTargetInfo;
  654. case DTYPE_KERNEL_TRIAGE64:
  655. return new KernelTriage64DumpTargetInfo;
  656. case DTYPE_KERNEL_FULL32:
  657. return new KernelFull32DumpTargetInfo;
  658. case DTYPE_KERNEL_FULL64:
  659. return new KernelFull64DumpTargetInfo;
  660. case DTYPE_USER_FULL32:
  661. return new UserFull32DumpTargetInfo;
  662. case DTYPE_USER_FULL64:
  663. return new UserFull64DumpTargetInfo;
  664. case DTYPE_USER_MINI_PARTIAL:
  665. return new UserMiniPartialDumpTargetInfo;
  666. case DTYPE_USER_MINI_FULL:
  667. return new UserMiniFullDumpTargetInfo;
  668. }
  669. return NULL;
  670. }
  671. HRESULT
  672. IdentifyDump(PCWSTR FileName, ULONG64 FileHandle,
  673. DumpTargetInfo** TargetRet)
  674. {
  675. HRESULT Status;
  676. dprintf("\nLoading Dump File [%ws]\n", FileName);
  677. if ((Status = AddDumpInfoFile(FileName, FileHandle,
  678. DUMP_INFO_DUMP,
  679. DUMP_INITIAL_VIEW_SIZE)) != S_OK)
  680. {
  681. return Status;
  682. }
  683. ViewMappedFile* File = &g_PendingDumpInfoFiles[DUMP_INFO_DUMP];
  684. ULONG i, FileIdx;
  685. ULONG64 BaseMapSize;
  686. DumpTargetInfo* Target = NULL;
  687. for (i = 0; i < DTYPE_COUNT; i++)
  688. {
  689. Target = NewDumpTargetInfo(i);
  690. if (Target == NULL)
  691. {
  692. return E_OUTOFMEMORY;
  693. }
  694. Target->m_DumpBase = File->m_MapBase;
  695. BaseMapSize = File->m_MapSize;
  696. // The target owns the dump info files while it's active.
  697. for (FileIdx = 0; FileIdx < DUMP_INFO_COUNT; FileIdx++)
  698. {
  699. g_PendingDumpInfoFiles[FileIdx].
  700. Transfer(&Target->m_InfoFiles[FileIdx]);
  701. }
  702. Status = Target->IdentifyDump(&BaseMapSize);
  703. // Remove the info files to handle potential errors and loops.
  704. for (FileIdx = 0; FileIdx < DUMP_INFO_COUNT; FileIdx++)
  705. {
  706. Target->m_InfoFiles[FileIdx].
  707. Transfer(&g_PendingDumpInfoFiles[FileIdx]);
  708. }
  709. if (Status != E_NOINTERFACE)
  710. {
  711. break;
  712. }
  713. delete Target;
  714. Target = NULL;
  715. }
  716. if (Status == E_NOINTERFACE)
  717. {
  718. ErrOut("Could not match Dump File signature - "
  719. "invalid file format\n");
  720. }
  721. else if (Status == S_OK &&
  722. BaseMapSize > File->m_MapSize)
  723. {
  724. if (BaseMapSize > File->m_FileSize ||
  725. BaseMapSize > DUMP_MAXIMUM_VIEW_SIZE)
  726. {
  727. ErrOut("Dump file is too large to map\n");
  728. Status = E_INVALIDARG;
  729. }
  730. else
  731. {
  732. // Target requested a larger mapping so
  733. // try and do so. Round up to a multiple
  734. // of the initial view size for cache alignment.
  735. BaseMapSize =
  736. (BaseMapSize + DUMP_INITIAL_VIEW_SIZE - 1) &
  737. ~(DUMP_INITIAL_VIEW_SIZE - 1);
  738. Status = File->RemapInitial((ULONG)BaseMapSize);
  739. }
  740. }
  741. if (Status == S_OK)
  742. {
  743. Target->m_DumpBase = File->m_MapBase;
  744. // Target now owns the info files permanently.
  745. for (FileIdx = 0; FileIdx < DUMP_INFO_COUNT; FileIdx++)
  746. {
  747. g_PendingDumpInfoFiles[FileIdx].
  748. Transfer(&Target->m_InfoFiles[FileIdx]);
  749. }
  750. *TargetRet = Target;
  751. }
  752. else
  753. {
  754. delete Target;
  755. File->Close();
  756. }
  757. return Status;
  758. }
  759. //----------------------------------------------------------------------------
  760. //
  761. // DumpTargetInfo.
  762. //
  763. //----------------------------------------------------------------------------
  764. HRESULT
  765. DumpIdentifyStatus(ULONG ExcepCode)
  766. {
  767. //
  768. // If we got an access violation it means that the
  769. // dump content we wanted wasn't present. Treat
  770. // this as an identification failure and not a
  771. // critical failure.
  772. //
  773. // Any other code is just passed back as a critical failure.
  774. //
  775. if (ExcepCode == STATUS_ACCESS_VIOLATION)
  776. {
  777. return E_NOINTERFACE;
  778. }
  779. else
  780. {
  781. return HRESULT_FROM_NT(ExcepCode);
  782. }
  783. }
  784. DumpTargetInfo::DumpTargetInfo(ULONG Class, ULONG Qual, BOOL MappedImages)
  785. : TargetInfo(Class, Qual, FALSE)
  786. {
  787. m_DumpBase = NULL;
  788. m_FormatFlags = 0;
  789. m_MappedImages = MappedImages;
  790. ZeroMemory(&m_ExceptionRecord, sizeof(m_ExceptionRecord));
  791. m_ExceptionFirstChance = FALSE;
  792. m_WriterStatus = DUMP_WRITER_STATUS_UNINITIALIZED;
  793. }
  794. DumpTargetInfo::~DumpTargetInfo(void)
  795. {
  796. // Force processes and threads to get cleaned up while
  797. // the memory maps are still available.
  798. DeleteSystemInfo();
  799. }
  800. HRESULT
  801. DumpTargetInfo::InitSystemInfo(ULONG BuildNumber, ULONG CheckedBuild,
  802. ULONG MachineType, ULONG PlatformId,
  803. ULONG MajorVersion, ULONG MinorVersion)
  804. {
  805. HRESULT Status;
  806. SetSystemVersionAndBuild(BuildNumber, PlatformId);
  807. m_CheckedBuild = CheckedBuild;
  808. m_KdApi64 = (m_SystemVersion > NT_SVER_NT4);
  809. m_PlatformId = PlatformId;
  810. // We can call InitializeForProcessor right away as it
  811. // doesn't do anything interesting for dumps.
  812. if ((Status = InitializeMachines(MachineType)) != S_OK ||
  813. (Status = InitializeForProcessor()) != S_OK)
  814. {
  815. return Status;
  816. }
  817. if (m_Machine == NULL)
  818. {
  819. ErrOut("Dump has an unknown processor type, 0x%X\n", MachineType);
  820. return HR_DATA_CORRUPT;
  821. }
  822. m_KdVersion.MachineType = (USHORT) MachineType;
  823. m_KdVersion.MajorVersion = (USHORT) MajorVersion;
  824. m_KdVersion.MinorVersion = (USHORT) MinorVersion;
  825. m_KdVersion.Flags = DBGKD_VERS_FLAG_DATA |
  826. (m_Machine->m_Ptr64 ? DBGKD_VERS_FLAG_PTR64 : 0);
  827. return S_OK;
  828. }
  829. HRESULT
  830. DumpTargetInfo::ReadVirtual(
  831. IN ProcessInfo* Process,
  832. ULONG64 Offset,
  833. PVOID Buffer,
  834. ULONG BufferSize,
  835. PULONG BytesRead
  836. )
  837. {
  838. ULONG Done = 0;
  839. ULONG FileIndex;
  840. ULONG Avail;
  841. ULONG Attempt;
  842. ULONG64 FileOffset;
  843. if (BufferSize == 0)
  844. {
  845. *BytesRead = 0;
  846. return S_OK;
  847. }
  848. while (BufferSize > 0)
  849. {
  850. FileOffset = VirtualToOffset(Offset, &FileIndex, &Avail);
  851. if (FileOffset == 0)
  852. {
  853. break;
  854. }
  855. if (Avail > BufferSize)
  856. {
  857. Avail = BufferSize;
  858. }
  859. Attempt = m_InfoFiles[FileIndex].
  860. ReadFileOffset(FileOffset, Buffer, Avail);
  861. Done += Attempt;
  862. if (Attempt < Avail)
  863. {
  864. break;
  865. }
  866. Offset += Avail;
  867. Buffer = (PUCHAR)Buffer + Avail;
  868. BufferSize -= Avail;
  869. }
  870. *BytesRead = Done;
  871. // If we didn't read anything return an error.
  872. return Done == 0 ? E_FAIL : S_OK;
  873. }
  874. HRESULT
  875. DumpTargetInfo::WriteVirtual(
  876. IN ProcessInfo* Process,
  877. ULONG64 Offset,
  878. PVOID Buffer,
  879. ULONG BufferSize,
  880. PULONG BytesWritten
  881. )
  882. {
  883. ULONG Done = 0;
  884. ULONG FileIndex;
  885. ULONG Avail;
  886. ULONG Attempt;
  887. ULONG64 FileOffset;
  888. if (BufferSize == 0)
  889. {
  890. *BytesWritten = 0;
  891. return S_OK;
  892. }
  893. while (BufferSize > 0)
  894. {
  895. FileOffset = VirtualToOffset(Offset, &FileIndex, &Avail);
  896. if (FileOffset == 0)
  897. {
  898. break;
  899. }
  900. if (Avail > BufferSize)
  901. {
  902. Avail = BufferSize;
  903. }
  904. Attempt = m_InfoFiles[FileIndex].
  905. WriteFileOffset(FileOffset, Buffer, Avail);
  906. Done += Attempt;
  907. if (Attempt < Avail)
  908. {
  909. break;
  910. }
  911. Offset += Avail;
  912. Buffer = (PUCHAR)Buffer + Avail;
  913. BufferSize -= Avail;
  914. }
  915. *BytesWritten = Done;
  916. // If we didn't write anything return an error.
  917. return Done == 0 ? E_FAIL : S_OK;
  918. }
  919. HRESULT
  920. DumpTargetInfo::MapReadVirtual(ProcessInfo* Process,
  921. ULONG64 Offset,
  922. PVOID Buffer,
  923. ULONG BufferSize,
  924. PULONG BytesRead)
  925. {
  926. //
  927. // There are two mapped memory lists kept, one
  928. // for dump data and one for images mapped from disk.
  929. // Dump data always takes precedence over mapped image
  930. // data as on-disk images may not reflect the true state
  931. // of memory at the time of the dump. Read from the dump
  932. // data map whenever possible, only going to the image map
  933. // when no dump data is available.
  934. //
  935. *BytesRead = 0;
  936. while (BufferSize > 0)
  937. {
  938. ULONG64 NextAddr;
  939. ULONG Req;
  940. ULONG Read;
  941. //
  942. // Check the dump data map.
  943. //
  944. if (m_DataMemMap.ReadMemory(Offset, Buffer, BufferSize, &Read))
  945. {
  946. Offset += Read;
  947. Buffer = (PVOID)((PUCHAR)Buffer + Read);
  948. BufferSize -= Read;
  949. *BytesRead += Read;
  950. // If we got everything we're done.
  951. if (BufferSize == 0)
  952. {
  953. break;
  954. }
  955. }
  956. //
  957. // We still have memory to read so check the image map.
  958. //
  959. // Find out where the next data block is so we can limit
  960. // the image map read.
  961. Req = BufferSize;
  962. if (m_DataMemMap.GetNextRegion(Offset, &NextAddr))
  963. {
  964. NextAddr -= Offset;
  965. if (NextAddr < Req)
  966. {
  967. Req = (ULONG)NextAddr;
  968. }
  969. }
  970. // Now demand-load any deferred image memory.
  971. DemandLoadReferencedImageMemory(Process, Offset, Req);
  972. // Try to read.
  973. if (m_ImageMemMap.ReadMemory(Offset, Buffer, Req, &Read))
  974. {
  975. Offset += Read;
  976. Buffer = (PVOID)((PUCHAR)Buffer + Read);
  977. BufferSize -= Read;
  978. *BytesRead += Read;
  979. // This read was limited to an area that wouldn't overlap
  980. // any data memory so if we didn't read the full request
  981. // we know there isn't data memory available either and
  982. // we can quit.
  983. if (Read < Req)
  984. {
  985. break;
  986. }
  987. }
  988. else
  989. {
  990. // No memory in either map.
  991. break;
  992. }
  993. }
  994. return *BytesRead > 0 ? S_OK : E_FAIL;
  995. }
  996. void
  997. DumpTargetInfo::MapNearestDifferentlyValidOffsets(ULONG64 Offset,
  998. PULONG64 NextOffset,
  999. PULONG64 NextPage)
  1000. {
  1001. //
  1002. // In a minidump there can be memory fragments mapped at
  1003. // arbitrary locations so we cannot assume validity
  1004. // changes on page boundaries.
  1005. //
  1006. if (NextOffset != NULL)
  1007. {
  1008. ULONG64 Next;
  1009. *NextOffset = (ULONG64)-1;
  1010. if (m_DataMemMap.GetNextRegion(Offset, &Next))
  1011. {
  1012. *NextOffset = Next;
  1013. }
  1014. if (m_DataMemMap.GetNextRegion(Offset, &Next) &&
  1015. Next < *NextOffset)
  1016. {
  1017. *NextOffset = Next;
  1018. }
  1019. if (*NextOffset == (ULONG64)-1)
  1020. {
  1021. *NextOffset = Offset + 1;
  1022. }
  1023. }
  1024. if (NextPage != NULL)
  1025. {
  1026. *NextPage = (Offset + m_Machine->m_PageSize) &
  1027. ~((ULONG64)m_Machine->m_PageSize - 1);
  1028. }
  1029. }
  1030. HRESULT
  1031. DumpTargetInfo::SwitchProcessors(ULONG Processor)
  1032. {
  1033. SetCurrentProcessorThread(this, Processor, FALSE);
  1034. return S_OK;
  1035. }
  1036. HRESULT
  1037. DumpTargetInfo::Write(HANDLE hFile, ULONG FormatFlags,
  1038. PCSTR CommentA, PCWSTR CommentW)
  1039. {
  1040. ErrOut("Dump file type does not support writing\n");
  1041. return E_NOTIMPL;
  1042. }
  1043. PVOID
  1044. DumpTargetInfo::IndexRva(PVOID Base, RVA Rva, ULONG Size, PCSTR Title)
  1045. {
  1046. if (Rva >= m_InfoFiles[DUMP_INFO_DUMP].m_MapSize)
  1047. {
  1048. ErrOut("ERROR: %s not present in dump (RVA 0x%X)\n",
  1049. Title, Rva);
  1050. FlushCallbacks();
  1051. return NULL;
  1052. }
  1053. else if (Rva + Size > m_InfoFiles[DUMP_INFO_DUMP].m_MapSize)
  1054. {
  1055. ErrOut("ERROR: %s only partially present in dump "
  1056. "(RVA 0x%X, size 0x%X)\n",
  1057. Title, Rva, Size);
  1058. FlushCallbacks();
  1059. return NULL;
  1060. }
  1061. return IndexByByte(Base, Rva);
  1062. }
  1063. //----------------------------------------------------------------------------
  1064. //
  1065. // KernelDumpTargetInfo.
  1066. //
  1067. //----------------------------------------------------------------------------
  1068. void
  1069. OutputHeaderString(PCSTR Format, PSTR Str)
  1070. {
  1071. if (*(PULONG)Str == DUMP_SIGNATURE32 ||
  1072. Str[0] == 0)
  1073. {
  1074. // String not present.
  1075. return;
  1076. }
  1077. dprintf(Format, Str);
  1078. }
  1079. HRESULT
  1080. KernelDumpTargetInfo::ReadControlSpaceIa64(
  1081. ULONG Processor,
  1082. ULONG64 Offset,
  1083. PVOID Buffer,
  1084. ULONG BufferSize,
  1085. PULONG BytesRead
  1086. )
  1087. {
  1088. ULONG64 StartAddr;
  1089. ULONG Read = 0;
  1090. HRESULT Status;
  1091. if (BufferSize < sizeof(ULONG64))
  1092. {
  1093. return E_INVALIDARG;
  1094. }
  1095. switch(Offset)
  1096. {
  1097. case IA64_DEBUG_CONTROL_SPACE_PCR:
  1098. StartAddr = m_KiProcessors[Processor] +
  1099. m_KdDebuggerData.OffsetPrcbPcrPage,
  1100. Status = ReadVirtual(m_ProcessHead,
  1101. StartAddr, &StartAddr,
  1102. sizeof(StartAddr), &Read);
  1103. if (Status == S_OK && Read == sizeof(StartAddr))
  1104. {
  1105. *(PULONG64)Buffer =
  1106. (StartAddr << IA64_PAGE_SHIFT) + IA64_PHYSICAL1_START;
  1107. }
  1108. break;
  1109. case IA64_DEBUG_CONTROL_SPACE_PRCB:
  1110. *(PULONG64)Buffer = m_KiProcessors[Processor];
  1111. Read = sizeof(ULONG64);
  1112. Status = S_OK;
  1113. break;
  1114. case IA64_DEBUG_CONTROL_SPACE_KSPECIAL:
  1115. StartAddr = m_KiProcessors[Processor] +
  1116. m_KdDebuggerData.OffsetPrcbProcStateSpecialReg;
  1117. Status = ReadVirtual(m_ProcessHead,
  1118. StartAddr, Buffer, BufferSize, &Read);
  1119. break;
  1120. case IA64_DEBUG_CONTROL_SPACE_THREAD:
  1121. StartAddr = m_KiProcessors[Processor] +
  1122. m_KdDebuggerData.OffsetPrcbCurrentThread;
  1123. Status = ReadVirtual(m_ProcessHead,
  1124. StartAddr, Buffer,
  1125. sizeof(ULONG64), &Read);
  1126. break;
  1127. }
  1128. *BytesRead = Read;
  1129. return Status;
  1130. }
  1131. HRESULT
  1132. KernelDumpTargetInfo::ReadControlSpaceAmd64(
  1133. ULONG Processor,
  1134. ULONG64 Offset,
  1135. PVOID Buffer,
  1136. ULONG BufferSize,
  1137. PULONG BytesRead
  1138. )
  1139. {
  1140. ULONG64 StartAddr;
  1141. ULONG Read = 0;
  1142. HRESULT Status;
  1143. if (BufferSize < sizeof(ULONG64))
  1144. {
  1145. return E_INVALIDARG;
  1146. }
  1147. switch(Offset)
  1148. {
  1149. case AMD64_DEBUG_CONTROL_SPACE_PCR:
  1150. *(PULONG64)Buffer = m_KiProcessors[Processor] -
  1151. m_KdDebuggerData.OffsetPcrContainedPrcb;
  1152. Read = sizeof(ULONG64);
  1153. Status = S_OK;
  1154. break;
  1155. case AMD64_DEBUG_CONTROL_SPACE_PRCB:
  1156. *(PULONG64)Buffer = m_KiProcessors[Processor];
  1157. Read = sizeof(ULONG64);
  1158. Status = S_OK;
  1159. break;
  1160. case AMD64_DEBUG_CONTROL_SPACE_KSPECIAL:
  1161. StartAddr = m_KiProcessors[Processor] +
  1162. m_KdDebuggerData.OffsetPrcbProcStateSpecialReg;
  1163. Status = ReadVirtual(m_ProcessHead,
  1164. StartAddr, Buffer, BufferSize, &Read);
  1165. break;
  1166. case AMD64_DEBUG_CONTROL_SPACE_THREAD:
  1167. StartAddr = m_KiProcessors[Processor] +
  1168. m_KdDebuggerData.OffsetPrcbCurrentThread;
  1169. Status = ReadVirtual(m_ProcessHead,
  1170. StartAddr, Buffer,
  1171. sizeof(ULONG64), &Read);
  1172. break;
  1173. }
  1174. *BytesRead = Read;
  1175. return Status;
  1176. }
  1177. HRESULT
  1178. KernelDumpTargetInfo::ReadControl(
  1179. IN ULONG Processor,
  1180. IN ULONG64 Offset,
  1181. OUT PVOID Buffer,
  1182. IN ULONG BufferSize,
  1183. OUT OPTIONAL PULONG BytesRead
  1184. )
  1185. {
  1186. ULONG64 StartAddr;
  1187. //
  1188. // This function will not currently work if the symbols are not loaded.
  1189. //
  1190. if (!IS_KERNEL_TRIAGE_DUMP(this) &&
  1191. m_KdDebuggerData.KiProcessorBlock == 0)
  1192. {
  1193. ErrOut("ReadControl failed - ntoskrnl symbols must be loaded first\n");
  1194. return E_FAIL;
  1195. }
  1196. if (m_KiProcessors[Processor] == 0)
  1197. {
  1198. // This error message is a little too verbose.
  1199. #if 0
  1200. ErrOut("No control space information for processor %d\n", Processor);
  1201. #endif
  1202. return E_FAIL;
  1203. }
  1204. switch(m_MachineType)
  1205. {
  1206. case IMAGE_FILE_MACHINE_I386:
  1207. // X86 control space is just a view of the PRCB's
  1208. // processor state. That starts with the context.
  1209. StartAddr = Offset +
  1210. m_KiProcessors[Processor] +
  1211. m_KdDebuggerData.OffsetPrcbProcStateContext;
  1212. return ReadVirtual(m_ProcessHead,
  1213. StartAddr, Buffer, BufferSize, BytesRead);
  1214. case IMAGE_FILE_MACHINE_IA64:
  1215. return ReadControlSpaceIa64(Processor, Offset, Buffer,
  1216. BufferSize, BytesRead);
  1217. case IMAGE_FILE_MACHINE_AMD64:
  1218. return ReadControlSpaceAmd64(Processor, Offset, Buffer,
  1219. BufferSize, BytesRead);
  1220. }
  1221. return E_FAIL;
  1222. }
  1223. HRESULT
  1224. KernelDumpTargetInfo::GetTaggedBaseOffset(PULONG64 Offset)
  1225. {
  1226. // The tagged offset can never be zero as that's
  1227. // always the dump header, so if the tagged offset
  1228. // is zero it means there's no tagged data.
  1229. *Offset = m_TaggedOffset;
  1230. return m_TaggedOffset ? S_OK : E_NOINTERFACE;
  1231. }
  1232. HRESULT
  1233. KernelDumpTargetInfo::ReadTagged(ULONG64 Offset, PVOID Buffer,
  1234. ULONG BufferSize)
  1235. {
  1236. ULONG Attempt = m_InfoFiles[DUMP_INFO_DUMP].
  1237. ReadFileOffset(Offset, Buffer, BufferSize);
  1238. return Attempt == BufferSize ?
  1239. S_OK : HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY);
  1240. }
  1241. HRESULT
  1242. KernelDumpTargetInfo::GetThreadIdByProcessor(
  1243. IN ULONG Processor,
  1244. OUT PULONG Id
  1245. )
  1246. {
  1247. *Id = VIRTUAL_THREAD_ID(Processor);
  1248. return S_OK;
  1249. }
  1250. HRESULT
  1251. KernelDumpTargetInfo::GetThreadInfoDataOffset(ThreadInfo* Thread,
  1252. ULONG64 ThreadHandle,
  1253. PULONG64 Offset)
  1254. {
  1255. return KdGetThreadInfoDataOffset(Thread, ThreadHandle, Offset);
  1256. }
  1257. HRESULT
  1258. KernelDumpTargetInfo::GetProcessInfoDataOffset(ThreadInfo* Thread,
  1259. ULONG Processor,
  1260. ULONG64 ThreadData,
  1261. PULONG64 Offset)
  1262. {
  1263. return KdGetProcessInfoDataOffset(Thread, Processor, ThreadData, Offset);
  1264. }
  1265. HRESULT
  1266. KernelDumpTargetInfo::GetThreadInfoTeb(ThreadInfo* Thread,
  1267. ULONG ThreadIndex,
  1268. ULONG64 ThreadData,
  1269. PULONG64 Offset)
  1270. {
  1271. return KdGetThreadInfoTeb(Thread, ThreadIndex, ThreadData, Offset);
  1272. }
  1273. HRESULT
  1274. KernelDumpTargetInfo::GetProcessInfoPeb(ThreadInfo* Thread,
  1275. ULONG Processor,
  1276. ULONG64 ThreadData,
  1277. PULONG64 Offset)
  1278. {
  1279. return KdGetProcessInfoPeb(Thread, Processor, ThreadData, Offset);
  1280. }
  1281. ULONG64
  1282. KernelDumpTargetInfo::GetCurrentTimeDateN(void)
  1283. {
  1284. if (m_SystemVersion < NT_SVER_W2K)
  1285. {
  1286. ULONG64 TimeDate;
  1287. // Header time not available. Try and read
  1288. // the time saved in the shared user data segment.
  1289. if (ReadSharedUserTimeDateN(&TimeDate) == S_OK)
  1290. {
  1291. return TimeDate;
  1292. }
  1293. else
  1294. {
  1295. return 0;
  1296. }
  1297. }
  1298. return m_Machine->m_Ptr64 ?
  1299. ((PDUMP_HEADER64)m_DumpBase)->SystemTime.QuadPart :
  1300. ((PDUMP_HEADER32)m_DumpBase)->SystemTime.QuadPart;
  1301. }
  1302. ULONG64
  1303. KernelDumpTargetInfo::GetCurrentSystemUpTimeN(void)
  1304. {
  1305. ULONG64 Page = DUMP_SIGNATURE32;
  1306. ULONG64 Page64 = Page | (Page << 32);
  1307. ULONG64 SystemUpTime = m_Machine->m_Ptr64 ?
  1308. ((PDUMP_HEADER64)m_DumpBase)->SystemUpTime.QuadPart :
  1309. ((PDUMP_HEADER32)m_DumpBase)->SystemUpTime.QuadPart;
  1310. if (SystemUpTime && (SystemUpTime != Page64))
  1311. {
  1312. return SystemUpTime;
  1313. }
  1314. // Header time not available. Try and read
  1315. // the time saved in the shared user data segment.
  1316. if (ReadSharedUserUpTimeN(&SystemUpTime) == S_OK)
  1317. {
  1318. return SystemUpTime;
  1319. }
  1320. else
  1321. {
  1322. return 0;
  1323. }
  1324. }
  1325. HRESULT
  1326. KernelDumpTargetInfo::GetProductInfo(PULONG ProductType, PULONG SuiteMask)
  1327. {
  1328. PULONG HdrType, HdrMask;
  1329. // Try and get the information from the header. If that's
  1330. // not available try and read it from the shared user data.
  1331. if (m_Machine->m_Ptr64)
  1332. {
  1333. HdrType = &((PDUMP_HEADER64)m_DumpBase)->ProductType;
  1334. HdrMask = &((PDUMP_HEADER64)m_DumpBase)->SuiteMask;
  1335. }
  1336. else
  1337. {
  1338. HdrType = &((PDUMP_HEADER32)m_DumpBase)->ProductType;
  1339. HdrMask = &((PDUMP_HEADER32)m_DumpBase)->SuiteMask;
  1340. }
  1341. if (*HdrType == DUMP_SIGNATURE32)
  1342. {
  1343. // Not available in header.
  1344. return ReadSharedUserProductInfo(ProductType, SuiteMask);
  1345. }
  1346. else
  1347. {
  1348. *ProductType = *HdrType;
  1349. *SuiteMask = *HdrMask;
  1350. }
  1351. return S_OK;
  1352. }
  1353. HRESULT
  1354. KernelDumpTargetInfo::GetProcessorId
  1355. (ULONG Processor, PDEBUG_PROCESSOR_IDENTIFICATION_ALL Id)
  1356. {
  1357. return m_Machine->ReadKernelProcessorId(Processor, Id);
  1358. }
  1359. HRESULT
  1360. KernelDumpTargetInfo::GetProcessorSpeed
  1361. (ULONG Processor, PULONG Speed)
  1362. {
  1363. HRESULT Status;
  1364. ULONG64 Prcb;
  1365. if ((Status =
  1366. GetProcessorSystemDataOffset(Processor, DEBUG_DATA_KPRCB_OFFSET,
  1367. &Prcb)) != S_OK)
  1368. {
  1369. return Status;
  1370. }
  1371. return
  1372. ReadAllVirtual(m_ProcessHead,
  1373. Prcb + m_KdDebuggerData.OffsetPrcbMhz, Speed,
  1374. sizeof(ULONG));
  1375. }
  1376. HRESULT
  1377. KernelDumpTargetInfo::InitGlobals32(PMEMORY_DUMP32 Dump)
  1378. {
  1379. if (Dump->Header.DirectoryTableBase == 0)
  1380. {
  1381. ErrOut("Invalid directory table base value 0x%x\n",
  1382. Dump->Header.DirectoryTableBase);
  1383. return HR_DATA_CORRUPT;
  1384. }
  1385. if (Dump->Header.MinorVersion > 1381 &&
  1386. Dump->Header.PaeEnabled == TRUE )
  1387. {
  1388. m_KdDebuggerData.PaeEnabled = TRUE;
  1389. }
  1390. else
  1391. {
  1392. m_KdDebuggerData.PaeEnabled = FALSE;
  1393. }
  1394. m_KdDebuggerData.PsLoadedModuleList =
  1395. EXTEND64(Dump->Header.PsLoadedModuleList);
  1396. m_KdVersion.PsLoadedModuleList =
  1397. m_KdDebuggerData.PsLoadedModuleList;
  1398. m_NumProcessors = Dump->Header.NumberProcessors;
  1399. ExceptionRecord32To64(&Dump->Header.Exception, &m_ExceptionRecord);
  1400. m_ExceptionFirstChance = FALSE;
  1401. m_HeaderContext = Dump->Header.ContextRecord;
  1402. // New field in XP, Win2k SP1 and above
  1403. if ((Dump->Header.KdDebuggerDataBlock) &&
  1404. (Dump->Header.KdDebuggerDataBlock != DUMP_SIGNATURE32))
  1405. {
  1406. m_KdDebuggerDataOffset =
  1407. EXTEND64(Dump->Header.KdDebuggerDataBlock);
  1408. }
  1409. m_WriterStatus = Dump->Header.WriterStatus;
  1410. OutputHeaderString("Comment: '%s'\n", Dump->Header.Comment);
  1411. HRESULT Status =
  1412. InitSystemInfo(Dump->Header.MinorVersion,
  1413. Dump->Header.MajorVersion & 0xFF,
  1414. Dump->Header.MachineImageType,
  1415. VER_PLATFORM_WIN32_NT,
  1416. Dump->Header.MajorVersion,
  1417. Dump->Header.MinorVersion);
  1418. if (Status != S_OK)
  1419. {
  1420. return Status;
  1421. }
  1422. if (IS_KERNEL_TRIAGE_DUMP(this))
  1423. {
  1424. return S_OK;
  1425. }
  1426. ULONG NextIdx;
  1427. // We're expecting that the header value will be non-zero
  1428. // so that we don't need a thread to indicate the current processor.
  1429. // If it turns out to be zero the implicit read will fail
  1430. // due to the NULL.
  1431. return m_Machine->
  1432. SetPageDirectory(NULL, PAGE_DIR_KERNEL,
  1433. Dump->Header.DirectoryTableBase,
  1434. &NextIdx);
  1435. }
  1436. HRESULT
  1437. KernelDumpTargetInfo::InitGlobals64(PMEMORY_DUMP64 Dump)
  1438. {
  1439. if (Dump->Header.DirectoryTableBase == 0)
  1440. {
  1441. ErrOut("Invalid directory table base value 0x%I64x\n",
  1442. Dump->Header.DirectoryTableBase);
  1443. return HR_DATA_CORRUPT;
  1444. }
  1445. m_KdDebuggerData.PaeEnabled = FALSE;
  1446. m_KdDebuggerData.PsLoadedModuleList =
  1447. Dump->Header.PsLoadedModuleList;
  1448. m_KdVersion.PsLoadedModuleList =
  1449. m_KdDebuggerData.PsLoadedModuleList;
  1450. m_NumProcessors = Dump->Header.NumberProcessors;
  1451. m_ExceptionRecord = Dump->Header.Exception;
  1452. m_ExceptionFirstChance = FALSE;
  1453. m_HeaderContext = Dump->Header.ContextRecord;
  1454. // New field in XP, Win2k SP1 and above
  1455. if ((Dump->Header.KdDebuggerDataBlock) &&
  1456. (Dump->Header.KdDebuggerDataBlock != DUMP_SIGNATURE32))
  1457. {
  1458. m_KdDebuggerDataOffset =
  1459. Dump->Header.KdDebuggerDataBlock;
  1460. }
  1461. m_WriterStatus = Dump->Header.WriterStatus;
  1462. OutputHeaderString("Comment: '%s'\n", Dump->Header.Comment);
  1463. HRESULT Status =
  1464. InitSystemInfo(Dump->Header.MinorVersion,
  1465. Dump->Header.MajorVersion & 0xFF,
  1466. Dump->Header.MachineImageType,
  1467. VER_PLATFORM_WIN32_NT,
  1468. Dump->Header.MajorVersion,
  1469. Dump->Header.MinorVersion);
  1470. if (Status != S_OK)
  1471. {
  1472. return Status;
  1473. }
  1474. if (IS_KERNEL_TRIAGE_DUMP(this))
  1475. {
  1476. return S_OK;
  1477. }
  1478. ULONG NextIdx;
  1479. // We're expecting that the header value will be non-zero
  1480. // so that we don't need a thread to indicate the current processor.
  1481. // If it turns out to be zero the implicit read will fail
  1482. // due to the NULL.
  1483. return m_Machine->
  1484. SetPageDirectory(NULL, PAGE_DIR_KERNEL,
  1485. Dump->Header.DirectoryTableBase,
  1486. &NextIdx);
  1487. }
  1488. void
  1489. KernelDumpTargetInfo::DumpHeader32(PDUMP_HEADER32 Header)
  1490. {
  1491. dprintf("\nDUMP_HEADER32:\n");
  1492. dprintf("MajorVersion %08lx\n", Header->MajorVersion);
  1493. dprintf("MinorVersion %08lx\n", Header->MinorVersion);
  1494. dprintf("DirectoryTableBase %08lx\n", Header->DirectoryTableBase);
  1495. dprintf("PfnDataBase %08lx\n", Header->PfnDataBase);
  1496. dprintf("PsLoadedModuleList %08lx\n", Header->PsLoadedModuleList);
  1497. dprintf("PsActiveProcessHead %08lx\n", Header->PsActiveProcessHead);
  1498. dprintf("MachineImageType %08lx\n", Header->MachineImageType);
  1499. dprintf("NumberProcessors %08lx\n", Header->NumberProcessors);
  1500. dprintf("BugCheckCode %08lx\n", Header->BugCheckCode);
  1501. dprintf("BugCheckParameter1 %08lx\n", Header->BugCheckParameter1);
  1502. dprintf("BugCheckParameter2 %08lx\n", Header->BugCheckParameter2);
  1503. dprintf("BugCheckParameter3 %08lx\n", Header->BugCheckParameter3);
  1504. dprintf("BugCheckParameter4 %08lx\n", Header->BugCheckParameter4);
  1505. OutputHeaderString("VersionUser '%s'\n", Header->VersionUser);
  1506. dprintf("PaeEnabled %08lx\n", Header->PaeEnabled);
  1507. dprintf("KdDebuggerDataBlock %08lx\n", Header->KdDebuggerDataBlock);
  1508. OutputHeaderString("Comment '%s'\n", Header->Comment);
  1509. if (Header->SecondaryDataState != DUMP_SIGNATURE32)
  1510. {
  1511. dprintf("SecondaryDataState %08lx\n", Header->SecondaryDataState);
  1512. }
  1513. if (Header->ProductType != DUMP_SIGNATURE32)
  1514. {
  1515. dprintf("ProductType %08lx\n", Header->ProductType);
  1516. dprintf("SuiteMask %08lx\n", Header->SuiteMask);
  1517. }
  1518. if (Header->WriterStatus != DUMP_SIGNATURE32)
  1519. {
  1520. dprintf("WriterStatus %08lx\n", Header->WriterStatus);
  1521. }
  1522. }
  1523. void
  1524. KernelDumpTargetInfo::DumpHeader64(PDUMP_HEADER64 Header)
  1525. {
  1526. dprintf("\nDUMP_HEADER64:\n");
  1527. dprintf("MajorVersion %08lx\n", Header->MajorVersion);
  1528. dprintf("MinorVersion %08lx\n", Header->MinorVersion);
  1529. dprintf("DirectoryTableBase %s\n",
  1530. FormatAddr64(Header->DirectoryTableBase));
  1531. dprintf("PfnDataBase %s\n",
  1532. FormatAddr64(Header->PfnDataBase));
  1533. dprintf("PsLoadedModuleList %s\n",
  1534. FormatAddr64(Header->PsLoadedModuleList));
  1535. dprintf("PsActiveProcessHead %s\n",
  1536. FormatAddr64(Header->PsActiveProcessHead));
  1537. dprintf("MachineImageType %08lx\n", Header->MachineImageType);
  1538. dprintf("NumberProcessors %08lx\n", Header->NumberProcessors);
  1539. dprintf("BugCheckCode %08lx\n", Header->BugCheckCode);
  1540. dprintf("BugCheckParameter1 %s\n",
  1541. FormatAddr64(Header->BugCheckParameter1));
  1542. dprintf("BugCheckParameter2 %s\n",
  1543. FormatAddr64(Header->BugCheckParameter2));
  1544. dprintf("BugCheckParameter3 %s\n",
  1545. FormatAddr64(Header->BugCheckParameter3));
  1546. dprintf("BugCheckParameter4 %s\n",
  1547. FormatAddr64(Header->BugCheckParameter4));
  1548. OutputHeaderString("VersionUser '%s'\n", Header->VersionUser);
  1549. dprintf("KdDebuggerDataBlock %s\n",
  1550. FormatAddr64(Header->KdDebuggerDataBlock));
  1551. OutputHeaderString("Comment '%s'\n", Header->Comment);
  1552. if (Header->SecondaryDataState != DUMP_SIGNATURE32)
  1553. {
  1554. dprintf("SecondaryDataState %08lx\n", Header->SecondaryDataState);
  1555. }
  1556. if (Header->ProductType != DUMP_SIGNATURE32)
  1557. {
  1558. dprintf("ProductType %08lx\n", Header->ProductType);
  1559. dprintf("SuiteMask %08lx\n", Header->SuiteMask);
  1560. }
  1561. if (Header->WriterStatus != DUMP_SIGNATURE32)
  1562. {
  1563. dprintf("WriterStatus %08lx\n", Header->WriterStatus);
  1564. }
  1565. }
  1566. //----------------------------------------------------------------------------
  1567. //
  1568. // KernelFullSumDumpTargetInfo.
  1569. //
  1570. //----------------------------------------------------------------------------
  1571. HRESULT
  1572. KernelFullSumDumpTargetInfo::PageFileOffset(ULONG PfIndex, ULONG64 PfOffset,
  1573. PULONG64 FileOffset)
  1574. {
  1575. ViewMappedFile* File = &m_InfoFiles[DUMP_INFO_PAGE_FILE];
  1576. if (File->m_File == NULL)
  1577. {
  1578. return HR_PAGE_NOT_AVAILABLE;
  1579. }
  1580. if (PfIndex > MAX_PAGING_FILE_MASK)
  1581. {
  1582. return HR_DATA_CORRUPT;
  1583. }
  1584. //
  1585. // We can safely assume the header information is present
  1586. // in the base mapping.
  1587. //
  1588. DMPPF_FILE_HEADER* Hdr = (DMPPF_FILE_HEADER*)File->m_MapBase;
  1589. DMPPF_PAGE_FILE_INFO* FileInfo = &Hdr->PageFiles[PfIndex];
  1590. ULONG64 PfPage = PfOffset >> m_Machine->m_PageShift;
  1591. if (PfPage >= FileInfo->MaximumSize)
  1592. {
  1593. return HR_PAGE_NOT_AVAILABLE;
  1594. }
  1595. ULONG i;
  1596. ULONG PageDirOffs = sizeof(*Hdr) + (ULONG)PfPage * sizeof(ULONG);
  1597. for (i = 0; i < PfIndex; i++)
  1598. {
  1599. PageDirOffs += Hdr->PageFiles[i].MaximumSize * sizeof(ULONG);
  1600. }
  1601. ULONG PageDirEnt;
  1602. if (m_InfoFiles[DUMP_INFO_PAGE_FILE].
  1603. ReadFileOffset(PageDirOffs, &PageDirEnt, sizeof(PageDirEnt)) !=
  1604. sizeof(PageDirEnt))
  1605. {
  1606. return HR_DATA_CORRUPT;
  1607. }
  1608. if (PageDirEnt == DMPPF_PAGE_NOT_PRESENT)
  1609. {
  1610. return HR_PAGE_NOT_AVAILABLE;
  1611. }
  1612. *FileOffset = Hdr->PageData +
  1613. (PageDirEnt << m_Machine->m_PageShift) +
  1614. (PfOffset & (m_Machine->m_PageSize - 1));
  1615. return S_OK;
  1616. }
  1617. HRESULT
  1618. KernelFullSumDumpTargetInfo::ReadPhysical(
  1619. ULONG64 Offset,
  1620. PVOID Buffer,
  1621. ULONG BufferSize,
  1622. ULONG Flags,
  1623. PULONG BytesRead
  1624. )
  1625. {
  1626. ULONG Done = 0;
  1627. ULONG Avail;
  1628. ULONG Attempt;
  1629. ULONG64 FileOffset;
  1630. if (Flags != PHYS_FLAG_DEFAULT)
  1631. {
  1632. return E_NOTIMPL;
  1633. }
  1634. if (BufferSize == 0)
  1635. {
  1636. *BytesRead = 0;
  1637. return S_OK;
  1638. }
  1639. while (BufferSize > 0)
  1640. {
  1641. // Don't produce error messages on a direct
  1642. // physical access as the behavior of all data access
  1643. // functions is to just return an error when
  1644. // data is not present.
  1645. FileOffset = PhysicalToOffset(Offset, FALSE, &Avail);
  1646. if (FileOffset == 0)
  1647. {
  1648. break;
  1649. }
  1650. if (Avail > BufferSize)
  1651. {
  1652. Avail = BufferSize;
  1653. }
  1654. Attempt = m_InfoFiles[DUMP_INFO_DUMP].
  1655. ReadFileOffset(FileOffset, Buffer, Avail);
  1656. Done += Attempt;
  1657. if (Attempt < Avail)
  1658. {
  1659. break;
  1660. }
  1661. Offset += Avail;
  1662. Buffer = (PUCHAR)Buffer + Avail;
  1663. BufferSize -= Avail;
  1664. }
  1665. *BytesRead = Done;
  1666. // If we didn't read anything return an error.
  1667. return Done == 0 ? E_FAIL : S_OK;
  1668. }
  1669. HRESULT
  1670. KernelFullSumDumpTargetInfo::WritePhysical(
  1671. ULONG64 Offset,
  1672. PVOID Buffer,
  1673. ULONG BufferSize,
  1674. ULONG Flags,
  1675. PULONG BytesWritten
  1676. )
  1677. {
  1678. ULONG Done = 0;
  1679. ULONG Avail;
  1680. ULONG Attempt;
  1681. ULONG64 FileOffset;
  1682. if (Flags != PHYS_FLAG_DEFAULT)
  1683. {
  1684. return E_NOTIMPL;
  1685. }
  1686. if (BufferSize == 0)
  1687. {
  1688. *BytesWritten = 0;
  1689. return S_OK;
  1690. }
  1691. while (BufferSize > 0)
  1692. {
  1693. // Don't produce error messages on a direct
  1694. // physical access as the behavior of all data access
  1695. // functions is to just return an error when
  1696. // data is not present.
  1697. FileOffset = PhysicalToOffset(Offset, FALSE, &Avail);
  1698. if (FileOffset == 0)
  1699. {
  1700. break;
  1701. }
  1702. if (Avail > BufferSize)
  1703. {
  1704. Avail = BufferSize;
  1705. }
  1706. Attempt = m_InfoFiles[DUMP_INFO_DUMP].
  1707. WriteFileOffset(FileOffset, Buffer, Avail);
  1708. Done += Attempt;
  1709. if (Attempt < Avail)
  1710. {
  1711. break;
  1712. }
  1713. Offset += Avail;
  1714. Buffer = (PUCHAR)Buffer + Avail;
  1715. BufferSize -= Avail;
  1716. }
  1717. *BytesWritten = Done;
  1718. // If we didn't write anything return an error.
  1719. return Done == 0 ? E_FAIL : S_OK;
  1720. }
  1721. HRESULT
  1722. KernelFullSumDumpTargetInfo::ReadPageFile(ULONG PfIndex, ULONG64 PfOffset,
  1723. PVOID Buffer, ULONG Size)
  1724. {
  1725. HRESULT Status;
  1726. ULONG64 FileOffset;
  1727. if ((Status = PageFileOffset(PfIndex, PfOffset, &FileOffset)) != S_OK)
  1728. {
  1729. return Status;
  1730. }
  1731. // It's assumed that all page file reads are for the
  1732. // entire amount requested, as there are no situations
  1733. // where it's useful to only read part of a page from the
  1734. // page file.
  1735. if (m_InfoFiles[DUMP_INFO_PAGE_FILE].
  1736. ReadFileOffset(FileOffset, Buffer, Size) < Size)
  1737. {
  1738. return HRESULT_FROM_WIN32(ERROR_READ_FAULT);
  1739. }
  1740. else
  1741. {
  1742. return S_OK;
  1743. }
  1744. }
  1745. HRESULT
  1746. KernelFullSumDumpTargetInfo::GetTargetContext(
  1747. ULONG64 Thread,
  1748. PVOID Context
  1749. )
  1750. {
  1751. ULONG Read;
  1752. HRESULT Status;
  1753. Status = ReadVirtual(m_ProcessHead,
  1754. m_KiProcessors[VIRTUAL_THREAD_INDEX(Thread)] +
  1755. m_KdDebuggerData.OffsetPrcbProcStateContext,
  1756. Context, m_TypeInfo.SizeTargetContext,
  1757. &Read);
  1758. if (Status != S_OK)
  1759. {
  1760. return Status;
  1761. }
  1762. return Read == m_TypeInfo.SizeTargetContext ? S_OK : E_FAIL;
  1763. }
  1764. HRESULT
  1765. KernelFullSumDumpTargetInfo::GetSelDescriptor(ThreadInfo* Thread,
  1766. MachineInfo* Machine,
  1767. ULONG Selector,
  1768. PDESCRIPTOR64 Desc)
  1769. {
  1770. return KdGetSelDescriptor(Thread, Machine, Selector, Desc);
  1771. }
  1772. void
  1773. KernelFullSumDumpTargetInfo::DumpDebug(void)
  1774. {
  1775. ULONG i;
  1776. dprintf("\nKiProcessorBlock at %s\n",
  1777. FormatAddr64(m_KdDebuggerData.KiProcessorBlock));
  1778. dprintf(" %d KiProcessorBlock entries:\n ",
  1779. m_NumProcessors);
  1780. for (i = 0; i < m_NumProcessors; i++)
  1781. {
  1782. dprintf(" %s", FormatAddr64(m_KiProcessors[i]));
  1783. }
  1784. dprintf("\n");
  1785. ViewMappedFile* PageDump = &m_InfoFiles[DUMP_INFO_PAGE_FILE];
  1786. if (PageDump->m_File != NULL)
  1787. {
  1788. // XXX drewb - Display more information when format is understood.
  1789. dprintf("\nAdditional page file in use\n");
  1790. }
  1791. }
  1792. ULONG64
  1793. KernelFullSumDumpTargetInfo::VirtualToOffset(ULONG64 Virt,
  1794. PULONG File, PULONG Avail)
  1795. {
  1796. HRESULT Status;
  1797. ULONG Levels;
  1798. ULONG PfIndex;
  1799. ULONG64 Phys;
  1800. *File = DUMP_INFO_DUMP;
  1801. if ((Status = m_Machine->
  1802. GetVirtualTranslationPhysicalOffsets(m_ProcessHead->
  1803. m_CurrentThread,
  1804. Virt, NULL, 0, &Levels,
  1805. &PfIndex, &Phys)) != S_OK)
  1806. {
  1807. // If the virtual address was paged out we got back
  1808. // a page file reference for the address. The user
  1809. // may have provided a page file in addition to the
  1810. // normal dump file so translate the reference into
  1811. // a secondary dump information file request.
  1812. if (Status == HR_PAGE_IN_PAGE_FILE)
  1813. {
  1814. if (PageFileOffset(PfIndex, Phys, &Phys) != S_OK)
  1815. {
  1816. return 0;
  1817. }
  1818. *File = DUMP_INFO_PAGE_FILE;
  1819. // Page files always have complete pages so the amount
  1820. // available is always the remainder of the page.
  1821. ULONG PageIndex =
  1822. (ULONG)Virt & (m_Machine->m_PageSize - 1);
  1823. *Avail = m_Machine->m_PageSize - PageIndex;
  1824. return Phys;
  1825. }
  1826. else
  1827. {
  1828. return 0;
  1829. }
  1830. }
  1831. else
  1832. {
  1833. // A summary dump will not contain any pages that
  1834. // are mapped by user-mode addresses. The virtual
  1835. // translation tables may still have valid mappings,
  1836. // though, so VToO will succeed. We want to suppress
  1837. // page-not-available messages in this case since
  1838. // the dump is known not to contain user pages.
  1839. return PhysicalToOffset(Phys, Virt >= m_SystemRangeStart, Avail);
  1840. }
  1841. }
  1842. ULONG
  1843. KernelFullSumDumpTargetInfo::GetCurrentProcessor(void)
  1844. {
  1845. ULONG i;
  1846. for (i = 0; i < m_NumProcessors; i++)
  1847. {
  1848. CROSS_PLATFORM_CONTEXT Context;
  1849. if (GetContext(VIRTUAL_THREAD_HANDLE(i), &Context) == S_OK)
  1850. {
  1851. switch(m_MachineType)
  1852. {
  1853. case IMAGE_FILE_MACHINE_I386:
  1854. if (Context.X86Nt5Context.Esp ==
  1855. ((PX86_NT5_CONTEXT)m_HeaderContext)->Esp)
  1856. {
  1857. return i;
  1858. }
  1859. break;
  1860. case IMAGE_FILE_MACHINE_IA64:
  1861. if (Context.IA64Context.IntSp ==
  1862. ((PIA64_CONTEXT)m_HeaderContext)->IntSp)
  1863. {
  1864. return i;
  1865. }
  1866. break;
  1867. case IMAGE_FILE_MACHINE_AMD64:
  1868. if (Context.Amd64Context.Rsp ==
  1869. ((PAMD64_CONTEXT)m_HeaderContext)->Rsp)
  1870. {
  1871. return i;
  1872. }
  1873. break;
  1874. }
  1875. }
  1876. }
  1877. // Give up and just pick the default processor.
  1878. return 0;
  1879. }
  1880. //----------------------------------------------------------------------------
  1881. //
  1882. // KernelSummaryDumpTargetInfo.
  1883. //
  1884. //----------------------------------------------------------------------------
  1885. void
  1886. KernelSummaryDumpTargetInfo::ConstructLocationCache(ULONG BitmapSize,
  1887. ULONG SizeOfBitMap,
  1888. PULONG Buffer)
  1889. {
  1890. PULONG Cache;
  1891. ULONG Index;
  1892. ULONG Offset;
  1893. m_PageBitmapSize = BitmapSize;
  1894. m_PageBitmap.SizeOfBitMap = SizeOfBitMap;
  1895. m_PageBitmap.Buffer = Buffer;
  1896. //
  1897. // Create a direct mapped cache.
  1898. //
  1899. Cache = new ULONG[BitmapSize];
  1900. if (!Cache)
  1901. {
  1902. // Not a failure; there just won't be a cache.
  1903. return;
  1904. }
  1905. //
  1906. // For each bit set in the bitmask fill the appropriate cache
  1907. // line location with the correct offset
  1908. //
  1909. Offset = 0;
  1910. for (Index = 0; Index < BitmapSize; Index++)
  1911. {
  1912. //
  1913. // If this page is in the summary dump fill in the offset
  1914. //
  1915. if ( RtlCheckBit (&m_PageBitmap, Index) )
  1916. {
  1917. Cache[ Index ] = Offset++;
  1918. }
  1919. }
  1920. //
  1921. // Assign back to the global storing the cache data.
  1922. //
  1923. m_LocationCache = Cache;
  1924. }
  1925. ULONG64
  1926. KernelSummaryDumpTargetInfo::SumPhysicalToOffset(ULONG HeaderSize,
  1927. ULONG64 Phys,
  1928. BOOL Verbose,
  1929. PULONG Avail)
  1930. {
  1931. ULONG Offset, j;
  1932. ULONG64 Page = Phys >> m_Machine->m_PageShift;
  1933. //
  1934. // Make sure this page is included in the dump
  1935. //
  1936. if (Page >= m_PageBitmapSize)
  1937. {
  1938. ErrOut("Page %x too large to be in the dump file.\n", Page);
  1939. return 0;
  1940. }
  1941. BOOL Present = TRUE;
  1942. __try
  1943. {
  1944. if (!RtlCheckBit(&m_PageBitmap, Page))
  1945. {
  1946. if (Verbose)
  1947. {
  1948. ErrOut("Page %x not present in the dump file. "
  1949. "Type \".hh dbgerr004\" for details\n",
  1950. Page);
  1951. }
  1952. Present = FALSE;
  1953. }
  1954. }
  1955. __except(MappingExceptionFilter(GetExceptionInformation()))
  1956. {
  1957. return 0;
  1958. }
  1959. if (!Present)
  1960. {
  1961. return 0;
  1962. }
  1963. //
  1964. // If the cache exists then find the location the easy way
  1965. //
  1966. if (m_LocationCache != NULL)
  1967. {
  1968. Offset = m_LocationCache[Page];
  1969. }
  1970. else
  1971. {
  1972. //
  1973. // CAVEAT This code will never execute unless there is a failure
  1974. // creating the summary dump (cache) mapping information
  1975. //
  1976. //
  1977. // The page is in the summary dump locate it's offset
  1978. // Note: this is painful. The offset is a count of
  1979. // all the bits set up to this page
  1980. //
  1981. Offset = 0;
  1982. __try
  1983. {
  1984. for (j = 0; j < m_PageBitmapSize; j++)
  1985. {
  1986. if (RtlCheckBit(&m_PageBitmap, j))
  1987. {
  1988. //
  1989. // If the offset is equal to the page were done.
  1990. //
  1991. if (j == Page)
  1992. {
  1993. break;
  1994. }
  1995. Offset++;
  1996. }
  1997. }
  1998. }
  1999. __except(MappingExceptionFilter(GetExceptionInformation()))
  2000. {
  2001. j = m_PageBitmapSize;
  2002. }
  2003. //
  2004. // Sanity check that we didn't drop out of the loop.
  2005. //
  2006. if (j >= m_PageBitmapSize)
  2007. {
  2008. return 0;
  2009. }
  2010. }
  2011. //
  2012. // The actual address is calculated as follows
  2013. // Header size - Size of header plus summary dump header
  2014. //
  2015. ULONG PageIndex =
  2016. (ULONG)Phys & (m_Machine->m_PageSize - 1);
  2017. *Avail = m_Machine->m_PageSize - PageIndex;
  2018. return HeaderSize + (Offset * m_Machine->m_PageSize) +
  2019. PageIndex;
  2020. }
  2021. HRESULT
  2022. KernelSummary32DumpTargetInfo::Initialize(void)
  2023. {
  2024. // Pick up any potentially modified base mapping pointer.
  2025. m_Dump = (PMEMORY_DUMP32)m_DumpBase;
  2026. dprintf("Kernel Summary Dump File: "
  2027. "Only kernel address space is available\n\n");
  2028. ConstructLocationCache(m_Dump->Summary.BitmapSize,
  2029. m_Dump->Summary.Bitmap.SizeOfBitMap,
  2030. m_Dump->Summary.Bitmap.Buffer);
  2031. HRESULT Status = InitGlobals32(m_Dump);
  2032. if (Status != S_OK)
  2033. {
  2034. return Status;
  2035. }
  2036. // Tagged data will follow all of the normal dump data.
  2037. m_TaggedOffset =
  2038. m_Dump->Summary.HeaderSize +
  2039. m_Dump->Summary.Pages * m_Machine->m_PageSize;
  2040. if (m_InfoFiles[DUMP_INFO_DUMP].m_FileSize < m_TaggedOffset)
  2041. {
  2042. WarnOut("************************************************************\n");
  2043. WarnOut("WARNING: Dump file has been truncated. "
  2044. "Data may be missing.\n");
  2045. WarnOut("************************************************************\n\n");
  2046. }
  2047. m_InfoFiles[DUMP_INFO_DUMP].m_FileSize =
  2048. m_Dump->Header.RequiredDumpSpace.QuadPart;
  2049. return KernelFullSumDumpTargetInfo::Initialize();
  2050. }
  2051. HRESULT
  2052. KernelSummary32DumpTargetInfo::GetDescription(PSTR Buffer, ULONG BufferLen,
  2053. PULONG DescLen)
  2054. {
  2055. HRESULT Status;
  2056. Status = AppendToStringBuffer(S_OK, "32-bit Kernel summary dump: ", TRUE,
  2057. &Buffer, &BufferLen, DescLen);
  2058. return AppendToStringBuffer(Status,
  2059. m_InfoFiles[DUMP_INFO_DUMP].m_FileNameA,
  2060. FALSE, &Buffer, &BufferLen, DescLen);
  2061. }
  2062. HRESULT
  2063. KernelSummary32DumpTargetInfo::ReadBugCheckData(PULONG Code, ULONG64 Args[4])
  2064. {
  2065. *Code = m_Dump->Header.BugCheckCode;
  2066. Args[0] = EXTEND64(m_Dump->Header.BugCheckParameter1);
  2067. Args[1] = EXTEND64(m_Dump->Header.BugCheckParameter2);
  2068. Args[2] = EXTEND64(m_Dump->Header.BugCheckParameter3);
  2069. Args[3] = EXTEND64(m_Dump->Header.BugCheckParameter4);
  2070. return S_OK;
  2071. }
  2072. HRESULT
  2073. KernelSummary32DumpTargetInfo::IdentifyDump(PULONG64 BaseMapSize)
  2074. {
  2075. HRESULT Status = E_NOINTERFACE;
  2076. PMEMORY_DUMP32 Dump = (PMEMORY_DUMP32)m_DumpBase;
  2077. __try
  2078. {
  2079. if (Dump->Header.Signature != DUMP_SIGNATURE32 ||
  2080. Dump->Header.ValidDump != DUMP_VALID_DUMP32 ||
  2081. Dump->Header.DumpType != DUMP_TYPE_SUMMARY)
  2082. {
  2083. __leave;
  2084. }
  2085. if (Dump->Summary.Signature != DUMP_SUMMARY_SIGNATURE)
  2086. {
  2087. // The header says it's a summary dump but
  2088. // it doesn't have a valid signature, so assume
  2089. // it's not a valid dump.
  2090. Status = HR_DATA_CORRUPT;
  2091. }
  2092. else
  2093. {
  2094. PPHYSICAL_MEMORY_RUN32 LastRun;
  2095. ULONG HighestPage;
  2096. // We rely on all of the header information being
  2097. // directly mapped. Unfortunately the header information
  2098. // can be off due to some size computation bugs, so
  2099. // attempt to get the right size regardless.
  2100. *BaseMapSize = Dump->Summary.HeaderSize;
  2101. LastRun = Dump->Header.PhysicalMemoryBlock.Run +
  2102. (Dump->Header.PhysicalMemoryBlock.NumberOfRuns - 1);
  2103. HighestPage = LastRun->BasePage + LastRun->PageCount;
  2104. if (HighestPage > Dump->Header.PhysicalMemoryBlock.NumberOfPages)
  2105. {
  2106. (*BaseMapSize) +=
  2107. (HighestPage -
  2108. Dump->Header.PhysicalMemoryBlock.NumberOfPages + 7) / 8;
  2109. }
  2110. Status = S_OK;
  2111. m_Dump = Dump;
  2112. }
  2113. }
  2114. __except(EXCEPTION_EXECUTE_HANDLER)
  2115. {
  2116. Status = DumpIdentifyStatus(GetExceptionCode());
  2117. }
  2118. return Status;
  2119. }
  2120. ULONG64
  2121. KernelSummary32DumpTargetInfo::PhysicalToOffset(ULONG64 Phys, BOOL Verbose,
  2122. PULONG Avail)
  2123. {
  2124. return SumPhysicalToOffset(m_Dump->Summary.HeaderSize, Phys, Verbose,
  2125. Avail);
  2126. }
  2127. void
  2128. KernelSummary32DumpTargetInfo::DumpDebug(void)
  2129. {
  2130. PSUMMARY_DUMP32 Sum = &m_Dump->Summary;
  2131. dprintf("----- 32 bit Kernel Summary Dump Analysis\n");
  2132. DumpHeader32(&m_Dump->Header);
  2133. dprintf("\nSUMMARY_DUMP32:\n");
  2134. dprintf("DumpOptions %08lx\n", Sum->DumpOptions);
  2135. dprintf("HeaderSize %08lx\n", Sum->HeaderSize);
  2136. dprintf("BitmapSize %08lx\n", Sum->BitmapSize);
  2137. dprintf("Pages %08lx\n", Sum->Pages);
  2138. dprintf("Bitmap.SizeOfBitMap %08lx\n", Sum->Bitmap.SizeOfBitMap);
  2139. KernelFullSumDumpTargetInfo::DumpDebug();
  2140. }
  2141. HRESULT
  2142. KernelSummary64DumpTargetInfo::Initialize(void)
  2143. {
  2144. // Pick up any potentially modified base mapping pointer.
  2145. m_Dump = (PMEMORY_DUMP64)m_DumpBase;
  2146. dprintf("Kernel Summary Dump File: "
  2147. "Only kernel address space is available\n\n");
  2148. ConstructLocationCache(m_Dump->Summary.BitmapSize,
  2149. m_Dump->Summary.Bitmap.SizeOfBitMap,
  2150. m_Dump->Summary.Bitmap.Buffer);
  2151. HRESULT Status = InitGlobals64(m_Dump);
  2152. if (Status != S_OK)
  2153. {
  2154. return Status;
  2155. }
  2156. // Tagged data will follow all of the normal dump data.
  2157. m_TaggedOffset =
  2158. m_Dump->Summary.HeaderSize +
  2159. m_Dump->Summary.Pages * m_Machine->m_PageSize;
  2160. if (m_InfoFiles[DUMP_INFO_DUMP].m_FileSize < m_TaggedOffset)
  2161. {
  2162. WarnOut("************************************************************\n");
  2163. WarnOut("WARNING: Dump file has been truncated. "
  2164. "Data may be missing.\n");
  2165. WarnOut("************************************************************\n\n");
  2166. }
  2167. m_InfoFiles[DUMP_INFO_DUMP].m_FileSize =
  2168. m_Dump->Header.RequiredDumpSpace.QuadPart;
  2169. return KernelFullSumDumpTargetInfo::Initialize();
  2170. }
  2171. HRESULT
  2172. KernelSummary64DumpTargetInfo::GetDescription(PSTR Buffer, ULONG BufferLen,
  2173. PULONG DescLen)
  2174. {
  2175. HRESULT Status;
  2176. Status = AppendToStringBuffer(S_OK, "64-bit Kernel summary dump: ", TRUE,
  2177. &Buffer, &BufferLen, DescLen);
  2178. return AppendToStringBuffer(Status,
  2179. m_InfoFiles[DUMP_INFO_DUMP].m_FileNameA,
  2180. FALSE, &Buffer, &BufferLen, DescLen);
  2181. }
  2182. HRESULT
  2183. KernelSummary64DumpTargetInfo::ReadBugCheckData(PULONG Code, ULONG64 Args[4])
  2184. {
  2185. *Code = m_Dump->Header.BugCheckCode;
  2186. Args[0] = m_Dump->Header.BugCheckParameter1;
  2187. Args[1] = m_Dump->Header.BugCheckParameter2;
  2188. Args[2] = m_Dump->Header.BugCheckParameter3;
  2189. Args[3] = m_Dump->Header.BugCheckParameter4;
  2190. return S_OK;
  2191. }
  2192. HRESULT
  2193. KernelSummary64DumpTargetInfo::IdentifyDump(PULONG64 BaseMapSize)
  2194. {
  2195. HRESULT Status = E_NOINTERFACE;
  2196. PMEMORY_DUMP64 Dump = (PMEMORY_DUMP64)m_DumpBase;
  2197. __try
  2198. {
  2199. if (Dump->Header.Signature != DUMP_SIGNATURE64 ||
  2200. Dump->Header.ValidDump != DUMP_VALID_DUMP64 ||
  2201. Dump->Header.DumpType != DUMP_TYPE_SUMMARY)
  2202. {
  2203. __leave;
  2204. }
  2205. if (Dump->Summary.Signature != DUMP_SUMMARY_SIGNATURE)
  2206. {
  2207. // The header says it's a summary dump but
  2208. // it doesn't have a valid signature, so assume
  2209. // it's not a valid dump.
  2210. Status = HR_DATA_CORRUPT;
  2211. }
  2212. else
  2213. {
  2214. PPHYSICAL_MEMORY_RUN64 LastRun;
  2215. ULONG64 HighestPage;
  2216. // We rely on all of the header information being
  2217. // directly mapped. Unfortunately the header information
  2218. // can be off due to some size computation bugs, so
  2219. // attempt to get the right size regardless.
  2220. *BaseMapSize = Dump->Summary.HeaderSize;
  2221. LastRun = Dump->Header.PhysicalMemoryBlock.Run +
  2222. (Dump->Header.PhysicalMemoryBlock.NumberOfRuns - 1);
  2223. HighestPage = LastRun->BasePage + LastRun->PageCount;
  2224. if (HighestPage > Dump->Header.PhysicalMemoryBlock.NumberOfPages)
  2225. {
  2226. (*BaseMapSize) +=
  2227. (HighestPage -
  2228. Dump->Header.PhysicalMemoryBlock.NumberOfPages + 7) / 8;
  2229. }
  2230. Status = S_OK;
  2231. m_Dump = Dump;
  2232. }
  2233. }
  2234. __except(EXCEPTION_EXECUTE_HANDLER)
  2235. {
  2236. Status = DumpIdentifyStatus(GetExceptionCode());
  2237. }
  2238. return Status;
  2239. }
  2240. ULONG64
  2241. KernelSummary64DumpTargetInfo::PhysicalToOffset(ULONG64 Phys, BOOL Verbose,
  2242. PULONG Avail)
  2243. {
  2244. return SumPhysicalToOffset(m_Dump->Summary.HeaderSize, Phys, Verbose,
  2245. Avail);
  2246. }
  2247. void
  2248. KernelSummary64DumpTargetInfo::DumpDebug(void)
  2249. {
  2250. PSUMMARY_DUMP64 Sum = &m_Dump->Summary;
  2251. dprintf("----- 64 bit Kernel Summary Dump Analysis\n");
  2252. DumpHeader64(&m_Dump->Header);
  2253. dprintf("\nSUMMARY_DUMP64:\n");
  2254. dprintf("DumpOptions %08lx\n", Sum->DumpOptions);
  2255. dprintf("HeaderSize %08lx\n", Sum->HeaderSize);
  2256. dprintf("BitmapSize %08lx\n", Sum->BitmapSize);
  2257. dprintf("Pages %08lx\n", Sum->Pages);
  2258. dprintf("Bitmap.SizeOfBitMap %08lx\n", Sum->Bitmap.SizeOfBitMap);
  2259. KernelFullSumDumpTargetInfo::DumpDebug();
  2260. }
  2261. //----------------------------------------------------------------------------
  2262. //
  2263. // KernelTriageDumpTargetInfo.
  2264. //
  2265. //----------------------------------------------------------------------------
  2266. void
  2267. KernelTriageDumpTargetInfo::NearestDifferentlyValidOffsets(ULONG64 Offset,
  2268. PULONG64 NextOffset,
  2269. PULONG64 NextPage)
  2270. {
  2271. return MapNearestDifferentlyValidOffsets(Offset, NextOffset, NextPage);
  2272. }
  2273. HRESULT
  2274. KernelTriageDumpTargetInfo::ReadVirtual(
  2275. IN ProcessInfo* Process,
  2276. IN ULONG64 Offset,
  2277. OUT PVOID Buffer,
  2278. IN ULONG BufferSize,
  2279. OUT OPTIONAL PULONG BytesRead
  2280. )
  2281. {
  2282. return MapReadVirtual(Process, Offset, Buffer, BufferSize, BytesRead);
  2283. }
  2284. HRESULT
  2285. KernelTriageDumpTargetInfo::GetProcessorSystemDataOffset(
  2286. IN ULONG Processor,
  2287. IN ULONG Index,
  2288. OUT PULONG64 Offset
  2289. )
  2290. {
  2291. if (Processor != GetCurrentProcessor())
  2292. {
  2293. return E_INVALIDARG;
  2294. }
  2295. ULONG64 Prcb = m_KiProcessors[Processor];
  2296. HRESULT Status;
  2297. switch(Index)
  2298. {
  2299. case DEBUG_DATA_KPCR_OFFSET:
  2300. // We don't have a full PCR, just a PRCB.
  2301. return E_FAIL;
  2302. case DEBUG_DATA_KPRCB_OFFSET:
  2303. *Offset = Prcb;
  2304. break;
  2305. case DEBUG_DATA_KTHREAD_OFFSET:
  2306. if ((Status = ReadPointer
  2307. (m_ProcessHead, m_Machine,
  2308. Prcb + m_KdDebuggerData.OffsetPrcbCurrentThread,
  2309. Offset)) != S_OK)
  2310. {
  2311. return Status;
  2312. }
  2313. break;
  2314. }
  2315. return S_OK;
  2316. }
  2317. HRESULT
  2318. KernelTriageDumpTargetInfo::GetTargetContext(
  2319. ULONG64 Thread,
  2320. PVOID Context
  2321. )
  2322. {
  2323. // We only have the current context in a triage dump.
  2324. if (VIRTUAL_THREAD_INDEX(Thread) != GetCurrentProcessor())
  2325. {
  2326. return E_INVALIDARG;
  2327. }
  2328. // The KPRCB could be used to retrieve context information as in
  2329. // KernelFullSumDumpTargetInfo::GetTargetContext but
  2330. // for consistency the header context is used since it's
  2331. // the officially advertised place.
  2332. memcpy(Context, m_HeaderContext,
  2333. m_TypeInfo.SizeTargetContext);
  2334. return S_OK;
  2335. }
  2336. HRESULT
  2337. KernelTriageDumpTargetInfo::GetSelDescriptor(ThreadInfo* Thread,
  2338. MachineInfo* Machine,
  2339. ULONG Selector,
  2340. PDESCRIPTOR64 Desc)
  2341. {
  2342. return EmulateNtSelDescriptor(Thread, Machine, Selector, Desc);
  2343. }
  2344. HRESULT
  2345. KernelTriageDumpTargetInfo::SwitchProcessors(ULONG Processor)
  2346. {
  2347. ErrOut("Can't switch processors on a kernel triage dump\n");
  2348. return E_UNEXPECTED;
  2349. }
  2350. ULONG64
  2351. KernelTriageDumpTargetInfo::VirtualToOffset(ULONG64 Virt,
  2352. PULONG File, PULONG Avail)
  2353. {
  2354. ULONG64 Base;
  2355. ULONG Size;
  2356. PVOID Mapping, Param;
  2357. *File = DUMP_INFO_DUMP;
  2358. // ReadVirtual is overridden to read the memory map directly
  2359. // so this function will only be called from the generic
  2360. // WriteVirtual. We can only write regions mapped out of
  2361. // the dump so only return data memory regions.
  2362. if (m_DataMemMap.GetRegionInfo(Virt, &Base, &Size, &Mapping, &Param))
  2363. {
  2364. ULONG Delta = (ULONG)(Virt - Base);
  2365. *Avail = Size - Delta;
  2366. return ((PUCHAR)Mapping - (PUCHAR)m_DumpBase) + Delta;
  2367. }
  2368. return 0;
  2369. }
  2370. ULONG
  2371. KernelTriageDumpTargetInfo::GetCurrentProcessor(void)
  2372. {
  2373. // Extract the processor number from the
  2374. // PRCB in the dump.
  2375. PUCHAR PrcbNumber = (PUCHAR)
  2376. IndexRva(m_DumpBase, m_PrcbOffset +
  2377. m_KdDebuggerData.OffsetPrcbNumber, sizeof(UCHAR),
  2378. "PRCB.Number");
  2379. return PrcbNumber ? *PrcbNumber : 0;
  2380. }
  2381. HRESULT
  2382. KernelTriageDumpTargetInfo::MapMemoryRegions(ULONG PrcbOffset,
  2383. ULONG ThreadOffset,
  2384. ULONG ProcessOffset,
  2385. ULONG64 TopOfStack,
  2386. ULONG SizeOfCallStack,
  2387. ULONG CallStackOffset,
  2388. ULONG64 BStoreLimit,
  2389. ULONG SizeOfBStore,
  2390. ULONG BStoreOffset,
  2391. ULONG64 DataPageAddress,
  2392. ULONG DataPageOffset,
  2393. ULONG DataPageSize,
  2394. ULONG64 DebuggerDataAddress,
  2395. ULONG DebuggerDataOffset,
  2396. ULONG DebuggerDataSize,
  2397. ULONG MmDataOffset,
  2398. ULONG DataBlocksOffset,
  2399. ULONG DataBlocksCount)
  2400. {
  2401. HRESULT Status;
  2402. // Map any debugger data.
  2403. // We have to do this first to get the size of the various NT
  2404. // data structures will will map after this.
  2405. if (DebuggerDataAddress)
  2406. {
  2407. if ((Status = m_DataMemMap.
  2408. AddRegion(DebuggerDataAddress,
  2409. DebuggerDataSize,
  2410. IndexRva(m_DumpBase,
  2411. DebuggerDataOffset,
  2412. DebuggerDataSize,
  2413. "Debugger data block"),
  2414. NULL, TRUE)) != S_OK)
  2415. {
  2416. return Status;
  2417. }
  2418. m_HasDebuggerData = TRUE;
  2419. if (MmDataOffset)
  2420. {
  2421. MM_TRIAGE_TRANSLATION* Trans = g_MmTriageTranslations;
  2422. // Map memory fragments for MM Triage information
  2423. // that equates to entries in the debugger data.
  2424. while (Trans->DebuggerDataOffset > 0)
  2425. {
  2426. ULONG64 UNALIGNED* DbgDataPtr;
  2427. ULONG64 DbgData;
  2428. ULONG MmData;
  2429. ULONG Size;
  2430. DbgDataPtr = (ULONG64 UNALIGNED*)
  2431. IndexRva(m_DumpBase, DebuggerDataOffset +
  2432. Trans->DebuggerDataOffset,
  2433. sizeof(ULONG64), "Debugger data block");
  2434. if (!DbgDataPtr)
  2435. {
  2436. return HR_DATA_CORRUPT;
  2437. }
  2438. DbgData = *DbgDataPtr;
  2439. Size = sizeof(ULONG);
  2440. if (m_Machine->m_Ptr64)
  2441. {
  2442. MmData = MmDataOffset + Trans->Triage64Offset;
  2443. if (Trans->PtrSize)
  2444. {
  2445. Size = sizeof(ULONG64);
  2446. }
  2447. }
  2448. else
  2449. {
  2450. MmData = MmDataOffset + Trans->Triage32Offset;
  2451. DbgData = EXTEND64(DbgData);
  2452. }
  2453. if ((Status = m_DataMemMap.
  2454. AddRegion(DbgData, Size,
  2455. IndexRva(m_DumpBase, MmData, Size,
  2456. "MMTRIAGE data"),
  2457. NULL, TRUE)) != S_OK)
  2458. {
  2459. return Status;
  2460. }
  2461. Trans++;
  2462. }
  2463. }
  2464. }
  2465. //
  2466. // Load KdDebuggerDataBlock data right now so
  2467. // that the type constants in it are available immediately.
  2468. //
  2469. ReadKdDataBlock(m_ProcessHead);
  2470. // Technically a triage dump doesn't have to contain a KPRCB
  2471. // but we really want it to have one. Nobody generates them
  2472. // without a KPRCB so this is really just a sanity check.
  2473. if (PrcbOffset == 0)
  2474. {
  2475. ErrOut("Dump does not contain KPRCB\n");
  2476. return E_FAIL;
  2477. }
  2478. // Set this first so GetCurrentProcessor works.
  2479. m_PrcbOffset = PrcbOffset;
  2480. ULONG Processor = GetCurrentProcessor();
  2481. if (Processor >= MAXIMUM_PROCS)
  2482. {
  2483. ErrOut("Dump does not contain valid processor number\n");
  2484. return E_FAIL;
  2485. }
  2486. // The dump contains one PRCB for the current processor.
  2487. // Map the PRCB at the processor-zero location because
  2488. // that location should not ever have some other mapping
  2489. // for the dump.
  2490. m_KiProcessors[Processor] = m_TypeInfo.TriagePrcbOffset;
  2491. if ((Status = m_DataMemMap.
  2492. AddRegion(m_KiProcessors[Processor],
  2493. m_KdDebuggerData.SizePrcb,
  2494. IndexRva(m_DumpBase, PrcbOffset,
  2495. m_KdDebuggerData.SizePrcb, "PRCB"),
  2496. NULL, FALSE)) != S_OK)
  2497. {
  2498. return Status;
  2499. }
  2500. //
  2501. // Add ETHREAD and EPROCESS memory regions if available.
  2502. //
  2503. if (ThreadOffset != 0)
  2504. {
  2505. PVOID CurThread =
  2506. IndexRva(m_DumpBase, PrcbOffset +
  2507. m_KdDebuggerData.OffsetPrcbCurrentThread,
  2508. m_Machine->m_Ptr64 ? 8 : 4,
  2509. "PRCB.CurrentThread");
  2510. ULONG64 ThreadAddr, ProcAddr;
  2511. PVOID DataPtr;
  2512. if (!CurThread)
  2513. {
  2514. return HR_DATA_CORRUPT;
  2515. }
  2516. if (m_Machine->m_Ptr64)
  2517. {
  2518. ThreadAddr = *(PULONG64)CurThread;
  2519. DataPtr = IndexRva(m_DumpBase, ThreadOffset +
  2520. m_KdDebuggerData.OffsetKThreadApcProcess,
  2521. sizeof(ULONG64), "PRCB.ApcState.Process");
  2522. if (!DataPtr)
  2523. {
  2524. return HR_DATA_CORRUPT;
  2525. }
  2526. ProcAddr = *(PULONG64)DataPtr;
  2527. }
  2528. else
  2529. {
  2530. ThreadAddr = EXTEND64(*(PULONG)CurThread);
  2531. DataPtr = IndexRva(m_DumpBase, ThreadOffset +
  2532. m_KdDebuggerData.OffsetKThreadApcProcess,
  2533. sizeof(ULONG), "PRCB.ApcState.Process");
  2534. if (!DataPtr)
  2535. {
  2536. return HR_DATA_CORRUPT;
  2537. }
  2538. ProcAddr = EXTEND64(*(PULONG)DataPtr);
  2539. }
  2540. if ((Status = m_DataMemMap.
  2541. AddRegion(ThreadAddr,
  2542. m_KdDebuggerData.SizeEThread,
  2543. IndexRva(m_DumpBase, ThreadOffset,
  2544. m_KdDebuggerData.SizeEThread,
  2545. "ETHREAD"),
  2546. NULL, TRUE)) != S_OK)
  2547. {
  2548. return Status;
  2549. }
  2550. if (ProcessOffset != 0)
  2551. {
  2552. if ((Status = m_DataMemMap.
  2553. AddRegion(ProcAddr,
  2554. m_KdDebuggerData.SizeEProcess,
  2555. IndexRva(m_DumpBase, ProcessOffset,
  2556. m_KdDebuggerData.SizeEProcess,
  2557. "EPROCESS"),
  2558. NULL, TRUE)) != S_OK)
  2559. {
  2560. return Status;
  2561. }
  2562. }
  2563. else
  2564. {
  2565. WarnOut("Mini Kernel Dump does not have "
  2566. "process information\n");
  2567. }
  2568. }
  2569. else
  2570. {
  2571. WarnOut("Mini Kernel Dump does not have thread information\n");
  2572. }
  2573. // Add the backing store region.
  2574. if (m_MachineType == IMAGE_FILE_MACHINE_IA64)
  2575. {
  2576. if (BStoreOffset != 0)
  2577. {
  2578. if ((Status = m_DataMemMap.
  2579. AddRegion(BStoreLimit - SizeOfBStore, SizeOfBStore,
  2580. IndexRva(m_DumpBase, BStoreOffset, SizeOfBStore,
  2581. "Backing store"),
  2582. NULL, TRUE)) != S_OK)
  2583. {
  2584. return Status;
  2585. }
  2586. }
  2587. else
  2588. {
  2589. WarnOut("Mini Kernel Dump does not have "
  2590. "backing store information\n");
  2591. }
  2592. }
  2593. // Add data page if available
  2594. if (DataPageAddress)
  2595. {
  2596. if ((Status = m_DataMemMap.
  2597. AddRegion(DataPageAddress, DataPageSize,
  2598. IndexRva(m_DumpBase, DataPageOffset, DataPageSize,
  2599. "Data page"),
  2600. NULL, TRUE)) != S_OK)
  2601. {
  2602. return Status;
  2603. }
  2604. }
  2605. // Map arbitrary data blocks.
  2606. if (DataBlocksCount > 0)
  2607. {
  2608. PTRIAGE_DATA_BLOCK Block;
  2609. Block = (PTRIAGE_DATA_BLOCK)
  2610. IndexRva(m_DumpBase, DataBlocksOffset, sizeof(Block),
  2611. "Data block descriptor");
  2612. if (!Block)
  2613. {
  2614. return HR_DATA_CORRUPT;
  2615. }
  2616. while (DataBlocksCount-- > 0)
  2617. {
  2618. if ((Status = m_DataMemMap.
  2619. AddRegion(Block->Address, Block->Size,
  2620. IndexRva(m_DumpBase, Block->Offset, Block->Size,
  2621. "Data block"),
  2622. NULL, TRUE)) != S_OK)
  2623. {
  2624. return Status;
  2625. }
  2626. Block++;
  2627. }
  2628. }
  2629. // Add the stack to the valid memory region.
  2630. return m_DataMemMap.
  2631. AddRegion(TopOfStack, SizeOfCallStack,
  2632. IndexRva(m_DumpBase, CallStackOffset,
  2633. SizeOfCallStack, "Call stack"),
  2634. NULL, TRUE);
  2635. }
  2636. void
  2637. KernelTriageDumpTargetInfo::DumpDataBlocks(ULONG Offset, ULONG Count)
  2638. {
  2639. PTRIAGE_DATA_BLOCK Block;
  2640. ULONG MaxOffset;
  2641. if (Count == 0)
  2642. {
  2643. return;
  2644. }
  2645. Block = (PTRIAGE_DATA_BLOCK)
  2646. IndexRva(m_DumpBase, Offset, sizeof(Block),
  2647. "Data block descriptor");
  2648. if (!Block)
  2649. {
  2650. return;
  2651. }
  2652. MaxOffset = 0;
  2653. while (Count-- > 0)
  2654. {
  2655. dprintf(" %s - %s at offset %08x\n",
  2656. FormatAddr64(Block->Address),
  2657. FormatAddr64(Block->Address + Block->Size - 1),
  2658. Block->Offset);
  2659. if (Block->Offset + Block->Size > MaxOffset)
  2660. {
  2661. MaxOffset = Block->Offset + Block->Size;
  2662. }
  2663. Block++;
  2664. }
  2665. dprintf(" Max offset %x, %x from end of file\n",
  2666. MaxOffset, (ULONG)(m_InfoFiles[DUMP_INFO_DUMP].m_FileSize -
  2667. MaxOffset));
  2668. }
  2669. HRESULT
  2670. KernelTriage32DumpTargetInfo::Initialize(void)
  2671. {
  2672. HRESULT Status;
  2673. if ((Status = KernelDumpTargetInfo::Initialize()) != S_OK)
  2674. {
  2675. return Status;
  2676. }
  2677. // Pick up any potentially modified base mapping pointer.
  2678. m_Dump = (PMEMORY_DUMP32)m_DumpBase;
  2679. dprintf("Mini Kernel Dump File: "
  2680. "Only registers and stack trace are available\n\n");
  2681. PTRIAGE_DUMP32 Triage = &m_Dump->Triage;
  2682. Status = InitGlobals32(m_Dump);
  2683. if (Status != S_OK)
  2684. {
  2685. return Status;
  2686. }
  2687. //
  2688. // Optional memory page
  2689. //
  2690. ULONG64 DataPageAddress = 0;
  2691. ULONG DataPageOffset = 0;
  2692. ULONG DataPageSize = 0;
  2693. if (((m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_BASIC_INFO) ==
  2694. TRIAGE_DUMP_BASIC_INFO) &&
  2695. (m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_DATAPAGE))
  2696. {
  2697. DataPageAddress = Triage->DataPageAddress;
  2698. DataPageOffset = Triage->DataPageOffset;
  2699. DataPageSize = Triage->DataPageSize;
  2700. }
  2701. //
  2702. // Optional KDDEBUGGER_DATA64.
  2703. //
  2704. ULONG64 DebuggerDataAddress = 0;
  2705. ULONG DebuggerDataOffset = 0;
  2706. ULONG DebuggerDataSize = 0;
  2707. if (((m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_BASIC_INFO) ==
  2708. TRIAGE_DUMP_BASIC_INFO) &&
  2709. (m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_DEBUGGER_DATA))
  2710. {
  2711. // DebuggerDataBlock field must be valid if the dump is
  2712. // new enough to have a data block in it.
  2713. DebuggerDataAddress = EXTEND64(m_Dump->Header.KdDebuggerDataBlock);
  2714. DebuggerDataOffset = Triage->DebuggerDataOffset;
  2715. DebuggerDataSize = Triage->DebuggerDataSize;
  2716. }
  2717. //
  2718. // Optional data blocks.
  2719. //
  2720. ULONG DataBlocksOffset = 0;
  2721. ULONG DataBlocksCount = 0;
  2722. if (((m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_BASIC_INFO) ==
  2723. TRIAGE_DUMP_BASIC_INFO) &&
  2724. (m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_DATA_BLOCKS))
  2725. {
  2726. DataBlocksOffset = Triage->DataBlocksOffset;
  2727. DataBlocksCount = Triage->DataBlocksCount;
  2728. }
  2729. //
  2730. // We store the service pack version in the header because we
  2731. // don't store the actual memory
  2732. //
  2733. SetNtCsdVersion(m_BuildNumber, m_Dump->Triage.ServicePackBuild);
  2734. // Tagged data will follow all of the normal dump data.
  2735. m_TaggedOffset = m_Dump->Triage.SizeOfDump;
  2736. return MapMemoryRegions(Triage->PrcbOffset, Triage->ThreadOffset,
  2737. Triage->ProcessOffset,
  2738. EXTEND64(Triage->TopOfStack),
  2739. Triage->SizeOfCallStack, Triage->CallStackOffset,
  2740. 0, 0, 0,
  2741. DataPageAddress, DataPageOffset, DataPageSize,
  2742. DebuggerDataAddress, DebuggerDataOffset,
  2743. DebuggerDataSize, Triage->MmOffset,
  2744. DataBlocksOffset, DataBlocksCount);
  2745. }
  2746. HRESULT
  2747. KernelTriage32DumpTargetInfo::GetDescription(PSTR Buffer, ULONG BufferLen,
  2748. PULONG DescLen)
  2749. {
  2750. HRESULT Status;
  2751. Status = AppendToStringBuffer(S_OK, "32-bit Kernel triage dump: ", TRUE,
  2752. &Buffer, &BufferLen, DescLen);
  2753. return AppendToStringBuffer(Status,
  2754. m_InfoFiles[DUMP_INFO_DUMP].m_FileNameA,
  2755. FALSE, &Buffer, &BufferLen, DescLen);
  2756. }
  2757. HRESULT
  2758. KernelTriage32DumpTargetInfo::ReadBugCheckData(PULONG Code, ULONG64 Args[4])
  2759. {
  2760. *Code = m_Dump->Header.BugCheckCode;
  2761. Args[0] = EXTEND64(m_Dump->Header.BugCheckParameter1);
  2762. Args[1] = EXTEND64(m_Dump->Header.BugCheckParameter2);
  2763. Args[2] = EXTEND64(m_Dump->Header.BugCheckParameter3);
  2764. Args[3] = EXTEND64(m_Dump->Header.BugCheckParameter4);
  2765. return S_OK;
  2766. }
  2767. HRESULT
  2768. KernelTriage32DumpTargetInfo::IdentifyDump(PULONG64 BaseMapSize)
  2769. {
  2770. HRESULT Status = E_NOINTERFACE;
  2771. PMEMORY_DUMP32 Dump = (PMEMORY_DUMP32)m_DumpBase;
  2772. __try
  2773. {
  2774. if (Dump->Header.Signature != DUMP_SIGNATURE32 ||
  2775. Dump->Header.ValidDump != DUMP_VALID_DUMP32 ||
  2776. Dump->Header.DumpType != DUMP_TYPE_TRIAGE)
  2777. {
  2778. __leave;
  2779. }
  2780. if (*(PULONG)IndexByByte(Dump, Dump->Triage.SizeOfDump -
  2781. sizeof(ULONG)) != TRIAGE_DUMP_VALID)
  2782. {
  2783. // The header says it's a triage dump but
  2784. // it doesn't have a valid signature, so assume
  2785. // it's not a valid dump.
  2786. Status = HR_DATA_CORRUPT;
  2787. __leave;
  2788. }
  2789. // Make sure that the dump has the minimal information that
  2790. // we want.
  2791. if (Dump->Triage.ContextOffset == 0 ||
  2792. Dump->Triage.ExceptionOffset == 0 ||
  2793. Dump->Triage.PrcbOffset == 0 ||
  2794. Dump->Triage.CallStackOffset == 0)
  2795. {
  2796. ErrOut("Mini Kernel Dump does not contain enough "
  2797. "information to be debugged\n");
  2798. Status = E_FAIL;
  2799. __leave;
  2800. }
  2801. // We rely on being able to directly access the entire
  2802. // content of the dump through the default view so
  2803. // ensure that it's possible.
  2804. *BaseMapSize = m_InfoFiles[DUMP_INFO_DUMP].m_FileSize;
  2805. m_Dump = Dump;
  2806. Status = S_OK;
  2807. }
  2808. __except(EXCEPTION_EXECUTE_HANDLER)
  2809. {
  2810. Status = DumpIdentifyStatus(GetExceptionCode());
  2811. }
  2812. return Status;
  2813. }
  2814. ModuleInfo*
  2815. KernelTriage32DumpTargetInfo::GetModuleInfo(BOOL UserMode)
  2816. {
  2817. return UserMode ? NULL : &g_KernelTriage32ModuleIterator;
  2818. }
  2819. UnloadedModuleInfo*
  2820. KernelTriage32DumpTargetInfo::GetUnloadedModuleInfo(void)
  2821. {
  2822. return &g_KernelTriage32UnloadedModuleIterator;
  2823. }
  2824. void
  2825. KernelTriage32DumpTargetInfo::DumpDebug(void)
  2826. {
  2827. PTRIAGE_DUMP32 Triage = &m_Dump->Triage;
  2828. dprintf("----- 32 bit Kernel Mini Dump Analysis\n");
  2829. DumpHeader32(&m_Dump->Header);
  2830. dprintf("MiniDumpFields %08lx \n", m_Dump->Header.MiniDumpFields);
  2831. dprintf("\nTRIAGE_DUMP32:\n");
  2832. dprintf("ServicePackBuild %08lx \n", Triage->ServicePackBuild );
  2833. dprintf("SizeOfDump %08lx \n", Triage->SizeOfDump );
  2834. dprintf("ValidOffset %08lx \n", Triage->ValidOffset );
  2835. dprintf("ContextOffset %08lx \n", Triage->ContextOffset );
  2836. dprintf("ExceptionOffset %08lx \n", Triage->ExceptionOffset );
  2837. dprintf("MmOffset %08lx \n", Triage->MmOffset );
  2838. dprintf("UnloadedDriversOffset %08lx \n", Triage->UnloadedDriversOffset );
  2839. dprintf("PrcbOffset %08lx \n", Triage->PrcbOffset );
  2840. dprintf("ProcessOffset %08lx \n", Triage->ProcessOffset );
  2841. dprintf("ThreadOffset %08lx \n", Triage->ThreadOffset );
  2842. dprintf("CallStackOffset %08lx \n", Triage->CallStackOffset );
  2843. dprintf("SizeOfCallStack %08lx \n", Triage->SizeOfCallStack );
  2844. dprintf("DriverListOffset %08lx \n", Triage->DriverListOffset );
  2845. dprintf("DriverCount %08lx \n", Triage->DriverCount );
  2846. dprintf("StringPoolOffset %08lx \n", Triage->StringPoolOffset );
  2847. dprintf("StringPoolSize %08lx \n", Triage->StringPoolSize );
  2848. dprintf("BrokenDriverOffset %08lx \n", Triage->BrokenDriverOffset );
  2849. dprintf("TriageOptions %08lx %s\n",
  2850. Triage->TriageOptions,
  2851. (Triage->TriageOptions != 0xffffffff &&
  2852. (Triage->TriageOptions & TRIAGE_OPTION_OVERFLOWED)) ?
  2853. "OVERFLOWED" : "");
  2854. dprintf("TopOfStack %08lx \n", Triage->TopOfStack );
  2855. if (((m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_BASIC_INFO) ==
  2856. TRIAGE_DUMP_BASIC_INFO) &&
  2857. (m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_DATAPAGE))
  2858. {
  2859. dprintf("DataPageAddress %08lx \n", Triage->DataPageAddress );
  2860. dprintf("DataPageOffset %08lx \n", Triage->DataPageOffset );
  2861. dprintf("DataPageSize %08lx \n", Triage->DataPageSize );
  2862. }
  2863. if (((m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_BASIC_INFO) ==
  2864. TRIAGE_DUMP_BASIC_INFO) &&
  2865. (m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_DEBUGGER_DATA))
  2866. {
  2867. dprintf("DebuggerDataOffset %08lx \n", Triage->DebuggerDataOffset);
  2868. dprintf("DebuggerDataSize %08lx \n", Triage->DebuggerDataSize );
  2869. }
  2870. if (((m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_BASIC_INFO) ==
  2871. TRIAGE_DUMP_BASIC_INFO) &&
  2872. (m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_DATA_BLOCKS))
  2873. {
  2874. dprintf("DataBlocksOffset %08lx \n", Triage->DataBlocksOffset );
  2875. dprintf("DataBlocksCount %08lx \n", Triage->DataBlocksCount );
  2876. DumpDataBlocks(Triage->DataBlocksOffset,
  2877. Triage->DataBlocksCount);
  2878. }
  2879. }
  2880. HRESULT
  2881. KernelTriage64DumpTargetInfo::Initialize(void)
  2882. {
  2883. HRESULT Status;
  2884. if ((Status = KernelDumpTargetInfo::Initialize()) != S_OK)
  2885. {
  2886. return Status;
  2887. }
  2888. // Pick up any potentially modified base mapping pointer.
  2889. m_Dump = (PMEMORY_DUMP64)m_DumpBase;
  2890. dprintf("Mini Kernel Dump File: "
  2891. "Only registers and stack trace are available\n\n");
  2892. PTRIAGE_DUMP64 Triage = &m_Dump->Triage;
  2893. Status = InitGlobals64(m_Dump);
  2894. if (Status != S_OK)
  2895. {
  2896. return Status;
  2897. }
  2898. //
  2899. // Optional memory page
  2900. //
  2901. ULONG64 DataPageAddress = 0;
  2902. ULONG DataPageOffset = 0;
  2903. ULONG DataPageSize = 0;
  2904. if (((m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_BASIC_INFO) ==
  2905. TRIAGE_DUMP_BASIC_INFO) &&
  2906. (m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_DATAPAGE))
  2907. {
  2908. DataPageAddress = Triage->DataPageAddress;
  2909. DataPageOffset = Triage->DataPageOffset;
  2910. DataPageSize = Triage->DataPageSize;
  2911. }
  2912. //
  2913. // Optional KDDEBUGGER_DATA64.
  2914. //
  2915. ULONG64 DebuggerDataAddress = 0;
  2916. ULONG DebuggerDataOffset = 0;
  2917. ULONG DebuggerDataSize = 0;
  2918. if (((m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_BASIC_INFO) ==
  2919. TRIAGE_DUMP_BASIC_INFO) &&
  2920. (m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_DEBUGGER_DATA))
  2921. {
  2922. // DebuggerDataBlock field must be valid if the dump is
  2923. // new enough to have a data block in it.
  2924. DebuggerDataAddress = m_Dump->Header.KdDebuggerDataBlock;
  2925. DebuggerDataOffset = Triage->DebuggerDataOffset;
  2926. DebuggerDataSize = Triage->DebuggerDataSize;
  2927. }
  2928. //
  2929. // Optional data blocks.
  2930. //
  2931. ULONG DataBlocksOffset = 0;
  2932. ULONG DataBlocksCount = 0;
  2933. if (((m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_BASIC_INFO) ==
  2934. TRIAGE_DUMP_BASIC_INFO) &&
  2935. (m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_DATA_BLOCKS))
  2936. {
  2937. DataBlocksOffset = Triage->DataBlocksOffset;
  2938. DataBlocksCount = Triage->DataBlocksCount;
  2939. }
  2940. //
  2941. // We store the service pack version in the header because we
  2942. // don't store the actual memory
  2943. //
  2944. SetNtCsdVersion(m_BuildNumber, m_Dump->Triage.ServicePackBuild);
  2945. // Tagged data will follow all of the normal dump data.
  2946. m_TaggedOffset = m_Dump->Triage.SizeOfDump;
  2947. return MapMemoryRegions(Triage->PrcbOffset, Triage->ThreadOffset,
  2948. Triage->ProcessOffset, Triage->TopOfStack,
  2949. Triage->SizeOfCallStack, Triage->CallStackOffset,
  2950. Triage->ArchitectureSpecific.Ia64.LimitOfBStore,
  2951. Triage->ArchitectureSpecific.Ia64.SizeOfBStore,
  2952. Triage->ArchitectureSpecific.Ia64.BStoreOffset,
  2953. DataPageAddress, DataPageOffset, DataPageSize,
  2954. DebuggerDataAddress, DebuggerDataOffset,
  2955. DebuggerDataSize, Triage->MmOffset,
  2956. DataBlocksOffset, DataBlocksCount);
  2957. }
  2958. HRESULT
  2959. KernelTriage64DumpTargetInfo::GetDescription(PSTR Buffer, ULONG BufferLen,
  2960. PULONG DescLen)
  2961. {
  2962. HRESULT Status;
  2963. Status = AppendToStringBuffer(S_OK, "64-bit Kernel triage dump: ", TRUE,
  2964. &Buffer, &BufferLen, DescLen);
  2965. return AppendToStringBuffer(Status,
  2966. m_InfoFiles[DUMP_INFO_DUMP].m_FileNameA,
  2967. FALSE, &Buffer, &BufferLen, DescLen);
  2968. }
  2969. HRESULT
  2970. KernelTriage64DumpTargetInfo::ReadBugCheckData(PULONG Code, ULONG64 Args[4])
  2971. {
  2972. *Code = m_Dump->Header.BugCheckCode;
  2973. Args[0] = m_Dump->Header.BugCheckParameter1;
  2974. Args[1] = m_Dump->Header.BugCheckParameter2;
  2975. Args[2] = m_Dump->Header.BugCheckParameter3;
  2976. Args[3] = m_Dump->Header.BugCheckParameter4;
  2977. return S_OK;
  2978. }
  2979. HRESULT
  2980. KernelTriage64DumpTargetInfo::IdentifyDump(PULONG64 BaseMapSize)
  2981. {
  2982. HRESULT Status = E_NOINTERFACE;
  2983. PMEMORY_DUMP64 Dump = (PMEMORY_DUMP64)m_DumpBase;
  2984. __try
  2985. {
  2986. if (Dump->Header.Signature != DUMP_SIGNATURE64 ||
  2987. Dump->Header.ValidDump != DUMP_VALID_DUMP64 ||
  2988. Dump->Header.DumpType != DUMP_TYPE_TRIAGE)
  2989. {
  2990. __leave;
  2991. }
  2992. if (*(PULONG)IndexByByte(Dump, Dump->Triage.SizeOfDump -
  2993. sizeof(ULONG)) != TRIAGE_DUMP_VALID)
  2994. {
  2995. // The header says it's a triage dump but
  2996. // it doesn't have a valid signature, so assume
  2997. // it's not a valid dump.
  2998. Status = HR_DATA_CORRUPT;
  2999. __leave;
  3000. }
  3001. // Make sure that the dump has the minimal information that
  3002. // we want.
  3003. if (Dump->Triage.ContextOffset == 0 ||
  3004. Dump->Triage.ExceptionOffset == 0 ||
  3005. Dump->Triage.PrcbOffset == 0 ||
  3006. Dump->Triage.CallStackOffset == 0)
  3007. {
  3008. ErrOut("Mini Kernel Dump does not contain enough "
  3009. "information to be debugged\n");
  3010. Status = E_FAIL;
  3011. __leave;
  3012. }
  3013. // We rely on being able to directly access the entire
  3014. // content of the dump through the default view so
  3015. // ensure that it's possible.
  3016. *BaseMapSize = m_InfoFiles[DUMP_INFO_DUMP].m_FileSize;
  3017. m_Dump = Dump;
  3018. Status = S_OK;
  3019. }
  3020. __except(EXCEPTION_EXECUTE_HANDLER)
  3021. {
  3022. Status = DumpIdentifyStatus(GetExceptionCode());
  3023. }
  3024. return Status;
  3025. }
  3026. ModuleInfo*
  3027. KernelTriage64DumpTargetInfo::GetModuleInfo(BOOL UserMode)
  3028. {
  3029. return UserMode ? NULL : &g_KernelTriage64ModuleIterator;
  3030. }
  3031. UnloadedModuleInfo*
  3032. KernelTriage64DumpTargetInfo::GetUnloadedModuleInfo(void)
  3033. {
  3034. return &g_KernelTriage64UnloadedModuleIterator;
  3035. }
  3036. void
  3037. KernelTriage64DumpTargetInfo::DumpDebug(void)
  3038. {
  3039. PTRIAGE_DUMP64 Triage = &m_Dump->Triage;
  3040. dprintf("----- 64 bit Kernel Mini Dump Analysis\n");
  3041. DumpHeader64(&m_Dump->Header);
  3042. dprintf("MiniDumpFields %08lx \n", m_Dump->Header.MiniDumpFields);
  3043. dprintf("\nTRIAGE_DUMP64:\n");
  3044. dprintf("ServicePackBuild %08lx \n", Triage->ServicePackBuild );
  3045. dprintf("SizeOfDump %08lx \n", Triage->SizeOfDump );
  3046. dprintf("ValidOffset %08lx \n", Triage->ValidOffset );
  3047. dprintf("ContextOffset %08lx \n", Triage->ContextOffset );
  3048. dprintf("ExceptionOffset %08lx \n", Triage->ExceptionOffset );
  3049. dprintf("MmOffset %08lx \n", Triage->MmOffset );
  3050. dprintf("UnloadedDriversOffset %08lx \n", Triage->UnloadedDriversOffset );
  3051. dprintf("PrcbOffset %08lx \n", Triage->PrcbOffset );
  3052. dprintf("ProcessOffset %08lx \n", Triage->ProcessOffset );
  3053. dprintf("ThreadOffset %08lx \n", Triage->ThreadOffset );
  3054. dprintf("CallStackOffset %08lx \n", Triage->CallStackOffset );
  3055. dprintf("SizeOfCallStack %08lx \n", Triage->SizeOfCallStack );
  3056. dprintf("DriverListOffset %08lx \n", Triage->DriverListOffset );
  3057. dprintf("DriverCount %08lx \n", Triage->DriverCount );
  3058. dprintf("StringPoolOffset %08lx \n", Triage->StringPoolOffset );
  3059. dprintf("StringPoolSize %08lx \n", Triage->StringPoolSize );
  3060. dprintf("BrokenDriverOffset %08lx \n", Triage->BrokenDriverOffset );
  3061. dprintf("TriageOptions %08lx %s\n",
  3062. Triage->TriageOptions,
  3063. (Triage->TriageOptions != 0xffffffff &&
  3064. (Triage->TriageOptions & TRIAGE_OPTION_OVERFLOWED)) ?
  3065. "OVERFLOWED" : "");
  3066. dprintf("TopOfStack %s \n",
  3067. FormatAddr64(Triage->TopOfStack));
  3068. dprintf("BStoreOffset %08lx \n",
  3069. Triage->ArchitectureSpecific.Ia64.BStoreOffset );
  3070. dprintf("SizeOfBStore %08lx \n",
  3071. Triage->ArchitectureSpecific.Ia64.SizeOfBStore );
  3072. dprintf("LimitOfBStore %s \n",
  3073. FormatAddr64(Triage->ArchitectureSpecific.Ia64.LimitOfBStore));
  3074. if (((m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_BASIC_INFO) ==
  3075. TRIAGE_DUMP_BASIC_INFO) &&
  3076. (m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_DATAPAGE))
  3077. {
  3078. dprintf("DataPageAddress %s \n",
  3079. FormatAddr64(Triage->DataPageAddress));
  3080. dprintf("DataPageOffset %08lx \n", Triage->DataPageOffset );
  3081. dprintf("DataPageSize %08lx \n", Triage->DataPageSize );
  3082. }
  3083. if (((m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_BASIC_INFO) ==
  3084. TRIAGE_DUMP_BASIC_INFO) &&
  3085. (m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_DEBUGGER_DATA))
  3086. {
  3087. dprintf("DebuggerDataOffset %08lx \n", Triage->DebuggerDataOffset);
  3088. dprintf("DebuggerDataSize %08lx \n", Triage->DebuggerDataSize );
  3089. }
  3090. if (((m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_BASIC_INFO) ==
  3091. TRIAGE_DUMP_BASIC_INFO) &&
  3092. (m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_DATA_BLOCKS))
  3093. {
  3094. dprintf("DataBlocksOffset %08lx \n", Triage->DataBlocksOffset );
  3095. dprintf("DataBlocksCount %08lx \n", Triage->DataBlocksCount );
  3096. DumpDataBlocks(Triage->DataBlocksOffset,
  3097. Triage->DataBlocksCount);
  3098. }
  3099. }
  3100. //----------------------------------------------------------------------------
  3101. //
  3102. // KernelFullDumpTargetInfo.
  3103. //
  3104. //----------------------------------------------------------------------------
  3105. HRESULT
  3106. KernelFull32DumpTargetInfo::Initialize(void)
  3107. {
  3108. // Pick up any potentially modified base mapping pointer.
  3109. m_Dump = (PMEMORY_DUMP32)m_DumpBase;
  3110. dprintf("Kernel Dump File: Full address space is available\n\n");
  3111. HRESULT Status = InitGlobals32(m_Dump);
  3112. if (Status != S_OK)
  3113. {
  3114. return Status;
  3115. }
  3116. // Tagged data will follow all of the normal dump data.
  3117. m_TaggedOffset =
  3118. sizeof(m_Dump->Header) +
  3119. m_Dump->Header.PhysicalMemoryBlock.NumberOfPages *
  3120. m_Machine->m_PageSize;
  3121. if (m_InfoFiles[DUMP_INFO_DUMP].m_FileSize < m_TaggedOffset)
  3122. {
  3123. WarnOut("************************************************************\n");
  3124. WarnOut("WARNING: Dump file has been truncated. "
  3125. "Data may be missing.\n");
  3126. WarnOut("************************************************************\n\n");
  3127. }
  3128. return KernelFullSumDumpTargetInfo::Initialize();
  3129. }
  3130. HRESULT
  3131. KernelFull32DumpTargetInfo::GetDescription(PSTR Buffer, ULONG BufferLen,
  3132. PULONG DescLen)
  3133. {
  3134. HRESULT Status;
  3135. Status = AppendToStringBuffer(S_OK, "32-bit Full kernel dump: ", TRUE,
  3136. &Buffer, &BufferLen, DescLen);
  3137. return AppendToStringBuffer(Status,
  3138. m_InfoFiles[DUMP_INFO_DUMP].m_FileNameA,
  3139. FALSE, &Buffer, &BufferLen, DescLen);
  3140. }
  3141. HRESULT
  3142. KernelFull32DumpTargetInfo::ReadBugCheckData(PULONG Code, ULONG64 Args[4])
  3143. {
  3144. *Code = m_Dump->Header.BugCheckCode;
  3145. Args[0] = EXTEND64(m_Dump->Header.BugCheckParameter1);
  3146. Args[1] = EXTEND64(m_Dump->Header.BugCheckParameter2);
  3147. Args[2] = EXTEND64(m_Dump->Header.BugCheckParameter3);
  3148. Args[3] = EXTEND64(m_Dump->Header.BugCheckParameter4);
  3149. return S_OK;
  3150. }
  3151. HRESULT
  3152. KernelFull32DumpTargetInfo::IdentifyDump(PULONG64 BaseMapSize)
  3153. {
  3154. HRESULT Status = E_NOINTERFACE;
  3155. PMEMORY_DUMP32 Dump = (PMEMORY_DUMP32)m_DumpBase;
  3156. __try
  3157. {
  3158. if (Dump->Header.Signature != DUMP_SIGNATURE32 ||
  3159. Dump->Header.ValidDump != DUMP_VALID_DUMP32)
  3160. {
  3161. __leave;
  3162. }
  3163. if (Dump->Header.DumpType != DUMP_SIGNATURE32 &&
  3164. Dump->Header.DumpType != DUMP_TYPE_FULL)
  3165. {
  3166. // We've seen some cases where the end of a dump
  3167. // header is messed up, leaving the dump type wrong.
  3168. // If this is an older build let such corruption
  3169. // go by with a warning.
  3170. if (Dump->Header.MinorVersion < 2195)
  3171. {
  3172. WarnOut("***************************************************************\n");
  3173. WarnOut("WARNING: Full dump header type is invalid, "
  3174. "dump may be corrupt.\n");
  3175. WarnOut("***************************************************************\n");
  3176. }
  3177. else
  3178. {
  3179. __leave;
  3180. }
  3181. }
  3182. // Summary and triage dumps must be checked before this
  3183. // so there's nothing left to check.
  3184. m_Dump = Dump;
  3185. Status = S_OK;
  3186. }
  3187. __except(EXCEPTION_EXECUTE_HANDLER)
  3188. {
  3189. Status = DumpIdentifyStatus(GetExceptionCode());
  3190. }
  3191. return Status;
  3192. }
  3193. ULONG64
  3194. KernelFull32DumpTargetInfo::PhysicalToOffset(ULONG64 Phys, BOOL Verbose,
  3195. PULONG Avail)
  3196. {
  3197. ULONG PageIndex =
  3198. (ULONG)Phys & (m_Machine->m_PageSize - 1);
  3199. *Avail = m_Machine->m_PageSize - PageIndex;
  3200. ULONG64 Offset = 0;
  3201. __try
  3202. {
  3203. PPHYSICAL_MEMORY_DESCRIPTOR32 PhysDesc =
  3204. &m_Dump->Header.PhysicalMemoryBlock;
  3205. ULONG64 Page = Phys >> m_Machine->m_PageShift;
  3206. ULONG j = 0;
  3207. while (j < PhysDesc->NumberOfRuns)
  3208. {
  3209. if ((Page >= PhysDesc->Run[j].BasePage) &&
  3210. (Page < (PhysDesc->Run[j].BasePage +
  3211. PhysDesc->Run[j].PageCount)))
  3212. {
  3213. Offset += Page - PhysDesc->Run[j].BasePage;
  3214. Offset = Offset * m_Machine->m_PageSize +
  3215. sizeof(m_Dump->Header) + PageIndex;
  3216. break;
  3217. }
  3218. Offset += PhysDesc->Run[j].PageCount;
  3219. j += 1;
  3220. }
  3221. if (j >= PhysDesc->NumberOfRuns)
  3222. {
  3223. KdOut("Physical Memory Address %s is "
  3224. "greater than MaxPhysicalAddress\n",
  3225. FormatDisp64(Phys));
  3226. Offset = 0;
  3227. }
  3228. }
  3229. __except(MappingExceptionFilter(GetExceptionInformation()))
  3230. {
  3231. Offset = 0;
  3232. }
  3233. return Offset;
  3234. }
  3235. void
  3236. KernelFull32DumpTargetInfo::DumpDebug(void)
  3237. {
  3238. PPHYSICAL_MEMORY_DESCRIPTOR32 PhysDesc =
  3239. &m_Dump->Header.PhysicalMemoryBlock;
  3240. ULONG PageSize = m_Machine->m_PageSize;
  3241. dprintf("----- 32 bit Kernel Full Dump Analysis\n");
  3242. DumpHeader32(&m_Dump->Header);
  3243. dprintf("\nPhysical Memory Description:\n");
  3244. dprintf("Number of runs: %d\n", PhysDesc->NumberOfRuns);
  3245. dprintf(" FileOffset Start Address Length\n");
  3246. ULONG j = 0;
  3247. ULONG Offset = 1;
  3248. while (j < PhysDesc->NumberOfRuns)
  3249. {
  3250. dprintf(" %08lx %08lx %08lx\n",
  3251. Offset * PageSize,
  3252. PhysDesc->Run[j].BasePage * PageSize,
  3253. PhysDesc->Run[j].PageCount * PageSize);
  3254. Offset += PhysDesc->Run[j].PageCount;
  3255. j += 1;
  3256. }
  3257. j--;
  3258. dprintf("Last Page: %08lx %08lx\n",
  3259. (Offset - 1) * PageSize,
  3260. (PhysDesc->Run[j].BasePage + PhysDesc->Run[j].PageCount - 1) *
  3261. PageSize);
  3262. KernelFullSumDumpTargetInfo::DumpDebug();
  3263. }
  3264. HRESULT
  3265. KernelFull64DumpTargetInfo::Initialize(void)
  3266. {
  3267. // Pick up any potentially modified base mapping pointer.
  3268. m_Dump = (PMEMORY_DUMP64)m_DumpBase;
  3269. dprintf("Kernel Dump File: Full address space is available\n\n");
  3270. HRESULT Status = InitGlobals64(m_Dump);
  3271. if (Status != S_OK)
  3272. {
  3273. return Status;
  3274. }
  3275. // Tagged data will follow all of the normal dump data.
  3276. m_TaggedOffset =
  3277. sizeof(m_Dump->Header) +
  3278. m_Dump->Header.PhysicalMemoryBlock.NumberOfPages *
  3279. m_Machine->m_PageSize;
  3280. if (m_InfoFiles[DUMP_INFO_DUMP].m_FileSize < m_TaggedOffset)
  3281. {
  3282. WarnOut("************************************************************\n");
  3283. WarnOut("WARNING: Dump file has been truncated. "
  3284. "Data may be missing.\n");
  3285. WarnOut("************************************************************\n\n");
  3286. }
  3287. return KernelFullSumDumpTargetInfo::Initialize();
  3288. }
  3289. HRESULT
  3290. KernelFull64DumpTargetInfo::GetDescription(PSTR Buffer, ULONG BufferLen,
  3291. PULONG DescLen)
  3292. {
  3293. HRESULT Status;
  3294. Status = AppendToStringBuffer(S_OK, "64-bit Full kernel dump: ", TRUE,
  3295. &Buffer, &BufferLen, DescLen);
  3296. return AppendToStringBuffer(Status,
  3297. m_InfoFiles[DUMP_INFO_DUMP].m_FileNameA,
  3298. FALSE, &Buffer, &BufferLen, DescLen);
  3299. }
  3300. HRESULT
  3301. KernelFull64DumpTargetInfo::ReadBugCheckData(PULONG Code, ULONG64 Args[4])
  3302. {
  3303. *Code = m_Dump->Header.BugCheckCode;
  3304. Args[0] = m_Dump->Header.BugCheckParameter1;
  3305. Args[1] = m_Dump->Header.BugCheckParameter2;
  3306. Args[2] = m_Dump->Header.BugCheckParameter3;
  3307. Args[3] = m_Dump->Header.BugCheckParameter4;
  3308. return S_OK;
  3309. }
  3310. HRESULT
  3311. KernelFull64DumpTargetInfo::IdentifyDump(PULONG64 BaseMapSize)
  3312. {
  3313. HRESULT Status = E_NOINTERFACE;
  3314. PMEMORY_DUMP64 Dump = (PMEMORY_DUMP64)m_DumpBase;
  3315. __try
  3316. {
  3317. if (Dump->Header.Signature != DUMP_SIGNATURE64 ||
  3318. Dump->Header.ValidDump != DUMP_VALID_DUMP64 ||
  3319. (Dump->Header.DumpType != DUMP_SIGNATURE32 &&
  3320. Dump->Header.DumpType != DUMP_TYPE_FULL))
  3321. {
  3322. __leave;
  3323. }
  3324. // Summary and triage dumps must be checked before this
  3325. // so there's nothing left to check.
  3326. m_Dump = Dump;
  3327. Status = S_OK;
  3328. }
  3329. __except(EXCEPTION_EXECUTE_HANDLER)
  3330. {
  3331. Status = DumpIdentifyStatus(GetExceptionCode());
  3332. }
  3333. return Status;
  3334. }
  3335. ULONG64
  3336. KernelFull64DumpTargetInfo::PhysicalToOffset(ULONG64 Phys, BOOL Verbose,
  3337. PULONG Avail)
  3338. {
  3339. ULONG PageIndex =
  3340. (ULONG)Phys & (m_Machine->m_PageSize - 1);
  3341. *Avail = m_Machine->m_PageSize - PageIndex;
  3342. ULONG64 Offset = 0;
  3343. __try
  3344. {
  3345. PPHYSICAL_MEMORY_DESCRIPTOR64 PhysDesc =
  3346. &m_Dump->Header.PhysicalMemoryBlock;
  3347. ULONG64 Page = Phys >> m_Machine->m_PageShift;
  3348. ULONG j = 0;
  3349. while (j < PhysDesc->NumberOfRuns)
  3350. {
  3351. if ((Page >= PhysDesc->Run[j].BasePage) &&
  3352. (Page < (PhysDesc->Run[j].BasePage +
  3353. PhysDesc->Run[j].PageCount)))
  3354. {
  3355. Offset += Page - PhysDesc->Run[j].BasePage;
  3356. Offset = Offset * m_Machine->m_PageSize +
  3357. sizeof(m_Dump->Header) + PageIndex;
  3358. break;
  3359. }
  3360. Offset += PhysDesc->Run[j].PageCount;
  3361. j += 1;
  3362. }
  3363. if (j >= PhysDesc->NumberOfRuns)
  3364. {
  3365. KdOut("Physical Memory Address %s is "
  3366. "greater than MaxPhysicalAddress\n",
  3367. FormatDisp64(Phys));
  3368. Offset = 0;
  3369. }
  3370. }
  3371. __except(MappingExceptionFilter(GetExceptionInformation()))
  3372. {
  3373. Offset = 0;
  3374. }
  3375. return Offset;
  3376. }
  3377. void
  3378. KernelFull64DumpTargetInfo::DumpDebug(void)
  3379. {
  3380. PPHYSICAL_MEMORY_DESCRIPTOR64 PhysDesc =
  3381. &m_Dump->Header.PhysicalMemoryBlock;
  3382. ULONG PageSize = m_Machine->m_PageSize;
  3383. dprintf("----- 64 bit Kernel Full Dump Analysis\n");
  3384. DumpHeader64(&m_Dump->Header);
  3385. dprintf("\nPhysical Memory Description:\n");
  3386. dprintf("Number of runs: %d\n", PhysDesc->NumberOfRuns);
  3387. dprintf(" FileOffset Start Address Length\n");
  3388. ULONG j = 0;
  3389. ULONG64 Offset = 1;
  3390. while (j < PhysDesc->NumberOfRuns)
  3391. {
  3392. dprintf(" %s %s %s\n",
  3393. FormatAddr64(Offset * PageSize),
  3394. FormatAddr64(PhysDesc->Run[j].BasePage * PageSize),
  3395. FormatAddr64(PhysDesc->Run[j].PageCount * PageSize));
  3396. Offset += PhysDesc->Run[j].PageCount;
  3397. j += 1;
  3398. }
  3399. j--;
  3400. dprintf("Last Page: %s %s\n",
  3401. FormatAddr64((Offset - 1) * PageSize),
  3402. FormatAddr64((PhysDesc->Run[j].BasePage +
  3403. PhysDesc->Run[j].PageCount - 1) *
  3404. PageSize));
  3405. KernelFullSumDumpTargetInfo::DumpDebug();
  3406. }
  3407. //----------------------------------------------------------------------------
  3408. //
  3409. // UserDumpTargetInfo.
  3410. //
  3411. //----------------------------------------------------------------------------
  3412. HRESULT
  3413. UserDumpTargetInfo::GetThreadInfoDataOffset(ThreadInfo* Thread,
  3414. ULONG64 ThreadHandle,
  3415. PULONG64 Offset)
  3416. {
  3417. if (Thread != NULL && Thread->m_DataOffset != 0)
  3418. {
  3419. *Offset = Thread->m_DataOffset;
  3420. return S_OK;
  3421. }
  3422. BOOL ContextThread = FALSE;
  3423. if (Thread != NULL)
  3424. {
  3425. ThreadHandle = Thread->m_Handle;
  3426. ContextThread = Thread == m_RegContextThread;
  3427. }
  3428. else if (ThreadHandle == 0)
  3429. {
  3430. return E_UNEXPECTED;
  3431. }
  3432. else
  3433. {
  3434. // Arbitrary thread handle provided.
  3435. ContextThread = FALSE;
  3436. }
  3437. HRESULT Status;
  3438. ULONG64 TebAddr;
  3439. ULONG Id, Suspend;
  3440. if ((Status = GetThreadInfo(VIRTUAL_THREAD_INDEX(ThreadHandle),
  3441. &Id, &Suspend, &TebAddr)) != S_OK)
  3442. {
  3443. ErrOut("User dump thread %u not available\n",
  3444. VIRTUAL_THREAD_INDEX(ThreadHandle));
  3445. return Status;
  3446. }
  3447. if (TebAddr == 0)
  3448. {
  3449. //
  3450. // NT4 dumps have a bug - they do not fill in the TEB value.
  3451. // luckily, for pretty much all user mode processes, the
  3452. // TEBs start two pages down from the highest user address.
  3453. // For example, on x86 we try 0x7FFDE000 (on 3GB systems 0xBFFDE000).
  3454. //
  3455. if (!m_Machine->m_Ptr64 &&
  3456. m_HighestMemoryRegion32 > 0x80000000)
  3457. {
  3458. TebAddr = 0xbffe0000;
  3459. }
  3460. else
  3461. {
  3462. TebAddr = 0x7ffe0000;
  3463. }
  3464. TebAddr -= 2 * m_Machine->m_PageSize;
  3465. //
  3466. // Try and validate that this is really a TEB.
  3467. // If it isn't search lower memory addresses for
  3468. // a while, but don't get hung up here.
  3469. //
  3470. ULONG64 TebCheck = TebAddr;
  3471. ULONG Attempts = 8;
  3472. BOOL IsATeb = FALSE;
  3473. while (Attempts > 0)
  3474. {
  3475. ULONG64 TebSelf;
  3476. // Check if this looks like a TEB. TEBs have a
  3477. // self pointer in the TIB that's useful for this.
  3478. if (ReadPointer(m_ProcessHead,
  3479. m_Machine,
  3480. TebCheck +
  3481. 6 * (m_Machine->m_Ptr64 ? 8 : 4),
  3482. &TebSelf) == S_OK &&
  3483. TebSelf == TebCheck)
  3484. {
  3485. // It looks like it's a TEB. Remember this address
  3486. // so that if all searching fails we'll at least
  3487. // return some TEB.
  3488. TebAddr = TebCheck;
  3489. IsATeb = TRUE;
  3490. // If the given thread is the current register context
  3491. // thread we can check and see if the current SP falls
  3492. // within the stack limits in the TEB.
  3493. if (ContextThread)
  3494. {
  3495. ULONG64 StackBase, StackLimit;
  3496. ADDR Sp;
  3497. m_Machine->GetSP(&Sp);
  3498. if (m_Machine->m_Ptr64)
  3499. {
  3500. StackBase = STACK_BASE_FROM_TEB64;
  3501. StackLimit = StackBase + 8;
  3502. }
  3503. else
  3504. {
  3505. StackBase = STACK_BASE_FROM_TEB32;
  3506. StackLimit = StackBase + 4;
  3507. }
  3508. if (ReadPointer(m_ProcessHead,
  3509. m_Machine,
  3510. TebCheck + StackBase,
  3511. &StackBase) == S_OK &&
  3512. ReadPointer(m_ProcessHead,
  3513. m_Machine,
  3514. TebCheck + StackLimit,
  3515. &StackLimit) == S_OK &&
  3516. Flat(Sp) >= StackLimit &&
  3517. Flat(Sp) <= StackBase)
  3518. {
  3519. // SP is within stack limits, everything
  3520. // looks good.
  3521. break;
  3522. }
  3523. }
  3524. else
  3525. {
  3526. // Can't validate SP so just go with it.
  3527. break;
  3528. }
  3529. // As long as we're looking through real TEBs
  3530. // we'll continue searching. Otherwise we
  3531. // wouldn't be able to locate TEBs in dumps that
  3532. // have a lot of threads.
  3533. Attempts++;
  3534. }
  3535. // The memory either wasn't a TEB or was the
  3536. // wrong TEB. Drop down a page and try again.
  3537. TebCheck -= m_Machine->m_PageSize;
  3538. Attempts--;
  3539. }
  3540. WarnOut("WARNING: Teb %u pointer is NULL - "
  3541. "defaulting to %s\n", VIRTUAL_THREAD_INDEX(ThreadHandle),
  3542. FormatAddr64(TebAddr));
  3543. if (!IsATeb)
  3544. {
  3545. WarnOut("WARNING: %s does not appear to be a TEB\n",
  3546. FormatAddr64(TebAddr));
  3547. }
  3548. else if (Attempts == 0)
  3549. {
  3550. WarnOut("WARNING: %s does not appear to be the right TEB\n",
  3551. FormatAddr64(TebAddr));
  3552. }
  3553. }
  3554. *Offset = TebAddr;
  3555. if (Thread != NULL)
  3556. {
  3557. Thread->m_DataOffset = TebAddr;
  3558. }
  3559. return S_OK;
  3560. }
  3561. HRESULT
  3562. UserDumpTargetInfo::GetProcessInfoDataOffset(ThreadInfo* Thread,
  3563. ULONG Processor,
  3564. ULONG64 ThreadData,
  3565. PULONG64 Offset)
  3566. {
  3567. if (Thread != NULL && Thread->m_Process->m_DataOffset != 0)
  3568. {
  3569. *Offset = Thread->m_Process->m_DataOffset;
  3570. return S_OK;
  3571. }
  3572. HRESULT Status;
  3573. if (Thread != NULL || ThreadData == 0)
  3574. {
  3575. if ((Status = GetThreadInfoDataOffset(Thread, 0,
  3576. &ThreadData)) != S_OK)
  3577. {
  3578. return Status;
  3579. }
  3580. }
  3581. ThreadData += m_Machine->m_Ptr64 ?
  3582. PEB_FROM_TEB64 : PEB_FROM_TEB32;
  3583. if ((Status = ReadPointer(m_ProcessHead,
  3584. m_Machine, ThreadData,
  3585. Offset)) != S_OK)
  3586. {
  3587. return Status;
  3588. }
  3589. if (Thread != NULL)
  3590. {
  3591. Thread->m_Process->m_DataOffset = *Offset;
  3592. }
  3593. return S_OK;
  3594. }
  3595. HRESULT
  3596. UserDumpTargetInfo::GetThreadInfoTeb(ThreadInfo* Thread,
  3597. ULONG Processor,
  3598. ULONG64 ThreadData,
  3599. PULONG64 Offset)
  3600. {
  3601. return GetThreadInfoDataOffset(Thread, ThreadData, Offset);
  3602. }
  3603. HRESULT
  3604. UserDumpTargetInfo::GetProcessInfoPeb(ThreadInfo* Thread,
  3605. ULONG Processor,
  3606. ULONG64 ThreadData,
  3607. PULONG64 Offset)
  3608. {
  3609. // Thread data is not useful.
  3610. return GetProcessInfoDataOffset(Thread, 0, 0, Offset);
  3611. }
  3612. HRESULT
  3613. UserDumpTargetInfo::GetSelDescriptor(ThreadInfo* Thread,
  3614. MachineInfo* Machine,
  3615. ULONG Selector,
  3616. PDESCRIPTOR64 Desc)
  3617. {
  3618. return EmulateNtSelDescriptor(Thread, Machine, Selector, Desc);
  3619. }
  3620. //----------------------------------------------------------------------------
  3621. //
  3622. // UserFullDumpTargetInfo.
  3623. //
  3624. //----------------------------------------------------------------------------
  3625. HRESULT
  3626. UserFullDumpTargetInfo::GetBuildAndPlatform(ULONG MachineType,
  3627. PULONG MajorVersion,
  3628. PULONG MinorVersion,
  3629. PULONG BuildNumber,
  3630. PULONG PlatformId)
  3631. {
  3632. //
  3633. // Allow a knowledgeable user to override the
  3634. // dump version in order to work around problems
  3635. // with userdump.exe always generating version 5
  3636. // dumps regardless of the actual OS version.
  3637. //
  3638. PSTR Override = getenv("DBGENG_FULL_DUMP_VERSION");
  3639. if (Override)
  3640. {
  3641. switch(sscanf(Override, "%d.%d:%d:%d",
  3642. MajorVersion, MinorVersion,
  3643. BuildNumber, PlatformId))
  3644. {
  3645. case 2:
  3646. case 3:
  3647. // Only major/minor given, so let the build
  3648. // and platform be guessed from them.
  3649. break;
  3650. case 4:
  3651. // Everything was given, we're done.
  3652. return S_OK;
  3653. default:
  3654. // Invalid format, this will produce an error below.
  3655. *MajorVersion = 0;
  3656. *MinorVersion = 0;
  3657. break;
  3658. }
  3659. }
  3660. //
  3661. // The only way to distinguish user dump
  3662. // platforms is guessing from the Major/MinorVersion
  3663. // and the extra QFE/Hotfix data.
  3664. //
  3665. // If this is for a processor that only CE supports
  3666. // we can immediately select CE.
  3667. if (MachineType == IMAGE_FILE_MACHINE_ARM)
  3668. {
  3669. *BuildNumber = 1;
  3670. *PlatformId = VER_PLATFORM_WIN32_CE;
  3671. goto CheckBuildNumber;
  3672. }
  3673. switch(*MajorVersion)
  3674. {
  3675. case 4:
  3676. switch(*MinorVersion & 0xffff)
  3677. {
  3678. case 0:
  3679. // This could be Win95 or NT4. We mostly
  3680. // deal with NT dumps so just assume NT.
  3681. *BuildNumber = 1381;
  3682. *PlatformId = VER_PLATFORM_WIN32_NT;
  3683. break;
  3684. case 3:
  3685. // Win95 OSR releases were 4.03. Treat them
  3686. // as Win95 for now.
  3687. *BuildNumber = 950;
  3688. *PlatformId = VER_PLATFORM_WIN32_WINDOWS;
  3689. break;
  3690. case 10:
  3691. // This could be Win98 or Win98SE. Go with Win98.
  3692. *BuildNumber = 1998;
  3693. *PlatformId = VER_PLATFORM_WIN32_WINDOWS;
  3694. break;
  3695. case 90:
  3696. // Win98 ME.
  3697. *BuildNumber = 3000;
  3698. *PlatformId = VER_PLATFORM_WIN32_WINDOWS;
  3699. break;
  3700. }
  3701. break;
  3702. case 5:
  3703. *PlatformId = VER_PLATFORM_WIN32_NT;
  3704. switch(*MinorVersion & 0xffff)
  3705. {
  3706. case 0:
  3707. *BuildNumber = 2195;
  3708. break;
  3709. case 1:
  3710. // Just has to be greater than 2195 to
  3711. // distinguish it from Win2K RTM.
  3712. *BuildNumber = 2196;
  3713. break;
  3714. }
  3715. break;
  3716. case 6:
  3717. // Has to be some form of NT. Longhorn is the only
  3718. // one we recognize.
  3719. *PlatformId = VER_PLATFORM_WIN32_NT;
  3720. // XXX drewb - Longhorn hasn't split their build numbers
  3721. // off yet so they're the same as .NET. Just pick
  3722. // a junk build.
  3723. *BuildNumber = 9999;
  3724. break;
  3725. case 0:
  3726. // AV: Busted BETA of the debugger generates a broken dump file
  3727. // Guess it's 2195.
  3728. WarnOut("Dump file was generated with NULL version - "
  3729. "guessing Windows 2000, ");
  3730. *PlatformId = VER_PLATFORM_WIN32_NT;
  3731. *BuildNumber = 2195;
  3732. break;
  3733. default:
  3734. // Other platforms are not supported.
  3735. ErrOut("Dump file was generated by an unsupported system, ");
  3736. ErrOut("version %x.%x\n", *MajorVersion, *MinorVersion & 0xffff);
  3737. return E_INVALIDARG;
  3738. }
  3739. CheckBuildNumber:
  3740. // Newer full user dumps have the actual build number in
  3741. // the high word, so use it if it's present.
  3742. if (*MinorVersion >> 16)
  3743. {
  3744. *BuildNumber = *MinorVersion >> 16;
  3745. }
  3746. return S_OK;
  3747. }
  3748. HRESULT
  3749. UserFull32DumpTargetInfo::Initialize(void)
  3750. {
  3751. // Pick up any potentially modified base mapping pointer.
  3752. m_Header = (PUSERMODE_CRASHDUMP_HEADER32)m_DumpBase;
  3753. dprintf("User Dump File: Only application data is available\n\n");
  3754. ULONG MajorVersion, MinorVersion;
  3755. ULONG BuildNumber;
  3756. ULONG PlatformId;
  3757. HRESULT Status;
  3758. MajorVersion = m_Header->MajorVersion;
  3759. MinorVersion = m_Header->MinorVersion;
  3760. if ((Status = GetBuildAndPlatform(m_Header->MachineImageType,
  3761. &MajorVersion, &MinorVersion,
  3762. &BuildNumber, &PlatformId)) != S_OK)
  3763. {
  3764. return Status;
  3765. }
  3766. if ((Status = InitSystemInfo(BuildNumber, 0,
  3767. m_Header->MachineImageType, PlatformId,
  3768. MajorVersion,
  3769. MinorVersion & 0xffff)) != S_OK)
  3770. {
  3771. return Status;
  3772. }
  3773. // Dump does not contain this information.
  3774. m_NumProcessors = 1;
  3775. DEBUG_EVENT32 Event;
  3776. if (m_InfoFiles[DUMP_INFO_DUMP].
  3777. ReadFileOffset(m_Header->DebugEventOffset, &Event,
  3778. sizeof(Event)) != sizeof(Event))
  3779. {
  3780. ErrOut("Unable to read debug event at offset %x\n",
  3781. m_Header->DebugEventOffset);
  3782. return E_FAIL;
  3783. }
  3784. m_EventProcessId = Event.dwProcessId;
  3785. m_EventProcessSymHandle =
  3786. GloballyUniqueProcessHandle(this, Event.dwProcessId);
  3787. m_EventThreadId = Event.dwThreadId;
  3788. if (Event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT)
  3789. {
  3790. ExceptionRecord32To64(&Event.u.Exception.ExceptionRecord,
  3791. &m_ExceptionRecord);
  3792. m_ExceptionFirstChance = Event.u.Exception.dwFirstChance;
  3793. }
  3794. else
  3795. {
  3796. // Fake an exception.
  3797. ZeroMemory(&m_ExceptionRecord, sizeof(m_ExceptionRecord));
  3798. m_ExceptionRecord.ExceptionCode = STATUS_BREAKPOINT;
  3799. m_ExceptionFirstChance = FALSE;
  3800. }
  3801. m_ThreadCount = m_Header->ThreadCount;
  3802. m_Memory = (PMEMORY_BASIC_INFORMATION32)
  3803. IndexByByte(m_Header, m_Header->MemoryRegionOffset);
  3804. //
  3805. // Determine the highest memory region address.
  3806. // This helps differentiate 2GB systems from 3GB systems.
  3807. //
  3808. ULONG i;
  3809. PMEMORY_BASIC_INFORMATION32 Mem;
  3810. ULONG TotalMemory;
  3811. Mem = m_Memory;
  3812. m_HighestMemoryRegion32 = 0;
  3813. for (i = 0; i < m_Header->MemoryRegionCount; i++)
  3814. {
  3815. if (Mem->BaseAddress > m_HighestMemoryRegion32)
  3816. {
  3817. m_HighestMemoryRegion32 = Mem->BaseAddress;
  3818. }
  3819. Mem++;
  3820. }
  3821. VerbOut(" Memory regions: %d\n",
  3822. m_Header->MemoryRegionCount);
  3823. TotalMemory = 0;
  3824. Mem = m_Memory;
  3825. for (i = 0; i < m_Header->MemoryRegionCount; i++)
  3826. {
  3827. VerbOut(" %5d: %08X - %08X off %08X, prot %08X, type %08X\n",
  3828. i, Mem->BaseAddress,
  3829. Mem->BaseAddress + Mem->RegionSize - 1,
  3830. TotalMemory + m_Header->DataOffset,
  3831. Mem->Protect, Mem->Type);
  3832. if ((Mem->Protect & PAGE_GUARD) ||
  3833. (Mem->Protect & PAGE_NOACCESS) ||
  3834. (Mem->State & MEM_FREE) ||
  3835. (Mem->State & MEM_RESERVE))
  3836. {
  3837. VerbOut(" Region has data-less pages\n");
  3838. }
  3839. TotalMemory += Mem->RegionSize;
  3840. Mem++;
  3841. }
  3842. VerbOut(" Total memory region size %X, file %08X - %08X\n",
  3843. TotalMemory, m_Header->DataOffset,
  3844. m_Header->DataOffset + TotalMemory - 1);
  3845. //
  3846. // Determine whether guard pages are present in
  3847. // the dump content or not.
  3848. //
  3849. // First try with IgnoreGuardPages == TRUE.
  3850. //
  3851. m_IgnoreGuardPages = TRUE;
  3852. if (!VerifyModules())
  3853. {
  3854. //
  3855. // That didn't work, try IgnoreGuardPages == FALSE.
  3856. //
  3857. m_IgnoreGuardPages = FALSE;
  3858. if (!VerifyModules())
  3859. {
  3860. ErrOut("Module list is corrupt\n");
  3861. return HR_DATA_CORRUPT;
  3862. }
  3863. }
  3864. return UserDumpTargetInfo::Initialize();
  3865. }
  3866. HRESULT
  3867. UserFull32DumpTargetInfo::GetDescription(PSTR Buffer, ULONG BufferLen,
  3868. PULONG DescLen)
  3869. {
  3870. HRESULT Status;
  3871. Status = AppendToStringBuffer(S_OK, "32-bit Full user dump: ", TRUE,
  3872. &Buffer, &BufferLen, DescLen);
  3873. return AppendToStringBuffer(Status,
  3874. m_InfoFiles[DUMP_INFO_DUMP].m_FileNameA,
  3875. FALSE, &Buffer, &BufferLen, DescLen);
  3876. }
  3877. HRESULT
  3878. UserFull32DumpTargetInfo::GetTargetContext(
  3879. ULONG64 Thread,
  3880. PVOID Context
  3881. )
  3882. {
  3883. if (VIRTUAL_THREAD_INDEX(Thread) >= m_Header->ThreadCount)
  3884. {
  3885. return E_INVALIDARG;
  3886. }
  3887. if (m_InfoFiles[DUMP_INFO_DUMP].
  3888. ReadFileOffset(m_Header->ThreadOffset +
  3889. VIRTUAL_THREAD_INDEX(Thread) *
  3890. m_TypeInfo.SizeTargetContext,
  3891. Context,
  3892. m_TypeInfo.SizeTargetContext) ==
  3893. m_TypeInfo.SizeTargetContext)
  3894. {
  3895. return S_OK;
  3896. }
  3897. else
  3898. {
  3899. return E_FAIL;
  3900. }
  3901. }
  3902. ModuleInfo*
  3903. UserFull32DumpTargetInfo::GetModuleInfo(BOOL UserMode)
  3904. {
  3905. DBG_ASSERT(UserMode);
  3906. // If this dump came from an NT system we'll just
  3907. // use the system's loaded module list. Otherwise
  3908. // we'll use the dump's module list.
  3909. return m_PlatformId == VER_PLATFORM_WIN32_NT ?
  3910. (ModuleInfo*)&g_NtTargetUserModuleIterator :
  3911. (ModuleInfo*)&g_UserFull32ModuleIterator;
  3912. }
  3913. HRESULT
  3914. UserFull32DumpTargetInfo::QueryMemoryRegion(ProcessInfo* Process,
  3915. PULONG64 Handle,
  3916. BOOL HandleIsOffset,
  3917. PMEMORY_BASIC_INFORMATION64 Info)
  3918. {
  3919. ULONG Index;
  3920. if (HandleIsOffset)
  3921. {
  3922. ULONG BestIndex;
  3923. ULONG BestDiff;
  3924. //
  3925. // Emulate VirtualQueryEx and return the closest higher
  3926. // region if a containing region isn't found.
  3927. //
  3928. BestIndex = 0xffffffff;
  3929. BestDiff = 0xffffffff;
  3930. for (Index = 0; Index < m_Header->MemoryRegionCount; Index++)
  3931. {
  3932. if ((ULONG)*Handle >= m_Memory[Index].BaseAddress)
  3933. {
  3934. if ((ULONG)*Handle < m_Memory[Index].BaseAddress +
  3935. m_Memory[Index].RegionSize)
  3936. {
  3937. // Found a containing region, we're done.
  3938. BestIndex = Index;
  3939. break;
  3940. }
  3941. // Not containing and lower in memory, ignore.
  3942. }
  3943. else
  3944. {
  3945. // Check and see if this is a closer
  3946. // region than what we've seen already.
  3947. ULONG Diff = m_Memory[Index].BaseAddress -
  3948. (ULONG)*Handle;
  3949. if (Diff <= BestDiff)
  3950. {
  3951. BestIndex = Index;
  3952. BestDiff = Diff;
  3953. }
  3954. }
  3955. }
  3956. if (BestIndex >= m_Header->MemoryRegionCount)
  3957. {
  3958. return E_NOINTERFACE;
  3959. }
  3960. Index = BestIndex;
  3961. }
  3962. else
  3963. {
  3964. Index = (ULONG)*Handle;
  3965. for (;;)
  3966. {
  3967. if (Index >= m_Header->MemoryRegionCount)
  3968. {
  3969. return HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES);
  3970. }
  3971. if (!(m_Memory[Index].Protect & PAGE_GUARD))
  3972. {
  3973. break;
  3974. }
  3975. Index++;
  3976. }
  3977. }
  3978. MemoryBasicInformation32To64(&m_Memory[Index], Info);
  3979. *Handle = ++Index;
  3980. return S_OK;
  3981. }
  3982. HRESULT
  3983. UserFull32DumpTargetInfo::IdentifyDump(PULONG64 BaseMapSize)
  3984. {
  3985. HRESULT Status = E_NOINTERFACE;
  3986. PUSERMODE_CRASHDUMP_HEADER32 Header =
  3987. (PUSERMODE_CRASHDUMP_HEADER32)m_DumpBase;
  3988. __try
  3989. {
  3990. if (Header->Signature != USERMODE_CRASHDUMP_SIGNATURE ||
  3991. Header->ValidDump != USERMODE_CRASHDUMP_VALID_DUMP32)
  3992. {
  3993. __leave;
  3994. }
  3995. //
  3996. // Check for the presence of some basic things.
  3997. //
  3998. if (Header->ThreadCount == 0 ||
  3999. Header->ModuleCount == 0 ||
  4000. Header->MemoryRegionCount == 0)
  4001. {
  4002. ErrOut("Thread, module or memory region count is zero.\n"
  4003. "The dump file is probably corrupt.\n");
  4004. Status = HR_DATA_CORRUPT;
  4005. __leave;
  4006. }
  4007. if (Header->ThreadOffset == 0 ||
  4008. Header->ModuleOffset == 0 ||
  4009. Header->DataOffset == 0 ||
  4010. Header->MemoryRegionOffset == 0 ||
  4011. Header->DebugEventOffset == 0 ||
  4012. Header->ThreadStateOffset == 0)
  4013. {
  4014. ErrOut("A dump header data offset is zero.\n"
  4015. "The dump file is probably corrupt.\n");
  4016. Status = HR_DATA_CORRUPT;
  4017. __leave;
  4018. }
  4019. // We don't want to have to call ReadFileOffset
  4020. // every time we check memory ranges so just require
  4021. // that the memory descriptors fit in the base view.
  4022. *BaseMapSize = Header->MemoryRegionOffset +
  4023. Header->MemoryRegionCount * sizeof(*m_Memory);
  4024. m_Header = Header;
  4025. Status = S_OK;
  4026. }
  4027. __except(EXCEPTION_EXECUTE_HANDLER)
  4028. {
  4029. Status = DumpIdentifyStatus(GetExceptionCode());
  4030. }
  4031. return Status;
  4032. }
  4033. void
  4034. UserFull32DumpTargetInfo::DumpDebug(void)
  4035. {
  4036. dprintf("----- 32 bit User Full Dump Analysis\n\n");
  4037. dprintf("MajorVersion: %d\n", m_Header->MajorVersion);
  4038. dprintf("MinorVersion: %d (Build %d)\n",
  4039. m_Header->MinorVersion & 0xffff,
  4040. m_Header->MinorVersion >> 16);
  4041. dprintf("MachineImageType: %08lx\n", m_Header->MachineImageType);
  4042. dprintf("ThreadCount: %08lx\n", m_Header->ThreadCount);
  4043. dprintf("ThreadOffset: %08lx\n", m_Header->ThreadOffset);
  4044. dprintf("ThreadStateOffset: %08lx\n", m_Header->ThreadStateOffset);
  4045. dprintf("ModuleCount: %08lx\n", m_Header->ModuleCount);
  4046. dprintf("ModuleOffset: %08lx\n", m_Header->ModuleOffset);
  4047. dprintf("DebugEventOffset: %08lx\n", m_Header->DebugEventOffset);
  4048. dprintf("VersionInfoOffset: %08lx\n", m_Header->VersionInfoOffset);
  4049. dprintf("\nVirtual Memory Description:\n");
  4050. dprintf("MemoryRegionOffset: %08lx\n", m_Header->MemoryRegionOffset);
  4051. dprintf("Number of regions: %d\n", m_Header->MemoryRegionCount);
  4052. dprintf(" FileOffset Start Address Length\n");
  4053. ULONG j = 0;
  4054. ULONG64 Offset = m_Header->DataOffset;
  4055. BOOL Skip;
  4056. while (j < m_Header->MemoryRegionCount)
  4057. {
  4058. Skip = FALSE;
  4059. dprintf(" %12I64lx %08lx %08lx",
  4060. Offset,
  4061. m_Memory[j].BaseAddress,
  4062. m_Memory[j].RegionSize);
  4063. if (m_Memory[j].Protect & PAGE_GUARD)
  4064. {
  4065. dprintf(" Guard Page");
  4066. if (m_IgnoreGuardPages)
  4067. {
  4068. dprintf(" - Ignored");
  4069. Skip = TRUE;
  4070. }
  4071. }
  4072. if (!Skip)
  4073. {
  4074. Offset += m_Memory[j].RegionSize;
  4075. }
  4076. dprintf("\n");
  4077. j += 1;
  4078. }
  4079. dprintf("Total memory: %12I64x\n", Offset - m_Header->DataOffset);
  4080. }
  4081. ULONG64
  4082. UserFull32DumpTargetInfo::VirtualToOffset(ULONG64 Virt,
  4083. PULONG File, PULONG Avail)
  4084. {
  4085. ULONG i;
  4086. ULONG Offset = 0;
  4087. ULONG64 RetOffset = 0;
  4088. *File = DUMP_INFO_DUMP;
  4089. // Ignore the upper 32 bits to avoid getting
  4090. // confused by sign extensions in pointer handling
  4091. Virt &= 0xffffffff;
  4092. __try
  4093. {
  4094. for (i = 0; i < m_Header->MemoryRegionCount; i++)
  4095. {
  4096. if (m_IgnoreGuardPages)
  4097. {
  4098. //
  4099. // Guard pages get reported, but they are not written
  4100. // out to the file
  4101. //
  4102. if (m_Memory[i].Protect & PAGE_GUARD)
  4103. {
  4104. continue;
  4105. }
  4106. }
  4107. if (Virt >= m_Memory[i].BaseAddress &&
  4108. Virt < m_Memory[i].BaseAddress + m_Memory[i].RegionSize)
  4109. {
  4110. ULONG Frag = (ULONG)Virt - m_Memory[i].BaseAddress;
  4111. *Avail = m_Memory[i].RegionSize - Frag;
  4112. if (Virt == (g_DebugDump_VirtualAddress & 0xffffffff))
  4113. {
  4114. g_NtDllCalls.DbgPrint("%X at offset %X\n",
  4115. (ULONG)Virt,
  4116. m_Header->DataOffset +
  4117. Offset + Frag);
  4118. }
  4119. RetOffset = m_Header->DataOffset + Offset + Frag;
  4120. break;
  4121. }
  4122. Offset += m_Memory[i].RegionSize;
  4123. }
  4124. }
  4125. __except(MappingExceptionFilter(GetExceptionInformation()))
  4126. {
  4127. RetOffset = 0;
  4128. }
  4129. return RetOffset;
  4130. }
  4131. HRESULT
  4132. UserFull32DumpTargetInfo::GetThreadInfo(ULONG Index,
  4133. PULONG Id, PULONG Suspend,
  4134. PULONG64 Teb)
  4135. {
  4136. if (Index >= m_ThreadCount)
  4137. {
  4138. return E_INVALIDARG;
  4139. }
  4140. CRASH_THREAD32 Thread;
  4141. if (m_InfoFiles[DUMP_INFO_DUMP].
  4142. ReadFileOffset(m_Header->ThreadStateOffset +
  4143. Index * sizeof(Thread),
  4144. &Thread, sizeof(Thread)) != sizeof(Thread))
  4145. {
  4146. return E_FAIL;
  4147. }
  4148. *Id = Thread.ThreadId;
  4149. *Suspend = Thread.SuspendCount;
  4150. *Teb = EXTEND64(Thread.Teb);
  4151. return S_OK;
  4152. }
  4153. #define DBG_VERIFY_MOD 0
  4154. BOOL
  4155. UserFull32DumpTargetInfo::VerifyModules(void)
  4156. {
  4157. CRASH_MODULE32 CrashModule;
  4158. ULONG i;
  4159. IMAGE_DOS_HEADER DosHeader;
  4160. ULONG Read;
  4161. BOOL Succ = TRUE;
  4162. ULONG Offset;
  4163. PSTR Env;
  4164. Env = getenv("DBGENG_VERIFY_MODULES");
  4165. if (Env != NULL)
  4166. {
  4167. return atoi(Env) == m_IgnoreGuardPages;
  4168. }
  4169. Offset = m_Header->ModuleOffset;
  4170. #if DBG_VERIFY_MOD
  4171. g_NtDllCalls.DbgPrint("Verify %d modules at offset %X\n",
  4172. m_Header->ModuleCount, Offset);
  4173. #endif
  4174. for (i = 0; i < m_Header->ModuleCount; i++)
  4175. {
  4176. if (m_InfoFiles[DUMP_INFO_DUMP].
  4177. ReadFileOffset(Offset, &CrashModule, sizeof(CrashModule)) !=
  4178. sizeof(CrashModule))
  4179. {
  4180. return FALSE;
  4181. }
  4182. #if DBG_VERIFY_MOD
  4183. g_NtDllCalls.DbgPrint("Mod %d of %d offs %X, base %s, ",
  4184. i, m_Header->ModuleCount, Offset,
  4185. FormatAddr64(CrashModule.BaseOfImage));
  4186. if (ReadVirtual(m_ProcessHead, CrashModule.BaseOfImage, &DosHeader,
  4187. sizeof(DosHeader), &Read) != S_OK ||
  4188. Read != sizeof(DosHeader))
  4189. {
  4190. g_NtDllCalls.DbgPrint("unable to read header\n");
  4191. }
  4192. else
  4193. {
  4194. g_NtDllCalls.DbgPrint("magic %04X\n", DosHeader.e_magic);
  4195. }
  4196. #endif
  4197. //
  4198. // It is not strictly a requirement that every image
  4199. // begin with an MZ header, though all of our tools
  4200. // today produce images like this. Check for it
  4201. // as a sanity check since it's so common nowadays.
  4202. //
  4203. if (ReadVirtual(NULL, CrashModule.BaseOfImage, &DosHeader,
  4204. sizeof(DosHeader), &Read) != S_OK ||
  4205. Read != sizeof(DosHeader) ||
  4206. DosHeader.e_magic != IMAGE_DOS_SIGNATURE)
  4207. {
  4208. Succ = FALSE;
  4209. break;
  4210. }
  4211. Offset += sizeof(CrashModule) + CrashModule.ImageNameLength;
  4212. }
  4213. #if DBG_VERIFY_MOD
  4214. g_NtDllCalls.DbgPrint("VerifyModules returning %d, %d of %d mods\n",
  4215. Succ, i, m_Header->ModuleCount);
  4216. #endif
  4217. return Succ;
  4218. }
  4219. HRESULT
  4220. UserFull64DumpTargetInfo::Initialize(void)
  4221. {
  4222. // Pick up any potentially modified base mapping pointer.
  4223. m_Header = (PUSERMODE_CRASHDUMP_HEADER64)m_DumpBase;
  4224. dprintf("User Dump File: Only application data is available\n\n");
  4225. ULONG MajorVersion, MinorVersion;
  4226. ULONG BuildNumber;
  4227. ULONG PlatformId;
  4228. HRESULT Status;
  4229. MajorVersion = m_Header->MajorVersion;
  4230. MinorVersion = m_Header->MinorVersion;
  4231. if ((Status = GetBuildAndPlatform(m_Header->MachineImageType,
  4232. &MajorVersion, &MinorVersion,
  4233. &BuildNumber, &PlatformId)) != S_OK)
  4234. {
  4235. return Status;
  4236. }
  4237. if ((Status = InitSystemInfo(BuildNumber, 0,
  4238. m_Header->MachineImageType, PlatformId,
  4239. MajorVersion,
  4240. MinorVersion & 0xffff)) != S_OK)
  4241. {
  4242. return Status;
  4243. }
  4244. // Dump does not contain this information.
  4245. m_NumProcessors = 1;
  4246. DEBUG_EVENT64 Event;
  4247. if (m_InfoFiles[DUMP_INFO_DUMP].
  4248. ReadFileOffset(m_Header->DebugEventOffset, &Event,
  4249. sizeof(Event)) != sizeof(Event))
  4250. {
  4251. ErrOut("Unable to read debug event at offset %I64x\n",
  4252. m_Header->DebugEventOffset);
  4253. return E_FAIL;
  4254. }
  4255. m_EventProcessId = Event.dwProcessId;
  4256. m_EventProcessSymHandle =
  4257. GloballyUniqueProcessHandle(this, Event.dwProcessId);
  4258. m_EventThreadId = Event.dwThreadId;
  4259. if (Event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT)
  4260. {
  4261. m_ExceptionRecord = Event.u.Exception.ExceptionRecord;
  4262. m_ExceptionFirstChance = Event.u.Exception.dwFirstChance;
  4263. }
  4264. else
  4265. {
  4266. // Fake an exception.
  4267. ZeroMemory(&m_ExceptionRecord, sizeof(m_ExceptionRecord));
  4268. m_ExceptionRecord.ExceptionCode = STATUS_BREAKPOINT;
  4269. m_ExceptionFirstChance = FALSE;
  4270. }
  4271. m_ThreadCount = m_Header->ThreadCount;
  4272. m_Memory = (PMEMORY_BASIC_INFORMATION64)
  4273. IndexByByte(m_Header, m_Header->MemoryRegionOffset);
  4274. ULONG64 TotalMemory;
  4275. ULONG i;
  4276. VerbOut(" Memory regions: %d\n",
  4277. m_Header->MemoryRegionCount);
  4278. TotalMemory = 0;
  4279. PMEMORY_BASIC_INFORMATION64 Mem = m_Memory;
  4280. for (i = 0; i < m_Header->MemoryRegionCount; i++)
  4281. {
  4282. VerbOut(" %5d: %s - %s, prot %08X, type %08X\n",
  4283. i, FormatAddr64(Mem->BaseAddress),
  4284. FormatAddr64(Mem->BaseAddress + Mem->RegionSize - 1),
  4285. Mem->Protect, Mem->Type);
  4286. if ((Mem->Protect & PAGE_GUARD) ||
  4287. (Mem->Protect & PAGE_NOACCESS) ||
  4288. (Mem->State & MEM_FREE) ||
  4289. (Mem->State & MEM_RESERVE))
  4290. {
  4291. VerbOut(" Region has data-less pages\n");
  4292. }
  4293. TotalMemory += Mem->RegionSize;
  4294. Mem++;
  4295. }
  4296. VerbOut(" Total memory region size %s\n",
  4297. FormatAddr64(TotalMemory));
  4298. return UserDumpTargetInfo::Initialize();
  4299. }
  4300. HRESULT
  4301. UserFull64DumpTargetInfo::GetDescription(PSTR Buffer, ULONG BufferLen,
  4302. PULONG DescLen)
  4303. {
  4304. HRESULT Status;
  4305. Status = AppendToStringBuffer(S_OK, "64-bit Full user dump: ", TRUE,
  4306. &Buffer, &BufferLen, DescLen);
  4307. return AppendToStringBuffer(Status,
  4308. m_InfoFiles[DUMP_INFO_DUMP].m_FileNameA,
  4309. FALSE, &Buffer, &BufferLen, DescLen);
  4310. }
  4311. HRESULT
  4312. UserFull64DumpTargetInfo::GetTargetContext(
  4313. ULONG64 Thread,
  4314. PVOID Context
  4315. )
  4316. {
  4317. if (VIRTUAL_THREAD_INDEX(Thread) >= m_Header->ThreadCount)
  4318. {
  4319. return E_INVALIDARG;
  4320. }
  4321. if (m_InfoFiles[DUMP_INFO_DUMP].
  4322. ReadFileOffset(m_Header->ThreadOffset +
  4323. VIRTUAL_THREAD_INDEX(Thread) *
  4324. m_TypeInfo.SizeTargetContext,
  4325. Context,
  4326. m_TypeInfo.SizeTargetContext) ==
  4327. m_TypeInfo.SizeTargetContext)
  4328. {
  4329. return S_OK;
  4330. }
  4331. else
  4332. {
  4333. return E_FAIL;
  4334. }
  4335. }
  4336. ModuleInfo*
  4337. UserFull64DumpTargetInfo::GetModuleInfo(BOOL UserMode)
  4338. {
  4339. DBG_ASSERT(UserMode);
  4340. // If this dump came from an NT system we'll just
  4341. // use the system's loaded module list. Otherwise
  4342. // we'll use the dump's module list.
  4343. return m_PlatformId == VER_PLATFORM_WIN32_NT ?
  4344. (ModuleInfo*)&g_NtTargetUserModuleIterator :
  4345. (ModuleInfo*)&g_UserFull64ModuleIterator;
  4346. }
  4347. HRESULT
  4348. UserFull64DumpTargetInfo::QueryMemoryRegion(ProcessInfo* Process,
  4349. PULONG64 Handle,
  4350. BOOL HandleIsOffset,
  4351. PMEMORY_BASIC_INFORMATION64 Info)
  4352. {
  4353. ULONG Index;
  4354. if (HandleIsOffset)
  4355. {
  4356. ULONG BestIndex;
  4357. ULONG64 BestDiff;
  4358. //
  4359. // Emulate VirtualQueryEx and return the closest higher
  4360. // region if a containing region isn't found.
  4361. //
  4362. BestIndex = 0xffffffff;
  4363. BestDiff = (ULONG64)-1;
  4364. for (Index = 0; Index < m_Header->MemoryRegionCount; Index++)
  4365. {
  4366. if (*Handle >= m_Memory[Index].BaseAddress)
  4367. {
  4368. if (*Handle < m_Memory[Index].BaseAddress +
  4369. m_Memory[Index].RegionSize)
  4370. {
  4371. // Found a containing region, we're done.
  4372. BestIndex = Index;
  4373. break;
  4374. }
  4375. // Not containing and lower in memory, ignore.
  4376. }
  4377. else
  4378. {
  4379. // Check and see if this is a closer
  4380. // region than what we've seen already.
  4381. ULONG64 Diff = m_Memory[Index].BaseAddress - *Handle;
  4382. if (Diff <= BestDiff)
  4383. {
  4384. BestIndex = Index;
  4385. BestDiff = Diff;
  4386. }
  4387. }
  4388. }
  4389. if (BestIndex >= m_Header->MemoryRegionCount)
  4390. {
  4391. return E_NOINTERFACE;
  4392. }
  4393. Index = BestIndex;
  4394. }
  4395. else
  4396. {
  4397. Index = (ULONG)*Handle;
  4398. if (Index >= m_Header->MemoryRegionCount)
  4399. {
  4400. return HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES);
  4401. }
  4402. // 64-bit user dump support came into being after
  4403. // guard pages were suppressed so they never contain them.
  4404. }
  4405. *Info = m_Memory[Index];
  4406. *Handle = ++Index;
  4407. return S_OK;
  4408. }
  4409. HRESULT
  4410. UserFull64DumpTargetInfo::IdentifyDump(PULONG64 BaseMapSize)
  4411. {
  4412. HRESULT Status = E_NOINTERFACE;
  4413. PUSERMODE_CRASHDUMP_HEADER64 Header =
  4414. (PUSERMODE_CRASHDUMP_HEADER64)m_DumpBase;
  4415. __try
  4416. {
  4417. if (Header->Signature != USERMODE_CRASHDUMP_SIGNATURE ||
  4418. Header->ValidDump != USERMODE_CRASHDUMP_VALID_DUMP64)
  4419. {
  4420. __leave;
  4421. }
  4422. //
  4423. // Check for the presence of some basic things.
  4424. //
  4425. if (Header->ThreadCount == 0 ||
  4426. Header->ModuleCount == 0 ||
  4427. Header->MemoryRegionCount == 0)
  4428. {
  4429. ErrOut("Thread, module or memory region count is zero.\n"
  4430. "The dump file is probably corrupt.\n");
  4431. Status = HR_DATA_CORRUPT;
  4432. __leave;
  4433. }
  4434. if (Header->ThreadOffset == 0 ||
  4435. Header->ModuleOffset == 0 ||
  4436. Header->DataOffset == 0 ||
  4437. Header->MemoryRegionOffset == 0 ||
  4438. Header->DebugEventOffset == 0 ||
  4439. Header->ThreadStateOffset == 0)
  4440. {
  4441. ErrOut("A dump header data offset is zero.\n"
  4442. "The dump file is probably corrupt.\n");
  4443. Status = HR_DATA_CORRUPT;
  4444. __leave;
  4445. }
  4446. // We don't want to have to call ReadFileOffset
  4447. // every time we check memory ranges so just require
  4448. // that the memory descriptors fit in the base view.
  4449. *BaseMapSize = Header->MemoryRegionOffset +
  4450. Header->MemoryRegionCount * sizeof(*m_Memory);
  4451. m_Header = Header;
  4452. Status = S_OK;
  4453. }
  4454. __except(EXCEPTION_EXECUTE_HANDLER)
  4455. {
  4456. Status = DumpIdentifyStatus(GetExceptionCode());
  4457. }
  4458. return Status;
  4459. }
  4460. void
  4461. UserFull64DumpTargetInfo::DumpDebug(void)
  4462. {
  4463. dprintf("----- 64 bit User Full Dump Analysis\n\n");
  4464. dprintf("MajorVersion: %d\n", m_Header->MajorVersion);
  4465. dprintf("MinorVersion: %d (Build %d)\n",
  4466. m_Header->MinorVersion & 0xffff,
  4467. m_Header->MinorVersion >> 16);
  4468. dprintf("MachineImageType: %08lx\n", m_Header->MachineImageType);
  4469. dprintf("ThreadCount: %08lx\n", m_Header->ThreadCount);
  4470. dprintf("ThreadOffset: %12I64lx\n", m_Header->ThreadOffset);
  4471. dprintf("ThreadStateOffset: %12I64lx\n", m_Header->ThreadStateOffset);
  4472. dprintf("ModuleCount: %08lx\n", m_Header->ModuleCount);
  4473. dprintf("ModuleOffset: %12I64lx\n", m_Header->ModuleOffset);
  4474. dprintf("DebugEventOffset: %12I64lx\n", m_Header->DebugEventOffset);
  4475. dprintf("VersionInfoOffset: %12I64lx\n", m_Header->VersionInfoOffset);
  4476. dprintf("\nVirtual Memory Description:\n");
  4477. dprintf("MemoryRegionOffset: %12I64lx\n", m_Header->MemoryRegionOffset);
  4478. dprintf("Number of regions: %d\n", m_Header->MemoryRegionCount);
  4479. dprintf(" FileOffset Start Address"
  4480. " Length\n");
  4481. ULONG j = 0;
  4482. ULONG64 Offset = m_Header->DataOffset;
  4483. while (j < m_Header->MemoryRegionCount)
  4484. {
  4485. dprintf(" %12I64lx %s %12I64x",
  4486. Offset,
  4487. FormatAddr64(m_Memory[j].BaseAddress),
  4488. m_Memory[j].RegionSize);
  4489. Offset += m_Memory[j].RegionSize;
  4490. dprintf("\n");
  4491. j += 1;
  4492. }
  4493. dprintf("Total memory: %12I64x\n", Offset - m_Header->DataOffset);
  4494. }
  4495. ULONG64
  4496. UserFull64DumpTargetInfo::VirtualToOffset(ULONG64 Virt,
  4497. PULONG File, PULONG Avail)
  4498. {
  4499. ULONG i;
  4500. ULONG64 Offset = 0;
  4501. ULONG64 RetOffset = 0;
  4502. *File = DUMP_INFO_DUMP;
  4503. __try
  4504. {
  4505. for (i = 0; i < m_Header->MemoryRegionCount; i++)
  4506. {
  4507. //
  4508. // Guard pages get reported, but they are not written
  4509. // out to the file
  4510. //
  4511. if (m_Memory[i].Protect & PAGE_GUARD)
  4512. {
  4513. continue;
  4514. }
  4515. if (Virt >= m_Memory[i].BaseAddress &&
  4516. Virt < m_Memory[i].BaseAddress + m_Memory[i].RegionSize)
  4517. {
  4518. ULONG64 Frag = Virt - m_Memory[i].BaseAddress;
  4519. ULONG64 Avail64 = m_Memory[i].RegionSize - Frag;
  4520. // It's extremely unlikely that there'll be a single
  4521. // region greater than 4GB, but check anyway. No
  4522. // reads should ever require more than 4GB so just
  4523. // indicate that 4GB is available.
  4524. if (Avail64 > 0xffffffff)
  4525. {
  4526. *Avail = 0xffffffff;
  4527. }
  4528. else
  4529. {
  4530. *Avail = (ULONG)Avail64;
  4531. }
  4532. RetOffset = m_Header->DataOffset + Offset + Frag;
  4533. break;
  4534. }
  4535. Offset += m_Memory[i].RegionSize;
  4536. }
  4537. }
  4538. __except(MappingExceptionFilter(GetExceptionInformation()))
  4539. {
  4540. RetOffset = 0;
  4541. }
  4542. return RetOffset;
  4543. }
  4544. HRESULT
  4545. UserFull64DumpTargetInfo::GetThreadInfo(ULONG Index,
  4546. PULONG Id, PULONG Suspend,
  4547. PULONG64 Teb)
  4548. {
  4549. if (Index >= m_ThreadCount)
  4550. {
  4551. return E_INVALIDARG;
  4552. }
  4553. CRASH_THREAD64 Thread;
  4554. if (m_InfoFiles[DUMP_INFO_DUMP].
  4555. ReadFileOffset(m_Header->ThreadStateOffset +
  4556. Index * sizeof(Thread),
  4557. &Thread, sizeof(Thread)) != sizeof(Thread))
  4558. {
  4559. return E_FAIL;
  4560. }
  4561. *Id = Thread.ThreadId;
  4562. *Suspend = Thread.SuspendCount;
  4563. *Teb = Thread.Teb;
  4564. return S_OK;
  4565. }
  4566. //----------------------------------------------------------------------------
  4567. //
  4568. // UserMiniDumpTargetInfo.
  4569. //
  4570. //----------------------------------------------------------------------------
  4571. HRESULT
  4572. UserMiniDumpTargetInfo::Initialize(void)
  4573. {
  4574. // Pick up any potentially modified base mapping pointer.
  4575. m_Header = (PMINIDUMP_HEADER)m_DumpBase;
  4576. // Clear pointers that have already been set so
  4577. // that they get picked up again.
  4578. m_SysInfo = NULL;
  4579. if (m_Header->Flags & MiniDumpWithFullMemory)
  4580. {
  4581. m_FormatFlags |= DEBUG_FORMAT_USER_SMALL_FULL_MEMORY;
  4582. }
  4583. if (m_Header->Flags & MiniDumpWithHandleData)
  4584. {
  4585. m_FormatFlags |= DEBUG_FORMAT_USER_SMALL_HANDLE_DATA;
  4586. }
  4587. if (m_Header->Flags & MiniDumpWithUnloadedModules)
  4588. {
  4589. m_FormatFlags |= DEBUG_FORMAT_USER_SMALL_UNLOADED_MODULES;
  4590. }
  4591. if (m_Header->Flags & MiniDumpWithIndirectlyReferencedMemory)
  4592. {
  4593. m_FormatFlags |= DEBUG_FORMAT_USER_SMALL_INDIRECT_MEMORY;
  4594. }
  4595. if (m_Header->Flags & MiniDumpWithDataSegs)
  4596. {
  4597. m_FormatFlags |= DEBUG_FORMAT_USER_SMALL_DATA_SEGMENTS;
  4598. }
  4599. if (m_Header->Flags & MiniDumpFilterMemory)
  4600. {
  4601. m_FormatFlags |= DEBUG_FORMAT_USER_SMALL_FILTER_MEMORY;
  4602. }
  4603. if (m_Header->Flags & MiniDumpFilterModulePaths)
  4604. {
  4605. m_FormatFlags |= DEBUG_FORMAT_USER_SMALL_FILTER_PATHS;
  4606. }
  4607. if (m_Header->Flags & MiniDumpWithProcessThreadData)
  4608. {
  4609. m_FormatFlags |= DEBUG_FORMAT_USER_SMALL_PROCESS_THREAD_DATA;
  4610. }
  4611. if (m_Header->Flags & MiniDumpWithPrivateReadWriteMemory)
  4612. {
  4613. m_FormatFlags |= DEBUG_FORMAT_USER_SMALL_PRIVATE_READ_WRITE_MEMORY;
  4614. }
  4615. MINIDUMP_DIRECTORY UNALIGNED *Dir;
  4616. MINIDUMP_MISC_INFO UNALIGNED *MiscPtr = NULL;
  4617. ULONG i;
  4618. ULONG Size;
  4619. Dir = (MINIDUMP_DIRECTORY UNALIGNED *)
  4620. IndexRva(m_Header, m_Header->StreamDirectoryRva,
  4621. m_Header->NumberOfStreams * sizeof(*Dir),
  4622. "Directory");
  4623. if (Dir == NULL)
  4624. {
  4625. return HR_DATA_CORRUPT;
  4626. }
  4627. for (i = 0; i < m_Header->NumberOfStreams; i++)
  4628. {
  4629. switch(Dir->StreamType)
  4630. {
  4631. case ThreadListStream:
  4632. if (IndexDirectory(i, Dir, (PVOID*)&m_Threads) == NULL)
  4633. {
  4634. break;
  4635. }
  4636. m_ActualThreadCount =
  4637. ((MINIDUMP_THREAD_LIST UNALIGNED *)m_Threads)->NumberOfThreads;
  4638. m_ThreadStructSize = sizeof(MINIDUMP_THREAD);
  4639. if (Dir->Location.DataSize !=
  4640. sizeof(MINIDUMP_THREAD_LIST) +
  4641. sizeof(MINIDUMP_THREAD) * m_ActualThreadCount)
  4642. {
  4643. m_Threads = NULL;
  4644. m_ActualThreadCount = 0;
  4645. }
  4646. else
  4647. {
  4648. // Move past count to actual thread data.
  4649. m_Threads += sizeof(MINIDUMP_THREAD_LIST);
  4650. }
  4651. break;
  4652. case ThreadExListStream:
  4653. if (IndexDirectory(i, Dir, (PVOID*)&m_Threads) == NULL)
  4654. {
  4655. break;
  4656. }
  4657. m_ActualThreadCount =
  4658. ((MINIDUMP_THREAD_EX_LIST UNALIGNED *)m_Threads)->
  4659. NumberOfThreads;
  4660. m_ThreadStructSize = sizeof(MINIDUMP_THREAD_EX);
  4661. if (Dir->Location.DataSize !=
  4662. sizeof(MINIDUMP_THREAD_EX_LIST) +
  4663. sizeof(MINIDUMP_THREAD_EX) * m_ActualThreadCount)
  4664. {
  4665. m_Threads = NULL;
  4666. m_ActualThreadCount = 0;
  4667. }
  4668. else
  4669. {
  4670. // Move past count to actual thread data.
  4671. m_Threads += sizeof(MINIDUMP_THREAD_EX_LIST);
  4672. }
  4673. break;
  4674. case ModuleListStream:
  4675. if (IndexDirectory(i, Dir, (PVOID*)&m_Modules) == NULL)
  4676. {
  4677. break;
  4678. }
  4679. if (Dir->Location.DataSize !=
  4680. sizeof(MINIDUMP_MODULE_LIST) +
  4681. sizeof(MINIDUMP_MODULE) * m_Modules->NumberOfModules)
  4682. {
  4683. m_Modules = NULL;
  4684. }
  4685. break;
  4686. case UnloadedModuleListStream:
  4687. if (IndexDirectory(i, Dir, (PVOID*)&m_UnlModules) == NULL)
  4688. {
  4689. break;
  4690. }
  4691. if (Dir->Location.DataSize !=
  4692. m_UnlModules->SizeOfHeader +
  4693. m_UnlModules->SizeOfEntry * m_UnlModules->NumberOfEntries)
  4694. {
  4695. m_UnlModules = NULL;
  4696. }
  4697. break;
  4698. case MemoryListStream:
  4699. if (m_Header->Flags & MiniDumpWithFullMemory)
  4700. {
  4701. ErrOut("Full memory minidumps can't have MemoryListStreams\n");
  4702. return HR_DATA_CORRUPT;
  4703. }
  4704. if (IndexDirectory(i, Dir, (PVOID*)&m_Memory) == NULL)
  4705. {
  4706. break;
  4707. }
  4708. if (Dir->Location.DataSize !=
  4709. sizeof(MINIDUMP_MEMORY_LIST) +
  4710. sizeof(MINIDUMP_MEMORY_DESCRIPTOR) *
  4711. m_Memory->NumberOfMemoryRanges)
  4712. {
  4713. m_Memory = NULL;
  4714. }
  4715. break;
  4716. case Memory64ListStream:
  4717. if (!(m_Header->Flags & MiniDumpWithFullMemory))
  4718. {
  4719. ErrOut("Partial memory minidumps can't have "
  4720. "Memory64ListStreams\n");
  4721. return HR_DATA_CORRUPT;
  4722. }
  4723. if (IndexDirectory(i, Dir, (PVOID*)&m_Memory64) == NULL)
  4724. {
  4725. break;
  4726. }
  4727. if (Dir->Location.DataSize !=
  4728. sizeof(MINIDUMP_MEMORY64_LIST) +
  4729. sizeof(MINIDUMP_MEMORY_DESCRIPTOR64) *
  4730. m_Memory64->NumberOfMemoryRanges)
  4731. {
  4732. m_Memory64 = NULL;
  4733. }
  4734. break;
  4735. case ExceptionStream:
  4736. if (IndexDirectory(i, Dir, (PVOID*)&m_Exception) == NULL)
  4737. {
  4738. break;
  4739. }
  4740. if (Dir->Location.DataSize !=
  4741. sizeof(MINIDUMP_EXCEPTION_STREAM))
  4742. {
  4743. m_Exception = NULL;
  4744. }
  4745. break;
  4746. case SystemInfoStream:
  4747. if (IndexDirectory(i, Dir, (PVOID*)&m_SysInfo) == NULL)
  4748. {
  4749. break;
  4750. }
  4751. if (Dir->Location.DataSize != sizeof(MINIDUMP_SYSTEM_INFO))
  4752. {
  4753. m_SysInfo = NULL;
  4754. }
  4755. break;
  4756. case CommentStreamA:
  4757. PSTR CommentA;
  4758. CommentA = NULL;
  4759. if (IndexDirectory(i, Dir, (PVOID*)&CommentA) == NULL)
  4760. {
  4761. break;
  4762. }
  4763. dprintf("Comment: '%s'\n", CommentA);
  4764. break;
  4765. case CommentStreamW:
  4766. PWSTR CommentW;
  4767. CommentW = NULL;
  4768. if (IndexDirectory(i, Dir, (PVOID*)&CommentW) == NULL)
  4769. {
  4770. break;
  4771. }
  4772. dprintf("Comment: '%ls'\n", CommentW);
  4773. break;
  4774. case HandleDataStream:
  4775. if (IndexDirectory(i, Dir, (PVOID*)&m_Handles) == NULL)
  4776. {
  4777. break;
  4778. }
  4779. if (Dir->Location.DataSize !=
  4780. m_Handles->SizeOfHeader +
  4781. m_Handles->SizeOfDescriptor *
  4782. m_Handles->NumberOfDescriptors)
  4783. {
  4784. m_Handles = NULL;
  4785. }
  4786. break;
  4787. case FunctionTableStream:
  4788. if (IndexDirectory(i, Dir, (PVOID*)&m_FunctionTables) == NULL)
  4789. {
  4790. break;
  4791. }
  4792. // Don't bother walking every table to verify the size,
  4793. // just do a simple minimum size check.
  4794. if (Dir->Location.DataSize <
  4795. m_FunctionTables->SizeOfHeader +
  4796. m_FunctionTables->SizeOfDescriptor *
  4797. m_FunctionTables->NumberOfDescriptors)
  4798. {
  4799. m_FunctionTables = NULL;
  4800. }
  4801. break;
  4802. case MiscInfoStream:
  4803. if (IndexDirectory(i, Dir, (PVOID*)&MiscPtr) == NULL)
  4804. {
  4805. break;
  4806. }
  4807. if (Dir->Location.DataSize < 2 * sizeof(ULONG32))
  4808. {
  4809. break;
  4810. }
  4811. // The dump keeps its own version of the struct
  4812. // as a data member to avoid having to check pointers
  4813. // and structure size. Later references just check
  4814. // flags, copy in what this dump has available.
  4815. Size = sizeof(m_MiscInfo);
  4816. if (Size > Dir->Location.DataSize)
  4817. {
  4818. Size = Dir->Location.DataSize;
  4819. }
  4820. CopyMemory(&m_MiscInfo, MiscPtr, Size);
  4821. break;
  4822. case UnusedStream:
  4823. // Nothing to do.
  4824. break;
  4825. default:
  4826. WarnOut("WARNING: Minidump contains unknown stream type 0x%x\n",
  4827. Dir->StreamType);
  4828. break;
  4829. }
  4830. Dir++;
  4831. }
  4832. // This was already checked in Identify but check
  4833. // again just in case something went wrong.
  4834. if (m_SysInfo == NULL)
  4835. {
  4836. ErrOut("Unable to locate system info\n");
  4837. return HR_DATA_CORRUPT;
  4838. }
  4839. HRESULT Status;
  4840. if ((Status = InitSystemInfo(m_SysInfo->BuildNumber, 0,
  4841. m_ImageType, m_SysInfo->PlatformId,
  4842. m_SysInfo->MajorVersion,
  4843. m_SysInfo->MinorVersion)) != S_OK)
  4844. {
  4845. return Status;
  4846. }
  4847. if (m_SysInfo->NumberOfProcessors)
  4848. {
  4849. m_NumProcessors = m_SysInfo->NumberOfProcessors;
  4850. }
  4851. else
  4852. {
  4853. // Dump does not contain this information.
  4854. m_NumProcessors = 1;
  4855. }
  4856. if (m_SysInfo->CSDVersionRva != 0)
  4857. {
  4858. MINIDUMP_STRING UNALIGNED *CsdString = (MINIDUMP_STRING UNALIGNED *)
  4859. IndexRva(m_Header,
  4860. m_SysInfo->CSDVersionRva, sizeof(*CsdString),
  4861. "CSD string");
  4862. if (CsdString != NULL && CsdString->Length > 0)
  4863. {
  4864. WCHAR UNALIGNED *WideStr = CsdString->Buffer;
  4865. ULONG WideLen = wcslen((PWSTR)WideStr);
  4866. if (m_ActualSystemVersion > W9X_SVER_START &&
  4867. m_ActualSystemVersion < W9X_SVER_END)
  4868. {
  4869. WCHAR UNALIGNED *Str;
  4870. //
  4871. // Win9x CSD strings are usually just a single
  4872. // letter surrounded by whitespace, so clean them
  4873. // up a little bit.
  4874. //
  4875. while (iswspace(*WideStr))
  4876. {
  4877. WideStr++;
  4878. }
  4879. Str = WideStr;
  4880. WideLen = 0;
  4881. while (*Str && !iswspace(*Str))
  4882. {
  4883. WideLen++;
  4884. Str++;
  4885. }
  4886. }
  4887. sprintf(m_ServicePackString,
  4888. "%.*S", WideLen, WideStr);
  4889. }
  4890. }
  4891. if (m_MiscInfo.Flags1 & MINIDUMP_MISC1_PROCESS_ID)
  4892. {
  4893. m_EventProcessId = m_MiscInfo.ProcessId;
  4894. }
  4895. else
  4896. {
  4897. // Some minidumps don't store the process ID. Add the system ID
  4898. // to the fake process ID base to keep each system's
  4899. // fake processes separate from each other.
  4900. m_EventProcessId = VIRTUAL_PROCESS_ID_BASE + m_UserId;
  4901. }
  4902. m_EventProcessSymHandle = VIRTUAL_PROCESS_HANDLE(m_EventProcessId);
  4903. if (m_Exception != NULL)
  4904. {
  4905. m_EventThreadId = m_Exception->ThreadId;
  4906. C_ASSERT(sizeof(m_Exception->ExceptionRecord) ==
  4907. sizeof(EXCEPTION_RECORD64));
  4908. m_ExceptionRecord = *(EXCEPTION_RECORD64 UNALIGNED *)
  4909. &m_Exception->ExceptionRecord;
  4910. }
  4911. else
  4912. {
  4913. m_EventThreadId = VIRTUAL_THREAD_ID(0);
  4914. // Fake an exception.
  4915. ZeroMemory(&m_ExceptionRecord, sizeof(m_ExceptionRecord));
  4916. m_ExceptionRecord.ExceptionCode = STATUS_BREAKPOINT;
  4917. }
  4918. m_ExceptionFirstChance = FALSE;
  4919. if (m_Threads != NULL)
  4920. {
  4921. m_ThreadCount = m_ActualThreadCount;
  4922. if (m_Exception == NULL)
  4923. {
  4924. m_EventThreadId = IndexThreads(0)->ThreadId;
  4925. }
  4926. }
  4927. else
  4928. {
  4929. m_ThreadCount = 1;
  4930. }
  4931. return UserDumpTargetInfo::Initialize();
  4932. }
  4933. void
  4934. UserMiniDumpTargetInfo::NearestDifferentlyValidOffsets(ULONG64 Offset,
  4935. PULONG64 NextOffset,
  4936. PULONG64 NextPage)
  4937. {
  4938. return MapNearestDifferentlyValidOffsets(Offset, NextOffset, NextPage);
  4939. }
  4940. HRESULT
  4941. UserMiniDumpTargetInfo::ReadHandleData(
  4942. IN ProcessInfo* Process,
  4943. IN ULONG64 Handle,
  4944. IN ULONG DataType,
  4945. OUT OPTIONAL PVOID Buffer,
  4946. IN ULONG BufferSize,
  4947. OUT OPTIONAL PULONG DataSize
  4948. )
  4949. {
  4950. if (m_Handles == NULL)
  4951. {
  4952. return E_FAIL;
  4953. }
  4954. MINIDUMP_HANDLE_DESCRIPTOR UNALIGNED *Desc;
  4955. if (DataType != DEBUG_HANDLE_DATA_TYPE_HANDLE_COUNT)
  4956. {
  4957. PUCHAR RawDesc = (PUCHAR)m_Handles + m_Handles->SizeOfHeader;
  4958. ULONG i;
  4959. for (i = 0; i < m_Handles->NumberOfDescriptors; i++)
  4960. {
  4961. Desc = (MINIDUMP_HANDLE_DESCRIPTOR UNALIGNED *)RawDesc;
  4962. if (Desc->Handle == Handle)
  4963. {
  4964. break;
  4965. }
  4966. RawDesc += m_Handles->SizeOfDescriptor;
  4967. }
  4968. if (i >= m_Handles->NumberOfDescriptors)
  4969. {
  4970. return E_NOINTERFACE;
  4971. }
  4972. }
  4973. ULONG Used;
  4974. RVA StrRva;
  4975. BOOL WideStr = FALSE;
  4976. switch(DataType)
  4977. {
  4978. case DEBUG_HANDLE_DATA_TYPE_BASIC:
  4979. Used = sizeof(DEBUG_HANDLE_DATA_BASIC);
  4980. if (Buffer == NULL)
  4981. {
  4982. break;
  4983. }
  4984. if (BufferSize < Used)
  4985. {
  4986. return E_INVALIDARG;
  4987. }
  4988. PDEBUG_HANDLE_DATA_BASIC Basic;
  4989. Basic = (PDEBUG_HANDLE_DATA_BASIC)Buffer;
  4990. Basic->TypeNameSize = Desc->TypeNameRva == 0 ? 0 :
  4991. ((MINIDUMP_STRING UNALIGNED *)
  4992. IndexByByte(m_Header, Desc->TypeNameRva))->
  4993. Length / sizeof(WCHAR) + 1;
  4994. Basic->ObjectNameSize = Desc->ObjectNameRva == 0 ? 0 :
  4995. ((MINIDUMP_STRING UNALIGNED *)
  4996. IndexByByte(m_Header, Desc->ObjectNameRva))->
  4997. Length / sizeof(WCHAR) + 1;
  4998. Basic->Attributes = Desc->Attributes;
  4999. Basic->GrantedAccess = Desc->GrantedAccess;
  5000. Basic->HandleCount = Desc->HandleCount;
  5001. Basic->PointerCount = Desc->PointerCount;
  5002. break;
  5003. case DEBUG_HANDLE_DATA_TYPE_TYPE_NAME_WIDE:
  5004. WideStr = TRUE;
  5005. case DEBUG_HANDLE_DATA_TYPE_TYPE_NAME:
  5006. StrRva = Desc->TypeNameRva;
  5007. break;
  5008. case DEBUG_HANDLE_DATA_TYPE_OBJECT_NAME_WIDE:
  5009. WideStr = TRUE;
  5010. case DEBUG_HANDLE_DATA_TYPE_OBJECT_NAME:
  5011. StrRva = Desc->ObjectNameRva;
  5012. break;
  5013. case DEBUG_HANDLE_DATA_TYPE_HANDLE_COUNT:
  5014. Used = sizeof(ULONG);
  5015. if (Buffer == NULL)
  5016. {
  5017. break;
  5018. }
  5019. if (BufferSize < Used)
  5020. {
  5021. return E_INVALIDARG;
  5022. }
  5023. *(PULONG)Buffer = m_Handles->NumberOfDescriptors;
  5024. break;
  5025. }
  5026. if (DataType == DEBUG_HANDLE_DATA_TYPE_TYPE_NAME ||
  5027. DataType == DEBUG_HANDLE_DATA_TYPE_TYPE_NAME_WIDE ||
  5028. DataType == DEBUG_HANDLE_DATA_TYPE_OBJECT_NAME ||
  5029. DataType == DEBUG_HANDLE_DATA_TYPE_OBJECT_NAME_WIDE)
  5030. {
  5031. if (StrRva == 0)
  5032. {
  5033. Used = WideStr ? sizeof(WCHAR) : sizeof(CHAR);
  5034. if (Buffer)
  5035. {
  5036. if (BufferSize < Used)
  5037. {
  5038. return E_INVALIDARG;
  5039. }
  5040. if (WideStr)
  5041. {
  5042. *(PWCHAR)Buffer = 0;
  5043. }
  5044. else
  5045. {
  5046. *(PCHAR)Buffer = 0;
  5047. }
  5048. }
  5049. }
  5050. else
  5051. {
  5052. MINIDUMP_STRING UNALIGNED *Str = (MINIDUMP_STRING UNALIGNED *)
  5053. IndexRva(m_Header, StrRva, sizeof(*Str), "Handle name string");
  5054. if (Str == NULL)
  5055. {
  5056. return HR_DATA_CORRUPT;
  5057. }
  5058. if (WideStr)
  5059. {
  5060. Used = Str->Length + sizeof(WCHAR);
  5061. }
  5062. else
  5063. {
  5064. Used = Str->Length / sizeof(WCHAR) + 1;
  5065. }
  5066. if (Buffer)
  5067. {
  5068. if (WideStr)
  5069. {
  5070. if (BufferSize < sizeof(WCHAR))
  5071. {
  5072. return E_INVALIDARG;
  5073. }
  5074. BufferSize /= sizeof(WCHAR);
  5075. // The string data may not be aligned, so
  5076. // check and handle both the aligned
  5077. // and unaligned cases.
  5078. if (!((ULONG_PTR)Str->Buffer & (sizeof(WCHAR) - 1)))
  5079. {
  5080. CopyStringW((PWSTR)Buffer, (PWSTR)Str->Buffer,
  5081. BufferSize);
  5082. }
  5083. else
  5084. {
  5085. PUCHAR RawStr = (PUCHAR)Str->Buffer;
  5086. while (--BufferSize > 0 &&
  5087. (RawStr[0] || RawStr[1]))
  5088. {
  5089. *(PWCHAR)Buffer =
  5090. ((USHORT)RawStr[1] << 8) | RawStr[0];
  5091. Buffer = (PVOID)((PWCHAR)Buffer + 1);
  5092. }
  5093. *(PWCHAR)Buffer = 0;
  5094. }
  5095. }
  5096. else
  5097. {
  5098. if (!WideCharToMultiByte(CP_ACP, 0,
  5099. (LPCWSTR)Str->Buffer, -1,
  5100. (LPSTR)Buffer, BufferSize,
  5101. NULL, NULL))
  5102. {
  5103. return WIN32_LAST_STATUS();
  5104. }
  5105. }
  5106. }
  5107. }
  5108. }
  5109. if (DataSize != NULL)
  5110. {
  5111. *DataSize = Used;
  5112. }
  5113. return S_OK;
  5114. }
  5115. HRESULT
  5116. UserMiniDumpTargetInfo::GetProcessorId
  5117. (ULONG Processor, PDEBUG_PROCESSOR_IDENTIFICATION_ALL Id)
  5118. {
  5119. PSTR Unavail = "<unavailable>";
  5120. // Allow any processor index as minidumps now
  5121. // remember the number of processors so requests
  5122. // may come in for processor indices other than zero.
  5123. if (m_SysInfo == NULL)
  5124. {
  5125. return E_UNEXPECTED;
  5126. }
  5127. switch(m_SysInfo->ProcessorArchitecture)
  5128. {
  5129. case PROCESSOR_ARCHITECTURE_INTEL:
  5130. Id->X86.Family = m_SysInfo->ProcessorLevel;
  5131. Id->X86.Model = (m_SysInfo->ProcessorRevision >> 8) & 0xf;
  5132. Id->X86.Stepping = m_SysInfo->ProcessorRevision & 0xf;
  5133. if (m_SysInfo->Cpu.X86CpuInfo.VendorId[0])
  5134. {
  5135. memcpy(Id->X86.VendorString,
  5136. m_SysInfo->Cpu.X86CpuInfo.VendorId,
  5137. sizeof(m_SysInfo->Cpu.X86CpuInfo.VendorId));
  5138. }
  5139. else
  5140. {
  5141. DBG_ASSERT(strlen(Unavail) < DIMA(Id->X86.VendorString));
  5142. strcpy(&(Id->X86.VendorString[0]), Unavail);
  5143. }
  5144. break;
  5145. case PROCESSOR_ARCHITECTURE_IA64:
  5146. Id->Ia64.Model = m_SysInfo->ProcessorLevel;
  5147. Id->Ia64.Revision = m_SysInfo->ProcessorRevision;
  5148. DBG_ASSERT(strlen(Unavail) < DIMA(Id->Ia64.VendorString));
  5149. strcpy(&(Id->Ia64.VendorString[0]), Unavail);
  5150. break;
  5151. case PROCESSOR_ARCHITECTURE_AMD64:
  5152. Id->Amd64.Family = m_SysInfo->ProcessorLevel;
  5153. Id->Amd64.Model = (m_SysInfo->ProcessorRevision >> 8) & 0xf;
  5154. Id->Amd64.Stepping = m_SysInfo->ProcessorRevision & 0xf;
  5155. DBG_ASSERT(strlen(Unavail) < DIMA(Id->Amd64.VendorString));
  5156. strcpy(&(Id->Amd64.VendorString[0]), Unavail);
  5157. break;
  5158. }
  5159. return S_OK;
  5160. }
  5161. HRESULT
  5162. UserMiniDumpTargetInfo::GetProcessorSpeed
  5163. (ULONG Processor, PULONG Speed)
  5164. {
  5165. return E_UNEXPECTED;
  5166. }
  5167. HRESULT
  5168. UserMiniDumpTargetInfo::GetGenericProcessorFeatures(
  5169. ULONG Processor,
  5170. PULONG64 Features,
  5171. ULONG FeaturesSize,
  5172. PULONG Used
  5173. )
  5174. {
  5175. // Allow any processor index as minidumps now
  5176. // remember the number of processors so requests
  5177. // may come in for processor indices other than zero.
  5178. if (m_SysInfo == NULL)
  5179. {
  5180. return E_UNEXPECTED;
  5181. }
  5182. if (m_MachineType == IMAGE_FILE_MACHINE_I386)
  5183. {
  5184. // x86 stores only specific features.
  5185. return E_NOINTERFACE;
  5186. }
  5187. *Used = DIMA(m_SysInfo->Cpu.OtherCpuInfo.ProcessorFeatures);
  5188. if (FeaturesSize > *Used)
  5189. {
  5190. FeaturesSize = *Used;
  5191. }
  5192. memcpy(Features, m_SysInfo->Cpu.OtherCpuInfo.ProcessorFeatures,
  5193. FeaturesSize * sizeof(*Features));
  5194. return S_OK;
  5195. }
  5196. HRESULT
  5197. UserMiniDumpTargetInfo::GetSpecificProcessorFeatures(
  5198. ULONG Processor,
  5199. PULONG64 Features,
  5200. ULONG FeaturesSize,
  5201. PULONG Used
  5202. )
  5203. {
  5204. // Allow any processor index as minidumps now
  5205. // remember the number of processors so requests
  5206. // may come in for processor indices other than zero.
  5207. if (m_SysInfo == NULL)
  5208. {
  5209. return E_UNEXPECTED;
  5210. }
  5211. if (m_MachineType != IMAGE_FILE_MACHINE_I386)
  5212. {
  5213. // Only x86 stores specific features.
  5214. return E_NOINTERFACE;
  5215. }
  5216. *Used = 2;
  5217. if (FeaturesSize > 0)
  5218. {
  5219. *Features++ = m_SysInfo->Cpu.X86CpuInfo.VersionInformation;
  5220. FeaturesSize--;
  5221. }
  5222. if (FeaturesSize > 0)
  5223. {
  5224. *Features++ = m_SysInfo->Cpu.X86CpuInfo.FeatureInformation;
  5225. FeaturesSize--;
  5226. }
  5227. if (m_SysInfo->Cpu.X86CpuInfo.VendorId[0] == AMD_VENDOR_ID_EBX &&
  5228. m_SysInfo->Cpu.X86CpuInfo.VendorId[1] == AMD_VENDOR_ID_EDX &&
  5229. m_SysInfo->Cpu.X86CpuInfo.VendorId[2] == AMD_VENDOR_ID_EBX)
  5230. {
  5231. if (FeaturesSize > 0)
  5232. {
  5233. (*Used)++;
  5234. *Features++ = m_SysInfo->Cpu.X86CpuInfo.AMDExtendedCpuFeatures;
  5235. FeaturesSize--;
  5236. }
  5237. }
  5238. return S_OK;
  5239. }
  5240. PVOID
  5241. UserMiniDumpTargetInfo::FindDynamicFunctionEntry(ProcessInfo* Process,
  5242. ULONG64 Address)
  5243. {
  5244. if (m_FunctionTables == NULL)
  5245. {
  5246. return NULL;
  5247. }
  5248. PUCHAR StreamData =
  5249. (PUCHAR)m_FunctionTables + m_FunctionTables->SizeOfHeader +
  5250. m_FunctionTables->SizeOfAlignPad;
  5251. ULONG TableIdx;
  5252. for (TableIdx = 0;
  5253. TableIdx < m_FunctionTables->NumberOfDescriptors;
  5254. TableIdx++)
  5255. {
  5256. // Stream structure contents are guaranteed to be
  5257. // properly aligned.
  5258. PMINIDUMP_FUNCTION_TABLE_DESCRIPTOR Desc =
  5259. (PMINIDUMP_FUNCTION_TABLE_DESCRIPTOR)StreamData;
  5260. StreamData += m_FunctionTables->SizeOfDescriptor;
  5261. PCROSS_PLATFORM_DYNAMIC_FUNCTION_TABLE RawTable =
  5262. (PCROSS_PLATFORM_DYNAMIC_FUNCTION_TABLE)StreamData;
  5263. StreamData += m_FunctionTables->SizeOfNativeDescriptor;
  5264. PVOID TableData = (PVOID)StreamData;
  5265. StreamData += Desc->EntryCount *
  5266. m_FunctionTables->SizeOfFunctionEntry +
  5267. Desc->SizeOfAlignPad;
  5268. if (Address >= Desc->MinimumAddress && Address < Desc->MaximumAddress)
  5269. {
  5270. PVOID Entry = m_Machine->FindDynamicFunctionEntry
  5271. (RawTable, Address, TableData,
  5272. Desc->EntryCount * m_FunctionTables->SizeOfFunctionEntry);
  5273. if (Entry)
  5274. {
  5275. return Entry;
  5276. }
  5277. }
  5278. }
  5279. return NULL;
  5280. }
  5281. ULONG64
  5282. UserMiniDumpTargetInfo::GetDynamicFunctionTableBase(ProcessInfo* Process,
  5283. ULONG64 Address)
  5284. {
  5285. if (m_FunctionTables == NULL)
  5286. {
  5287. return 0;
  5288. }
  5289. PUCHAR StreamData =
  5290. (PUCHAR)m_FunctionTables + m_FunctionTables->SizeOfHeader +
  5291. m_FunctionTables->SizeOfAlignPad;
  5292. ULONG TableIdx;
  5293. for (TableIdx = 0;
  5294. TableIdx < m_FunctionTables->NumberOfDescriptors;
  5295. TableIdx++)
  5296. {
  5297. // Stream structure contents are guaranteed to be
  5298. // properly aligned.
  5299. PMINIDUMP_FUNCTION_TABLE_DESCRIPTOR Desc =
  5300. (PMINIDUMP_FUNCTION_TABLE_DESCRIPTOR)StreamData;
  5301. StreamData +=
  5302. m_FunctionTables->SizeOfDescriptor +
  5303. m_FunctionTables->SizeOfNativeDescriptor +
  5304. Desc->EntryCount * m_FunctionTables->SizeOfFunctionEntry +
  5305. Desc->SizeOfAlignPad;
  5306. if (Address >= Desc->MinimumAddress && Address < Desc->MaximumAddress)
  5307. {
  5308. return Desc->BaseAddress;
  5309. }
  5310. }
  5311. return 0;
  5312. }
  5313. HRESULT
  5314. UserMiniDumpTargetInfo::EnumFunctionTables(IN ProcessInfo* Process,
  5315. IN OUT PULONG64 Start,
  5316. IN OUT PULONG64 Handle,
  5317. OUT PULONG64 MinAddress,
  5318. OUT PULONG64 MaxAddress,
  5319. OUT PULONG64 BaseAddress,
  5320. OUT PULONG EntryCount,
  5321. OUT PCROSS_PLATFORM_DYNAMIC_FUNCTION_TABLE RawTable,
  5322. OUT PVOID* RawEntries)
  5323. {
  5324. PUCHAR StreamData;
  5325. if (!m_FunctionTables)
  5326. {
  5327. return S_FALSE;
  5328. }
  5329. if (*Start == 0)
  5330. {
  5331. StreamData = (PUCHAR)m_FunctionTables +
  5332. m_FunctionTables->SizeOfHeader +
  5333. m_FunctionTables->SizeOfAlignPad;
  5334. *Start = (LONG_PTR)StreamData;
  5335. *Handle = 0;
  5336. }
  5337. else
  5338. {
  5339. StreamData = (PUCHAR)(ULONG_PTR)*Start;
  5340. }
  5341. if (*Handle >= m_FunctionTables->NumberOfDescriptors)
  5342. {
  5343. return S_FALSE;
  5344. }
  5345. // Stream structure contents are guaranteed to be
  5346. // properly aligned.
  5347. PMINIDUMP_FUNCTION_TABLE_DESCRIPTOR Desc =
  5348. (PMINIDUMP_FUNCTION_TABLE_DESCRIPTOR)StreamData;
  5349. *MinAddress = Desc->MinimumAddress;
  5350. *MaxAddress = Desc->MaximumAddress;
  5351. *BaseAddress = Desc->BaseAddress;
  5352. *EntryCount = Desc->EntryCount;
  5353. StreamData += m_FunctionTables->SizeOfDescriptor;
  5354. memcpy(RawTable, StreamData, m_FunctionTables->SizeOfNativeDescriptor);
  5355. StreamData += m_FunctionTables->SizeOfNativeDescriptor;
  5356. *RawEntries = malloc(Desc->EntryCount *
  5357. m_FunctionTables->SizeOfFunctionEntry);
  5358. if (!*RawEntries)
  5359. {
  5360. return E_OUTOFMEMORY;
  5361. }
  5362. memcpy(*RawEntries, StreamData, Desc->EntryCount *
  5363. m_FunctionTables->SizeOfFunctionEntry);
  5364. StreamData += Desc->EntryCount *
  5365. m_FunctionTables->SizeOfFunctionEntry +
  5366. Desc->SizeOfAlignPad;
  5367. *Start = (LONG_PTR)StreamData;
  5368. (*Handle)++;
  5369. return S_OK;
  5370. }
  5371. HRESULT
  5372. UserMiniDumpTargetInfo::GetTargetContext(
  5373. ULONG64 Thread,
  5374. PVOID Context
  5375. )
  5376. {
  5377. if (m_Threads == NULL ||
  5378. VIRTUAL_THREAD_INDEX(Thread) >= m_ActualThreadCount)
  5379. {
  5380. return E_INVALIDARG;
  5381. }
  5382. PVOID ContextData =
  5383. IndexRva(m_Header,
  5384. IndexThreads(VIRTUAL_THREAD_INDEX(Thread))->ThreadContext.Rva,
  5385. m_TypeInfo.SizeTargetContext,
  5386. "Thread context data");
  5387. if (ContextData == NULL)
  5388. {
  5389. return HR_DATA_CORRUPT;
  5390. }
  5391. memcpy(Context, ContextData, m_TypeInfo.SizeTargetContext);
  5392. return S_OK;
  5393. }
  5394. HRESULT
  5395. UserMiniDumpTargetInfo::IdentifyDump(PULONG64 BaseMapSize)
  5396. {
  5397. HRESULT Status = E_NOINTERFACE;
  5398. // m_Header must be set as other methods rely on it.
  5399. m_Header = (PMINIDUMP_HEADER)m_DumpBase;
  5400. __try
  5401. {
  5402. if (m_Header->Signature != MINIDUMP_SIGNATURE ||
  5403. (m_Header->Version & 0xffff) != MINIDUMP_VERSION)
  5404. {
  5405. __leave;
  5406. }
  5407. MINIDUMP_DIRECTORY UNALIGNED *Dir;
  5408. ULONG i;
  5409. Dir = (MINIDUMP_DIRECTORY UNALIGNED *)
  5410. IndexRva(m_Header, m_Header->StreamDirectoryRva,
  5411. m_Header->NumberOfStreams * sizeof(*Dir),
  5412. "Directory");
  5413. if (Dir == NULL)
  5414. {
  5415. Status = HR_DATA_CORRUPT;
  5416. __leave;
  5417. }
  5418. for (i = 0; i < m_Header->NumberOfStreams; i++)
  5419. {
  5420. switch(Dir->StreamType)
  5421. {
  5422. case SystemInfoStream:
  5423. if (IndexDirectory(i, Dir, (PVOID*)&m_SysInfo) == NULL)
  5424. {
  5425. break;
  5426. }
  5427. if (Dir->Location.DataSize != sizeof(MINIDUMP_SYSTEM_INFO))
  5428. {
  5429. m_SysInfo = NULL;
  5430. }
  5431. break;
  5432. case Memory64ListStream:
  5433. MINIDUMP_MEMORY64_LIST Mem64;
  5434. // The memory for the full memory list may not
  5435. // fit within the initial mapping used at identify
  5436. // time so do not directly index. Instead, use
  5437. // the adaptive read to get the data so we can
  5438. // determine the data base.
  5439. if (m_InfoFiles[DUMP_INFO_DUMP].
  5440. ReadFileOffset(Dir->Location.Rva,
  5441. &Mem64, sizeof(Mem64)) == sizeof(Mem64) &&
  5442. Dir->Location.DataSize ==
  5443. sizeof(MINIDUMP_MEMORY64_LIST) +
  5444. sizeof(MINIDUMP_MEMORY_DESCRIPTOR64) *
  5445. Mem64.NumberOfMemoryRanges)
  5446. {
  5447. m_Memory64DataBase = Mem64.BaseRva;
  5448. }
  5449. // Clear any cache entries that may have been
  5450. // added by the above read so that only the
  5451. // identify mapping is active.
  5452. m_InfoFiles[DUMP_INFO_DUMP].EmptyCache();
  5453. break;
  5454. }
  5455. Dir++;
  5456. }
  5457. if (m_SysInfo == NULL)
  5458. {
  5459. ErrOut("Minidump does not have system info\n");
  5460. Status = E_FAIL;
  5461. __leave;
  5462. }
  5463. m_ImageType = ProcArchToImageMachine(m_SysInfo->ProcessorArchitecture);
  5464. if (m_ImageType == IMAGE_FILE_MACHINE_UNKNOWN)
  5465. {
  5466. ErrOut("Minidump has unrecognized processor architecture 0x%x\n",
  5467. m_SysInfo->ProcessorArchitecture);
  5468. Status = E_FAIL;
  5469. __leave;
  5470. }
  5471. // We rely on being able to directly access the entire
  5472. // content of the dump through the default view so
  5473. // ensure that it's possible.
  5474. *BaseMapSize = m_InfoFiles[DUMP_INFO_DUMP].m_FileSize;
  5475. Status = S_OK;
  5476. }
  5477. __except(EXCEPTION_EXECUTE_HANDLER)
  5478. {
  5479. Status = DumpIdentifyStatus(GetExceptionCode());
  5480. }
  5481. if (Status != S_OK)
  5482. {
  5483. m_Header = NULL;
  5484. }
  5485. return Status;
  5486. }
  5487. ModuleInfo*
  5488. UserMiniDumpTargetInfo::GetModuleInfo(BOOL UserMode)
  5489. {
  5490. DBG_ASSERT(UserMode);
  5491. return &g_UserMiniModuleIterator;
  5492. }
  5493. HRESULT
  5494. UserMiniDumpTargetInfo::GetImageVersionInformation(ProcessInfo* Process,
  5495. PCSTR ImagePath,
  5496. ULONG64 ImageBase,
  5497. PCSTR Item,
  5498. PVOID Buffer,
  5499. ULONG BufferSize,
  5500. PULONG VerInfoSize)
  5501. {
  5502. //
  5503. // Find the image in the dump module list.
  5504. //
  5505. if (m_Modules == NULL)
  5506. {
  5507. return E_NOINTERFACE;
  5508. }
  5509. ULONG i;
  5510. MINIDUMP_MODULE UNALIGNED *Mod = m_Modules->Modules;
  5511. for (i = 0; i < m_Modules->NumberOfModules; i++)
  5512. {
  5513. if (ImageBase == Mod->BaseOfImage)
  5514. {
  5515. break;
  5516. }
  5517. Mod++;
  5518. }
  5519. if (i == m_Modules->NumberOfModules)
  5520. {
  5521. return E_NOINTERFACE;
  5522. }
  5523. PVOID Data = NULL;
  5524. ULONG DataSize = 0;
  5525. if (Item[0] == '\\' && Item[1] == 0)
  5526. {
  5527. Data = &Mod->VersionInfo;
  5528. DataSize = sizeof(Mod->VersionInfo);
  5529. }
  5530. else
  5531. {
  5532. return E_INVALIDARG;
  5533. }
  5534. return FillDataBuffer(Data, DataSize, Buffer, BufferSize, VerInfoSize);
  5535. }
  5536. HRESULT
  5537. UserMiniDumpTargetInfo::GetExceptionContext(PCROSS_PLATFORM_CONTEXT Context)
  5538. {
  5539. if (m_Exception != NULL)
  5540. {
  5541. PVOID ContextData;
  5542. if (m_Exception->ThreadContext.DataSize <
  5543. m_TypeInfo.SizeTargetContext ||
  5544. (ContextData = IndexRva(m_Header,
  5545. m_Exception->ThreadContext.Rva,
  5546. m_TypeInfo.SizeTargetContext,
  5547. "Exception context")) == NULL)
  5548. {
  5549. return E_FAIL;
  5550. }
  5551. memcpy(Context, ContextData,
  5552. m_TypeInfo.SizeTargetContext);
  5553. return S_OK;
  5554. }
  5555. else
  5556. {
  5557. ErrOut("Minidump doesn't have an exception context\n");
  5558. return E_FAIL;
  5559. }
  5560. }
  5561. ULONG64
  5562. UserMiniDumpTargetInfo::GetCurrentTimeDateN(void)
  5563. {
  5564. return TimeDateStampToFileTime(m_Header->TimeDateStamp);
  5565. }
  5566. ULONG64
  5567. UserMiniDumpTargetInfo::GetProcessUpTimeN(ProcessInfo* Process)
  5568. {
  5569. if (m_MiscInfo.Flags1 & MINIDUMP_MISC1_PROCESS_TIMES)
  5570. {
  5571. return TimeToFileTime(m_Header->TimeDateStamp -
  5572. m_MiscInfo.ProcessCreateTime);
  5573. }
  5574. else
  5575. {
  5576. return 0;
  5577. }
  5578. }
  5579. HRESULT
  5580. UserMiniDumpTargetInfo::GetProcessTimes(ProcessInfo* Process,
  5581. PULONG64 Create,
  5582. PULONG64 Exit,
  5583. PULONG64 Kernel,
  5584. PULONG64 User)
  5585. {
  5586. if (m_MiscInfo.Flags1 & MINIDUMP_MISC1_PROCESS_TIMES)
  5587. {
  5588. *Create = TimeDateStampToFileTime(m_MiscInfo.ProcessCreateTime);
  5589. *Exit = 0;
  5590. *Kernel = TimeToFileTime(m_MiscInfo.ProcessKernelTime);
  5591. *User = TimeToFileTime(m_MiscInfo.ProcessUserTime);
  5592. return S_OK;
  5593. }
  5594. else
  5595. {
  5596. return E_NOINTERFACE;
  5597. }
  5598. }
  5599. HRESULT
  5600. UserMiniDumpTargetInfo::GetProductInfo(PULONG ProductType, PULONG SuiteMask)
  5601. {
  5602. if (m_SysInfo->ProductType != INVALID_PRODUCT_TYPE)
  5603. {
  5604. *ProductType = m_SysInfo->ProductType;
  5605. *SuiteMask = m_SysInfo->SuiteMask;
  5606. return S_OK;
  5607. }
  5608. else
  5609. {
  5610. return TargetInfo::GetProductInfo(ProductType, SuiteMask);
  5611. }
  5612. }
  5613. HRESULT
  5614. UserMiniDumpTargetInfo::GetThreadInfo(ULONG Index,
  5615. PULONG Id, PULONG Suspend, PULONG64 Teb)
  5616. {
  5617. if (m_Threads == NULL || Index >= m_ActualThreadCount)
  5618. {
  5619. return E_INVALIDARG;
  5620. }
  5621. MINIDUMP_THREAD_EX UNALIGNED *Thread = IndexThreads(Index);
  5622. *Id = Thread->ThreadId;
  5623. *Suspend = Thread->SuspendCount;
  5624. *Teb = Thread->Teb;
  5625. return S_OK;
  5626. }
  5627. PSTR g_MiniStreamNames[] =
  5628. {
  5629. "UnusedStream", "ReservedStream0", "ReservedStream1", "ThreadListStream",
  5630. "ModuleListStream", "MemoryListStream", "ExceptionStream",
  5631. "SystemInfoStream", "ThreadExListStream", "Memory64ListStream",
  5632. "CommentStreamA", "CommentStreamW", "HandleDataStream",
  5633. "FunctionTableStream", "UnloadedModuleListStream", "MiscInfoStream",
  5634. };
  5635. PSTR
  5636. MiniStreamTypeName(ULONG32 Type)
  5637. {
  5638. if (Type < sizeof(g_MiniStreamNames) / sizeof(g_MiniStreamNames[0]))
  5639. {
  5640. return g_MiniStreamNames[Type];
  5641. }
  5642. else
  5643. {
  5644. return "???";
  5645. }
  5646. }
  5647. PVOID
  5648. UserMiniDumpTargetInfo::IndexDirectory(ULONG Index,
  5649. MINIDUMP_DIRECTORY UNALIGNED *Dir,
  5650. PVOID* Store)
  5651. {
  5652. if (*Store != NULL)
  5653. {
  5654. WarnOut("WARNING: Ignoring extra %s stream, dir entry %d\n",
  5655. MiniStreamTypeName(Dir->StreamType), Index);
  5656. return NULL;
  5657. }
  5658. char Msg[128];
  5659. sprintf(Msg, "Dir entry %d, %s stream",
  5660. Index, MiniStreamTypeName(Dir->StreamType));
  5661. PVOID Ptr = IndexRva(m_Header,
  5662. Dir->Location.Rva, Dir->Location.DataSize, Msg);
  5663. if (Ptr != NULL)
  5664. {
  5665. *Store = Ptr;
  5666. }
  5667. return Ptr;
  5668. }
  5669. void
  5670. UserMiniDumpTargetInfo::DumpDebug(void)
  5671. {
  5672. ULONG i;
  5673. dprintf("----- User Mini Dump Analysis\n");
  5674. dprintf("\nMINIDUMP_HEADER:\n");
  5675. dprintf("Version %X (%X)\n",
  5676. m_Header->Version & 0xffff, m_Header->Version >> 16);
  5677. dprintf("NumberOfStreams %d\n", m_Header->NumberOfStreams);
  5678. if (m_Header->CheckSum)
  5679. {
  5680. dprintf("Failure flags: %X\n", m_Header->CheckSum);
  5681. }
  5682. dprintf("Flags %X\n", m_Header->Flags);
  5683. MINIDUMP_DIRECTORY UNALIGNED *Dir;
  5684. dprintf("\nStreams:\n");
  5685. Dir = (MINIDUMP_DIRECTORY UNALIGNED *)
  5686. IndexRva(m_Header, m_Header->StreamDirectoryRva,
  5687. m_Header->NumberOfStreams * sizeof(*Dir),
  5688. "Directory");
  5689. if (Dir == NULL)
  5690. {
  5691. return;
  5692. }
  5693. PVOID Data;
  5694. for (i = 0; i < m_Header->NumberOfStreams; i++)
  5695. {
  5696. dprintf("Stream %d: type %s (%d), size %08X, RVA %08X\n",
  5697. i, MiniStreamTypeName(Dir->StreamType), Dir->StreamType,
  5698. Dir->Location.DataSize, Dir->Location.Rva);
  5699. Data = NULL;
  5700. if (IndexDirectory(i, Dir, &Data) == NULL)
  5701. {
  5702. continue;
  5703. }
  5704. ULONG j;
  5705. RVA Rva;
  5706. WCHAR StrBuf[MAX_PATH];
  5707. Rva = Dir->Location.Rva;
  5708. switch(Dir->StreamType)
  5709. {
  5710. case ModuleListStream:
  5711. {
  5712. MINIDUMP_MODULE_LIST UNALIGNED *ModList;
  5713. MINIDUMP_MODULE UNALIGNED *Mod;
  5714. ModList = (MINIDUMP_MODULE_LIST UNALIGNED *)Data;
  5715. Mod = ModList->Modules;
  5716. dprintf(" %d modules\n", ModList->NumberOfModules);
  5717. Rva += FIELD_OFFSET(MINIDUMP_MODULE_LIST, Modules);
  5718. for (j = 0; j < ModList->NumberOfModules; j++)
  5719. {
  5720. PVOID Str = IndexRva(m_Header, Mod->ModuleNameRva,
  5721. sizeof(MINIDUMP_STRING),
  5722. "Module entry name");
  5723. // The Unicode string text may not be aligned,
  5724. // so copy it to an alignment-friendly buffer.
  5725. if (Str)
  5726. {
  5727. memcpy(StrBuf, ((MINIDUMP_STRING UNALIGNED *)Str)->Buffer,
  5728. sizeof(StrBuf));
  5729. StrBuf[DIMA(StrBuf) - 1] = 0;
  5730. }
  5731. else
  5732. {
  5733. wcscpy(StrBuf, L"** Invalid **");
  5734. }
  5735. dprintf(" RVA %08X, %s - %s: '%S'\n",
  5736. Rva,
  5737. FormatAddr64(Mod->BaseOfImage),
  5738. FormatAddr64(Mod->BaseOfImage + Mod->SizeOfImage),
  5739. StrBuf);
  5740. Mod++;
  5741. Rva += sizeof(*Mod);
  5742. }
  5743. break;
  5744. }
  5745. case UnloadedModuleListStream:
  5746. {
  5747. MINIDUMP_UNLOADED_MODULE_LIST UNALIGNED *UnlModList;
  5748. UnlModList = (MINIDUMP_UNLOADED_MODULE_LIST UNALIGNED *)Data;
  5749. dprintf(" %d unloaded modules\n", UnlModList->NumberOfEntries);
  5750. Rva += UnlModList->SizeOfHeader;
  5751. for (j = 0; j < UnlModList->NumberOfEntries; j++)
  5752. {
  5753. MINIDUMP_UNLOADED_MODULE UNALIGNED *UnlMod =
  5754. (MINIDUMP_UNLOADED_MODULE UNALIGNED *)
  5755. IndexRva(m_Header, Rva, sizeof(MINIDUMP_UNLOADED_MODULE),
  5756. "Unloaded module entry");
  5757. if (!UnlMod)
  5758. {
  5759. break;
  5760. }
  5761. PVOID Str = IndexRva(m_Header, UnlMod->ModuleNameRva,
  5762. sizeof(MINIDUMP_STRING),
  5763. "Unloaded module entry name");
  5764. // The Unicode string text may not be aligned,
  5765. // so copy it to an alignment-friendly buffer.
  5766. if (Str)
  5767. {
  5768. memcpy(StrBuf, ((MINIDUMP_STRING UNALIGNED *)Str)->Buffer,
  5769. sizeof(StrBuf));
  5770. StrBuf[DIMA(StrBuf) - 1] = 0;
  5771. }
  5772. else
  5773. {
  5774. wcscpy(StrBuf, L"** Invalid **");
  5775. }
  5776. dprintf(" RVA %08X, %s - %s: '%S'\n",
  5777. Rva,
  5778. FormatAddr64(UnlMod->BaseOfImage),
  5779. FormatAddr64(UnlMod->BaseOfImage +
  5780. UnlMod->SizeOfImage),
  5781. StrBuf);
  5782. Rva += UnlModList->SizeOfEntry;
  5783. }
  5784. break;
  5785. }
  5786. case MemoryListStream:
  5787. {
  5788. MINIDUMP_MEMORY_LIST UNALIGNED *MemList;
  5789. ULONG64 Total = 0;
  5790. MemList = (MINIDUMP_MEMORY_LIST UNALIGNED *)Data;
  5791. dprintf(" %d memory ranges\n", MemList->NumberOfMemoryRanges);
  5792. dprintf(" range# Address %sSize\n",
  5793. m_Machine->m_Ptr64 ? " " : "");
  5794. for (j = 0; j < MemList->NumberOfMemoryRanges; j++)
  5795. {
  5796. dprintf(" %4d %s %s\n",
  5797. j,
  5798. FormatAddr64(MemList->MemoryRanges[j].StartOfMemoryRange),
  5799. FormatAddr64(MemList->MemoryRanges[j].Memory.DataSize));
  5800. Total += MemList->MemoryRanges[j].Memory.DataSize;
  5801. }
  5802. dprintf(" Total memory: %I64x\n", Total);
  5803. break;
  5804. }
  5805. case Memory64ListStream:
  5806. {
  5807. MINIDUMP_MEMORY64_LIST UNALIGNED *MemList;
  5808. ULONG64 Total = 0;
  5809. MemList = (MINIDUMP_MEMORY64_LIST UNALIGNED *)Data;
  5810. dprintf(" %d memory ranges\n", MemList->NumberOfMemoryRanges);
  5811. dprintf(" RVA 0x%X BaseRva\n", (ULONG)(MemList->BaseRva));
  5812. dprintf(" range# Address %sSize\n",
  5813. m_Machine->m_Ptr64 ? " " : "");
  5814. for (j = 0; j < MemList->NumberOfMemoryRanges; j++)
  5815. {
  5816. dprintf(" %4d %s %s\n",
  5817. j,
  5818. FormatAddr64(MemList->MemoryRanges[j].StartOfMemoryRange),
  5819. FormatAddr64(MemList->MemoryRanges[j].DataSize));
  5820. Total += MemList->MemoryRanges[j].DataSize;
  5821. }
  5822. dprintf(" Total memory: %I64x\n", Total);
  5823. break;
  5824. }
  5825. case CommentStreamA:
  5826. dprintf(" '%s'\n", Data);
  5827. break;
  5828. case CommentStreamW:
  5829. dprintf(" '%ls'\n", Data);
  5830. break;
  5831. }
  5832. Dir++;
  5833. }
  5834. }
  5835. //----------------------------------------------------------------------------
  5836. //
  5837. // UserMiniPartialDumpTargetInfo.
  5838. //
  5839. //----------------------------------------------------------------------------
  5840. HRESULT
  5841. UserMiniPartialDumpTargetInfo::Initialize(void)
  5842. {
  5843. HRESULT Status;
  5844. dprintf("User Mini Dump File: Only registers, stack and portions of "
  5845. "memory are available\n\n");
  5846. if ((Status = UserMiniDumpTargetInfo::Initialize()) != S_OK)
  5847. {
  5848. return Status;
  5849. }
  5850. if (m_Memory != NULL)
  5851. {
  5852. //
  5853. // Map every piece of memory in the dump. This makes
  5854. // ReadVirtual very simple and there shouldn't be that
  5855. // many ranges so it doesn't require that many map regions.
  5856. //
  5857. MINIDUMP_MEMORY_DESCRIPTOR UNALIGNED *Mem;
  5858. ULONG i;
  5859. ULONG64 TotalMemory;
  5860. Mem = m_Memory->MemoryRanges;
  5861. for (i = 0; i < m_Memory->NumberOfMemoryRanges; i++)
  5862. {
  5863. PVOID Data = IndexRva(m_Header,
  5864. Mem->Memory.Rva, Mem->Memory.DataSize,
  5865. "Memory range data");
  5866. if (Data == NULL)
  5867. {
  5868. return HR_DATA_CORRUPT;
  5869. }
  5870. if ((Status = m_DataMemMap.
  5871. AddRegion(Mem->StartOfMemoryRange,
  5872. Mem->Memory.DataSize, Data,
  5873. NULL, FALSE)) != S_OK)
  5874. {
  5875. return Status;
  5876. }
  5877. Mem++;
  5878. }
  5879. VerbOut(" Memory regions: %d\n",
  5880. m_Memory->NumberOfMemoryRanges);
  5881. Mem = m_Memory->MemoryRanges;
  5882. TotalMemory = 0;
  5883. for (i = 0; i < m_Memory->NumberOfMemoryRanges; i++)
  5884. {
  5885. VerbOut(" %5d: %s - %s\n",
  5886. i, FormatAddr64(Mem->StartOfMemoryRange),
  5887. FormatAddr64(Mem->StartOfMemoryRange +
  5888. Mem->Memory.DataSize - 1));
  5889. TotalMemory += Mem->Memory.DataSize;
  5890. Mem++;
  5891. }
  5892. VerbOut(" Total memory region size %s\n",
  5893. FormatAddr64(TotalMemory));
  5894. }
  5895. return S_OK;
  5896. }
  5897. HRESULT
  5898. UserMiniPartialDumpTargetInfo::GetDescription(PSTR Buffer, ULONG BufferLen,
  5899. PULONG DescLen)
  5900. {
  5901. HRESULT Status;
  5902. Status = AppendToStringBuffer(S_OK, "User mini dump: ", TRUE,
  5903. &Buffer, &BufferLen, DescLen);
  5904. return AppendToStringBuffer(Status,
  5905. m_InfoFiles[DUMP_INFO_DUMP].m_FileNameA,
  5906. FALSE, &Buffer, &BufferLen, DescLen);
  5907. }
  5908. HRESULT
  5909. UserMiniPartialDumpTargetInfo::ReadVirtual(
  5910. IN ProcessInfo* Process,
  5911. IN ULONG64 Offset,
  5912. OUT PVOID Buffer,
  5913. IN ULONG BufferSize,
  5914. OUT OPTIONAL PULONG BytesRead
  5915. )
  5916. {
  5917. return MapReadVirtual(Process, Offset, Buffer, BufferSize, BytesRead);
  5918. }
  5919. HRESULT
  5920. UserMiniPartialDumpTargetInfo::QueryMemoryRegion
  5921. (ProcessInfo* Process,
  5922. PULONG64 Handle,
  5923. BOOL HandleIsOffset,
  5924. PMEMORY_BASIC_INFORMATION64 Info)
  5925. {
  5926. ULONG Index;
  5927. MINIDUMP_MEMORY_DESCRIPTOR UNALIGNED *Mem;
  5928. if (HandleIsOffset)
  5929. {
  5930. if (m_Memory == NULL)
  5931. {
  5932. return E_NOINTERFACE;
  5933. }
  5934. MINIDUMP_MEMORY_DESCRIPTOR UNALIGNED *BestMem;
  5935. ULONG64 BestDiff;
  5936. //
  5937. // Emulate VirtualQueryEx and return the closest higher
  5938. // region if a containing region isn't found.
  5939. //
  5940. BestMem = NULL;
  5941. BestDiff = (ULONG64)-1;
  5942. Mem = m_Memory->MemoryRanges;
  5943. for (Index = 0; Index < m_Memory->NumberOfMemoryRanges; Index++)
  5944. {
  5945. if (*Handle >= Mem->StartOfMemoryRange)
  5946. {
  5947. if (*Handle < Mem->StartOfMemoryRange + Mem->Memory.DataSize)
  5948. {
  5949. // Found a containing region, we're done.
  5950. BestMem = Mem;
  5951. break;
  5952. }
  5953. // Not containing and lower in memory, ignore.
  5954. }
  5955. else
  5956. {
  5957. // Check and see if this is a closer
  5958. // region than what we've seen already.
  5959. ULONG64 Diff = Mem->StartOfMemoryRange - *Handle;
  5960. if (Diff <= BestDiff)
  5961. {
  5962. BestMem = Mem;
  5963. BestDiff = Diff;
  5964. }
  5965. }
  5966. Mem++;
  5967. }
  5968. if (!BestMem)
  5969. {
  5970. return E_NOINTERFACE;
  5971. }
  5972. Mem = BestMem;
  5973. }
  5974. else
  5975. {
  5976. Index = (ULONG)*Handle;
  5977. if (m_Memory == NULL || Index >= m_Memory->NumberOfMemoryRanges)
  5978. {
  5979. return HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES);
  5980. }
  5981. Mem = m_Memory->MemoryRanges + Index;
  5982. }
  5983. Info->BaseAddress = Mem->StartOfMemoryRange;
  5984. Info->AllocationBase = Mem->StartOfMemoryRange;
  5985. Info->AllocationProtect = PAGE_READWRITE;
  5986. Info->__alignment1 = 0;
  5987. Info->RegionSize = Mem->Memory.DataSize;
  5988. Info->State = MEM_COMMIT;
  5989. Info->Protect = PAGE_READWRITE;
  5990. Info->Type = MEM_PRIVATE;
  5991. Info->__alignment2 = 0;
  5992. *Handle = ++Index;
  5993. return S_OK;
  5994. }
  5995. UnloadedModuleInfo*
  5996. UserMiniPartialDumpTargetInfo::GetUnloadedModuleInfo(void)
  5997. {
  5998. return &g_UserMiniUnloadedModuleIterator;
  5999. }
  6000. HRESULT
  6001. UserMiniPartialDumpTargetInfo::IdentifyDump(PULONG64 BaseMapSize)
  6002. {
  6003. HRESULT Status;
  6004. if ((Status = UserMiniDumpTargetInfo::IdentifyDump(BaseMapSize)) != S_OK)
  6005. {
  6006. return Status;
  6007. }
  6008. __try
  6009. {
  6010. if (m_Header->Flags & MiniDumpWithFullMemory)
  6011. {
  6012. m_Header = NULL;
  6013. m_SysInfo = NULL;
  6014. Status = E_NOINTERFACE;
  6015. }
  6016. else
  6017. {
  6018. Status = S_OK;
  6019. }
  6020. }
  6021. __except(EXCEPTION_EXECUTE_HANDLER)
  6022. {
  6023. Status = DumpIdentifyStatus(GetExceptionCode());
  6024. }
  6025. return Status;
  6026. }
  6027. ULONG64
  6028. UserMiniPartialDumpTargetInfo::VirtualToOffset(ULONG64 Virt,
  6029. PULONG File, PULONG Avail)
  6030. {
  6031. *File = DUMP_INFO_DUMP;
  6032. if (m_Memory == NULL)
  6033. {
  6034. return 0;
  6035. }
  6036. MINIDUMP_MEMORY_DESCRIPTOR UNALIGNED *Mem = m_Memory->MemoryRanges;
  6037. ULONG i;
  6038. ULONG64 RetOffset = 0;
  6039. __try
  6040. {
  6041. for (i = 0; i < m_Memory->NumberOfMemoryRanges; i++)
  6042. {
  6043. if (Virt >= Mem->StartOfMemoryRange &&
  6044. Virt < Mem->StartOfMemoryRange + Mem->Memory.DataSize)
  6045. {
  6046. ULONG Frag = (ULONG)(Virt - Mem->StartOfMemoryRange);
  6047. *Avail = Mem->Memory.DataSize - Frag;
  6048. RetOffset = Mem->Memory.Rva + Frag;
  6049. break;
  6050. }
  6051. Mem++;
  6052. }
  6053. }
  6054. __except(MappingExceptionFilter(GetExceptionInformation()))
  6055. {
  6056. RetOffset = 0;
  6057. }
  6058. return RetOffset;
  6059. }
  6060. //----------------------------------------------------------------------------
  6061. //
  6062. // UserMiniFullDumpTargetInfo.
  6063. //
  6064. //----------------------------------------------------------------------------
  6065. HRESULT
  6066. UserMiniFullDumpTargetInfo::Initialize(void)
  6067. {
  6068. HRESULT Status;
  6069. dprintf("User Mini Dump File with Full Memory: Only application "
  6070. "data is available\n\n");
  6071. if ((Status = UserMiniDumpTargetInfo::Initialize()) != S_OK)
  6072. {
  6073. return Status;
  6074. }
  6075. if (m_Memory64 != NULL)
  6076. {
  6077. ULONG64 TotalMemory;
  6078. ULONG i;
  6079. MINIDUMP_MEMORY_DESCRIPTOR64 UNALIGNED *Mem;
  6080. VerbOut(" Memory regions: %d\n",
  6081. m_Memory64->NumberOfMemoryRanges);
  6082. Mem = m_Memory64->MemoryRanges;
  6083. TotalMemory = 0;
  6084. for (i = 0; i < m_Memory64->NumberOfMemoryRanges; i++)
  6085. {
  6086. VerbOut(" %5d: %s - %s\n",
  6087. i, FormatAddr64(Mem->StartOfMemoryRange),
  6088. FormatAddr64(Mem->StartOfMemoryRange +
  6089. Mem->DataSize - 1));
  6090. TotalMemory += Mem->DataSize;
  6091. Mem++;
  6092. }
  6093. VerbOut(" Total memory region size %s\n",
  6094. FormatAddr64(TotalMemory));
  6095. if (TotalMemory + m_Memory64->BaseRva >
  6096. m_InfoFiles[DUMP_INFO_DUMP].m_FileSize)
  6097. {
  6098. WarnOut("****************************************"
  6099. "********************\n");
  6100. WarnOut("WARNING: Dump file has been truncated. "
  6101. "Data may be missing.\n");
  6102. WarnOut("****************************************"
  6103. "********************\n\n");
  6104. }
  6105. }
  6106. return S_OK;
  6107. }
  6108. HRESULT
  6109. UserMiniFullDumpTargetInfo::GetDescription(PSTR Buffer, ULONG BufferLen,
  6110. PULONG DescLen)
  6111. {
  6112. HRESULT Status;
  6113. Status = AppendToStringBuffer(S_OK, "Full memory user mini dump: ", TRUE,
  6114. &Buffer, &BufferLen, DescLen);
  6115. return AppendToStringBuffer(Status,
  6116. m_InfoFiles[DUMP_INFO_DUMP].m_FileNameA,
  6117. FALSE, &Buffer, &BufferLen, DescLen);
  6118. }
  6119. HRESULT
  6120. UserMiniFullDumpTargetInfo::QueryMemoryRegion
  6121. (ProcessInfo* Process,
  6122. PULONG64 Handle,
  6123. BOOL HandleIsOffset,
  6124. PMEMORY_BASIC_INFORMATION64 Info)
  6125. {
  6126. ULONG Index;
  6127. MINIDUMP_MEMORY_DESCRIPTOR64 UNALIGNED *Mem;
  6128. if (HandleIsOffset)
  6129. {
  6130. if (m_Memory64 == NULL)
  6131. {
  6132. return E_NOINTERFACE;
  6133. }
  6134. MINIDUMP_MEMORY_DESCRIPTOR64 UNALIGNED *BestMem;
  6135. ULONG64 BestDiff;
  6136. //
  6137. // Emulate VirtualQueryEx and return the closest higher
  6138. // region if a containing region isn't found.
  6139. //
  6140. BestMem = NULL;
  6141. BestDiff = (ULONG64)-1;
  6142. Mem = m_Memory64->MemoryRanges;
  6143. if (m_Machine->m_Ptr64)
  6144. {
  6145. for (Index = 0; Index < m_Memory64->NumberOfMemoryRanges; Index++)
  6146. {
  6147. if (*Handle >= Mem->StartOfMemoryRange)
  6148. {
  6149. if (*Handle < Mem->StartOfMemoryRange + Mem->DataSize)
  6150. {
  6151. // Found a containing region, we're done.
  6152. BestMem = Mem;
  6153. break;
  6154. }
  6155. // Not containing and lower in memory, ignore.
  6156. }
  6157. else
  6158. {
  6159. // Check and see if this is a closer
  6160. // region than what we've seen already.
  6161. ULONG64 Diff = Mem->StartOfMemoryRange - *Handle;
  6162. if (Diff <= BestDiff)
  6163. {
  6164. BestMem = Mem;
  6165. BestDiff = Diff;
  6166. }
  6167. }
  6168. Mem++;
  6169. }
  6170. }
  6171. else
  6172. {
  6173. ULONG64 Check;
  6174. //
  6175. // Ignore any sign extension on a 32-bit dump.
  6176. //
  6177. Check = (ULONG)*Handle;
  6178. for (Index = 0; Index < m_Memory64->NumberOfMemoryRanges; Index++)
  6179. {
  6180. if (Check >= (ULONG)Mem->StartOfMemoryRange)
  6181. {
  6182. if (Check < (ULONG)
  6183. (Mem->StartOfMemoryRange + Mem->DataSize))
  6184. {
  6185. // Found a containing region, we're done.
  6186. BestMem = Mem;
  6187. break;
  6188. }
  6189. // Not containing and lower in memory, ignore.
  6190. }
  6191. else
  6192. {
  6193. // Check and see if this is a closer
  6194. // region than what we've seen already.
  6195. ULONG64 Diff = (ULONG)Mem->StartOfMemoryRange - Check;
  6196. if (Diff <= BestDiff)
  6197. {
  6198. BestMem = Mem;
  6199. BestDiff = Diff;
  6200. }
  6201. }
  6202. Mem++;
  6203. }
  6204. }
  6205. if (!BestMem)
  6206. {
  6207. return E_NOINTERFACE;
  6208. }
  6209. Mem = BestMem;
  6210. }
  6211. else
  6212. {
  6213. Index = (ULONG)*Handle;
  6214. if (m_Memory64 == NULL || Index >= m_Memory64->NumberOfMemoryRanges)
  6215. {
  6216. return HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES);
  6217. }
  6218. Mem = m_Memory64->MemoryRanges + Index;
  6219. }
  6220. Info->BaseAddress = Mem->StartOfMemoryRange;
  6221. Info->AllocationBase = Mem->StartOfMemoryRange;
  6222. Info->AllocationProtect = PAGE_READWRITE;
  6223. Info->__alignment1 = 0;
  6224. Info->RegionSize = Mem->DataSize;
  6225. Info->State = MEM_COMMIT;
  6226. Info->Protect = PAGE_READWRITE;
  6227. Info->Type = MEM_PRIVATE;
  6228. Info->__alignment2 = 0;
  6229. *Handle = ++Index;
  6230. return S_OK;
  6231. }
  6232. UnloadedModuleInfo*
  6233. UserMiniFullDumpTargetInfo::GetUnloadedModuleInfo(void)
  6234. {
  6235. // As this is a full-memory dump we may have unloaded module
  6236. // information in the memory itself. If we don't have
  6237. // an official unloaded module stream, try to get it from memory.
  6238. if (m_UnlModules)
  6239. {
  6240. return &g_UserMiniUnloadedModuleIterator;
  6241. }
  6242. else if (m_PlatformId == VER_PLATFORM_WIN32_NT)
  6243. {
  6244. return &g_NtUserUnloadedModuleIterator;
  6245. }
  6246. else
  6247. {
  6248. return NULL;
  6249. }
  6250. }
  6251. HRESULT
  6252. UserMiniFullDumpTargetInfo::IdentifyDump(PULONG64 BaseMapSize)
  6253. {
  6254. HRESULT Status;
  6255. if ((Status = UserMiniDumpTargetInfo::IdentifyDump(BaseMapSize)) != S_OK)
  6256. {
  6257. return Status;
  6258. }
  6259. __try
  6260. {
  6261. if (!(m_Header->Flags & MiniDumpWithFullMemory))
  6262. {
  6263. m_Header = NULL;
  6264. m_SysInfo = NULL;
  6265. Status = E_NOINTERFACE;
  6266. __leave;
  6267. }
  6268. if (m_Memory64DataBase == 0)
  6269. {
  6270. ErrOut("Full-memory minidump must have a Memory64ListStream\n");
  6271. Status = E_FAIL;
  6272. __leave;
  6273. }
  6274. // In the case of a full memory minidump we don't
  6275. // want to map the entire dump as it can be very large.
  6276. // Fortunately, we are guaranteed that all of the raw
  6277. // memory data in a full memory minidump will be at the
  6278. // end of the dump, so we can just map the dump up
  6279. // to the memory content and stop.
  6280. *BaseMapSize = m_Memory64DataBase;
  6281. Status = S_OK;
  6282. }
  6283. __except(EXCEPTION_EXECUTE_HANDLER)
  6284. {
  6285. Status = DumpIdentifyStatus(GetExceptionCode());
  6286. }
  6287. return Status;
  6288. }
  6289. ULONG64
  6290. UserMiniFullDumpTargetInfo::VirtualToOffset(ULONG64 Virt,
  6291. PULONG File, PULONG Avail)
  6292. {
  6293. *File = DUMP_INFO_DUMP;
  6294. if (m_Memory64 == NULL)
  6295. {
  6296. return 0;
  6297. }
  6298. MINIDUMP_MEMORY_DESCRIPTOR64 UNALIGNED *Mem = m_Memory64->MemoryRanges;
  6299. ULONG i;
  6300. ULONG64 Offset = m_Memory64->BaseRva;
  6301. ULONG64 RetOffset = 0;
  6302. __try
  6303. {
  6304. if (m_Machine->m_Ptr64)
  6305. {
  6306. for (i = 0; i < m_Memory64->NumberOfMemoryRanges; i++)
  6307. {
  6308. if (Virt >= Mem->StartOfMemoryRange &&
  6309. Virt < Mem->StartOfMemoryRange + Mem->DataSize)
  6310. {
  6311. ULONG64 Frag = Virt - Mem->StartOfMemoryRange;
  6312. ULONG64 Avail64 = Mem->DataSize - Frag;
  6313. if (Avail64 > 0xffffffff)
  6314. {
  6315. *Avail = 0xffffffff;
  6316. }
  6317. else
  6318. {
  6319. *Avail = (ULONG)Avail64;
  6320. }
  6321. RetOffset = Offset + Frag;
  6322. break;
  6323. }
  6324. Offset += Mem->DataSize;
  6325. Mem++;
  6326. }
  6327. }
  6328. else
  6329. {
  6330. //
  6331. // Ignore any sign extension on a 32-bit dump.
  6332. //
  6333. Virt = (ULONG)Virt;
  6334. for (i = 0; i < m_Memory64->NumberOfMemoryRanges; i++)
  6335. {
  6336. if (Virt >= (ULONG)Mem->StartOfMemoryRange &&
  6337. Virt < (ULONG)(Mem->StartOfMemoryRange + Mem->DataSize))
  6338. {
  6339. ULONG64 Frag = Virt - (ULONG)Mem->StartOfMemoryRange;
  6340. ULONG64 Avail64 = Mem->DataSize - Frag;
  6341. if (Avail64 > 0xffffffff)
  6342. {
  6343. *Avail = 0xffffffff;
  6344. }
  6345. else
  6346. {
  6347. *Avail = (ULONG)Avail64;
  6348. }
  6349. RetOffset = Offset + Frag;
  6350. break;
  6351. }
  6352. Offset += Mem->DataSize;
  6353. Mem++;
  6354. }
  6355. }
  6356. }
  6357. __except(MappingExceptionFilter(GetExceptionInformation()))
  6358. {
  6359. RetOffset = 0;
  6360. }
  6361. return RetOffset;
  6362. }
  6363. //----------------------------------------------------------------------------
  6364. //
  6365. // ModuleInfo implementations.
  6366. //
  6367. //----------------------------------------------------------------------------
  6368. HRESULT
  6369. KernelTriage32ModuleInfo::Initialize(ThreadInfo* Thread)
  6370. {
  6371. InitSource(Thread);
  6372. m_DumpTarget = (KernelTriage32DumpTargetInfo*)m_Target;
  6373. if (m_DumpTarget->m_Dump->Triage.DriverListOffset != 0)
  6374. {
  6375. m_Count = m_DumpTarget->m_Dump->Triage.DriverCount;
  6376. m_Cur = 0;
  6377. return S_OK;
  6378. }
  6379. else
  6380. {
  6381. dprintf("Mini Kernel Dump does not contain driver list\n");
  6382. return S_FALSE;
  6383. }
  6384. }
  6385. HRESULT
  6386. KernelTriage32ModuleInfo::GetEntry(PMODULE_INFO_ENTRY Entry)
  6387. {
  6388. if (m_Cur == m_Count)
  6389. {
  6390. return S_FALSE;
  6391. }
  6392. PDUMP_DRIVER_ENTRY32 DriverEntry;
  6393. PDUMP_STRING DriverName;
  6394. DBG_ASSERT(m_DumpTarget->m_Dump->Triage.DriverListOffset != 0);
  6395. DriverEntry = (PDUMP_DRIVER_ENTRY32)
  6396. m_DumpTarget->IndexRva(m_DumpTarget->m_Dump, (RVA)
  6397. (m_DumpTarget->m_Dump->Triage.DriverListOffset +
  6398. m_Cur * sizeof(*DriverEntry)),
  6399. sizeof(*DriverEntry), "Driver entry");
  6400. if (DriverEntry == NULL)
  6401. {
  6402. return HR_DATA_CORRUPT;
  6403. }
  6404. DriverName = (PDUMP_STRING)
  6405. m_DumpTarget->IndexRva(m_DumpTarget->m_Dump,
  6406. DriverEntry->DriverNameOffset,
  6407. sizeof(*DriverName), "Driver entry name");
  6408. if (DriverName == NULL)
  6409. {
  6410. Entry->NamePtr = NULL;
  6411. Entry->NameLength = 0;
  6412. }
  6413. else
  6414. {
  6415. Entry->NamePtr = (PSTR)DriverName->Buffer;
  6416. Entry->UnicodeNamePtr = 1;
  6417. Entry->NameLength = DriverName->Length * sizeof(WCHAR);
  6418. }
  6419. Entry->Base = EXTEND64(DriverEntry->LdrEntry.DllBase);
  6420. Entry->Size = DriverEntry->LdrEntry.SizeOfImage;
  6421. Entry->ImageInfoValid = TRUE;
  6422. Entry->CheckSum = DriverEntry->LdrEntry.CheckSum;
  6423. Entry->TimeDateStamp = DriverEntry->LdrEntry.TimeDateStamp;
  6424. m_Cur++;
  6425. return S_OK;
  6426. }
  6427. KernelTriage32ModuleInfo g_KernelTriage32ModuleIterator;
  6428. HRESULT
  6429. KernelTriage64ModuleInfo::Initialize(ThreadInfo* Thread)
  6430. {
  6431. InitSource(Thread);
  6432. m_DumpTarget = (KernelTriage64DumpTargetInfo*)m_Target;
  6433. if (m_DumpTarget->m_Dump->Triage.DriverListOffset != 0)
  6434. {
  6435. m_Count = m_DumpTarget->m_Dump->Triage.DriverCount;
  6436. m_Cur = 0;
  6437. return S_OK;
  6438. }
  6439. else
  6440. {
  6441. dprintf("Mini Kernel Dump does not contain driver list\n");
  6442. return S_FALSE;
  6443. }
  6444. }
  6445. HRESULT
  6446. KernelTriage64ModuleInfo::GetEntry(PMODULE_INFO_ENTRY Entry)
  6447. {
  6448. if (m_Cur == m_Count)
  6449. {
  6450. return S_FALSE;
  6451. }
  6452. PDUMP_DRIVER_ENTRY64 DriverEntry;
  6453. PDUMP_STRING DriverName;
  6454. DBG_ASSERT(m_DumpTarget->m_Dump->Triage.DriverListOffset != 0);
  6455. DriverEntry = (PDUMP_DRIVER_ENTRY64)
  6456. m_DumpTarget->IndexRva(m_DumpTarget->m_Dump, (RVA)
  6457. (m_DumpTarget->m_Dump->Triage.DriverListOffset +
  6458. m_Cur * sizeof(*DriverEntry)),
  6459. sizeof(*DriverEntry), "Driver entry");
  6460. if (DriverEntry == NULL)
  6461. {
  6462. return HR_DATA_CORRUPT;
  6463. }
  6464. DriverName = (PDUMP_STRING)
  6465. m_DumpTarget->IndexRva(m_DumpTarget->m_Dump,
  6466. DriverEntry->DriverNameOffset,
  6467. sizeof(*DriverName), "Driver entry name");
  6468. if (DriverName == NULL)
  6469. {
  6470. Entry->NamePtr = NULL;
  6471. Entry->NameLength = 0;
  6472. }
  6473. else
  6474. {
  6475. Entry->NamePtr = (PSTR)DriverName->Buffer;
  6476. Entry->UnicodeNamePtr = 1;
  6477. Entry->NameLength = DriverName->Length * sizeof(WCHAR);
  6478. }
  6479. Entry->Base = DriverEntry->LdrEntry.DllBase;
  6480. Entry->Size = DriverEntry->LdrEntry.SizeOfImage;
  6481. Entry->ImageInfoValid = TRUE;
  6482. Entry->CheckSum = DriverEntry->LdrEntry.CheckSum;
  6483. Entry->TimeDateStamp = DriverEntry->LdrEntry.TimeDateStamp;
  6484. m_Cur++;
  6485. return S_OK;
  6486. }
  6487. KernelTriage64ModuleInfo g_KernelTriage64ModuleIterator;
  6488. HRESULT
  6489. UserFull32ModuleInfo::Initialize(ThreadInfo* Thread)
  6490. {
  6491. InitSource(Thread);
  6492. m_DumpTarget = (UserFull32DumpTargetInfo*)m_Target;
  6493. if (m_DumpTarget->m_Header->ModuleOffset &&
  6494. m_DumpTarget->m_Header->ModuleCount)
  6495. {
  6496. m_Offset = m_DumpTarget->m_Header->ModuleOffset;
  6497. m_Count = m_DumpTarget->m_Header->ModuleCount;
  6498. m_Cur = 0;
  6499. return S_OK;
  6500. }
  6501. else
  6502. {
  6503. m_Offset = 0;
  6504. m_Count = 0;
  6505. m_Cur = 0;
  6506. dprintf("User Mode Full Dump does not have a module list\n");
  6507. return S_FALSE;
  6508. }
  6509. }
  6510. HRESULT
  6511. UserFull32ModuleInfo::GetEntry(PMODULE_INFO_ENTRY Entry)
  6512. {
  6513. if (m_Cur == m_Count)
  6514. {
  6515. return S_FALSE;
  6516. }
  6517. CRASH_MODULE32 CrashModule;
  6518. if (m_DumpTarget->m_InfoFiles[DUMP_INFO_DUMP].
  6519. ReadFileOffset(m_Offset, &CrashModule, sizeof(CrashModule)) !=
  6520. sizeof(CrashModule))
  6521. {
  6522. return HR_DATA_CORRUPT;
  6523. }
  6524. if (CrashModule.ImageNameLength >= MAX_IMAGE_PATH ||
  6525. m_DumpTarget->m_InfoFiles[DUMP_INFO_DUMP].
  6526. ReadFileOffset(m_Offset + FIELD_OFFSET(CRASH_MODULE32, ImageName),
  6527. Entry->Buffer, CrashModule.ImageNameLength) !=
  6528. CrashModule.ImageNameLength)
  6529. {
  6530. Entry->NamePtr = NULL;
  6531. Entry->NameLength = 0;
  6532. }
  6533. else
  6534. {
  6535. Entry->NamePtr = (PSTR)Entry->Buffer;
  6536. Entry->NameLength = CrashModule.ImageNameLength - 1;
  6537. }
  6538. Entry->Base = EXTEND64(CrashModule.BaseOfImage);
  6539. Entry->Size = CrashModule.SizeOfImage;
  6540. m_Cur++;
  6541. m_Offset += sizeof(CrashModule) + CrashModule.ImageNameLength;
  6542. return S_OK;
  6543. }
  6544. UserFull32ModuleInfo g_UserFull32ModuleIterator;
  6545. HRESULT
  6546. UserFull64ModuleInfo::Initialize(ThreadInfo* Thread)
  6547. {
  6548. InitSource(Thread);
  6549. m_DumpTarget = (UserFull64DumpTargetInfo*)m_Target;
  6550. if (m_DumpTarget->m_Header->ModuleOffset &&
  6551. m_DumpTarget->m_Header->ModuleCount)
  6552. {
  6553. m_Offset = m_DumpTarget->m_Header->ModuleOffset;
  6554. m_Count = m_DumpTarget->m_Header->ModuleCount;
  6555. m_Cur = 0;
  6556. return S_OK;
  6557. }
  6558. else
  6559. {
  6560. m_Offset = 0;
  6561. m_Count = 0;
  6562. m_Cur = 0;
  6563. dprintf("User Mode Full Dump does not have a module list\n");
  6564. return S_FALSE;
  6565. }
  6566. }
  6567. HRESULT
  6568. UserFull64ModuleInfo::GetEntry(PMODULE_INFO_ENTRY Entry)
  6569. {
  6570. if (m_Cur == m_Count)
  6571. {
  6572. return S_FALSE;
  6573. }
  6574. CRASH_MODULE64 CrashModule;
  6575. if (m_DumpTarget->m_InfoFiles[DUMP_INFO_DUMP].
  6576. ReadFileOffset(m_Offset, &CrashModule, sizeof(CrashModule)) !=
  6577. sizeof(CrashModule))
  6578. {
  6579. return HR_DATA_CORRUPT;
  6580. }
  6581. if (CrashModule.ImageNameLength >= MAX_IMAGE_PATH ||
  6582. m_DumpTarget->m_InfoFiles[DUMP_INFO_DUMP].
  6583. ReadFileOffset(m_Offset + FIELD_OFFSET(CRASH_MODULE64, ImageName),
  6584. Entry->Buffer, CrashModule.ImageNameLength) !=
  6585. CrashModule.ImageNameLength)
  6586. {
  6587. Entry->NamePtr = NULL;
  6588. Entry->NameLength = 0;
  6589. }
  6590. else
  6591. {
  6592. Entry->NamePtr = (PSTR)Entry->Buffer;
  6593. Entry->NameLength = CrashModule.ImageNameLength - 1;
  6594. }
  6595. Entry->Base = CrashModule.BaseOfImage;
  6596. Entry->Size = CrashModule.SizeOfImage;
  6597. m_Cur++;
  6598. m_Offset += sizeof(CrashModule) + CrashModule.ImageNameLength;
  6599. return S_OK;
  6600. }
  6601. UserFull64ModuleInfo g_UserFull64ModuleIterator;
  6602. HRESULT
  6603. UserMiniModuleInfo::Initialize(ThreadInfo* Thread)
  6604. {
  6605. InitSource(Thread);
  6606. m_DumpTarget = (UserMiniDumpTargetInfo*)m_Target;
  6607. if (m_DumpTarget->m_Modules != NULL)
  6608. {
  6609. m_Count = m_DumpTarget->m_Modules->NumberOfModules;
  6610. m_Cur = 0;
  6611. return S_OK;
  6612. }
  6613. else
  6614. {
  6615. m_Count = 0;
  6616. m_Cur = 0;
  6617. dprintf("User Mode Mini Dump does not have a module list\n");
  6618. return S_FALSE;
  6619. }
  6620. }
  6621. HRESULT
  6622. UserMiniModuleInfo::GetEntry(PMODULE_INFO_ENTRY Entry)
  6623. {
  6624. if (m_Cur == m_Count)
  6625. {
  6626. return S_FALSE;
  6627. }
  6628. MINIDUMP_MODULE UNALIGNED *Mod;
  6629. MINIDUMP_STRING UNALIGNED *ModName;
  6630. DBG_ASSERT(m_DumpTarget->m_Modules != NULL);
  6631. Mod = m_DumpTarget->m_Modules->Modules + m_Cur;
  6632. ModName = (MINIDUMP_STRING UNALIGNED *)
  6633. m_DumpTarget->IndexRva(m_DumpTarget->m_Header,
  6634. Mod->ModuleNameRva, sizeof(*ModName),
  6635. "Module entry name");
  6636. if (ModName == NULL)
  6637. {
  6638. Entry->NamePtr = NULL;
  6639. Entry->NameLength = 0;
  6640. }
  6641. else
  6642. {
  6643. memcpy(Entry->Buffer, (VOID * UNALIGNED) ModName->Buffer, sizeof(Entry->Buffer));
  6644. Entry->Buffer[sizeof(Entry->Buffer)/sizeof(WCHAR)-1] = 0;
  6645. Entry->NamePtr = (PSTR)Entry->Buffer;
  6646. Entry->UnicodeNamePtr = 1;
  6647. Entry->NameLength = ModName->Length;
  6648. }
  6649. // Some dumps do not have properly sign-extended addresses,
  6650. // so force the extension on 32-bit platforms.
  6651. if (!m_Machine->m_Ptr64)
  6652. {
  6653. Entry->Base = EXTEND64(Mod->BaseOfImage);
  6654. }
  6655. else
  6656. {
  6657. Entry->Base = Mod->BaseOfImage;
  6658. }
  6659. Entry->Size = Mod->SizeOfImage;
  6660. Entry->ImageInfoValid = TRUE;
  6661. Entry->CheckSum = Mod->CheckSum;
  6662. Entry->TimeDateStamp = Mod->TimeDateStamp;
  6663. m_Cur++;
  6664. return S_OK;
  6665. }
  6666. UserMiniModuleInfo g_UserMiniModuleIterator;
  6667. HRESULT
  6668. UserMiniUnloadedModuleInfo::Initialize(ThreadInfo* Thread)
  6669. {
  6670. InitSource(Thread);
  6671. m_DumpTarget = (UserMiniDumpTargetInfo*)m_Target;
  6672. if (m_DumpTarget->m_UnlModules)
  6673. {
  6674. m_Index = 0;
  6675. return S_OK;
  6676. }
  6677. else
  6678. {
  6679. // Don't display a message as this is a common case.
  6680. return S_FALSE;
  6681. }
  6682. }
  6683. HRESULT
  6684. UserMiniUnloadedModuleInfo::GetEntry(PSTR Name,
  6685. PDEBUG_MODULE_PARAMETERS Params)
  6686. {
  6687. if (m_Index >= m_DumpTarget->m_UnlModules->NumberOfEntries)
  6688. {
  6689. return S_FALSE;
  6690. }
  6691. MINIDUMP_UNLOADED_MODULE UNALIGNED * Mod =
  6692. (MINIDUMP_UNLOADED_MODULE UNALIGNED *)
  6693. m_DumpTarget->
  6694. IndexRva(m_DumpTarget->m_Header,
  6695. (RVA)((PUCHAR)m_DumpTarget->m_UnlModules -
  6696. (PUCHAR)m_DumpTarget->m_Header) +
  6697. m_DumpTarget->m_UnlModules->SizeOfHeader +
  6698. m_DumpTarget->m_UnlModules->SizeOfEntry * m_Index,
  6699. sizeof(*Mod), "Unloaded module entry");
  6700. if (Mod == NULL)
  6701. {
  6702. return HR_DATA_CORRUPT;
  6703. }
  6704. ZeroMemory(Params, sizeof(*Params));
  6705. Params->Base = Mod->BaseOfImage;
  6706. Params->Size = Mod->SizeOfImage;
  6707. Params->TimeDateStamp = Mod->TimeDateStamp;
  6708. Params->Checksum = Mod->CheckSum;
  6709. Params->Flags = DEBUG_MODULE_UNLOADED;
  6710. if (Name != NULL)
  6711. {
  6712. MINIDUMP_STRING UNALIGNED * ModName = (MINIDUMP_STRING UNALIGNED *)
  6713. m_DumpTarget->IndexRva(m_DumpTarget->m_Header,
  6714. Mod->ModuleNameRva, sizeof(*ModName),
  6715. "Unloaded module entry name");
  6716. if (ModName == NULL)
  6717. {
  6718. UnknownImageName(Mod->BaseOfImage, Name, MAX_INFO_UNLOADED_NAME);
  6719. }
  6720. else
  6721. {
  6722. ConvertAndValidateImagePathW((PWSTR)ModName->Buffer,
  6723. wcslen((PWSTR)ModName->Buffer),
  6724. Mod->BaseOfImage,
  6725. Name,
  6726. MAX_INFO_UNLOADED_NAME);
  6727. }
  6728. }
  6729. m_Index++;
  6730. return S_OK;
  6731. }
  6732. UserMiniUnloadedModuleInfo g_UserMiniUnloadedModuleIterator;
  6733. HRESULT
  6734. KernelTriage32UnloadedModuleInfo::Initialize(ThreadInfo* Thread)
  6735. {
  6736. InitSource(Thread);
  6737. m_DumpTarget = (KernelTriage32DumpTargetInfo*)m_Target;
  6738. if (m_DumpTarget->m_Dump->Triage.UnloadedDriversOffset != 0)
  6739. {
  6740. PVOID Data = m_DumpTarget->IndexRva
  6741. (m_DumpTarget->m_Dump,
  6742. m_DumpTarget->m_Dump->Triage.UnloadedDriversOffset,
  6743. sizeof(ULONG), "Unloaded driver list");
  6744. if (!Data)
  6745. {
  6746. return HR_DATA_CORRUPT;
  6747. }
  6748. m_Cur = (PDUMP_UNLOADED_DRIVERS32)((PULONG)Data + 1);
  6749. m_End = m_Cur + *(PULONG)Data;
  6750. return S_OK;
  6751. }
  6752. else
  6753. {
  6754. dprintf("Mini Kernel Dump does not contain unloaded driver list\n");
  6755. return S_FALSE;
  6756. }
  6757. }
  6758. HRESULT
  6759. KernelTriage32UnloadedModuleInfo::GetEntry(PSTR Name,
  6760. PDEBUG_MODULE_PARAMETERS Params)
  6761. {
  6762. if (m_Cur == m_End)
  6763. {
  6764. return S_FALSE;
  6765. }
  6766. ZeroMemory(Params, sizeof(*Params));
  6767. Params->Base = EXTEND64(m_Cur->StartAddress);
  6768. Params->Size = m_Cur->EndAddress - m_Cur->StartAddress;
  6769. Params->Flags = DEBUG_MODULE_UNLOADED;
  6770. if (Name != NULL)
  6771. {
  6772. USHORT NameLen = m_Cur->Name.Length;
  6773. if (NameLen > MAX_UNLOADED_NAME_LENGTH)
  6774. {
  6775. NameLen = MAX_UNLOADED_NAME_LENGTH;
  6776. }
  6777. ConvertAndValidateImagePathW(m_Cur->DriverName,
  6778. NameLen / sizeof(WCHAR),
  6779. Params->Base,
  6780. Name,
  6781. MAX_INFO_UNLOADED_NAME);
  6782. }
  6783. m_Cur++;
  6784. return S_OK;
  6785. }
  6786. KernelTriage32UnloadedModuleInfo g_KernelTriage32UnloadedModuleIterator;
  6787. HRESULT
  6788. KernelTriage64UnloadedModuleInfo::Initialize(ThreadInfo* Thread)
  6789. {
  6790. InitSource(Thread);
  6791. m_DumpTarget = (KernelTriage64DumpTargetInfo*)m_Target;
  6792. if (m_DumpTarget->m_Dump->Triage.UnloadedDriversOffset != 0)
  6793. {
  6794. PVOID Data = m_DumpTarget->IndexRva
  6795. (m_DumpTarget->m_Dump,
  6796. m_DumpTarget->m_Dump->Triage.UnloadedDriversOffset,
  6797. sizeof(ULONG), "Unloaded driver list");
  6798. if (!Data)
  6799. {
  6800. return HR_DATA_CORRUPT;
  6801. }
  6802. m_Cur = (PDUMP_UNLOADED_DRIVERS64)((PULONG64)Data + 1);
  6803. m_End = m_Cur + *(PULONG)Data;
  6804. return S_OK;
  6805. }
  6806. else
  6807. {
  6808. dprintf("Mini Kernel Dump does not contain unloaded driver list\n");
  6809. return S_FALSE;
  6810. }
  6811. }
  6812. HRESULT
  6813. KernelTriage64UnloadedModuleInfo::GetEntry(PSTR Name,
  6814. PDEBUG_MODULE_PARAMETERS Params)
  6815. {
  6816. if (m_Cur == m_End)
  6817. {
  6818. return S_FALSE;
  6819. }
  6820. ZeroMemory(Params, sizeof(*Params));
  6821. Params->Base = m_Cur->StartAddress;
  6822. Params->Size = (ULONG)(m_Cur->EndAddress - m_Cur->StartAddress);
  6823. Params->Flags = DEBUG_MODULE_UNLOADED;
  6824. if (Name != NULL)
  6825. {
  6826. USHORT NameLen = m_Cur->Name.Length;
  6827. if (NameLen > MAX_UNLOADED_NAME_LENGTH)
  6828. {
  6829. NameLen = MAX_UNLOADED_NAME_LENGTH;
  6830. }
  6831. ConvertAndValidateImagePathW(m_Cur->DriverName,
  6832. NameLen / sizeof(WCHAR),
  6833. Params->Base,
  6834. Name,
  6835. MAX_INFO_UNLOADED_NAME);
  6836. }
  6837. m_Cur++;
  6838. return S_OK;
  6839. }
  6840. KernelTriage64UnloadedModuleInfo g_KernelTriage64UnloadedModuleIterator;