Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6694 lines
184 KiB

  1. /*++
  2. Copyright (c) 1990-2001 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 HR_DUMP_CORRUPT HRESULT_FROM_WIN32(ERROR_FILE_CORRUPT)
  29. #define DUMP_INITIAL_VIEW_SIZE (1024 * 1024)
  30. #define DUMP_MAXIMUM_VIEW_SIZE (256 * 1024 * 1024)
  31. typedef ULONG PFN_NUMBER32;
  32. //
  33. // Page file dump file information.
  34. //
  35. #define DMPPF_IDENTIFIER "PAGE.DMP"
  36. #define DMPPF_PAGE_NOT_PRESENT 0xffffffff
  37. struct DMPPF_PAGE_FILE_INFO
  38. {
  39. ULONG Size;
  40. ULONG MaximumSize;
  41. };
  42. // Left to its own devices the compiler will add a
  43. // ULONG of padding at the end of this structure to
  44. // keep it an even ULONG64 multiple in size. Force
  45. // it to consider only the declared items.
  46. #pragma pack(4)
  47. struct DMPPF_FILE_HEADER
  48. {
  49. char Id[8];
  50. LARGE_INTEGER BootTime;
  51. ULONG PageData;
  52. DMPPF_PAGE_FILE_INFO PageFiles[16];
  53. };
  54. #pragma pack()
  55. KernelSummary32DumpTargetInfo g_KernelSummary32DumpTarget;
  56. KernelSummary64DumpTargetInfo g_KernelSummary64DumpTarget;
  57. KernelTriage32DumpTargetInfo g_KernelTriage32DumpTarget;
  58. KernelTriage64DumpTargetInfo g_KernelTriage64DumpTarget;
  59. KernelFull32DumpTargetInfo g_KernelFull32DumpTarget;
  60. KernelFull64DumpTargetInfo g_KernelFull64DumpTarget;
  61. UserFull32DumpTargetInfo g_UserFull32DumpTarget;
  62. UserFull64DumpTargetInfo g_UserFull64DumpTarget;
  63. UserMiniPartialDumpTargetInfo g_UserMiniPartialDumpTarget;
  64. UserMiniFullDumpTargetInfo g_UserMiniFullDumpTarget;
  65. // Indexed by DTYPE.
  66. DumpTargetInfo* g_DumpTargets[DTYPE_COUNT] =
  67. {
  68. &g_KernelSummary32DumpTarget,
  69. &g_KernelSummary64DumpTarget,
  70. &g_KernelTriage32DumpTarget,
  71. &g_KernelTriage64DumpTarget,
  72. &g_KernelFull32DumpTarget,
  73. &g_KernelFull64DumpTarget,
  74. &g_UserFull32DumpTarget,
  75. &g_UserFull64DumpTarget,
  76. &g_UserMiniPartialDumpTarget,
  77. &g_UserMiniFullDumpTarget,
  78. };
  79. // Set this value to track down page numbers and contents of a virtual address
  80. // in a dump file.
  81. // Initialized to an address no one will look for.
  82. ULONG64 g_DebugDump_VirtualAddress = 12344321;
  83. //
  84. // Globals
  85. //
  86. #define IndexByByte(Pointer, Index) (&(((CHAR*) (Pointer))) [Index])
  87. #define RtlCheckBit(BMH,BP) ((((BMH)->Buffer[(BP) / 32]) >> ((BP) % 32)) & 0x1)
  88. ULONG64 g_DumpKiProcessors[MAXIMUM_PROCESSORS];
  89. ULONG64 g_DumpKiPcrBaseAddress;
  90. BOOL g_TriageDumpHasDebuggerData;
  91. DTYPE g_DumpType = DTYPE_COUNT;
  92. ULONG g_DumpFormatFlags;
  93. EXCEPTION_RECORD64 g_DumpException;
  94. ULONG g_DumpExceptionFirstChance;
  95. //
  96. // MM Triage information.
  97. //
  98. struct MM_TRIAGE_TRANSLATION
  99. {
  100. ULONG DebuggerDataOffset;
  101. ULONG Triage32Offset;
  102. ULONG Triage64Offset;
  103. ULONG PtrSize:1;
  104. };
  105. MM_TRIAGE_TRANSLATION g_MmTriageTranslations[] =
  106. {
  107. FIELD_OFFSET(KDDEBUGGER_DATA64, MmSpecialPoolTag),
  108. FIELD_OFFSET(DUMP_MM_STORAGE32, MmSpecialPoolTag),
  109. FIELD_OFFSET(DUMP_MM_STORAGE64, MmSpecialPoolTag),
  110. FALSE,
  111. FIELD_OFFSET(KDDEBUGGER_DATA64, MmTriageActionTaken),
  112. FIELD_OFFSET(DUMP_MM_STORAGE32, MiTriageActionTaken),
  113. FIELD_OFFSET(DUMP_MM_STORAGE64, MiTriageActionTaken),
  114. FALSE,
  115. FIELD_OFFSET(KDDEBUGGER_DATA64, KernelVerifier),
  116. FIELD_OFFSET(DUMP_MM_STORAGE32, KernelVerifier),
  117. FIELD_OFFSET(DUMP_MM_STORAGE64, KernelVerifier),
  118. FALSE,
  119. FIELD_OFFSET(KDDEBUGGER_DATA64, MmAllocatedNonPagedPool),
  120. FIELD_OFFSET(DUMP_MM_STORAGE32, MmAllocatedNonPagedPool),
  121. FIELD_OFFSET(DUMP_MM_STORAGE64, MmAllocatedNonPagedPool),
  122. TRUE,
  123. FIELD_OFFSET(KDDEBUGGER_DATA64, MmTotalCommittedPages),
  124. FIELD_OFFSET(DUMP_MM_STORAGE32, CommittedPages),
  125. FIELD_OFFSET(DUMP_MM_STORAGE64, CommittedPages),
  126. TRUE,
  127. FIELD_OFFSET(KDDEBUGGER_DATA64, MmPeakCommitment),
  128. FIELD_OFFSET(DUMP_MM_STORAGE32, CommittedPagesPeak),
  129. FIELD_OFFSET(DUMP_MM_STORAGE64, CommittedPagesPeak),
  130. TRUE,
  131. FIELD_OFFSET(KDDEBUGGER_DATA64, MmTotalCommitLimitMaximum),
  132. FIELD_OFFSET(DUMP_MM_STORAGE32, CommitLimitMaximum),
  133. FIELD_OFFSET(DUMP_MM_STORAGE64, CommitLimitMaximum),
  134. TRUE,
  135. #if 0
  136. // These MM triage fields are in pages while the corresponding
  137. // debugger data fields are in bytes. There's no way to
  138. // directly map one to the other.
  139. FIELD_OFFSET(KDDEBUGGER_DATA64, MmMaximumNonPagedPoolInBytes),
  140. FIELD_OFFSET(DUMP_MM_STORAGE32, MmMaximumNonPagedPool),
  141. FIELD_OFFSET(DUMP_MM_STORAGE64, MmMaximumNonPagedPool),
  142. TRUE,
  143. FIELD_OFFSET(KDDEBUGGER_DATA64, MmSizeOfPagedPoolInBytes),
  144. FIELD_OFFSET(DUMP_MM_STORAGE32, PagedPoolMaximum),
  145. FIELD_OFFSET(DUMP_MM_STORAGE64, PagedPoolMaximum),
  146. TRUE,
  147. #endif
  148. 0, 0, 0, 0, 0,
  149. };
  150. //
  151. // Internal globals.
  152. //
  153. struct DUMP_INFO_FILE
  154. {
  155. HANDLE File;
  156. ULONG64 FileSize;
  157. HANDLE Map;
  158. PVOID MapBase;
  159. ULONG MapSize;
  160. //
  161. // If a page is dirty, it will stay in the cache indefinitely.
  162. // A maximum of MAX_CLEAN_PAGE_RECORD clean pages are kept in
  163. // the LRU list.
  164. //
  165. ULONG ActiveCleanPages;
  166. //
  167. // Cache may be cleaned up after use and reinitialized later.
  168. // This flag records its current state.
  169. //
  170. BOOL Initialized;
  171. //
  172. // This is a list of all mapped pages, dirty and clean.
  173. // This list is not intended to get very big: the page finder
  174. // searches it, so it is not a good data structure for a large
  175. // list. It is expected that MAX_CLEAN_PAGE_RECORD will be a
  176. // small number, and that there aren't going to be very many
  177. // pages dirtied in a typical debugging session, so this will
  178. // work well.
  179. //
  180. LIST_ENTRY InFileOrderList;
  181. //
  182. // This is a list of all clean pages. When the list is full
  183. // and a new page is mapped, the oldest page will be discarded.
  184. //
  185. LIST_ENTRY InLRUOrderList;
  186. };
  187. typedef DUMP_INFO_FILE* PDUMP_INFO_FILE;
  188. DUMP_INFO_FILE g_DumpInfoFiles[DUMP_INFO_COUNT];
  189. PVOID g_DumpBase;
  190. //
  191. // Cache manager
  192. //
  193. // A dump file may be larger than can be mapped into the
  194. // debugger's address space, so we use a simple cached
  195. // paging method to access the data area.
  196. //
  197. //
  198. // Allocation granularity for cache. This will be the
  199. // allocation granularity for the system hosting the
  200. // debugger and not for the system which produced the dump.
  201. //
  202. ULONG g_DumpCacheGranularity;
  203. //
  204. // Cache structure
  205. //
  206. typedef struct _DUMPFILE_CACHE_RECORD
  207. {
  208. LIST_ENTRY InFileOrderList;
  209. LIST_ENTRY InLRUOrderList;
  210. //
  211. // Base address of mapped region.
  212. //
  213. PVOID MappedAddress;
  214. //
  215. // File page number of mapped region. pages are of
  216. // size == FileCacheData.Granularity.
  217. //
  218. // The virtual address of a page is not stored; it is
  219. // translated into a page number by the read routines
  220. // and all access is by page number.
  221. //
  222. ULONG64 PageNumber;
  223. //
  224. // A page may be locked into the cache, either because it is used
  225. // frequently or because it has been modified.
  226. //
  227. BOOL Locked;
  228. } DUMPFILE_CACHE_RECORD, *PDUMPFILE_CACHE_RECORD;
  229. #define MAX_CLEAN_PAGE_RECORD 4
  230. void
  231. DmppDumpFileCacheInit(PDUMP_INFO_FILE File)
  232. {
  233. File->ActiveCleanPages = 0;
  234. InitializeListHead(&File->InFileOrderList);
  235. InitializeListHead(&File->InLRUOrderList);
  236. File->Initialized = TRUE;
  237. }
  238. VOID
  239. DmppDumpFileCacheEmpty(PDUMP_INFO_FILE File)
  240. {
  241. PLIST_ENTRY Next;
  242. PDUMPFILE_CACHE_RECORD CacheRecord;
  243. Next = File->InFileOrderList.Flink;
  244. while (Next != &File->InFileOrderList)
  245. {
  246. CacheRecord = CONTAINING_RECORD(Next,
  247. DUMPFILE_CACHE_RECORD,
  248. InFileOrderList);
  249. Next = Next->Flink;
  250. UnmapViewOfFile(CacheRecord->MappedAddress);
  251. free (CacheRecord);
  252. }
  253. File->ActiveCleanPages = 0;
  254. InitializeListHead(&File->InFileOrderList);
  255. InitializeListHead(&File->InLRUOrderList);
  256. }
  257. VOID
  258. DmppDumpFileCacheCleanup(PDUMP_INFO_FILE File)
  259. {
  260. if (File->Initialized)
  261. {
  262. File->Initialized = FALSE;
  263. DmppDumpFileCacheEmpty(File);
  264. }
  265. }
  266. PDUMPFILE_CACHE_RECORD
  267. DmppReuseOldestCacheRecord(PDUMP_INFO_FILE File, ULONG64 FileByteOffset)
  268. {
  269. PDUMPFILE_CACHE_RECORD CacheRecord;
  270. PLIST_ENTRY Next;
  271. PVOID MappedAddress;
  272. ULONG64 MapOffset;
  273. ULONG Size;
  274. MapOffset = FileByteOffset & ~((ULONG64)g_DumpCacheGranularity - 1);
  275. if ((File->FileSize - MapOffset) < g_DumpCacheGranularity)
  276. {
  277. Size = (ULONG)(File->FileSize - MapOffset);
  278. }
  279. else
  280. {
  281. Size = g_DumpCacheGranularity;
  282. }
  283. MappedAddress = MapViewOfFile(File->Map, FILE_MAP_READ,
  284. (DWORD)(MapOffset >> 32),
  285. (DWORD)MapOffset, Size);
  286. if (MappedAddress == NULL)
  287. {
  288. return NULL;
  289. }
  290. Next = File->InLRUOrderList.Flink;
  291. CacheRecord = CONTAINING_RECORD(Next,
  292. DUMPFILE_CACHE_RECORD,
  293. InLRUOrderList);
  294. UnmapViewOfFile(CacheRecord->MappedAddress);
  295. CacheRecord->PageNumber = FileByteOffset / g_DumpCacheGranularity;
  296. CacheRecord->MappedAddress = MappedAddress;
  297. //
  298. // Move record to end of LRU
  299. //
  300. RemoveEntryList(Next);
  301. InsertTailList(&File->InLRUOrderList, Next);
  302. //
  303. // Move record to correct place in ordered list
  304. //
  305. RemoveEntryList(&CacheRecord->InFileOrderList);
  306. Next = File->InFileOrderList.Flink;
  307. while (Next != &File->InFileOrderList)
  308. {
  309. PDUMPFILE_CACHE_RECORD NextCacheRecord;
  310. NextCacheRecord = CONTAINING_RECORD(Next,
  311. DUMPFILE_CACHE_RECORD,
  312. InFileOrderList);
  313. if (CacheRecord->PageNumber < NextCacheRecord->PageNumber)
  314. {
  315. break;
  316. }
  317. Next = Next->Flink;
  318. }
  319. InsertTailList(Next, &CacheRecord->InFileOrderList);
  320. return CacheRecord;
  321. }
  322. PDUMPFILE_CACHE_RECORD
  323. DmppFindCacheRecordForFileByteOffset(PDUMP_INFO_FILE File,
  324. ULONG64 FileByteOffset)
  325. {
  326. PDUMPFILE_CACHE_RECORD CacheRecord;
  327. PLIST_ENTRY Next;
  328. ULONG64 PageNumber;
  329. PageNumber = FileByteOffset / g_DumpCacheGranularity;
  330. Next = File->InFileOrderList.Flink;
  331. while (Next != &File->InFileOrderList)
  332. {
  333. CacheRecord = CONTAINING_RECORD(Next,
  334. DUMPFILE_CACHE_RECORD,
  335. InFileOrderList);
  336. if (CacheRecord->PageNumber < PageNumber)
  337. {
  338. Next = Next->Flink;
  339. }
  340. else if (CacheRecord->PageNumber == PageNumber)
  341. {
  342. if (!CacheRecord->Locked)
  343. {
  344. RemoveEntryList(&CacheRecord->InLRUOrderList);
  345. InsertTailList(&File->InLRUOrderList,
  346. &CacheRecord->InLRUOrderList);
  347. }
  348. return CacheRecord;
  349. }
  350. else
  351. {
  352. break;
  353. }
  354. }
  355. //
  356. // Can't find it in cache.
  357. //
  358. return NULL;
  359. }
  360. PDUMPFILE_CACHE_RECORD
  361. DmppCreateNewFileCacheRecord(PDUMP_INFO_FILE File, ULONG64 FileByteOffset)
  362. {
  363. PDUMPFILE_CACHE_RECORD CacheRecord;
  364. PDUMPFILE_CACHE_RECORD NextCacheRecord;
  365. PLIST_ENTRY Next;
  366. ULONG64 MapOffset;
  367. ULONG Size;
  368. CacheRecord = (PDUMPFILE_CACHE_RECORD)malloc(sizeof(*CacheRecord));
  369. if (CacheRecord == NULL)
  370. {
  371. return NULL;
  372. }
  373. ZeroMemory(CacheRecord, sizeof(*CacheRecord));
  374. MapOffset = (FileByteOffset / g_DumpCacheGranularity) *
  375. g_DumpCacheGranularity;
  376. if ((File->FileSize - MapOffset) < g_DumpCacheGranularity)
  377. {
  378. Size = (ULONG)(File->FileSize - MapOffset);
  379. }
  380. else
  381. {
  382. Size = g_DumpCacheGranularity;
  383. }
  384. CacheRecord->MappedAddress = MapViewOfFile(File->Map, FILE_MAP_READ,
  385. (DWORD)(MapOffset >> 32),
  386. (DWORD)MapOffset, Size);
  387. if (CacheRecord->MappedAddress == NULL)
  388. {
  389. free(CacheRecord);
  390. return NULL;
  391. }
  392. CacheRecord->PageNumber = FileByteOffset / g_DumpCacheGranularity;
  393. //
  394. // Insert new record in file order list
  395. //
  396. Next = File->InFileOrderList.Flink;
  397. while (Next != &File->InFileOrderList)
  398. {
  399. NextCacheRecord = CONTAINING_RECORD(Next,
  400. DUMPFILE_CACHE_RECORD,
  401. InFileOrderList);
  402. if (CacheRecord->PageNumber < NextCacheRecord->PageNumber)
  403. {
  404. break;
  405. }
  406. Next = Next->Flink;
  407. }
  408. InsertTailList(Next, &CacheRecord->InFileOrderList);
  409. //
  410. // Insert new record at tail of LRU list
  411. //
  412. InsertTailList(&File->InLRUOrderList,
  413. &CacheRecord->InLRUOrderList);
  414. return CacheRecord;
  415. }
  416. PUCHAR
  417. DmppFileOffsetToMappedAddress(IN PDUMP_INFO_FILE File,
  418. IN ULONG64 FileOffset,
  419. IN BOOL LockCacheRecord,
  420. OUT PULONG Avail)
  421. {
  422. PDUMPFILE_CACHE_RECORD CacheRecord;
  423. ULONG64 FileByteOffset;
  424. if (FileOffset == 0)
  425. {
  426. return NULL;
  427. }
  428. // The base view covers the beginning of the file.
  429. if (FileOffset < File->MapSize)
  430. {
  431. *Avail = (ULONG)(File->MapSize - FileOffset);
  432. return (PUCHAR)File->MapBase + FileOffset;
  433. }
  434. FileByteOffset = FileOffset;
  435. CacheRecord = DmppFindCacheRecordForFileByteOffset(File, FileByteOffset);
  436. if (CacheRecord == NULL)
  437. {
  438. if (File->ActiveCleanPages < MAX_CLEAN_PAGE_RECORD)
  439. {
  440. CacheRecord = DmppCreateNewFileCacheRecord(File, FileByteOffset);
  441. if (CacheRecord)
  442. {
  443. File->ActiveCleanPages++;
  444. }
  445. }
  446. else
  447. {
  448. //
  449. // too many pages cached in
  450. // overwrite existing cache
  451. //
  452. CacheRecord = DmppReuseOldestCacheRecord(File, FileByteOffset);
  453. }
  454. }
  455. if (CacheRecord == NULL)
  456. {
  457. return NULL;
  458. }
  459. else
  460. {
  461. if (LockCacheRecord && !CacheRecord->Locked)
  462. {
  463. RemoveEntryList(&CacheRecord->InLRUOrderList);
  464. CacheRecord->Locked = TRUE;
  465. File->ActiveCleanPages--;
  466. }
  467. ULONG PageRemainder =
  468. (ULONG)(FileByteOffset & (g_DumpCacheGranularity - 1));
  469. *Avail = g_DumpCacheGranularity - PageRemainder;
  470. return ((PUCHAR)CacheRecord->MappedAddress) + PageRemainder;
  471. }
  472. }
  473. ULONG
  474. DmppReadFileOffset(ULONG FileIndex,
  475. ULONG64 Offset, PVOID Buffer, ULONG BufferSize)
  476. {
  477. ULONG Done = 0;
  478. ULONG Avail;
  479. PUCHAR Mapping;
  480. PDUMP_INFO_FILE File = &g_DumpInfoFiles[FileIndex];
  481. if (File->File == NULL)
  482. {
  483. // Information for this kind of file wasn't provided.
  484. return 0;
  485. }
  486. __try
  487. {
  488. while (BufferSize > 0)
  489. {
  490. Mapping = DmppFileOffsetToMappedAddress(File, Offset, FALSE,
  491. &Avail);
  492. if (Mapping == NULL)
  493. {
  494. break;
  495. }
  496. if (Avail > BufferSize)
  497. {
  498. Avail = BufferSize;
  499. }
  500. memcpy(Buffer, Mapping, Avail);
  501. Offset += Avail;
  502. Buffer = (PUCHAR)Buffer + Avail;
  503. BufferSize -= Avail;
  504. Done += Avail;
  505. }
  506. }
  507. __except(MappingExceptionFilter(GetExceptionInformation()))
  508. {
  509. Done = 0;
  510. }
  511. return Done;
  512. }
  513. ULONG
  514. DmppWriteFileOffset(ULONG FileIndex,
  515. ULONG64 Offset, PVOID Buffer, ULONG BufferSize)
  516. {
  517. ULONG Done = 0;
  518. ULONG Avail;
  519. PUCHAR Mapping;
  520. ULONG Protect;
  521. PDUMP_INFO_FILE File = &g_DumpInfoFiles[FileIndex];
  522. if (File->File == NULL)
  523. {
  524. // Information for this kind of file wasn't provided.
  525. return 0;
  526. }
  527. __try
  528. {
  529. while (BufferSize > 0)
  530. {
  531. Mapping = DmppFileOffsetToMappedAddress(File, Offset, TRUE,
  532. &Avail);
  533. if (Mapping == NULL)
  534. {
  535. break;
  536. }
  537. if (Avail > BufferSize)
  538. {
  539. Avail = BufferSize;
  540. }
  541. VirtualProtect(Mapping, Avail, PAGE_WRITECOPY, &Protect);
  542. memcpy(Mapping, Buffer, Avail);
  543. Offset += Avail;
  544. Buffer = (PUCHAR)Buffer + Avail;
  545. BufferSize -= Avail;
  546. Done += Avail;
  547. }
  548. }
  549. __except(MappingExceptionFilter(GetExceptionInformation()))
  550. {
  551. Done = 0;
  552. }
  553. return Done;
  554. }
  555. HRESULT
  556. AddDumpInfoFile(PCSTR FileName, ULONG Index, ULONG InitialView)
  557. {
  558. HRESULT Status;
  559. PDUMP_INFO_FILE File = &g_DumpInfoFiles[Index];
  560. DBG_ASSERT(((g_DumpCacheGranularity - 1) & InitialView) == 0);
  561. if (File->File != NULL)
  562. {
  563. return E_INVALIDARG;
  564. }
  565. // We have to share everything in order to be
  566. // able to reopen already-open temporary files
  567. // expanded from CABs as they are marked as
  568. // delete-on-close.
  569. File->File = CreateFile(FileName,
  570. GENERIC_READ,
  571. FILE_SHARE_READ | FILE_SHARE_WRITE |
  572. FILE_SHARE_DELETE,
  573. NULL,
  574. OPEN_EXISTING,
  575. FILE_ATTRIBUTE_NORMAL,
  576. NULL);
  577. if (File->File == INVALID_HANDLE_VALUE)
  578. {
  579. goto LastStatus;
  580. }
  581. //
  582. // Get file size and map initial view.
  583. //
  584. ULONG SizeLow, SizeHigh;
  585. SizeLow = GetFileSize(File->File, &SizeHigh);
  586. File->FileSize = ((ULONG64)SizeHigh << 32) | SizeLow;
  587. File->Map = CreateFileMapping(File->File, NULL, PAGE_READONLY,
  588. 0, 0, NULL);
  589. if (File->Map == NULL)
  590. {
  591. goto LastStatus;
  592. }
  593. if (File->FileSize < InitialView)
  594. {
  595. InitialView = (ULONG)File->FileSize;
  596. }
  597. File->MapBase = MapViewOfFile(File->Map, FILE_MAP_READ, 0, 0,
  598. InitialView);
  599. if (File->MapBase == NULL)
  600. {
  601. goto LastStatus;
  602. }
  603. switch(Index)
  604. {
  605. case DUMP_INFO_PAGE_FILE:
  606. if (memcmp(File->MapBase, DMPPF_IDENTIFIER,
  607. sizeof(DMPPF_IDENTIFIER) - 1) != 0)
  608. {
  609. Status = HR_DUMP_CORRUPT;
  610. goto Fail;
  611. }
  612. break;
  613. }
  614. File->MapSize = InitialView;
  615. DmppDumpFileCacheInit(File);
  616. return S_OK;
  617. LastStatus:
  618. Status = WIN32_LAST_STATUS();
  619. Fail:
  620. CloseDumpInfoFile(Index);
  621. return Status;
  622. }
  623. void
  624. CloseDumpInfoFile(ULONG Index)
  625. {
  626. PDUMP_INFO_FILE File = &g_DumpInfoFiles[Index];
  627. if (Index == DUMP_INFO_DUMP)
  628. {
  629. g_DumpBase = NULL;
  630. }
  631. DmppDumpFileCacheCleanup(File);
  632. if (File->MapBase != NULL)
  633. {
  634. UnmapViewOfFile(File->MapBase);
  635. File->MapBase = NULL;
  636. }
  637. if (File->Map != NULL)
  638. {
  639. CloseHandle(File->Map);
  640. File->Map = NULL;
  641. }
  642. if (File->File != NULL && File->File != INVALID_HANDLE_VALUE)
  643. {
  644. CloseHandle(File->File);
  645. }
  646. File->File = NULL;
  647. }
  648. void
  649. CloseDumpInfoFiles(void)
  650. {
  651. ULONG i;
  652. for (i = 0; i < DUMP_INFO_COUNT; i++)
  653. {
  654. CloseDumpInfoFile(i);
  655. }
  656. }
  657. HRESULT
  658. DmpInitialize(LPCSTR FileName)
  659. {
  660. HRESULT Status;
  661. dprintf("\nLoading Dump File [%s]\n", FileName);
  662. if ((Status = AddDumpInfoFile(FileName, DUMP_INFO_DUMP,
  663. DUMP_INITIAL_VIEW_SIZE)) != S_OK)
  664. {
  665. return Status;
  666. }
  667. PDUMP_INFO_FILE File = &g_DumpInfoFiles[DUMP_INFO_DUMP];
  668. ULONG i;
  669. ULONG64 BaseMapSize;
  670. g_DumpBase = File->MapBase;
  671. for (i = 0; i < DTYPE_COUNT; i++)
  672. {
  673. BaseMapSize = File->MapSize;
  674. Status = g_DumpTargets[i]->IdentifyDump(&BaseMapSize);
  675. if (Status != E_NOINTERFACE)
  676. {
  677. break;
  678. }
  679. }
  680. if (Status == E_NOINTERFACE)
  681. {
  682. ErrOut("Could not match Dump File signature - "
  683. "invalid file format\n");
  684. }
  685. else if (Status == S_OK &&
  686. BaseMapSize > File->MapSize)
  687. {
  688. if (BaseMapSize > File->FileSize ||
  689. BaseMapSize > DUMP_MAXIMUM_VIEW_SIZE)
  690. {
  691. ErrOut("Dump file is too large to map\n");
  692. Status = E_INVALIDARG;
  693. }
  694. else
  695. {
  696. // Target requested a larger mapping so
  697. // try and do so. Round up to a multiple
  698. // of the initial view size for cache alignment.
  699. BaseMapSize =
  700. (BaseMapSize + DUMP_INITIAL_VIEW_SIZE - 1) &
  701. ~(DUMP_INITIAL_VIEW_SIZE - 1);
  702. if (BaseMapSize > File->FileSize)
  703. {
  704. BaseMapSize = File->FileSize;
  705. }
  706. UnmapViewOfFile(File->MapBase);
  707. File->MapBase = MapViewOfFile(File->Map, FILE_MAP_READ,
  708. 0, 0, (ULONG)BaseMapSize);
  709. if (File->MapBase == NULL)
  710. {
  711. Status = WIN32_LAST_STATUS();
  712. }
  713. }
  714. }
  715. if (Status == S_OK)
  716. {
  717. File->MapSize = (ULONG)BaseMapSize;
  718. g_DumpType = (DTYPE)i;
  719. g_DumpBase = File->MapBase;
  720. }
  721. else
  722. {
  723. CloseDumpInfoFile(DUMP_INFO_DUMP);
  724. }
  725. return Status;
  726. }
  727. VOID
  728. DmpUninitialize(VOID)
  729. {
  730. if (g_DumpType < DTYPE_COUNT)
  731. {
  732. g_DumpTargets[g_DumpType]->Uninitialize();
  733. g_DumpType = DTYPE_COUNT;
  734. }
  735. }
  736. HRESULT
  737. DmppInitGlobals(ULONG BuildNumber, ULONG CheckedBuild,
  738. ULONG MachineType, ULONG PlatformId,
  739. ULONG MajorVersion, ULONG MinorVersion)
  740. {
  741. SetTargetSystemVersionAndBuild(BuildNumber, PlatformId);
  742. g_TargetCheckedBuild = CheckedBuild;
  743. DbgKdApi64 = (g_SystemVersion > NT_SVER_NT4);
  744. HRESULT Status = InitializeMachines(MachineType);
  745. if (Status != S_OK)
  746. {
  747. return Status;
  748. }
  749. if (g_TargetMachine == NULL)
  750. {
  751. ErrOut("Dump has an unknown processor type, 0x%X\n", MachineType);
  752. return HR_DUMP_CORRUPT;
  753. }
  754. g_TargetPlatformId = PlatformId;
  755. g_KdVersion.MachineType = (USHORT) MachineType;
  756. g_KdVersion.MajorVersion = (USHORT) MajorVersion;
  757. g_KdVersion.MinorVersion = (USHORT) MinorVersion;
  758. g_KdVersion.Flags = DBGKD_VERS_FLAG_DATA |
  759. (g_TargetMachine->m_Ptr64 ? DBGKD_VERS_FLAG_PTR64 : 0);
  760. return S_OK;
  761. }
  762. //----------------------------------------------------------------------------
  763. //
  764. // DumpTargetInfo.
  765. //
  766. //----------------------------------------------------------------------------
  767. void
  768. DumpTargetInfo::Uninitialize(void)
  769. {
  770. CloseDumpInfoFiles();
  771. g_DumpType = DTYPE_COUNT;
  772. g_DumpFormatFlags = 0;
  773. }
  774. HRESULT
  775. DumpTargetInfo::ReadVirtual(
  776. ULONG64 Offset,
  777. PVOID Buffer,
  778. ULONG BufferSize,
  779. PULONG BytesRead
  780. )
  781. {
  782. ULONG Done = 0;
  783. ULONG FileIndex;
  784. ULONG Avail;
  785. ULONG Attempt;
  786. ULONG64 FileOffset;
  787. if (BufferSize == 0)
  788. {
  789. *BytesRead = 0;
  790. return S_OK;
  791. }
  792. while (BufferSize > 0)
  793. {
  794. FileOffset = VirtualToOffset(Offset, &FileIndex, &Avail);
  795. if (FileOffset == 0)
  796. {
  797. break;
  798. }
  799. if (Avail > BufferSize)
  800. {
  801. Avail = BufferSize;
  802. }
  803. Attempt = DmppReadFileOffset(FileIndex, FileOffset, Buffer, Avail);
  804. Done += Attempt;
  805. if (Attempt < Avail)
  806. {
  807. break;
  808. }
  809. Offset += Avail;
  810. Buffer = (PUCHAR)Buffer + Avail;
  811. BufferSize -= Avail;
  812. }
  813. *BytesRead = Done;
  814. // If we didn't read anything return an error.
  815. return Done == 0 ? E_FAIL : S_OK;
  816. }
  817. HRESULT
  818. DumpTargetInfo::WriteVirtual(
  819. ULONG64 Offset,
  820. PVOID Buffer,
  821. ULONG BufferSize,
  822. PULONG BytesWritten
  823. )
  824. {
  825. ULONG Done = 0;
  826. ULONG FileIndex;
  827. ULONG Avail;
  828. ULONG Attempt;
  829. ULONG64 FileOffset;
  830. if (BufferSize == 0)
  831. {
  832. *BytesWritten = 0;
  833. return S_OK;
  834. }
  835. while (BufferSize > 0)
  836. {
  837. FileOffset = VirtualToOffset(Offset, &FileIndex, &Avail);
  838. if (FileOffset == 0)
  839. {
  840. break;
  841. }
  842. if (Avail > BufferSize)
  843. {
  844. Avail = BufferSize;
  845. }
  846. Attempt = DmppWriteFileOffset(FileIndex, FileOffset, Buffer, Avail);
  847. Done += Attempt;
  848. if (Attempt < Avail)
  849. {
  850. break;
  851. }
  852. Offset += Avail;
  853. Buffer = (PUCHAR)Buffer + Avail;
  854. BufferSize -= Avail;
  855. }
  856. *BytesWritten = Done;
  857. // If we didn't write anything return an error.
  858. return Done == 0 ? E_FAIL : S_OK;
  859. }
  860. HRESULT
  861. DumpTargetInfo::Write(HANDLE hFile, ULONG FormatFlags, PCSTR Comment)
  862. {
  863. ErrOut("Dump file type does not support writing\n");
  864. return E_NOTIMPL;
  865. }
  866. //----------------------------------------------------------------------------
  867. //
  868. // KernelDumpTargetInfo.
  869. //
  870. //----------------------------------------------------------------------------
  871. void
  872. OutputHeaderString(PCSTR Format, PSTR Str)
  873. {
  874. if (*(PULONG)Str == DUMP_SIGNATURE32 ||
  875. Str[0] == 0)
  876. {
  877. // String not present.
  878. return;
  879. }
  880. dprintf(Format, Str);
  881. }
  882. void
  883. KernelDumpTargetInfo::Uninitialize(void)
  884. {
  885. m_HeaderContext = NULL;
  886. ZeroMemory(g_DumpKiProcessors, sizeof(g_DumpKiProcessors));
  887. g_DumpKiPcrBaseAddress = 0;
  888. DumpTargetInfo::Uninitialize();
  889. }
  890. HRESULT
  891. DmppReadControlSpaceAxp(
  892. ULONG Processor,
  893. ULONG64 Offset,
  894. PVOID Buffer,
  895. ULONG BufferSize,
  896. PULONG BytesRead
  897. )
  898. {
  899. ULONG64 StartAddr;
  900. ULONG Read = 0;
  901. HRESULT Status;
  902. ULONG PtrSize = g_TargetMachine->m_Ptr64 ?
  903. sizeof(ULONG64) : sizeof(ULONG);
  904. if (BufferSize < PtrSize)
  905. {
  906. return E_INVALIDARG;
  907. }
  908. switch(Offset)
  909. {
  910. case ALPHA_DEBUG_CONTROL_SPACE_PCR:
  911. if (g_DumpKiPcrBaseAddress == 0)
  912. {
  913. WarnOut("Unable to determine KiPcrBaseAddress\n");
  914. Status = E_FAIL;
  915. }
  916. else
  917. {
  918. // Return the PCR address for the current processor.
  919. Status = g_Target->ReadVirtual(g_DumpKiPcrBaseAddress,
  920. Buffer,
  921. PtrSize, &Read);
  922. }
  923. break;
  924. case ALPHA_DEBUG_CONTROL_SPACE_PRCB:
  925. //
  926. // Return the prcb address for the current processor.
  927. //
  928. memcpy(Buffer, &g_DumpKiProcessors[Processor], PtrSize);
  929. Read = PtrSize;
  930. Status = S_OK;
  931. break;
  932. case ALPHA_DEBUG_CONTROL_SPACE_THREAD:
  933. //
  934. // Return the pointer to the current thread address for the
  935. // current processor.
  936. //
  937. StartAddr = g_DumpKiProcessors[Processor] +
  938. (g_TargetMachine->m_Ptr64 ?
  939. KPRCB_CURRENT_THREAD_OFFSET_64 :
  940. KPRCB_CURRENT_THREAD_OFFSET_32);
  941. Status = g_Target->ReadVirtual(StartAddr, Buffer,
  942. PtrSize, &Read);
  943. break;
  944. case ALPHA_DEBUG_CONTROL_SPACE_TEB:
  945. //
  946. // Return the current Thread Environment Block pointer for the
  947. // current thread on the current processor.
  948. //
  949. StartAddr = g_DumpKiProcessors[Processor] +
  950. (g_TargetMachine->m_Ptr64 ?
  951. KPRCB_CURRENT_THREAD_OFFSET_64 :
  952. KPRCB_CURRENT_THREAD_OFFSET_32);
  953. Status = g_Target->ReadPointer(g_TargetMachine, StartAddr, &StartAddr);
  954. if (Status == S_OK)
  955. {
  956. StartAddr += g_TargetMachine->m_OffsetKThreadTeb;
  957. Status = g_Target->ReadVirtual(StartAddr, Buffer,
  958. PtrSize, &Read);
  959. }
  960. break;
  961. }
  962. *BytesRead = Read;
  963. return Status;
  964. }
  965. HRESULT
  966. DmppReadControlSpaceIa64(
  967. ULONG Processor,
  968. ULONG64 Offset,
  969. PVOID Buffer,
  970. ULONG BufferSize,
  971. PULONG BytesRead
  972. )
  973. {
  974. ULONG64 StartAddr;
  975. ULONG Read = 0;
  976. HRESULT Status;
  977. if (BufferSize < sizeof(ULONG64))
  978. {
  979. return E_INVALIDARG;
  980. }
  981. switch(Offset)
  982. {
  983. case IA64_DEBUG_CONTROL_SPACE_PCR:
  984. StartAddr = g_DumpKiProcessors[Processor] +
  985. FIELD_OFFSET(IA64_PARTIAL_KPRCB, PcrPage);
  986. Status = g_Target->ReadVirtual(StartAddr, &StartAddr,
  987. sizeof(StartAddr), &Read);
  988. if (Status == S_OK && Read == sizeof(StartAddr))
  989. {
  990. *(PULONG64)Buffer =
  991. (StartAddr << IA64_PAGE_SHIFT) + IA64_PHYSICAL1_START;
  992. }
  993. break;
  994. case IA64_DEBUG_CONTROL_SPACE_PRCB:
  995. *(PULONG64)Buffer = g_DumpKiProcessors[Processor];
  996. Read = sizeof(ULONG64);
  997. Status = S_OK;
  998. break;
  999. case IA64_DEBUG_CONTROL_SPACE_KSPECIAL:
  1000. StartAddr = g_DumpKiProcessors[Processor] +
  1001. FIELD_OFFSET(IA64_PARTIAL_KPRCB, ProcessorState.SpecialRegisters);
  1002. Status = g_Target->ReadVirtual(StartAddr, Buffer, BufferSize, &Read);
  1003. break;
  1004. case IA64_DEBUG_CONTROL_SPACE_THREAD:
  1005. StartAddr = g_DumpKiProcessors[Processor] +
  1006. FIELD_OFFSET(IA64_PARTIAL_KPRCB, CurrentThread);
  1007. Status = g_Target->ReadVirtual(StartAddr, Buffer,
  1008. sizeof(ULONG64), &Read);
  1009. break;
  1010. }
  1011. *BytesRead = Read;
  1012. return Status;
  1013. }
  1014. HRESULT
  1015. DmppReadControlSpaceAmd64(
  1016. ULONG Processor,
  1017. ULONG64 Offset,
  1018. PVOID Buffer,
  1019. ULONG BufferSize,
  1020. PULONG BytesRead
  1021. )
  1022. {
  1023. ULONG64 StartAddr;
  1024. ULONG Read = 0;
  1025. HRESULT Status;
  1026. if (BufferSize < sizeof(ULONG64))
  1027. {
  1028. return E_INVALIDARG;
  1029. }
  1030. switch(Offset)
  1031. {
  1032. case AMD64_DEBUG_CONTROL_SPACE_PCR:
  1033. *(PULONG64)Buffer = g_DumpKiProcessors[Processor] -
  1034. FIELD_OFFSET(AMD64_KPCR, Prcb);
  1035. Read = sizeof(ULONG64);
  1036. Status = S_OK;
  1037. break;
  1038. case AMD64_DEBUG_CONTROL_SPACE_PRCB:
  1039. *(PULONG64)Buffer = g_DumpKiProcessors[Processor];
  1040. Read = sizeof(ULONG64);
  1041. Status = S_OK;
  1042. break;
  1043. case AMD64_DEBUG_CONTROL_SPACE_KSPECIAL:
  1044. StartAddr = g_DumpKiProcessors[Processor] +
  1045. FIELD_OFFSET(AMD64_PARTIAL_KPRCB, ProcessorState.SpecialRegisters);
  1046. Status = g_Target->ReadVirtual(StartAddr, Buffer, BufferSize, &Read);
  1047. break;
  1048. case AMD64_DEBUG_CONTROL_SPACE_THREAD:
  1049. StartAddr = g_DumpKiProcessors[Processor] +
  1050. FIELD_OFFSET(AMD64_PARTIAL_KPRCB, CurrentThread);
  1051. Status = g_Target->ReadVirtual(StartAddr, Buffer,
  1052. sizeof(ULONG64), &Read);
  1053. break;
  1054. }
  1055. *BytesRead = Read;
  1056. return Status;
  1057. }
  1058. HRESULT
  1059. KernelDumpTargetInfo::ReadControl(
  1060. IN ULONG Processor,
  1061. IN ULONG64 Offset,
  1062. OUT PVOID Buffer,
  1063. IN ULONG BufferSize,
  1064. OUT OPTIONAL PULONG BytesRead
  1065. )
  1066. {
  1067. ULONG64 StartAddr;
  1068. //
  1069. // This function will not currently work if the symbols are not loaded.
  1070. //
  1071. if (!IS_KERNEL_TRIAGE_DUMP() &&
  1072. KdDebuggerData.KiProcessorBlock == 0)
  1073. {
  1074. ErrOut("ReadControl failed - ntoskrnl symbols must be loaded first\n");
  1075. return E_FAIL;
  1076. }
  1077. if (g_DumpKiProcessors[Processor] == 0)
  1078. {
  1079. // This error message is a little too verbose.
  1080. #if 0
  1081. ErrOut("No control space information for processor %d\n", Processor);
  1082. #endif
  1083. return E_FAIL;
  1084. }
  1085. switch(g_TargetMachineType)
  1086. {
  1087. case IMAGE_FILE_MACHINE_I386:
  1088. StartAddr = Offset +
  1089. g_DumpKiProcessors[Processor] +
  1090. g_TargetMachine->m_OffsetPrcbProcessorState;
  1091. return ReadVirtual(StartAddr, Buffer, BufferSize, BytesRead);
  1092. case IMAGE_FILE_MACHINE_ALPHA:
  1093. case IMAGE_FILE_MACHINE_AXP64:
  1094. return DmppReadControlSpaceAxp(Processor, Offset, Buffer,
  1095. BufferSize, BytesRead);
  1096. case IMAGE_FILE_MACHINE_IA64:
  1097. return DmppReadControlSpaceIa64(Processor, Offset, Buffer,
  1098. BufferSize, BytesRead);
  1099. case IMAGE_FILE_MACHINE_AMD64:
  1100. return DmppReadControlSpaceAmd64(Processor, Offset, Buffer,
  1101. BufferSize, BytesRead);
  1102. }
  1103. return E_FAIL;
  1104. }
  1105. HRESULT
  1106. KernelDumpTargetInfo::GetThreadIdByProcessor(
  1107. IN ULONG Processor,
  1108. OUT PULONG Id
  1109. )
  1110. {
  1111. *Id = VIRTUAL_THREAD_ID(Processor);
  1112. return S_OK;
  1113. }
  1114. HRESULT
  1115. KernelDumpTargetInfo::GetThreadInfoDataOffset(PTHREAD_INFO Thread,
  1116. ULONG64 ThreadHandle,
  1117. PULONG64 Offset)
  1118. {
  1119. return KdGetThreadInfoDataOffset(Thread, ThreadHandle, Offset);
  1120. }
  1121. HRESULT
  1122. KernelDumpTargetInfo::GetProcessInfoDataOffset(PTHREAD_INFO Thread,
  1123. ULONG Processor,
  1124. ULONG64 ThreadData,
  1125. PULONG64 Offset)
  1126. {
  1127. return KdGetProcessInfoDataOffset(Thread, Processor, ThreadData, Offset);
  1128. }
  1129. HRESULT
  1130. KernelDumpTargetInfo::GetThreadInfoTeb(PTHREAD_INFO Thread,
  1131. ULONG ThreadIndex,
  1132. ULONG64 ThreadData,
  1133. PULONG64 Offset)
  1134. {
  1135. return KdGetThreadInfoTeb(Thread, ThreadIndex, ThreadData, Offset);
  1136. }
  1137. HRESULT
  1138. KernelDumpTargetInfo::GetProcessInfoPeb(PTHREAD_INFO Thread,
  1139. ULONG Processor,
  1140. ULONG64 ThreadData,
  1141. PULONG64 Offset)
  1142. {
  1143. return KdGetProcessInfoPeb(Thread, Processor, ThreadData, Offset);
  1144. }
  1145. ULONG64
  1146. KernelDumpTargetInfo::GetCurrentTimeDateN(void)
  1147. {
  1148. if (g_SystemVersion < NT_SVER_W2K)
  1149. {
  1150. ULONG64 TimeDate;
  1151. // Header time not available. Try and read
  1152. // the time saved in the shared user data segment.
  1153. if (ReadSharedUserTimeDateN(&TimeDate) == S_OK)
  1154. {
  1155. return TimeDate;
  1156. }
  1157. else
  1158. {
  1159. return 0;
  1160. }
  1161. }
  1162. return g_TargetMachine->m_Ptr64 ?
  1163. ((PDUMP_HEADER64)g_DumpBase)->SystemTime.QuadPart :
  1164. ((PDUMP_HEADER32)g_DumpBase)->SystemTime.QuadPart;
  1165. }
  1166. ULONG64
  1167. KernelDumpTargetInfo::GetCurrentSystemUpTimeN(void)
  1168. {
  1169. ULONG64 page = 'EGAP';
  1170. ULONG64 page64 = page | (page << 32);
  1171. ULONG64 SystemUpTime = g_TargetMachine->m_Ptr64 ?
  1172. ((PDUMP_HEADER64)g_DumpBase)->SystemUpTime.QuadPart :
  1173. ((PDUMP_HEADER32)g_DumpBase)->SystemUpTime.QuadPart;
  1174. if (SystemUpTime && (SystemUpTime != page64))
  1175. {
  1176. return SystemUpTime;
  1177. }
  1178. // Header time not available. Try and read
  1179. // the time saved in the shared user data segment.
  1180. if (ReadSharedUserUpTimeN(&SystemUpTime) == S_OK)
  1181. {
  1182. return SystemUpTime;
  1183. }
  1184. else
  1185. {
  1186. return 0;
  1187. }
  1188. }
  1189. HRESULT
  1190. KernelDumpTargetInfo::InitGlobals32(PMEMORY_DUMP32 Dump)
  1191. {
  1192. if (Dump->Header.DirectoryTableBase == 0)
  1193. {
  1194. ErrOut("Invalid directory table base value 0x%x\n",
  1195. Dump->Header.DirectoryTableBase);
  1196. return HR_DUMP_CORRUPT;
  1197. }
  1198. if (Dump->Header.MinorVersion > 1381 &&
  1199. Dump->Header.PaeEnabled == TRUE )
  1200. {
  1201. KdDebuggerData.PaeEnabled = TRUE;
  1202. }
  1203. else
  1204. {
  1205. KdDebuggerData.PaeEnabled = FALSE;
  1206. }
  1207. KdDebuggerData.PsLoadedModuleList =
  1208. EXTEND64(Dump->Header.PsLoadedModuleList);
  1209. g_TargetNumberProcessors = Dump->Header.NumberProcessors;
  1210. ExceptionRecord32To64(&Dump->Header.Exception, &g_DumpException);
  1211. g_DumpExceptionFirstChance = FALSE;
  1212. m_HeaderContext = Dump->Header.ContextRecord;
  1213. // New field in Windows Whistler and NT SP1 and above
  1214. if ((Dump->Header.KdDebuggerDataBlock) &&
  1215. (Dump->Header.KdDebuggerDataBlock != DUMP_SIGNATURE32))
  1216. {
  1217. g_KdDebuggerDataBlock = EXTEND64(Dump->Header.KdDebuggerDataBlock);
  1218. }
  1219. OutputHeaderString("Comment: '%s'\n", Dump->Header.Comment);
  1220. HRESULT Status =
  1221. DmppInitGlobals(Dump->Header.MinorVersion,
  1222. Dump->Header.MajorVersion & 0xFF,
  1223. Dump->Header.MachineImageType,
  1224. VER_PLATFORM_WIN32_NT,
  1225. Dump->Header.MajorVersion,
  1226. Dump->Header.MinorVersion);
  1227. if (Status != S_OK)
  1228. {
  1229. return Status;
  1230. }
  1231. ULONG NextIdx;
  1232. return g_TargetMachine->
  1233. SetPageDirectory(PAGE_DIR_KERNEL, Dump->Header.DirectoryTableBase,
  1234. &NextIdx);
  1235. }
  1236. HRESULT
  1237. KernelDumpTargetInfo::InitGlobals64(PMEMORY_DUMP64 Dump)
  1238. {
  1239. if (Dump->Header.DirectoryTableBase == 0)
  1240. {
  1241. ErrOut("Invalid directory table base value 0x%I64x\n",
  1242. Dump->Header.DirectoryTableBase);
  1243. return HR_DUMP_CORRUPT;
  1244. }
  1245. KdDebuggerData.PaeEnabled = FALSE;
  1246. KdDebuggerData.PsLoadedModuleList =
  1247. Dump->Header.PsLoadedModuleList;
  1248. g_TargetNumberProcessors = Dump->Header.NumberProcessors;
  1249. g_DumpException = Dump->Header.Exception;
  1250. g_DumpExceptionFirstChance = FALSE;
  1251. m_HeaderContext = Dump->Header.ContextRecord;
  1252. // New field in Windows Whistler and NT SP1 and above
  1253. if ((Dump->Header.KdDebuggerDataBlock) &&
  1254. (Dump->Header.KdDebuggerDataBlock != DUMP_SIGNATURE32))
  1255. {
  1256. g_KdDebuggerDataBlock = Dump->Header.KdDebuggerDataBlock;
  1257. }
  1258. OutputHeaderString("Comment: '%s'\n", Dump->Header.Comment);
  1259. HRESULT Status =
  1260. DmppInitGlobals(Dump->Header.MinorVersion,
  1261. Dump->Header.MajorVersion & 0xFF,
  1262. Dump->Header.MachineImageType,
  1263. VER_PLATFORM_WIN32_NT,
  1264. Dump->Header.MajorVersion,
  1265. Dump->Header.MinorVersion);
  1266. if (Status != S_OK)
  1267. {
  1268. return Status;
  1269. }
  1270. ULONG NextIdx;
  1271. return g_TargetMachine->
  1272. SetPageDirectory(PAGE_DIR_KERNEL, Dump->Header.DirectoryTableBase,
  1273. &NextIdx);
  1274. }
  1275. void
  1276. KernelDumpTargetInfo::DumpHeader32(PDUMP_HEADER32 Header)
  1277. {
  1278. dprintf("\nDUMP_HEADER32:\n");
  1279. dprintf("MajorVersion %08lx\n", Header->MajorVersion);
  1280. dprintf("MinorVersion %08lx\n", Header->MinorVersion);
  1281. dprintf("DirectoryTableBase %08lx\n", Header->DirectoryTableBase);
  1282. dprintf("PfnDataBase %08lx\n", Header->PfnDataBase);
  1283. dprintf("PsLoadedModuleList %08lx\n", Header->PsLoadedModuleList);
  1284. dprintf("PsActiveProcessHead %08lx\n", Header->PsActiveProcessHead);
  1285. dprintf("MachineImageType %08lx\n", Header->MachineImageType);
  1286. dprintf("NumberProcessors %08lx\n", Header->NumberProcessors);
  1287. dprintf("BugCheckCode %08lx\n", Header->BugCheckCode);
  1288. dprintf("BugCheckParameter1 %08lx\n", Header->BugCheckParameter1);
  1289. dprintf("BugCheckParameter2 %08lx\n", Header->BugCheckParameter2);
  1290. dprintf("BugCheckParameter3 %08lx\n", Header->BugCheckParameter3);
  1291. dprintf("BugCheckParameter4 %08lx\n", Header->BugCheckParameter4);
  1292. OutputHeaderString("VersionUser '%s'\n", Header->VersionUser);
  1293. dprintf("PaeEnabled %08lx\n", Header->PaeEnabled);
  1294. dprintf("KdDebuggerDataBlock %08lx\n", Header->KdDebuggerDataBlock);
  1295. OutputHeaderString("Comment '%s'\n", Header->Comment);
  1296. }
  1297. void
  1298. KernelDumpTargetInfo::DumpHeader64(PDUMP_HEADER64 Header)
  1299. {
  1300. dprintf("\nDUMP_HEADER64:\n");
  1301. dprintf("MajorVersion %08lx\n", Header->MajorVersion);
  1302. dprintf("MinorVersion %08lx\n", Header->MinorVersion);
  1303. dprintf("DirectoryTableBase %s\n",
  1304. FormatAddr64(Header->DirectoryTableBase));
  1305. dprintf("PfnDataBase %s\n",
  1306. FormatAddr64(Header->PfnDataBase));
  1307. dprintf("PsLoadedModuleList %s\n",
  1308. FormatAddr64(Header->PsLoadedModuleList));
  1309. dprintf("PsActiveProcessHead %s\n",
  1310. FormatAddr64(Header->PsActiveProcessHead));
  1311. dprintf("MachineImageType %08lx\n", Header->MachineImageType);
  1312. dprintf("NumberProcessors %08lx\n", Header->NumberProcessors);
  1313. dprintf("BugCheckCode %08lx\n", Header->BugCheckCode);
  1314. dprintf("BugCheckParameter1 %s\n",
  1315. FormatAddr64(Header->BugCheckParameter1));
  1316. dprintf("BugCheckParameter2 %s\n",
  1317. FormatAddr64(Header->BugCheckParameter2));
  1318. dprintf("BugCheckParameter3 %s\n",
  1319. FormatAddr64(Header->BugCheckParameter3));
  1320. dprintf("BugCheckParameter4 %s\n",
  1321. FormatAddr64(Header->BugCheckParameter4));
  1322. OutputHeaderString("VersionUser '%s'\n", Header->VersionUser);
  1323. dprintf("KdDebuggerDataBlock %s\n",
  1324. FormatAddr64(Header->KdDebuggerDataBlock));
  1325. OutputHeaderString("Comment '%s'\n", Header->Comment);
  1326. }
  1327. //----------------------------------------------------------------------------
  1328. //
  1329. // KernelFullSumDumpTargetInfo.
  1330. //
  1331. //----------------------------------------------------------------------------
  1332. HRESULT
  1333. PageFileOffset(ULONG PfIndex, ULONG64 PfOffset, PULONG64 FileOffset)
  1334. {
  1335. PDUMP_INFO_FILE File = &g_DumpInfoFiles[DUMP_INFO_PAGE_FILE];
  1336. if (File->File == NULL)
  1337. {
  1338. return HR_PAGE_NOT_AVAILABLE;
  1339. }
  1340. if (PfIndex > MAX_PAGING_FILE_MASK)
  1341. {
  1342. return HR_DUMP_CORRUPT;
  1343. }
  1344. //
  1345. // We can safely assume the header information is present
  1346. // in the base mapping.
  1347. //
  1348. DMPPF_FILE_HEADER* Hdr = (DMPPF_FILE_HEADER*)File->MapBase;
  1349. DMPPF_PAGE_FILE_INFO* FileInfo = &Hdr->PageFiles[PfIndex];
  1350. ULONG64 PfPage = PfOffset >> g_TargetMachine->m_PageShift;
  1351. if (PfPage >= FileInfo->MaximumSize)
  1352. {
  1353. return HR_PAGE_NOT_AVAILABLE;
  1354. }
  1355. ULONG i;
  1356. ULONG PageDirOffs = sizeof(*Hdr) + (ULONG)PfPage * sizeof(ULONG);
  1357. for (i = 0; i < PfIndex; i++)
  1358. {
  1359. PageDirOffs += Hdr->PageFiles[i].MaximumSize * sizeof(ULONG);
  1360. }
  1361. ULONG PageDirEnt;
  1362. if (DmppReadFileOffset(DUMP_INFO_PAGE_FILE, PageDirOffs,
  1363. &PageDirEnt, sizeof(PageDirEnt)) !=
  1364. sizeof(PageDirEnt))
  1365. {
  1366. return HR_DUMP_CORRUPT;
  1367. }
  1368. if (PageDirEnt == DMPPF_PAGE_NOT_PRESENT)
  1369. {
  1370. return HR_PAGE_NOT_AVAILABLE;
  1371. }
  1372. *FileOffset = Hdr->PageData +
  1373. (PageDirEnt << g_TargetMachine->m_PageShift) +
  1374. (PfOffset & (g_Machine->m_PageSize - 1));
  1375. return S_OK;
  1376. }
  1377. HRESULT
  1378. KernelFullSumDumpTargetInfo::Initialize(void)
  1379. {
  1380. InitSelCache();
  1381. m_ProvokingVirtAddr = 0;
  1382. return S_OK;
  1383. }
  1384. HRESULT
  1385. KernelFullSumDumpTargetInfo::ReadPhysical(
  1386. ULONG64 Offset,
  1387. PVOID Buffer,
  1388. ULONG BufferSize,
  1389. PULONG BytesRead
  1390. )
  1391. {
  1392. ULONG Done = 0;
  1393. ULONG Avail;
  1394. ULONG Attempt;
  1395. ULONG64 FileOffset;
  1396. if (BufferSize == 0)
  1397. {
  1398. *BytesRead = 0;
  1399. return S_OK;
  1400. }
  1401. while (BufferSize > 0)
  1402. {
  1403. FileOffset = PhysicalToOffset(Offset, &Avail);
  1404. if (FileOffset == 0)
  1405. {
  1406. break;
  1407. }
  1408. if (Avail > BufferSize)
  1409. {
  1410. Avail = BufferSize;
  1411. }
  1412. Attempt = DmppReadFileOffset(DUMP_INFO_DUMP,
  1413. FileOffset, Buffer, Avail);
  1414. Done += Attempt;
  1415. if (Attempt < Avail)
  1416. {
  1417. break;
  1418. }
  1419. Offset += Avail;
  1420. Buffer = (PUCHAR)Buffer + Avail;
  1421. BufferSize -= Avail;
  1422. }
  1423. *BytesRead = Done;
  1424. // If we didn't read anything return an error.
  1425. return Done == 0 ? E_FAIL : S_OK;
  1426. }
  1427. HRESULT
  1428. KernelFullSumDumpTargetInfo::WritePhysical(
  1429. ULONG64 Offset,
  1430. PVOID Buffer,
  1431. ULONG BufferSize,
  1432. PULONG BytesWritten
  1433. )
  1434. {
  1435. ULONG Done = 0;
  1436. ULONG Avail;
  1437. ULONG Attempt;
  1438. ULONG64 FileOffset;
  1439. if (BufferSize == 0)
  1440. {
  1441. *BytesWritten = 0;
  1442. return S_OK;
  1443. }
  1444. while (BufferSize > 0)
  1445. {
  1446. FileOffset = PhysicalToOffset(Offset, &Avail);
  1447. if (FileOffset == 0)
  1448. {
  1449. break;
  1450. }
  1451. if (Avail > BufferSize)
  1452. {
  1453. Avail = BufferSize;
  1454. }
  1455. Attempt = DmppWriteFileOffset(DUMP_INFO_DUMP,
  1456. FileOffset, Buffer, Avail);
  1457. Done += Attempt;
  1458. if (Attempt < Avail)
  1459. {
  1460. break;
  1461. }
  1462. Offset += Avail;
  1463. Buffer = (PUCHAR)Buffer + Avail;
  1464. BufferSize -= Avail;
  1465. }
  1466. *BytesWritten = Done;
  1467. // If we didn't write anything return an error.
  1468. return Done == 0 ? E_FAIL : S_OK;
  1469. }
  1470. HRESULT
  1471. KernelFullSumDumpTargetInfo::GetProcessorId
  1472. (ULONG Processor, PDEBUG_PROCESSOR_IDENTIFICATION_ALL Id)
  1473. {
  1474. return g_TargetMachine->ReadKernelProcessorId(Processor, Id);
  1475. }
  1476. HRESULT
  1477. KernelFullSumDumpTargetInfo::ReadPageFile(ULONG PfIndex, ULONG64 PfOffset,
  1478. PVOID Buffer, ULONG Size)
  1479. {
  1480. HRESULT Status;
  1481. ULONG64 FileOffset;
  1482. if ((Status = PageFileOffset(PfIndex, PfOffset, &FileOffset)) != S_OK)
  1483. {
  1484. return Status;
  1485. }
  1486. // It's assumed that all page file reads are for the
  1487. // entire amount requested, as there are no situations
  1488. // where it's useful to only read part of a page from the
  1489. // page file.
  1490. if (DmppReadFileOffset(DUMP_INFO_PAGE_FILE, FileOffset,
  1491. Buffer, Size) < Size)
  1492. {
  1493. return HRESULT_FROM_WIN32(ERROR_READ_FAULT);
  1494. }
  1495. else
  1496. {
  1497. return S_OK;
  1498. }
  1499. }
  1500. HRESULT
  1501. KernelFullSumDumpTargetInfo::GetTargetContext(
  1502. ULONG64 Thread,
  1503. PVOID Context
  1504. )
  1505. {
  1506. ULONG Read;
  1507. HRESULT Status;
  1508. Status = ReadVirtual(g_DumpKiProcessors[VIRTUAL_THREAD_INDEX(Thread)] +
  1509. g_TargetMachine->m_OffsetPrcbProcessorState,
  1510. Context, g_TargetMachine->m_SizeTargetContext,
  1511. &Read);
  1512. if (Status != S_OK)
  1513. {
  1514. return Status;
  1515. }
  1516. return Read == g_TargetMachine->m_SizeTargetContext ? S_OK : E_FAIL;
  1517. }
  1518. HRESULT
  1519. KernelFullSumDumpTargetInfo::GetSelDescriptor(MachineInfo* Machine,
  1520. ULONG64 Thread,
  1521. ULONG Selector,
  1522. PDESCRIPTOR64 Desc)
  1523. {
  1524. return KdGetSelDescriptor(Machine, Thread, Selector, Desc);
  1525. }
  1526. void
  1527. KernelFullSumDumpTargetInfo::DumpDebug(void)
  1528. {
  1529. ULONG i;
  1530. dprintf("\nKiProcessorBlock at %s\n",
  1531. FormatAddr64(KdDebuggerData.KiProcessorBlock));
  1532. dprintf(" %d KiProcessorBlock entries:\n ", g_TargetNumberProcessors);
  1533. for (i = 0; i < g_TargetNumberProcessors; i++)
  1534. {
  1535. dprintf(" %s", FormatAddr64(g_DumpKiProcessors[i]));
  1536. }
  1537. dprintf("\n");
  1538. PDUMP_INFO_FILE PageDump = &g_DumpInfoFiles[DUMP_INFO_PAGE_FILE];
  1539. if (PageDump->File != NULL)
  1540. {
  1541. // XXX drewb - Display more information when format is understood.
  1542. dprintf("\nAdditional page file in use\n");
  1543. }
  1544. }
  1545. ULONG64
  1546. KernelFullSumDumpTargetInfo::VirtualToOffset(ULONG64 Virt,
  1547. PULONG File, PULONG Avail)
  1548. {
  1549. HRESULT Status;
  1550. ULONG Levels;
  1551. ULONG PfIndex;
  1552. ULONG64 Phys;
  1553. *File = DUMP_INFO_DUMP;
  1554. if ((Status = g_TargetMachine->
  1555. GetVirtualTranslationPhysicalOffsets(Virt, NULL, 0, &Levels,
  1556. &PfIndex, &Phys)) != S_OK)
  1557. {
  1558. // If the virtual address was paged out we got back
  1559. // a page file reference for the address. The user
  1560. // may have provided a page file in addition to the
  1561. // normal dump file so translate the reference into
  1562. // a secondary dump information file request.
  1563. if (Status == HR_PAGE_IN_PAGE_FILE)
  1564. {
  1565. if (PageFileOffset(PfIndex, Phys, &Phys) != S_OK)
  1566. {
  1567. return 0;
  1568. }
  1569. *File = DUMP_INFO_PAGE_FILE;
  1570. // Page files always have complete pages so the amount
  1571. // available is always the remainder of the page.
  1572. ULONG PageIndex = (ULONG)Virt & (g_TargetMachine->m_PageSize - 1);
  1573. *Avail = g_TargetMachine->m_PageSize - PageIndex;
  1574. return Phys;
  1575. }
  1576. else
  1577. {
  1578. return 0;
  1579. }
  1580. }
  1581. else
  1582. {
  1583. ULONG64 Offs;
  1584. // A summary dump will not contain any pages that
  1585. // are mapped by user-mode addresses. The virtual
  1586. // translation tables may still have valid mappings,
  1587. // though, so VToO will succeed. We want to suppress
  1588. // page-not-available messages in this case since
  1589. // the dump is known not to contain user pages.
  1590. // Record the provoking virtual address so that
  1591. // summary dump's PhysicalToOffset will know whether
  1592. // a message should be displayed or not.
  1593. m_ProvokingVirtAddr = Virt;
  1594. Offs = PhysicalToOffset(Phys, Avail);
  1595. m_ProvokingVirtAddr = 0;
  1596. return Offs;
  1597. }
  1598. }
  1599. ULONG
  1600. KernelFullSumDumpTargetInfo::GetCurrentProcessor(void)
  1601. {
  1602. ULONG i;
  1603. for (i = 0; i < g_TargetNumberProcessors; i++)
  1604. {
  1605. CROSS_PLATFORM_CONTEXT Context;
  1606. if (g_Target->GetContext(VIRTUAL_THREAD_HANDLE(i), &Context) == S_OK)
  1607. {
  1608. switch(g_TargetMachineType)
  1609. {
  1610. case IMAGE_FILE_MACHINE_I386:
  1611. if (Context.X86Nt5Context.Esp ==
  1612. ((PX86_NT5_CONTEXT)m_HeaderContext)->Esp)
  1613. {
  1614. return i;
  1615. }
  1616. break;
  1617. case IMAGE_FILE_MACHINE_ALPHA:
  1618. if (g_SystemVersion <= NT_SVER_NT4)
  1619. {
  1620. if (Context.AlphaNt5Context.IntSp ==
  1621. (((PALPHA_CONTEXT)m_HeaderContext)->IntSp |
  1622. ((ULONG64)((PALPHA_CONTEXT)m_HeaderContext)->
  1623. HighIntSp << 32)))
  1624. {
  1625. return i;
  1626. }
  1627. break;
  1628. }
  1629. // Fall through.
  1630. case IMAGE_FILE_MACHINE_AXP64:
  1631. if (Context.AlphaNt5Context.IntSp ==
  1632. ((PALPHA_NT5_CONTEXT)m_HeaderContext)->IntSp)
  1633. {
  1634. return i;
  1635. }
  1636. break;
  1637. case IMAGE_FILE_MACHINE_IA64:
  1638. if (Context.IA64Context.IntSp ==
  1639. ((PIA64_CONTEXT)m_HeaderContext)->IntSp)
  1640. {
  1641. return i;
  1642. }
  1643. break;
  1644. case IMAGE_FILE_MACHINE_AMD64:
  1645. if (Context.Amd64Context.Rsp ==
  1646. ((PAMD64_CONTEXT)m_HeaderContext)->Rsp)
  1647. {
  1648. return i;
  1649. }
  1650. break;
  1651. }
  1652. }
  1653. }
  1654. // Give up and just pick the default processor.
  1655. return 0;
  1656. }
  1657. //----------------------------------------------------------------------------
  1658. //
  1659. // KernelSummaryDumpTargetInfo.
  1660. //
  1661. //----------------------------------------------------------------------------
  1662. void
  1663. KernelSummaryDumpTargetInfo::Uninitialize(void)
  1664. {
  1665. delete m_LocationCache;
  1666. m_LocationCache = NULL;
  1667. m_PageBitmapSize = 0;
  1668. ZeroMemory(&m_PageBitmap, sizeof(m_PageBitmap));
  1669. KernelDumpTargetInfo::Uninitialize();
  1670. }
  1671. void
  1672. KernelSummaryDumpTargetInfo::ConstructLocationCache(ULONG BitmapSize,
  1673. ULONG SizeOfBitMap,
  1674. PULONG Buffer)
  1675. {
  1676. PULONG Cache;
  1677. ULONG Index;
  1678. ULONG Offset;
  1679. m_PageBitmapSize = BitmapSize;
  1680. m_PageBitmap.SizeOfBitMap = SizeOfBitMap;
  1681. m_PageBitmap.Buffer = Buffer;
  1682. //
  1683. // Create a direct mapped cache.
  1684. //
  1685. Cache = new ULONG[BitmapSize];
  1686. if (!Cache)
  1687. {
  1688. // Not a failure; there just won't be a cache.
  1689. return;
  1690. }
  1691. //
  1692. // For each bit set in the bitmask fill the appropriate cache
  1693. // line location with the correct offset
  1694. //
  1695. Offset = 0;
  1696. for (Index = 0; Index < BitmapSize; Index++)
  1697. {
  1698. //
  1699. // If this page is in the summary dump fill in the offset
  1700. //
  1701. if ( RtlCheckBit (&m_PageBitmap, Index) )
  1702. {
  1703. Cache[ Index ] = Offset++;
  1704. }
  1705. }
  1706. //
  1707. // Assign back to the global storing the cache data.
  1708. //
  1709. m_LocationCache = Cache;
  1710. }
  1711. ULONG64
  1712. KernelSummaryDumpTargetInfo::SumPhysicalToOffset(ULONG HeaderSize,
  1713. ULONG64 Phys,
  1714. PULONG Avail)
  1715. {
  1716. ULONG Offset, j;
  1717. ULONG64 Page = Phys >> g_TargetMachine->m_PageShift;
  1718. //
  1719. // Make sure this page is included in the dump
  1720. //
  1721. if ( Page >= m_PageBitmapSize )
  1722. {
  1723. ErrOut("Page %x too large to be in the dump file.\n", Page);
  1724. return 0;
  1725. }
  1726. if ( !RtlCheckBit ( &m_PageBitmap, Page ) )
  1727. {
  1728. // If this page lookup is the result of a user-mode
  1729. // address translation it's guaranteed that
  1730. // the page won't be present since summary dumps
  1731. // exclude user pages. Don't bother displaying
  1732. // an error message in that case.
  1733. if (!m_ProvokingVirtAddr || m_ProvokingVirtAddr >= g_SystemRangeStart)
  1734. {
  1735. ErrOut("Page %x not present in the dump file.\n", Page);
  1736. }
  1737. return 0;
  1738. }
  1739. //
  1740. // If the cache exists then find the location the easy way
  1741. //
  1742. if (m_LocationCache != NULL)
  1743. {
  1744. Offset = m_LocationCache[ Page ];
  1745. }
  1746. else
  1747. {
  1748. //
  1749. // CAVEAT This code will never execute unless there is a failure
  1750. // creating the summary dump (cache) mapping information
  1751. //
  1752. //
  1753. // The page is in the summary dump locate it's offset
  1754. // Note: this is painful. The offset is a count of
  1755. // all the bits set up to this page
  1756. //
  1757. Offset = 0;
  1758. for (j = 0; j < m_PageBitmapSize; j++ )
  1759. {
  1760. if ( RtlCheckBit( &m_PageBitmap, j ) )
  1761. {
  1762. //
  1763. // If the offset is equal to the page were done.
  1764. //
  1765. if (j == Page)
  1766. {
  1767. break;
  1768. }
  1769. Offset++;
  1770. }
  1771. }
  1772. //
  1773. // Sanity check that we didn't drop out of the loop.
  1774. //
  1775. if ( j >= m_PageBitmapSize )
  1776. {
  1777. return 0;
  1778. }
  1779. }
  1780. //
  1781. // The actual address is calculated as follows
  1782. // Header size - Size of header plus summary dump header
  1783. //
  1784. ULONG PageIndex = (ULONG)Phys & (g_TargetMachine->m_PageSize - 1);
  1785. *Avail = g_TargetMachine->m_PageSize - PageIndex;
  1786. return HeaderSize + (Offset * g_TargetMachine->m_PageSize) + PageIndex;
  1787. }
  1788. HRESULT
  1789. KernelSummary32DumpTargetInfo::Initialize(void)
  1790. {
  1791. // Pick up any potentially modified base mapping pointer.
  1792. m_Dump = (PMEMORY_DUMP32)g_DumpBase;
  1793. dprintf("Kernel Summary Dump File: "
  1794. "Only kernel address space is available\n\n");
  1795. g_TargetClass = DEBUG_CLASS_KERNEL;
  1796. g_TargetClassQualifier = DEBUG_KERNEL_DUMP;
  1797. ConstructLocationCache(m_Dump->Summary.BitmapSize,
  1798. m_Dump->Summary.Bitmap.SizeOfBitMap,
  1799. m_Dump->Summary.Bitmap.Buffer);
  1800. g_DumpInfoFiles[DUMP_INFO_DUMP].FileSize = m_Dump->Header.RequiredDumpSpace.QuadPart;
  1801. HRESULT Status = InitGlobals32(m_Dump);
  1802. if (Status != S_OK)
  1803. {
  1804. return Status;
  1805. }
  1806. return KernelFullSumDumpTargetInfo::Initialize();
  1807. }
  1808. void
  1809. KernelSummary32DumpTargetInfo::Uninitialize(void)
  1810. {
  1811. m_Dump = NULL;
  1812. KernelSummaryDumpTargetInfo::Uninitialize();
  1813. }
  1814. HRESULT
  1815. KernelSummary32DumpTargetInfo::ReadBugCheckData(PULONG Code, ULONG64 Args[4])
  1816. {
  1817. *Code = m_Dump->Header.BugCheckCode;
  1818. Args[0] = EXTEND64(m_Dump->Header.BugCheckParameter1);
  1819. Args[1] = EXTEND64(m_Dump->Header.BugCheckParameter2);
  1820. Args[2] = EXTEND64(m_Dump->Header.BugCheckParameter3);
  1821. Args[3] = EXTEND64(m_Dump->Header.BugCheckParameter4);
  1822. return S_OK;
  1823. }
  1824. HRESULT
  1825. KernelSummary32DumpTargetInfo::IdentifyDump(PULONG64 BaseMapSize)
  1826. {
  1827. HRESULT Status = E_NOINTERFACE;
  1828. PMEMORY_DUMP32 Dump = (PMEMORY_DUMP32)g_DumpBase;
  1829. if (Dump->Header.Signature != DUMP_SIGNATURE32 ||
  1830. Dump->Header.ValidDump != DUMP_VALID_DUMP32)
  1831. {
  1832. return Status;
  1833. }
  1834. __try
  1835. {
  1836. if (Dump->Header.DumpType == DUMP_TYPE_SUMMARY)
  1837. {
  1838. if (Dump->Summary.Signature != DUMP_SUMMARY_SIGNATURE)
  1839. {
  1840. // The header says it's a summary dump but
  1841. // it doesn't have a valid signature, so assume
  1842. // it's not a valid dump.
  1843. Status = HR_DUMP_CORRUPT;
  1844. }
  1845. else
  1846. {
  1847. Status = S_OK;
  1848. m_Dump = Dump;
  1849. }
  1850. }
  1851. }
  1852. __except(EXCEPTION_EXECUTE_HANDLER)
  1853. {
  1854. }
  1855. return Status;
  1856. }
  1857. ULONG64
  1858. KernelSummary32DumpTargetInfo::PhysicalToOffset(ULONG64 Phys, PULONG Avail)
  1859. {
  1860. return SumPhysicalToOffset(m_Dump->Summary.HeaderSize, Phys, Avail);
  1861. }
  1862. HRESULT
  1863. KernelSummary64DumpTargetInfo::Initialize(void)
  1864. {
  1865. // Pick up any potentially modified base mapping pointer.
  1866. m_Dump = (PMEMORY_DUMP64)g_DumpBase;
  1867. dprintf("Kernel Summary Dump File: "
  1868. "Only kernel address space is available\n\n");
  1869. g_TargetClass = DEBUG_CLASS_KERNEL;
  1870. g_TargetClassQualifier = DEBUG_KERNEL_DUMP;
  1871. ConstructLocationCache(m_Dump->Summary.BitmapSize,
  1872. m_Dump->Summary.Bitmap.SizeOfBitMap,
  1873. m_Dump->Summary.Bitmap.Buffer);
  1874. g_DumpInfoFiles[DUMP_INFO_DUMP].FileSize = m_Dump->Header.RequiredDumpSpace.QuadPart;
  1875. HRESULT Status = InitGlobals64(m_Dump);
  1876. if (Status != S_OK)
  1877. {
  1878. return Status;
  1879. }
  1880. return KernelFullSumDumpTargetInfo::Initialize();
  1881. }
  1882. void
  1883. KernelSummary32DumpTargetInfo::DumpDebug(void)
  1884. {
  1885. PSUMMARY_DUMP32 Sum = &m_Dump->Summary;
  1886. dprintf("----- 32 bit Kernel Summary Dump Analysis\n");
  1887. DumpHeader32(&m_Dump->Header);
  1888. dprintf("\nSUMMARY_DUMP32:\n");
  1889. dprintf("DumpOptions %08lx\n", Sum->DumpOptions);
  1890. dprintf("HeaderSize %08lx\n", Sum->HeaderSize);
  1891. dprintf("BitmapSize %08lx\n", Sum->BitmapSize);
  1892. dprintf("Pages %08lx\n", Sum->Pages);
  1893. dprintf("Bitmap.SizeOfBitMap %08lx\n", Sum->Bitmap.SizeOfBitMap);
  1894. KernelFullSumDumpTargetInfo::DumpDebug();
  1895. }
  1896. void
  1897. KernelSummary64DumpTargetInfo::Uninitialize(void)
  1898. {
  1899. m_Dump = NULL;
  1900. KernelSummaryDumpTargetInfo::Uninitialize();
  1901. }
  1902. HRESULT
  1903. KernelSummary64DumpTargetInfo::ReadBugCheckData(PULONG Code, ULONG64 Args[4])
  1904. {
  1905. *Code = m_Dump->Header.BugCheckCode;
  1906. Args[0] = m_Dump->Header.BugCheckParameter1;
  1907. Args[1] = m_Dump->Header.BugCheckParameter2;
  1908. Args[2] = m_Dump->Header.BugCheckParameter3;
  1909. Args[3] = m_Dump->Header.BugCheckParameter4;
  1910. return S_OK;
  1911. }
  1912. HRESULT
  1913. KernelSummary64DumpTargetInfo::IdentifyDump(PULONG64 BaseMapSize)
  1914. {
  1915. HRESULT Status = E_NOINTERFACE;
  1916. PMEMORY_DUMP64 Dump = (PMEMORY_DUMP64)g_DumpBase;
  1917. if (Dump->Header.Signature != DUMP_SIGNATURE64 ||
  1918. Dump->Header.ValidDump != DUMP_VALID_DUMP64)
  1919. {
  1920. return Status;
  1921. }
  1922. __try
  1923. {
  1924. if (Dump->Header.DumpType == DUMP_TYPE_SUMMARY)
  1925. {
  1926. if (Dump->Summary.Signature != DUMP_SUMMARY_SIGNATURE)
  1927. {
  1928. // The header says it's a summary dump but
  1929. // it doesn't have a valid signature, so assume
  1930. // it's not a valid dump.
  1931. Status = HR_DUMP_CORRUPT;
  1932. }
  1933. else
  1934. {
  1935. Status = S_OK;
  1936. m_Dump = Dump;
  1937. }
  1938. }
  1939. }
  1940. __except(EXCEPTION_EXECUTE_HANDLER)
  1941. {
  1942. }
  1943. return Status;
  1944. }
  1945. ULONG64
  1946. KernelSummary64DumpTargetInfo::PhysicalToOffset(ULONG64 Phys, PULONG Avail)
  1947. {
  1948. return SumPhysicalToOffset(m_Dump->Summary.HeaderSize, Phys, Avail);
  1949. }
  1950. void
  1951. KernelSummary64DumpTargetInfo::DumpDebug(void)
  1952. {
  1953. PSUMMARY_DUMP64 Sum = &m_Dump->Summary;
  1954. dprintf("----- 64 bit Kernel Summary Dump Analysis\n");
  1955. DumpHeader64(&m_Dump->Header);
  1956. dprintf("\nSUMMARY_DUMP64:\n");
  1957. dprintf("DumpOptions %08lx\n", Sum->DumpOptions);
  1958. dprintf("HeaderSize %08lx\n", Sum->HeaderSize);
  1959. dprintf("BitmapSize %08lx\n", Sum->BitmapSize);
  1960. dprintf("Pages %08lx\n", Sum->Pages);
  1961. dprintf("Bitmap.SizeOfBitMap %08lx\n", Sum->Bitmap.SizeOfBitMap);
  1962. KernelFullSumDumpTargetInfo::DumpDebug();
  1963. }
  1964. //----------------------------------------------------------------------------
  1965. //
  1966. // KernelTriageDumpTargetInfo.
  1967. //
  1968. //----------------------------------------------------------------------------
  1969. void
  1970. KernelTriageDumpTargetInfo::Uninitialize(void)
  1971. {
  1972. m_PrcbOffset = 0;
  1973. MemoryMap_Destroy();
  1974. KernelDumpTargetInfo::Uninitialize();
  1975. g_TriageDumpHasDebuggerData = FALSE;
  1976. }
  1977. void
  1978. KernelTriageDumpTargetInfo::NearestDifferentlyValidOffsets(ULONG64 Offset,
  1979. PULONG64 NextOffset,
  1980. PULONG64 NextPage)
  1981. {
  1982. //
  1983. // In a minidump there can be memory fragments mapped at
  1984. // arbitrary locations so we cannot assume validity
  1985. // changes on page boundaries. We could attempt to
  1986. // scan the memory list and try to find the closest valid
  1987. // chunk of memory but it's rarely important that
  1988. // complete accuracy is required. Just return the
  1989. // next byte.
  1990. //
  1991. if (NextOffset != NULL)
  1992. {
  1993. *NextOffset = Offset + 1;
  1994. }
  1995. if (NextPage != NULL)
  1996. {
  1997. *NextPage = (Offset + g_TargetMachine->m_PageSize) &
  1998. ~((ULONG64)g_TargetMachine->m_PageSize - 1);
  1999. }
  2000. }
  2001. HRESULT
  2002. KernelTriageDumpTargetInfo::ReadVirtual(
  2003. IN ULONG64 Offset,
  2004. OUT PVOID Buffer,
  2005. IN ULONG BufferSize,
  2006. OUT OPTIONAL PULONG BytesRead
  2007. )
  2008. {
  2009. // All virtual memory is contained in the memory map.
  2010. return MemoryMap_ReadMemory(Offset, Buffer, BufferSize,
  2011. BytesRead) ? S_OK : E_FAIL;
  2012. }
  2013. HRESULT
  2014. KernelTriageDumpTargetInfo::GetProcessorSystemDataOffset(
  2015. IN ULONG Processor,
  2016. IN ULONG Index,
  2017. OUT PULONG64 Offset
  2018. )
  2019. {
  2020. if (Processor != GetCurrentProcessor())
  2021. {
  2022. return E_INVALIDARG;
  2023. }
  2024. ULONG64 Prcb = g_DumpKiProcessors[Processor];
  2025. HRESULT Status;
  2026. switch(Index)
  2027. {
  2028. case DEBUG_DATA_KPCR_OFFSET:
  2029. // We don't have a full PCR, just a PRCB.
  2030. return E_FAIL;
  2031. case DEBUG_DATA_KPRCB_OFFSET:
  2032. *Offset = Prcb;
  2033. break;
  2034. case DEBUG_DATA_KTHREAD_OFFSET:
  2035. if ((Status = ReadPointer(g_TargetMachine,
  2036. Prcb + (g_TargetMachine->m_Ptr64 ?
  2037. KPRCB_CURRENT_THREAD_OFFSET_64 :
  2038. KPRCB_CURRENT_THREAD_OFFSET_32),
  2039. Offset)) != S_OK)
  2040. {
  2041. return Status;
  2042. }
  2043. break;
  2044. }
  2045. return S_OK;
  2046. }
  2047. HRESULT
  2048. KernelTriageDumpTargetInfo::GetTargetContext(
  2049. ULONG64 Thread,
  2050. PVOID Context
  2051. )
  2052. {
  2053. // We only have the current context in a triage dump.
  2054. if (VIRTUAL_THREAD_INDEX(Thread) != GetCurrentProcessor())
  2055. {
  2056. return E_INVALIDARG;
  2057. }
  2058. // The KPRCB could be used to retrieve context information as in
  2059. // KernelFullSumDumpTargetInfo::GetTargetContext but
  2060. // for consistency the header context is used since it's
  2061. // the officially advertised place.
  2062. memcpy(Context, m_HeaderContext, g_TargetMachine->m_SizeTargetContext);
  2063. return S_OK;
  2064. }
  2065. HRESULT
  2066. KernelTriageDumpTargetInfo::GetSelDescriptor(MachineInfo* Machine,
  2067. ULONG64 Thread,
  2068. ULONG Selector,
  2069. PDESCRIPTOR64 Desc)
  2070. {
  2071. return EmulateNtSelDescriptor(Machine, Selector, Desc);
  2072. }
  2073. ULONG64
  2074. KernelTriageDumpTargetInfo::VirtualToOffset(ULONG64 Virt,
  2075. PULONG File, PULONG Avail)
  2076. {
  2077. ULONG64 Base;
  2078. ULONG Size;
  2079. PVOID Mapping, Param;
  2080. *File = DUMP_INFO_DUMP;
  2081. // ReadVirtual is overridden to read the memory map directly
  2082. // so this function will only be called from the generic
  2083. // WriteVirtual. We can only write regions mapped out of
  2084. // the dump so only return memory regions that don't have
  2085. // an image pointer as their user data.
  2086. if (MemoryMap_GetRegionInfo(Virt, &Base, &Size, &Mapping, &Param) &&
  2087. Param == NULL)
  2088. {
  2089. *Avail = Size - (ULONG)(Virt - Base);
  2090. return (PUCHAR)Mapping - (PUCHAR)g_DumpBase;
  2091. }
  2092. return 0;
  2093. }
  2094. ULONG
  2095. KernelTriageDumpTargetInfo::GetCurrentProcessor(void)
  2096. {
  2097. // Extract the processor number from the
  2098. // PRCB in the dump.
  2099. return *(PUCHAR)
  2100. IndexByByte(g_DumpBase, m_PrcbOffset +
  2101. g_TargetMachine->m_OffsetPrcbNumber);
  2102. }
  2103. HRESULT
  2104. KernelTriageDumpTargetInfo::MapMemoryRegions(ULONG PrcbOffset,
  2105. ULONG ThreadOffset,
  2106. ULONG ProcessOffset,
  2107. ULONG64 TopOfStack,
  2108. ULONG SizeOfCallStack,
  2109. ULONG CallStackOffset,
  2110. ULONG64 BStoreLimit,
  2111. ULONG SizeOfBStore,
  2112. ULONG BStoreOffset,
  2113. ULONG64 DataPageAddress,
  2114. ULONG DataPageOffset,
  2115. ULONG DataPageSize,
  2116. ULONG64 DebuggerDataAddress,
  2117. ULONG DebuggerDataOffset,
  2118. ULONG DebuggerDataSize,
  2119. ULONG MmDataOffset,
  2120. ULONG DataBlocksOffset,
  2121. ULONG DataBlocksCount)
  2122. {
  2123. HRESULT Status;
  2124. if (!MemoryMap_Create())
  2125. {
  2126. return E_OUTOFMEMORY;
  2127. }
  2128. // Technically a triage dump doesn't have to contain a KPRCB
  2129. // but we really want it to have one. Nobody generates them
  2130. // without a KPRCB so this is really just a sanity check.
  2131. if (PrcbOffset == 0)
  2132. {
  2133. ErrOut("Dump does not contain KPRCB\n");
  2134. return E_FAIL;
  2135. }
  2136. // Set this first so GetCurrentProcessor works.
  2137. m_PrcbOffset = PrcbOffset;
  2138. ULONG Processor = GetCurrentProcessor();
  2139. // The dump contains one PRCB for the current processor.
  2140. // Map the PRCB at the processor-zero location because
  2141. // that location should not ever have some other mapping
  2142. // for the dump.
  2143. g_DumpKiProcessors[Processor] = g_TargetMachine->m_TriagePrcbOffset;
  2144. if ((Status = MemoryMap_AddRegion(g_DumpKiProcessors[Processor],
  2145. g_TargetMachine->m_SizePrcb,
  2146. IndexByByte(g_DumpBase, PrcbOffset),
  2147. NULL, FALSE)) != S_OK)
  2148. {
  2149. return Status;
  2150. }
  2151. //
  2152. // Add ETHREAD and EPROCESS memory regions if available.
  2153. //
  2154. if (ThreadOffset != 0)
  2155. {
  2156. PVOID CurThread =
  2157. IndexByByte(g_DumpBase, PrcbOffset +
  2158. (g_TargetMachine->m_Ptr64 ?
  2159. KPRCB_CURRENT_THREAD_OFFSET_64 :
  2160. KPRCB_CURRENT_THREAD_OFFSET_32));
  2161. ULONG64 ThreadAddr, ProcAddr;
  2162. if (g_TargetMachine->m_Ptr64)
  2163. {
  2164. ThreadAddr = *(PULONG64)CurThread;
  2165. ProcAddr = *(PULONG64)
  2166. IndexByByte(g_DumpBase, ThreadOffset +
  2167. g_TargetMachine->m_OffsetKThreadApcProcess);
  2168. }
  2169. else
  2170. {
  2171. ThreadAddr = EXTEND64(*(PULONG)CurThread);
  2172. ProcAddr = EXTEND64(*(PULONG)
  2173. IndexByByte(g_DumpBase, ThreadOffset +
  2174. g_TargetMachine->m_OffsetKThreadApcProcess));
  2175. }
  2176. if ((Status = MemoryMap_AddRegion(ThreadAddr,
  2177. g_TargetMachine->m_SizeEThread,
  2178. IndexByByte(g_DumpBase,
  2179. ThreadOffset),
  2180. NULL, TRUE)) != S_OK)
  2181. {
  2182. return Status;
  2183. }
  2184. if (ProcessOffset != 0)
  2185. {
  2186. if ((Status = MemoryMap_AddRegion(ProcAddr,
  2187. g_TargetMachine->m_SizeEProcess,
  2188. IndexByByte(g_DumpBase,
  2189. ProcessOffset),
  2190. NULL, TRUE)) != S_OK)
  2191. {
  2192. return Status;
  2193. }
  2194. }
  2195. else
  2196. {
  2197. WarnOut("Mini Kernel Dump does not have "
  2198. "process information\n");
  2199. }
  2200. }
  2201. else
  2202. {
  2203. WarnOut("Mini Kernel Dump does not have thread information\n");
  2204. }
  2205. // Add the backing store region.
  2206. if (g_TargetMachineType == IMAGE_FILE_MACHINE_IA64)
  2207. {
  2208. if (BStoreOffset != 0)
  2209. {
  2210. if ((Status = MemoryMap_AddRegion(BStoreLimit - SizeOfBStore,
  2211. SizeOfBStore,
  2212. IndexByByte(g_DumpBase,
  2213. BStoreOffset),
  2214. NULL, TRUE)) != S_OK)
  2215. {
  2216. return Status;
  2217. }
  2218. }
  2219. else
  2220. {
  2221. WarnOut("Mini Kernel Dump does not have "
  2222. "backing store information\n");
  2223. }
  2224. }
  2225. // Add data page if available
  2226. if (DataPageAddress)
  2227. {
  2228. if ((Status = MemoryMap_AddRegion(DataPageAddress, DataPageSize,
  2229. IndexByByte(g_DumpBase,
  2230. DataPageOffset),
  2231. NULL, TRUE)) != S_OK)
  2232. {
  2233. return Status;
  2234. }
  2235. }
  2236. // Map any debugger data.
  2237. if (DebuggerDataAddress)
  2238. {
  2239. if ((Status = MemoryMap_AddRegion(DebuggerDataAddress,
  2240. DebuggerDataSize,
  2241. IndexByByte(g_DumpBase,
  2242. DebuggerDataOffset),
  2243. NULL, TRUE)) != S_OK)
  2244. {
  2245. return Status;
  2246. }
  2247. g_TriageDumpHasDebuggerData = TRUE;
  2248. if (MmDataOffset)
  2249. {
  2250. MM_TRIAGE_TRANSLATION* Trans = g_MmTriageTranslations;
  2251. // Map memory fragments for MM Triage information
  2252. // that equates to entries in the debugger data.
  2253. while (Trans->DebuggerDataOffset > 0)
  2254. {
  2255. ULONG64 DbgData;
  2256. ULONG MmData;
  2257. ULONG Size;
  2258. DbgData = *(ULONG64 UNALIGNED*)
  2259. IndexByByte(g_DumpBase, DebuggerDataOffset +
  2260. Trans->DebuggerDataOffset);
  2261. Size = sizeof(ULONG);
  2262. if (g_TargetMachine->m_Ptr64)
  2263. {
  2264. MmData = MmDataOffset + Trans->Triage64Offset;
  2265. if (Trans->PtrSize)
  2266. {
  2267. Size = sizeof(ULONG64);
  2268. }
  2269. }
  2270. else
  2271. {
  2272. MmData = MmDataOffset + Trans->Triage32Offset;
  2273. DbgData = EXTEND64(DbgData);
  2274. }
  2275. if ((Status = MemoryMap_AddRegion(DbgData, Size,
  2276. IndexByByte(g_DumpBase,
  2277. MmData),
  2278. NULL, TRUE)) != S_OK)
  2279. {
  2280. return Status;
  2281. }
  2282. Trans++;
  2283. }
  2284. }
  2285. }
  2286. // Map arbitrary data blocks.
  2287. if (DataBlocksCount > 0)
  2288. {
  2289. PTRIAGE_DATA_BLOCK Block;
  2290. Block = (PTRIAGE_DATA_BLOCK)IndexByByte(g_DumpBase, DataBlocksOffset);
  2291. while (DataBlocksCount-- > 0)
  2292. {
  2293. if ((Status = MemoryMap_AddRegion(Block->Address,
  2294. Block->Size,
  2295. IndexByByte(g_DumpBase,
  2296. Block->Offset),
  2297. NULL, TRUE)) != S_OK)
  2298. {
  2299. return Status;
  2300. }
  2301. Block++;
  2302. }
  2303. }
  2304. // Add the stack to the valid memory region.
  2305. return MemoryMap_AddRegion(TopOfStack, SizeOfCallStack,
  2306. IndexByByte(g_DumpBase, CallStackOffset),
  2307. NULL, TRUE);
  2308. }
  2309. HRESULT
  2310. KernelTriage32DumpTargetInfo::Initialize(void)
  2311. {
  2312. // Pick up any potentially modified base mapping pointer.
  2313. m_Dump = (PMEMORY_DUMP32)g_DumpBase;
  2314. dprintf("Mini Kernel Dump File: "
  2315. "Only registers and stack trace are available\n\n");
  2316. g_TargetClass = DEBUG_CLASS_KERNEL;
  2317. g_TargetClassQualifier = DEBUG_KERNEL_SMALL_DUMP;
  2318. PTRIAGE_DUMP32 Triage = &m_Dump->Triage;
  2319. HRESULT Status = InitGlobals32(m_Dump);
  2320. if (Status != S_OK)
  2321. {
  2322. return Status;
  2323. }
  2324. //
  2325. // Optional memory page
  2326. //
  2327. ULONG64 DataPageAddress = 0;
  2328. ULONG DataPageOffset = 0;
  2329. ULONG DataPageSize = 0;
  2330. if (((m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_BASIC_INFO) ==
  2331. TRIAGE_DUMP_BASIC_INFO) &&
  2332. (m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_DATAPAGE))
  2333. {
  2334. DataPageAddress = Triage->DataPageAddress;
  2335. DataPageOffset = Triage->DataPageOffset;
  2336. DataPageSize = Triage->DataPageSize;
  2337. }
  2338. //
  2339. // Optional KDDEBUGGER_DATA64.
  2340. //
  2341. ULONG64 DebuggerDataAddress = 0;
  2342. ULONG DebuggerDataOffset = 0;
  2343. ULONG DebuggerDataSize = 0;
  2344. if (((m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_BASIC_INFO) ==
  2345. TRIAGE_DUMP_BASIC_INFO) &&
  2346. (m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_DEBUGGER_DATA))
  2347. {
  2348. // DebuggerDataBlock field must be valid if the dump is
  2349. // new enough to have a data block in it.
  2350. DebuggerDataAddress = EXTEND64(m_Dump->Header.KdDebuggerDataBlock);
  2351. DebuggerDataOffset = Triage->DebuggerDataOffset;
  2352. DebuggerDataSize = Triage->DebuggerDataSize;
  2353. }
  2354. //
  2355. // Optional data blocks.
  2356. //
  2357. ULONG DataBlocksOffset = 0;
  2358. ULONG DataBlocksCount = 0;
  2359. if (((m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_BASIC_INFO) ==
  2360. TRIAGE_DUMP_BASIC_INFO) &&
  2361. (m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_DATA_BLOCKS))
  2362. {
  2363. DataBlocksOffset = Triage->DataBlocksOffset;
  2364. DataBlocksCount = Triage->DataBlocksCount;
  2365. }
  2366. //
  2367. // We store the servicepack version in the header because we
  2368. // don't store the actual memory
  2369. //
  2370. SetTargetNtCsdVersion(m_Dump->Triage.ServicePackBuild);
  2371. return MapMemoryRegions(Triage->PrcbOffset, Triage->ThreadOffset,
  2372. Triage->ProcessOffset,
  2373. EXTEND64(Triage->TopOfStack),
  2374. Triage->SizeOfCallStack, Triage->CallStackOffset,
  2375. 0, 0, 0,
  2376. DataPageAddress, DataPageOffset, DataPageSize,
  2377. DebuggerDataAddress, DebuggerDataOffset,
  2378. DebuggerDataSize, Triage->MmOffset,
  2379. DataBlocksOffset, DataBlocksCount);
  2380. }
  2381. void
  2382. KernelTriage32DumpTargetInfo::Uninitialize(void)
  2383. {
  2384. m_Dump = NULL;
  2385. KernelTriageDumpTargetInfo::Uninitialize();
  2386. }
  2387. HRESULT
  2388. KernelTriage32DumpTargetInfo::ReadBugCheckData(PULONG Code, ULONG64 Args[4])
  2389. {
  2390. *Code = m_Dump->Header.BugCheckCode;
  2391. Args[0] = EXTEND64(m_Dump->Header.BugCheckParameter1);
  2392. Args[1] = EXTEND64(m_Dump->Header.BugCheckParameter2);
  2393. Args[2] = EXTEND64(m_Dump->Header.BugCheckParameter3);
  2394. Args[3] = EXTEND64(m_Dump->Header.BugCheckParameter4);
  2395. return S_OK;
  2396. }
  2397. HRESULT
  2398. KernelTriage32DumpTargetInfo::IdentifyDump(PULONG64 BaseMapSize)
  2399. {
  2400. HRESULT Status = E_NOINTERFACE;
  2401. PMEMORY_DUMP32 Dump = (PMEMORY_DUMP32)g_DumpBase;
  2402. if (Dump->Header.Signature != DUMP_SIGNATURE32 ||
  2403. Dump->Header.ValidDump != DUMP_VALID_DUMP32)
  2404. {
  2405. return Status;
  2406. }
  2407. __try
  2408. {
  2409. if (Dump->Header.DumpType == DUMP_TYPE_TRIAGE)
  2410. {
  2411. if (*(PULONG)IndexByByte(Dump, Dump->Triage.SizeOfDump -
  2412. sizeof(ULONG)) != TRIAGE_DUMP_VALID)
  2413. {
  2414. // The header says it's a triage dump but
  2415. // it doesn't have a valid signature, so assume
  2416. // it's not a valid dump.
  2417. Status = HR_DUMP_CORRUPT;
  2418. }
  2419. else
  2420. {
  2421. Status = S_OK;
  2422. }
  2423. }
  2424. }
  2425. __except(EXCEPTION_EXECUTE_HANDLER)
  2426. {
  2427. }
  2428. if (Status != S_OK)
  2429. {
  2430. return Status;
  2431. }
  2432. // Make sure that the dump has the minimal information that
  2433. // we want.
  2434. if (Dump->Triage.ContextOffset == 0 ||
  2435. Dump->Triage.ExceptionOffset == 0 ||
  2436. Dump->Triage.PrcbOffset == 0 ||
  2437. Dump->Triage.CallStackOffset == 0)
  2438. {
  2439. ErrOut("Mini Kernel Dump does not contain enough "
  2440. "information to be debugged\n");
  2441. return E_FAIL;
  2442. }
  2443. // We rely on being able to directly access the entire
  2444. // content of the dump through the default view so
  2445. // ensure that it's possible.
  2446. *BaseMapSize = g_DumpInfoFiles[DUMP_INFO_DUMP].FileSize;
  2447. m_Dump = Dump;
  2448. return Status;
  2449. }
  2450. ModuleInfo*
  2451. KernelTriage32DumpTargetInfo::GetModuleInfo(BOOL UserMode)
  2452. {
  2453. return UserMode ? NULL : &g_KernelTriage32ModuleIterator;
  2454. }
  2455. UnloadedModuleInfo*
  2456. KernelTriage32DumpTargetInfo::GetUnloadedModuleInfo(void)
  2457. {
  2458. return &g_KernelTriage32UnloadedModuleIterator;
  2459. }
  2460. void
  2461. KernelTriage32DumpTargetInfo::DumpDebug(void)
  2462. {
  2463. PTRIAGE_DUMP32 Triage = &m_Dump->Triage;
  2464. dprintf("----- 32 bit Kernel Mini Dump Analysis\n");
  2465. DumpHeader32(&m_Dump->Header);
  2466. dprintf("MiniDumpFields %08lx \n", m_Dump->Header.MiniDumpFields);
  2467. dprintf("\nTRIAGE_DUMP32:\n");
  2468. dprintf("ServicePackBuild %08lx \n", Triage->ServicePackBuild );
  2469. dprintf("SizeOfDump %08lx \n", Triage->SizeOfDump );
  2470. dprintf("ValidOffset %08lx \n", Triage->ValidOffset );
  2471. dprintf("ContextOffset %08lx \n", Triage->ContextOffset );
  2472. dprintf("ExceptionOffset %08lx \n", Triage->ExceptionOffset );
  2473. dprintf("MmOffset %08lx \n", Triage->MmOffset );
  2474. dprintf("UnloadedDriversOffset %08lx \n", Triage->UnloadedDriversOffset );
  2475. dprintf("PrcbOffset %08lx \n", Triage->PrcbOffset );
  2476. dprintf("ProcessOffset %08lx \n", Triage->ProcessOffset );
  2477. dprintf("ThreadOffset %08lx \n", Triage->ThreadOffset );
  2478. dprintf("CallStackOffset %08lx \n", Triage->CallStackOffset );
  2479. dprintf("SizeOfCallStack %08lx \n", Triage->SizeOfCallStack );
  2480. dprintf("DriverListOffset %08lx \n", Triage->DriverListOffset );
  2481. dprintf("DriverCount %08lx \n", Triage->DriverCount );
  2482. dprintf("StringPoolOffset %08lx \n", Triage->StringPoolOffset );
  2483. dprintf("StringPoolSize %08lx \n", Triage->StringPoolSize );
  2484. dprintf("BrokenDriverOffset %08lx \n", Triage->BrokenDriverOffset );
  2485. dprintf("TriageOptions %08lx \n", Triage->TriageOptions );
  2486. dprintf("TopOfStack %08lx \n", Triage->TopOfStack );
  2487. if (((m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_BASIC_INFO) ==
  2488. TRIAGE_DUMP_BASIC_INFO) &&
  2489. (m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_DATAPAGE))
  2490. {
  2491. dprintf("DataPageAddress %08lx \n", Triage->DataPageAddress );
  2492. dprintf("DataPageOffset %08lx \n", Triage->DataPageOffset );
  2493. dprintf("DataPageSize %08lx \n", Triage->DataPageSize );
  2494. }
  2495. if (((m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_BASIC_INFO) ==
  2496. TRIAGE_DUMP_BASIC_INFO) &&
  2497. (m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_DEBUGGER_DATA))
  2498. {
  2499. dprintf("DebuggerDataOffset %08lx \n", Triage->DebuggerDataOffset);
  2500. dprintf("DebuggerDataSize %08lx \n", Triage->DebuggerDataSize );
  2501. }
  2502. if (((m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_BASIC_INFO) ==
  2503. TRIAGE_DUMP_BASIC_INFO) &&
  2504. (m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_DATA_BLOCKS))
  2505. {
  2506. dprintf("DataBlocksOffset %08lx \n", Triage->DataBlocksOffset );
  2507. dprintf("DataBlocksCount %08lx \n", Triage->DataBlocksCount );
  2508. }
  2509. }
  2510. HRESULT
  2511. KernelTriage64DumpTargetInfo::Initialize(void)
  2512. {
  2513. // Pick up any potentially modified base mapping pointer.
  2514. m_Dump = (PMEMORY_DUMP64)g_DumpBase;
  2515. dprintf("Mini Kernel Dump File: "
  2516. "Only registers and stack trace are available\n\n");
  2517. g_TargetClass = DEBUG_CLASS_KERNEL;
  2518. g_TargetClassQualifier = DEBUG_KERNEL_SMALL_DUMP;
  2519. PTRIAGE_DUMP64 Triage = &m_Dump->Triage;
  2520. HRESULT Status = InitGlobals64(m_Dump);
  2521. if (Status != S_OK)
  2522. {
  2523. return Status;
  2524. }
  2525. //
  2526. // Optional memory page
  2527. //
  2528. ULONG64 DataPageAddress = 0;
  2529. ULONG DataPageOffset = 0;
  2530. ULONG DataPageSize = 0;
  2531. if (((m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_BASIC_INFO) ==
  2532. TRIAGE_DUMP_BASIC_INFO) &&
  2533. (m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_DATAPAGE))
  2534. {
  2535. DataPageAddress = Triage->DataPageAddress;
  2536. DataPageOffset = Triage->DataPageOffset;
  2537. DataPageSize = Triage->DataPageSize;
  2538. }
  2539. //
  2540. // Optional KDDEBUGGER_DATA64.
  2541. //
  2542. ULONG64 DebuggerDataAddress = 0;
  2543. ULONG DebuggerDataOffset = 0;
  2544. ULONG DebuggerDataSize = 0;
  2545. if (((m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_BASIC_INFO) ==
  2546. TRIAGE_DUMP_BASIC_INFO) &&
  2547. (m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_DEBUGGER_DATA))
  2548. {
  2549. // DebuggerDataBlock field must be valid if the dump is
  2550. // new enough to have a data block in it.
  2551. DebuggerDataAddress = m_Dump->Header.KdDebuggerDataBlock;
  2552. DebuggerDataOffset = Triage->DebuggerDataOffset;
  2553. DebuggerDataSize = Triage->DebuggerDataSize;
  2554. }
  2555. //
  2556. // Optional data blocks.
  2557. //
  2558. ULONG DataBlocksOffset = 0;
  2559. ULONG DataBlocksCount = 0;
  2560. if (((m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_BASIC_INFO) ==
  2561. TRIAGE_DUMP_BASIC_INFO) &&
  2562. (m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_DATA_BLOCKS))
  2563. {
  2564. DataBlocksOffset = Triage->DataBlocksOffset;
  2565. DataBlocksCount = Triage->DataBlocksCount;
  2566. }
  2567. //
  2568. // We store the servicepack version in the header because we
  2569. // don't store the actual memory
  2570. //
  2571. SetTargetNtCsdVersion(m_Dump->Triage.ServicePackBuild);
  2572. return MapMemoryRegions(Triage->PrcbOffset, Triage->ThreadOffset,
  2573. Triage->ProcessOffset, Triage->TopOfStack,
  2574. Triage->SizeOfCallStack, Triage->CallStackOffset,
  2575. Triage->ArchitectureSpecific.Ia64.LimitOfBStore,
  2576. Triage->ArchitectureSpecific.Ia64.SizeOfBStore,
  2577. Triage->ArchitectureSpecific.Ia64.BStoreOffset,
  2578. DataPageAddress, DataPageOffset, DataPageSize,
  2579. DebuggerDataAddress, DebuggerDataOffset,
  2580. DebuggerDataSize, Triage->MmOffset,
  2581. DataBlocksOffset, DataBlocksCount);
  2582. }
  2583. void
  2584. KernelTriage64DumpTargetInfo::Uninitialize(void)
  2585. {
  2586. m_Dump = NULL;
  2587. KernelTriageDumpTargetInfo::Uninitialize();
  2588. }
  2589. HRESULT
  2590. KernelTriage64DumpTargetInfo::ReadBugCheckData(PULONG Code, ULONG64 Args[4])
  2591. {
  2592. *Code = m_Dump->Header.BugCheckCode;
  2593. Args[0] = m_Dump->Header.BugCheckParameter1;
  2594. Args[1] = m_Dump->Header.BugCheckParameter2;
  2595. Args[2] = m_Dump->Header.BugCheckParameter3;
  2596. Args[3] = m_Dump->Header.BugCheckParameter4;
  2597. return S_OK;
  2598. }
  2599. HRESULT
  2600. KernelTriage64DumpTargetInfo::IdentifyDump(PULONG64 BaseMapSize)
  2601. {
  2602. HRESULT Status = E_NOINTERFACE;
  2603. PMEMORY_DUMP64 Dump = (PMEMORY_DUMP64)g_DumpBase;
  2604. if (Dump->Header.Signature != DUMP_SIGNATURE64 ||
  2605. Dump->Header.ValidDump != DUMP_VALID_DUMP64)
  2606. {
  2607. return Status;
  2608. }
  2609. __try
  2610. {
  2611. if (Dump->Header.DumpType == DUMP_TYPE_TRIAGE)
  2612. {
  2613. if (*(PULONG)IndexByByte(Dump, Dump->Triage.SizeOfDump -
  2614. sizeof(ULONG)) != TRIAGE_DUMP_VALID)
  2615. {
  2616. // The header says it's a triage dump but
  2617. // it doesn't have a valid signature, so assume
  2618. // it's not a valid dump.
  2619. Status = HR_DUMP_CORRUPT;
  2620. }
  2621. else
  2622. {
  2623. Status = S_OK;
  2624. }
  2625. }
  2626. }
  2627. __except(EXCEPTION_EXECUTE_HANDLER)
  2628. {
  2629. }
  2630. if (Status != S_OK)
  2631. {
  2632. return Status;
  2633. }
  2634. // Make sure that the dump has the minimal information that
  2635. // we want.
  2636. if (Dump->Triage.ContextOffset == 0 ||
  2637. Dump->Triage.ExceptionOffset == 0 ||
  2638. Dump->Triage.PrcbOffset == 0 ||
  2639. Dump->Triage.CallStackOffset == 0)
  2640. {
  2641. ErrOut("Mini Kernel Dump does not contain enough "
  2642. "information to be debugged\n");
  2643. return E_FAIL;
  2644. }
  2645. // We rely on being able to directly access the entire
  2646. // content of the dump through the default view so
  2647. // ensure that it's possible.
  2648. *BaseMapSize = g_DumpInfoFiles[DUMP_INFO_DUMP].FileSize;
  2649. m_Dump = Dump;
  2650. return Status;
  2651. }
  2652. ModuleInfo*
  2653. KernelTriage64DumpTargetInfo::GetModuleInfo(BOOL UserMode)
  2654. {
  2655. return UserMode ? NULL : &g_KernelTriage64ModuleIterator;
  2656. }
  2657. UnloadedModuleInfo*
  2658. KernelTriage64DumpTargetInfo::GetUnloadedModuleInfo(void)
  2659. {
  2660. return &g_KernelTriage64UnloadedModuleIterator;
  2661. }
  2662. void
  2663. KernelTriage64DumpTargetInfo::DumpDebug(void)
  2664. {
  2665. PTRIAGE_DUMP64 Triage = &m_Dump->Triage;
  2666. dprintf("----- 64 bit Kernel Mini Dump Analysis\n");
  2667. DumpHeader64(&m_Dump->Header);
  2668. dprintf("MiniDumpFields %08lx \n", m_Dump->Header.MiniDumpFields);
  2669. dprintf("\nTRIAGE_DUMP64:\n");
  2670. dprintf("ServicePackBuild %08lx \n", Triage->ServicePackBuild );
  2671. dprintf("SizeOfDump %08lx \n", Triage->SizeOfDump );
  2672. dprintf("ValidOffset %08lx \n", Triage->ValidOffset );
  2673. dprintf("ContextOffset %08lx \n", Triage->ContextOffset );
  2674. dprintf("ExceptionOffset %08lx \n", Triage->ExceptionOffset );
  2675. dprintf("MmOffset %08lx \n", Triage->MmOffset );
  2676. dprintf("UnloadedDriversOffset %08lx \n", Triage->UnloadedDriversOffset );
  2677. dprintf("PrcbOffset %08lx \n", Triage->PrcbOffset );
  2678. dprintf("ProcessOffset %08lx \n", Triage->ProcessOffset );
  2679. dprintf("ThreadOffset %08lx \n", Triage->ThreadOffset );
  2680. dprintf("CallStackOffset %08lx \n", Triage->CallStackOffset );
  2681. dprintf("SizeOfCallStack %08lx \n", Triage->SizeOfCallStack );
  2682. dprintf("DriverListOffset %08lx \n", Triage->DriverListOffset );
  2683. dprintf("DriverCount %08lx \n", Triage->DriverCount );
  2684. dprintf("StringPoolOffset %08lx \n", Triage->StringPoolOffset );
  2685. dprintf("StringPoolSize %08lx \n", Triage->StringPoolSize );
  2686. dprintf("BrokenDriverOffset %08lx \n", Triage->BrokenDriverOffset );
  2687. dprintf("TriageOptions %08lx \n", Triage->TriageOptions );
  2688. dprintf("TopOfStack %s \n",
  2689. FormatAddr64(Triage->TopOfStack));
  2690. dprintf("BStoreOffset %08lx \n",
  2691. Triage->ArchitectureSpecific.Ia64.BStoreOffset );
  2692. dprintf("SizeOfBStore %08lx \n",
  2693. Triage->ArchitectureSpecific.Ia64.SizeOfBStore );
  2694. dprintf("LimitOfBStore %s \n",
  2695. FormatAddr64(Triage->ArchitectureSpecific.Ia64.LimitOfBStore));
  2696. if (((m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_BASIC_INFO) ==
  2697. TRIAGE_DUMP_BASIC_INFO) &&
  2698. (m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_DATAPAGE))
  2699. {
  2700. dprintf("DataPageAddress %s \n",
  2701. FormatAddr64(Triage->DataPageAddress));
  2702. dprintf("DataPageOffset %08lx \n", Triage->DataPageOffset );
  2703. dprintf("DataPageSize %08lx \n", Triage->DataPageSize );
  2704. }
  2705. if (((m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_BASIC_INFO) ==
  2706. TRIAGE_DUMP_BASIC_INFO) &&
  2707. (m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_DEBUGGER_DATA))
  2708. {
  2709. dprintf("DebuggerDataOffset %08lx \n", Triage->DebuggerDataOffset);
  2710. dprintf("DebuggerDataSize %08lx \n", Triage->DebuggerDataSize );
  2711. }
  2712. if (((m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_BASIC_INFO) ==
  2713. TRIAGE_DUMP_BASIC_INFO) &&
  2714. (m_Dump->Header.MiniDumpFields & TRIAGE_DUMP_DATA_BLOCKS))
  2715. {
  2716. dprintf("DataBlocksOffset %08lx \n", Triage->DataBlocksOffset );
  2717. dprintf("DataBlocksCount %08lx \n", Triage->DataBlocksCount );
  2718. }
  2719. }
  2720. //----------------------------------------------------------------------------
  2721. //
  2722. // KernelFullDumpTargetInfo.
  2723. //
  2724. //----------------------------------------------------------------------------
  2725. HRESULT
  2726. KernelFull32DumpTargetInfo::Initialize(void)
  2727. {
  2728. // Pick up any potentially modified base mapping pointer.
  2729. m_Dump = (PMEMORY_DUMP32)g_DumpBase;
  2730. dprintf("Kernel Dump File: Full address space is available\n\n");
  2731. g_TargetClass = DEBUG_CLASS_KERNEL;
  2732. g_TargetClassQualifier = DEBUG_KERNEL_FULL_DUMP;
  2733. HRESULT Status = InitGlobals32(m_Dump);
  2734. if (Status != S_OK)
  2735. {
  2736. return Status;
  2737. }
  2738. return KernelFullSumDumpTargetInfo::Initialize();
  2739. }
  2740. void
  2741. KernelFull32DumpTargetInfo::Uninitialize(void)
  2742. {
  2743. m_Dump = NULL;
  2744. KernelDumpTargetInfo::Uninitialize();
  2745. }
  2746. HRESULT
  2747. KernelFull32DumpTargetInfo::ReadBugCheckData(PULONG Code, ULONG64 Args[4])
  2748. {
  2749. *Code = m_Dump->Header.BugCheckCode;
  2750. Args[0] = EXTEND64(m_Dump->Header.BugCheckParameter1);
  2751. Args[1] = EXTEND64(m_Dump->Header.BugCheckParameter2);
  2752. Args[2] = EXTEND64(m_Dump->Header.BugCheckParameter3);
  2753. Args[3] = EXTEND64(m_Dump->Header.BugCheckParameter4);
  2754. return S_OK;
  2755. }
  2756. HRESULT
  2757. KernelFull32DumpTargetInfo::IdentifyDump(PULONG64 BaseMapSize)
  2758. {
  2759. m_Dump = (PMEMORY_DUMP32)g_DumpBase;
  2760. if (m_Dump->Header.Signature != DUMP_SIGNATURE32 ||
  2761. m_Dump->Header.ValidDump != DUMP_VALID_DUMP32 ||
  2762. (m_Dump->Header.DumpType != DUMP_SIGNATURE32 &&
  2763. m_Dump->Header.DumpType != DUMP_TYPE_FULL))
  2764. {
  2765. m_Dump = NULL;
  2766. return E_NOINTERFACE;
  2767. }
  2768. // Summary and triage dumps must be checked before this
  2769. // so there's nothing left to check.
  2770. return S_OK;
  2771. }
  2772. ULONG64
  2773. KernelFull32DumpTargetInfo::PhysicalToOffset(ULONG64 Phys, PULONG Avail)
  2774. {
  2775. ULONG PageIndex = (ULONG)Phys & (g_TargetMachine->m_PageSize - 1);
  2776. *Avail = g_TargetMachine->m_PageSize - PageIndex;
  2777. PPHYSICAL_MEMORY_DESCRIPTOR32 PhysDesc = &m_Dump->Header.PhysicalMemoryBlock;
  2778. ULONG64 Page = Phys >> g_TargetMachine->m_PageShift;
  2779. //
  2780. // Memory start after one page.
  2781. //
  2782. ULONG64 Offset = 1;
  2783. ULONG j = 0;
  2784. while (j < PhysDesc->NumberOfRuns)
  2785. {
  2786. if ((Page >= PhysDesc->Run[j].BasePage) &&
  2787. (Page < (PhysDesc->Run[j].BasePage +
  2788. PhysDesc->Run[j].PageCount)))
  2789. {
  2790. Offset += Page - PhysDesc->Run[j].BasePage;
  2791. return Offset * g_TargetMachine->m_PageSize + PageIndex;
  2792. }
  2793. Offset += PhysDesc->Run[j].PageCount;
  2794. j += 1;
  2795. }
  2796. KdOut("Physical Memory Address %s is greater than MaxPhysicalAddress\n",
  2797. FormatDisp64(Phys));
  2798. return 0;
  2799. }
  2800. void
  2801. KernelFull32DumpTargetInfo::DumpDebug(void)
  2802. {
  2803. PPHYSICAL_MEMORY_DESCRIPTOR32 PhysDesc =
  2804. &m_Dump->Header.PhysicalMemoryBlock;
  2805. ULONG PageSize = g_TargetMachine->m_PageSize;
  2806. dprintf("----- 32 bit Kernel Full Dump Analysis\n");
  2807. DumpHeader32(&m_Dump->Header);
  2808. dprintf("\nPhysical Memory Description:\n");
  2809. dprintf("Number of runs: %d\n", PhysDesc->NumberOfRuns);
  2810. dprintf(" FileOffset Start Address Length\n");
  2811. ULONG j = 0;
  2812. ULONG Offset = 1;
  2813. while (j < PhysDesc->NumberOfRuns)
  2814. {
  2815. dprintf(" %08lx %08lx %08lx\n",
  2816. Offset * PageSize,
  2817. PhysDesc->Run[j].BasePage * PageSize,
  2818. PhysDesc->Run[j].PageCount * PageSize);
  2819. Offset += PhysDesc->Run[j].PageCount;
  2820. j += 1;
  2821. }
  2822. j--;
  2823. dprintf("Last Page: %08lx %08lx\n",
  2824. (Offset - 1) * PageSize,
  2825. (PhysDesc->Run[j].BasePage + PhysDesc->Run[j].PageCount - 1) *
  2826. PageSize);
  2827. KernelFullSumDumpTargetInfo::DumpDebug();
  2828. }
  2829. HRESULT
  2830. KernelFull64DumpTargetInfo::Initialize(void)
  2831. {
  2832. // Pick up any potentially modified base mapping pointer.
  2833. m_Dump = (PMEMORY_DUMP64)g_DumpBase;
  2834. dprintf("Kernel Dump File: Full address space is available\n\n");
  2835. g_TargetClass = DEBUG_CLASS_KERNEL;
  2836. g_TargetClassQualifier = DEBUG_KERNEL_FULL_DUMP;
  2837. HRESULT Status = InitGlobals64(m_Dump);
  2838. if (Status != S_OK)
  2839. {
  2840. return Status;
  2841. }
  2842. return KernelFullSumDumpTargetInfo::Initialize();
  2843. }
  2844. void
  2845. KernelFull64DumpTargetInfo::Uninitialize(void)
  2846. {
  2847. m_Dump = NULL;
  2848. KernelDumpTargetInfo::Uninitialize();
  2849. }
  2850. HRESULT
  2851. KernelFull64DumpTargetInfo::ReadBugCheckData(PULONG Code, ULONG64 Args[4])
  2852. {
  2853. *Code = m_Dump->Header.BugCheckCode;
  2854. Args[0] = m_Dump->Header.BugCheckParameter1;
  2855. Args[1] = m_Dump->Header.BugCheckParameter2;
  2856. Args[2] = m_Dump->Header.BugCheckParameter3;
  2857. Args[3] = m_Dump->Header.BugCheckParameter4;
  2858. return S_OK;
  2859. }
  2860. HRESULT
  2861. KernelFull64DumpTargetInfo::IdentifyDump(PULONG64 BaseMapSize)
  2862. {
  2863. m_Dump = (PMEMORY_DUMP64)g_DumpBase;
  2864. if (m_Dump->Header.Signature != DUMP_SIGNATURE64 ||
  2865. m_Dump->Header.ValidDump != DUMP_VALID_DUMP64 ||
  2866. (m_Dump->Header.DumpType != DUMP_SIGNATURE32 &&
  2867. m_Dump->Header.DumpType != DUMP_TYPE_FULL))
  2868. {
  2869. m_Dump = NULL;
  2870. return E_NOINTERFACE;
  2871. }
  2872. // Summary and triage dumps must be checked before this
  2873. // so there's nothing left to check.
  2874. return S_OK;
  2875. }
  2876. ULONG64
  2877. KernelFull64DumpTargetInfo::PhysicalToOffset(ULONG64 Phys, PULONG Avail)
  2878. {
  2879. ULONG PageIndex = (ULONG)Phys & (g_TargetMachine->m_PageSize - 1);
  2880. *Avail = g_TargetMachine->m_PageSize - PageIndex;
  2881. PPHYSICAL_MEMORY_DESCRIPTOR64 PhysDesc = &m_Dump->Header.PhysicalMemoryBlock;
  2882. ULONG64 Page = Phys >> g_TargetMachine->m_PageShift;
  2883. //
  2884. // Memory start after one page.
  2885. //
  2886. ULONG64 Offset = 1;
  2887. ULONG j = 0;
  2888. while (j < PhysDesc->NumberOfRuns)
  2889. {
  2890. if ((Page >= PhysDesc->Run[j].BasePage) &&
  2891. (Page < (PhysDesc->Run[j].BasePage +
  2892. PhysDesc->Run[j].PageCount)))
  2893. {
  2894. Offset += Page - PhysDesc->Run[j].BasePage;
  2895. return Offset * g_TargetMachine->m_PageSize + PageIndex;
  2896. }
  2897. Offset += PhysDesc->Run[j].PageCount;
  2898. j += 1;
  2899. }
  2900. KdOut("Physical Memory Address %I64 is greater than MaxPhysicalAddress\n",
  2901. Phys);
  2902. return 0;
  2903. }
  2904. void
  2905. KernelFull64DumpTargetInfo::DumpDebug(void)
  2906. {
  2907. PPHYSICAL_MEMORY_DESCRIPTOR64 PhysDesc =
  2908. &m_Dump->Header.PhysicalMemoryBlock;
  2909. ULONG PageSize = g_TargetMachine->m_PageSize;
  2910. dprintf("----- 64 bit Kernel Full Dump Analysis\n");
  2911. DumpHeader64(&m_Dump->Header);
  2912. dprintf("\nPhysical Memory Description:\n");
  2913. dprintf("Number of runs: %d\n", PhysDesc->NumberOfRuns);
  2914. dprintf(" FileOffset Start Address Length\n");
  2915. ULONG j = 0;
  2916. ULONG64 Offset = 1;
  2917. while (j < PhysDesc->NumberOfRuns)
  2918. {
  2919. dprintf(" %s %s %s\n",
  2920. FormatAddr64(Offset * PageSize),
  2921. FormatAddr64(PhysDesc->Run[j].BasePage * PageSize),
  2922. FormatAddr64(PhysDesc->Run[j].PageCount * PageSize));
  2923. Offset += PhysDesc->Run[j].PageCount;
  2924. j += 1;
  2925. }
  2926. j--;
  2927. dprintf("Last Page: %s %s\n",
  2928. FormatAddr64((Offset - 1) * PageSize),
  2929. FormatAddr64((PhysDesc->Run[j].BasePage +
  2930. PhysDesc->Run[j].PageCount - 1) *
  2931. PageSize));
  2932. KernelFullSumDumpTargetInfo::DumpDebug();
  2933. }
  2934. //----------------------------------------------------------------------------
  2935. //
  2936. // UserDumpTargetInfo.
  2937. //
  2938. //----------------------------------------------------------------------------
  2939. void
  2940. UserDumpTargetInfo::Uninitialize(void)
  2941. {
  2942. m_HighestMemoryRegion32 = 0;
  2943. m_EventProcess = 0;
  2944. m_EventThread = 0;
  2945. m_ThreadCount = 0;
  2946. DumpTargetInfo::Uninitialize();
  2947. }
  2948. HRESULT
  2949. UserDumpTargetInfo::GetThreadInfoDataOffset(PTHREAD_INFO Thread,
  2950. ULONG64 ThreadHandle,
  2951. PULONG64 Offset)
  2952. {
  2953. if (Thread != NULL && Thread->DataOffset != 0)
  2954. {
  2955. *Offset = Thread->DataOffset;
  2956. return S_OK;
  2957. }
  2958. BOOL ContextThread = FALSE;
  2959. if (Thread != NULL)
  2960. {
  2961. ThreadHandle = Thread->Handle;
  2962. ContextThread = Thread == g_RegContextThread;
  2963. }
  2964. else if (ThreadHandle == NULL)
  2965. {
  2966. ThreadHandle = g_CurrentProcess->CurrentThread->Handle;
  2967. ContextThread = g_CurrentProcess->CurrentThread == g_RegContextThread;
  2968. }
  2969. HRESULT Status;
  2970. ULONG64 TebAddr;
  2971. ULONG Id, Suspend;
  2972. if ((Status = GetThreadInfo(VIRTUAL_THREAD_INDEX(ThreadHandle),
  2973. &Id, &Suspend, &TebAddr)) != S_OK)
  2974. {
  2975. ErrOut("User dump thread %u not available\n",
  2976. VIRTUAL_THREAD_INDEX(ThreadHandle));
  2977. return Status;
  2978. }
  2979. if (TebAddr == 0)
  2980. {
  2981. //
  2982. // NT4 dumps have a bug - they do not fill in the TEB value.
  2983. // luckily, for pretty much all user mode processes, the
  2984. // TEBs start two pages down from the highest user address.
  2985. // For example, on x86 we try 0x7FFDE000 (on 3GB systems 0xBFFDE000).
  2986. //
  2987. if (!g_TargetMachine->m_Ptr64 && m_HighestMemoryRegion32 > 0x80000000)
  2988. {
  2989. TebAddr = 0xbffe0000;
  2990. }
  2991. else
  2992. {
  2993. TebAddr = 0x7ffe0000;
  2994. }
  2995. TebAddr -= 2 * g_TargetMachine->m_PageSize;
  2996. //
  2997. // Try and validate that this is really a TEB.
  2998. // If it isn't search lower memory addresses for
  2999. // a while, but don't get hung up here.
  3000. //
  3001. ULONG64 TebCheck = TebAddr;
  3002. ULONG Attempts = 8;
  3003. BOOL IsATeb = FALSE;
  3004. while (Attempts > 0)
  3005. {
  3006. ULONG64 TebSelf;
  3007. // Check if this looks like a TEB. TEBs have a
  3008. // self pointer in the TIB that's useful for this.
  3009. if (ReadPointer(g_TargetMachine,
  3010. TebCheck + 6 * (g_TargetMachine->m_Ptr64 ? 8 : 4),
  3011. &TebSelf) == S_OK &&
  3012. TebSelf == TebCheck)
  3013. {
  3014. // It looks like it's a TEB. Remember this address
  3015. // so that if all searching fails we'll at least
  3016. // return some TEB.
  3017. TebAddr = TebCheck;
  3018. IsATeb = TRUE;
  3019. // If the given thread is the current register context
  3020. // thread we can check and see if the current SP falls
  3021. // within the stack limits in the TEB.
  3022. if (ContextThread)
  3023. {
  3024. ULONG64 StackBase, StackLimit;
  3025. ADDR Sp;
  3026. g_TargetMachine->GetSP(&Sp);
  3027. if (g_TargetMachine->m_Ptr64)
  3028. {
  3029. StackBase = STACK_BASE_FROM_TEB64;
  3030. StackLimit = StackBase + 8;
  3031. }
  3032. else
  3033. {
  3034. StackBase = STACK_BASE_FROM_TEB32;
  3035. StackLimit = StackBase + 4;
  3036. }
  3037. if (ReadPointer(g_TargetMachine,
  3038. TebCheck + StackBase,
  3039. &StackBase) == S_OK &&
  3040. ReadPointer(g_TargetMachine,
  3041. TebCheck + StackLimit,
  3042. &StackLimit) == S_OK &&
  3043. Flat(Sp) >= StackLimit &&
  3044. Flat(Sp) <= StackBase)
  3045. {
  3046. // SP is within stack limits, everything
  3047. // looks good.
  3048. break;
  3049. }
  3050. }
  3051. else
  3052. {
  3053. // Can't validate SP so just go with it.
  3054. break;
  3055. }
  3056. // As long as we're looking through real TEBs
  3057. // we'll continue searching. Otherwise we
  3058. // wouldn't be able to locate TEBs in dumps that
  3059. // have a lot of threads.
  3060. Attempts++;
  3061. }
  3062. // The memory either wasn't a TEB or was the
  3063. // wrong TEB. Drop down a page and try again.
  3064. TebCheck -= g_TargetMachine->m_PageSize;
  3065. Attempts--;
  3066. }
  3067. WarnOut("WARNING: Teb %u pointer is NULL - "
  3068. "defaulting to %s\n", VIRTUAL_THREAD_INDEX(ThreadHandle),
  3069. FormatAddr64(TebAddr));
  3070. if (!IsATeb)
  3071. {
  3072. WarnOut("WARNING: %s does not appear to be a TEB\n",
  3073. FormatAddr64(TebAddr));
  3074. }
  3075. else if (Attempts == 0)
  3076. {
  3077. WarnOut("WARNING: %s does not appear to be the right TEB\n",
  3078. FormatAddr64(TebAddr));
  3079. }
  3080. }
  3081. *Offset = TebAddr;
  3082. if (Thread != NULL)
  3083. {
  3084. Thread->DataOffset = TebAddr;
  3085. }
  3086. return S_OK;
  3087. }
  3088. HRESULT
  3089. UserDumpTargetInfo::GetProcessInfoDataOffset(PTHREAD_INFO Thread,
  3090. ULONG Processor,
  3091. ULONG64 ThreadData,
  3092. PULONG64 Offset)
  3093. {
  3094. if (Thread != NULL && Thread->Process->DataOffset != 0)
  3095. {
  3096. *Offset = Thread->Process->DataOffset;
  3097. return S_OK;
  3098. }
  3099. HRESULT Status;
  3100. if (Thread != NULL || ThreadData == 0)
  3101. {
  3102. if ((Status = GetThreadInfoDataOffset(Thread,
  3103. VIRTUAL_THREAD_HANDLE(Processor),
  3104. &ThreadData)) != S_OK)
  3105. {
  3106. return Status;
  3107. }
  3108. }
  3109. ThreadData += g_TargetMachine->m_Ptr64 ? PEB_FROM_TEB64 : PEB_FROM_TEB32;
  3110. if ((Status = ReadPointer(g_TargetMachine, ThreadData, Offset)) != S_OK)
  3111. {
  3112. return Status;
  3113. }
  3114. if (Thread != NULL)
  3115. {
  3116. Thread->Process->DataOffset = *Offset;
  3117. }
  3118. return S_OK;
  3119. }
  3120. HRESULT
  3121. UserDumpTargetInfo::GetThreadInfoTeb(PTHREAD_INFO Thread,
  3122. ULONG Processor,
  3123. ULONG64 ThreadData,
  3124. PULONG64 Offset)
  3125. {
  3126. return GetThreadInfoDataOffset(Thread, ThreadData, Offset);
  3127. }
  3128. HRESULT
  3129. UserDumpTargetInfo::GetProcessInfoPeb(PTHREAD_INFO Thread,
  3130. ULONG Processor,
  3131. ULONG64 ThreadData,
  3132. PULONG64 Offset)
  3133. {
  3134. // Thread data is not useful.
  3135. return GetProcessInfoDataOffset(Thread, 0, 0, Offset);
  3136. }
  3137. HRESULT
  3138. UserDumpTargetInfo::GetSelDescriptor(MachineInfo* Machine,
  3139. ULONG64 Thread, ULONG Selector,
  3140. PDESCRIPTOR64 Desc)
  3141. {
  3142. return EmulateNtSelDescriptor(Machine, Selector, Desc);
  3143. }
  3144. //----------------------------------------------------------------------------
  3145. //
  3146. // UserFullDumpTargetInfo.
  3147. //
  3148. //----------------------------------------------------------------------------
  3149. void
  3150. UserFullDumpTargetInfo::Uninitialize(void)
  3151. {
  3152. UserDumpTargetInfo::Uninitialize();
  3153. }
  3154. HRESULT
  3155. UserFullDumpTargetInfo::GetBuildAndPlatform(ULONG MajorVersion,
  3156. ULONG MinorVersion,
  3157. PULONG BuildNumber,
  3158. PULONG PlatformId)
  3159. {
  3160. //
  3161. // The only way to distinguish user dump
  3162. // platforms is guessing from the Major/MinorVersion
  3163. // and the extra QFE/Hotfix data.
  3164. //
  3165. switch(MajorVersion)
  3166. {
  3167. case 4:
  3168. switch(MinorVersion & 0xffff)
  3169. {
  3170. case 0:
  3171. // This could be Win95 or NT4. We mostly
  3172. // deal with NT dumps so just assume NT.
  3173. *BuildNumber = 1381;
  3174. *PlatformId = VER_PLATFORM_WIN32_NT;
  3175. break;
  3176. case 3:
  3177. // Win95 OSR releases were 4.03. Treat them
  3178. // as Win95 for now.
  3179. *BuildNumber = 950;
  3180. *PlatformId = VER_PLATFORM_WIN32_WINDOWS;
  3181. break;
  3182. case 10:
  3183. // This could be Win98 or Win98SE. Go with Win98.
  3184. *BuildNumber = 1998;
  3185. *PlatformId = VER_PLATFORM_WIN32_WINDOWS;
  3186. break;
  3187. }
  3188. break;
  3189. case 5:
  3190. *PlatformId = VER_PLATFORM_WIN32_NT;
  3191. switch(MinorVersion & 0xffff)
  3192. {
  3193. case 0:
  3194. *BuildNumber = 2195;
  3195. break;
  3196. case 1:
  3197. // Just has to be greater than 2195 to
  3198. // distinguish it from Win2K RTM.
  3199. *BuildNumber = 2196;
  3200. break;
  3201. }
  3202. break;
  3203. case 0:
  3204. // AV: Busted BETA of the debugger generates a broken dump file
  3205. // Guess it's 2195.
  3206. WarnOut("Dump file was generated with NULL version - guessing NT5, ");
  3207. *PlatformId = VER_PLATFORM_WIN32_NT;
  3208. *BuildNumber = 2195;
  3209. break;
  3210. default:
  3211. // Other platforms are not supported.
  3212. ErrOut("Dump file was generated by an unsupported system, ");
  3213. ErrOut("version %x.%x\n", MajorVersion, MinorVersion & 0xffff);
  3214. return E_INVALIDARG;
  3215. }
  3216. // Newer full user dumps have the actual build number in
  3217. // the high word, so use it if it's present.
  3218. if (MinorVersion >> 16)
  3219. {
  3220. *BuildNumber = MinorVersion >> 16;
  3221. }
  3222. return S_OK;
  3223. }
  3224. HRESULT
  3225. UserFull32DumpTargetInfo::Initialize(void)
  3226. {
  3227. // Pick up any potentially modified base mapping pointer.
  3228. m_Header = (PUSERMODE_CRASHDUMP_HEADER32)g_DumpBase;
  3229. dprintf("User Dump File: Only application data is available\n\n");
  3230. g_TargetClass = DEBUG_CLASS_USER_WINDOWS;
  3231. g_TargetClassQualifier = DEBUG_USER_WINDOWS_DUMP;
  3232. ULONG BuildNumber;
  3233. ULONG PlatformId;
  3234. HRESULT Status;
  3235. if ((Status = GetBuildAndPlatform(m_Header->MajorVersion,
  3236. m_Header->MinorVersion,
  3237. &BuildNumber, &PlatformId)) != S_OK)
  3238. {
  3239. return Status;
  3240. }
  3241. if ((Status = DmppInitGlobals(BuildNumber, 0,
  3242. m_Header->MachineImageType, PlatformId,
  3243. m_Header->MajorVersion,
  3244. m_Header->MinorVersion & 0xffff)) != S_OK)
  3245. {
  3246. return Status;
  3247. }
  3248. // Dump does not contain this information.
  3249. g_TargetNumberProcessors = 1;
  3250. DEBUG_EVENT32 Event;
  3251. if (DmppReadFileOffset(DUMP_INFO_DUMP, m_Header->DebugEventOffset, &Event,
  3252. sizeof(Event)) != sizeof(Event))
  3253. {
  3254. ErrOut("Unable to read debug event at offset %x\n",
  3255. m_Header->DebugEventOffset);
  3256. return E_FAIL;
  3257. }
  3258. m_EventProcess = Event.dwProcessId;
  3259. m_EventThread = Event.dwThreadId;
  3260. if (Event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT)
  3261. {
  3262. ExceptionRecord32To64(&Event.u.Exception.ExceptionRecord,
  3263. &g_DumpException);
  3264. g_DumpExceptionFirstChance = Event.u.Exception.dwFirstChance;
  3265. }
  3266. else
  3267. {
  3268. // Fake an exception.
  3269. ZeroMemory(&g_DumpException, sizeof(g_DumpException));
  3270. g_DumpException.ExceptionCode = STATUS_BREAKPOINT;
  3271. g_DumpExceptionFirstChance = FALSE;
  3272. }
  3273. m_ThreadCount = m_Header->ThreadCount;
  3274. m_Memory = (PMEMORY_BASIC_INFORMATION32)
  3275. IndexByByte(m_Header, m_Header->MemoryRegionOffset);
  3276. //
  3277. // Determine the highest memory region address.
  3278. // This helps differentiate 2GB systems from 3GB systems.
  3279. //
  3280. ULONG i;
  3281. PMEMORY_BASIC_INFORMATION32 Mem;
  3282. ULONG TotalMemory;
  3283. Mem = m_Memory;
  3284. m_HighestMemoryRegion32 = 0;
  3285. for (i = 0; i < m_Header->MemoryRegionCount; i++)
  3286. {
  3287. if (Mem->BaseAddress > m_HighestMemoryRegion32)
  3288. {
  3289. m_HighestMemoryRegion32 = Mem->BaseAddress;
  3290. }
  3291. Mem++;
  3292. }
  3293. VerbOut(" Memory regions: %d\n",
  3294. m_Header->MemoryRegionCount);
  3295. TotalMemory = 0;
  3296. Mem = m_Memory;
  3297. for (i = 0; i < m_Header->MemoryRegionCount; i++)
  3298. {
  3299. VerbOut(" %5d: %08X - %08X off %08X, prot %08X, type %08X\n",
  3300. i, Mem->BaseAddress,
  3301. Mem->BaseAddress + Mem->RegionSize - 1,
  3302. TotalMemory + m_Header->DataOffset,
  3303. Mem->Protect, Mem->Type);
  3304. if ((Mem->Protect & PAGE_GUARD) ||
  3305. (Mem->Protect & PAGE_NOACCESS) ||
  3306. (Mem->State & MEM_FREE) ||
  3307. (Mem->State & MEM_RESERVE))
  3308. {
  3309. VerbOut(" Region has data-less pages\n");
  3310. }
  3311. TotalMemory += Mem->RegionSize;
  3312. Mem++;
  3313. }
  3314. VerbOut(" Total memory region size %X, file %08X - %08X\n",
  3315. TotalMemory, m_Header->DataOffset,
  3316. m_Header->DataOffset + TotalMemory - 1);
  3317. //
  3318. // Determine whether guard pages are present in
  3319. // the dump content or not.
  3320. //
  3321. // First try with IgnoreGuardPages == TRUE.
  3322. //
  3323. m_IgnoreGuardPages = TRUE;
  3324. if (!VerifyModules())
  3325. {
  3326. //
  3327. // That didn't work, try IgnoreGuardPages == FALSE.
  3328. //
  3329. m_IgnoreGuardPages = FALSE;
  3330. if (!VerifyModules())
  3331. {
  3332. ErrOut("Module list is corrupt\n");
  3333. return E_FAIL;
  3334. }
  3335. }
  3336. return S_OK;
  3337. }
  3338. void
  3339. UserFull32DumpTargetInfo::Uninitialize(void)
  3340. {
  3341. m_Header = NULL;
  3342. m_Memory = NULL;
  3343. m_IgnoreGuardPages = TRUE;
  3344. UserFullDumpTargetInfo::Uninitialize();
  3345. }
  3346. HRESULT
  3347. UserFull32DumpTargetInfo::GetTargetContext(
  3348. ULONG64 Thread,
  3349. PVOID Context
  3350. )
  3351. {
  3352. if (VIRTUAL_THREAD_INDEX(Thread) >= m_Header->ThreadCount)
  3353. {
  3354. return E_INVALIDARG;
  3355. }
  3356. if (DmppReadFileOffset(DUMP_INFO_DUMP,
  3357. m_Header->ThreadOffset +
  3358. VIRTUAL_THREAD_INDEX(Thread) *
  3359. g_TargetMachine->m_SizeTargetContext,
  3360. Context,
  3361. g_TargetMachine->m_SizeTargetContext) ==
  3362. g_TargetMachine->m_SizeTargetContext)
  3363. {
  3364. return S_OK;
  3365. }
  3366. else
  3367. {
  3368. return E_FAIL;
  3369. }
  3370. }
  3371. HRESULT
  3372. UserFull32DumpTargetInfo::GetImageVersionInformation(PCSTR ImagePath,
  3373. ULONG64 ImageBase,
  3374. PCSTR Item,
  3375. PVOID Buffer,
  3376. ULONG BufferSize,
  3377. PULONG VerInfoSize)
  3378. {
  3379. HRESULT Status;
  3380. IMAGE_DOS_HEADER DosHdr;
  3381. IMAGE_NT_HEADERS32 NtHdr;
  3382. if ((Status = ReadAllVirtual(ImageBase, &DosHdr, sizeof(DosHdr))) != S_OK)
  3383. {
  3384. return Status;
  3385. }
  3386. if (DosHdr.e_magic != IMAGE_DOS_SIGNATURE)
  3387. {
  3388. return E_FAIL;
  3389. }
  3390. if ((Status = ReadAllVirtual(ImageBase + DosHdr.e_lfanew,
  3391. &NtHdr, sizeof(NtHdr))) != S_OK)
  3392. {
  3393. return Status;
  3394. }
  3395. if (NtHdr.Signature != IMAGE_NT_SIGNATURE ||
  3396. NtHdr.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR32_MAGIC)
  3397. {
  3398. return E_FAIL;
  3399. }
  3400. if (NtHdr.OptionalHeader.NumberOfRvaAndSizes <=
  3401. IMAGE_DIRECTORY_ENTRY_RESOURCE)
  3402. {
  3403. // No resource information so no version information.
  3404. return E_NOINTERFACE;
  3405. }
  3406. return ReadImageVersionInfo(ImageBase, Item,
  3407. Buffer, BufferSize, VerInfoSize,
  3408. &NtHdr.OptionalHeader.
  3409. DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]);
  3410. }
  3411. HRESULT
  3412. UserFull32DumpTargetInfo::QueryMemoryRegion(PULONG64 Handle,
  3413. BOOL HandleIsOffset,
  3414. PMEMORY_BASIC_INFORMATION64 Info)
  3415. {
  3416. ULONG Index;
  3417. if (HandleIsOffset)
  3418. {
  3419. for (Index = 0; Index < m_Header->MemoryRegionCount; Index++)
  3420. {
  3421. if ((ULONG)*Handle >= m_Memory[Index].BaseAddress &&
  3422. (ULONG)*Handle < m_Memory[Index].BaseAddress +
  3423. m_Memory[Index].RegionSize)
  3424. {
  3425. break;
  3426. }
  3427. }
  3428. if (Index >= m_Header->MemoryRegionCount)
  3429. {
  3430. return E_NOINTERFACE;
  3431. }
  3432. }
  3433. else
  3434. {
  3435. Index = (ULONG)*Handle;
  3436. for (;;)
  3437. {
  3438. if (Index >= m_Header->MemoryRegionCount)
  3439. {
  3440. return HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES);
  3441. }
  3442. if (!(m_Memory[Index].Protect & PAGE_GUARD))
  3443. {
  3444. break;
  3445. }
  3446. Index++;
  3447. }
  3448. }
  3449. MemoryBasicInformation32To64(&m_Memory[Index], Info);
  3450. *Handle = ++Index;
  3451. return S_OK;
  3452. }
  3453. HRESULT
  3454. UserFull32DumpTargetInfo::IdentifyDump(PULONG64 BaseMapSize)
  3455. {
  3456. m_Header = (PUSERMODE_CRASHDUMP_HEADER32)g_DumpBase;
  3457. if (m_Header->Signature != USERMODE_CRASHDUMP_SIGNATURE ||
  3458. m_Header->ValidDump != USERMODE_CRASHDUMP_VALID_DUMP32)
  3459. {
  3460. m_Header = NULL;
  3461. return E_NOINTERFACE;
  3462. }
  3463. //
  3464. // Check for the presence of some basic things.
  3465. //
  3466. if (m_Header->ThreadCount == 0 ||
  3467. m_Header->ModuleCount == 0 ||
  3468. m_Header->MemoryRegionCount == 0)
  3469. {
  3470. ErrOut("Thread, module or memory region count is zero.\n"
  3471. "The dump file is probably corrupt.\n");
  3472. return HR_DUMP_CORRUPT;
  3473. }
  3474. if (m_Header->ThreadOffset == 0 ||
  3475. m_Header->ModuleOffset == 0 ||
  3476. m_Header->DataOffset == 0 ||
  3477. m_Header->MemoryRegionOffset == 0 ||
  3478. m_Header->DebugEventOffset == 0 ||
  3479. m_Header->ThreadStateOffset == 0)
  3480. {
  3481. ErrOut("A dump header data offset is zero.\n"
  3482. "The dump file is probably corrupt.\n");
  3483. return HR_DUMP_CORRUPT;
  3484. }
  3485. // We don't want to have to call DmppReadFileOffset
  3486. // every time we check memory ranges so just require
  3487. // that the memory descriptors fit in the base view.
  3488. *BaseMapSize = m_Header->MemoryRegionOffset +
  3489. m_Header->MemoryRegionCount * sizeof(*m_Memory);
  3490. return S_OK;
  3491. }
  3492. void
  3493. UserFull32DumpTargetInfo::DumpDebug(void)
  3494. {
  3495. dprintf("----- 32 bit User Full Dump Analysis\n\n");
  3496. dprintf("MajorVersion: %d\n", m_Header->MajorVersion);
  3497. dprintf("MinorVersion: %d (Build %d)\n",
  3498. m_Header->MinorVersion & 0xffff,
  3499. m_Header->MinorVersion >> 16);
  3500. dprintf("MachineImageType: %08lx\n", m_Header->MachineImageType);
  3501. dprintf("ThreadCount: %08lx\n", m_Header->ThreadCount);
  3502. dprintf("ThreadOffset: %08lx\n", m_Header->ThreadOffset);
  3503. dprintf("ModuleCount: %08lx\n", m_Header->ModuleCount);
  3504. dprintf("ModuleOffset: %08lx\n", m_Header->ModuleOffset);
  3505. dprintf("DebugEventOffset: %08lx\n", m_Header->DebugEventOffset);
  3506. dprintf("VersionInfoOffset: %08lx\n", m_Header->VersionInfoOffset);
  3507. dprintf("\nVirtual Memory Description:\n");
  3508. dprintf("Number of regions: %d\n", m_Header->MemoryRegionCount);
  3509. dprintf(" FileOffset Start Address Length\n");
  3510. ULONG j = 0;
  3511. ULONG64 Offset = 0;
  3512. BOOL Skip;
  3513. while (j < m_Header->MemoryRegionCount)
  3514. {
  3515. Skip = FALSE;
  3516. dprintf(" %12I64lx %08lx %08lx",
  3517. Offset,
  3518. m_Memory[j].BaseAddress,
  3519. m_Memory[j].RegionSize);
  3520. if (m_Memory[j].Protect & PAGE_GUARD)
  3521. {
  3522. dprintf(" Guard Page");
  3523. if (m_IgnoreGuardPages)
  3524. {
  3525. dprintf(" - Ignored");
  3526. Skip = TRUE;
  3527. }
  3528. }
  3529. if (!Skip)
  3530. {
  3531. Offset += m_Memory[j].RegionSize;
  3532. }
  3533. dprintf("\n");
  3534. j += 1;
  3535. }
  3536. }
  3537. ULONG64
  3538. UserFull32DumpTargetInfo::VirtualToOffset(ULONG64 Virt,
  3539. PULONG File, PULONG Avail)
  3540. {
  3541. ULONG i;
  3542. ULONG Offset = 0;
  3543. *File = DUMP_INFO_DUMP;
  3544. // Ignore the upper 32 bits to avoid getting
  3545. // confused by sign extensions in pointer handling
  3546. Virt &= 0xffffffff;
  3547. for (i = 0; i < m_Header->MemoryRegionCount; i++)
  3548. {
  3549. if (m_IgnoreGuardPages)
  3550. {
  3551. //
  3552. // Guard pages get reported, but they are not written
  3553. // out to the file
  3554. //
  3555. if (m_Memory[i].Protect & PAGE_GUARD)
  3556. {
  3557. continue;
  3558. }
  3559. }
  3560. if (Virt >= m_Memory[i].BaseAddress &&
  3561. Virt < m_Memory[i].BaseAddress + m_Memory[i].RegionSize)
  3562. {
  3563. ULONG Frag = (ULONG)Virt - m_Memory[i].BaseAddress;
  3564. *Avail = m_Memory[i].RegionSize - Frag;
  3565. if (Virt == (g_DebugDump_VirtualAddress & 0xffffffff))
  3566. {
  3567. g_NtDllCalls.DbgPrint("%X at offset %X\n",
  3568. (ULONG)Virt,
  3569. m_Header->DataOffset + Offset + Frag);
  3570. }
  3571. return m_Header->DataOffset + Offset + Frag;
  3572. }
  3573. Offset += m_Memory[i].RegionSize;
  3574. }
  3575. return 0;
  3576. }
  3577. HRESULT
  3578. UserFull32DumpTargetInfo::GetThreadInfo(ULONG Index,
  3579. PULONG Id, PULONG Suspend,
  3580. PULONG64 Teb)
  3581. {
  3582. if (Index >= m_ThreadCount)
  3583. {
  3584. return E_INVALIDARG;
  3585. }
  3586. CRASH_THREAD32 Thread;
  3587. if (DmppReadFileOffset(DUMP_INFO_DUMP,
  3588. m_Header->ThreadStateOffset +
  3589. Index * sizeof(Thread),
  3590. &Thread, sizeof(Thread)) != sizeof(Thread))
  3591. {
  3592. return E_FAIL;
  3593. }
  3594. *Id = Thread.ThreadId;
  3595. *Suspend = Thread.SuspendCount;
  3596. *Teb = EXTEND64(Thread.Teb);
  3597. return S_OK;
  3598. }
  3599. // #define DBG_VERIFY_MOD
  3600. BOOL
  3601. UserFull32DumpTargetInfo::VerifyModules(void)
  3602. {
  3603. CRASH_MODULE32 CrashModule;
  3604. ULONG i;
  3605. IMAGE_DOS_HEADER DosHeader;
  3606. ULONG Read;
  3607. BOOL Succ = TRUE;
  3608. ULONG Offset;
  3609. PSTR Env;
  3610. Env = getenv("DBGENG_VERIFY_MODULES");
  3611. if (Env != NULL)
  3612. {
  3613. return atoi(Env) == m_IgnoreGuardPages;
  3614. }
  3615. Offset = m_Header->ModuleOffset;
  3616. #ifdef DBG_VERIFY_MOD
  3617. g_NtDllCalls.DbgPrint("Verify %d modules at offset %X\n",
  3618. m_Header->ModuleCount, Offset);
  3619. #endif
  3620. for (i = 0; i < m_Header->ModuleCount; i++)
  3621. {
  3622. if (DmppReadFileOffset(DUMP_INFO_DUMP, Offset,
  3623. &CrashModule, sizeof(CrashModule)) !=
  3624. sizeof(CrashModule))
  3625. {
  3626. return FALSE;
  3627. }
  3628. #ifdef DBG_VERIFY_MOD
  3629. g_NtDllCalls.DbgPrint("Mod %d of %d offs %X, base %s, ",
  3630. i, m_Header->ModuleCount, Offset,
  3631. FormatAddr64(CrashModule.BaseOfImage));
  3632. if (ReadVirtual(CrashModule.BaseOfImage, &DosHeader,
  3633. sizeof(DosHeader), &Read) != S_OK ||
  3634. Read != sizeof(DosHeader))
  3635. {
  3636. g_NtDllCalls.DbgPrint("unable to read header\n");
  3637. }
  3638. else
  3639. {
  3640. g_NtDllCalls.DbgPrint("magic %04X\n", DosHeader.e_magic);
  3641. }
  3642. #endif
  3643. //
  3644. // It is not strictly a requirement that every image
  3645. // begin with an MZ header, though all of our tools
  3646. // today produce images like this. Check for it
  3647. // as a sanity check since it's so common nowadays.
  3648. //
  3649. if (ReadVirtual(CrashModule.BaseOfImage, &DosHeader,
  3650. sizeof(DosHeader), &Read) != S_OK ||
  3651. Read != sizeof(DosHeader) ||
  3652. DosHeader.e_magic != IMAGE_DOS_SIGNATURE)
  3653. {
  3654. Succ = FALSE;
  3655. break;
  3656. }
  3657. Offset += sizeof(CrashModule) + CrashModule.ImageNameLength;
  3658. }
  3659. #ifdef DBG_VERIFY_MOD
  3660. g_NtDllCalls.DbgPrint("VerifyModules returning %d, %d of %d mods\n",
  3661. Succ, i, m_Header->ModuleCount);
  3662. #endif
  3663. return Succ;
  3664. }
  3665. HRESULT
  3666. UserFull64DumpTargetInfo::Initialize(void)
  3667. {
  3668. // Pick up any potentially modified base mapping pointer.
  3669. m_Header = (PUSERMODE_CRASHDUMP_HEADER64)g_DumpBase;
  3670. dprintf("User Dump File: Only application data is available\n\n");
  3671. g_TargetClass = DEBUG_CLASS_USER_WINDOWS;
  3672. g_TargetClassQualifier = DEBUG_USER_WINDOWS_DUMP;
  3673. ULONG BuildNumber;
  3674. ULONG PlatformId;
  3675. HRESULT Status;
  3676. if ((Status = GetBuildAndPlatform(m_Header->MajorVersion,
  3677. m_Header->MinorVersion,
  3678. &BuildNumber, &PlatformId)) != S_OK)
  3679. {
  3680. return Status;
  3681. }
  3682. if ((Status = DmppInitGlobals(BuildNumber, 0,
  3683. m_Header->MachineImageType, PlatformId,
  3684. m_Header->MajorVersion,
  3685. m_Header->MinorVersion & 0xffff)) != S_OK)
  3686. {
  3687. return Status;
  3688. }
  3689. // Dump does not contain this information.
  3690. g_TargetNumberProcessors = 1;
  3691. DEBUG_EVENT64 Event;
  3692. if (DmppReadFileOffset(DUMP_INFO_DUMP, m_Header->DebugEventOffset, &Event,
  3693. sizeof(Event)) != sizeof(Event))
  3694. {
  3695. ErrOut("Unable to read debug event at offset %I64x\n",
  3696. m_Header->DebugEventOffset);
  3697. return E_FAIL;
  3698. }
  3699. m_EventProcess = Event.dwProcessId;
  3700. m_EventThread = Event.dwThreadId;
  3701. if (Event.dwDebugEventCode == EXCEPTION_DEBUG_EVENT)
  3702. {
  3703. g_DumpException = Event.u.Exception.ExceptionRecord;
  3704. g_DumpExceptionFirstChance = Event.u.Exception.dwFirstChance;
  3705. }
  3706. else
  3707. {
  3708. // Fake an exception.
  3709. ZeroMemory(&g_DumpException, sizeof(g_DumpException));
  3710. g_DumpException.ExceptionCode = STATUS_BREAKPOINT;
  3711. g_DumpExceptionFirstChance = FALSE;
  3712. }
  3713. m_ThreadCount = m_Header->ThreadCount;
  3714. m_Memory = (PMEMORY_BASIC_INFORMATION64)
  3715. IndexByByte(m_Header, m_Header->MemoryRegionOffset);
  3716. ULONG64 TotalMemory;
  3717. ULONG i;
  3718. VerbOut(" Memory regions: %d\n",
  3719. m_Header->MemoryRegionCount);
  3720. TotalMemory = 0;
  3721. PMEMORY_BASIC_INFORMATION64 Mem = m_Memory;
  3722. for (i = 0; i < m_Header->MemoryRegionCount; i++)
  3723. {
  3724. VerbOut(" %5d: %s - %s, prot %08X, type %08X\n",
  3725. i, FormatAddr64(Mem->BaseAddress),
  3726. FormatAddr64(Mem->BaseAddress + Mem->RegionSize - 1),
  3727. Mem->Protect, Mem->Type);
  3728. if ((Mem->Protect & PAGE_GUARD) ||
  3729. (Mem->Protect & PAGE_NOACCESS) ||
  3730. (Mem->State & MEM_FREE) ||
  3731. (Mem->State & MEM_RESERVE))
  3732. {
  3733. VerbOut(" Region has data-less pages\n");
  3734. }
  3735. TotalMemory += Mem->RegionSize;
  3736. Mem++;
  3737. }
  3738. VerbOut(" Total memory region size %s\n",
  3739. FormatAddr64(TotalMemory));
  3740. return S_OK;
  3741. }
  3742. void
  3743. UserFull64DumpTargetInfo::Uninitialize(void)
  3744. {
  3745. m_Header = NULL;
  3746. m_Memory = NULL;
  3747. UserFullDumpTargetInfo::Uninitialize();
  3748. }
  3749. HRESULT
  3750. UserFull64DumpTargetInfo::GetTargetContext(
  3751. ULONG64 Thread,
  3752. PVOID Context
  3753. )
  3754. {
  3755. if (VIRTUAL_THREAD_INDEX(Thread) >= m_Header->ThreadCount)
  3756. {
  3757. return E_INVALIDARG;
  3758. }
  3759. if (DmppReadFileOffset(DUMP_INFO_DUMP,
  3760. m_Header->ThreadOffset +
  3761. VIRTUAL_THREAD_INDEX(Thread) *
  3762. g_TargetMachine->m_SizeTargetContext,
  3763. Context,
  3764. g_TargetMachine->m_SizeTargetContext) ==
  3765. g_TargetMachine->m_SizeTargetContext)
  3766. {
  3767. return S_OK;
  3768. }
  3769. else
  3770. {
  3771. return E_FAIL;
  3772. }
  3773. }
  3774. HRESULT
  3775. UserFull64DumpTargetInfo::GetImageVersionInformation(PCSTR ImagePath,
  3776. ULONG64 ImageBase,
  3777. PCSTR Item,
  3778. PVOID Buffer,
  3779. ULONG BufferSize,
  3780. PULONG VerInfoSize)
  3781. {
  3782. HRESULT Status;
  3783. IMAGE_DOS_HEADER DosHdr;
  3784. IMAGE_NT_HEADERS64 NtHdr;
  3785. if ((Status = ReadAllVirtual(ImageBase, &DosHdr, sizeof(DosHdr))) != S_OK)
  3786. {
  3787. return Status;
  3788. }
  3789. if (DosHdr.e_magic != IMAGE_DOS_SIGNATURE)
  3790. {
  3791. return E_FAIL;
  3792. }
  3793. if ((Status = ReadAllVirtual(ImageBase + DosHdr.e_lfanew,
  3794. &NtHdr, sizeof(NtHdr))) != S_OK)
  3795. {
  3796. return Status;
  3797. }
  3798. if (NtHdr.Signature != IMAGE_NT_SIGNATURE ||
  3799. NtHdr.OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR64_MAGIC)
  3800. {
  3801. return E_FAIL;
  3802. }
  3803. if (NtHdr.OptionalHeader.NumberOfRvaAndSizes <=
  3804. IMAGE_DIRECTORY_ENTRY_RESOURCE)
  3805. {
  3806. // No resource information so no version information.
  3807. return E_NOINTERFACE;
  3808. }
  3809. return ReadImageVersionInfo(ImageBase, Item,
  3810. Buffer, BufferSize, VerInfoSize,
  3811. &NtHdr.OptionalHeader.
  3812. DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE]);
  3813. }
  3814. HRESULT
  3815. UserFull64DumpTargetInfo::QueryMemoryRegion(PULONG64 Handle,
  3816. BOOL HandleIsOffset,
  3817. PMEMORY_BASIC_INFORMATION64 Info)
  3818. {
  3819. ULONG Index;
  3820. if (HandleIsOffset)
  3821. {
  3822. for (Index = 0; Index < m_Header->MemoryRegionCount; Index++)
  3823. {
  3824. if (*Handle >= m_Memory[Index].BaseAddress &&
  3825. *Handle < m_Memory[Index].BaseAddress +
  3826. m_Memory[Index].RegionSize)
  3827. {
  3828. break;
  3829. }
  3830. }
  3831. if (Index >= m_Header->MemoryRegionCount)
  3832. {
  3833. return E_NOINTERFACE;
  3834. }
  3835. }
  3836. else
  3837. {
  3838. Index = (ULONG)*Handle;
  3839. if (Index >= m_Header->MemoryRegionCount)
  3840. {
  3841. return HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES);
  3842. }
  3843. // 64-bit user dump support came into being after
  3844. // guard pages were suppressed so they never contain them.
  3845. }
  3846. *Info = m_Memory[Index];
  3847. *Handle = ++Index;
  3848. return S_OK;
  3849. }
  3850. HRESULT
  3851. UserFull64DumpTargetInfo::IdentifyDump(PULONG64 BaseMapSize)
  3852. {
  3853. m_Header = (PUSERMODE_CRASHDUMP_HEADER64)g_DumpBase;
  3854. if (m_Header->Signature != USERMODE_CRASHDUMP_SIGNATURE ||
  3855. m_Header->ValidDump != USERMODE_CRASHDUMP_VALID_DUMP64)
  3856. {
  3857. m_Header = NULL;
  3858. return E_NOINTERFACE;
  3859. }
  3860. //
  3861. // Check for the presence of some basic things.
  3862. //
  3863. if (m_Header->ThreadCount == 0 ||
  3864. m_Header->ModuleCount == 0 ||
  3865. m_Header->MemoryRegionCount == 0)
  3866. {
  3867. ErrOut("Thread, module or memory region count is zero.\n"
  3868. "The dump file is probably corrupt.\n");
  3869. return HR_DUMP_CORRUPT;
  3870. }
  3871. if (m_Header->ThreadOffset == 0 ||
  3872. m_Header->ModuleOffset == 0 ||
  3873. m_Header->DataOffset == 0 ||
  3874. m_Header->MemoryRegionOffset == 0 ||
  3875. m_Header->DebugEventOffset == 0 ||
  3876. m_Header->ThreadStateOffset == 0)
  3877. {
  3878. ErrOut("A dump header data offset is zero.\n"
  3879. "The dump file is probably corrupt.\n");
  3880. return HR_DUMP_CORRUPT;
  3881. }
  3882. // We don't want to have to call DmppReadFileOffset
  3883. // every time we check memory ranges so just require
  3884. // that the memory descriptors fit in the default view.
  3885. *BaseMapSize = m_Header->MemoryRegionOffset +
  3886. m_Header->MemoryRegionCount * sizeof(*m_Memory);
  3887. return S_OK;
  3888. }
  3889. void
  3890. UserFull64DumpTargetInfo::DumpDebug(void)
  3891. {
  3892. dprintf("----- 64 bit User Full Dump Analysis\n\n");
  3893. dprintf("MajorVersion: %d\n", m_Header->MajorVersion);
  3894. dprintf("MinorVersion: %d (Build %d)\n",
  3895. m_Header->MinorVersion & 0xffff,
  3896. m_Header->MinorVersion >> 16);
  3897. dprintf("MachineImageType: %08lx\n", m_Header->MachineImageType);
  3898. dprintf("ThreadCount: %08lx\n", m_Header->ThreadCount);
  3899. dprintf("ThreadOffset: %12I64lx\n", m_Header->ThreadOffset);
  3900. dprintf("ModuleCount: %08lx\n", m_Header->ModuleCount);
  3901. dprintf("ModuleOffset: %12I64lx\n", m_Header->ModuleOffset);
  3902. dprintf("DebugEventOffset: %12I64lx\n", m_Header->DebugEventOffset);
  3903. dprintf("VersionInfoOffset: %12I64lx\n", m_Header->VersionInfoOffset);
  3904. dprintf("\nVirtual Memory Description:\n");
  3905. dprintf("Number of regions: %d\n", m_Header->MemoryRegionCount);
  3906. dprintf(" FileOffset Start Address"
  3907. " Length\n");
  3908. ULONG j = 0;
  3909. ULONG64 Offset = 0;
  3910. while (j < m_Header->MemoryRegionCount)
  3911. {
  3912. dprintf(" %12I64lx %s %12I64x",
  3913. Offset,
  3914. FormatAddr64(m_Memory[j].BaseAddress),
  3915. m_Memory[j].RegionSize);
  3916. Offset += m_Memory[j].RegionSize;
  3917. dprintf("\n");
  3918. j += 1;
  3919. }
  3920. }
  3921. ULONG64
  3922. UserFull64DumpTargetInfo::VirtualToOffset(ULONG64 Virt,
  3923. PULONG File, PULONG Avail)
  3924. {
  3925. ULONG i;
  3926. ULONG64 Offset = 0;
  3927. *File = DUMP_INFO_DUMP;
  3928. for (i = 0; i < m_Header->MemoryRegionCount; i++)
  3929. {
  3930. //
  3931. // Guard pages get reported, but they are not written
  3932. // out to the file
  3933. //
  3934. if (m_Memory[i].Protect & PAGE_GUARD)
  3935. {
  3936. continue;
  3937. }
  3938. if (Virt >= m_Memory[i].BaseAddress &&
  3939. Virt < m_Memory[i].BaseAddress + m_Memory[i].RegionSize)
  3940. {
  3941. ULONG64 Frag = Virt - m_Memory[i].BaseAddress;
  3942. ULONG64 Avail64 = m_Memory[i].RegionSize - Frag;
  3943. // It's extremely unlikely that there'll be a single
  3944. // region greater than 4GB, but check anyway. No
  3945. // reads should ever require more than 4GB so just
  3946. // indicate that 4GB is available.
  3947. if (Avail64 > 0xffffffff)
  3948. {
  3949. *Avail = 0xffffffff;
  3950. }
  3951. else
  3952. {
  3953. *Avail = (ULONG)Avail64;
  3954. }
  3955. return m_Header->DataOffset + Offset + Frag;
  3956. }
  3957. Offset += m_Memory[i].RegionSize;
  3958. }
  3959. return 0;
  3960. }
  3961. HRESULT
  3962. UserFull64DumpTargetInfo::GetThreadInfo(ULONG Index,
  3963. PULONG Id, PULONG Suspend,
  3964. PULONG64 Teb)
  3965. {
  3966. if (Index >= m_ThreadCount)
  3967. {
  3968. return E_INVALIDARG;
  3969. }
  3970. CRASH_THREAD64 Thread;
  3971. if (DmppReadFileOffset(DUMP_INFO_DUMP,
  3972. m_Header->ThreadStateOffset +
  3973. Index * sizeof(Thread),
  3974. &Thread, sizeof(Thread)) != sizeof(Thread))
  3975. {
  3976. return E_FAIL;
  3977. }
  3978. *Id = Thread.ThreadId;
  3979. *Suspend = Thread.SuspendCount;
  3980. *Teb = Thread.Teb;
  3981. return S_OK;
  3982. }
  3983. //----------------------------------------------------------------------------
  3984. //
  3985. // UserMiniDumpTargetInfo.
  3986. //
  3987. //----------------------------------------------------------------------------
  3988. HRESULT
  3989. UserMiniDumpTargetInfo::Initialize(void)
  3990. {
  3991. // Pick up any potentially modified base mapping pointer.
  3992. m_Header = (PMINIDUMP_HEADER)g_DumpBase;
  3993. // Clear pointers that have already been set so
  3994. // that they get picked up again.
  3995. m_SysInfo = NULL;
  3996. g_TargetClass = DEBUG_CLASS_USER_WINDOWS;
  3997. g_TargetClassQualifier = DEBUG_USER_WINDOWS_SMALL_DUMP;
  3998. g_DumpFormatFlags = 0;
  3999. if (m_Header->Flags & MiniDumpWithFullMemory)
  4000. {
  4001. g_DumpFormatFlags |= DEBUG_FORMAT_USER_SMALL_FULL_MEMORY;
  4002. }
  4003. if (m_Header->Flags & MiniDumpWithHandleData)
  4004. {
  4005. g_DumpFormatFlags |= DEBUG_FORMAT_USER_SMALL_HANDLE_DATA;
  4006. }
  4007. MINIDUMP_DIRECTORY UNALIGNED *Dir;
  4008. ULONG i;
  4009. Dir = (MINIDUMP_DIRECTORY UNALIGNED *)
  4010. IndexRva(m_Header->StreamDirectoryRva,
  4011. m_Header->NumberOfStreams * sizeof(*Dir),
  4012. "Directory");
  4013. if (Dir == NULL)
  4014. {
  4015. return HR_DUMP_CORRUPT;
  4016. }
  4017. for (i = 0; i < m_Header->NumberOfStreams; i++)
  4018. {
  4019. switch(Dir->StreamType)
  4020. {
  4021. case ThreadListStream:
  4022. if (IndexDirectory(i, Dir, (PVOID*)&m_Threads) == NULL)
  4023. {
  4024. break;
  4025. }
  4026. m_ActualThreadCount =
  4027. ((MINIDUMP_THREAD_LIST UNALIGNED *)m_Threads)->NumberOfThreads;
  4028. m_ThreadStructSize = sizeof(MINIDUMP_THREAD);
  4029. if (Dir->Location.DataSize !=
  4030. sizeof(MINIDUMP_THREAD_LIST) +
  4031. sizeof(MINIDUMP_THREAD) * m_ActualThreadCount)
  4032. {
  4033. m_Threads = NULL;
  4034. m_ActualThreadCount = 0;
  4035. }
  4036. else
  4037. {
  4038. // Move past count to actual thread data.
  4039. m_Threads += sizeof(MINIDUMP_THREAD_LIST);
  4040. }
  4041. break;
  4042. case ThreadExListStream:
  4043. if (IndexDirectory(i, Dir, (PVOID*)&m_Threads) == NULL)
  4044. {
  4045. break;
  4046. }
  4047. m_ActualThreadCount =
  4048. ((MINIDUMP_THREAD_EX_LIST UNALIGNED *)m_Threads)->
  4049. NumberOfThreads;
  4050. m_ThreadStructSize = sizeof(MINIDUMP_THREAD_EX);
  4051. if (Dir->Location.DataSize !=
  4052. sizeof(MINIDUMP_THREAD_EX_LIST) +
  4053. sizeof(MINIDUMP_THREAD_EX) * m_ActualThreadCount)
  4054. {
  4055. m_Threads = NULL;
  4056. m_ActualThreadCount = 0;
  4057. }
  4058. else
  4059. {
  4060. // Move past count to actual thread data.
  4061. m_Threads += sizeof(MINIDUMP_THREAD_EX_LIST);
  4062. }
  4063. break;
  4064. case ModuleListStream:
  4065. if (IndexDirectory(i, Dir, (PVOID*)&m_Modules) == NULL)
  4066. {
  4067. break;
  4068. }
  4069. if (Dir->Location.DataSize !=
  4070. sizeof(MINIDUMP_MODULE_LIST) +
  4071. sizeof(MINIDUMP_MODULE) * m_Modules->NumberOfModules)
  4072. {
  4073. m_Modules = NULL;
  4074. }
  4075. break;
  4076. case MemoryListStream:
  4077. if (m_Header->Flags & MiniDumpWithFullMemory)
  4078. {
  4079. ErrOut("Full memory minidumps can't have MemoryListStreams\n");
  4080. return HR_DUMP_CORRUPT;
  4081. }
  4082. if (IndexDirectory(i, Dir, (PVOID*)&m_Memory) == NULL)
  4083. {
  4084. break;
  4085. }
  4086. if (Dir->Location.DataSize !=
  4087. sizeof(MINIDUMP_MEMORY_LIST) +
  4088. sizeof(MINIDUMP_MEMORY_DESCRIPTOR) *
  4089. m_Memory->NumberOfMemoryRanges)
  4090. {
  4091. m_Memory = NULL;
  4092. }
  4093. break;
  4094. case Memory64ListStream:
  4095. if (!(m_Header->Flags & MiniDumpWithFullMemory))
  4096. {
  4097. ErrOut("Partial memory minidumps can't have "
  4098. "Memory64ListStreams\n");
  4099. return HR_DUMP_CORRUPT;
  4100. }
  4101. if (IndexDirectory(i, Dir, (PVOID*)&m_Memory64) == NULL)
  4102. {
  4103. break;
  4104. }
  4105. if (Dir->Location.DataSize !=
  4106. sizeof(MINIDUMP_MEMORY64_LIST) +
  4107. sizeof(MINIDUMP_MEMORY_DESCRIPTOR64) *
  4108. m_Memory64->NumberOfMemoryRanges)
  4109. {
  4110. m_Memory64 = NULL;
  4111. }
  4112. break;
  4113. case ExceptionStream:
  4114. if (IndexDirectory(i, Dir, (PVOID*)&m_Exception) == NULL)
  4115. {
  4116. break;
  4117. }
  4118. if (Dir->Location.DataSize !=
  4119. sizeof(MINIDUMP_EXCEPTION_STREAM))
  4120. {
  4121. m_Exception = NULL;
  4122. }
  4123. break;
  4124. case SystemInfoStream:
  4125. if (IndexDirectory(i, Dir, (PVOID*)&m_SysInfo) == NULL)
  4126. {
  4127. break;
  4128. }
  4129. if (Dir->Location.DataSize != sizeof(MINIDUMP_SYSTEM_INFO))
  4130. {
  4131. m_SysInfo = NULL;
  4132. }
  4133. break;
  4134. case CommentStreamA:
  4135. PSTR CommentA;
  4136. CommentA = NULL;
  4137. if (IndexDirectory(i, Dir, (PVOID*)&CommentA) == NULL)
  4138. {
  4139. break;
  4140. }
  4141. dprintf("Comment: '%s'\n", CommentA);
  4142. break;
  4143. case CommentStreamW:
  4144. PWSTR CommentW;
  4145. CommentW = NULL;
  4146. if (IndexDirectory(i, Dir, (PVOID*)&CommentW) == NULL)
  4147. {
  4148. break;
  4149. }
  4150. dprintf("Comment: '%ls'\n", CommentW);
  4151. break;
  4152. case HandleDataStream:
  4153. if (IndexDirectory(i, Dir, (PVOID*)&m_Handles) == NULL)
  4154. {
  4155. break;
  4156. }
  4157. if (Dir->Location.DataSize !=
  4158. m_Handles->SizeOfHeader +
  4159. m_Handles->SizeOfDescriptor *
  4160. m_Handles->NumberOfDescriptors)
  4161. {
  4162. m_Handles = NULL;
  4163. }
  4164. break;
  4165. case FunctionTableStream:
  4166. if (IndexDirectory(i, Dir, (PVOID*)&m_FunctionTables) == NULL)
  4167. {
  4168. break;
  4169. }
  4170. // Don't bother walking every table to verify the size,
  4171. // just do a simple minimum size check.
  4172. if (Dir->Location.DataSize <
  4173. m_FunctionTables->SizeOfHeader +
  4174. m_FunctionTables->SizeOfDescriptor *
  4175. m_FunctionTables->NumberOfDescriptors)
  4176. {
  4177. m_FunctionTables = NULL;
  4178. }
  4179. break;
  4180. case UnusedStream:
  4181. // Nothing to do.
  4182. break;
  4183. default:
  4184. WarnOut("WARNING: Minidump contains unknown stream type 0x%x\n",
  4185. Dir->StreamType);
  4186. break;
  4187. }
  4188. Dir++;
  4189. }
  4190. // This was already checked in Identify but check
  4191. // again just in case something went wrong.
  4192. if (m_SysInfo == NULL)
  4193. {
  4194. ErrOut("Unable to locate system info\n");
  4195. return HR_DUMP_CORRUPT;
  4196. }
  4197. HRESULT Status;
  4198. if ((Status = DmppInitGlobals(m_SysInfo->BuildNumber, 0,
  4199. m_ImageType, m_SysInfo->PlatformId,
  4200. m_SysInfo->MajorVersion,
  4201. m_SysInfo->MinorVersion)) != S_OK)
  4202. {
  4203. return Status;
  4204. }
  4205. // Dump does not contain this information.
  4206. g_TargetNumberProcessors = 1;
  4207. if (m_SysInfo->CSDVersionRva != 0)
  4208. {
  4209. MINIDUMP_STRING UNALIGNED *CsdString = (MINIDUMP_STRING UNALIGNED *)
  4210. IndexRva(m_SysInfo->CSDVersionRva, sizeof(*CsdString),
  4211. "CSD string");
  4212. if (CsdString != NULL && CsdString->Length > 0)
  4213. {
  4214. WCHAR UNALIGNED *WideStr = CsdString->Buffer;
  4215. ULONG WideLen = wcslen((PWSTR)WideStr);
  4216. if (g_ActualSystemVersion > W9X_SVER_START &&
  4217. g_ActualSystemVersion < W9X_SVER_END)
  4218. {
  4219. WCHAR UNALIGNED *Str;
  4220. //
  4221. // Win9x CSD strings are usually just a single
  4222. // letter surrounded by whitespace, so clean them
  4223. // up a little bit.
  4224. //
  4225. while (iswspace(*WideStr))
  4226. {
  4227. WideStr++;
  4228. }
  4229. Str = WideStr;
  4230. WideLen = 0;
  4231. while (*Str && !iswspace(*Str))
  4232. {
  4233. WideLen++;
  4234. Str++;
  4235. }
  4236. }
  4237. sprintf(g_TargetServicePackString, "%.*S", WideLen, WideStr);
  4238. }
  4239. }
  4240. // Minidumps don't store the process ID.
  4241. m_EventProcess = VIRTUAL_PROCESS_ID;
  4242. if (m_Exception != NULL)
  4243. {
  4244. m_EventThread = m_Exception->ThreadId;
  4245. C_ASSERT(sizeof(m_Exception->ExceptionRecord) ==
  4246. sizeof(EXCEPTION_RECORD64));
  4247. g_DumpException = *(EXCEPTION_RECORD64 UNALIGNED *)
  4248. &m_Exception->ExceptionRecord;
  4249. }
  4250. else
  4251. {
  4252. m_EventThread = VIRTUAL_THREAD_ID(0);
  4253. // Fake an exception.
  4254. ZeroMemory(&g_DumpException, sizeof(g_DumpException));
  4255. g_DumpException.ExceptionCode = STATUS_BREAKPOINT;
  4256. }
  4257. g_DumpExceptionFirstChance = FALSE;
  4258. if (m_Threads != NULL)
  4259. {
  4260. m_ThreadCount = m_ActualThreadCount;
  4261. if (m_Exception == NULL)
  4262. {
  4263. m_EventThread = IndexThreads(0)->ThreadId;
  4264. }
  4265. }
  4266. else
  4267. {
  4268. m_ThreadCount = 1;
  4269. }
  4270. return S_OK;
  4271. }
  4272. void
  4273. UserMiniDumpTargetInfo::Uninitialize(void)
  4274. {
  4275. MemoryMap_Destroy();
  4276. m_Header = NULL;
  4277. m_SysInfo = NULL;
  4278. m_ActualThreadCount = 0;
  4279. m_ThreadStructSize = 0;
  4280. m_Threads = NULL;
  4281. m_Modules = NULL;
  4282. m_Memory = NULL;
  4283. m_Memory64 = NULL;
  4284. m_Memory64DataBase = 0;
  4285. m_Exception = NULL;
  4286. m_Handles = NULL;
  4287. m_FunctionTables = NULL;
  4288. m_ImageType = IMAGE_FILE_MACHINE_UNKNOWN;
  4289. UserDumpTargetInfo::Uninitialize();
  4290. }
  4291. void
  4292. UserMiniDumpTargetInfo::NearestDifferentlyValidOffsets(ULONG64 Offset,
  4293. PULONG64 NextOffset,
  4294. PULONG64 NextPage)
  4295. {
  4296. //
  4297. // In a minidump there can be memory fragments mapped at
  4298. // arbitrary locations so we cannot assume validity
  4299. // changes on page boundaries. We could attempt to
  4300. // scan the memory list and try to find the closest valid
  4301. // chunk of memory but it's rarely important that
  4302. // complete accuracy is required. Just return the
  4303. // next byte.
  4304. //
  4305. if (NextOffset != NULL)
  4306. {
  4307. *NextOffset = Offset + 1;
  4308. }
  4309. if (NextPage != NULL)
  4310. {
  4311. *NextPage = (Offset + g_TargetMachine->m_PageSize) &
  4312. ~((ULONG64)g_TargetMachine->m_PageSize - 1);
  4313. }
  4314. }
  4315. HRESULT
  4316. UserMiniDumpTargetInfo::ReadHandleData(
  4317. IN ULONG64 Handle,
  4318. IN ULONG DataType,
  4319. OUT OPTIONAL PVOID Buffer,
  4320. IN ULONG BufferSize,
  4321. OUT OPTIONAL PULONG DataSize
  4322. )
  4323. {
  4324. if (m_Handles == NULL)
  4325. {
  4326. return E_FAIL;
  4327. }
  4328. MINIDUMP_HANDLE_DESCRIPTOR UNALIGNED *Desc;
  4329. if (DataType != DEBUG_HANDLE_DATA_TYPE_HANDLE_COUNT)
  4330. {
  4331. PUCHAR RawDesc = (PUCHAR)m_Handles + m_Handles->SizeOfHeader;
  4332. ULONG i;
  4333. for (i = 0; i < m_Handles->NumberOfDescriptors; i++)
  4334. {
  4335. Desc = (MINIDUMP_HANDLE_DESCRIPTOR UNALIGNED *)RawDesc;
  4336. if (Desc->Handle == Handle)
  4337. {
  4338. break;
  4339. }
  4340. RawDesc += m_Handles->SizeOfDescriptor;
  4341. }
  4342. if (i >= m_Handles->NumberOfDescriptors)
  4343. {
  4344. return E_NOINTERFACE;
  4345. }
  4346. }
  4347. ULONG Used;
  4348. RVA StrRva;
  4349. switch(DataType)
  4350. {
  4351. case DEBUG_HANDLE_DATA_TYPE_BASIC:
  4352. Used = sizeof(DEBUG_HANDLE_DATA_BASIC);
  4353. if (Buffer == NULL)
  4354. {
  4355. break;
  4356. }
  4357. if (BufferSize < Used)
  4358. {
  4359. return E_INVALIDARG;
  4360. }
  4361. PDEBUG_HANDLE_DATA_BASIC Basic;
  4362. Basic = (PDEBUG_HANDLE_DATA_BASIC)Buffer;
  4363. Basic->TypeNameSize = Desc->TypeNameRva == 0 ? 0 :
  4364. ((MINIDUMP_STRING UNALIGNED *)
  4365. IndexByByte(m_Header, Desc->TypeNameRva))->
  4366. Length / sizeof(WCHAR) + 1;
  4367. Basic->ObjectNameSize = Desc->ObjectNameRva == 0 ? 0 :
  4368. ((MINIDUMP_STRING UNALIGNED *)
  4369. IndexByByte(m_Header, Desc->ObjectNameRva))->
  4370. Length / sizeof(WCHAR) + 1;
  4371. Basic->Attributes = Desc->Attributes;
  4372. Basic->GrantedAccess = Desc->GrantedAccess;
  4373. Basic->HandleCount = Desc->HandleCount;
  4374. Basic->PointerCount = Desc->PointerCount;
  4375. break;
  4376. case DEBUG_HANDLE_DATA_TYPE_TYPE_NAME:
  4377. StrRva = Desc->TypeNameRva;
  4378. break;
  4379. case DEBUG_HANDLE_DATA_TYPE_OBJECT_NAME:
  4380. StrRva = Desc->ObjectNameRva;
  4381. break;
  4382. case DEBUG_HANDLE_DATA_TYPE_HANDLE_COUNT:
  4383. Used = sizeof(ULONG);
  4384. if (Buffer == NULL)
  4385. {
  4386. break;
  4387. }
  4388. if (BufferSize < Used)
  4389. {
  4390. return E_INVALIDARG;
  4391. }
  4392. *(PULONG)Buffer = m_Handles->NumberOfDescriptors;
  4393. break;
  4394. }
  4395. if (DataType == DEBUG_HANDLE_DATA_TYPE_TYPE_NAME ||
  4396. DataType == DEBUG_HANDLE_DATA_TYPE_OBJECT_NAME)
  4397. {
  4398. if (StrRva == 0)
  4399. {
  4400. Used = 1;
  4401. if (Buffer != NULL && BufferSize < Used)
  4402. {
  4403. return E_INVALIDARG;
  4404. }
  4405. *(PCHAR)Buffer = 0;
  4406. }
  4407. else
  4408. {
  4409. MINIDUMP_STRING UNALIGNED *Str = (MINIDUMP_STRING UNALIGNED *)
  4410. IndexRva(StrRva, sizeof(*Str), "Handle name string");
  4411. if (Str == NULL)
  4412. {
  4413. return HR_DUMP_CORRUPT;
  4414. }
  4415. Used = Str->Length / sizeof(WCHAR) + 1;
  4416. if (Buffer != NULL &&
  4417. WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)Str->Buffer,
  4418. -1, (LPSTR)Buffer, BufferSize,
  4419. NULL, NULL) == 0)
  4420. {
  4421. return WIN32_LAST_STATUS();
  4422. }
  4423. }
  4424. }
  4425. if (DataSize != NULL)
  4426. {
  4427. *DataSize = Used;
  4428. }
  4429. return S_OK;
  4430. }
  4431. HRESULT
  4432. UserMiniDumpTargetInfo::GetProcessorId
  4433. (ULONG Processor, PDEBUG_PROCESSOR_IDENTIFICATION_ALL Id)
  4434. {
  4435. LPTSTR vendor = "<unavailable>";
  4436. if (Processor != 0)
  4437. {
  4438. return E_INVALIDARG;
  4439. }
  4440. if (m_SysInfo == NULL)
  4441. {
  4442. return E_UNEXPECTED;
  4443. }
  4444. switch(m_SysInfo->ProcessorArchitecture)
  4445. {
  4446. case PROCESSOR_ARCHITECTURE_INTEL:
  4447. Id->X86.Family = m_SysInfo->ProcessorLevel;
  4448. Id->X86.Model = (m_SysInfo->ProcessorRevision >> 8) & 0xf;
  4449. Id->X86.Stepping = m_SysInfo->ProcessorRevision & 0xf;
  4450. strcpy(&(Id->X86.VendorString[0]), vendor);
  4451. break;
  4452. case PROCESSOR_ARCHITECTURE_ALPHA:
  4453. Id->Alpha.Type = m_SysInfo->ProcessorLevel;
  4454. Id->Alpha.Revision = m_SysInfo->ProcessorRevision;
  4455. break;
  4456. case PROCESSOR_ARCHITECTURE_IA64:
  4457. Id->Ia64.Model = m_SysInfo->ProcessorLevel;
  4458. Id->Ia64.Revision = m_SysInfo->ProcessorRevision;
  4459. strcpy(&(Id->Ia64.VendorString[0]), vendor);
  4460. break;
  4461. case PROCESSOR_ARCHITECTURE_AMD64:
  4462. Id->Amd64.Family = m_SysInfo->ProcessorLevel;
  4463. Id->Amd64.Model = (m_SysInfo->ProcessorRevision >> 8) & 0xf;
  4464. Id->Amd64.Stepping = m_SysInfo->ProcessorRevision & 0xf;
  4465. strcpy(&(Id->Amd64.VendorString[0]), vendor);
  4466. break;
  4467. }
  4468. return S_OK;
  4469. }
  4470. PVOID
  4471. UserMiniDumpTargetInfo::FindDynamicFunctionEntry(MachineInfo* Machine,
  4472. ULONG64 Address)
  4473. {
  4474. if (m_FunctionTables == NULL)
  4475. {
  4476. return NULL;
  4477. }
  4478. PUCHAR StreamData =
  4479. (PUCHAR)m_FunctionTables + m_FunctionTables->SizeOfHeader +
  4480. m_FunctionTables->SizeOfAlignPad;
  4481. ULONG TableIdx;
  4482. for (TableIdx = 0;
  4483. TableIdx < m_FunctionTables->NumberOfDescriptors;
  4484. TableIdx++)
  4485. {
  4486. // Stream structure contents are guaranteed to be
  4487. // properly aligned.
  4488. PMINIDUMP_FUNCTION_TABLE_DESCRIPTOR Desc =
  4489. (PMINIDUMP_FUNCTION_TABLE_DESCRIPTOR)StreamData;
  4490. StreamData += m_FunctionTables->SizeOfDescriptor;
  4491. PCROSS_PLATFORM_DYNAMIC_FUNCTION_TABLE RawTable =
  4492. (PCROSS_PLATFORM_DYNAMIC_FUNCTION_TABLE)StreamData;
  4493. StreamData += m_FunctionTables->SizeOfNativeDescriptor;
  4494. PVOID TableData = (PVOID)StreamData;
  4495. StreamData += Desc->EntryCount *
  4496. m_FunctionTables->SizeOfFunctionEntry +
  4497. Desc->SizeOfAlignPad;
  4498. if (Address >= Desc->MinimumAddress && Address < Desc->MaximumAddress)
  4499. {
  4500. PVOID Entry = Machine->FindDynamicFunctionEntry
  4501. (RawTable, Address, TableData,
  4502. Desc->EntryCount * m_FunctionTables->SizeOfFunctionEntry);
  4503. if (Entry)
  4504. {
  4505. return Entry;
  4506. }
  4507. }
  4508. }
  4509. return NULL;
  4510. }
  4511. ULONG64
  4512. UserMiniDumpTargetInfo::GetDynamicFunctionTableBase(MachineInfo* Machine,
  4513. ULONG64 Address)
  4514. {
  4515. if (m_FunctionTables == NULL)
  4516. {
  4517. return 0;
  4518. }
  4519. PUCHAR StreamData =
  4520. (PUCHAR)m_FunctionTables + m_FunctionTables->SizeOfHeader +
  4521. m_FunctionTables->SizeOfAlignPad;
  4522. ULONG TableIdx;
  4523. for (TableIdx = 0;
  4524. TableIdx < m_FunctionTables->NumberOfDescriptors;
  4525. TableIdx++)
  4526. {
  4527. // Stream structure contents are guaranteed to be
  4528. // properly aligned.
  4529. PMINIDUMP_FUNCTION_TABLE_DESCRIPTOR Desc =
  4530. (PMINIDUMP_FUNCTION_TABLE_DESCRIPTOR)StreamData;
  4531. StreamData +=
  4532. m_FunctionTables->SizeOfDescriptor +
  4533. m_FunctionTables->SizeOfNativeDescriptor +
  4534. Desc->EntryCount * m_FunctionTables->SizeOfFunctionEntry +
  4535. Desc->SizeOfAlignPad;
  4536. if (Address >= Desc->MinimumAddress && Address < Desc->MaximumAddress)
  4537. {
  4538. return Desc->BaseAddress;
  4539. }
  4540. }
  4541. return 0;
  4542. }
  4543. HRESULT
  4544. UserMiniDumpTargetInfo::GetTargetContext(
  4545. ULONG64 Thread,
  4546. PVOID Context
  4547. )
  4548. {
  4549. if (m_Threads == NULL ||
  4550. VIRTUAL_THREAD_INDEX(Thread) >= m_ActualThreadCount)
  4551. {
  4552. return E_INVALIDARG;
  4553. }
  4554. PVOID ContextData =
  4555. IndexRva(IndexThreads(VIRTUAL_THREAD_INDEX(Thread))->ThreadContext.Rva,
  4556. g_TargetMachine->m_SizeTargetContext,
  4557. "Thread context data");
  4558. if (ContextData == NULL)
  4559. {
  4560. return HR_DUMP_CORRUPT;
  4561. }
  4562. memcpy(Context, ContextData, g_TargetMachine->m_SizeTargetContext);
  4563. return S_OK;
  4564. }
  4565. HRESULT
  4566. UserMiniDumpTargetInfo::IdentifyDump(PULONG64 BaseMapSize)
  4567. {
  4568. m_Header = (PMINIDUMP_HEADER)g_DumpBase;
  4569. if (m_Header->Signature != MINIDUMP_SIGNATURE ||
  4570. (m_Header->Version & 0xffff) != MINIDUMP_VERSION)
  4571. {
  4572. m_Header = NULL;
  4573. return E_NOINTERFACE;
  4574. }
  4575. MINIDUMP_DIRECTORY UNALIGNED *Dir;
  4576. ULONG i;
  4577. Dir = (MINIDUMP_DIRECTORY UNALIGNED *)
  4578. IndexRva(m_Header->StreamDirectoryRva,
  4579. m_Header->NumberOfStreams * sizeof(*Dir),
  4580. "Directory");
  4581. if (Dir == NULL)
  4582. {
  4583. return HR_DUMP_CORRUPT;
  4584. }
  4585. for (i = 0; i < m_Header->NumberOfStreams; i++)
  4586. {
  4587. switch(Dir->StreamType)
  4588. {
  4589. case SystemInfoStream:
  4590. if (IndexDirectory(i, Dir, (PVOID*)&m_SysInfo) == NULL)
  4591. {
  4592. break;
  4593. }
  4594. if (Dir->Location.DataSize != sizeof(MINIDUMP_SYSTEM_INFO))
  4595. {
  4596. m_SysInfo = NULL;
  4597. }
  4598. break;
  4599. case Memory64ListStream:
  4600. MINIDUMP_MEMORY64_LIST Mem64;
  4601. // The memory for the full memory list may not
  4602. // fit within the initial mapping used at identify
  4603. // time so do not directly index. Instead, use
  4604. // the adaptive read to get the data so we can
  4605. // determine the data base.
  4606. if (DmppReadFileOffset(DUMP_INFO_DUMP, Dir->Location.Rva,
  4607. &Mem64, sizeof(Mem64)) == sizeof(Mem64) &&
  4608. Dir->Location.DataSize ==
  4609. sizeof(MINIDUMP_MEMORY64_LIST) +
  4610. sizeof(MINIDUMP_MEMORY_DESCRIPTOR64) *
  4611. Mem64.NumberOfMemoryRanges)
  4612. {
  4613. m_Memory64DataBase = Mem64.BaseRva;
  4614. }
  4615. // Clear any cache entries that may have been
  4616. // added by the above read so that only the
  4617. // identify mapping is active.
  4618. DmppDumpFileCacheEmpty(&g_DumpInfoFiles[DUMP_INFO_DUMP]);
  4619. break;
  4620. }
  4621. Dir++;
  4622. }
  4623. if (m_SysInfo == NULL)
  4624. {
  4625. ErrOut("Minidump does not have system info\n");
  4626. return E_FAIL;
  4627. }
  4628. switch(m_SysInfo->ProcessorArchitecture)
  4629. {
  4630. case PROCESSOR_ARCHITECTURE_INTEL:
  4631. m_ImageType = IMAGE_FILE_MACHINE_I386;
  4632. break;
  4633. case PROCESSOR_ARCHITECTURE_ALPHA:
  4634. m_ImageType = IMAGE_FILE_MACHINE_ALPHA;
  4635. break;
  4636. case PROCESSOR_ARCHITECTURE_IA64:
  4637. m_ImageType = IMAGE_FILE_MACHINE_IA64;
  4638. break;
  4639. case PROCESSOR_ARCHITECTURE_ALPHA64:
  4640. m_ImageType = IMAGE_FILE_MACHINE_AXP64;
  4641. break;
  4642. case PROCESSOR_ARCHITECTURE_AMD64:
  4643. m_ImageType = IMAGE_FILE_MACHINE_AMD64;
  4644. break;
  4645. default:
  4646. return E_FAIL;
  4647. }
  4648. // We rely on being able to directly access the entire
  4649. // content of the dump through the default view so
  4650. // ensure that it's possible.
  4651. *BaseMapSize = g_DumpInfoFiles[DUMP_INFO_DUMP].FileSize;
  4652. return S_OK;
  4653. }
  4654. ModuleInfo*
  4655. UserMiniDumpTargetInfo::GetModuleInfo(BOOL UserMode)
  4656. {
  4657. DBG_ASSERT(UserMode);
  4658. return &g_UserMiniModuleIterator;
  4659. }
  4660. HRESULT
  4661. UserMiniDumpTargetInfo::GetImageVersionInformation(PCSTR ImagePath,
  4662. ULONG64 ImageBase,
  4663. PCSTR Item,
  4664. PVOID Buffer,
  4665. ULONG BufferSize,
  4666. PULONG VerInfoSize)
  4667. {
  4668. //
  4669. // Find the image in the dump module list.
  4670. //
  4671. if (m_Modules == NULL)
  4672. {
  4673. return E_NOINTERFACE;
  4674. }
  4675. ULONG i;
  4676. MINIDUMP_MODULE UNALIGNED *Mod = m_Modules->Modules;
  4677. for (i = 0; i < m_Modules->NumberOfModules; i++)
  4678. {
  4679. if (ImageBase == Mod->BaseOfImage)
  4680. {
  4681. break;
  4682. }
  4683. Mod++;
  4684. }
  4685. if (i == m_Modules->NumberOfModules)
  4686. {
  4687. return E_NOINTERFACE;
  4688. }
  4689. PVOID Data = NULL;
  4690. ULONG DataSize = 0;
  4691. if (Item[0] == '\\' && Item[1] == 0)
  4692. {
  4693. Data = &Mod->VersionInfo;
  4694. DataSize = sizeof(Mod->VersionInfo);
  4695. }
  4696. else
  4697. {
  4698. return E_INVALIDARG;
  4699. }
  4700. return FillDataBuffer(Data, DataSize, Buffer, BufferSize, VerInfoSize);
  4701. }
  4702. HRESULT
  4703. UserMiniDumpTargetInfo::GetExceptionContext(PCROSS_PLATFORM_CONTEXT Context)
  4704. {
  4705. if (m_Exception != NULL)
  4706. {
  4707. PVOID ContextData;
  4708. if (m_Exception->ThreadContext.DataSize <
  4709. g_TargetMachine->m_SizeTargetContext ||
  4710. (ContextData = IndexRva(m_Exception->ThreadContext.Rva,
  4711. g_TargetMachine->m_SizeTargetContext,
  4712. "Exception context")) == NULL)
  4713. {
  4714. return E_FAIL;
  4715. }
  4716. memcpy(Context, ContextData, g_TargetMachine->m_SizeTargetContext);
  4717. return S_OK;
  4718. }
  4719. else
  4720. {
  4721. ErrOut("Minidump doesn't have an exception context\n");
  4722. return E_FAIL;
  4723. }
  4724. }
  4725. ULONG64
  4726. UserMiniDumpTargetInfo::GetCurrentTimeDateN(void)
  4727. {
  4728. return TimeDateStampToFileTime(m_Header->TimeDateStamp);
  4729. }
  4730. HRESULT
  4731. UserMiniDumpTargetInfo::GetThreadInfo(ULONG Index,
  4732. PULONG Id, PULONG Suspend, PULONG64 Teb)
  4733. {
  4734. if (m_Threads == NULL || Index >= m_ActualThreadCount)
  4735. {
  4736. return E_INVALIDARG;
  4737. }
  4738. MINIDUMP_THREAD_EX UNALIGNED *Thread = IndexThreads(Index);
  4739. *Id = Thread->ThreadId;
  4740. *Suspend = Thread->SuspendCount;
  4741. *Teb = Thread->Teb;
  4742. return S_OK;
  4743. }
  4744. PSTR g_MiniStreamNames[] =
  4745. {
  4746. "UnusedStream", "ReservedStream0", "ReservedStream1", "ThreadListStream",
  4747. "ModuleListStream", "MemoryListStream", "ExceptionStream",
  4748. "SystemInfoStream", "ThreadExListStream", "Memory64ListStream",
  4749. "CommentStreamA", "CommentStreamW", "HandleDataStream",
  4750. "FunctionTableStream",
  4751. };
  4752. PSTR
  4753. MiniStreamTypeName(ULONG32 Type)
  4754. {
  4755. if (Type < sizeof(g_MiniStreamNames) / sizeof(g_MiniStreamNames[0]))
  4756. {
  4757. return g_MiniStreamNames[Type];
  4758. }
  4759. else
  4760. {
  4761. return "???";
  4762. }
  4763. }
  4764. PVOID
  4765. UserMiniDumpTargetInfo::IndexRva(RVA Rva, ULONG Size, PCSTR Title)
  4766. {
  4767. if (Rva >= g_DumpInfoFiles[DUMP_INFO_DUMP].MapSize)
  4768. {
  4769. ErrOut("ERROR: %s not present in dump (RVA 0x%X)\n",
  4770. Title, Rva);
  4771. return NULL;
  4772. }
  4773. else if (Rva + Size > g_DumpInfoFiles[DUMP_INFO_DUMP].MapSize)
  4774. {
  4775. ErrOut("ERROR: %s only partially present in dump "
  4776. "(RVA 0x%X, size 0x%X)\n",
  4777. Title, Rva, Size);
  4778. return NULL;
  4779. }
  4780. return IndexByByte(m_Header, Rva);
  4781. }
  4782. PVOID
  4783. UserMiniDumpTargetInfo::IndexDirectory(ULONG Index,
  4784. MINIDUMP_DIRECTORY UNALIGNED *Dir,
  4785. PVOID* Store)
  4786. {
  4787. if (*Store != NULL)
  4788. {
  4789. WarnOut("WARNING: Ignoring extra %s stream, dir entry %d\n",
  4790. MiniStreamTypeName(Dir->StreamType), Index);
  4791. return NULL;
  4792. }
  4793. char Msg[128];
  4794. sprintf(Msg, "Dir entry %d, %s stream",
  4795. Index, MiniStreamTypeName(Dir->StreamType));
  4796. PVOID Ptr = IndexRva(Dir->Location.Rva, Dir->Location.DataSize, Msg);
  4797. if (Ptr != NULL)
  4798. {
  4799. *Store = Ptr;
  4800. }
  4801. return Ptr;
  4802. }
  4803. void
  4804. UserMiniDumpTargetInfo::DumpDebug(void)
  4805. {
  4806. ULONG i;
  4807. dprintf("----- User Mini Dump Analysis\n");
  4808. dprintf("\nMINIDUMP_HEADER:\n");
  4809. dprintf("Version %X (%X)\n",
  4810. m_Header->Version & 0xffff, m_Header->Version >> 16);
  4811. dprintf("NumberOfStreams %d\n", m_Header->NumberOfStreams);
  4812. dprintf("Flags %X\n", m_Header->Flags);
  4813. MINIDUMP_DIRECTORY UNALIGNED *Dir;
  4814. dprintf("\nStreams:\n");
  4815. Dir = (MINIDUMP_DIRECTORY UNALIGNED *)
  4816. IndexRva(m_Header->StreamDirectoryRva,
  4817. m_Header->NumberOfStreams * sizeof(*Dir),
  4818. "Directory");
  4819. if (Dir == NULL)
  4820. {
  4821. return;
  4822. }
  4823. PVOID Data;
  4824. for (i = 0; i < m_Header->NumberOfStreams; i++)
  4825. {
  4826. dprintf("Stream %d: type %s (%d), size %08X, RVA %08X\n",
  4827. i, MiniStreamTypeName(Dir->StreamType), Dir->StreamType,
  4828. Dir->Location.DataSize, Dir->Location.Rva);
  4829. Data = NULL;
  4830. if (IndexDirectory(i, Dir, &Data) == NULL)
  4831. {
  4832. continue;
  4833. }
  4834. ULONG j;
  4835. RVA Rva;
  4836. Rva = Dir->Location.Rva;
  4837. switch(Dir->StreamType)
  4838. {
  4839. case ModuleListStream:
  4840. MINIDUMP_MODULE_LIST UNALIGNED *ModList;
  4841. MINIDUMP_MODULE UNALIGNED *Mod;
  4842. ModList = (MINIDUMP_MODULE_LIST UNALIGNED *)Data;
  4843. Mod = ModList->Modules;
  4844. dprintf(" %d modules\n", ModList->NumberOfModules);
  4845. Rva += FIELD_OFFSET(MINIDUMP_MODULE_LIST, Modules);
  4846. for (j = 0; j < ModList->NumberOfModules; j++)
  4847. {
  4848. PVOID Str = IndexRva(Mod->ModuleNameRva,
  4849. sizeof(MINIDUMP_STRING),
  4850. "Module entry name");
  4851. dprintf(" RVA %08X, %s - %s: '%S'\n",
  4852. Rva,
  4853. FormatAddr64(Mod->BaseOfImage),
  4854. FormatAddr64(Mod->BaseOfImage + Mod->SizeOfImage),
  4855. Str != NULL ?
  4856. ((MINIDUMP_STRING UNALIGNED *)Str)->Buffer :
  4857. L"** Invalid **");
  4858. Mod++;
  4859. Rva += sizeof(*Mod);
  4860. }
  4861. break;
  4862. case MemoryListStream:
  4863. {
  4864. MINIDUMP_MEMORY_LIST UNALIGNED *MemList;
  4865. MemList = (MINIDUMP_MEMORY_LIST UNALIGNED *)Data;
  4866. dprintf(" %d memory ranges\n", MemList->NumberOfMemoryRanges);
  4867. dprintf(" range# Address %sSize\n",
  4868. g_TargetMachine->m_Ptr64 ? " " : "");
  4869. for (j = 0; j < MemList->NumberOfMemoryRanges; j++)
  4870. {
  4871. dprintf(" %4d %s %s\n",
  4872. j,
  4873. FormatAddr64(MemList->MemoryRanges[j].StartOfMemoryRange),
  4874. FormatAddr64(MemList->MemoryRanges[j].Memory.DataSize));
  4875. }
  4876. break;
  4877. }
  4878. case Memory64ListStream:
  4879. {
  4880. MINIDUMP_MEMORY64_LIST UNALIGNED *MemList;
  4881. MemList = (MINIDUMP_MEMORY64_LIST UNALIGNED *)Data;
  4882. dprintf(" %d memory ranges\n", MemList->NumberOfMemoryRanges);
  4883. dprintf(" RVA 0x%X BaseRva\n", (ULONG)(MemList->BaseRva));
  4884. dprintf(" range# Address %sSize\n",
  4885. g_TargetMachine->m_Ptr64 ? " " : "");
  4886. for (j = 0; j < MemList->NumberOfMemoryRanges; j++)
  4887. {
  4888. dprintf(" %4d %s %s\n",
  4889. j,
  4890. FormatAddr64(MemList->MemoryRanges[j].StartOfMemoryRange),
  4891. FormatAddr64(MemList->MemoryRanges[j].DataSize));
  4892. }
  4893. break;
  4894. }
  4895. case CommentStreamA:
  4896. dprintf(" '%s'\n", Data);
  4897. break;
  4898. case CommentStreamW:
  4899. dprintf(" '%ls'\n", Data);
  4900. break;
  4901. }
  4902. Dir++;
  4903. }
  4904. }
  4905. //----------------------------------------------------------------------------
  4906. //
  4907. // UserMiniPartialDumpTargetInfo.
  4908. //
  4909. //----------------------------------------------------------------------------
  4910. HRESULT
  4911. UserMiniPartialDumpTargetInfo::Initialize(void)
  4912. {
  4913. HRESULT Status;
  4914. dprintf("User Mini Dump File: Only registers and stack "
  4915. "trace are available\n\n");
  4916. if ((Status = UserMiniDumpTargetInfo::Initialize()) != S_OK)
  4917. {
  4918. return Status;
  4919. }
  4920. if (m_Memory != NULL)
  4921. {
  4922. //
  4923. // Map every piece of memory in the dump. This makes
  4924. // ReadVirtual very simple and there shouldn't be that
  4925. // many ranges so it doesn't require that many map regions.
  4926. //
  4927. if (!MemoryMap_Create())
  4928. {
  4929. return E_OUTOFMEMORY;
  4930. }
  4931. MINIDUMP_MEMORY_DESCRIPTOR UNALIGNED *Mem;
  4932. ULONG i;
  4933. ULONG64 TotalMemory;
  4934. Mem = m_Memory->MemoryRanges;
  4935. for (i = 0; i < m_Memory->NumberOfMemoryRanges; i++)
  4936. {
  4937. PVOID Data = IndexRva(Mem->Memory.Rva, Mem->Memory.DataSize,
  4938. "Memory range data");
  4939. if (Data == NULL)
  4940. {
  4941. return HR_DUMP_CORRUPT;
  4942. }
  4943. if ((Status = MemoryMap_AddRegion(Mem->StartOfMemoryRange,
  4944. Mem->Memory.DataSize, Data,
  4945. NULL, FALSE)) != S_OK)
  4946. {
  4947. return Status;
  4948. }
  4949. Mem++;
  4950. }
  4951. VerbOut(" Memory regions: %d\n",
  4952. m_Memory->NumberOfMemoryRanges);
  4953. Mem = m_Memory->MemoryRanges;
  4954. TotalMemory = 0;
  4955. for (i = 0; i < m_Memory->NumberOfMemoryRanges; i++)
  4956. {
  4957. VerbOut(" %5d: %s - %s\n",
  4958. i, FormatAddr64(Mem->StartOfMemoryRange),
  4959. FormatAddr64(Mem->StartOfMemoryRange +
  4960. Mem->Memory.DataSize - 1));
  4961. TotalMemory += Mem->Memory.DataSize;
  4962. Mem++;
  4963. }
  4964. VerbOut(" Total memory region size %s\n",
  4965. FormatAddr64(TotalMemory));
  4966. }
  4967. return S_OK;
  4968. }
  4969. HRESULT
  4970. UserMiniPartialDumpTargetInfo::ReadVirtual(
  4971. IN ULONG64 Offset,
  4972. OUT PVOID Buffer,
  4973. IN ULONG BufferSize,
  4974. OUT OPTIONAL PULONG BytesRead
  4975. )
  4976. {
  4977. // All virtual memory is contained in the memory map.
  4978. return MemoryMap_ReadMemory(Offset, Buffer, BufferSize,
  4979. BytesRead) ? S_OK : E_FAIL;
  4980. }
  4981. HRESULT
  4982. UserMiniPartialDumpTargetInfo::QueryMemoryRegion
  4983. (PULONG64 Handle,
  4984. BOOL HandleIsOffset,
  4985. PMEMORY_BASIC_INFORMATION64 Info)
  4986. {
  4987. ULONG Index;
  4988. MINIDUMP_MEMORY_DESCRIPTOR UNALIGNED *Mem;
  4989. if (HandleIsOffset)
  4990. {
  4991. if (m_Memory == NULL)
  4992. {
  4993. return E_NOINTERFACE;
  4994. }
  4995. Mem = m_Memory->MemoryRanges;
  4996. for (Index = 0; Index < m_Memory->NumberOfMemoryRanges; Index++)
  4997. {
  4998. if (*Handle >= Mem->StartOfMemoryRange &&
  4999. *Handle < Mem->StartOfMemoryRange + Mem->Memory.DataSize)
  5000. {
  5001. break;
  5002. }
  5003. Mem++;
  5004. }
  5005. if (Index >= m_Memory->NumberOfMemoryRanges)
  5006. {
  5007. return E_NOINTERFACE;
  5008. }
  5009. }
  5010. else
  5011. {
  5012. Index = (ULONG)*Handle;
  5013. if (m_Memory == NULL || Index >= m_Memory->NumberOfMemoryRanges)
  5014. {
  5015. return HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES);
  5016. }
  5017. Mem = m_Memory->MemoryRanges + Index;
  5018. }
  5019. Info->BaseAddress = Mem->StartOfMemoryRange;
  5020. Info->AllocationBase = Mem->StartOfMemoryRange;
  5021. Info->AllocationProtect = PAGE_READWRITE;
  5022. Info->__alignment1 = 0;
  5023. Info->RegionSize = Mem->Memory.DataSize;
  5024. Info->State = MEM_COMMIT;
  5025. Info->Protect = PAGE_READWRITE;
  5026. Info->Type = MEM_PRIVATE;
  5027. Info->__alignment2 = 0;
  5028. *Handle = ++Index;
  5029. return S_OK;
  5030. }
  5031. HRESULT
  5032. UserMiniPartialDumpTargetInfo::IdentifyDump(PULONG64 BaseMapSize)
  5033. {
  5034. HRESULT Status;
  5035. if ((Status = UserMiniDumpTargetInfo::IdentifyDump(BaseMapSize)) != S_OK)
  5036. {
  5037. return Status;
  5038. }
  5039. if (m_Header->Flags & MiniDumpWithFullMemory)
  5040. {
  5041. return E_NOINTERFACE;
  5042. }
  5043. return S_OK;
  5044. }
  5045. ULONG64
  5046. UserMiniPartialDumpTargetInfo::VirtualToOffset(ULONG64 Virt,
  5047. PULONG File, PULONG Avail)
  5048. {
  5049. *File = DUMP_INFO_DUMP;
  5050. if (m_Memory == NULL)
  5051. {
  5052. return 0;
  5053. }
  5054. MINIDUMP_MEMORY_DESCRIPTOR UNALIGNED *Mem = m_Memory->MemoryRanges;
  5055. ULONG i;
  5056. for (i = 0; i < m_Memory->NumberOfMemoryRanges; i++)
  5057. {
  5058. if (Virt >= Mem->StartOfMemoryRange &&
  5059. Virt < Mem->StartOfMemoryRange + Mem->Memory.DataSize)
  5060. {
  5061. ULONG Frag = (ULONG)(Virt - Mem->StartOfMemoryRange);
  5062. *Avail = Mem->Memory.DataSize - Frag;
  5063. return Mem->Memory.Rva + Frag;
  5064. }
  5065. Mem++;
  5066. }
  5067. return 0;
  5068. }
  5069. //----------------------------------------------------------------------------
  5070. //
  5071. // UserMiniFullDumpTargetInfo.
  5072. //
  5073. //----------------------------------------------------------------------------
  5074. HRESULT
  5075. UserMiniFullDumpTargetInfo::Initialize(void)
  5076. {
  5077. HRESULT Status;
  5078. dprintf("User Mini Dump File with Full Memory: Only application "
  5079. "data is available\n\n");
  5080. if ((Status = UserMiniDumpTargetInfo::Initialize()) != S_OK)
  5081. {
  5082. return Status;
  5083. }
  5084. if (m_Memory != NULL)
  5085. {
  5086. ULONG64 TotalMemory;
  5087. ULONG i;
  5088. MINIDUMP_MEMORY_DESCRIPTOR64 UNALIGNED *Mem;
  5089. VerbOut(" Memory regions: %d\n",
  5090. m_Memory64->NumberOfMemoryRanges);
  5091. Mem = m_Memory64->MemoryRanges;
  5092. TotalMemory = 0;
  5093. for (i = 0; i < m_Memory64->NumberOfMemoryRanges; i++)
  5094. {
  5095. VerbOut(" %5d: %s - %s\n",
  5096. i, FormatAddr64(Mem->StartOfMemoryRange),
  5097. FormatAddr64(Mem->StartOfMemoryRange +
  5098. Mem->DataSize - 1));
  5099. TotalMemory += Mem->DataSize;
  5100. Mem++;
  5101. }
  5102. VerbOut(" Total memory region size %s\n",
  5103. FormatAddr64(TotalMemory));
  5104. }
  5105. return S_OK;
  5106. }
  5107. HRESULT
  5108. UserMiniFullDumpTargetInfo::QueryMemoryRegion
  5109. (PULONG64 Handle,
  5110. BOOL HandleIsOffset,
  5111. PMEMORY_BASIC_INFORMATION64 Info)
  5112. {
  5113. ULONG Index;
  5114. MINIDUMP_MEMORY_DESCRIPTOR64 UNALIGNED *Mem;
  5115. if (HandleIsOffset)
  5116. {
  5117. if (m_Memory64 == NULL)
  5118. {
  5119. return E_NOINTERFACE;
  5120. }
  5121. Mem = m_Memory64->MemoryRanges;
  5122. for (Index = 0; Index < m_Memory64->NumberOfMemoryRanges; Index++)
  5123. {
  5124. if (*Handle >= Mem->StartOfMemoryRange &&
  5125. *Handle < Mem->StartOfMemoryRange + Mem->DataSize)
  5126. {
  5127. break;
  5128. }
  5129. Mem++;
  5130. }
  5131. if (Index >= m_Memory64->NumberOfMemoryRanges)
  5132. {
  5133. return E_NOINTERFACE;
  5134. }
  5135. }
  5136. else
  5137. {
  5138. Index = (ULONG)*Handle;
  5139. if (m_Memory64 == NULL || Index >= m_Memory64->NumberOfMemoryRanges)
  5140. {
  5141. return HRESULT_FROM_WIN32(ERROR_NO_MORE_FILES);
  5142. }
  5143. Mem = m_Memory64->MemoryRanges + Index;
  5144. }
  5145. Info->BaseAddress = Mem->StartOfMemoryRange;
  5146. Info->AllocationBase = Mem->StartOfMemoryRange;
  5147. Info->AllocationProtect = PAGE_READWRITE;
  5148. Info->__alignment1 = 0;
  5149. Info->RegionSize = Mem->DataSize;
  5150. Info->State = MEM_COMMIT;
  5151. Info->Protect = PAGE_READWRITE;
  5152. Info->Type = MEM_PRIVATE;
  5153. Info->__alignment2 = 0;
  5154. *Handle = ++Index;
  5155. return S_OK;
  5156. }
  5157. HRESULT
  5158. UserMiniFullDumpTargetInfo::IdentifyDump(PULONG64 BaseMapSize)
  5159. {
  5160. HRESULT Status;
  5161. if ((Status = UserMiniDumpTargetInfo::IdentifyDump(BaseMapSize)) != S_OK)
  5162. {
  5163. return Status;
  5164. }
  5165. if (!(m_Header->Flags & MiniDumpWithFullMemory))
  5166. {
  5167. return E_NOINTERFACE;
  5168. }
  5169. if (m_Memory64DataBase == 0)
  5170. {
  5171. ErrOut("Full-memory minidump must have a Memory64ListStream\n");
  5172. return E_FAIL;
  5173. }
  5174. // In the case of a full memory minidump we don't
  5175. // want to map the entire dump as it can be very large.
  5176. // Fortunately, we are guaranteed that all of the raw
  5177. // memory data in a full memory minidump will be at the
  5178. // end of the dump, so we can just map the dump up
  5179. // to the memory content and stop.
  5180. *BaseMapSize = m_Memory64DataBase;
  5181. return S_OK;
  5182. }
  5183. ULONG64
  5184. UserMiniFullDumpTargetInfo::VirtualToOffset(ULONG64 Virt,
  5185. PULONG File, PULONG Avail)
  5186. {
  5187. *File = DUMP_INFO_DUMP;
  5188. if (m_Memory64 == NULL)
  5189. {
  5190. return 0;
  5191. }
  5192. MINIDUMP_MEMORY_DESCRIPTOR64 UNALIGNED *Mem = m_Memory64->MemoryRanges;
  5193. ULONG i;
  5194. ULONG64 Offset = m_Memory64->BaseRva;
  5195. for (i = 0; i < m_Memory64->NumberOfMemoryRanges; i++)
  5196. {
  5197. if (Virt >= Mem->StartOfMemoryRange &&
  5198. Virt < Mem->StartOfMemoryRange + Mem->DataSize)
  5199. {
  5200. ULONG64 Frag = Virt - Mem->StartOfMemoryRange;
  5201. ULONG64 Avail64 = Mem->DataSize - Frag;
  5202. if (Avail64 > 0xffffffff)
  5203. {
  5204. *Avail = 0xffffffff;
  5205. }
  5206. else
  5207. {
  5208. *Avail = (ULONG)Avail64;
  5209. }
  5210. return Offset + Frag;
  5211. }
  5212. Offset += Mem->DataSize;
  5213. Mem++;
  5214. }
  5215. return 0;
  5216. }
  5217. //----------------------------------------------------------------------------
  5218. //
  5219. // ModuleInfo implementations.
  5220. //
  5221. //----------------------------------------------------------------------------
  5222. HRESULT
  5223. KernelTriage32ModuleInfo::Initialize(void)
  5224. {
  5225. m_Target = (KernelTriage32DumpTargetInfo*)g_Target;
  5226. if (m_Target->m_Dump->Triage.DriverListOffset != 0)
  5227. {
  5228. m_Head = m_Target->m_Dump->Triage.DriverCount;
  5229. m_Cur = 0;
  5230. return S_OK;
  5231. }
  5232. else
  5233. {
  5234. dprintf("Mini Kernel Dump does not contain driver list\n");
  5235. return S_FALSE;
  5236. }
  5237. }
  5238. HRESULT
  5239. KernelTriage32ModuleInfo::GetEntry(PMODULE_INFO_ENTRY Entry)
  5240. {
  5241. if (m_Cur == m_Head)
  5242. {
  5243. return S_FALSE;
  5244. }
  5245. PDUMP_DRIVER_ENTRY32 DriverEntry;
  5246. PDUMP_STRING DriverName;
  5247. DBG_ASSERT(m_Target->m_Dump->Triage.DriverListOffset != 0);
  5248. DriverEntry = (PDUMP_DRIVER_ENTRY32)
  5249. IndexByByte(m_Target->m_Dump,
  5250. m_Target->m_Dump->Triage.DriverListOffset +
  5251. m_Cur * sizeof(*DriverEntry));
  5252. DriverName = (PDUMP_STRING)
  5253. IndexByByte(m_Target->m_Dump, DriverEntry->DriverNameOffset);
  5254. Entry->NamePtr = (PSTR)DriverName->Buffer;
  5255. Entry->UnicodeNamePtr = 1;
  5256. Entry->NameLength = DriverName->Length * sizeof(WCHAR);
  5257. Entry->Base = EXTEND64(DriverEntry->LdrEntry.DllBase);
  5258. Entry->Size = DriverEntry->LdrEntry.SizeOfImage;
  5259. Entry->ImageInfoValid = TRUE;
  5260. Entry->CheckSum = DriverEntry->LdrEntry.CheckSum;
  5261. Entry->TimeDateStamp = DriverEntry->LdrEntry.TimeDateStamp;
  5262. m_Cur++;
  5263. return S_OK;
  5264. }
  5265. KernelTriage32ModuleInfo g_KernelTriage32ModuleIterator;
  5266. HRESULT
  5267. KernelTriage64ModuleInfo::Initialize(void)
  5268. {
  5269. m_Target = (KernelTriage64DumpTargetInfo*)g_Target;
  5270. if (m_Target->m_Dump->Triage.DriverListOffset != 0)
  5271. {
  5272. m_Head = m_Target->m_Dump->Triage.DriverCount;
  5273. m_Cur = 0;
  5274. return S_OK;
  5275. }
  5276. else
  5277. {
  5278. dprintf("Mini Kernel Dump does not contain driver list\n");
  5279. return S_FALSE;
  5280. }
  5281. }
  5282. HRESULT
  5283. KernelTriage64ModuleInfo::GetEntry(PMODULE_INFO_ENTRY Entry)
  5284. {
  5285. if (m_Cur == m_Head)
  5286. {
  5287. return S_FALSE;
  5288. }
  5289. PDUMP_DRIVER_ENTRY64 DriverEntry;
  5290. PDUMP_STRING DriverName;
  5291. DBG_ASSERT(m_Target->m_Dump->Triage.DriverListOffset != 0);
  5292. DriverEntry = (PDUMP_DRIVER_ENTRY64)
  5293. IndexByByte(m_Target->m_Dump,
  5294. m_Target->m_Dump->Triage.DriverListOffset +
  5295. m_Cur * sizeof(*DriverEntry));
  5296. DriverName = (PDUMP_STRING)
  5297. IndexByByte(m_Target->m_Dump, DriverEntry->DriverNameOffset);
  5298. Entry->NamePtr = (PSTR)DriverName->Buffer;
  5299. Entry->UnicodeNamePtr = 1;
  5300. Entry->NameLength = DriverName->Length * sizeof(WCHAR);
  5301. Entry->Base = DriverEntry->LdrEntry.DllBase;
  5302. Entry->Size = DriverEntry->LdrEntry.SizeOfImage;
  5303. Entry->ImageInfoValid = TRUE;
  5304. Entry->CheckSum = DriverEntry->LdrEntry.CheckSum;
  5305. Entry->TimeDateStamp = DriverEntry->LdrEntry.TimeDateStamp;
  5306. m_Cur++;
  5307. return S_OK;
  5308. }
  5309. KernelTriage64ModuleInfo g_KernelTriage64ModuleIterator;
  5310. HRESULT
  5311. UserMiniModuleInfo::Initialize(void)
  5312. {
  5313. m_Target = (UserMiniDumpTargetInfo*)g_Target;
  5314. if (m_Target->m_Modules != NULL)
  5315. {
  5316. m_Head = m_Target->m_Modules->NumberOfModules;
  5317. m_Cur = 0;
  5318. return S_OK;
  5319. }
  5320. else
  5321. {
  5322. m_Head = 0;
  5323. m_Cur = 0;
  5324. dprintf("User Mode Mini Dump does not have a module list\n");
  5325. return S_FALSE;
  5326. }
  5327. }
  5328. HRESULT
  5329. UserMiniModuleInfo::GetEntry(PMODULE_INFO_ENTRY Entry)
  5330. {
  5331. if (m_Cur == m_Head)
  5332. {
  5333. return S_FALSE;
  5334. }
  5335. MINIDUMP_MODULE UNALIGNED *Mod;
  5336. MINIDUMP_STRING UNALIGNED *ModName;
  5337. DBG_ASSERT(m_Target->m_Modules != NULL);
  5338. Mod = m_Target->m_Modules->Modules + m_Cur;
  5339. ModName = (MINIDUMP_STRING UNALIGNED *)
  5340. m_Target->IndexRva(Mod->ModuleNameRva, sizeof(*ModName),
  5341. "Module entry name");
  5342. if (ModName == NULL)
  5343. {
  5344. return HR_DUMP_CORRUPT;
  5345. }
  5346. Entry->NamePtr = (PSTR)ModName->Buffer;
  5347. Entry->UnicodeNamePtr = 1;
  5348. Entry->NameLength = ModName->Length;
  5349. // Some dumps do not have properly sign-extended addresses,
  5350. // so force the extension on 32-bit platforms.
  5351. if (g_TargetMachineType == IMAGE_FILE_MACHINE_I386 ||
  5352. g_TargetMachineType == IMAGE_FILE_MACHINE_ALPHA)
  5353. {
  5354. Entry->Base = EXTEND64(Mod->BaseOfImage);
  5355. }
  5356. else
  5357. {
  5358. Entry->Base = Mod->BaseOfImage;
  5359. }
  5360. Entry->Size = Mod->SizeOfImage;
  5361. Entry->ImageInfoValid = TRUE;
  5362. Entry->CheckSum = Mod->CheckSum;
  5363. Entry->TimeDateStamp = Mod->TimeDateStamp;
  5364. m_Cur++;
  5365. return S_OK;
  5366. }
  5367. UserMiniModuleInfo g_UserMiniModuleIterator;
  5368. HRESULT
  5369. KernelTriage32UnloadedModuleInfo::Initialize(void)
  5370. {
  5371. m_Target = (KernelTriage32DumpTargetInfo*)g_Target;
  5372. if (m_Target->m_Dump->Triage.UnloadedDriversOffset != 0)
  5373. {
  5374. PVOID Data = IndexByByte
  5375. (m_Target->m_Dump, m_Target->m_Dump->Triage.UnloadedDriversOffset);
  5376. m_Cur = (PDUMP_UNLOADED_DRIVERS32)((PULONG)Data + 1);
  5377. m_End = m_Cur + *(PULONG)Data;
  5378. return S_OK;
  5379. }
  5380. else
  5381. {
  5382. dprintf("Mini Kernel Dump does not contain unloaded driver list\n");
  5383. return S_FALSE;
  5384. }
  5385. }
  5386. HRESULT
  5387. KernelTriage32UnloadedModuleInfo::GetEntry(PSTR Name,
  5388. PDEBUG_MODULE_PARAMETERS Params)
  5389. {
  5390. if (m_Cur == m_End)
  5391. {
  5392. return S_FALSE;
  5393. }
  5394. ZeroMemory(Params, sizeof(*Params));
  5395. Params->Base = EXTEND64(m_Cur->StartAddress);
  5396. Params->Size = m_Cur->EndAddress - m_Cur->StartAddress;
  5397. Params->Flags = DEBUG_MODULE_UNLOADED;
  5398. if (Name != NULL)
  5399. {
  5400. USHORT NameLen = m_Cur->Name.Length;
  5401. if (NameLen > MAX_UNLOADED_NAME_LENGTH)
  5402. {
  5403. NameLen = MAX_UNLOADED_NAME_LENGTH;
  5404. }
  5405. if (WideCharToMultiByte(CP_ACP, 0, m_Cur->DriverName,
  5406. NameLen / sizeof(WCHAR),
  5407. Name,
  5408. MAX_UNLOADED_NAME_LENGTH / sizeof(WCHAR) + 1,
  5409. NULL, NULL) == 0)
  5410. {
  5411. return WIN32_LAST_STATUS();
  5412. }
  5413. Name[NameLen / sizeof(WCHAR)] = 0;
  5414. }
  5415. m_Cur++;
  5416. return S_OK;
  5417. }
  5418. KernelTriage32UnloadedModuleInfo g_KernelTriage32UnloadedModuleIterator;
  5419. HRESULT
  5420. KernelTriage64UnloadedModuleInfo::Initialize(void)
  5421. {
  5422. m_Target = (KernelTriage64DumpTargetInfo*)g_Target;
  5423. if (m_Target->m_Dump->Triage.UnloadedDriversOffset != 0)
  5424. {
  5425. PVOID Data = IndexByByte
  5426. (m_Target->m_Dump, m_Target->m_Dump->Triage.UnloadedDriversOffset);
  5427. m_Cur = (PDUMP_UNLOADED_DRIVERS64)((PULONG64)Data + 1);
  5428. m_End = m_Cur + *(PULONG)Data;
  5429. return S_OK;
  5430. }
  5431. else
  5432. {
  5433. dprintf("Mini Kernel Dump does not contain unloaded driver list\n");
  5434. return S_FALSE;
  5435. }
  5436. }
  5437. HRESULT
  5438. KernelTriage64UnloadedModuleInfo::GetEntry(PSTR Name,
  5439. PDEBUG_MODULE_PARAMETERS Params)
  5440. {
  5441. if (m_Cur == m_End)
  5442. {
  5443. return S_FALSE;
  5444. }
  5445. ZeroMemory(Params, sizeof(*Params));
  5446. Params->Base = m_Cur->StartAddress;
  5447. Params->Size = (ULONG)(m_Cur->EndAddress - m_Cur->StartAddress);
  5448. Params->Flags = DEBUG_MODULE_UNLOADED;
  5449. if (Name != NULL)
  5450. {
  5451. USHORT NameLen = m_Cur->Name.Length;
  5452. if (NameLen > MAX_UNLOADED_NAME_LENGTH)
  5453. {
  5454. NameLen = MAX_UNLOADED_NAME_LENGTH;
  5455. }
  5456. if (WideCharToMultiByte(CP_ACP, 0, m_Cur->DriverName,
  5457. NameLen / sizeof(WCHAR),
  5458. Name,
  5459. MAX_UNLOADED_NAME_LENGTH / sizeof(WCHAR) + 1,
  5460. NULL, NULL) == 0)
  5461. {
  5462. return WIN32_LAST_STATUS();
  5463. }
  5464. Name[NameLen / sizeof(WCHAR)] = 0;
  5465. }
  5466. m_Cur++;
  5467. return S_OK;
  5468. }
  5469. KernelTriage64UnloadedModuleInfo g_KernelTriage64UnloadedModuleIterator;
  5470. //----------------------------------------------------------------------------
  5471. //
  5472. // Validation code.
  5473. //
  5474. //----------------------------------------------------------------------------
  5475. #if DBG
  5476. VOID
  5477. DumpPageMap (
  5478. IN PRTL_BITMAP PageMap
  5479. )
  5480. {
  5481. PFN_NUMBER32 StartOfRun;
  5482. BOOL Mapped;
  5483. ULONG LineCount;
  5484. ULONG i;
  5485. printf ("VERBOSE:\nSummary Dump Page Map (not mapped pages): \n\n");
  5486. LineCount = 0;
  5487. StartOfRun = 0;
  5488. Mapped = RtlCheckBit (PageMap, 0);
  5489. for (i = 1; i < PageMap->SizeOfBitMap; i++) {
  5490. if (RtlCheckBit (PageMap, i)) {
  5491. printf ("%4.4x ", (SHORT) i);
  5492. if (LineCount == 11) {
  5493. printf ("\n");
  5494. LineCount = 0;
  5495. }
  5496. LineCount++;
  5497. }
  5498. }
  5499. printf ("\n\n");
  5500. }
  5501. #endif
  5502. // XXX drewb - Verification disabled until we decide what we want.
  5503. #ifdef VALIDATE_DUMPS
  5504. BOOL
  5505. DmppVerifyPagePresentInDumpFile(
  5506. ULONG Page,
  5507. ULONG Size
  5508. )
  5509. {
  5510. CHAR * Address;
  5511. CHAR ch;
  5512. BOOL ret = FALSE;
  5513. __try {
  5514. Address = DmppFileOffsetToMappedAddress (
  5515. DmppPageToOffset( Page ), FALSE);
  5516. if (!Address) {
  5517. ret = FALSE;
  5518. __leave;
  5519. }
  5520. ch = *Address;
  5521. Address += Size - 1;
  5522. ch = *Address;
  5523. ret = TRUE;
  5524. }
  5525. __except (EXCEPTION_EXECUTE_HANDLER) {
  5526. ret = FALSE;
  5527. }
  5528. return ret;
  5529. }
  5530. BOOL
  5531. WINAPI
  5532. DmpValidateDumpFile(
  5533. BOOL ThoroughCheck
  5534. )
  5535. /*++
  5536. Routine Description:
  5537. Validate that a dump file is valid. This will do the work of checking
  5538. if the file is a user-mode or kernel-mode dump file and verifying
  5539. that it is correct.
  5540. Arguments:
  5541. ThoroughCheck - If TRUE, instructs DmpValidateDumpFile to do a thorough
  5542. (significantly slower) check of the dump file. Otherwise a qicker,
  5543. less complete check is done.
  5544. Return Values:
  5545. TRUE - The dumpfile is valid.
  5546. FALSE - The dumpfile is invalid. Extended error status is available using
  5547. GetLastError.
  5548. --*/
  5549. {
  5550. PPHYSICAL_MEMORY_DESCRIPTOR32 PhysicalMemoryBlock;
  5551. BOOL ret = TRUE;
  5552. if (IS_FULL_USER_DUMP()) {
  5553. // ret = DmppUserModeTestHeader ();
  5554. // if (ret == 1 && ThoroughCheck) {
  5555. // ret = DmppUserModeTestContents ();
  5556. // }
  5557. } else {
  5558. PhysicalMemoryBlock = &g_DumpHeaderKernel32->Header.PhysicalMemoryBlock;
  5559. if (IS_SUMMARY_DUMP()) {
  5560. //
  5561. // The summary dump will have holes in the page table, so it's
  5562. // useless to even check it.
  5563. //
  5564. ret = TRUE;
  5565. } else {
  5566. if (g_DumpAddressExtensions) {
  5567. //
  5568. // This function is broken.
  5569. //
  5570. return TRUE;
  5571. #if 0
  5572. ULONG i;
  5573. ULONG j;
  5574. BOOL ret;
  5575. X86PAE_HARDWARE_PDPTE * PageDirectoryPointerTableBase;
  5576. X86PAE_HARDWARE_PDPTE * PageDirectoryPointerTableEntry;
  5577. HARDWARE_PDE_X86PAE * PageDirectoryBase;
  5578. HARDWARE_PDE_X86PAE * PageDirectoryEntry;
  5579. HARDWARE_PTE_X86PAE * PageTableBase;
  5580. //
  5581. // On a PAE kernel DmpPdePage is actually a pointer to the
  5582. // Page-Directory-Pointer-Table, not the Page-Directory.
  5583. //
  5584. //ASSERT ( DmpPdePage );
  5585. PageDirectoryPointerTableBase = (X86PAE_HARDWARE_PDPTE *) DmpPdePage;
  5586. //
  5587. // Loop through the top-level Page-Directory-Dointer Table.
  5588. //
  5589. ret = TRUE;
  5590. for (i = 0; i < 4; i++) {
  5591. PageDirectoryPointerTableEntry = &PageDirectoryPointerTableBase [ i ];
  5592. if (!PageDirectoryPointerTableEntry->Valid) {
  5593. //
  5594. // All Page-Directory-Pointer Table Entries must be present.
  5595. //
  5596. ret = FALSE;
  5597. break;
  5598. }
  5599. PageDirectoryBase = DmppFileOffsetToMappedAddress(
  5600. DmppPageToOffset(PageDirectoryPointerTableEntry->PageFrameNumber),
  5601. TRUE);
  5602. if (!PageDirectoryBase) {
  5603. //
  5604. // The specified page frame number did not map to a valid page.
  5605. //
  5606. ret = FALSE;
  5607. break;
  5608. }
  5609. //
  5610. // Loop through the Page-Directory Table.
  5611. //
  5612. for (j = 0; (j < 512) && (ret == TRUE) ; j++) {
  5613. PageDirectoryEntry = &PageDirectoryBase [ j ];
  5614. if (!PageDirectoryEntry->Valid) {
  5615. //
  5616. // The specific Page Table is not present. Not an error.
  5617. //
  5618. continue;
  5619. }
  5620. PageTableBase = DmppFileOffsetToMappedAddress(
  5621. DmppPageToOffset(PageDirectoryEntry->PageFrameNumber),
  5622. TRUE);
  5623. if (!PageTableBase) {
  5624. //
  5625. // The Page Table did not map to a valid address.
  5626. //
  5627. ret = FALSE;
  5628. break;
  5629. }
  5630. }
  5631. }
  5632. #endif
  5633. } else {
  5634. // NOT implemented
  5635. ret = TRUE;
  5636. }
  5637. //
  5638. // Dump validation routine. This routine verifies that any
  5639. // memory present in the MmPhysicalMemoryBlock was actually
  5640. // written to the dump file.
  5641. if (ret == 0 && ThoroughCheck) {
  5642. PFN_NUMBER32 i;
  5643. PFN_NUMBER32 j;
  5644. PFN_NUMBER32 Page;
  5645. for (i = 0; i < PhysicalMemoryBlock->NumberOfRuns; i++) {
  5646. for (j = 0; j < PhysicalMemoryBlock->Run [ i ].PageCount; j++) {
  5647. Page = PhysicalMemoryBlock->Run [ i ].BasePage + j;
  5648. if (!DmppVerifyPagePresentInDumpFile (Page, PageSize)) {
  5649. ret = FALSE;
  5650. break;
  5651. }
  5652. }
  5653. }
  5654. }
  5655. }
  5656. }
  5657. return ret;
  5658. }
  5659. #endif // #ifdef VALIDATE_DUMPS