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.

6702 lines
177 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. dumpctl.c
  5. Abstract:
  6. This module contains the code to dump memory to disk after a crash.
  7. Author:
  8. Darryl E. Havens (darrylh) 17-dec-1993
  9. Environment:
  10. Kernel mode
  11. Revision History:
  12. --*/
  13. #include "iomgr.h"
  14. #include "dumpctl.h"
  15. #include "ntddft.h"
  16. #include <inbv.h>
  17. #include <windef.h>
  18. #define NOEXTAPI
  19. #include <wdbgexts.h>
  20. extern KDDEBUGGER_DATA64 KdDebuggerDataBlock;
  21. typedef struct _TRIAGE_PTR_DATA_BLOCK {
  22. PUCHAR MinAddress;
  23. PUCHAR MaxAddress;
  24. } TRIAGE_PTR_DATA_BLOCK, *PTRIAGE_PTR_DATA_BLOCK;
  25. // A triage dump is sixteen pages long. Some of that is
  26. // header information and at least a few other pages will
  27. // be used for basic dump information so limit the number
  28. // of extra data blocks to something less than sixteen
  29. // to save array space.
  30. #define IO_MAX_TRIAGE_DUMP_DATA_BLOCKS 8
  31. //
  32. // Global variables
  33. //
  34. extern PVOID MmPfnDatabase;
  35. extern PFN_NUMBER MmHighestPossiblePhysicalPage;
  36. #if defined (_IA64_)
  37. extern PFN_NUMBER MmSystemParentTablePage;
  38. #endif
  39. ULONG IopAutoReboot;
  40. NTSTATUS IopFinalCrashDumpStatus = -1;
  41. ERESOURCE IopCrashDumpLock;
  42. ULONG IopNumTriageDumpDataBlocks;
  43. TRIAGE_PTR_DATA_BLOCK IopTriageDumpDataBlocks[IO_MAX_TRIAGE_DUMP_DATA_BLOCKS];
  44. //
  45. // If space is available in a triage dump it's possible
  46. // to add "interesting" data pages referenced by runtime
  47. // information such as context registers. The following
  48. // lists are offsets into the CONTEXT structure of pointers
  49. // which usually point to interesting data. They are
  50. // in priority order.
  51. //
  52. #define IOP_LAST_CONTEXT_OFFSET 0xffff
  53. #if defined(_X86_)
  54. USHORT IopRunTimeContextOffsets[] = {
  55. FIELD_OFFSET(CONTEXT, Ebx),
  56. FIELD_OFFSET(CONTEXT, Esi),
  57. FIELD_OFFSET(CONTEXT, Edi),
  58. FIELD_OFFSET(CONTEXT, Ecx),
  59. FIELD_OFFSET(CONTEXT, Edx),
  60. FIELD_OFFSET(CONTEXT, Eax),
  61. FIELD_OFFSET(CONTEXT, Eip),
  62. IOP_LAST_CONTEXT_OFFSET
  63. };
  64. #elif defined(_IA64_)
  65. USHORT IopRunTimeContextOffsets[] = {
  66. FIELD_OFFSET(CONTEXT, IntS0),
  67. FIELD_OFFSET(CONTEXT, IntS1),
  68. FIELD_OFFSET(CONTEXT, IntS2),
  69. FIELD_OFFSET(CONTEXT, IntS3),
  70. FIELD_OFFSET(CONTEXT, StIIP),
  71. IOP_LAST_CONTEXT_OFFSET
  72. };
  73. #elif defined(_AMD64_)
  74. USHORT IopRunTimeContextOffsets[] = {
  75. FIELD_OFFSET(CONTEXT, Rbx),
  76. FIELD_OFFSET(CONTEXT, Rsi),
  77. FIELD_OFFSET(CONTEXT, Rdi),
  78. FIELD_OFFSET(CONTEXT, Rcx),
  79. FIELD_OFFSET(CONTEXT, Rdx),
  80. FIELD_OFFSET(CONTEXT, Rax),
  81. FIELD_OFFSET(CONTEXT, Rip),
  82. IOP_LAST_CONTEXT_OFFSET
  83. };
  84. #else
  85. USHORT IopRunTimeContextOffsets[] = {
  86. IOP_LAST_CONTEXT_OFFSET
  87. };
  88. #endif
  89. //
  90. // Set IopIgnoreDumpCheck to TRUE when debugging dumps to prevent
  91. // the checksum from interfering with debugging.
  92. //
  93. LOGICAL IopIgnoreDumpCheck = FALSE;
  94. //
  95. // Max dump transfer sizes
  96. //
  97. #define IO_DUMP_MAXIMUM_TRANSFER_SIZE ( 1024 * 64 )
  98. #define IO_DUMP_MINIMUM_TRANSFER_SIZE ( 1024 * 32 )
  99. #define IO_DUMP_MINIMUM_FILE_SIZE ( PAGE_SIZE * 256 )
  100. #define MAX_UNICODE_LENGTH ( 512 )
  101. #define DEFAULT_DRIVER_PATH ( L"\\SystemRoot\\System32\\Drivers\\" )
  102. #define DEFAULT_DUMP_DRIVER ( L"\\SystemRoot\\System32\\Drivers\\diskdump.sys" )
  103. #define SCSIPORT_DRIVER_NAME ( L"scsiport.sys" )
  104. #define STORPORT_DRIVER_NAME ( L"storport.sys" )
  105. #ifdef _WIN64
  106. #define MAX_TRIAGE_STACK_SIZE ( 32 * 1024 )
  107. #else
  108. #define MAX_TRIAGE_STACK_SIZE ( 16 * 1024 )
  109. #endif
  110. #define DEFAULT_TRIAGE_DUMP_FLAGS ( 0xFFFFFFFF )
  111. //
  112. // for memory allocations
  113. //
  114. #define DUMP_TAG ('pmuD')
  115. #undef ExAllocatePool
  116. #define ExAllocatePool(Pool,Size) ExAllocatePoolWithTag(Pool,Size,DUMP_TAG)
  117. //
  118. // Function prototypes
  119. //
  120. NTSTATUS
  121. IoConfigureCrashDump(
  122. CRASHDUMP_CONFIGURATION Configuration
  123. );
  124. BOOLEAN
  125. IoInitializeCrashDump(
  126. IN HANDLE hPageFile
  127. );
  128. NTSTATUS
  129. IopWriteTriageDump(
  130. IN ULONG FieldsToWrite,
  131. IN PDUMP_DRIVER_WRITE WriteRoutine,
  132. IN OUT PLARGE_INTEGER * Mcb,
  133. IN OUT PMDL Mdl,
  134. IN ULONG DiverTransferSize,
  135. IN PCONTEXT Context,
  136. IN PKTHREAD Thread,
  137. IN LPBYTE Buffer,
  138. IN ULONG BufferSize,
  139. IN ULONG ServicePackBuild,
  140. IN ULONG TriageOptions
  141. );
  142. NTSTATUS
  143. IopWriteSummaryDump(
  144. IN PRTL_BITMAP PageMap,
  145. IN PDUMP_DRIVER_WRITE WriteRoutine,
  146. IN PANSI_STRING ProgressMessage,
  147. IN PUCHAR MessageBuffer,
  148. IN OUT PLARGE_INTEGER * Mcb,
  149. IN ULONG DiverTransferSize
  150. );
  151. NTSTATUS
  152. IopWriteToDisk(
  153. IN PVOID Buffer,
  154. IN ULONG WriteLength,
  155. IN PDUMP_DRIVER_WRITE DriverWriteRoutine,
  156. IN OUT PLARGE_INTEGER * Mcb,
  157. IN OUT PMDL Mdl,
  158. IN ULONG DriverTransferSize,
  159. IN KBUGCHECK_DUMP_IO_TYPE DataType
  160. );
  161. VOID
  162. IopMapPhysicalMemory(
  163. IN OUT PMDL Mdl,
  164. IN ULONG_PTR MemoryAddress,
  165. IN PPHYSICAL_MEMORY_RUN PhysicalMemoryRun,
  166. IN ULONG Length
  167. );
  168. NTSTATUS
  169. IopLoadDumpDriver (
  170. IN OUT PDUMP_STACK_CONTEXT DumpStack,
  171. IN PWCHAR DriverNameString,
  172. IN PWCHAR NewBaseNameString
  173. );
  174. NTSTATUS
  175. IopInitializeSummaryDump(
  176. IN OUT PMEMORY_DUMP MemoryDump,
  177. IN PDUMP_CONTROL_BLOCK DumpControlBlock
  178. );
  179. NTSTATUS
  180. IopWriteSummaryHeader(
  181. IN PSUMMARY_DUMP SummaryHeader,
  182. IN PDUMP_DRIVER_WRITE Write,
  183. IN OUT PLARGE_INTEGER * Mcb,
  184. IN OUT PMDL Mdl,
  185. IN ULONG WriteSize,
  186. IN ULONG Length
  187. );
  188. VOID
  189. IopMapVirtualToPhysicalMdl(
  190. IN OUT PMDL pMdl,
  191. IN ULONG_PTR dwMemoryAddress,
  192. IN ULONG dwLength
  193. );
  194. ULONG
  195. IopCreateSummaryDump (
  196. IN PMEMORY_DUMP MemoryDump
  197. );
  198. VOID
  199. IopDeleteNonExistentMemory(
  200. PSUMMARY_DUMP Header,
  201. PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock
  202. );
  203. NTSTATUS
  204. IopInvokeSecondaryDumpDataCallbacks(
  205. IN PDUMP_DRIVER_WRITE DriverWriteRoutine,
  206. IN OUT PLARGE_INTEGER * Mcb,
  207. IN OUT PMDL Mdl,
  208. IN ULONG DriverTransferSize,
  209. IN BYTE* Buffer,
  210. IN ULONG BufferSize,
  211. IN ULONG MaxTotal,
  212. IN ULONG MaxPerCallback,
  213. OUT OPTIONAL PULONG SpaceNeeded
  214. );
  215. NTSTATUS
  216. IopInvokeDumpIoCallbacks(
  217. IN PVOID Buffer,
  218. IN ULONG BufferSize,
  219. IN KBUGCHECK_DUMP_IO_TYPE Type
  220. );
  221. NTSTATUS
  222. IopGetDumpStack (
  223. IN PWCHAR ModulePrefix,
  224. OUT PDUMP_STACK_CONTEXT *pDumpStack,
  225. IN PUNICODE_STRING pUniDeviceName,
  226. IN PWSTR pDumpDriverName,
  227. IN DEVICE_USAGE_NOTIFICATION_TYPE UsageType,
  228. IN ULONG IgnoreDeviceUsageFailure
  229. );
  230. BOOLEAN
  231. IopInitializeDCB(
  232. );
  233. LARGE_INTEGER
  234. IopCalculateRequiredDumpSpace(
  235. IN ULONG dwDmpFlags,
  236. IN ULONG dwHeaderSize,
  237. IN PFN_NUMBER dwMaxPages,
  238. IN PFN_NUMBER dwMaxSummaryPages
  239. );
  240. NTSTATUS
  241. IopCompleteDumpInitialization(
  242. IN HANDLE FileHandle
  243. );
  244. #ifdef ALLOC_PRAGMA
  245. VOID
  246. IopReadDumpRegistry(
  247. OUT PULONG dumpControl,
  248. OUT PULONG numberOfHeaderPages,
  249. OUT PULONG autoReboot,
  250. OUT PULONG dumpFileSize
  251. );
  252. VOID
  253. IopFreeDCB(
  254. BOOLEAN FreeDCB
  255. );
  256. #pragma alloc_text(PAGE,IoGetDumpStack)
  257. #pragma alloc_text(PAGE,IopGetDumpStack)
  258. #pragma alloc_text(PAGE,IopLoadDumpDriver)
  259. #pragma alloc_text(PAGE,IoFreeDumpStack)
  260. #pragma alloc_text(PAGE,IopCompleteDumpInitialization)
  261. #pragma alloc_text(PAGE,IopFreeDCB)
  262. #pragma alloc_text(PAGE,IopReadDumpRegistry)
  263. #pragma alloc_text(PAGE,IopInitializeDCB)
  264. #pragma alloc_text(PAGE,IopConfigureCrashDump)
  265. #pragma alloc_text(PAGE,IoInitializeCrashDump)
  266. #pragma alloc_text(PAGE,IoConfigureCrashDump)
  267. #endif
  268. #if defined (i386)
  269. //
  270. // Functions
  271. //
  272. BOOLEAN
  273. X86PaeEnabled(
  274. )
  275. /*++
  276. Routine Description:
  277. Is PAE currently enabled?
  278. Return Values:
  279. Return TRUE if PAE is enabled in the CR4 register, FALSE otherwise.
  280. --*/
  281. {
  282. ULONG Reg_Cr4;
  283. _asm {
  284. _emit 0Fh
  285. _emit 20h
  286. _emit 0E0h ;; mov eax, cr4
  287. mov Reg_Cr4, eax
  288. }
  289. return (Reg_Cr4 & CR4_PAE ? TRUE : FALSE);
  290. }
  291. #endif
  292. BOOLEAN
  293. IopIsAddressRangeValid(
  294. IN PVOID VirtualAddress,
  295. IN SIZE_T Length
  296. )
  297. /*++
  298. Routine Description:
  299. Validate a range of addresses.
  300. Arguments:
  301. Virtual Address - Beginning of of memory block to validate.
  302. Length - Length of memory block to validate.
  303. Return Value:
  304. TRUE - Address range is valid.
  305. FALSE - Address range is not valid.
  306. --*/
  307. {
  308. UINT_PTR Va;
  309. ULONG Pages;
  310. Va = (UINT_PTR) PAGE_ALIGN (VirtualAddress);
  311. Pages = ADDRESS_AND_SIZE_TO_SPAN_PAGES (VirtualAddress, Length);
  312. while (Pages) {
  313. if ((Va < 0x10000) ||
  314. (!MmIsAddressValid ( (LPVOID) Va))) {
  315. return FALSE;
  316. }
  317. Va += PAGE_SIZE;
  318. Pages--;
  319. }
  320. return TRUE;
  321. }
  322. BOOLEAN
  323. IoAddTriageDumpDataBlock(
  324. IN PVOID Address,
  325. IN ULONG Length
  326. )
  327. /*++
  328. Routine Description:
  329. Add an entry to the list of data blocks that should
  330. be saved in any triage dump generated. The entire
  331. block must be valid for any of it to be saved.
  332. Arguments:
  333. Address - Beginning of data block.
  334. Length - Length of data block. This must be less than
  335. the triage dump size.
  336. Return Value:
  337. TRUE - Block was added.
  338. FALSE - Block was not added.
  339. --*/
  340. {
  341. ULONG i;
  342. PTRIAGE_PTR_DATA_BLOCK Block;
  343. PUCHAR MinAddress, MaxAddress;
  344. if (Length >= TRIAGE_DUMP_SIZE ||
  345. !IopIsAddressRangeValid(Address, Length)) {
  346. return FALSE;
  347. }
  348. MinAddress = (PUCHAR)Address;
  349. MaxAddress = MinAddress + Length;
  350. //
  351. // Minimize overlap between the new block and existing blocks.
  352. // Blocks cannot simply be merged as blocks are inserted in
  353. // priority order for storage in the dump. Combining a low-priority
  354. // block with a high-priority block could lead to a medium-
  355. // priority block being bumped improperly from the dump.
  356. //
  357. Block = IopTriageDumpDataBlocks;
  358. for (i = 0; i < IopNumTriageDumpDataBlocks; i++, Block++) {
  359. if (MinAddress >= Block->MaxAddress ||
  360. MaxAddress <= Block->MinAddress) {
  361. // No overlap.
  362. continue;
  363. }
  364. //
  365. // Trim overlap out of the new block. If this
  366. // would split the new block into pieces don't
  367. // trim to keep things simple. Content may then
  368. // be duplicated in the dump.
  369. //
  370. if (MinAddress >= Block->MinAddress) {
  371. if (MaxAddress <= Block->MaxAddress) {
  372. // New block is completely contained.
  373. return TRUE;
  374. }
  375. // New block extends above the current block
  376. // so trim off the low-range overlap.
  377. MinAddress = Block->MaxAddress;
  378. } else if (MaxAddress <= Block->MaxAddress) {
  379. // New block extends below the current block
  380. // so trim off the high-range overlap.
  381. MaxAddress = Block->MinAddress;
  382. }
  383. }
  384. if (IopNumTriageDumpDataBlocks >= IO_MAX_TRIAGE_DUMP_DATA_BLOCKS) {
  385. return FALSE;
  386. }
  387. Block = IopTriageDumpDataBlocks + IopNumTriageDumpDataBlocks++;
  388. Block->MinAddress = MinAddress;
  389. Block->MaxAddress = MaxAddress;
  390. return TRUE;
  391. }
  392. VOID
  393. IopAddRunTimeTriageDataBlocks(
  394. IN PCONTEXT Context,
  395. IN PVOID* StackMin,
  396. IN PVOID* StackMax,
  397. IN PVOID* StoreMin,
  398. IN PVOID* StoreMax
  399. )
  400. /*++
  401. Routine Description:
  402. Add data blocks referenced by the context or
  403. other runtime state.
  404. Arguments:
  405. Context - Context record at the time the dump is being generated for.
  406. StackMin, StackMax - Stack memory boundaries. Stack memory is
  407. stored elsewhere in the dump.
  408. StoreMin, StoreMax - Backing store memory boundaries. Store memory
  409. is stored elsewhere in the dump.
  410. Return Value:
  411. None.
  412. --*/
  413. {
  414. PUSHORT ContextOffset;
  415. ContextOffset = IopRunTimeContextOffsets;
  416. while (*ContextOffset < IOP_LAST_CONTEXT_OFFSET) {
  417. PVOID* Ptr;
  418. //
  419. // Retrieve possible pointers from the context
  420. // registers.
  421. //
  422. Ptr = *(PVOID**)((PUCHAR)Context + *ContextOffset);
  423. // Stack and backing store memory is already saved
  424. // so ignore any pointers that fall into those ranges.
  425. if ((Ptr < StackMin || Ptr >= StackMax) &&
  426. (Ptr < StoreMin || Ptr >= StoreMax)) {
  427. IoAddTriageDumpDataBlock(PAGE_ALIGN(Ptr), PAGE_SIZE);
  428. }
  429. ContextOffset++;
  430. }
  431. }
  432. NTSTATUS
  433. IoGetDumpStack (
  434. IN PWCHAR ModulePrefix,
  435. OUT PDUMP_STACK_CONTEXT * pDumpStack,
  436. IN DEVICE_USAGE_NOTIFICATION_TYPE UsageType,
  437. IN ULONG IgnoreDeviceUsageFailure
  438. )
  439. /*++
  440. Routine Description:
  441. This routine loads a dump stack instance and returns an allocated
  442. context structure to track the loaded dumps stack.
  443. Arguments:
  444. ModePrefix - The prefix to prepent to BaseName during the load
  445. operation. This allows loading the same drivers
  446. multiple times with different virtual names and
  447. linkages.
  448. pDumpStack - The returned dump stack context structure
  449. UsageType - The Device Notification Usage Type for this file, that
  450. this routine will send as to the device object once the
  451. file has been successfully created and initialized.
  452. IgnoreDeviceUsageFailure - If the Device Usage Notification Irp fails, allow
  453. this to succeed anyway.
  454. Return Value:
  455. Status
  456. --*/
  457. {
  458. PAGED_CODE();
  459. return IopGetDumpStack(ModulePrefix,
  460. pDumpStack,
  461. &IoArcBootDeviceName,
  462. DEFAULT_DUMP_DRIVER,
  463. UsageType,
  464. IgnoreDeviceUsageFailure
  465. );
  466. }
  467. BOOLEAN
  468. IoIsTriageDumpEnabled(
  469. VOID
  470. )
  471. {
  472. if (IopDumpControlBlock &&
  473. (IopDumpControlBlock->Flags & DCB_TRIAGE_DUMP_ENABLED)) {
  474. return TRUE;
  475. }
  476. return FALSE;
  477. }
  478. VOID
  479. IopDisplayString(
  480. IN PCCHAR FormatString,
  481. ...
  482. )
  483. /*++
  484. Routine Description:
  485. Display a string to the boot video console. This will also print the
  486. string to the debugger, if the proper flags have been enabled.
  487. Arguments:
  488. String - String to display.
  489. Return Value:
  490. None.
  491. --*/
  492. {
  493. va_list ap;
  494. CHAR buffer [ 128 ];
  495. va_start( ap, FormatString );
  496. _vsnprintf( buffer,
  497. sizeof ( buffer ),
  498. FormatString,
  499. ap );
  500. //
  501. // Display the string to the boot video monitor.
  502. //
  503. InbvDisplayString ( buffer );
  504. //
  505. // And, optionally, to the debugger.
  506. //
  507. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  508. CRASHDUMP_TRACE,
  509. "CRASHDUMP [DISP]: %s\r",
  510. buffer ));
  511. va_end(ap);
  512. }
  513. typedef struct _INTERNAL_GEOMETRY {
  514. DISK_GEOMETRY Geometry;
  515. LARGE_INTEGER DiskSize;
  516. DISK_PARTITION_INFO PartitionInfo;
  517. } INTERNAL_GEOMETRY, *PINTERNAL_GEOMETRY;
  518. C_ASSERT ( FIELD_OFFSET (INTERNAL_GEOMETRY, PartitionInfo) == FIELD_OFFSET (DISK_GEOMETRY_EX, Data) );
  519. NTSTATUS
  520. IopGetDumpStack (
  521. IN PWCHAR ModulePrefix,
  522. OUT PDUMP_STACK_CONTEXT * DumpStackBuffer,
  523. IN PUNICODE_STRING UniDeviceName,
  524. IN PWCHAR DumpDriverName,
  525. IN DEVICE_USAGE_NOTIFICATION_TYPE UsageType,
  526. IN ULONG IgnoreDeviceUsageFailure
  527. )
  528. /*++
  529. Routine Description:
  530. This routine loads a dump stack instance and returns an allocated
  531. context structure to track the loaded dumps stack.
  532. Arguments:
  533. ModePrefix - The prefix to prepent to BaseName during the load
  534. operation. This allows loading the same drivers
  535. multiple times with different virtual names and
  536. linkages.
  537. DumpStackBuffer - The returned dump stack context structure
  538. DeviceName - The name of the target dump device
  539. DumpDriverName - The name of the target dump driver
  540. UsageType - The Device Notification Usage Type for this file, that
  541. this routine will send as to the device object once the
  542. file has been successfully created and initialized.
  543. IgnoreDeviceUsageFailure - If the Device Usage Notification Irp fails, allow
  544. this to succeed anyway.
  545. Return Value:
  546. Status
  547. --*/
  548. {
  549. PDUMP_STACK_CONTEXT DumpStack;
  550. PUCHAR Buffer;
  551. ANSI_STRING AnsiString;
  552. UNICODE_STRING TempName;
  553. OBJECT_ATTRIBUTES ObjectAttributes;
  554. NTSTATUS Status;
  555. HANDLE DeviceHandle;
  556. SCSI_ADDRESS ScsiAddress;
  557. BOOLEAN ScsiDump;
  558. PARTITION_INFORMATION_EX PartitionInfo;
  559. PFILE_OBJECT FileObject;
  560. PDEVICE_OBJECT DeviceObject;
  561. PDUMP_POINTERS DumpPointers;
  562. UNICODE_STRING DriverName;
  563. PDRIVER_OBJECT DriverObject;
  564. PIRP Irp;
  565. PIO_STACK_LOCATION IrpSp;
  566. IO_STATUS_BLOCK IoStatus;
  567. PWCHAR DumpName;
  568. PWCHAR NameOffset;
  569. KEVENT Event;
  570. PVOID p1;
  571. PHYSICAL_ADDRESS pa;
  572. ULONG i;
  573. IO_STACK_LOCATION irpSp;
  574. PINTERNAL_GEOMETRY Geometry;
  575. PDUMP_INITIALIZATION_CONTEXT DumpInit;
  576. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  577. CRASHDUMP_TRACE,
  578. "CRASHDUMP: Prefix:%ws stk: %x device:%ws driver:%ws\n",
  579. ModulePrefix,
  580. DumpStackBuffer,
  581. UniDeviceName->Buffer,
  582. DumpDriverName
  583. ));
  584. ASSERT (DeviceUsageTypeUndefined != UsageType);
  585. DumpStack = ExAllocatePool (
  586. NonPagedPool,
  587. sizeof (DUMP_STACK_CONTEXT) + sizeof (DUMP_POINTERS)
  588. );
  589. if (!DumpStack) {
  590. return STATUS_INSUFFICIENT_RESOURCES;
  591. }
  592. RtlZeroMemory(DumpStack, sizeof(DUMP_STACK_CONTEXT)+sizeof(DUMP_POINTERS));
  593. DumpInit = &DumpStack->Init;
  594. DumpPointers = (PDUMP_POINTERS) (DumpStack + 1);
  595. DumpStack->DumpPointers = DumpPointers;
  596. InitializeListHead (&DumpStack->DriverList);
  597. DumpName = NULL;
  598. //
  599. // Allocate scratch buffer
  600. //
  601. Buffer = ExAllocatePool (PagedPool, PAGE_SIZE);
  602. if (!Buffer) {
  603. ExFreePool (DumpStack);
  604. return STATUS_INSUFFICIENT_RESOURCES;
  605. }
  606. if (!KeGetBugMessageText(BUGCODE_PSS_CRASH_INIT, &DumpStack->InitMsg) ||
  607. !KeGetBugMessageText(BUGCODE_PSS_CRASH_PROGRESS, &DumpStack->ProgMsg) ||
  608. !KeGetBugMessageText(BUGCODE_PSS_CRASH_DONE, &DumpStack->DoneMsg)) {
  609. Status = STATUS_UNSUCCESSFUL;
  610. goto Done;
  611. }
  612. InitializeObjectAttributes(
  613. &ObjectAttributes,
  614. UniDeviceName,
  615. 0,
  616. NULL,
  617. NULL
  618. );
  619. Status = ZwOpenFile(
  620. &DeviceHandle,
  621. FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
  622. &ObjectAttributes,
  623. &IoStatus,
  624. FILE_SHARE_READ | FILE_SHARE_WRITE,
  625. FILE_NON_DIRECTORY_FILE
  626. );
  627. if (!NT_SUCCESS(Status)) {
  628. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  629. CRASHDUMP_ERROR,
  630. "CRASHDUMP: Could not open boot device partition, %s\n",
  631. Buffer
  632. ));
  633. goto Done;
  634. }
  635. //
  636. // Check to see whether or not the system was booted from a SCSI device.
  637. //
  638. Status = ZwDeviceIoControlFile (
  639. DeviceHandle,
  640. NULL,
  641. NULL,
  642. NULL,
  643. &IoStatus,
  644. IOCTL_SCSI_GET_ADDRESS,
  645. NULL,
  646. 0,
  647. &ScsiAddress,
  648. sizeof( SCSI_ADDRESS )
  649. );
  650. if (Status == STATUS_PENDING) {
  651. ZwWaitForSingleObject (
  652. DeviceHandle,
  653. FALSE,
  654. NULL
  655. );
  656. Status = IoStatus.Status;
  657. }
  658. ScsiDump = (BOOLEAN) (NT_SUCCESS(Status));
  659. //
  660. // If SCSI then allocate storage to contain the target address information.
  661. //
  662. DumpInit->TargetAddress = NULL;
  663. if (ScsiDump) {
  664. DumpInit->TargetAddress = ExAllocatePool(
  665. NonPagedPool,
  666. sizeof (SCSI_ADDRESS)
  667. );
  668. //
  669. // Formerly, this allocation was allowed to fail and the dump port
  670. // driver would search for a disk with a matching signature. No
  671. // longer. If we can't allocate a SCSI address, just fail.
  672. // Note, if we always pass in a valid SCSI target address, then the
  673. // disk signature isn't really necessary, but leave it in for now.
  674. //
  675. if (DumpInit->TargetAddress == NULL) {
  676. Status = STATUS_NO_MEMORY;
  677. goto Done;
  678. }
  679. RtlCopyMemory(
  680. DumpInit->TargetAddress,
  681. &ScsiAddress,
  682. sizeof(SCSI_ADDRESS)
  683. );
  684. }
  685. //
  686. // Determine the disk signature for the device from which the system was
  687. // booted and get the partition offset.
  688. //
  689. Status = ZwDeviceIoControlFile(
  690. DeviceHandle,
  691. NULL,
  692. NULL,
  693. NULL,
  694. &IoStatus,
  695. IOCTL_DISK_GET_PARTITION_INFO_EX,
  696. NULL,
  697. 0,
  698. &PartitionInfo,
  699. sizeof( PartitionInfo )
  700. );
  701. if (Status == STATUS_PENDING) {
  702. ZwWaitForSingleObject (
  703. DeviceHandle,
  704. FALSE,
  705. NULL
  706. );
  707. Status = IoStatus.Status;
  708. }
  709. //
  710. // Use the scratch buffer for the geometry.
  711. //
  712. Geometry = (PINTERNAL_GEOMETRY) Buffer;
  713. Status = ZwDeviceIoControlFile(
  714. DeviceHandle,
  715. NULL,
  716. NULL,
  717. NULL,
  718. &IoStatus,
  719. IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
  720. NULL,
  721. 0,
  722. Geometry,
  723. sizeof (*Geometry)
  724. );
  725. if (Status == STATUS_PENDING) {
  726. ZwWaitForSingleObject (
  727. DeviceHandle,
  728. FALSE,
  729. NULL
  730. );
  731. Status = IoStatus.Status;
  732. }
  733. //
  734. // Copy the signature, either MBR or GPT.
  735. //
  736. DumpInit->PartitionStyle = Geometry->PartitionInfo.PartitionStyle;
  737. if ( DumpInit->PartitionStyle == PARTITION_STYLE_MBR ) {
  738. DumpInit->DiskInfo.Mbr.Signature = Geometry->PartitionInfo.Mbr.Signature;
  739. DumpInit->DiskInfo.Mbr.CheckSum = Geometry->PartitionInfo.Mbr.CheckSum;
  740. } else {
  741. DumpInit->DiskInfo.Gpt.DiskId = Geometry->PartitionInfo.Gpt.DiskId;
  742. }
  743. //
  744. // The scratch buffer is now free to use.
  745. //
  746. Geometry = NULL;
  747. //
  748. // Get the adapter object and base mapping registers for the disk from
  749. // the disk driver. These will be used to call the HAL once the system
  750. // system has crashed, since it is not possible at that point to recreate
  751. // them from scratch.
  752. //
  753. ObReferenceObjectByHandle (
  754. DeviceHandle,
  755. 0,
  756. IoFileObjectType,
  757. KernelMode,
  758. (PVOID *) &FileObject,
  759. NULL
  760. );
  761. DeviceObject = IoGetRelatedDeviceObject (FileObject);
  762. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  763. Irp = IoBuildDeviceIoControlRequest(
  764. IOCTL_SCSI_GET_DUMP_POINTERS,
  765. DeviceObject,
  766. NULL,
  767. 0,
  768. DumpPointers,
  769. sizeof (DUMP_POINTERS),
  770. FALSE,
  771. &Event,
  772. &IoStatus
  773. );
  774. if (!Irp) {
  775. ObDereferenceObject (FileObject);
  776. ZwClose (DeviceHandle);
  777. Status = STATUS_INSUFFICIENT_RESOURCES;
  778. goto Done;
  779. }
  780. IrpSp = IoGetNextIrpStackLocation (Irp);
  781. IrpSp->FileObject = FileObject;
  782. Status = IoCallDriver( DeviceObject, Irp );
  783. if (Status == STATUS_PENDING) {
  784. KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
  785. Status = IoStatus.Status;
  786. }
  787. if (!NT_SUCCESS(Status) ||
  788. IoStatus.Information < FIELD_OFFSET(DUMP_POINTERS, DeviceObject)) {
  789. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  790. CRASHDUMP_ERROR,
  791. "CRASHDUMP: Could not get dump pointers; error = %x, length %x\n",
  792. Status,
  793. IoStatus.Information
  794. ));
  795. ObDereferenceObject (FileObject);
  796. ZwClose (DeviceHandle);
  797. goto Done;
  798. }
  799. DumpStack->PointersLength = (ULONG) IoStatus.Information;
  800. //
  801. // If the driver returned a pointer to a device object, that is the
  802. // object for the dump driver (non-scsi case)
  803. //
  804. DeviceObject = (PDEVICE_OBJECT) DumpPointers->DeviceObject;
  805. if (DeviceObject) {
  806. DriverObject = DeviceObject->DriverObject;
  807. //
  808. // Loop through the name of the driver looking for the end of the name,
  809. // which is the name of the dump image.
  810. //
  811. DumpName = DriverObject->DriverName.Buffer;
  812. while ( NameOffset = wcsstr( DumpName, L"\\" )) {
  813. DumpName = ++NameOffset;
  814. }
  815. ScsiDump = FALSE;
  816. }
  817. //
  818. // Release the handle, but keep the reference to the file object as it
  819. // will be needed at free dump dump driver time
  820. //
  821. DumpStack->FileObject = FileObject;
  822. ZwClose (DeviceHandle);
  823. //
  824. // Fill in some DumpInit results
  825. //
  826. DumpInit->Length = sizeof (DUMP_INITIALIZATION_CONTEXT);
  827. DumpInit->Reserved = 0;
  828. DumpInit->StallRoutine = &KeStallExecutionProcessor;
  829. DumpInit->AdapterObject = DumpPointers->AdapterObject;
  830. DumpInit->MappedRegisterBase = DumpPointers->MappedRegisterBase;
  831. DumpInit->PortConfiguration = DumpPointers->DumpData;
  832. DumpStack->ModulePrefix = ModulePrefix;
  833. DumpStack->PartitionOffset = PartitionInfo.StartingOffset;
  834. DumpStack->UsageType = DeviceUsageTypeUndefined;
  835. //
  836. // The minimum common buffer size is IO_DUMP_COMMON_BUFFER_SIZE (compatability)
  837. // This is used by the dump driver for SRB extension, CachedExtension, and sense buffer
  838. //
  839. if (DumpPointers->CommonBufferSize < IO_DUMP_COMMON_BUFFER_SIZE) {
  840. DumpPointers->CommonBufferSize = IO_DUMP_COMMON_BUFFER_SIZE;
  841. }
  842. DumpInit->CommonBufferSize = DumpPointers->CommonBufferSize;
  843. //
  844. // Allocate the required common buffers
  845. //
  846. if (DumpPointers->AllocateCommonBuffers) {
  847. pa.QuadPart = 0x1000000 - 1;
  848. for (i=0; i < 2; i++) {
  849. if (DumpInit->AdapterObject) {
  850. p1 = (*((PDMA_ADAPTER)DumpInit->AdapterObject)->DmaOperations->
  851. AllocateCommonBuffer)(
  852. (PDMA_ADAPTER)DumpInit->AdapterObject,
  853. DumpPointers->CommonBufferSize,
  854. &pa,
  855. FALSE
  856. );
  857. } else {
  858. p1 = MmAllocateContiguousMemory (
  859. DumpPointers->CommonBufferSize,
  860. pa
  861. );
  862. if (!p1) {
  863. p1 = MmAllocateNonCachedMemory (DumpPointers->CommonBufferSize);
  864. }
  865. pa = MmGetPhysicalAddress(p1);
  866. }
  867. if (!p1) {
  868. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  869. CRASHDUMP_ERROR,
  870. "CRASHDUMP: Could not allocate common buffers for dump\n"
  871. ));
  872. Status = STATUS_INSUFFICIENT_RESOURCES;
  873. goto Done;
  874. }
  875. DumpInit->CommonBuffer[i] = p1;
  876. DumpInit->PhysicalAddress[i] = pa;
  877. }
  878. }
  879. //
  880. // Determine whether or not the system booted from SCSI.
  881. //
  882. if (ScsiDump) {
  883. //
  884. // Load the boot disk and port driver to be used by the various
  885. // miniports for writing memory to the disk.
  886. //
  887. Status = IopLoadDumpDriver (
  888. DumpStack,
  889. DumpDriverName,
  890. SCSIPORT_DRIVER_NAME
  891. );
  892. if (!NT_SUCCESS(Status)) {
  893. IopLogErrorEvent(0,9,STATUS_SUCCESS,IO_DUMP_DRIVER_LOAD_FAILURE,0,NULL,0,NULL);
  894. goto Done;
  895. }
  896. //
  897. // The disk and port dump driver has been loaded. Load the appropriate
  898. // miniport driver as well so that the boot device can be accessed.
  899. //
  900. DriverName.Length = 0;
  901. DriverName.Buffer = (PVOID) Buffer;
  902. DriverName.MaximumLength = PAGE_SIZE;
  903. //
  904. // The system was booted from SCSI. Get the name of the appropriate
  905. // miniport driver and load it.
  906. //
  907. sprintf(Buffer, "\\Device\\ScsiPort%d", ScsiAddress.PortNumber );
  908. RtlInitAnsiString( &AnsiString, Buffer );
  909. RtlAnsiStringToUnicodeString( &TempName, &AnsiString, TRUE );
  910. InitializeObjectAttributes(
  911. &ObjectAttributes,
  912. &TempName,
  913. 0,
  914. NULL,
  915. NULL
  916. );
  917. Status = ZwOpenFile(
  918. &DeviceHandle,
  919. FILE_READ_ATTRIBUTES,
  920. &ObjectAttributes,
  921. &IoStatus,
  922. FILE_SHARE_READ | FILE_SHARE_WRITE,
  923. FILE_NON_DIRECTORY_FILE
  924. );
  925. RtlFreeUnicodeString( &TempName );
  926. if (!NT_SUCCESS( Status )) {
  927. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  928. CRASHDUMP_ERROR,
  929. "CRASHDUMP: Could not open SCSI port %d, error = %x\n",
  930. ScsiAddress.PortNumber,
  931. Status
  932. ));
  933. goto Done;
  934. }
  935. //
  936. // Convert the file handle into a pointer to the device object, and
  937. // get the name of the driver from its driver object.
  938. //
  939. ObReferenceObjectByHandle(
  940. DeviceHandle,
  941. 0,
  942. IoFileObjectType,
  943. KernelMode,
  944. (PVOID *) &FileObject,
  945. NULL
  946. );
  947. DriverObject = FileObject->DeviceObject->DriverObject;
  948. ObDereferenceObject( FileObject );
  949. ZwClose( DeviceHandle );
  950. //
  951. // Loop through the name of the driver looking for the end of the name,
  952. // which is the name of the miniport image.
  953. //
  954. DumpName = DriverObject->DriverName.Buffer;
  955. while ( NameOffset = wcsstr( DumpName, L"\\" )) {
  956. DumpName = ++NameOffset;
  957. }
  958. }
  959. //
  960. // Load the dump driver
  961. //
  962. if (!DumpName) {
  963. Status = STATUS_NOT_SUPPORTED;
  964. goto Done;
  965. }
  966. swprintf ((PWCHAR) Buffer, L"\\SystemRoot\\System32\\Drivers\\%s.sys", DumpName);
  967. Status = IopLoadDumpDriver (
  968. DumpStack,
  969. (PWCHAR) Buffer,
  970. NULL
  971. );
  972. if (!NT_SUCCESS(Status)) {
  973. IopLogErrorEvent(0,10,STATUS_SUCCESS,IO_DUMP_DRIVER_LOAD_FAILURE,0,NULL,0,NULL);
  974. goto Done;
  975. }
  976. //
  977. // Claim the file as part of specific device usage path.
  978. //
  979. FileObject = DumpStack->FileObject;
  980. DeviceObject = IoGetRelatedDeviceObject (FileObject);
  981. RtlZeroMemory (&irpSp, sizeof (IO_STACK_LOCATION));
  982. irpSp.MajorFunction = IRP_MJ_PNP;
  983. irpSp.MinorFunction = IRP_MN_DEVICE_USAGE_NOTIFICATION;
  984. irpSp.Parameters.UsageNotification.Type = UsageType;
  985. irpSp.Parameters.UsageNotification.InPath = TRUE;
  986. irpSp.FileObject = FileObject;
  987. Status = IopSynchronousCall (DeviceObject, &irpSp, NULL);
  988. if (!NT_SUCCESS(Status) && IgnoreDeviceUsageFailure) {
  989. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  990. CRASHDUMP_WARNING,
  991. "CRASHDUMP: IopGetDumpStack: DEVICE_USAGE_NOTIFICATION "
  992. "Error ignored (%x)\n",
  993. Status
  994. ));
  995. Status = STATUS_SUCCESS;
  996. }
  997. if (NT_SUCCESS(Status)) {
  998. DumpStack->UsageType = UsageType;
  999. }
  1000. Done:
  1001. if (NT_SUCCESS(Status)) {
  1002. *DumpStackBuffer = DumpStack;
  1003. } else {
  1004. IoFreeDumpStack (DumpStack);
  1005. }
  1006. ExFreePool (Buffer);
  1007. return Status;
  1008. }
  1009. NTSTATUS
  1010. IopLoadDumpDriver (
  1011. IN OUT PDUMP_STACK_CONTEXT DumpStack,
  1012. IN PWCHAR DriverNameString,
  1013. IN PWCHAR NewBaseNameString OPTIONAL
  1014. )
  1015. /*++
  1016. Routine Description:
  1017. Worker function for IoGetDumpStack to load a particular driver into
  1018. the current DumpStack being created
  1019. Arguments:
  1020. DumpStack - Dump driver stack being built
  1021. DriverNameString - The string name of the driver to load
  1022. NewBaseNameString - The modified basename of the driver once loaded
  1023. Return Value:
  1024. Status
  1025. --*/
  1026. {
  1027. NTSTATUS Status;
  1028. PDUMP_STACK_IMAGE DumpImage;
  1029. UNICODE_STRING DriverName;
  1030. UNICODE_STRING BaseName;
  1031. UNICODE_STRING Prefix;
  1032. PUNICODE_STRING LoadBaseName;
  1033. //
  1034. // Allocate space to track this dump driver
  1035. //
  1036. DumpImage = ExAllocatePool(
  1037. NonPagedPool,
  1038. sizeof (DUMP_STACK_IMAGE)
  1039. );
  1040. if (!DumpImage) {
  1041. return STATUS_INSUFFICIENT_RESOURCES;
  1042. }
  1043. //
  1044. // Load the system image
  1045. //
  1046. RtlInitUnicodeString (&DriverName, DriverNameString);
  1047. RtlInitUnicodeString (&Prefix, DumpStack->ModulePrefix);
  1048. LoadBaseName = NULL;
  1049. if (NewBaseNameString) {
  1050. LoadBaseName = &BaseName;
  1051. RtlInitUnicodeString (&BaseName, NewBaseNameString);
  1052. BaseName.MaximumLength = Prefix.Length + BaseName.Length;
  1053. BaseName.Buffer = ExAllocatePool (
  1054. NonPagedPool,
  1055. BaseName.MaximumLength
  1056. );
  1057. if (!BaseName.Buffer) {
  1058. ExFreePool (DumpImage);
  1059. return STATUS_INSUFFICIENT_RESOURCES;
  1060. }
  1061. BaseName.Length = 0;
  1062. RtlAppendUnicodeStringToString (&BaseName, &Prefix);
  1063. RtlAppendUnicodeToString (&BaseName, NewBaseNameString);
  1064. }
  1065. else {
  1066. BaseName.Buffer = NULL;
  1067. }
  1068. Status = MmLoadSystemImage(
  1069. &DriverName,
  1070. &Prefix,
  1071. LoadBaseName,
  1072. MM_LOAD_IMAGE_AND_LOCKDOWN,
  1073. &DumpImage->Image,
  1074. &DumpImage->ImageBase
  1075. );
  1076. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1077. CRASHDUMP_TRACE,
  1078. "CRASHDUMP: MmLoadAndLockSystemImage\n"
  1079. " DumpImage %p Image %p Base %p\n",
  1080. DumpImage,
  1081. DumpImage->Image,
  1082. DumpImage->ImageBase
  1083. ));
  1084. if (BaseName.Buffer) {
  1085. ExFreePool (BaseName.Buffer);
  1086. }
  1087. if (!NT_SUCCESS (Status)) {
  1088. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1089. CRASHDUMP_ERROR,
  1090. "CRASHDUMP: Could not load %wZ; error = %x\n",
  1091. &DriverName,
  1092. Status
  1093. ));
  1094. ExFreePool (DumpImage);
  1095. return Status;
  1096. }
  1097. //
  1098. // Put this driver on the list of drivers to be processed at crash time
  1099. //
  1100. DumpImage->SizeOfImage = DumpImage->Image->SizeOfImage;
  1101. InsertTailList (&DumpStack->DriverList, &DumpImage->Link);
  1102. return STATUS_SUCCESS;
  1103. }
  1104. ULONG
  1105. IopGetDumpControlBlockCheck (
  1106. IN PDUMP_CONTROL_BLOCK Dcb
  1107. )
  1108. /*++
  1109. Routine Description:
  1110. Return the current checksum total for the Dcb
  1111. Arguments:
  1112. DumpStack - Dump driver stack to checksum
  1113. Return Value:
  1114. Checksum value
  1115. --*/
  1116. {
  1117. ULONG Check;
  1118. PLIST_ENTRY Link;
  1119. PDUMP_STACK_IMAGE DumpImage;
  1120. PMAPPED_ADDRESS MappedAddress;
  1121. PDUMP_STACK_CONTEXT DumpStack;
  1122. //
  1123. // Check the DCB, memory descriptor array, and the FileDescriptorArray
  1124. //
  1125. Check = PoSimpleCheck(0, Dcb, sizeof(DUMP_CONTROL_BLOCK));
  1126. Check = PoSimpleCheck(Check, Dcb->FileDescriptorArray, Dcb->FileDescriptorSize);
  1127. DumpStack = Dcb->DumpStack;
  1128. if (DumpStack) {
  1129. //
  1130. // Include the dump stack context structure, and dump driver images
  1131. //
  1132. Check = PoSimpleCheck(Check, DumpStack, sizeof(DUMP_STACK_CONTEXT));
  1133. Check = PoSimpleCheck(Check, DumpStack->DumpPointers, DumpStack->PointersLength);
  1134. for (Link = DumpStack->DriverList.Flink;
  1135. Link != &DumpStack->DriverList;
  1136. Link = Link->Flink) {
  1137. DumpImage = CONTAINING_RECORD(Link, DUMP_STACK_IMAGE, Link);
  1138. Check = PoSimpleCheck(Check, DumpImage, sizeof(DUMP_STACK_IMAGE));
  1139. #if !defined (_IA64_)
  1140. //
  1141. // ISSUE - 2000/02/14 - math: Add image check image for IA64.
  1142. //
  1143. // Disable the image checksum on IA64 because it's broken.
  1144. Check = PoSimpleCheck(Check, DumpImage->ImageBase, DumpImage->SizeOfImage);
  1145. #endif
  1146. }
  1147. //
  1148. // Include the mapped addresses
  1149. //
  1150. // If this is non-null it is treated as a PMAPPED_ADDRESS * (see scsiport and atdisk)
  1151. //
  1152. if (DumpStack->Init.MappedRegisterBase != NULL) {
  1153. MappedAddress = *(PMAPPED_ADDRESS *)DumpStack->Init.MappedRegisterBase;
  1154. } else {
  1155. MappedAddress = NULL;
  1156. }
  1157. while (MappedAddress) {
  1158. Check = PoSimpleCheck (Check, MappedAddress, sizeof(MAPPED_ADDRESS));
  1159. MappedAddress = MappedAddress->NextMappedAddress;
  1160. }
  1161. }
  1162. return Check;
  1163. }
  1164. NTSTATUS
  1165. IoInitializeDumpStack (
  1166. IN PDUMP_STACK_CONTEXT DumpStack,
  1167. IN PUCHAR MessageBuffer OPTIONAL
  1168. )
  1169. /*++
  1170. Routine Description:
  1171. Initialize the dump driver stack referenced by DumpStack to perform IO.
  1172. Arguments:
  1173. DumpStack - Dump driver stack being initialized
  1174. Return Value:
  1175. Status
  1176. --*/
  1177. {
  1178. PDUMP_INITIALIZATION_CONTEXT DumpInit;
  1179. PLIST_ENTRY Link;
  1180. NTSTATUS Status;
  1181. PDRIVER_INITIALIZE DriverInit;
  1182. PDUMP_STACK_IMAGE DumpImage;
  1183. DumpInit = &DumpStack->Init;
  1184. //
  1185. // ISSUE - 2000/02/07 - math: Verify checksum on DumpStack structure
  1186. //
  1187. //
  1188. // Initializes the dump drivers
  1189. //
  1190. for (Link = DumpStack->DriverList.Flink;
  1191. Link != &DumpStack->DriverList;
  1192. Link = Link->Flink) {
  1193. DumpImage = CONTAINING_RECORD(Link, DUMP_STACK_IMAGE, Link);
  1194. //
  1195. // Call this driver's driver init. Only the first driver gets the
  1196. // dump initialization context
  1197. //
  1198. DriverInit = (PDRIVER_INITIALIZE) (ULONG_PTR) DumpImage->Image->EntryPoint;
  1199. Status = DriverInit (NULL, (PUNICODE_STRING) DumpInit);
  1200. DumpInit = NULL;
  1201. if (!NT_SUCCESS(Status)) {
  1202. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1203. CRASHDUMP_ERROR,
  1204. "CRASHDUMP: Unable to initialize driver; error = %x\n",
  1205. Status
  1206. ));
  1207. return Status;
  1208. }
  1209. }
  1210. DumpInit = &DumpStack->Init;
  1211. //
  1212. // Display string we are starting
  1213. //
  1214. if (MessageBuffer) {
  1215. IopDisplayString ( MessageBuffer );
  1216. }
  1217. //
  1218. // Open the partition from which the system was booted.
  1219. // This returns TRUE if the disk w/the appropriate signature was found,
  1220. // otherwise a NULL, in which case there is no way to continue.
  1221. //
  1222. if (!DumpInit->OpenRoutine (DumpStack->PartitionOffset)) {
  1223. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1224. CRASHDUMP_ERROR,
  1225. "CRASHDUMP: Could not find/open partition offset\n"
  1226. ));
  1227. return STATUS_UNSUCCESSFUL;
  1228. }
  1229. return STATUS_SUCCESS;
  1230. }
  1231. VOID
  1232. IoGetDumpHiberRanges (
  1233. IN PVOID HiberContext,
  1234. IN PDUMP_STACK_CONTEXT DumpStack
  1235. )
  1236. /*++
  1237. Routine Description:
  1238. Adds the dump driver stack storage to the hibernate range list,
  1239. to inform the hibernate procedure which pages need cloned,
  1240. discarded or not checksumed as they are in use by the dump
  1241. stack.
  1242. Arguments:
  1243. HiberContext - Pointer to the hiber context structure
  1244. DumpStack - Dump driver stack being initialized
  1245. Return Value:
  1246. None
  1247. --*/
  1248. {
  1249. PDUMP_POINTERS DumpPointers;
  1250. PDUMP_STACK_IMAGE DumpImage;
  1251. PLIST_ENTRY Link;
  1252. DumpPointers = DumpStack->DumpPointers;
  1253. //
  1254. // Report the common buffer
  1255. //
  1256. if (DumpPointers->CommonBufferVa) {
  1257. PoSetHiberRange (
  1258. HiberContext,
  1259. PO_MEM_CL_OR_NCHK,
  1260. DumpPointers->CommonBufferVa,
  1261. DumpPointers->CommonBufferSize,
  1262. 'fubc'
  1263. );
  1264. }
  1265. //
  1266. // Dump the entire image of the dump drivers
  1267. //
  1268. for (Link = DumpStack->DriverList.Flink;
  1269. Link != &DumpStack->DriverList;
  1270. Link = Link->Flink) {
  1271. DumpImage = CONTAINING_RECORD(Link, DUMP_STACK_IMAGE, Link);
  1272. PoSetHiberRange (
  1273. HiberContext,
  1274. PO_MEM_CL_OR_NCHK,
  1275. DumpImage->ImageBase,
  1276. DumpImage->SizeOfImage,
  1277. 'gmID'
  1278. );
  1279. }
  1280. }
  1281. VOID
  1282. IoFreeDumpStack (
  1283. IN PDUMP_STACK_CONTEXT DumpStack
  1284. )
  1285. /*++
  1286. Routine Description:
  1287. Free the dump driver stack referenced by DumpStack
  1288. Arguments:
  1289. DumpStack - Dump driver stack being initialized
  1290. Return Value:
  1291. None
  1292. --*/
  1293. {
  1294. PDUMP_INITIALIZATION_CONTEXT DumpInit;
  1295. PDUMP_STACK_IMAGE DumpImage;
  1296. PDEVICE_OBJECT DeviceObject;
  1297. PIO_STACK_LOCATION IrpSp;
  1298. IO_STATUS_BLOCK IoStatus;
  1299. PIRP Irp;
  1300. KEVENT Event;
  1301. NTSTATUS Status;
  1302. ULONG i;
  1303. PFILE_OBJECT FileObject;
  1304. IO_STACK_LOCATION irpSp;
  1305. PAGED_CODE();
  1306. DumpInit = &DumpStack->Init;
  1307. //
  1308. // Release the claim to this file as a specific device usage path.
  1309. //
  1310. FileObject = DumpStack->FileObject;
  1311. if (FileObject) {
  1312. DeviceObject = IoGetRelatedDeviceObject (FileObject);
  1313. RtlZeroMemory (&irpSp, sizeof (IO_STACK_LOCATION));
  1314. irpSp.MajorFunction = IRP_MJ_PNP;
  1315. irpSp.MinorFunction = IRP_MN_DEVICE_USAGE_NOTIFICATION;
  1316. irpSp.Parameters.UsageNotification.Type = DumpStack->UsageType;
  1317. irpSp.Parameters.UsageNotification.InPath = FALSE;
  1318. irpSp.FileObject = FileObject;
  1319. if (DeviceUsageTypeUndefined != DumpStack->UsageType) {
  1320. Status = IopSynchronousCall (DeviceObject, &irpSp, NULL);
  1321. } else {
  1322. Status = STATUS_SUCCESS;
  1323. }
  1324. }
  1325. //
  1326. // Free any common buffers which where allocated
  1327. //
  1328. for (i=0; i < 2; i++) {
  1329. if (DumpInit->CommonBuffer[i]) {
  1330. if (DumpInit->AdapterObject) {
  1331. (*((PDMA_ADAPTER)DumpInit->AdapterObject)->DmaOperations->
  1332. FreeCommonBuffer )(
  1333. (PDMA_ADAPTER)DumpInit->AdapterObject,
  1334. ((PDUMP_POINTERS)DumpStack->DumpPointers)->CommonBufferSize,
  1335. DumpInit->PhysicalAddress[i],
  1336. DumpInit->CommonBuffer[i],
  1337. FALSE
  1338. );
  1339. } else {
  1340. MmFreeContiguousMemory (DumpInit->CommonBuffer[i]);
  1341. }
  1342. }
  1343. DumpInit->CommonBuffer[i] = NULL;
  1344. }
  1345. //
  1346. // Unload the dump drivers
  1347. //
  1348. while (!IsListEmpty(&DumpStack->DriverList)) {
  1349. DumpImage = CONTAINING_RECORD(DumpStack->DriverList.Blink, DUMP_STACK_IMAGE, Link);
  1350. RemoveEntryList (&DumpImage->Link);
  1351. MmUnloadSystemImage (DumpImage->Image);
  1352. ExFreePool (DumpImage);
  1353. }
  1354. //
  1355. // Inform the driver stack that the dump registartion is over
  1356. //
  1357. if (DumpStack->FileObject) {
  1358. DeviceObject = IoGetRelatedDeviceObject ((PFILE_OBJECT) DumpStack->FileObject);
  1359. KeInitializeEvent( &Event, NotificationEvent, FALSE );
  1360. Irp = IoBuildDeviceIoControlRequest(
  1361. IOCTL_SCSI_FREE_DUMP_POINTERS,
  1362. DeviceObject,
  1363. DumpStack->DumpPointers,
  1364. sizeof (DUMP_POINTERS),
  1365. NULL,
  1366. 0,
  1367. FALSE,
  1368. &Event,
  1369. &IoStatus
  1370. );
  1371. IrpSp = IoGetNextIrpStackLocation (Irp);
  1372. IrpSp->FileObject = DumpStack->FileObject;
  1373. Status = IoCallDriver( DeviceObject, Irp );
  1374. if (Status == STATUS_PENDING) {
  1375. KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
  1376. Status = IoStatus.Status;
  1377. }
  1378. ObDereferenceObject( DumpStack->FileObject );
  1379. }
  1380. //
  1381. // Free the target address if it exists
  1382. //
  1383. if (DumpStack->Init.TargetAddress) {
  1384. ExFreePool( DumpStack->Init.TargetAddress);
  1385. }
  1386. //
  1387. // Free the dump stack context
  1388. //
  1389. ExFreePool (DumpStack);
  1390. }
  1391. VOID
  1392. IopGetSecondaryDumpDataLimits(
  1393. ULONG Flags,
  1394. OUT PULONG MaxData,
  1395. OUT PULONG MaxPerCallback
  1396. )
  1397. {
  1398. // When the selected dump type is small also
  1399. // limit the amount of secondary dump data.
  1400. // This prevents overzealous secondary dumpers from
  1401. // creating multi-megabyte secondary dumps when triage
  1402. // dumps are selected.
  1403. if (!(Flags & DCB_DUMP_ENABLED) ||
  1404. (Flags & DCB_DUMP_HEADER_ENABLED)) {
  1405. *MaxData = 0;
  1406. *MaxPerCallback = 0;
  1407. } else if (Flags & DCB_TRIAGE_DUMP_ENABLED) {
  1408. *MaxData = 16 * PAGE_SIZE;
  1409. *MaxPerCallback = PAGE_SIZE;
  1410. } else {
  1411. // Arbitrarily limit maximum data amount to 256MB.
  1412. // There shouldn't be any reason that callers should
  1413. // have anywhere near that much data that wouldn't
  1414. // get picked up by a full dump.
  1415. *MaxData = 256 * 1024 * 1024;
  1416. *MaxPerCallback = *MaxData / 4;
  1417. }
  1418. }
  1419. NTSTATUS
  1420. IopGetSecondaryDumpDataSpace(
  1421. IN PDUMP_CONTROL_BLOCK dcb,
  1422. OUT PULONG Space
  1423. )
  1424. {
  1425. ULONG MaxDumpData;
  1426. ULONG MaxPerCallbackDumpData;
  1427. NTSTATUS NtStatus;
  1428. IopGetSecondaryDumpDataLimits(dcb->Flags,
  1429. &MaxDumpData, &MaxPerCallbackDumpData);
  1430. NtStatus = IopInvokeSecondaryDumpDataCallbacks(NULL, NULL, NULL, 0,
  1431. (PBYTE)dcb->HeaderPage,
  1432. PAGE_SIZE,
  1433. MaxDumpData,
  1434. MaxPerCallbackDumpData,
  1435. Space);
  1436. if (!NT_SUCCESS(NtStatus)) {
  1437. *Space = 0;
  1438. }
  1439. return NtStatus;
  1440. }
  1441. NTSTATUS
  1442. IopInitializeDumpSpaceAndType(
  1443. IN PDUMP_CONTROL_BLOCK dcb,
  1444. IN OUT PMEMORY_DUMP MemoryDump,
  1445. IN ULONG SecondarySpace
  1446. )
  1447. {
  1448. LARGE_INTEGER Space;
  1449. Space.QuadPart = 0;
  1450. if (dcb->Flags & DCB_TRIAGE_DUMP_ENABLED) {
  1451. //
  1452. // Fixed size dump for triage-dumps.
  1453. //
  1454. MemoryDump->Header.DumpType = DUMP_TYPE_TRIAGE;
  1455. MemoryDump->Header.MiniDumpFields = dcb->TriageDumpFlags;
  1456. Space.QuadPart = TRIAGE_DUMP_SIZE;
  1457. } else if (dcb->Flags & DCB_SUMMARY_DUMP_ENABLED) {
  1458. MemoryDump->Header.DumpType = DUMP_TYPE_SUMMARY;
  1459. Space = IopCalculateRequiredDumpSpace(
  1460. dcb->Flags,
  1461. dcb->HeaderSize,
  1462. MmPhysicalMemoryBlock->NumberOfPages,
  1463. MemoryDump->Summary.Pages
  1464. );
  1465. } else {
  1466. if (dcb->Flags & DCB_DUMP_HEADER_ENABLED) {
  1467. MemoryDump->Header.DumpType = DUMP_TYPE_HEADER;
  1468. }
  1469. Space = IopCalculateRequiredDumpSpace(
  1470. dcb->Flags,
  1471. dcb->HeaderSize,
  1472. MmPhysicalMemoryBlock->NumberOfPages,
  1473. MmPhysicalMemoryBlock->NumberOfPages
  1474. );
  1475. }
  1476. //
  1477. // Add in any secondary space.
  1478. //
  1479. Space.QuadPart += SecondarySpace;
  1480. //
  1481. // If the calculated size is larger than the pagefile, truncate it to
  1482. // the pagefile size.
  1483. //
  1484. if (Space.QuadPart > dcb->DumpFileSize.QuadPart) {
  1485. Space.QuadPart = dcb->DumpFileSize.QuadPart;
  1486. }
  1487. MemoryDump->Header.RequiredDumpSpace = Space;
  1488. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1489. CRASHDUMP_TRACE,
  1490. "CRASHDUMP: Dump File Size set to %I64x\n",
  1491. Space.QuadPart
  1492. ));
  1493. return STATUS_SUCCESS;
  1494. }
  1495. BOOLEAN
  1496. IoWriteCrashDump(
  1497. IN ULONG BugCheckCode,
  1498. IN ULONG_PTR BugCheckParameter1,
  1499. IN ULONG_PTR BugCheckParameter2,
  1500. IN ULONG_PTR BugCheckParameter3,
  1501. IN ULONG_PTR BugCheckParameter4,
  1502. IN PVOID ContextSave,
  1503. IN PKTHREAD Thread,
  1504. OUT PBOOLEAN Reboot
  1505. )
  1506. /*++
  1507. Routine Description:
  1508. This routine checks to see whether or not crash dumps are enabled and, if
  1509. so, writes all of physical memory to the system disk's paging file.
  1510. Arguments:
  1511. BugCheckCode/ParameterN - Code and parameters w/which BugCheck was called.
  1512. Return Value:
  1513. None.
  1514. --*/
  1515. {
  1516. NTSTATUS status;
  1517. PDUMP_CONTROL_BLOCK dcb;
  1518. PDUMP_STACK_CONTEXT dumpStack;
  1519. PDUMP_DRIVER_WRITE write;
  1520. PDUMP_DRIVER_FINISH finishUp;
  1521. PDUMP_HEADER header;
  1522. PCONTEXT context = ContextSave;
  1523. PMEMORY_DUMP MemoryDump;
  1524. LARGE_INTEGER diskByteOffset;
  1525. PPFN_NUMBER page;
  1526. PFN_NUMBER localMdl[(sizeof( MDL )/sizeof(PFN_NUMBER)) + 17];
  1527. PMDL mdl;
  1528. PLARGE_INTEGER mcb;
  1529. ULONG_PTR memoryAddress;
  1530. ULONG byteOffset;
  1531. ULONG byteCount;
  1532. ULONG bytesRemaining;
  1533. PFN_NUMBER ActualPages;
  1534. ULONG dwTransferSize;
  1535. PFN_NUMBER NumberOfPages;
  1536. #if defined (_X86_)
  1537. ULONG_PTR DirBasePage;
  1538. #endif
  1539. ULONG MaxDumpData;
  1540. ULONG MaxPerCallbackDumpData;
  1541. NTSTATUS SecondaryStatus;
  1542. ULONG SecondarySpace;
  1543. KdCheckForDebugBreak();
  1544. ASSERT (Reboot != NULL);
  1545. //
  1546. // Initialization
  1547. //
  1548. MemoryDump = NULL;
  1549. //
  1550. // Immediately fill out the reboot parameter as auto-reboot
  1551. // may be enabled even with no other post-mortem features.
  1552. //
  1553. if (IopAutoReboot) {
  1554. *Reboot = TRUE;
  1555. } else {
  1556. *Reboot = FALSE;
  1557. }
  1558. //
  1559. // Begin by determining whether or not crash dumps are enabled. If not,
  1560. // return immediately since there is nothing to do.
  1561. //
  1562. dcb = IopDumpControlBlock;
  1563. if (!dcb) {
  1564. return FALSE;
  1565. }
  1566. if (dcb->Flags & DCB_DUMP_ENABLED || dcb->Flags & DCB_SUMMARY_ENABLED) {
  1567. IopFinalCrashDumpStatus = STATUS_PENDING;
  1568. //
  1569. // A dump is to be written to the paging file. Ensure that all of the
  1570. // descriptor data for what needs to be done is valid, otherwise it
  1571. // could be that part of the reason for the bugcheck is that this data
  1572. // was corrupted. Or, it could be that no paging file was found yet,
  1573. // or any number of other situations.
  1574. //
  1575. //
  1576. // We do not check the checksum if IopIgnoreDumpCheck is TRUE. Use
  1577. // this to make debugging easier.
  1578. //
  1579. if (!IopIgnoreDumpCheck &&
  1580. IopGetDumpControlBlockCheck(dcb) != IopDumpControlBlockChecksum) {
  1581. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1582. CRASHDUMP_ERROR,
  1583. "CRASHDUMP: Disk dump routine returning due to DCB integrity error\n"
  1584. " Computed Checksum: %d != Saved Checksum %d\n"
  1585. " No dump will be created\n",
  1586. IopGetDumpControlBlockCheck (dcb),
  1587. IopDumpControlBlockChecksum
  1588. ));
  1589. IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL;
  1590. return FALSE;
  1591. }
  1592. //
  1593. // Message that we are starting the crashdump
  1594. //
  1595. dumpStack = dcb->DumpStack;
  1596. // sprintf( messageBuffer, "%Z\n", &dumpStack->InitMsg );
  1597. //
  1598. // Disable HAL Verifier during a crash dump.
  1599. //
  1600. VfDisableHalVerifier();
  1601. //
  1602. // Initialize the dump stack
  1603. //
  1604. status = IoInitializeDumpStack (dumpStack, NULL);
  1605. KdCheckForDebugBreak();
  1606. if (!NT_SUCCESS( status )) {
  1607. IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL;
  1608. return FALSE;
  1609. }
  1610. //
  1611. // If we successfully initialized the dump stack, print out the PSS
  1612. // message.
  1613. //
  1614. IopDisplayString ("%Z\n", &dumpStack->InitMsg);
  1615. //
  1616. // Record the dump driver's entry points.
  1617. //
  1618. write = dumpStack->Init.WriteRoutine;
  1619. finishUp = dumpStack->Init.FinishRoutine;
  1620. dwTransferSize = dumpStack->Init.MaximumTransferSize;
  1621. if ( ( !dwTransferSize ) || ( dwTransferSize > IO_DUMP_MAXIMUM_TRANSFER_SIZE ) ) {
  1622. dwTransferSize = IO_DUMP_MINIMUM_TRANSFER_SIZE;
  1623. }
  1624. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1625. CRASHDUMP_TRACE,
  1626. "CRASHDUMP: Maximum Transfer Size = %x\n",dwTransferSize
  1627. ));
  1628. //
  1629. // The boot partition was found, so put together a dump file header
  1630. // and write it to the disk.
  1631. //
  1632. // Get the amount of secondary dump data while the
  1633. // header page can still be used as scratch space.
  1634. SecondaryStatus = IopGetSecondaryDumpDataSpace(dcb, &SecondarySpace);
  1635. MemoryDump = (PMEMORY_DUMP) dcb->HeaderPage;
  1636. header = &MemoryDump->Header;
  1637. RtlFillMemoryUlong( header, sizeof(*header), DUMP_SIGNATURE );
  1638. header->ValidDump = DUMP_VALID_DUMP;
  1639. header->BugCheckCode = BugCheckCode;
  1640. header->BugCheckParameter1 = BugCheckParameter1;
  1641. header->BugCheckParameter2 = BugCheckParameter2;
  1642. header->BugCheckParameter3 = BugCheckParameter3;
  1643. header->BugCheckParameter4 = BugCheckParameter4;
  1644. header->SecondaryDataState = (ULONG)SecondaryStatus;
  1645. #if defined (_X86_)
  1646. //
  1647. // Add the current page directory table page - don't use the directory
  1648. // table base for the crashing process as we have switched cr3 on
  1649. // stack overflow crashes, etc.
  1650. //
  1651. _asm {
  1652. mov eax, cr3
  1653. mov DirBasePage, eax
  1654. }
  1655. header->DirectoryTableBase = DirBasePage;
  1656. #elif defined (_IA64_)
  1657. ASSERT (((MmSystemParentTablePage << PAGE_SHIFT) >> PAGE_SHIFT) ==
  1658. MmSystemParentTablePage);
  1659. header->DirectoryTableBase = MmSystemParentTablePage << PAGE_SHIFT;
  1660. #else
  1661. header->DirectoryTableBase = KeGetCurrentThread()->ApcState.Process->DirectoryTableBase[0];
  1662. #endif
  1663. header->PfnDataBase = (ULONG_PTR)MmPfnDatabase;
  1664. header->PsLoadedModuleList = (ULONG_PTR) &PsLoadedModuleList;
  1665. header->PsActiveProcessHead = (ULONG_PTR) &PsActiveProcessHead;
  1666. header->NumberProcessors = dcb->NumberProcessors;
  1667. header->MajorVersion = dcb->MajorVersion;
  1668. header->MinorVersion = dcb->MinorVersion;
  1669. #if defined (i386)
  1670. header->PaeEnabled = X86PaeEnabled ();
  1671. #endif
  1672. header->KdDebuggerDataBlock = KdGetDataBlock();
  1673. header->MachineImageType = CURRENT_IMAGE_TYPE ();
  1674. if (!(dcb->Flags & DCB_DUMP_ENABLED)) {
  1675. NumberOfPages = 1;
  1676. } else {
  1677. NumberOfPages = MmPhysicalMemoryBlock->NumberOfPages;
  1678. }
  1679. strcpy( header->VersionUser, dcb->VersionUser );
  1680. //
  1681. // Copy the physical memory descriptor.
  1682. //
  1683. RtlCopyMemory (&MemoryDump->Header.PhysicalMemoryBlock,
  1684. MmPhysicalMemoryBlock,
  1685. sizeof( PHYSICAL_MEMORY_DESCRIPTOR ) +
  1686. ((MmPhysicalMemoryBlock->NumberOfRuns - 1) *
  1687. sizeof( PHYSICAL_MEMORY_RUN )) );
  1688. RtlCopyMemory( MemoryDump->Header.ContextRecord,
  1689. context,
  1690. sizeof( CONTEXT ) );
  1691. MemoryDump->Header.Exception.ExceptionCode = STATUS_BREAKPOINT;
  1692. MemoryDump->Header.Exception.ExceptionRecord = 0;
  1693. MemoryDump->Header.Exception.NumberParameters = 0;
  1694. MemoryDump->Header.Exception.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
  1695. MemoryDump->Header.Exception.ExceptionAddress = PROGRAM_COUNTER (context);
  1696. //
  1697. // Init dump type to FULL
  1698. //
  1699. MemoryDump->Header.DumpType = DUMP_TYPE_FULL;
  1700. //
  1701. // Save the System time and uptime (This is always available)
  1702. // It's a KSYSTEM_TIME structure, but we only store the low and
  1703. // high 1 part
  1704. //
  1705. MemoryDump->Header.SystemTime.LowPart = SharedUserData->SystemTime.LowPart;
  1706. MemoryDump->Header.SystemTime.HighPart = SharedUserData->SystemTime.High1Time;
  1707. MemoryDump->Header.SystemUpTime.LowPart = SharedUserData->InterruptTime.LowPart;
  1708. MemoryDump->Header.SystemUpTime.HighPart = SharedUserData->InterruptTime.High1Time;
  1709. // Save product type and suite.
  1710. MemoryDump->Header.ProductType = SharedUserData->NtProductType;
  1711. MemoryDump->Header.SuiteMask = SharedUserData->SuiteMask;
  1712. //
  1713. // Set the Required dump size in the dump header. In the case of
  1714. // a summary dump the file allocation size can be significantly larger
  1715. // then the amount of used space.
  1716. //
  1717. MemoryDump->Header.RequiredDumpSpace.QuadPart = 0;
  1718. IopGetSecondaryDumpDataLimits(dcb->Flags,
  1719. &MaxDumpData, &MaxPerCallbackDumpData);
  1720. if (MaxDumpData > SecondarySpace) {
  1721. MaxDumpData = SecondarySpace;
  1722. if (MaxPerCallbackDumpData > MaxDumpData) {
  1723. MaxPerCallbackDumpData = MaxDumpData;
  1724. }
  1725. }
  1726. if (dcb->Flags & DCB_DUMP_ENABLED) {
  1727. //
  1728. // If summary dump try to create the dump header
  1729. //
  1730. if ( (dcb->Flags & DCB_SUMMARY_DUMP_ENABLED) ) {
  1731. //
  1732. // Initialize the summary dump
  1733. //
  1734. status = IopInitializeSummaryDump( MemoryDump, dcb );
  1735. if ( !NT_SUCCESS (status) ) {
  1736. //
  1737. // No summary dump header so return.
  1738. //
  1739. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1740. CRASHDUMP_WARNING,
  1741. "CRASHDUMP: NULL summary dump header\n"
  1742. ));
  1743. IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL;
  1744. return FALSE;
  1745. }
  1746. }
  1747. IopInitializeDumpSpaceAndType ( dcb, MemoryDump, SecondarySpace );
  1748. }
  1749. //
  1750. // All of the pieces of the header file have been generated. Before
  1751. // mapping or writing anything to the disk, the I- & D-stream caches
  1752. // must be flushed so that page color coherency is kept. Sweep both
  1753. // caches now.
  1754. //
  1755. KeSweepCurrentDcache();
  1756. KeSweepCurrentIcache();
  1757. //
  1758. // Create MDL for dump.
  1759. //
  1760. mdl = (PMDL) &localMdl[0];
  1761. MmCreateMdl( mdl, NULL, PAGE_SIZE );
  1762. mdl->MdlFlags |= MDL_PAGES_LOCKED;
  1763. mcb = dcb->FileDescriptorArray;
  1764. page = MmGetMdlPfnArray(mdl);
  1765. *page = dcb->HeaderPfn;
  1766. mdl->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA;
  1767. bytesRemaining = PAGE_SIZE;
  1768. memoryAddress = (ULONG_PTR) dcb->HeaderPage;
  1769. IopInvokeDumpIoCallbacks(dcb->HeaderPage, PAGE_SIZE,
  1770. KbDumpIoHeader);
  1771. //
  1772. // All of the pieces of the header file have been generated. Write
  1773. // the header page to the paging file, using the appropriate drivers,
  1774. // etc.
  1775. //
  1776. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1777. CRASHDUMP_TRACE,
  1778. "CRASHDUMP: Writing dump header to disk\n"
  1779. ));
  1780. while (bytesRemaining) {
  1781. if (mcb[0].QuadPart <= bytesRemaining) {
  1782. byteCount = mcb[0].LowPart;
  1783. } else {
  1784. byteCount = bytesRemaining;
  1785. }
  1786. mdl->ByteCount = byteCount;
  1787. mdl->ByteOffset = (ULONG)(memoryAddress & (PAGE_SIZE - 1));
  1788. mdl->MappedSystemVa = (PVOID) memoryAddress;
  1789. mdl->StartVa = PAGE_ALIGN ((PVOID)memoryAddress);
  1790. //
  1791. // Write to disk.
  1792. //
  1793. KdCheckForDebugBreak();
  1794. if (!NT_SUCCESS( write( &mcb[1], mdl ) )) {
  1795. IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL;
  1796. return FALSE;
  1797. }
  1798. //
  1799. // Adjust bytes remaining.
  1800. //
  1801. bytesRemaining -= byteCount;
  1802. memoryAddress += byteCount;
  1803. mcb[0].QuadPart = mcb[0].QuadPart - byteCount;
  1804. mcb[1].QuadPart = mcb[1].QuadPart + byteCount;
  1805. if (!mcb[0].QuadPart) {
  1806. mcb += 2;
  1807. }
  1808. }
  1809. //
  1810. // If only requesting a header dump, we are now done.
  1811. //
  1812. if (dcb->Flags & DCB_DUMP_HEADER_ENABLED) {
  1813. goto FinishDump;
  1814. }
  1815. //
  1816. // The header page has been written. If this is a triage-dump, write
  1817. // the dump information and bail. Otherwise, fall through and do the
  1818. // full or summary dump.
  1819. //
  1820. if (dcb->Flags & DCB_TRIAGE_DUMP_ENABLED) {
  1821. status = IopWriteTriageDump (dcb->TriageDumpFlags,
  1822. write,
  1823. &mcb,
  1824. mdl,
  1825. dwTransferSize,
  1826. context,
  1827. Thread,
  1828. dcb->TriageDumpBuffer,
  1829. dcb->TriageDumpBufferSize - sizeof(DUMP_HEADER),
  1830. dcb->BuildNumber,
  1831. (UCHAR)dcb->Flags
  1832. );
  1833. if (!NT_SUCCESS (status)) {
  1834. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1835. CRASHDUMP_WARNING,
  1836. "CRASHDUMP: Failed to write triage-dump\n"
  1837. ));
  1838. IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL;
  1839. return FALSE;
  1840. }
  1841. goto FinishDump;
  1842. }
  1843. //
  1844. // The header page has been written to the paging file. If a full dump
  1845. // of all of physical memory is to be written, write it now.
  1846. //
  1847. if (dcb->Flags & DCB_DUMP_ENABLED) {
  1848. ULONG64 bytesDoneSoFar = 0;
  1849. ULONG currentPercentage = 0;
  1850. ULONG maximumPercentage = 0;
  1851. //
  1852. // Actual Pages is the number of pages to dump.
  1853. //
  1854. ActualPages = NumberOfPages;
  1855. if (dcb->Flags & DCB_SUMMARY_DUMP_ENABLED) {
  1856. //
  1857. // At this point the dump header header has been sucessfully
  1858. // written. Write the summary dump header.
  1859. //
  1860. status = IopWriteSummaryHeader(
  1861. &MemoryDump->Summary,
  1862. write,
  1863. &mcb,
  1864. mdl,
  1865. dwTransferSize,
  1866. (dcb->HeaderSize - sizeof(DUMP_HEADER))
  1867. );
  1868. if ( !NT_SUCCESS (status) ) {
  1869. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1870. CRASHDUMP_WARNING,
  1871. "CRASHDUMP: Error writing summary dump header %08x\n",
  1872. status
  1873. ));
  1874. IopFinalCrashDumpStatus = status;
  1875. return FALSE;
  1876. }
  1877. ActualPages = MemoryDump->Summary.Pages;
  1878. }
  1879. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1880. CRASHDUMP_TRACE,
  1881. "CRASHDUMP: Writing Memory Dump\n"
  1882. ));
  1883. //
  1884. // Set the virtual file offset and initialize loop variables and
  1885. // constants.
  1886. //
  1887. memoryAddress = (ULONG_PTR)MmPhysicalMemoryBlock->Run[0].BasePage * PAGE_SIZE;
  1888. if ( dcb->Flags & DCB_SUMMARY_DUMP_ENABLED ) {
  1889. status = IopWriteSummaryDump (
  1890. (PRTL_BITMAP) &MemoryDump->Summary.Bitmap,
  1891. write,
  1892. &dumpStack->ProgMsg,
  1893. NULL,
  1894. &mcb,
  1895. dwTransferSize
  1896. );
  1897. if (!NT_SUCCESS (status)) {
  1898. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1899. CRASHDUMP_WARNING,
  1900. "CRASHDUMP: Failed to write kernel memory dump\n"
  1901. ));
  1902. IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL;
  1903. return FALSE;
  1904. }
  1905. goto FinishDump;
  1906. }
  1907. //
  1908. // Now loop, writing all of physical memory to the paging file.
  1909. //
  1910. while (mcb[0].QuadPart) {
  1911. diskByteOffset = mcb[1];
  1912. //
  1913. // Calculate byte offset;
  1914. //
  1915. byteOffset = (ULONG)(memoryAddress & (PAGE_SIZE - 1));
  1916. if (dwTransferSize <= mcb[0].QuadPart) {
  1917. byteCount = dwTransferSize - byteOffset;
  1918. } else {
  1919. byteCount = mcb[0].LowPart;
  1920. }
  1921. if ((ULONG64)ActualPages * PAGE_SIZE - bytesDoneSoFar <
  1922. byteCount) {
  1923. byteCount = (ULONG)
  1924. ((ULONG64)ActualPages * PAGE_SIZE - bytesDoneSoFar);
  1925. }
  1926. bytesDoneSoFar += byteCount;
  1927. currentPercentage = (ULONG)
  1928. (((bytesDoneSoFar / PAGE_SIZE) * 100) / ActualPages);
  1929. if (currentPercentage > maximumPercentage) {
  1930. maximumPercentage = currentPercentage;
  1931. //
  1932. // Update message on screen.
  1933. //
  1934. IopDisplayString ( "%Z: %3d\r",
  1935. &dumpStack->ProgMsg,
  1936. maximumPercentage
  1937. );
  1938. }
  1939. //
  1940. // Map the physical memory and write it to the
  1941. // current segment of the file.
  1942. //
  1943. IopMapPhysicalMemory( mdl,
  1944. memoryAddress,
  1945. &MmPhysicalMemoryBlock->Run[0],
  1946. byteCount
  1947. );
  1948. //
  1949. // Write the next segment.
  1950. //
  1951. KdCheckForDebugBreak();
  1952. IopInvokeDumpIoCallbacks((PUCHAR)mdl->MappedSystemVa +
  1953. mdl->ByteOffset, byteCount,
  1954. KbDumpIoBody);
  1955. if (!NT_SUCCESS( write( &diskByteOffset, mdl ) )) {
  1956. IopFinalCrashDumpStatus = STATUS_UNSUCCESSFUL;
  1957. return FALSE;
  1958. }
  1959. //
  1960. // Adjust pointers for next part.
  1961. //
  1962. memoryAddress += byteCount;
  1963. mcb[0].QuadPart = mcb[0].QuadPart - byteCount;
  1964. mcb[1].QuadPart = mcb[1].QuadPart + byteCount;
  1965. if (!mcb[0].QuadPart) {
  1966. mcb += 2;
  1967. }
  1968. if ((bytesDoneSoFar / PAGE_SIZE) >= ActualPages) {
  1969. break;
  1970. }
  1971. }
  1972. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  1973. CRASHDUMP_TRACE,
  1974. "CRASHDUMP: memory dump written\n"
  1975. ));
  1976. }
  1977. FinishDump:
  1978. IopDisplayString ( "%Z", &dumpStack->DoneMsg );
  1979. IopInvokeSecondaryDumpDataCallbacks(write,
  1980. &mcb,
  1981. mdl,
  1982. dwTransferSize,
  1983. (PBYTE)dcb->HeaderPage,
  1984. PAGE_SIZE,
  1985. MaxDumpData,
  1986. MaxPerCallbackDumpData,
  1987. NULL);
  1988. // Final I/O complete notification.
  1989. IopInvokeDumpIoCallbacks(NULL, 0, KbDumpIoComplete);
  1990. //
  1991. // Sweep the cache so the debugger will work.
  1992. //
  1993. KeSweepCurrentDcache();
  1994. KeSweepCurrentIcache();
  1995. //
  1996. // Have the dump flush the adapter and disk caches.
  1997. //
  1998. finishUp();
  1999. //
  2000. // Indicate to the debugger that the dump has been successfully
  2001. // written.
  2002. //
  2003. IopFinalCrashDumpStatus = STATUS_SUCCESS;
  2004. }
  2005. KdCheckForDebugBreak();
  2006. return TRUE;
  2007. }
  2008. VOID
  2009. IopMapPhysicalMemory(
  2010. IN OUT PMDL Mdl,
  2011. IN ULONG_PTR MemoryAddress,
  2012. IN PPHYSICAL_MEMORY_RUN PhysicalMemoryRun,
  2013. IN ULONG Length
  2014. )
  2015. /*++
  2016. Routine Description:
  2017. This routine is invoked to fill in the specified MDL (Memory Descriptor
  2018. List) w/the appropriate information to map the specified memory address
  2019. range.
  2020. Arguments:
  2021. Mdl - Address of the MDL to be filled in.
  2022. MemoryAddress - Pseudo-virtual address being mapped.
  2023. PhysicalMemoryRun - Base address of the physical memory run list.
  2024. Length - Length of transfer to be mapped.
  2025. Return Value:
  2026. None.
  2027. --*/
  2028. {
  2029. PPHYSICAL_MEMORY_RUN pmr = PhysicalMemoryRun;
  2030. PPFN_NUMBER page;
  2031. PFN_NUMBER pages;
  2032. PFN_NUMBER base;
  2033. PFN_NUMBER currentBase;
  2034. //
  2035. // Begin by determining the base physical page of the start of the address
  2036. // range and filling in the MDL appropriately.
  2037. //
  2038. Mdl->StartVa = PAGE_ALIGN( (PVOID) (MemoryAddress) );
  2039. Mdl->ByteOffset = (ULONG)(MemoryAddress & (PAGE_SIZE - 1));
  2040. Mdl->ByteCount = Length;
  2041. //
  2042. // Get the page frame index for the base address.
  2043. //
  2044. base = (PFN_NUMBER) ((ULONG_PTR)(Mdl->StartVa) >> PAGE_SHIFT);
  2045. pages = ADDRESS_AND_SIZE_TO_SPAN_PAGES(MemoryAddress, Length);
  2046. currentBase = pmr->BasePage;
  2047. page = MmGetMdlPfnArray(Mdl);
  2048. //
  2049. // Map all of the pages for this transfer until there are no more remaining
  2050. // to be mapped.
  2051. //
  2052. while (pages) {
  2053. //
  2054. // Find the memory run that maps the beginning of this transfer.
  2055. //
  2056. while (currentBase + pmr->PageCount <= base) {
  2057. currentBase += pmr->PageCount;
  2058. pmr++;
  2059. }
  2060. //
  2061. // The current memory run maps the start of this transfer. Capture
  2062. // the base page for the start of the transfer.
  2063. //
  2064. *page++ = pmr->BasePage + (PFN_NUMBER)(base++ - currentBase);
  2065. pages--;
  2066. }
  2067. //
  2068. // All of the PFNs for the address range have been filled in so map the
  2069. // physical memory into virtual address space.
  2070. //
  2071. MmMapMemoryDumpMdl( Mdl );
  2072. }
  2073. VOID
  2074. IopAddPageToPageMap(
  2075. IN ULONG MaxPage,
  2076. IN PRTL_BITMAP BitMap,
  2077. IN ULONG PageFrameIndex,
  2078. IN ULONG NumberOfPages
  2079. )
  2080. {
  2081. //
  2082. // Sometimes we get PFNs that are out of range. Just ignore them.
  2083. //
  2084. if (PageFrameIndex >= MaxPage) {
  2085. return;
  2086. }
  2087. RtlSetBits (BitMap, PageFrameIndex, NumberOfPages);
  2088. }
  2089. VOID
  2090. IopRemovePageFromPageMap(
  2091. IN ULONG MaxPage,
  2092. IN PRTL_BITMAP BitMap,
  2093. IN ULONG PageFrameIndex,
  2094. IN ULONG NumberOfPages
  2095. )
  2096. {
  2097. //
  2098. // Sometimes we get PFNs that are out of range. Just ignore them.
  2099. //
  2100. if (PageFrameIndex >= MaxPage) {
  2101. return;
  2102. }
  2103. RtlClearBits (BitMap, PageFrameIndex, NumberOfPages);
  2104. }
  2105. NTSTATUS
  2106. IoSetDumpRange(
  2107. IN PMM_KERNEL_DUMP_CONTEXT Context,
  2108. IN PVOID StartVa,
  2109. IN ULONG_PTR Pages,
  2110. IN ULONG AddressFlags
  2111. )
  2112. /*++
  2113. Routine Description:
  2114. This routine includes this range of memory in the dump
  2115. Arguments:
  2116. Context - Dump context.
  2117. StartVa - Starting virtual address.
  2118. Pages - The number of pages to include
  2119. AddressFlags - 0 if the address is virtually mapped.
  2120. 1 if the address is super/large page mapped. This implies
  2121. the entire page range is physically contiguous.
  2122. 2 if the address really represents a physical page frame
  2123. number. This also implies the entire page range is
  2124. physically contiguous.
  2125. Return Value:
  2126. STATUS_SUCCESS - On success.
  2127. NTSTATUS - Error.
  2128. --*/
  2129. {
  2130. PCHAR Va;
  2131. PRTL_BITMAP BitMap;
  2132. PHYSICAL_ADDRESS PhyAddr;
  2133. PSUMMARY_DUMP Summary;
  2134. BOOLEAN AllPagesSet;
  2135. ULONG_PTR PageFrameIndex;
  2136. //
  2137. // Validation
  2138. //
  2139. ASSERT (Context != NULL &&
  2140. Context->Context != NULL);
  2141. //
  2142. // Initialization
  2143. //
  2144. Summary = (PSUMMARY_DUMP) Context->Context;
  2145. BitMap = (PRTL_BITMAP) &Summary->Bitmap;
  2146. Va = StartVa;
  2147. AllPagesSet = TRUE;
  2148. //
  2149. // Win64 can have really large page addresses. This dump code does
  2150. // not handle that yet. Note that before this assert is removed
  2151. // the casts of Pages to ULONG must be removed.
  2152. //
  2153. ASSERT(Pages <= MAXULONG);
  2154. if (AddressFlags == 1) {
  2155. PhyAddr = MmGetPhysicalAddress (Va);
  2156. IopAddPageToPageMap ( Summary->BitmapSize,
  2157. BitMap,
  2158. (ULONG) (PhyAddr.QuadPart >> PAGE_SHIFT),
  2159. (ULONG) Pages
  2160. );
  2161. } else if (AddressFlags == 2) {
  2162. PageFrameIndex = (ULONG_PTR) Va;
  2163. IopAddPageToPageMap ( Summary->BitmapSize,
  2164. BitMap,
  2165. (ULONG) PageFrameIndex,
  2166. (ULONG) Pages
  2167. );
  2168. } else {
  2169. //
  2170. // Not physically contiguous.
  2171. //
  2172. while (Pages) {
  2173. //
  2174. // Only do a translation for valid pages.
  2175. //
  2176. if ( MmIsAddressValid(Va) ) {
  2177. //
  2178. // Get the physical mapping. Note: this does not require a lock
  2179. //
  2180. PhyAddr = MmGetPhysicalAddress (Va);
  2181. IopAddPageToPageMap ( Summary->BitmapSize,
  2182. BitMap,
  2183. (ULONG)( PhyAddr.QuadPart >> PAGE_SHIFT),
  2184. 1);
  2185. if (PhyAddr.QuadPart >> PAGE_SHIFT > Summary->BitmapSize) {
  2186. AllPagesSet = FALSE;
  2187. }
  2188. }
  2189. Va += PAGE_SIZE;
  2190. Pages--;
  2191. }
  2192. }
  2193. if (AllPagesSet) {
  2194. return STATUS_SUCCESS;
  2195. }
  2196. return STATUS_INVALID_ADDRESS;
  2197. }
  2198. NTSTATUS
  2199. IoFreeDumpRange(
  2200. IN PMM_KERNEL_DUMP_CONTEXT Context,
  2201. IN PVOID StartVa,
  2202. IN ULONG_PTR Pages,
  2203. IN ULONG AddressFlags
  2204. )
  2205. /*++
  2206. Routine Description:
  2207. This routine excludes this range of memory in the dump.
  2208. Arguments:
  2209. DumpContext - dump context
  2210. StartVa - Starting VA
  2211. Pages - The number of pages to include
  2212. AddressFlags - 0 if the address is virtually mapped.
  2213. 1 if the address is super/large page mapped. This implies
  2214. the entire page range is physically contiguous.
  2215. 2 if the address really represents a physical page frame
  2216. number. This also implies the entire page range is
  2217. physically contiguous.
  2218. Return Value:
  2219. STATUS_SUCCESS - On success.
  2220. NTSTATUS - Error.
  2221. --*/
  2222. {
  2223. PCHAR Va;
  2224. PRTL_BITMAP BitMap;
  2225. PHYSICAL_ADDRESS PhyAddr;
  2226. PSUMMARY_DUMP Summary;
  2227. ULONG_PTR PageFrameIndex;
  2228. ASSERT (Context != NULL &&
  2229. Context->Context != NULL);
  2230. //
  2231. // Round to page size.
  2232. //
  2233. Summary = (PSUMMARY_DUMP)Context->Context;
  2234. BitMap = (PRTL_BITMAP) &Summary->Bitmap;
  2235. Va = StartVa;
  2236. //
  2237. // Win64 can have really large page addresses. This dump code does
  2238. // not handle that yet. Note that before this assert is removed
  2239. // the casts of Pages to ULONG must be removed.
  2240. //
  2241. ASSERT (Pages <= MAXULONG);
  2242. if (AddressFlags == 1) {
  2243. PhyAddr = MmGetPhysicalAddress(Va);
  2244. IopRemovePageFromPageMap (Summary->BitmapSize,
  2245. BitMap,
  2246. (ULONG)(PhyAddr.QuadPart >> PAGE_SHIFT),
  2247. (ULONG) Pages
  2248. );
  2249. } else if (AddressFlags == 2) {
  2250. PageFrameIndex = (ULONG_PTR) Va;
  2251. IopRemovePageFromPageMap (Summary->BitmapSize,
  2252. BitMap,
  2253. (ULONG) PageFrameIndex,
  2254. (ULONG) Pages
  2255. );
  2256. } else {
  2257. while (Pages) {
  2258. //
  2259. // Only do a translation for valid pages.
  2260. //
  2261. if ( MmIsAddressValid (Va) ) {
  2262. PhyAddr = MmGetPhysicalAddress (Va);
  2263. IopRemovePageFromPageMap (Summary->BitmapSize,
  2264. BitMap,
  2265. (ULONG)(PhyAddr.QuadPart >> PAGE_SHIFT),
  2266. 1);
  2267. }
  2268. Va += PAGE_SIZE;
  2269. Pages--;
  2270. }
  2271. }
  2272. return STATUS_SUCCESS;
  2273. }
  2274. LARGE_INTEGER
  2275. IopCalculateRequiredDumpSpace(
  2276. IN ULONG dwDmpFlags,
  2277. IN ULONG dwHeaderSize,
  2278. IN PFN_NUMBER dwMaxPages,
  2279. IN PFN_NUMBER dwMaxSummaryPages
  2280. )
  2281. /*++
  2282. Routine Description:
  2283. This routine is used to calcuate required dump space
  2284. 1. Crash dump summary must be at least 1 page in length.
  2285. 2. Summary dump must be large enough for kernel memory plus header,
  2286. plus summary header.
  2287. 3. Full dump must be large enough for header plus all physical memory.
  2288. Arguments:
  2289. dwDmpFlags - Dump Control Block (DCB) flags.
  2290. dwHeaderSize - The size of the dump header.
  2291. dwMaxPages - All physical memory.
  2292. dwMaxSummaryPages - Maximum pages in summary dump.
  2293. Return Value:
  2294. Size of the dump file
  2295. --*/
  2296. {
  2297. LARGE_INTEGER maxMemorySize;
  2298. //
  2299. // Dump header or dump summary.
  2300. //
  2301. if ( (dwDmpFlags & DCB_DUMP_HEADER_ENABLED) ||
  2302. ( !( dwDmpFlags & DCB_DUMP_ENABLED ) &&
  2303. ( dwDmpFlags & DCB_SUMMARY_ENABLED ) ) ) {
  2304. maxMemorySize.QuadPart = IO_DUMP_MINIMUM_FILE_SIZE;
  2305. return maxMemorySize;
  2306. }
  2307. if (dwDmpFlags & DCB_TRIAGE_DUMP_ENABLED) {
  2308. maxMemorySize.QuadPart = TRIAGE_DUMP_SIZE;
  2309. return maxMemorySize;
  2310. }
  2311. if (dwDmpFlags & DCB_SUMMARY_DUMP_ENABLED) {
  2312. ULONG dwGB;
  2313. maxMemorySize.QuadPart = (dwMaxSummaryPages) * PAGE_SIZE;
  2314. //
  2315. // If biased then max kernel memory is 1GB otherwise it is 2GB
  2316. //
  2317. dwGB = 1024 * 1024 * 1024;
  2318. if (maxMemorySize.QuadPart > (2 * dwGB) ) {
  2319. if (MmVirtualBias) {
  2320. maxMemorySize.QuadPart = dwGB;
  2321. } else {
  2322. maxMemorySize.QuadPart = (2 * dwGB);
  2323. }
  2324. }
  2325. //
  2326. // Control block header size for summary dump
  2327. // includes space for the base header, the summary
  2328. // header and the page bitmap.
  2329. //
  2330. maxMemorySize.QuadPart += dwHeaderSize;
  2331. return maxMemorySize;
  2332. }
  2333. //
  2334. // Full memory dump is #pages * pagesize plus 1 page for the dump header.
  2335. //
  2336. maxMemorySize.QuadPart = (dwMaxPages * PAGE_SIZE) + dwHeaderSize;
  2337. return maxMemorySize;
  2338. }
  2339. //
  2340. // Triage-dump support routines.
  2341. //
  2342. NTSTATUS
  2343. IopGetLoadedDriverInfo(
  2344. OUT ULONG * lpDriverCount,
  2345. OUT ULONG * lpSizeOfStringData
  2346. )
  2347. /*++
  2348. Routine Description:
  2349. Get information about all loaded drivers.
  2350. Arguments:
  2351. lpDriverCount - Buffer to return the count of all the drivers that are
  2352. currently loaded in the system.
  2353. lpSizeOfStringData - Buffer to return the sum of the sizes of all driver
  2354. name strings (FullDllName). This does not include the size
  2355. of the UNICODE_STRING structure or a trailing NULL byte.
  2356. Return Values:
  2357. NTSTATUS
  2358. --*/
  2359. {
  2360. ULONG DriverCount = 0;
  2361. ULONG SizeOfStringData = 0;
  2362. PLIST_ENTRY NextEntry;
  2363. PKLDR_DATA_TABLE_ENTRY DriverEntry;
  2364. NextEntry = PsLoadedModuleList.Flink;
  2365. while (NextEntry != &PsLoadedModuleList) {
  2366. DriverEntry = CONTAINING_RECORD (NextEntry,
  2367. KLDR_DATA_TABLE_ENTRY,
  2368. InLoadOrderLinks
  2369. );
  2370. if (!IopIsAddressRangeValid (DriverEntry, sizeof (*DriverEntry)) ||
  2371. !IopIsAddressRangeValid (DriverEntry->BaseDllName.Buffer,
  2372. DriverEntry->BaseDllName.Length)) {
  2373. return STATUS_UNSUCCESSFUL;
  2374. }
  2375. DriverCount++;
  2376. //
  2377. // The extra two bytes is for the NULL termination. The extra 7 is
  2378. // because we force 8-byte alignment of all strings.
  2379. //
  2380. SizeOfStringData += DriverEntry->BaseDllName.Length + 2 + 7;
  2381. NextEntry = NextEntry->Flink;
  2382. }
  2383. *lpDriverCount = DriverCount;
  2384. *lpSizeOfStringData = SizeOfStringData;
  2385. return STATUS_SUCCESS;
  2386. }
  2387. #define DmpPoolStringSize(DumpString)\
  2388. (sizeof (DUMP_STRING) + sizeof (WCHAR) * ( DumpString->Length + 1 ))
  2389. #define DmpNextPoolString(DumpString) \
  2390. (PDUMP_STRING) ( \
  2391. ALIGN_UP_POINTER( \
  2392. ((LPBYTE) DumpString) + DmpPoolStringSize (DumpString), \
  2393. ULONGLONG \
  2394. ) \
  2395. )
  2396. #define ALIGN_8(_x) ALIGN_UP(_x, DWORDLONG)
  2397. #define ASSERT_ALIGNMENT(Pointer, Alignment)\
  2398. ASSERT ((((ULONG_PTR)Pointer) & ((Alignment) - 1)) == 0)
  2399. #ifndef IndexByByte
  2400. #define IndexByByte(Pointer, Index) (&(((BYTE*) (Pointer)) [Index]))
  2401. #endif
  2402. NTSTATUS
  2403. IopWriteDriverList(
  2404. IN ULONG_PTR BufferAddress,
  2405. IN ULONG BufferSize,
  2406. IN ULONG DriverListOffset,
  2407. IN ULONG StringPoolOffset
  2408. )
  2409. /*++
  2410. Routine Description:
  2411. Write the triage dump driver list to the buffer.
  2412. Arguments:
  2413. BufferAddress - The address of the buffer.
  2414. BufferSize - The size of the buffer.
  2415. DriverListOffset - The offset within the buffer where the driver list
  2416. should be written.
  2417. StringPoolOffset - The offset within the buffer where the driver list's
  2418. string pool should start. If there are no other strings for the triage
  2419. dump other than driver name strings, this will be the string pool
  2420. offset.
  2421. Return Value:
  2422. NTSTATUS
  2423. --*/
  2424. {
  2425. ULONG i = 0;
  2426. PLIST_ENTRY NextEntry;
  2427. PKLDR_DATA_TABLE_ENTRY DriverEntry;
  2428. PDUMP_DRIVER_ENTRY DumpImageArray;
  2429. PDUMP_STRING DumpStringName = NULL;
  2430. PIMAGE_NT_HEADERS NtHeaders;
  2431. ASSERT (DriverListOffset != 0);
  2432. ASSERT (StringPoolOffset != 0);
  2433. UNREFERENCED_PARAMETER (BufferSize);
  2434. DumpImageArray = (PDUMP_DRIVER_ENTRY) (BufferAddress + DriverListOffset);
  2435. DumpStringName = (PDUMP_STRING) (BufferAddress + StringPoolOffset);
  2436. NextEntry = PsLoadedModuleList.Flink;
  2437. while (NextEntry != &PsLoadedModuleList) {
  2438. DriverEntry = CONTAINING_RECORD (NextEntry,
  2439. KLDR_DATA_TABLE_ENTRY,
  2440. InLoadOrderLinks);
  2441. //
  2442. // Verify the memory is valid before reading anything from it.
  2443. //
  2444. if (!IopIsAddressRangeValid (DriverEntry, sizeof (*DriverEntry)) ||
  2445. !IopIsAddressRangeValid (DriverEntry->BaseDllName.Buffer,
  2446. DriverEntry->BaseDllName.Length)) {
  2447. return STATUS_UNSUCCESSFUL;
  2448. }
  2449. //
  2450. // Build the entry in the string pool. We guarantee all strings are
  2451. // NULL terminated as well as length prefixed.
  2452. //
  2453. DumpStringName->Length = DriverEntry->BaseDllName.Length / 2;
  2454. RtlCopyMemory (DumpStringName->Buffer,
  2455. DriverEntry->BaseDllName.Buffer,
  2456. DumpStringName->Length * sizeof (WCHAR)
  2457. );
  2458. DumpStringName->Buffer[ DumpStringName->Length ] = '\000';
  2459. RtlCopyMemory (&DumpImageArray [i].LdrEntry,
  2460. DriverEntry,
  2461. sizeof (DumpImageArray [i].LdrEntry)
  2462. );
  2463. //
  2464. // Add the time/date stamp.
  2465. //
  2466. DumpImageArray[i].LdrEntry.TimeDateStamp = 0;
  2467. DumpImageArray[i].LdrEntry.SizeOfImage = 0;
  2468. if ( MmIsAddressValid (DriverEntry->DllBase ) ) {
  2469. NtHeaders = RtlImageNtHeader (DriverEntry->DllBase);
  2470. ASSERT ( NtHeaders );
  2471. DumpImageArray[i].LdrEntry.TimeDateStamp =
  2472. NtHeaders->FileHeader.TimeDateStamp;
  2473. DumpImageArray[i].LdrEntry.SizeOfImage =
  2474. NtHeaders->OptionalHeader.SizeOfImage;
  2475. } else if (DriverEntry->Flags & LDRP_NON_PAGED_DEBUG_INFO) {
  2476. DumpImageArray[i].LdrEntry.TimeDateStamp =
  2477. DriverEntry->NonPagedDebugInfo->TimeDateStamp;
  2478. DumpImageArray[i].LdrEntry.SizeOfImage =
  2479. DriverEntry->NonPagedDebugInfo->SizeOfImage;
  2480. }
  2481. DumpImageArray [i].DriverNameOffset =
  2482. (ULONG)((ULONG_PTR) DumpStringName - BufferAddress);
  2483. i++;
  2484. DumpStringName = DmpNextPoolString (DumpStringName);
  2485. NextEntry = NextEntry->Flink;
  2486. }
  2487. return STATUS_SUCCESS;
  2488. }
  2489. ULONG
  2490. IopSizeTriageDumpDataBlocks(
  2491. PTRIAGE_DUMP TriageDump,
  2492. ULONG Offset,
  2493. ULONG BufferSize
  2494. )
  2495. /*++
  2496. Routine Description:
  2497. Determine all triage dump data blocks that fit and
  2498. update dump header to match.
  2499. Arguments:
  2500. TriageDump - Dump header.
  2501. Offset - Current offset in dump buffer.
  2502. BufferSize - Dump buffer size.
  2503. Return Values:
  2504. Updated offset.
  2505. --*/
  2506. {
  2507. ULONG i;
  2508. ULONG Size;
  2509. PTRIAGE_PTR_DATA_BLOCK Block;
  2510. TriageDump->DataBlocksCount = 0;
  2511. Block = IopTriageDumpDataBlocks;
  2512. for (i = 0; i < IopNumTriageDumpDataBlocks; i++, Block++) {
  2513. Size = ALIGN_8(sizeof(TRIAGE_DATA_BLOCK)) +
  2514. ALIGN_8((ULONG)(Block->MaxAddress - Block->MinAddress));
  2515. if (Offset + Size >= BufferSize) {
  2516. TriageDump->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  2517. break;
  2518. }
  2519. if (i == 0) {
  2520. TriageDump->DataBlocksOffset = Offset;
  2521. }
  2522. Offset += Size;
  2523. TriageDump->DataBlocksCount++;
  2524. }
  2525. return Offset;
  2526. }
  2527. VOID
  2528. IopWriteTriageDumpDataBlocks(
  2529. PTRIAGE_DUMP TriageDump,
  2530. PUCHAR BufferAddress
  2531. )
  2532. /*++
  2533. Routine Description:
  2534. Write triage dump data blocks given in header.
  2535. Arguments:
  2536. TriageDump - Dump header.
  2537. BufferAddress - Address of dump data buffer.
  2538. Return Values:
  2539. None.
  2540. --*/
  2541. {
  2542. ULONG i;
  2543. PTRIAGE_PTR_DATA_BLOCK Block;
  2544. PUCHAR DataBuffer;
  2545. PTRIAGE_DATA_BLOCK DumpBlock;
  2546. DumpBlock = (PTRIAGE_DATA_BLOCK)
  2547. (BufferAddress + TriageDump->DataBlocksOffset);
  2548. DataBuffer = (PUCHAR)(DumpBlock + TriageDump->DataBlocksCount);
  2549. Block = IopTriageDumpDataBlocks;
  2550. for (i = 0; i < TriageDump->DataBlocksCount; i++, Block++) {
  2551. DumpBlock->Address = (ULONG64)(LONG_PTR)Block->MinAddress;
  2552. DumpBlock->Offset = (ULONG)(DataBuffer - BufferAddress);
  2553. DumpBlock->Size = (ULONG)(Block->MaxAddress - Block->MinAddress);
  2554. RtlCopyMemory(DataBuffer, Block->MinAddress, DumpBlock->Size);
  2555. DataBuffer += DumpBlock->Size;
  2556. DumpBlock++;
  2557. }
  2558. }
  2559. NTSTATUS
  2560. IopWriteTriageDump(
  2561. IN ULONG Fields,
  2562. IN PDUMP_DRIVER_WRITE DriverWriteRoutine,
  2563. IN OUT PLARGE_INTEGER * Mcb,
  2564. IN OUT PMDL Mdl,
  2565. IN ULONG DriverTransferSize,
  2566. IN PCONTEXT Context,
  2567. IN PKTHREAD Thread,
  2568. IN BYTE* Buffer,
  2569. IN ULONG BufferSize,
  2570. IN ULONG ServicePackBuild,
  2571. IN ULONG TriageOptions
  2572. )
  2573. /*++
  2574. Routine Description:
  2575. Write the Triage-Dump to the MCB.
  2576. Arguments:
  2577. Fields - The set of fields that should be written.
  2578. DriverWriteRoutine - The write routine for the driver.
  2579. Mcb - Message Control Block where the data is to be written.
  2580. Mdl - A MDL descrbing the data to be written (??).
  2581. DriverTransferSize - The maximum transfer size for the driver.
  2582. Context - The context.
  2583. Buffer - The buffer to use as a scratch buffer.
  2584. BufferSize - The size of the buffer.
  2585. ServicePackBuild - Service Pack BuildNumber.
  2586. TriageOptions - Triage Options.
  2587. Return Values:
  2588. STATUS_SUCCESS - On success.
  2589. NTSTATUS - Otherwise.
  2590. Comments:
  2591. This function assumes that exactly one header page was written.
  2592. --*/
  2593. {
  2594. ULONG SizeOfSection;
  2595. ULONG SizeOfStringData;
  2596. ULONG DriverCount = 0;
  2597. LPVOID Address = NULL;
  2598. ULONG BytesToWrite = 0;
  2599. ULONG_PTR BufferAddress = 0;
  2600. NTSTATUS Status;
  2601. ULONG Offset;
  2602. PTRIAGE_DUMP TriageDump = NULL;
  2603. //
  2604. // Setup the triage-dump header.
  2605. //
  2606. if (BufferSize < sizeof (TRIAGE_DUMP) + sizeof (DWORD)) {
  2607. return STATUS_NO_MEMORY;
  2608. }
  2609. TriageDump = (PTRIAGE_DUMP) Buffer;
  2610. RtlZeroMemory (TriageDump, sizeof (*TriageDump));
  2611. //
  2612. // The normal dump header is a DUMP_HEADER.
  2613. //
  2614. TriageDump->SizeOfDump = BufferSize + sizeof(DUMP_HEADER);
  2615. //
  2616. // Adjust the BufferSize so we can write the final status DWORD at the
  2617. // end.
  2618. //
  2619. BufferSize -= sizeof (DWORD);
  2620. RtlZeroMemory (IndexByByte (Buffer, BufferSize), sizeof (DWORD));
  2621. TriageDump->ValidOffset = ( TriageDump->SizeOfDump - sizeof (ULONG) );
  2622. TriageDump->ContextOffset = FIELD_OFFSET (DUMP_HEADER, ContextRecord);
  2623. TriageDump->ExceptionOffset = FIELD_OFFSET (DUMP_HEADER, Exception);
  2624. TriageDump->BrokenDriverOffset = 0;
  2625. TriageDump->ServicePackBuild = ServicePackBuild;
  2626. TriageDump->TriageOptions = TriageOptions;
  2627. Offset = ALIGN_8 (sizeof(DUMP_HEADER) + sizeof (TRIAGE_DUMP));
  2628. ASSERT_ALIGNMENT (Offset, 8);
  2629. //
  2630. // Set the Mm Offset, if necessary.
  2631. //
  2632. SizeOfSection = ALIGN_8 (MmSizeOfTriageInformation());
  2633. if (Offset + SizeOfSection < BufferSize) {
  2634. TriageDump->MmOffset = Offset;
  2635. Offset += SizeOfSection;
  2636. } else {
  2637. TriageDump->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  2638. }
  2639. ASSERT_ALIGNMENT (Offset, 8);
  2640. //
  2641. // Set the Unloaded Drivers Offset, if necessary.
  2642. //
  2643. SizeOfSection = ALIGN_8 (MmSizeOfUnloadedDriverInformation());
  2644. if (Offset + SizeOfSection < BufferSize) {
  2645. TriageDump->UnloadedDriversOffset = Offset;
  2646. Offset += SizeOfSection;
  2647. } else {
  2648. TriageDump->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  2649. }
  2650. ASSERT_ALIGNMENT (Offset, 8);
  2651. //
  2652. // Set the Prcb Offset, if necessary.
  2653. //
  2654. if (Fields & TRIAGE_DUMP_PRCB) {
  2655. SizeOfSection = ALIGN_8 (sizeof (KPRCB));
  2656. if (Offset + SizeOfSection < BufferSize) {
  2657. TriageDump->PrcbOffset = Offset;
  2658. Offset += SizeOfSection;
  2659. } else {
  2660. TriageDump->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  2661. }
  2662. }
  2663. ASSERT_ALIGNMENT (Offset, 8);
  2664. //
  2665. // Set the Process Offset, if necessary.
  2666. //
  2667. if (Fields & TRIAGE_DUMP_PROCESS) {
  2668. SizeOfSection = ALIGN_8 (sizeof (EPROCESS));
  2669. if (Offset + SizeOfSection < BufferSize) {
  2670. TriageDump->ProcessOffset = Offset;
  2671. Offset += SizeOfSection;
  2672. } else {
  2673. TriageDump->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  2674. }
  2675. }
  2676. ASSERT_ALIGNMENT (Offset, 8);
  2677. //
  2678. // Set the Thread Offset, if necessary.
  2679. //
  2680. if (Fields & TRIAGE_DUMP_THREAD) {
  2681. SizeOfSection = ALIGN_8 (sizeof (ETHREAD));
  2682. if (Offset + SizeOfSection < BufferSize) {
  2683. TriageDump->ThreadOffset = Offset;
  2684. Offset += SizeOfSection;
  2685. } else {
  2686. TriageDump->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  2687. }
  2688. }
  2689. ASSERT_ALIGNMENT (Offset, 8);
  2690. //
  2691. // Set the CallStack Offset, if necessary.
  2692. //
  2693. if (Fields & TRIAGE_DUMP_STACK) {
  2694. //
  2695. // If there is a stack, calculate its size.
  2696. //
  2697. //
  2698. // Remember: the callstack grows downward in memory, therefore,
  2699. // Base >= Current = SP = Top > Limit.
  2700. //
  2701. if (Thread->KernelStackResident) {
  2702. ULONG_PTR StackBase;
  2703. ULONG_PTR StackLimit;
  2704. ULONG_PTR StackTop;
  2705. StackBase = (ULONG_PTR) Thread->StackBase;
  2706. StackLimit = (ULONG_PTR) Thread->StackLimit;
  2707. //
  2708. // Don't necessarily trust that SP is valid. If it's
  2709. // outside the reasonable range, just copy from the limit.
  2710. //
  2711. if (StackLimit < STACK_POINTER (Context) &&
  2712. STACK_POINTER (Context) <= StackBase) {
  2713. StackTop = STACK_POINTER (Context);
  2714. } else {
  2715. StackTop = (ULONG_PTR) Thread->StackLimit;
  2716. }
  2717. ASSERT (StackLimit <= StackTop && StackTop < StackBase);
  2718. //
  2719. // There is a valid stack. Note that we limit the size of
  2720. // the triage dump stack to MAX_TRIAGE_STACK_SIZE (currently
  2721. // 16 KB).
  2722. //
  2723. SizeOfSection = (ULONG) min (StackBase - StackTop,
  2724. MAX_TRIAGE_STACK_SIZE - 1);
  2725. if (SizeOfSection) {
  2726. if (Offset + SizeOfSection < BufferSize) {
  2727. TriageDump->CallStackOffset = Offset;
  2728. TriageDump->SizeOfCallStack = SizeOfSection;
  2729. TriageDump->TopOfStack = StackTop;
  2730. Offset += SizeOfSection;
  2731. Offset = ALIGN_8 (Offset);
  2732. } else {
  2733. TriageDump->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  2734. }
  2735. }
  2736. } else {
  2737. //
  2738. // There is not a valid stack.
  2739. //
  2740. }
  2741. }
  2742. ASSERT_ALIGNMENT (Offset, 8);
  2743. #if defined (_IA64_)
  2744. //
  2745. // The IA64 contains two callstacks. The first is the normal
  2746. // callstack, and the second is a scratch region where
  2747. // the processor can spill registers. It is this latter stack,
  2748. // the backing-store, that we now save.
  2749. //
  2750. if ( Fields & TRIAGE_DUMP_STACK ) {
  2751. ULONG_PTR BStoreBase;
  2752. ULONG_PTR BStoreLimit;
  2753. BStoreBase = (ULONG_PTR) Thread->InitialBStore;
  2754. BStoreLimit = (ULONG_PTR) Thread->BStoreLimit;
  2755. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  2756. CRASHDUMP_TRACE,
  2757. "CRASHDUMP: IA64 BStore: base %p limit %p\n",
  2758. BStoreBase,
  2759. BStoreLimit));
  2760. SizeOfSection = (ULONG) (BStoreLimit - BStoreBase);
  2761. //
  2762. // The calculated size had better be less than the maximum size
  2763. // for a BSTORE region.
  2764. //
  2765. ASSERT ( SizeOfSection < KERNEL_LARGE_BSTORE_SIZE );
  2766. if (SizeOfSection) {
  2767. if (Offset + SizeOfSection < BufferSize) {
  2768. TriageDump->ArchitectureSpecific.Ia64.BStoreOffset = Offset;
  2769. TriageDump->ArchitectureSpecific.Ia64.SizeOfBStore = SizeOfSection;
  2770. TriageDump->ArchitectureSpecific.Ia64.LimitOfBStore= BStoreLimit;
  2771. Offset += SizeOfSection;
  2772. Offset = ALIGN_8 (Offset);
  2773. } else {
  2774. TriageDump->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  2775. }
  2776. }
  2777. }
  2778. #endif
  2779. ASSERT_ALIGNMENT (Offset, 8);
  2780. if (Fields & TRIAGE_DUMP_DEBUGGER_DATA) {
  2781. if (Offset + ALIGN_8(sizeof(KdDebuggerDataBlock)) < BufferSize) {
  2782. TriageDump->DebuggerDataOffset = Offset;
  2783. TriageDump->DebuggerDataSize = sizeof(KdDebuggerDataBlock);
  2784. Offset += ALIGN_8(sizeof(KdDebuggerDataBlock));
  2785. Offset = ALIGN_8 (Offset);
  2786. } else {
  2787. TriageDump->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  2788. }
  2789. }
  2790. ASSERT_ALIGNMENT (Offset, 8);
  2791. //
  2792. // Set the Driver List Offset, if necessary.
  2793. //
  2794. Status = IopGetLoadedDriverInfo (&DriverCount, &SizeOfStringData);
  2795. if (NT_SUCCESS (Status) && (Fields & TRIAGE_DUMP_DRIVER_LIST)) {
  2796. SizeOfSection = ALIGN_8 (DriverCount * sizeof (DUMP_DRIVER_ENTRY));
  2797. if (SizeOfSection) {
  2798. if (Offset + SizeOfSection < BufferSize) {
  2799. TriageDump->DriverListOffset = Offset;
  2800. TriageDump->DriverCount = DriverCount;
  2801. Offset += SizeOfSection;
  2802. } else {
  2803. TriageDump->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  2804. }
  2805. }
  2806. } else {
  2807. SizeOfSection = 0;
  2808. SizeOfStringData = 0;
  2809. }
  2810. //
  2811. // Set the String Pool offset.
  2812. //
  2813. SizeOfSection = ALIGN_8 (SizeOfStringData +
  2814. DriverCount * (sizeof (WCHAR) + sizeof (DUMP_STRING)));
  2815. if (SizeOfSection) {
  2816. if (Offset + SizeOfSection < BufferSize) {
  2817. TriageDump->StringPoolOffset = (ULONG)Offset;
  2818. TriageDump->StringPoolSize = SizeOfSection;
  2819. Offset += SizeOfSection;
  2820. Offset = ALIGN_8 (Offset);
  2821. } else {
  2822. TriageDump->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  2823. }
  2824. }
  2825. ASSERT_ALIGNMENT (Offset, 8);
  2826. if (Fields & TRIAGE_DUMP_DATA_BLOCKS) {
  2827. #ifdef _IA64_
  2828. volatile KPCR* const Pcr = KeGetPcr();
  2829. //
  2830. // In certain failures there is a switch from
  2831. // the current thread's stack and store to
  2832. // a special stack and store. The PCR contains
  2833. // stack and store pointers which will be different
  2834. // from the current thread's stack and store pointers
  2835. // so save the extra stack and store if they are.
  2836. //
  2837. if ((PVOID)Pcr->InitialBStore != Thread->InitialBStore ||
  2838. (PVOID)Pcr->BStoreLimit != Thread->BStoreLimit) {
  2839. ULONG64 StoreTop, StoreBase;
  2840. ULONG FrameSize;
  2841. ULONG StoreSize;
  2842. StoreTop = Context->RsBSP;
  2843. StoreBase = Pcr->InitialBStore;
  2844. FrameSize = (ULONG)(Context->StIFS & PFS_SIZE_MASK);
  2845. // Add in a ULONG64 for every register in the
  2846. // current frame. While doing so, check for
  2847. // spill entries.
  2848. while (FrameSize-- > 0) {
  2849. StoreTop += sizeof(ULONG64);
  2850. if ((StoreTop & 0x1f8) == 0x1f8) {
  2851. // Spill will be placed at this address so
  2852. // account for it.
  2853. StoreTop += sizeof(ULONG64);
  2854. }
  2855. }
  2856. if (StoreTop < Pcr->InitialBStore ||
  2857. StoreTop >= Pcr->BStoreLimit) {
  2858. // BSP isn't in the PCR store range so
  2859. // just save the whole thing.
  2860. StoreTop = Pcr->BStoreLimit;
  2861. }
  2862. StoreSize = (ULONG)(StoreTop - Pcr->InitialBStore);
  2863. if (StoreSize > MAX_TRIAGE_STACK_SIZE) {
  2864. StoreSize = MAX_TRIAGE_STACK_SIZE;
  2865. StoreBase = StoreTop - StoreSize;
  2866. }
  2867. IoAddTriageDumpDataBlock((PVOID)StoreBase, StoreSize);
  2868. }
  2869. if ((PVOID)Pcr->InitialStack != Thread->InitialStack ||
  2870. (PVOID)Pcr->StackLimit != Thread->StackLimit) {
  2871. ULONG64 StackTop;
  2872. ULONG StackSize;
  2873. StackTop = STACK_POINTER(Context);
  2874. if (StackTop < Pcr->StackLimit ||
  2875. StackTop >= Pcr->InitialStack) {
  2876. // SP isn't in the PCR stack range so
  2877. // just save the whole thing.
  2878. StackTop = Pcr->StackLimit;
  2879. }
  2880. StackSize = (ULONG)(Pcr->InitialStack - StackTop);
  2881. if (StackSize > MAX_TRIAGE_STACK_SIZE) {
  2882. StackSize = MAX_TRIAGE_STACK_SIZE;
  2883. }
  2884. IoAddTriageDumpDataBlock((PVOID)StackTop, StackSize);
  2885. }
  2886. #endif
  2887. // Add data blocks which might be referred to by
  2888. // the context or other runtime state.
  2889. IopAddRunTimeTriageDataBlocks(Context,
  2890. (PVOID*)TriageDump->TopOfStack,
  2891. (PVOID*)((PUCHAR)TriageDump->TopOfStack +
  2892. TriageDump->SizeOfCallStack),
  2893. #ifdef _IA64_
  2894. (PVOID*)Thread->InitialBStore,
  2895. (PVOID*)((PUCHAR)Thread->InitialBStore +
  2896. TriageDump->ArchitectureSpecific.Ia64.SizeOfBStore)
  2897. #else
  2898. NULL, NULL
  2899. #endif
  2900. );
  2901. // Check which data blocks fit.
  2902. Offset = IopSizeTriageDumpDataBlocks(TriageDump, Offset, BufferSize);
  2903. Offset = ALIGN_8 (Offset);
  2904. }
  2905. ASSERT_ALIGNMENT (Offset, 8);
  2906. BytesToWrite = (ULONG)Offset;
  2907. BufferAddress = ((ULONG_PTR) Buffer) - sizeof(DUMP_HEADER);
  2908. //
  2909. // Write the Mm information.
  2910. //
  2911. if (TriageDump->MmOffset) {
  2912. Address = (LPVOID) (BufferAddress + TriageDump->MmOffset);
  2913. MmWriteTriageInformation (Address);
  2914. }
  2915. if (TriageDump->UnloadedDriversOffset) {
  2916. Address = (LPVOID) (BufferAddress + TriageDump->UnloadedDriversOffset);
  2917. MmWriteUnloadedDriverInformation (Address);
  2918. }
  2919. //
  2920. // Write the PRCB.
  2921. //
  2922. if (TriageDump->PrcbOffset) {
  2923. Address = (LPVOID) (BufferAddress + TriageDump->PrcbOffset);
  2924. RtlCopyMemory (Address,
  2925. KeGetCurrentPrcb (),
  2926. sizeof (KPRCB)
  2927. );
  2928. }
  2929. //
  2930. // Write the EPROCESS.
  2931. //
  2932. if (TriageDump->ProcessOffset) {
  2933. Address = (LPVOID) (BufferAddress + TriageDump->ProcessOffset);
  2934. RtlCopyMemory (Address,
  2935. Thread->ApcState.Process,
  2936. sizeof (EPROCESS)
  2937. );
  2938. }
  2939. //
  2940. // Write the ETHREAD.
  2941. //
  2942. if (TriageDump->ThreadOffset) {
  2943. Address = (LPVOID) (BufferAddress + TriageDump->ThreadOffset);
  2944. RtlCopyMemory (Address,
  2945. Thread,
  2946. sizeof (ETHREAD));
  2947. }
  2948. //
  2949. // Write the Call Stack.
  2950. //
  2951. if (TriageDump->CallStackOffset) {
  2952. PVOID StackTop;
  2953. ASSERT (TriageDump->SizeOfCallStack != 0);
  2954. StackTop = (PVOID)TriageDump->TopOfStack;
  2955. ASSERT (IopIsAddressRangeValid (StackTop, TriageDump->SizeOfCallStack));
  2956. Address = (LPVOID) (BufferAddress + TriageDump->CallStackOffset);
  2957. RtlCopyMemory (Address,
  2958. StackTop,
  2959. TriageDump->SizeOfCallStack
  2960. );
  2961. }
  2962. #if defined (_IA64_)
  2963. //
  2964. // Write the IA64 BStore.
  2965. //
  2966. if ( TriageDump->ArchitectureSpecific.Ia64.BStoreOffset ) {
  2967. ASSERT (IopIsAddressRangeValid (Thread->InitialBStore,
  2968. TriageDump->ArchitectureSpecific.Ia64.SizeOfBStore));
  2969. Address = (PVOID) (BufferAddress + TriageDump->ArchitectureSpecific.Ia64.BStoreOffset);
  2970. RtlCopyMemory (Address,
  2971. Thread->InitialBStore,
  2972. TriageDump->ArchitectureSpecific.Ia64.SizeOfBStore
  2973. );
  2974. }
  2975. #endif // IA64
  2976. //
  2977. // Write the debugger data block.
  2978. //
  2979. if (TriageDump->DebuggerDataOffset) {
  2980. Address = (LPVOID) (BufferAddress + TriageDump->DebuggerDataOffset);
  2981. RtlCopyMemory (Address,
  2982. &KdDebuggerDataBlock,
  2983. sizeof(KdDebuggerDataBlock)
  2984. );
  2985. }
  2986. //
  2987. // Write the Driver List.
  2988. //
  2989. if (TriageDump->DriverListOffset &&
  2990. TriageDump->StringPoolOffset) {
  2991. Status = IopWriteDriverList (BufferAddress,
  2992. BufferSize,
  2993. TriageDump->DriverListOffset,
  2994. TriageDump->StringPoolOffset
  2995. );
  2996. if (!NT_SUCCESS (Status)) {
  2997. TriageDump->DriverListOffset = 0;
  2998. }
  2999. }
  3000. //
  3001. // Write the data blocks.
  3002. //
  3003. IopWriteTriageDumpDataBlocks(TriageDump, (PUCHAR)BufferAddress);
  3004. ASSERT (BytesToWrite < BufferSize);
  3005. ASSERT (ALIGN_UP (BytesToWrite, PAGE_SIZE) < BufferSize);
  3006. //
  3007. // Write the valid status to the end of the dump.
  3008. //
  3009. *((ULONG *)IndexByByte (Buffer, BufferSize)) = TRIAGE_DUMP_VALID ;
  3010. //
  3011. // Re-adjust the buffer size.
  3012. //
  3013. BufferSize += sizeof (DWORD);
  3014. //
  3015. // NOTE: This routine writes the entire buffer, even if it is not
  3016. // all required.
  3017. //
  3018. Status = IopWriteToDisk (Buffer,
  3019. BufferSize,
  3020. DriverWriteRoutine,
  3021. Mcb,
  3022. Mdl,
  3023. DriverTransferSize,
  3024. KbDumpIoBody
  3025. );
  3026. return Status;
  3027. }
  3028. NTSTATUS
  3029. IopWritePageToDisk(
  3030. IN PDUMP_DRIVER_WRITE DriverWrite,
  3031. IN OUT PLARGE_INTEGER * McbBuffer,
  3032. IN OUT ULONG DriverTransferSize,
  3033. IN PFN_NUMBER PageFrameIndex
  3034. )
  3035. /*++
  3036. Routine Description:
  3037. Write the page described by PageFrameIndex to the disk/file (DriverWrite,
  3038. McbBuffer) and update the MCB buffer to reflect the new position in the
  3039. file.
  3040. Arguments:
  3041. DriverWrite - The driver write routine.
  3042. McbBuffer - A pointer to the MCB array. This array is terminated by
  3043. a zero-length MCB entry. On success, this pointer is updated
  3044. to reflect the new position in the MCB array.
  3045. NB: MCB[0] is the size and MCB[1] is the offset.
  3046. DriverTransferSize - The maximum transfer size for this driver.
  3047. PageFrameIndex - The page to be written.
  3048. Return Values:
  3049. NTSTATUS code.
  3050. --*/
  3051. {
  3052. NTSTATUS Status = STATUS_SUCCESS;
  3053. PFN_NUMBER MdlHack [ (sizeof (MDL) / sizeof (PFN_NUMBER)) + 1];
  3054. PPFN_NUMBER PfnArray;
  3055. PLARGE_INTEGER Mcb;
  3056. ULONG ByteCount;
  3057. ULONG ByteOffset;
  3058. ULONG BytesToWrite;
  3059. PMDL TempMdl;
  3060. ASSERT ( DriverWrite );
  3061. ASSERT ( McbBuffer );
  3062. ASSERT ( DriverTransferSize && DriverTransferSize >= PAGE_SIZE );
  3063. KdCheckForDebugBreak();
  3064. //
  3065. // Initialization
  3066. //
  3067. TempMdl = (PMDL) &MdlHack[0];
  3068. Mcb = *McbBuffer;
  3069. BytesToWrite = PAGE_SIZE;
  3070. //
  3071. // Initialze the MDL to point to this page.
  3072. //
  3073. MmInitializeMdl (TempMdl, NULL, PAGE_SIZE);
  3074. // TempMdl->StartVa = (PVOID) (PageFrameIndex << PAGE_SHIFT);
  3075. PfnArray = MmGetMdlPfnArray ( TempMdl );
  3076. PfnArray[0] = PageFrameIndex;
  3077. //
  3078. // We loop for the cases when the space remaining in this block (Mcb [0])
  3079. // is less than one page. Generally the Mcb will be large enough to hold
  3080. // the entire page and this loop will only be executed once. When Mcb[0]
  3081. // is less than a page, we will write the first part of the page to this
  3082. // Mcb then increment the Mcb and write the remaining part to the next
  3083. // page.
  3084. //
  3085. ByteOffset = 0;
  3086. while ( BytesToWrite ) {
  3087. ASSERT ( Mcb[0].QuadPart != 0 );
  3088. ByteCount = (ULONG) min3 ((LONGLONG) BytesToWrite,
  3089. (LONGLONG) DriverTransferSize,
  3090. Mcb[0].QuadPart
  3091. );
  3092. ASSERT ( ByteCount != 0 );
  3093. //
  3094. // Update the MDL byte count and byte offset.
  3095. //
  3096. TempMdl->ByteCount = ByteCount;
  3097. TempMdl->ByteOffset = ByteOffset;
  3098. //
  3099. // Map the MDL. The flags are updated to show that MappedSystemVa
  3100. // is valid (which should probably be done in MmMapMemoryDumpMdl).
  3101. //
  3102. MmMapMemoryDumpMdl ( TempMdl );
  3103. TempMdl->MdlFlags |= ( MDL_PAGES_LOCKED | MDL_MAPPED_TO_SYSTEM_VA );
  3104. TempMdl->StartVa = PAGE_ALIGN (TempMdl->MappedSystemVa);
  3105. IopInvokeDumpIoCallbacks((PUCHAR)TempMdl->StartVa + ByteOffset,
  3106. ByteCount, KbDumpIoBody);
  3107. //
  3108. // Write the bufffer.
  3109. //
  3110. Status = DriverWrite ( &Mcb[1], TempMdl );
  3111. if (!NT_SUCCESS (Status)) {
  3112. return Status;
  3113. }
  3114. BytesToWrite -= ByteCount;
  3115. ByteOffset += ByteCount;
  3116. Mcb[0].QuadPart -= ByteCount;
  3117. Mcb[1].QuadPart += ByteCount;
  3118. //
  3119. // If there is no more room for this MCB, go to the next one.
  3120. //
  3121. if ( Mcb[0].QuadPart == 0 ) {
  3122. Mcb += 2;
  3123. //
  3124. // We have filled up all the space in the paging file.
  3125. //
  3126. if ( Mcb[0].QuadPart == 0) {
  3127. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  3128. CRASHDUMP_ERROR,
  3129. "CRASHDUMP: Pagefile is full.\n"));
  3130. return STATUS_END_OF_FILE;
  3131. }
  3132. }
  3133. }
  3134. *McbBuffer = Mcb;
  3135. return Status;
  3136. }
  3137. NTSTATUS
  3138. IopWriteSummaryDump(
  3139. IN PRTL_BITMAP PageMap,
  3140. IN PDUMP_DRIVER_WRITE DriverWriteRoutine,
  3141. IN PANSI_STRING ProgressMessage,
  3142. IN PUCHAR MessageBuffer,
  3143. IN OUT PLARGE_INTEGER * Mcb,
  3144. IN OUT ULONG DriverTransferSize
  3145. )
  3146. /*++
  3147. Routine Description:
  3148. Write a summary dump to the disk.
  3149. Arguments:
  3150. PageMap - A bitmap of the pages that need to be written.
  3151. DriverWriteRoutine - The driver's write routine.
  3152. ProgressMessage - The "Percent Complete" message.
  3153. MessageBuffer - Not used. Must be NULL.
  3154. Mcb - Message Control Block where the data is to be written.
  3155. DriverTransferSize - The maximum transfer size for the driver.
  3156. Return Values:
  3157. NTSTATUS code.
  3158. --*/
  3159. {
  3160. PFN_NUMBER PageFrameIndex;
  3161. NTSTATUS Status;
  3162. ULONG WriteCount;
  3163. ULONG MaxWriteCount;
  3164. ULONG Step;
  3165. #if !DBG
  3166. UNREFERENCED_PARAMETER (MessageBuffer);
  3167. #endif
  3168. ASSERT ( DriverWriteRoutine != NULL );
  3169. ASSERT ( Mcb != NULL );
  3170. ASSERT ( DriverTransferSize != 0 );
  3171. ASSERT ( MessageBuffer == NULL );
  3172. MaxWriteCount = RtlNumberOfSetBits ( PageMap );
  3173. ASSERT (MaxWriteCount != 0);
  3174. Step = MaxWriteCount / 100;
  3175. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  3176. CRASHDUMP_TRACE,
  3177. "CRASHDUMP: Summary Dump\n"
  3178. " Writing %x pages to disk from a total of %x\n",
  3179. MaxWriteCount,
  3180. PageMap->SizeOfBitMap
  3181. ));
  3182. //
  3183. // Loop over all pages in the system and write those that are set
  3184. // in the bitmap.
  3185. //
  3186. WriteCount = 0;
  3187. for ( PageFrameIndex = 0;
  3188. PageFrameIndex < PageMap->SizeOfBitMap;
  3189. PageFrameIndex++) {
  3190. //
  3191. // If this page needs to be included in the dump file.
  3192. //
  3193. if ( RtlCheckBit (PageMap, PageFrameIndex) ) {
  3194. if (++WriteCount % Step == 0) {
  3195. //
  3196. // Update the progress percentage.
  3197. //
  3198. IopDisplayString ("%Z: %3d\r",
  3199. ProgressMessage,
  3200. (WriteCount * 100) / MaxWriteCount
  3201. );
  3202. }
  3203. ASSERT ( WriteCount <= MaxWriteCount );
  3204. //
  3205. // Write the page to disk.
  3206. //
  3207. KdCheckForDebugBreak();
  3208. Status = IopWritePageToDisk (
  3209. DriverWriteRoutine,
  3210. Mcb,
  3211. DriverTransferSize,
  3212. PageFrameIndex
  3213. );
  3214. if (!NT_SUCCESS (Status)) {
  3215. return STATUS_UNSUCCESSFUL;
  3216. }
  3217. }
  3218. }
  3219. return STATUS_SUCCESS;
  3220. }
  3221. NTSTATUS
  3222. IopInitializeSummaryDump(
  3223. IN OUT PMEMORY_DUMP MemoryDump,
  3224. IN PDUMP_CONTROL_BLOCK DumpControlBlock
  3225. )
  3226. /*++
  3227. Routine Description:
  3228. This routine creates a summary dump header. In particular it initializes
  3229. a bitmap that contains a map of kernel memory.
  3230. Arguments:
  3231. MemoryDump - The memory dump.
  3232. DumpControlBlock - A pointer to the dump control block.
  3233. Return Value:
  3234. Non-NULL - A pointer to the summary dump header
  3235. NULL - Error
  3236. --*/
  3237. {
  3238. ULONG ActualPages;
  3239. ASSERT ( MemoryDump != NULL );
  3240. ASSERT ( DumpControlBlock != NULL );
  3241. //
  3242. // Fill the header with signatures.
  3243. //
  3244. RtlFillMemoryUlong( &MemoryDump->Summary,
  3245. sizeof (SUMMARY_DUMP),
  3246. DUMP_SUMMARY_SIGNATURE);
  3247. //
  3248. // Set the size and valid signature.
  3249. //
  3250. //
  3251. // ISSUE - 2000/02/07 - math: Review for Win64
  3252. //
  3253. // Computing the bitmap size is probably wrong for 64 bit.
  3254. //
  3255. MemoryDump->Summary.BitmapSize =
  3256. (ULONG)( MmPhysicalMemoryBlock->Run[MmPhysicalMemoryBlock->NumberOfRuns-1].BasePage +
  3257. MmPhysicalMemoryBlock->Run[MmPhysicalMemoryBlock->NumberOfRuns-1].PageCount );
  3258. MemoryDump->Summary.ValidDump = DUMP_SUMMARY_VALID;
  3259. //
  3260. // Construct the kernel memory bitmap.
  3261. //
  3262. //
  3263. // ISSUE - 2000/02/07 - math: Review for Win64
  3264. //
  3265. // Actual will probably need to be a 64-bit value for Win64.
  3266. //
  3267. ActualPages = IopCreateSummaryDump (MemoryDump);
  3268. KdPrintEx ((DPFLTR_CRASHDUMP_ID, CRASHDUMP_TRACE,
  3269. "CRASHDUMP: Kernel Pages = %x\n",
  3270. ActualPages ));
  3271. if (ActualPages == 0) {
  3272. return STATUS_UNSUCCESSFUL;
  3273. }
  3274. //
  3275. // Set the actual number of physical pages in the summary dump
  3276. //
  3277. MemoryDump->Summary.Pages = ActualPages;
  3278. MemoryDump->Summary.HeaderSize = DumpControlBlock->HeaderSize;
  3279. return STATUS_SUCCESS;
  3280. }
  3281. NTSTATUS
  3282. IopWriteSummaryHeader(
  3283. IN PSUMMARY_DUMP SummaryHeader,
  3284. IN PDUMP_DRIVER_WRITE WriteRoutine,
  3285. IN OUT PLARGE_INTEGER * McbBuffer,
  3286. IN OUT PMDL Mdl,
  3287. IN ULONG WriteSize,
  3288. IN ULONG Length
  3289. )
  3290. /*++
  3291. Routine Description:
  3292. Write the summary dump header to the dump file.
  3293. Arguments:
  3294. SummaryHeader - pointer to the summary dump bitmap
  3295. WriteRoutine - dump driver write function
  3296. McbBuffer - Pointer to the dump file MCB array.
  3297. Mdl - Pointer to an MDL
  3298. WriteSize - the max transfer size for the dump driver
  3299. Length - the length of this transfer
  3300. Return Value:
  3301. NTSTATUS code.
  3302. --*/
  3303. {
  3304. NTSTATUS Status;
  3305. ULONG BytesRemaining;
  3306. ULONG_PTR MemoryAddress;
  3307. ULONG ByteOffset;
  3308. ULONG ByteCount;
  3309. PLARGE_INTEGER Mcb;
  3310. Mcb = *McbBuffer;
  3311. BytesRemaining = Length;
  3312. MemoryAddress = (ULONG_PTR) SummaryHeader;
  3313. IopInvokeDumpIoCallbacks(SummaryHeader, Length, KbDumpIoBody);
  3314. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  3315. CRASHDUMP_TRACE,
  3316. "CRASHDUMP: Writing SUMMARY dump header to disk\n" ));
  3317. while ( BytesRemaining ) {
  3318. ByteOffset = BYTE_OFFSET ( MemoryAddress );
  3319. //
  3320. // See if the number of bytes to write is greator than the crash
  3321. // drives max transfer.
  3322. //
  3323. if ( BytesRemaining <= WriteSize) {
  3324. ByteCount = BytesRemaining;
  3325. } else {
  3326. ByteCount = WriteSize;
  3327. }
  3328. //
  3329. // If the byteCount is greater than the remaining mcb then correct it.
  3330. //
  3331. if ( ByteCount > Mcb[0].QuadPart) {
  3332. ByteCount = Mcb[0].LowPart;
  3333. }
  3334. Mdl->ByteCount = ByteCount;
  3335. Mdl->ByteOffset = ByteOffset;
  3336. Mdl->MappedSystemVa = (PVOID) MemoryAddress;
  3337. //
  3338. // Get the actual physical frame and create an mdl.
  3339. //
  3340. IopMapVirtualToPhysicalMdl ( Mdl, MemoryAddress, ByteCount );
  3341. //
  3342. // Write to disk.
  3343. //
  3344. Status = WriteRoutine ( &Mcb[1], Mdl );
  3345. if ( !NT_SUCCESS (Status)) {
  3346. return Status;
  3347. }
  3348. //
  3349. // Adjust bytes remaining.
  3350. //
  3351. BytesRemaining -= ByteCount;
  3352. MemoryAddress += ByteCount;
  3353. Mcb[0].QuadPart = Mcb[0].QuadPart - ByteCount;
  3354. Mcb[1].QuadPart = Mcb[1].QuadPart + ByteCount;
  3355. if (Mcb[0].QuadPart == 0) {
  3356. Mcb += 2;
  3357. }
  3358. if (Mcb[0].QuadPart == 0) {
  3359. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  3360. CRASHDUMP_ERROR,
  3361. "CRASHDUMP: Pagefile is full.\n"));
  3362. return STATUS_END_OF_FILE;
  3363. }
  3364. }
  3365. *McbBuffer = Mcb;
  3366. return STATUS_SUCCESS;
  3367. }
  3368. NTSTATUS
  3369. IopWriteToDisk(
  3370. IN PVOID Buffer,
  3371. IN ULONG WriteLength,
  3372. IN PDUMP_DRIVER_WRITE DriverWriteRoutine,
  3373. IN OUT PLARGE_INTEGER * McbBuffer,
  3374. IN OUT PMDL Mdl,
  3375. IN ULONG DriverTransferSize,
  3376. IN KBUGCHECK_DUMP_IO_TYPE DataType
  3377. )
  3378. /*++
  3379. Routine Description:
  3380. Write the summary dump header to the dump file.
  3381. Arguments:
  3382. Buffer - Pointer to the buffer to write.
  3383. WriteLength - The length of this transfer.
  3384. DriverWriteRoutine - Dump driver write function.
  3385. McbBuffer - Pointer to the dump file Mapped Control Block.
  3386. Mdl - Pointer to an MDL.
  3387. DriverTransferSize - The max transfer size for the dump driver.
  3388. DataType - Type of data being written, for I/O callbacks.
  3389. Return Value:
  3390. --*/
  3391. {
  3392. ULONG BytesRemaining;
  3393. ULONG_PTR MemoryAddress;
  3394. ULONG ByteOffset;
  3395. ULONG ByteCount;
  3396. PLARGE_INTEGER Mcb;
  3397. ASSERT (Buffer);
  3398. ASSERT (WriteLength);
  3399. ASSERT (DriverWriteRoutine);
  3400. ASSERT (McbBuffer && *McbBuffer);
  3401. ASSERT (Mdl);
  3402. ASSERT (DriverTransferSize >= IO_DUMP_MINIMUM_TRANSFER_SIZE &&
  3403. DriverTransferSize <= IO_DUMP_MAXIMUM_TRANSFER_SIZE);
  3404. IopInvokeDumpIoCallbacks(Buffer, WriteLength, DataType);
  3405. Mcb = *McbBuffer;
  3406. BytesRemaining = WriteLength;
  3407. MemoryAddress = (ULONG_PTR) Buffer;
  3408. while ( BytesRemaining ) {
  3409. ASSERT (IopDumpControlBlock->FileDescriptorArray <= Mcb &&
  3410. (LPBYTE) Mcb < (LPBYTE) IopDumpControlBlock->FileDescriptorArray +
  3411. IopDumpControlBlock->FileDescriptorSize
  3412. );
  3413. if (Mcb[0].QuadPart == 0) {
  3414. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  3415. CRASHDUMP_ERROR,
  3416. "CRASHDUMP: Pagefile is full.\n"));
  3417. return STATUS_END_OF_FILE;
  3418. }
  3419. ByteOffset = BYTE_OFFSET ( MemoryAddress );
  3420. //
  3421. // See if the number of bytes to write is greator than the crash
  3422. // drives max transfer.
  3423. //
  3424. ByteCount = min ( BytesRemaining, DriverTransferSize );
  3425. //
  3426. // If the byteCount is greater than the remaining mcb then correct it.
  3427. //
  3428. if (ByteCount > Mcb[0].QuadPart) {
  3429. ByteCount = Mcb[0].LowPart;
  3430. }
  3431. Mdl->ByteCount = ByteCount;
  3432. Mdl->ByteOffset = ByteOffset;
  3433. Mdl->MappedSystemVa = (PVOID) MemoryAddress;
  3434. //
  3435. // Get the actual physical frame and create an mdl.
  3436. //
  3437. IopMapVirtualToPhysicalMdl(Mdl, MemoryAddress, ByteCount);
  3438. KdCheckForDebugBreak();
  3439. if (!NT_SUCCESS( DriverWriteRoutine ( &Mcb[1], Mdl ) )) {
  3440. //
  3441. // We are in deep trouble if we failed the write.
  3442. //
  3443. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  3444. CRASHDUMP_ERROR,
  3445. "CRASHDUMP: Failed to write Mcb = %p, Mdl = %p to disk\n",
  3446. &Mcb[1],
  3447. Mdl
  3448. ));
  3449. return STATUS_UNSUCCESSFUL;
  3450. }
  3451. //
  3452. // Adjust bytes remaining.
  3453. //
  3454. ASSERT ( BytesRemaining >= ByteCount );
  3455. ASSERT ( ByteCount != 0 );
  3456. BytesRemaining -= ByteCount;
  3457. MemoryAddress += ByteCount;
  3458. Mcb[0].QuadPart -= ByteCount;
  3459. Mcb[1].QuadPart += ByteCount;
  3460. if (Mcb[0].QuadPart == 0) {
  3461. Mcb += 2;
  3462. }
  3463. }
  3464. *McbBuffer = Mcb;
  3465. return STATUS_SUCCESS;
  3466. }
  3467. VOID
  3468. IopMapVirtualToPhysicalMdl(
  3469. IN OUT PMDL Mdl,
  3470. IN ULONG_PTR MemoryAddress,
  3471. IN ULONG Length
  3472. )
  3473. {
  3474. ULONG Pages;
  3475. PPFN_NUMBER Pfn;
  3476. PCHAR BaseVa;
  3477. PHYSICAL_ADDRESS PhysicalAddress;
  3478. //
  3479. // ISSUE - 2000/02/07 - math: Review for Win64
  3480. //
  3481. // This whole function needs to be revisited for Win64.
  3482. // There are a ton of tacit assumptions here about the
  3483. // size of a PFN.
  3484. //
  3485. //
  3486. // Begin by determining the base physical page of the start of the address
  3487. // range and filling in the MDL appropriately.
  3488. //
  3489. Mdl->StartVa = PAGE_ALIGN ( MemoryAddress );
  3490. Mdl->ByteOffset = BYTE_OFFSET ( MemoryAddress );
  3491. Mdl->ByteCount = Length;
  3492. Mdl->MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA;
  3493. //
  3494. // Compute the number of pages spanned
  3495. //
  3496. Pages = ADDRESS_AND_SIZE_TO_SPAN_PAGES( MemoryAddress, Length );
  3497. Pfn = MmGetMdlPfnArray ( Mdl );
  3498. //
  3499. // Map all of the pages for this transfer until there are no more remaining
  3500. // to be mapped.
  3501. //
  3502. BaseVa = PAGE_ALIGN ( MemoryAddress );
  3503. while ( Pages ) {
  3504. PhysicalAddress = MmGetPhysicalAddress ( BaseVa );
  3505. *Pfn++ = (PFN_NUMBER)(PhysicalAddress.QuadPart >> PAGE_SHIFT);
  3506. BaseVa += PAGE_SIZE;
  3507. Pages--;
  3508. }
  3509. //
  3510. // All of the PFNs for the address range have been filled in so map the
  3511. // physical memory into virtual address space using crash dump PTE.
  3512. //
  3513. // MmMapMemoryDumpMdl( pMdl );
  3514. }
  3515. ULONG
  3516. IopCreateSummaryDump (
  3517. IN PMEMORY_DUMP MemoryDump
  3518. )
  3519. /*++
  3520. Routine Description:
  3521. This routine determines the kernel memory and data structures to include
  3522. in the summary memory dump.
  3523. NOTE: This function uses MmGetPhysicalAddress. MmGetPhysicalAddress does
  3524. not acquire any locks. It uses a set of macros for translation.
  3525. Arguments:
  3526. MemoryDump - The memory dump.
  3527. Return Value:
  3528. Status
  3529. --*/
  3530. {
  3531. PRTL_BITMAP BitMap;
  3532. ULONG UserPages;
  3533. LARGE_INTEGER DumpFileSize;
  3534. ULONG PagesUsed;
  3535. ULONG PagesInDumpFile;
  3536. PSUMMARY_DUMP Summary;
  3537. MM_KERNEL_DUMP_CONTEXT Context;
  3538. //
  3539. // Validation
  3540. //
  3541. ASSERT (MemoryDump != NULL);
  3542. //
  3543. // Initialize Bit Map, set the size and buffer address.
  3544. //
  3545. Summary = &MemoryDump->Summary;
  3546. BitMap = (PRTL_BITMAP) &Summary->Bitmap;
  3547. BitMap->SizeOfBitMap = Summary->BitmapSize; // Why??
  3548. BitMap->Buffer = Summary->Bitmap.Buffer;
  3549. //
  3550. // Clear all bits
  3551. //
  3552. RtlClearAllBits (BitMap);
  3553. //
  3554. // Have MM initialize the kernel memory to dump
  3555. //
  3556. Context.Context = Summary;
  3557. Context.SetDumpRange = IoSetDumpRange;
  3558. Context.FreeDumpRange = IoFreeDumpRange;
  3559. MmGetKernelDumpRange (&Context);
  3560. PagesUsed = RtlNumberOfSetBits ( BitMap );
  3561. //
  3562. // See If we have room to Include user va for the current process
  3563. //
  3564. DumpFileSize = MemoryDump->Header.RequiredDumpSpace;
  3565. DumpFileSize.QuadPart -= IopDumpControlBlock->HeaderSize;
  3566. //
  3567. // ISSUE - 2000/02/07 - math: Win64
  3568. //
  3569. // For Win64 the total number of physical pages can exceed 2^32.
  3570. //
  3571. PagesInDumpFile = (ULONG)(PFN_NUMBER)(DumpFileSize.QuadPart >> PAGE_SHIFT);
  3572. //
  3573. // Only copy user virtual if there extra room in the dump file.
  3574. //
  3575. UserPages = 0;
  3576. PagesUsed += UserPages;
  3577. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  3578. CRASHDUMP_TRACE,
  3579. "CRASHDUMP: Number of user mode pages for kernel dump = %x\n",
  3580. UserPages
  3581. ));
  3582. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  3583. CRASHDUMP_TRACE,
  3584. "CRASHDUMP: Kernel Dump, Header = %p\n",
  3585. Summary
  3586. ));
  3587. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  3588. CRASHDUMP_TRACE,
  3589. " BitMapSize: %x\n"
  3590. " Pages: %x\n"
  3591. " BitMapBuffer: %p\n",
  3592. Summary->BitmapSize,
  3593. PagesUsed,
  3594. BitMap->Buffer
  3595. ));
  3596. return PagesUsed;
  3597. }
  3598. VOID
  3599. IopDeleteNonExistentMemory(
  3600. PSUMMARY_DUMP Summary,
  3601. PPHYSICAL_MEMORY_DESCRIPTOR MmPhysicalMemoryBlock
  3602. )
  3603. /*++
  3604. Routine Description:
  3605. This deletes non existent memory. Non existent memory is defined as the
  3606. unassigned memory between memory runs. For example, memory between
  3607. (run[0].base + size) and run[1].base.
  3608. Arguments:
  3609. pHeader - This is a pointer to the summary dump header.
  3610. dwStartingIndex - The starting bit index in the bitmap (starting page).
  3611. dwMemoryAddress - Pseudo-virtual address being mapped.
  3612. dwByteCount - The number of bytes to copy.
  3613. dwMaxBitmapBit - The limit or the highest possible valid bit in the bitmap.
  3614. pMdl - The MDL to create.
  3615. Return Value:
  3616. (none)
  3617. --*/
  3618. {
  3619. ULONG NumberOfRuns;
  3620. ULONG i;
  3621. PFN_NUMBER CurrentPageFrame;
  3622. PFN_NUMBER NextPageFrame;
  3623. PRTL_BITMAP BitMap;
  3624. PPHYSICAL_MEMORY_RUN Run;
  3625. //
  3626. // Verification
  3627. //
  3628. ASSERT ( Summary != NULL );
  3629. ASSERT ( MmPhysicalMemoryBlock != NULL );
  3630. //
  3631. // Initialization
  3632. //
  3633. BitMap = (PRTL_BITMAP) &Summary->Bitmap;
  3634. NumberOfRuns = MmPhysicalMemoryBlock->NumberOfRuns;
  3635. Run = &MmPhysicalMemoryBlock->Run[0];
  3636. i = 0;
  3637. CurrentPageFrame = 1;
  3638. NextPageFrame = Run->BasePage;
  3639. //
  3640. // Remove the gap from 0 till the first run.
  3641. //
  3642. if (NextPageFrame > CurrentPageFrame) {
  3643. //
  3644. // ISSUE - 2000/02/07 - math: Win64 PFN_NUMBER > 32 bits.
  3645. //
  3646. // We must handle page frame numbers greater than 32 bits.
  3647. // Then remove the casts on the PageFrames below.
  3648. //
  3649. IopRemovePageFromPageMap (Summary->BitmapSize,
  3650. BitMap,
  3651. (ULONG)CurrentPageFrame,
  3652. (ULONG)(NextPageFrame-CurrentPageFrame)
  3653. );
  3654. }
  3655. //
  3656. // Remove the gaps between runs.
  3657. //
  3658. while (i < NumberOfRuns - 1) {
  3659. CurrentPageFrame = Run->BasePage + Run->PageCount;
  3660. i++;
  3661. Run++;
  3662. //
  3663. // Get the next starting BasePage.
  3664. //
  3665. NextPageFrame = Run->BasePage;
  3666. if (NextPageFrame != CurrentPageFrame) {
  3667. //
  3668. // ISSUE - 2000/02/07 - math: Win64 PFN_NUMBER > 32 bits.
  3669. //
  3670. // We must handle page frame numbers greater than 32 bits.
  3671. // Then remove the casts on the page frames below.
  3672. //
  3673. IopRemovePageFromPageMap (Summary->BitmapSize,
  3674. BitMap,
  3675. (ULONG)CurrentPageFrame,
  3676. (ULONG)(NextPageFrame - CurrentPageFrame)
  3677. );
  3678. }
  3679. }
  3680. }
  3681. NTSTATUS
  3682. IopInvokeSecondaryDumpDataCallbacks(
  3683. IN PDUMP_DRIVER_WRITE DriverWriteRoutine,
  3684. IN OUT PLARGE_INTEGER * Mcb,
  3685. IN OUT PMDL Mdl,
  3686. IN ULONG DriverTransferSize,
  3687. IN BYTE* Buffer,
  3688. IN ULONG BufferSize,
  3689. IN ULONG MaxTotal,
  3690. IN ULONG MaxPerCallback,
  3691. OUT OPTIONAL PULONG SpaceNeeded
  3692. )
  3693. /*++
  3694. Routine Description:
  3695. Walk the list of dump data callbacks, invoking them
  3696. and writing their data out.
  3697. Arguments:
  3698. DriverWriteRoutine - The write routine for the driver.
  3699. Mcb - Message Control Block where the data is to be written.
  3700. Mdl - Address of the MDL to be filled in.
  3701. DriverTransferSize - The maximum transfer size for the driver.
  3702. Buffer - The buffer to use as a scratch buffer.
  3703. BufferSize - Size of Buffer.
  3704. MaxTotal - Maximum amount of data allowed overall.
  3705. MaxPerCallback - Maximum amount of data allowed per callback.
  3706. SpaceNeeded - Amount of data used by all callbacks. If this
  3707. argument is present then no I/O is done, just
  3708. accumulation of data sizes.
  3709. Return Values:
  3710. STATUS_SUCCESS - On success.
  3711. NTSTATUS - Otherwise.
  3712. --*/
  3713. {
  3714. PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord;
  3715. ULONG_PTR Checksum;
  3716. ULONG Index;
  3717. PLIST_ENTRY LastEntry;
  3718. PLIST_ENTRY ListHead;
  3719. PLIST_ENTRY NextEntry;
  3720. PUCHAR Source;
  3721. PDUMP_BLOB_FILE_HEADER BlobFileHdr;
  3722. PDUMP_BLOB_HEADER BlobHdr;
  3723. // Assert that basic structures preserve 8-byte alignment.
  3724. C_ASSERT((sizeof(DUMP_BLOB_FILE_HEADER) & 7) == 0);
  3725. C_ASSERT((sizeof(DUMP_BLOB_HEADER) & 7) == 0);
  3726. if (ARGUMENT_PRESENT(SpaceNeeded)) {
  3727. *SpaceNeeded = 0;
  3728. }
  3729. //
  3730. // If the caller isn't allowing a reasonable amount of
  3731. // data don't even bother to look.
  3732. //
  3733. if (MaxPerCallback < PAGE_SIZE || MaxTotal < MaxPerCallback) {
  3734. return STATUS_SUCCESS;
  3735. }
  3736. //
  3737. // If the bug check callback listhead is not initialized, then the
  3738. // bug check has occured before the system has gotten far enough
  3739. // in the initialization code to enable anyone to register a callback.
  3740. //
  3741. ListHead = &KeBugCheckReasonCallbackListHead;
  3742. if (ListHead->Flink == NULL || ListHead->Blink == NULL) {
  3743. return STATUS_SUCCESS;
  3744. }
  3745. //
  3746. // The current dump I/O routines only handle
  3747. // page-granular I/O so everything must be
  3748. // packed into a page for a single write.
  3749. //
  3750. // Start out with an overall file header followed
  3751. // by a blob header. After the first blob is written
  3752. // the blob header will be moved down to the head
  3753. // of the buffer.
  3754. //
  3755. BlobFileHdr = (PDUMP_BLOB_FILE_HEADER)Buffer;
  3756. BlobHdr = (PDUMP_BLOB_HEADER)(BlobFileHdr + 1);
  3757. //
  3758. // Scan the bug check callback list.
  3759. //
  3760. LastEntry = ListHead;
  3761. NextEntry = ListHead->Flink;
  3762. while (NextEntry != ListHead) {
  3763. //
  3764. // If no more dump data is allowed we're done.
  3765. //
  3766. if (!MaxTotal) {
  3767. break;
  3768. }
  3769. //
  3770. // The next entry address must be aligned properly, the
  3771. // callback record must be readable, and the callback record
  3772. // must have back link to the last entry.
  3773. //
  3774. if (((ULONG_PTR)NextEntry & (sizeof(ULONG_PTR) - 1)) != 0) {
  3775. return STATUS_DATATYPE_MISALIGNMENT;
  3776. }
  3777. CallbackRecord = CONTAINING_RECORD(NextEntry,
  3778. KBUGCHECK_REASON_CALLBACK_RECORD,
  3779. Entry);
  3780. Source = (PUCHAR)CallbackRecord;
  3781. for (Index = 0; Index < sizeof(*CallbackRecord); Index += 1) {
  3782. if (MmIsAddressValid((PVOID)Source) == FALSE) {
  3783. return STATUS_PARTIAL_COPY;
  3784. }
  3785. Source += 1;
  3786. }
  3787. if (CallbackRecord->Entry.Blink != LastEntry) {
  3788. return STATUS_INVALID_PARAMETER;
  3789. }
  3790. LastEntry = NextEntry;
  3791. NextEntry = NextEntry->Flink;
  3792. //
  3793. // If the callback record has a state of inserted and the
  3794. // computed checksum matches the callback record checksum,
  3795. // then call the specified bug check callback routine.
  3796. //
  3797. Checksum = (ULONG_PTR)CallbackRecord->CallbackRoutine;
  3798. Checksum += (ULONG_PTR)CallbackRecord->Reason;
  3799. Checksum += (ULONG_PTR)CallbackRecord->Component;
  3800. if ((CallbackRecord->State != BufferInserted) ||
  3801. (CallbackRecord->Checksum != Checksum) ||
  3802. (CallbackRecord->Reason != KbCallbackSecondaryDumpData) ||
  3803. MmIsAddressValid((PVOID)(ULONG_PTR)CallbackRecord->
  3804. CallbackRoutine) == FALSE) {
  3805. continue;
  3806. }
  3807. //
  3808. // Call the specified bug check callback routine and
  3809. // handle any exceptions that occur.
  3810. //
  3811. if (!ARGUMENT_PRESENT(SpaceNeeded)) {
  3812. CallbackRecord->State = BufferStarted;
  3813. }
  3814. try {
  3815. KBUGCHECK_SECONDARY_DUMP_DATA CbArgument;
  3816. NTSTATUS Status;
  3817. ULONG BufferAvail;
  3818. // Clean the buffer before letting
  3819. // the callback have it.
  3820. RtlZeroMemory(Buffer, BufferSize);
  3821. // Start the callback's buffer after the blob header.
  3822. CbArgument.InBuffer = (PVOID)(BlobHdr + 1);
  3823. BufferAvail = BufferSize - (ULONG)
  3824. ((ULONG_PTR)CbArgument.InBuffer - (ULONG_PTR)Buffer);
  3825. CbArgument.InBufferLength = BufferAvail;
  3826. CbArgument.MaximumAllowed = MaxPerCallback;
  3827. RtlZeroMemory(&CbArgument.Guid, sizeof(CbArgument.Guid));
  3828. CbArgument.OutBuffer = ARGUMENT_PRESENT(SpaceNeeded) ?
  3829. NULL : CbArgument.InBuffer;
  3830. CbArgument.OutBufferLength = 0;
  3831. (CallbackRecord->CallbackRoutine)(KbCallbackSecondaryDumpData,
  3832. CallbackRecord,
  3833. &CbArgument,
  3834. sizeof(CbArgument));
  3835. //
  3836. // If no data was used there's nothing to write.
  3837. //
  3838. if (!CbArgument.OutBuffer || !CbArgument.OutBufferLength) {
  3839. // Set this state even when sizing as
  3840. // there's no need to call again.
  3841. CallbackRecord->State = BufferFinished;
  3842. __leave;
  3843. }
  3844. //
  3845. // The callback may have used the buffer given or
  3846. // it may have returned its own buffer. If it
  3847. // used the buffer given it must be page aligned.
  3848. //
  3849. if ((PBYTE)CbArgument.OutBuffer >= Buffer &&
  3850. (PBYTE)CbArgument.OutBuffer < Buffer + BufferSize) {
  3851. if (CbArgument.OutBuffer != (PVOID)(BlobHdr + 1) ||
  3852. CbArgument.OutBufferLength > BufferAvail) {
  3853. // If too much or the wrong data was used memory has
  3854. // been trashed. Exit and hope the system still runs.
  3855. return STATUS_INVALID_PARAMETER;
  3856. }
  3857. // The header buffer was used so we can write
  3858. // the data along with the header.
  3859. BlobHdr->PrePad = 0;
  3860. BlobHdr->PostPad = BufferAvail - CbArgument.OutBufferLength;
  3861. } else {
  3862. if (CbArgument.OutBufferLength > MaxPerCallback ||
  3863. BYTE_OFFSET(CbArgument.OutBuffer) ||
  3864. !IopIsAddressRangeValid(CbArgument.OutBuffer,
  3865. CbArgument.OutBufferLength)) {
  3866. return STATUS_INVALID_PARAMETER;
  3867. }
  3868. // The header buffer is separate from the data
  3869. // buffer so prepad and postpad to a page boundary.
  3870. BlobHdr->PrePad = BufferAvail;
  3871. BlobHdr->PostPad =
  3872. (ULONG)(ROUND_TO_PAGES(CbArgument.OutBufferLength) -
  3873. CbArgument.OutBufferLength);
  3874. }
  3875. //
  3876. // Write the page containing the headers.
  3877. //
  3878. if ((PBYTE)BlobHdr > Buffer) {
  3879. BlobFileHdr->Signature1 = DUMP_BLOB_SIGNATURE1;
  3880. BlobFileHdr->Signature2 = DUMP_BLOB_SIGNATURE2;
  3881. BlobFileHdr->HeaderSize = sizeof(*BlobFileHdr);
  3882. BlobFileHdr->BuildNumber = NtBuildNumber;
  3883. }
  3884. BlobHdr->HeaderSize = sizeof(*BlobHdr);
  3885. BlobHdr->Tag = CbArgument.Guid;
  3886. BlobHdr->DataSize = CbArgument.OutBufferLength;
  3887. if (ARGUMENT_PRESENT(SpaceNeeded)) {
  3888. (*SpaceNeeded) += BufferSize;
  3889. } else {
  3890. Status = IopWriteToDisk(Buffer, BufferSize,
  3891. DriverWriteRoutine,
  3892. Mcb, Mdl, DriverTransferSize,
  3893. KbDumpIoSecondaryData);
  3894. if (!NT_SUCCESS(Status)) {
  3895. return Status;
  3896. }
  3897. }
  3898. //
  3899. // Write any extra data buffer pages.
  3900. //
  3901. if (CbArgument.OutBuffer != (PVOID)(BlobHdr + 1)) {
  3902. if (ARGUMENT_PRESENT(SpaceNeeded)) {
  3903. (*SpaceNeeded) += (ULONG)
  3904. ROUND_TO_PAGES(CbArgument.OutBufferLength);
  3905. } else {
  3906. Status = IopWriteToDisk(CbArgument.OutBuffer,
  3907. (ULONG)ROUND_TO_PAGES(CbArgument.OutBufferLength),
  3908. DriverWriteRoutine,
  3909. Mcb, Mdl, DriverTransferSize,
  3910. KbDumpIoSecondaryData);
  3911. if (!NT_SUCCESS(Status)) {
  3912. return Status;
  3913. }
  3914. }
  3915. }
  3916. MaxTotal -= (ULONG)ROUND_TO_PAGES(CbArgument.OutBufferLength);
  3917. // We've written at least one blob so we don't
  3918. // need the file header any more.
  3919. BlobHdr = (PDUMP_BLOB_HEADER)Buffer;
  3920. if (!ARGUMENT_PRESENT(SpaceNeeded)) {
  3921. CallbackRecord->State = BufferFinished;
  3922. }
  3923. } except(EXCEPTION_EXECUTE_HANDLER) {
  3924. // Set this state even when sizing as
  3925. // we don't want to call a bad callback again.
  3926. CallbackRecord->State = BufferIncomplete;
  3927. }
  3928. }
  3929. return STATUS_SUCCESS;
  3930. }
  3931. NTSTATUS
  3932. IopInvokeDumpIoCallbacks(
  3933. IN PVOID Buffer,
  3934. IN ULONG BufferLength,
  3935. IN KBUGCHECK_DUMP_IO_TYPE Type
  3936. )
  3937. /*++
  3938. Routine Description:
  3939. Walk the list of dump I/O callbacks and invoke them.
  3940. Arguments:
  3941. Buffer - The buffer of data being written.
  3942. BufferLength - Size of Buffer.
  3943. Type - Type of data being written.
  3944. Return Values:
  3945. STATUS_SUCCESS - On success.
  3946. NTSTATUS - Otherwise.
  3947. --*/
  3948. {
  3949. PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord;
  3950. ULONG_PTR Checksum;
  3951. ULONG Index;
  3952. PLIST_ENTRY LastEntry;
  3953. PLIST_ENTRY ListHead;
  3954. PLIST_ENTRY NextEntry;
  3955. PUCHAR Source;
  3956. //
  3957. // If the bug check callback listhead is not initialized, then the
  3958. // bug check has occured before the system has gotten far enough
  3959. // in the initialization code to enable anyone to register a callback.
  3960. //
  3961. ListHead = &KeBugCheckReasonCallbackListHead;
  3962. if (ListHead->Flink == NULL || ListHead->Blink == NULL) {
  3963. return STATUS_SUCCESS;
  3964. }
  3965. //
  3966. // Scan the bug check callback list.
  3967. //
  3968. LastEntry = ListHead;
  3969. NextEntry = ListHead->Flink;
  3970. while (NextEntry != ListHead) {
  3971. //
  3972. // The next entry address must be aligned properly, the
  3973. // callback record must be readable, and the callback record
  3974. // must have back link to the last entry.
  3975. //
  3976. if (((ULONG_PTR)NextEntry & (sizeof(ULONG_PTR) - 1)) != 0) {
  3977. return STATUS_DATATYPE_MISALIGNMENT;
  3978. }
  3979. CallbackRecord = CONTAINING_RECORD(NextEntry,
  3980. KBUGCHECK_REASON_CALLBACK_RECORD,
  3981. Entry);
  3982. Source = (PUCHAR)CallbackRecord;
  3983. for (Index = 0; Index < sizeof(*CallbackRecord); Index += 1) {
  3984. if (MmIsAddressValid((PVOID)Source) == FALSE) {
  3985. return STATUS_PARTIAL_COPY;
  3986. }
  3987. Source += 1;
  3988. }
  3989. if (CallbackRecord->Entry.Blink != LastEntry) {
  3990. return STATUS_INVALID_PARAMETER;
  3991. }
  3992. LastEntry = NextEntry;
  3993. NextEntry = NextEntry->Flink;
  3994. //
  3995. // If the callback record has a state of inserted and the
  3996. // computed checksum matches the callback record checksum,
  3997. // then call the specified bug check callback routine.
  3998. //
  3999. Checksum = (ULONG_PTR)CallbackRecord->CallbackRoutine;
  4000. Checksum += (ULONG_PTR)CallbackRecord->Reason;
  4001. Checksum += (ULONG_PTR)CallbackRecord->Component;
  4002. if ((CallbackRecord->State != BufferInserted) ||
  4003. (CallbackRecord->Checksum != Checksum) ||
  4004. (CallbackRecord->Reason != KbCallbackDumpIo) ||
  4005. MmIsAddressValid((PVOID)(ULONG_PTR)CallbackRecord->
  4006. CallbackRoutine) == FALSE) {
  4007. continue;
  4008. }
  4009. //
  4010. // Call the specified bug check callback routine and
  4011. // handle any exceptions that occur.
  4012. //
  4013. try {
  4014. KBUGCHECK_DUMP_IO CbArgument;
  4015. // Currently we aren't allowing arbitrary I/O
  4016. // so always use the special sequential I/O offset.
  4017. CbArgument.Offset = (ULONG64)-1;
  4018. CbArgument.Buffer = Buffer;
  4019. CbArgument.BufferLength = BufferLength;
  4020. CbArgument.Type = Type;
  4021. (CallbackRecord->CallbackRoutine)(KbCallbackDumpIo,
  4022. CallbackRecord,
  4023. &CbArgument,
  4024. sizeof(CbArgument));
  4025. if (Type == KbDumpIoComplete) {
  4026. CallbackRecord->State = BufferFinished;
  4027. }
  4028. } except(EXCEPTION_EXECUTE_HANDLER) {
  4029. CallbackRecord->State = BufferIncomplete;
  4030. }
  4031. }
  4032. return STATUS_SUCCESS;
  4033. }
  4034. NTSTATUS
  4035. IopCompleteDumpInitialization(
  4036. IN HANDLE FileHandle
  4037. )
  4038. /*++
  4039. Routine Description:
  4040. This routine is invoked after the dump file is created.
  4041. The purpose is to obtain the retrieval pointers so that they can then be
  4042. used later to write the dump. The last step is to checksum the
  4043. IopDumpControlBlock.
  4044. Fields in the IopDumpControlBlock are updated if necessary and the
  4045. IopDumpControlBlockChecksum is initialized.
  4046. This is the final step in dump initialization.
  4047. Arguments:
  4048. FileHandle - Handle to the dump file just created.
  4049. Return Value:
  4050. STATUS_SUCCESS - Indicates success.
  4051. Other NTSTATUS - Failure.
  4052. --*/
  4053. {
  4054. NTSTATUS Status;
  4055. NTSTATUS ErrorToLog;
  4056. ULONG i;
  4057. LARGE_INTEGER RequestedFileSize;
  4058. PLARGE_INTEGER mcb;
  4059. PFILE_OBJECT FileObject;
  4060. PDEVICE_OBJECT DeviceObject;
  4061. IO_STATUS_BLOCK IoStatusBlock;
  4062. FILE_STANDARD_INFORMATION StandardFileInfo;
  4063. ULONG MaxSecondaryData;
  4064. ULONG MaxSecondaryCbData;
  4065. Status = STATUS_UNSUCCESSFUL;
  4066. ErrorToLog = STATUS_SUCCESS; // No error
  4067. FileObject = NULL;
  4068. DeviceObject = NULL;
  4069. Status = ObReferenceObjectByHandle( FileHandle,
  4070. 0,
  4071. IoFileObjectType,
  4072. KernelMode,
  4073. (PVOID *) &FileObject,
  4074. NULL
  4075. );
  4076. if ( !NT_SUCCESS (Status) ) {
  4077. ASSERT (FALSE);
  4078. goto Cleanup;
  4079. }
  4080. DeviceObject = FileObject->DeviceObject;
  4081. //
  4082. // If this device object represents the boot partition then query
  4083. // the retrieval pointers for the file.
  4084. //
  4085. if ( !(DeviceObject->Flags & DO_SYSTEM_BOOT_PARTITION) ) {
  4086. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  4087. CRASHDUMP_ERROR,
  4088. "CRASHDUMP: Cannot dump to pagefile on non-system partition.\n"
  4089. " DO = %p\n",
  4090. DeviceObject));
  4091. goto Cleanup;
  4092. }
  4093. Status = ZwQueryInformationFile(
  4094. FileHandle,
  4095. &IoStatusBlock,
  4096. &StandardFileInfo,
  4097. sizeof (StandardFileInfo),
  4098. FileStandardInformation
  4099. );
  4100. if (Status == STATUS_PENDING) {
  4101. Status = KeWaitForSingleObject( &FileObject->Event,
  4102. Executive,
  4103. KernelMode,
  4104. FALSE,
  4105. NULL
  4106. );
  4107. Status = IoStatusBlock.Status;
  4108. }
  4109. if ( !NT_SUCCESS (Status) ) {
  4110. goto Cleanup;
  4111. }
  4112. //
  4113. // Ask for as much space as needed for the basic dump
  4114. // plus extra space for secondary dump data.
  4115. //
  4116. RequestedFileSize = IopDumpControlBlock->DumpFileSize;
  4117. IopGetSecondaryDumpDataLimits(IopDumpControlBlock->Flags,
  4118. &MaxSecondaryData, &MaxSecondaryCbData);
  4119. RequestedFileSize.QuadPart += MaxSecondaryData;
  4120. //
  4121. // Do not ask for more space than is in the pagefile.
  4122. //
  4123. if (RequestedFileSize.QuadPart > StandardFileInfo.EndOfFile.QuadPart) {
  4124. RequestedFileSize = StandardFileInfo.EndOfFile;
  4125. }
  4126. Status = ZwFsControlFile(
  4127. FileHandle,
  4128. NULL,
  4129. NULL,
  4130. NULL,
  4131. &IoStatusBlock,
  4132. FSCTL_QUERY_RETRIEVAL_POINTERS,
  4133. &RequestedFileSize,
  4134. sizeof( LARGE_INTEGER ),
  4135. &mcb,
  4136. sizeof( PVOID )
  4137. );
  4138. if (Status == STATUS_PENDING) {
  4139. Status = KeWaitForSingleObject( &FileObject->Event,
  4140. Executive,
  4141. KernelMode,
  4142. FALSE,
  4143. NULL );
  4144. Status = IoStatusBlock.Status;
  4145. }
  4146. //
  4147. // NOTE: If you fail here, put a BP on ntfs!NtfsQueryRetrievalPointers
  4148. // or FatQueryRetrievalPointers and see why you failed.
  4149. //
  4150. if ( !NT_SUCCESS (Status) ) {
  4151. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  4152. CRASHDUMP_ERROR,
  4153. "CRASHDUMP: ZwFsControlFile returnd %d\n"
  4154. " File = %p\n",
  4155. FileObject,
  4156. Status
  4157. ));
  4158. ErrorToLog = IO_DUMP_POINTER_FAILURE;
  4159. goto Cleanup;
  4160. }
  4161. //
  4162. // This paging file is on the system boot partition, and
  4163. // the retrieval pointers for the file were just successfully
  4164. // queried. Walk the MCB to size it, and then checksum it.
  4165. //
  4166. for (i = 0; mcb [i].QuadPart; i++) {
  4167. NOTHING;
  4168. }
  4169. //
  4170. // Write back fields of the IopDumpControlBlock.
  4171. //
  4172. IopDumpControlBlock->FileDescriptorArray = mcb;
  4173. IopDumpControlBlock->FileDescriptorSize = (i + 1) * sizeof (LARGE_INTEGER);
  4174. IopDumpControlBlock->DumpFileSize = RequestedFileSize;
  4175. IopDumpControlBlockChecksum = IopGetDumpControlBlockCheck ( IopDumpControlBlock );
  4176. Status = STATUS_SUCCESS;
  4177. Cleanup:
  4178. if (Status != STATUS_SUCCESS &&
  4179. ErrorToLog != STATUS_SUCCESS ) {
  4180. IopLogErrorEvent (0,
  4181. 4,
  4182. STATUS_SUCCESS,
  4183. ErrorToLog,
  4184. 0,
  4185. NULL,
  4186. 0,
  4187. NULL
  4188. );
  4189. }
  4190. DeviceObject = NULL;
  4191. if ( FileObject ) {
  4192. ObDereferenceObject( FileObject );
  4193. FileObject = NULL;
  4194. }
  4195. return Status;
  4196. }
  4197. VOID
  4198. IopFreeDCB(
  4199. BOOLEAN FreeDCB
  4200. )
  4201. /*++
  4202. Routine Description:
  4203. Free dump control block storage.
  4204. Arguments:
  4205. FreeDCB - Implictly free storage for the dump control block.
  4206. Return Value:
  4207. None
  4208. --*/
  4209. {
  4210. PDUMP_CONTROL_BLOCK dcb;
  4211. dcb = IopDumpControlBlock;
  4212. if (dcb) {
  4213. if (dcb->HeaderPage) {
  4214. ExFreePool (dcb->HeaderPage);
  4215. dcb->HeaderPage = NULL;
  4216. }
  4217. if (dcb->FileDescriptorArray) {
  4218. ExFreePool (dcb->FileDescriptorArray);
  4219. dcb->FileDescriptorArray = NULL;
  4220. }
  4221. if (dcb->DumpStack) {
  4222. IoFreeDumpStack (dcb->DumpStack);
  4223. dcb->DumpStack = NULL;
  4224. }
  4225. if (dcb->TriageDumpBuffer) {
  4226. ExFreePool (dcb->TriageDumpBuffer);
  4227. dcb->TriageDumpBuffer = NULL;
  4228. dcb->TriageDumpBufferSize = 0;
  4229. }
  4230. //
  4231. // Disable all options that require dump file access
  4232. //
  4233. dcb->Flags = 0;
  4234. if (FreeDCB) {
  4235. IopDumpControlBlock = NULL;
  4236. ExFreePool( dcb );
  4237. }
  4238. }
  4239. }
  4240. NTSTATUS
  4241. IoConfigureCrashDump(
  4242. CRASHDUMP_CONFIGURATION Configuration
  4243. )
  4244. /*++
  4245. Routine Description:
  4246. Change the configuration of the crashdump for this machine.
  4247. Arguments:
  4248. Configuration - What to change the configuration to.
  4249. CrashDumpDisable - Disable crashdumps for this machine.
  4250. CrashDumpReconfigure - Reread crashdump settings from the
  4251. registry and apply them.
  4252. Return Value:
  4253. NTSTATUS code.
  4254. --*/
  4255. {
  4256. NTSTATUS Status;
  4257. HANDLE FileHandle;
  4258. PKTHREAD CurrentThread;
  4259. CurrentThread = KeGetCurrentThread ();
  4260. KeEnterCriticalRegionThread(CurrentThread);
  4261. switch (Configuration) {
  4262. case CrashDumpDisable:
  4263. if (ExAcquireResourceExclusiveLite(&IopCrashDumpLock, FALSE)) {
  4264. IopFreeDCB (FALSE);
  4265. ExReleaseResourceLite(&IopCrashDumpLock);
  4266. }
  4267. Status = STATUS_SUCCESS;
  4268. break;
  4269. case CrashDumpReconfigure:
  4270. FileHandle = MmGetSystemPageFile();
  4271. if (FileHandle == NULL) {
  4272. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  4273. } else {
  4274. ExAcquireResourceExclusiveLite(&IopCrashDumpLock,TRUE);
  4275. if (IoInitializeCrashDump(FileHandle)) {
  4276. Status = STATUS_SUCCESS;
  4277. } else {
  4278. Status = STATUS_UNSUCCESSFUL;
  4279. }
  4280. ExReleaseResourceLite(&IopCrashDumpLock);
  4281. }
  4282. break;
  4283. default:
  4284. Status = STATUS_INVALID_DEVICE_REQUEST;
  4285. }
  4286. KeLeaveCriticalRegionThread(CurrentThread);
  4287. return Status;
  4288. }
  4289. VOID
  4290. IopReadDumpRegistry(
  4291. OUT PULONG dumpControl,
  4292. OUT PULONG numberOfHeaderPages,
  4293. OUT PULONG autoReboot,
  4294. OUT PULONG dumpFileSize
  4295. )
  4296. /*++
  4297. Routine Description:
  4298. This routine reads the dump parameters from the registry.
  4299. Arguments:
  4300. dumpControl - Supplies a pointer to the dumpControl flags to set.
  4301. Return Value:
  4302. None.
  4303. --*/
  4304. {
  4305. HANDLE keyHandle;
  4306. HANDLE crashHandle;
  4307. LOGICAL crashHandleOpened;
  4308. UNICODE_STRING keyName;
  4309. NTSTATUS status;
  4310. PKEY_VALUE_FULL_INFORMATION keyValueInformation;
  4311. ULONG handleValue;
  4312. *dumpControl = 0;
  4313. *autoReboot = 0;
  4314. *dumpFileSize = 0;
  4315. *numberOfHeaderPages = BYTES_TO_PAGES(sizeof(DUMP_HEADER));
  4316. //
  4317. // Begin by opening the path to the control for dumping memory. Note
  4318. // that if it does not exist, then no dumps will occur.
  4319. //
  4320. crashHandleOpened = FALSE;
  4321. RtlInitUnicodeString( &keyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control" );
  4322. status = IopOpenRegistryKey( &keyHandle,
  4323. (HANDLE) NULL,
  4324. &keyName,
  4325. KEY_READ,
  4326. FALSE );
  4327. if (!NT_SUCCESS( status )) {
  4328. return;
  4329. }
  4330. RtlInitUnicodeString( &keyName, L"CrashControl" );
  4331. status = IopOpenRegistryKey( &crashHandle,
  4332. keyHandle,
  4333. &keyName,
  4334. KEY_READ,
  4335. FALSE );
  4336. NtClose( keyHandle );
  4337. if (!NT_SUCCESS( status )) {
  4338. return;
  4339. }
  4340. crashHandleOpened = TRUE;
  4341. //
  4342. // Now get the value of the crash control to determine whether or not
  4343. // dumping is enabled.
  4344. //
  4345. status = IopGetRegistryValue( crashHandle,
  4346. L"CrashDumpEnabled",
  4347. &keyValueInformation );
  4348. if (NT_SUCCESS (status)) {
  4349. if (keyValueInformation->DataLength) {
  4350. handleValue = * ((PULONG) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset));
  4351. ExFreePool( keyValueInformation );
  4352. if (handleValue) {
  4353. *dumpControl |= DCB_DUMP_ENABLED;
  4354. if ( handleValue == 3 ) {
  4355. *dumpControl |= DCB_TRIAGE_DUMP_ENABLED;
  4356. } else if ( handleValue == 4 ) {
  4357. *dumpControl |= ( DCB_TRIAGE_DUMP_ENABLED | DCB_TRIAGE_DUMP_ACT_UPON_ENABLED );
  4358. } else if ( handleValue == 2 ) {
  4359. *dumpControl |= DCB_SUMMARY_DUMP_ENABLED;
  4360. //
  4361. // Allocate enough storage for the dump header, summary
  4362. // dump header and bitmap.
  4363. //
  4364. *numberOfHeaderPages = (ULONG) BYTES_TO_PAGES(
  4365. sizeof(DUMP_HEADER) +
  4366. ((MmPhysicalMemoryBlock->NumberOfPages / 8) + 1) +
  4367. sizeof (SUMMARY_DUMP));
  4368. }
  4369. }
  4370. }
  4371. }
  4372. status = IopGetRegistryValue( crashHandle,
  4373. L"LogEvent",
  4374. &keyValueInformation );
  4375. if (NT_SUCCESS( status )) {
  4376. if (keyValueInformation->DataLength) {
  4377. handleValue = * ((PULONG) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset));
  4378. ExFreePool( keyValueInformation);
  4379. if (handleValue) {
  4380. *dumpControl |= DCB_SUMMARY_ENABLED;
  4381. }
  4382. }
  4383. }
  4384. status = IopGetRegistryValue( crashHandle,
  4385. L"SendAlert",
  4386. &keyValueInformation );
  4387. if (NT_SUCCESS( status )) {
  4388. if (keyValueInformation->DataLength) {
  4389. handleValue = * ((PULONG) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset));
  4390. ExFreePool( keyValueInformation);
  4391. if (handleValue) {
  4392. *dumpControl |= DCB_SUMMARY_ENABLED;
  4393. }
  4394. }
  4395. }
  4396. //
  4397. // Now determine whether or not automatic reboot is enabled.
  4398. //
  4399. status = IopGetRegistryValue( crashHandle,
  4400. L"AutoReboot",
  4401. &keyValueInformation );
  4402. if (NT_SUCCESS( status )) {
  4403. if (keyValueInformation->DataLength) {
  4404. *autoReboot = * ((PULONG) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset));
  4405. }
  4406. ExFreePool( keyValueInformation );
  4407. }
  4408. //
  4409. // If we aren't auto rebooting or crashing then return now.
  4410. //
  4411. if (*dumpControl == 0 && *autoReboot == 0) {
  4412. if (crashHandleOpened == TRUE) {
  4413. NtClose( crashHandle );
  4414. }
  4415. return;
  4416. }
  4417. status = IopGetRegistryValue( crashHandle,
  4418. L"DumpFileSize",
  4419. &keyValueInformation );
  4420. if (NT_SUCCESS( status )) {
  4421. if (keyValueInformation->DataLength) {
  4422. *dumpFileSize = * ((PULONG) ((PUCHAR) keyValueInformation + keyValueInformation->DataOffset));
  4423. }
  4424. ExFreePool( keyValueInformation );
  4425. }
  4426. return;
  4427. }
  4428. BOOLEAN
  4429. IopInitializeDCB(
  4430. )
  4431. /*++
  4432. Routine Description:
  4433. This routine initializes the Dump Control Block (DCB). It allocates the
  4434. DCB and reads the crashdump parameters from the registry.
  4435. Arguments:
  4436. Return Value:
  4437. The final function value is TRUE if everything worked, else FALSE.
  4438. --*/
  4439. {
  4440. PDUMP_CONTROL_BLOCK dcb;
  4441. ULONG dumpControl;
  4442. ULONG dcbSize;
  4443. LARGE_INTEGER page;
  4444. ULONG numberOfHeaderPages;
  4445. ULONG dumpFileSize;
  4446. //
  4447. // Read all the registry default values first.
  4448. //
  4449. IopReadDumpRegistry ( &dumpControl,
  4450. &numberOfHeaderPages,
  4451. &IopAutoReboot,
  4452. &dumpFileSize);
  4453. //
  4454. // If we aren't crashing or auto rebooting then return now.
  4455. //
  4456. if (dumpControl == 0 && IopAutoReboot == 0) {
  4457. //
  4458. // At some point, we will conditionally on system size, type, etc,
  4459. // set dump defaults like the below and skip over the return.
  4460. //
  4461. // *dumpControl = (DCB_DUMP_ENABLED | DCB_TRIAGE_DUMP_ENABLED);
  4462. // *IopAutoReboot = 1;
  4463. // *dumpFileSize = ?
  4464. //
  4465. return TRUE;
  4466. }
  4467. if (dumpControl & DCB_TRIAGE_DUMP_ENABLED) {
  4468. dumpControl &= ~DCB_SUMMARY_ENABLED;
  4469. dumpFileSize = TRIAGE_DUMP_SIZE;
  4470. }
  4471. //
  4472. // Allocate and initialize the structures necessary to describe and control
  4473. // the post-bugcheck code.
  4474. //
  4475. dcbSize = sizeof( DUMP_CONTROL_BLOCK ) + sizeof( MINIPORT_NODE );
  4476. dcb = ExAllocatePool( NonPagedPool, dcbSize );
  4477. if (!dcb) {
  4478. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  4479. CRASHDUMP_ERROR,
  4480. "CRASHDUMP: Not enough pool to allocate DCB %d\n",
  4481. __LINE__
  4482. ));
  4483. IopLogErrorEvent(0,1,STATUS_SUCCESS,IO_DUMP_INITIALIZATION_FAILURE,0,NULL,0,NULL);
  4484. return FALSE;
  4485. }
  4486. RtlZeroMemory( dcb, dcbSize );
  4487. dcb->Type = IO_TYPE_DCB;
  4488. dcb->Size = (USHORT) dcbSize;
  4489. dcb->Flags = (UCHAR) dumpControl;
  4490. dcb->NumberProcessors = KeNumberProcessors;
  4491. dcb->ProcessorArchitecture = KeProcessorArchitecture;
  4492. dcb->MinorVersion = (USHORT) NtBuildNumber;
  4493. dcb->MajorVersion = (USHORT) ((NtBuildNumber >> 28) & 0xfffffff);
  4494. dcb->BuildNumber = CmNtCSDVersion;
  4495. dcb->TriageDumpFlags = TRIAGE_DUMP_BASIC_INFO | TRIAGE_DUMP_MMINFO |
  4496. TRIAGE_DUMP_DEBUGGER_DATA | TRIAGE_DUMP_DATA_BLOCKS;
  4497. dcb->DumpFileSize.QuadPart = dumpFileSize;
  4498. //
  4499. // Allocate header page.
  4500. //
  4501. dcb->HeaderSize = numberOfHeaderPages * PAGE_SIZE;
  4502. dcb->HeaderPage = ExAllocatePool( NonPagedPool, dcb->HeaderSize );
  4503. if (!dcb->HeaderPage) {
  4504. ExFreePool (dcb);
  4505. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  4506. CRASHDUMP_ERROR,
  4507. "CRASHDUMP: Not enough pool to allocate DCB %d\n",
  4508. __LINE__
  4509. ));
  4510. IopLogErrorEvent(0,1,STATUS_SUCCESS,IO_DUMP_INITIALIZATION_FAILURE,0,NULL,0,NULL);
  4511. return FALSE;
  4512. }
  4513. page = MmGetPhysicalAddress( dcb->HeaderPage );
  4514. dcb->HeaderPfn = (ULONG)(page.QuadPart >> PAGE_SHIFT);
  4515. //
  4516. // Allocate the triage-dump buffer.
  4517. //
  4518. if (dumpControl & DCB_TRIAGE_DUMP_ENABLED) {
  4519. dcb->TriageDumpBuffer = ExAllocatePool (
  4520. NonPagedPool,
  4521. dumpFileSize
  4522. );
  4523. if (!dcb->TriageDumpBuffer) {
  4524. ExFreePool (dcb->HeaderPage);
  4525. ExFreePool (dcb);
  4526. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  4527. CRASHDUMP_ERROR,
  4528. "CRASHDUMP: Not enough pool to allocate DCB %d\n",
  4529. __LINE__
  4530. ));
  4531. IopLogErrorEvent(0,1,STATUS_SUCCESS,IO_DUMP_INITIALIZATION_FAILURE,0,NULL,0,NULL);
  4532. return FALSE;
  4533. }
  4534. dcb->TriageDumpBufferSize = dumpFileSize;
  4535. }
  4536. IopDumpControlBlock = dcb;
  4537. return TRUE;
  4538. }
  4539. BOOLEAN
  4540. IoInitializeCrashDump(
  4541. IN HANDLE hPageFile
  4542. )
  4543. /*++
  4544. Routine Description:
  4545. This routine configures the system for crash dump. The following things
  4546. are done:
  4547. 1. Initialize the dump control block and init registry crashdump
  4548. parameters.
  4549. 2. Configure either page or fast dump.
  4550. 3. Complete dump file initialization.
  4551. This routine is called as each page file is created. A return value of
  4552. TRUE tells the caller (i.e., NtCreatePagingFiles, IoPageFileCreated)
  4553. that crash dump has been configured.
  4554. Arguments:
  4555. hPageFile - Handle to the paging file
  4556. Return Value:
  4557. TRUE - Configuration complete (or crash dump not enabled).
  4558. FALSE - Error, retry PageFile is not on boot partition.
  4559. --*/
  4560. {
  4561. NTSTATUS dwStatus;
  4562. PFILE_OBJECT fileObject;
  4563. PDEVICE_OBJECT deviceObject;
  4564. //
  4565. // If crashdump is already enabled, free it and reinitialize with the
  4566. // current settings.
  4567. //
  4568. IopFreeDCB (TRUE);
  4569. if (!IopInitializeDCB()) {
  4570. return TRUE;
  4571. }
  4572. //
  4573. // Return crash dump not enabled
  4574. //
  4575. if (!IopDumpControlBlock) {
  4576. return TRUE;
  4577. }
  4578. //
  4579. // No dump enabled?
  4580. //
  4581. if ( !( IopDumpControlBlock->Flags & (DCB_DUMP_ENABLED | DCB_SUMMARY_ENABLED) ) ) {
  4582. return TRUE;
  4583. }
  4584. //
  4585. // Configure the paging file for crash dump.
  4586. //
  4587. dwStatus = ObReferenceObjectByHandle(
  4588. hPageFile,
  4589. 0,
  4590. IoFileObjectType,
  4591. KernelMode,
  4592. (PVOID *) &fileObject,
  4593. NULL
  4594. );
  4595. if (!NT_SUCCESS( dwStatus )) {
  4596. goto error_return;
  4597. }
  4598. //
  4599. // Get a pointer to the device object for this file. Note that it
  4600. // cannot go away, since there is an open handle to it, so it is
  4601. // OK to dereference it and then use it.
  4602. //
  4603. deviceObject = fileObject->DeviceObject;
  4604. ObDereferenceObject( fileObject );
  4605. //
  4606. // This should never be called on devices that are not the boot partition
  4607. //
  4608. ASSERT(deviceObject->Flags & DO_SYSTEM_BOOT_PARTITION);
  4609. //
  4610. // Load paging file dump stack
  4611. //
  4612. dwStatus = IoGetDumpStack (L"dump_",
  4613. &IopDumpControlBlock->DumpStack,
  4614. DeviceUsageTypeDumpFile,
  4615. FALSE);
  4616. if (!NT_SUCCESS(dwStatus)) {
  4617. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  4618. CRASHDUMP_ERROR,
  4619. "CRASHDUMP: Could not load dump stack status = %x\n",
  4620. dwStatus
  4621. ));
  4622. goto error_return;
  4623. }
  4624. IopDumpControlBlock->DumpStack->Init.CrashDump = TRUE;
  4625. IopDumpControlBlock->DumpStack->Init.MemoryBlock = ExAllocatePool (
  4626. NonPagedPool,
  4627. IO_DUMP_MEMORY_BLOCK_PAGES * PAGE_SIZE
  4628. );
  4629. if (!IopDumpControlBlock->DumpStack->Init.MemoryBlock) {
  4630. dwStatus = STATUS_NO_MEMORY;
  4631. goto error_return;
  4632. }
  4633. //
  4634. // Calculate the amount of space required for the dump
  4635. //
  4636. IopDumpControlBlock->DumpFileSize =
  4637. IopCalculateRequiredDumpSpace(
  4638. IopDumpControlBlock->Flags,
  4639. IopDumpControlBlock->HeaderSize,
  4640. MmPhysicalMemoryBlock->NumberOfPages,
  4641. MmPhysicalMemoryBlock->NumberOfPages
  4642. );
  4643. //
  4644. // Complete dump initialization
  4645. //
  4646. dwStatus = IopCompleteDumpInitialization(hPageFile);
  4647. error_return:
  4648. //
  4649. // The BOOT partition paging file could not be configured.
  4650. // 1. Log an error message
  4651. // 2. Return TRUE so that MM does not try again
  4652. //
  4653. if (!NT_SUCCESS(dwStatus)) {
  4654. KdPrintEx ((DPFLTR_CRASHDUMP_ID,
  4655. CRASHDUMP_ERROR,
  4656. "CRASHDUMP: Page File dump init FAILED status = %x\n",
  4657. dwStatus
  4658. ));
  4659. IopLogErrorEvent(0, 3, STATUS_SUCCESS, IO_DUMP_PAGE_CONFIG_FAILED, 0, NULL, 0, NULL);
  4660. //
  4661. // ISSUE - 2000/02/07 - math: IopFreeDCB probably wrong.
  4662. //
  4663. // Is the call to IopFreeDCB() correct here? Doesn't this prevent
  4664. // other dump types from working properly? Review this.
  4665. //
  4666. IopFreeDCB(FALSE);
  4667. }
  4668. return TRUE;
  4669. }
  4670. #define TRIAGE_DUMP_DATA_SIZE (TRIAGE_DUMP_SIZE - sizeof(ULONG))
  4671. static
  4672. BOOLEAN
  4673. IopValidateSectionSize(
  4674. ULONG Offset,
  4675. ULONG* pSectionSize
  4676. )
  4677. /*++
  4678. Routine Description:
  4679. Checks whether specified section size will overflow the dump buffer
  4680. (used just for creation of live minidumps)
  4681. Arguments:
  4682. Offset - Section offset
  4683. pSectionSize - Section size (will be changed to fit the dump)
  4684. pbOverflow - used to return the overflow status
  4685. Return Value:
  4686. TRUE - if the section fits the dump, otherwise section size will decreased
  4687. and FALSE will be returned
  4688. --*/
  4689. {
  4690. if ((Offset + *pSectionSize) < TRIAGE_DUMP_DATA_SIZE) return TRUE;
  4691. *pSectionSize = (Offset < TRIAGE_DUMP_DATA_SIZE) ?
  4692. (TRIAGE_DUMP_DATA_SIZE - Offset) : 0;
  4693. return FALSE;
  4694. }
  4695. static
  4696. ULONG
  4697. IopGetMaxValidSectionSize(
  4698. ULONG_PTR Base,
  4699. ULONG MaxSize
  4700. )
  4701. /*++
  4702. Routine Description:
  4703. Gets maximum valid memory section size less than SectionMaxSize
  4704. Arguments:
  4705. Base - beginning of the section
  4706. MaxSize - Maximum size of the section
  4707. Return Value:
  4708. Size of the continuously valid memory starting from SectionBase up to
  4709. SectionMaxSize
  4710. --*/
  4711. {
  4712. ULONG Size = 0;
  4713. // XXX olegk - optimize it later to iterate by page size
  4714. while ((Size < MaxSize) && (MmIsAddressValid((PVOID)(Base + Size))))
  4715. ++Size;
  4716. return Size;
  4717. }
  4718. static
  4719. ULONG
  4720. IopGetMaxValidSectionSizeDown(
  4721. ULONG_PTR Base,
  4722. ULONG MaxSize
  4723. )
  4724. /*++
  4725. Routine Description:
  4726. Gets maximum valid memory section size less than SectionMaxSize
  4727. Arguments:
  4728. Base - End of the section
  4729. MaxSize - Maximum size of the section
  4730. Return Value:
  4731. Size of the continuously valid memory ending at SectionBase downto to
  4732. SectionMaxSize
  4733. --*/
  4734. {
  4735. ULONG Size = 0;
  4736. if ((ULONG_PTR)Base < (ULONG_PTR)MaxSize) MaxSize = (ULONG)Base;
  4737. // XXX olegk - optimize it later to iterate by page size
  4738. while ((Size < MaxSize) && (MmIsAddressValid((PVOID)(Base - Size))))
  4739. ++Size;
  4740. return Size;
  4741. }
  4742. ULONG
  4743. KeCapturePersistentThreadState(
  4744. PCONTEXT pContext,
  4745. PETHREAD pThread,
  4746. ULONG ulBugCheckCode,
  4747. ULONG_PTR ulpBugCheckParam1,
  4748. ULONG_PTR ulpBugCheckParam2,
  4749. ULONG_PTR ulpBugCheckParam3,
  4750. ULONG_PTR ulpBugCheckParam4,
  4751. PVOID pvDump
  4752. )
  4753. /*++
  4754. Routine Description:
  4755. Creates main portion of the minidump in the specified buffer
  4756. This function can be used to crate live minidump (originaly designed to
  4757. work with EA recovery for video drivers)
  4758. Arguments:
  4759. pContext - context of failed thread
  4760. pThread - failed thread object (NULL means current thread)
  4761. ulBugCheckCode,
  4762. ulpBugCheckParam1,
  4763. ulpBugCheckParam2,
  4764. ulpBugCheckParam3,
  4765. ulpBugCheckParam4 - Bugcheck info
  4766. pModules - List of te loaded modules
  4767. pDump - Memory buffer to write dump context (Size of the buffer should
  4768. be at least TRIAGE_DUMP_SIZE
  4769. Return Value:
  4770. Actual size of the dump file to save on disk (always at least TRIAGE_DUMP_SIZE)
  4771. --*/
  4772. {
  4773. PMEMORY_DUMP pDump = (PMEMORY_DUMP)pvDump;
  4774. PDUMP_HEADER pdh = &(pDump->Header);
  4775. PTRIAGE_DUMP ptdh = &(pDump->Triage);
  4776. ULONG Offset = 0, SectionSize = 0;
  4777. PKDDEBUGGER_DATA64 pKdDebuggerDataBlock = (PKDDEBUGGER_DATA64)KdGetDataBlock();
  4778. PEPROCESS pProcess;
  4779. if (!pvDump) return 0;
  4780. if (!pThread) pThread = PsGetCurrentThread();
  4781. pProcess = (PEPROCESS)pThread->Tcb.ApcState.Process;
  4782. RtlZeroMemory(pDump, TRIAGE_DUMP_SIZE);
  4783. //
  4784. // Fill the dump header with signature
  4785. //
  4786. RtlFillMemoryUlong(pdh, sizeof(*pdh), DUMP_SIGNATURE);
  4787. pdh->Signature = DUMP_SIGNATURE;
  4788. pdh->ValidDump = DUMP_VALID_DUMP;
  4789. pdh->MinorVersion = (USHORT) NtBuildNumber;
  4790. pdh->MajorVersion = (USHORT) ((NtBuildNumber >> 28) & 0xfffffff);
  4791. #if defined (_IA64_)
  4792. pdh->DirectoryTableBase = MmSystemParentTablePage << PAGE_SHIFT;
  4793. #else
  4794. pdh->DirectoryTableBase = pThread->Tcb.ApcState.Process->DirectoryTableBase[0];
  4795. #endif
  4796. pdh->PfnDataBase = (ULONG_PTR)MmPfnDatabase;
  4797. pdh->PsLoadedModuleList = (ULONG_PTR)&PsLoadedModuleList;
  4798. pdh->PsActiveProcessHead = (ULONG_PTR)&PsActiveProcessHead;
  4799. pdh->MachineImageType = CURRENT_IMAGE_TYPE();
  4800. pdh->NumberProcessors = KeNumberProcessors;
  4801. pdh->BugCheckCode = ulBugCheckCode;
  4802. pdh->BugCheckParameter1 = ulpBugCheckParam1;
  4803. pdh->BugCheckParameter2 = ulpBugCheckParam2;
  4804. pdh->BugCheckParameter3 = ulpBugCheckParam3;
  4805. pdh->BugCheckParameter4 = ulpBugCheckParam4;
  4806. #if defined (_X86_)
  4807. pdh->PaeEnabled = X86PaeEnabled ();
  4808. #endif
  4809. pdh->Exception.ExceptionCode = STATUS_BREAKPOINT; // XXX olegk - ???
  4810. pdh->Exception.ExceptionRecord = 0;
  4811. pdh->Exception.NumberParameters = 0;
  4812. pdh->Exception.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
  4813. pdh->Exception.ExceptionAddress = PROGRAM_COUNTER (pContext);
  4814. pdh->RequiredDumpSpace.QuadPart = TRIAGE_DUMP_SIZE;
  4815. pdh->SystemTime.LowPart = SharedUserData->SystemTime.LowPart;
  4816. pdh->SystemTime.HighPart = SharedUserData->SystemTime.High1Time;
  4817. pdh->SystemUpTime.LowPart = SharedUserData->InterruptTime.LowPart;
  4818. pdh->SystemUpTime.HighPart = SharedUserData->InterruptTime.High1Time;
  4819. pdh->DumpType = DUMP_TYPE_TRIAGE;
  4820. pdh->MiniDumpFields = TRIAGE_DUMP_EXCEPTION |
  4821. TRIAGE_DUMP_BROKEN_DRIVER; // XXX olegk - debugger need it for memory mapping
  4822. pdh->ProductType = SharedUserData->NtProductType;
  4823. pdh->SuiteMask = SharedUserData->SuiteMask;
  4824. //
  4825. // TRIAGE header
  4826. //
  4827. ptdh->TriageOptions = 0;
  4828. ptdh->ServicePackBuild = CmNtCSDVersion;
  4829. ptdh->SizeOfDump = TRIAGE_DUMP_SIZE;
  4830. ptdh->ExceptionOffset = FIELD_OFFSET(DUMP_HEADER, Exception);
  4831. ptdh->BrokenDriverOffset = 0;
  4832. Offset = sizeof(DUMP_HEADER) + sizeof(TRIAGE_DUMP);
  4833. //
  4834. // Context
  4835. //
  4836. pdh->MiniDumpFields |= TRIAGE_DUMP_CONTEXT;
  4837. ptdh->ContextOffset = FIELD_OFFSET (DUMP_HEADER, ContextRecord);
  4838. RtlCopyMemory(pdh->ContextRecord, pContext, sizeof(CONTEXT));
  4839. //
  4840. // Save debugger data block
  4841. //
  4842. SectionSize = sizeof(KDDEBUGGER_DATA64);
  4843. if (IopValidateSectionSize(ALIGN_8(Offset), &SectionSize)) {
  4844. Offset = ALIGN_8(Offset);
  4845. pdh->MiniDumpFields |= TRIAGE_DUMP_DEBUGGER_DATA;
  4846. pdh->KdDebuggerDataBlock = (LONG_PTR)pKdDebuggerDataBlock;
  4847. ptdh->DebuggerDataOffset = Offset;
  4848. ptdh->DebuggerDataSize = sizeof(KDDEBUGGER_DATA64);
  4849. RtlCopyMemory((char*)pDump + Offset,
  4850. pKdDebuggerDataBlock,
  4851. SectionSize);
  4852. Offset += SectionSize;
  4853. }
  4854. //
  4855. // Write the PRCB.
  4856. //
  4857. SectionSize = sizeof(KPRCB);
  4858. if (IopValidateSectionSize(ALIGN_8(Offset), &SectionSize)) {
  4859. Offset = ALIGN_8(Offset);
  4860. pdh->MiniDumpFields |= TRIAGE_DUMP_PRCB;
  4861. ptdh->PrcbOffset = Offset;
  4862. RtlCopyMemory((char*)pDump + Offset,
  4863. KeGetCurrentPrcb(),
  4864. SectionSize);
  4865. Offset += SectionSize;
  4866. }
  4867. //
  4868. // Write the EPROCESS
  4869. //
  4870. SectionSize = sizeof(EPROCESS);
  4871. if (IopValidateSectionSize(ALIGN_8(Offset), &SectionSize)) {
  4872. Offset = ALIGN_8(Offset);
  4873. pdh->MiniDumpFields |= TRIAGE_DUMP_PROCESS;
  4874. ptdh->ProcessOffset = Offset;
  4875. RtlCopyMemory((char*)pDump + Offset,
  4876. pThread->Tcb.ApcState.Process,
  4877. SectionSize);
  4878. Offset += SectionSize;
  4879. }
  4880. //
  4881. // Write the ETHREAD
  4882. //
  4883. SectionSize = sizeof(ETHREAD);
  4884. if (IopValidateSectionSize(ALIGN_8(Offset), &SectionSize)) {
  4885. Offset = ALIGN_8(Offset);
  4886. pdh->MiniDumpFields |= TRIAGE_DUMP_THREAD;
  4887. ptdh->ThreadOffset = Offset;
  4888. RtlCopyMemory((PUCHAR)pDump + Offset,
  4889. pThread,
  4890. SectionSize);
  4891. Offset += SectionSize;
  4892. }
  4893. //
  4894. // Call Stack (and backing store on ia64)
  4895. //
  4896. if (pThread->Tcb.KernelStackResident) {
  4897. ULONG_PTR StackBase = (ULONG_PTR)pThread->Tcb.StackBase;
  4898. ULONG_PTR StackLimit = (ULONG_PTR)pThread->Tcb.StackLimit;
  4899. ULONG_PTR StackTop = STACK_POINTER(pContext);
  4900. if ((StackLimit > StackTop) || (StackTop >= StackBase))
  4901. StackTop = (ULONG_PTR)pThread->Tcb.StackLimit;
  4902. SectionSize = (StackBase > StackTop) ? (ULONG)(StackBase - StackTop) : 0;
  4903. SectionSize = min(SectionSize, MAX_TRIAGE_STACK_SIZE - 1);
  4904. SectionSize = IopGetMaxValidSectionSize(StackTop, SectionSize);
  4905. if (SectionSize) {
  4906. if (!IopValidateSectionSize(Offset, &SectionSize))
  4907. ptdh->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  4908. pdh->MiniDumpFields |= TRIAGE_DUMP_STACK;
  4909. ptdh->CallStackOffset = Offset;
  4910. ptdh->SizeOfCallStack = SectionSize;
  4911. ptdh->TopOfStack = (LONG_PTR)StackTop;
  4912. RtlCopyMemory((char*)pDump + Offset,
  4913. (char*)StackTop,
  4914. SectionSize);
  4915. Offset += SectionSize;
  4916. }
  4917. #if defined(_IA64_)
  4918. {
  4919. ULONG_PTR BStoreTop = pContext->RsBSP;
  4920. ULONG_PTR BStoreBase = (ULONG_PTR)pThread->Tcb.InitialBStore;
  4921. ULONG_PTR BStoreLimit = (ULONG_PTR)pThread->Tcb.BStoreLimit;
  4922. if ((BStoreBase >= BStoreTop) || (BStoreTop > BStoreLimit))
  4923. BStoreTop = (ULONG_PTR)pThread->Tcb.BStoreLimit;
  4924. SectionSize = (BStoreTop > BStoreBase) ? (ULONG)(BStoreTop - BStoreBase) : 0;
  4925. SectionSize = min(SectionSize, MAX_TRIAGE_STACK_SIZE - 1);
  4926. SectionSize = IopGetMaxValidSectionSizeDown(BStoreTop, SectionSize);
  4927. if (SectionSize) {
  4928. if (!IopValidateSectionSize(Offset, &SectionSize))
  4929. ptdh->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  4930. ptdh->ArchitectureSpecific.Ia64.BStoreOffset = Offset;
  4931. ptdh->ArchitectureSpecific.Ia64.SizeOfBStore = SectionSize;
  4932. ptdh->ArchitectureSpecific.Ia64.LimitOfBStore = (LONG_PTR)BStoreTop;
  4933. RtlCopyMemory((char*)pDump + Offset,
  4934. (char*)BStoreTop - SectionSize + 1,
  4935. SectionSize);
  4936. Offset += SectionSize;
  4937. }
  4938. }
  4939. #endif // defined(_IA64_)
  4940. }
  4941. //
  4942. // Loaded modules list
  4943. //
  4944. {
  4945. ULONG DrvOffset = ALIGN_8(Offset);
  4946. ULONG DrvCount, StrDataSize;
  4947. KIRQL OldIrql;
  4948. OldIrql = KeGetCurrentIrql();
  4949. if (OldIrql < DISPATCH_LEVEL) {
  4950. KeRaiseIrqlToDpcLevel();
  4951. }
  4952. ExAcquireSpinLockAtDpcLevel(&PsLoadedModuleSpinLock);
  4953. if (NT_SUCCESS(IopGetLoadedDriverInfo(&DrvCount, &StrDataSize))) {
  4954. SectionSize = ALIGN_8(DrvCount * sizeof(DUMP_DRIVER_ENTRY));
  4955. if (SectionSize &&
  4956. IopValidateSectionSize(DrvOffset, &SectionSize))
  4957. {
  4958. ULONG StrOffset = DrvOffset + SectionSize;
  4959. SectionSize = ALIGN_8(StrDataSize +
  4960. DrvCount * (sizeof(WCHAR) +
  4961. sizeof(DUMP_STRING)));
  4962. if (SectionSize &&
  4963. IopValidateSectionSize(StrOffset, &SectionSize))
  4964. {
  4965. if (NT_SUCCESS(IopWriteDriverList((ULONG_PTR)pDump,
  4966. TRIAGE_DUMP_DATA_SIZE,
  4967. DrvOffset,
  4968. StrOffset)))
  4969. {
  4970. pdh->MiniDumpFields |= TRIAGE_DUMP_DRIVER_LIST;
  4971. ptdh->DriverListOffset = DrvOffset;
  4972. ptdh->DriverCount = DrvCount;
  4973. ptdh->StringPoolOffset = (ULONG)StrOffset;
  4974. ptdh->StringPoolSize = SectionSize;
  4975. Offset = StrOffset + SectionSize;
  4976. }
  4977. } else {
  4978. ptdh->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  4979. }
  4980. } else {
  4981. ptdh->TriageOptions |= TRIAGE_OPTION_OVERFLOWED;
  4982. }
  4983. }
  4984. ExReleaseSpinLock(&PsLoadedModuleSpinLock, OldIrql);
  4985. } // Loaded modules list
  4986. //
  4987. // Save some current code
  4988. //
  4989. SectionSize = PAGE_SIZE + sizeof(TRIAGE_DATA_BLOCK);
  4990. IopValidateSectionSize(ALIGN_8(Offset), &SectionSize);
  4991. if (SectionSize > sizeof(TRIAGE_DATA_BLOCK)) {
  4992. ULONG DataSize = SectionSize - sizeof(TRIAGE_DATA_BLOCK);
  4993. ULONG PreIpSize = IopGetMaxValidSectionSizeDown(PROGRAM_COUNTER(pContext),
  4994. DataSize / 2);
  4995. if (PreIpSize) {
  4996. ULONG_PTR CodeStartOffset = PROGRAM_COUNTER(pContext) - PreIpSize + 1;
  4997. DataSize = IopGetMaxValidSectionSize(CodeStartOffset,
  4998. DataSize);
  4999. if (DataSize) {
  5000. PTRIAGE_DATA_BLOCK pDataBlock;
  5001. Offset = ALIGN_8(Offset);
  5002. pdh->MiniDumpFields |= TRIAGE_DUMP_DATA_BLOCKS;
  5003. ptdh->DataBlocksOffset = Offset;
  5004. ptdh->DataBlocksCount = 1;
  5005. pDataBlock = (PTRIAGE_DATA_BLOCK)((char*)pDump + Offset);
  5006. Offset += sizeof(*pDataBlock);
  5007. Offset = ALIGN_8(Offset);
  5008. pDataBlock->Address = (LONG_PTR)CodeStartOffset;
  5009. pDataBlock->Size = DataSize;
  5010. pDataBlock->Offset = Offset;
  5011. RtlCopyMemory((char*)pDump + Offset,
  5012. (char*)CodeStartOffset,
  5013. DataSize);
  5014. Offset += DataSize;
  5015. }
  5016. }
  5017. }
  5018. //
  5019. // End of dump validation
  5020. //
  5021. ptdh->ValidOffset = TRIAGE_DUMP_SIZE - sizeof(ULONG);
  5022. *(PULONG)((char*)pDump + ptdh->ValidOffset) = TRIAGE_DUMP_VALID;
  5023. Offset = TRIAGE_DUMP_SIZE;
  5024. return Offset;
  5025. }