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

745 lines
19 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. triage.c
  5. Abstract:
  6. This module contains the Phase 0 code to triage bugchecks and
  7. automatically enable various system tracing components until the
  8. guilty party is found.
  9. Author:
  10. Landy Wang 13-Jan-1999
  11. Revision History:
  12. --*/
  13. #include "mi.h"
  14. #include "ntiodump.h"
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(INIT,MiTriageSystem)
  17. #pragma alloc_text(INIT,MiTriageAddDrivers)
  18. #endif
  19. //
  20. // Always update this macro when adding triage support for additional bugchecks.
  21. //
  22. #define MI_CAN_TRIAGE_BUGCHECK(BugCheckCode) \
  23. ((BugCheckCode) == PROCESS_HAS_LOCKED_PAGES || \
  24. (BugCheckCode) == NO_MORE_SYSTEM_PTES || \
  25. (BugCheckCode) == BAD_POOL_HEADER || \
  26. (BugCheckCode) == DRIVER_CORRUPTED_SYSPTES || \
  27. (BugCheckCode) == DRIVER_CORRUPTED_EXPOOL || \
  28. (BugCheckCode) == DRIVER_CORRUPTED_MMPOOL)
  29. //
  30. // These are bugchecks that were presumably triggered by either autotriage or
  31. // the admin's registry settings - so don't apply any new rules and in addition,
  32. // keep the old ones unaltered so it can reproduce.
  33. //
  34. #define MI_HOLD_TRIAGE_BUGCHECK(BugCheckCode) \
  35. ((BugCheckCode) == DRIVER_USED_EXCESSIVE_PTES || \
  36. (BugCheckCode) == DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS || \
  37. (BugCheckCode) == PAGE_FAULT_IN_FREED_SPECIAL_POOL || \
  38. (BugCheckCode) == DRIVER_PAGE_FAULT_IN_FREED_SPECIAL_POOL || \
  39. (BugCheckCode) == PAGE_FAULT_BEYOND_END_OF_ALLOCATION || \
  40. (BugCheckCode) == DRIVER_PAGE_FAULT_BEYOND_END_OF_ALLOCATION || \
  41. (BugCheckCode) == DRIVER_CAUGHT_MODIFYING_FREED_POOL || \
  42. (BugCheckCode) == SYSTEM_PTE_MISUSE)
  43. #define MI_TRACKING_LOCKED_PAGES 0x00000001
  44. #define MI_TRACKING_PTES 0x00000002
  45. #define MI_PROTECT_FREED_NONPAGED_POOL 0x00000004
  46. #define MI_VERIFYING_PRENT5_DRIVERS 0x00000008
  47. #define MI_KEEPING_PREVIOUS_SETTINGS 0x00000010
  48. #ifdef ALLOC_DATA_PRAGMA
  49. #pragma const_seg("INITCONST")
  50. #pragma data_seg("INITDATA")
  51. #endif
  52. const PCHAR MiTriageActionStrings[] = {
  53. "Locked pages tracking",
  54. "System PTE usage tracking",
  55. "Making accesses to freed nonpaged pool cause bugchecks",
  56. "Driver Verifying Pre-Windows 2000 built drivers",
  57. "Keeping previous autotriage settings"
  58. };
  59. #if DBG
  60. ULONG MiTriageDebug = 0;
  61. BOOLEAN MiTriageRegardless = FALSE;
  62. #endif
  63. #ifdef ALLOC_DATA_PRAGMA
  64. #pragma const_seg()
  65. #pragma data_seg()
  66. #endif
  67. //
  68. // N.B. The debugger references this.
  69. //
  70. ULONG MmTriageActionTaken;
  71. //
  72. // The Version number must be incremented whenever the MI_TRIAGE_STORAGE
  73. // structure is changed. This enables usermode programs to decode the Mm
  74. // portions of triage dumps regardless of which kernel revision created the
  75. // dump.
  76. //
  77. typedef struct _MI_TRIAGE_STORAGE {
  78. ULONG Version;
  79. ULONG Size;
  80. ULONG MmSpecialPoolTag;
  81. ULONG MiTriageActionTaken;
  82. ULONG MmVerifyDriverLevel;
  83. ULONG KernelVerifier;
  84. ULONG_PTR MmMaximumNonPagedPool;
  85. ULONG_PTR MmAllocatedNonPagedPool;
  86. ULONG_PTR PagedPoolMaximum;
  87. ULONG_PTR PagedPoolAllocated;
  88. ULONG_PTR CommittedPages;
  89. ULONG_PTR CommittedPagesPeak;
  90. ULONG_PTR CommitLimitMaximum;
  91. } MI_TRIAGE_STORAGE, *PMI_TRIAGE_STORAGE;
  92. PKLDR_DATA_TABLE_ENTRY
  93. TriageGetLoaderEntry (
  94. IN PVOID TriageDumpBlock,
  95. IN ULONG ModuleIndex
  96. );
  97. LOGICAL
  98. TriageActUpon(
  99. IN PVOID TriageDumpBlock
  100. );
  101. PVOID
  102. TriageGetMmInformation (
  103. IN PVOID TriageDumpBlock
  104. );
  105. LOGICAL
  106. MiTriageSystem (
  107. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  108. )
  109. /*++
  110. Routine Description:
  111. This routine takes the information from the last bugcheck (if any)
  112. and triages it. Various debugging options are then automatically
  113. enabled.
  114. Arguments:
  115. LoaderBlock - Supplies a pointer to the system loader block.
  116. Return Value:
  117. TRUE if triaging succeeded and options were enabled. FALSE otherwise.
  118. --*/
  119. {
  120. PVOID TriageDumpBlock;
  121. ULONG_PTR BugCheckData[5];
  122. ULONG i;
  123. ULONG ModuleCount;
  124. NTSTATUS Status;
  125. PLIST_ENTRY NextEntry;
  126. PKLDR_DATA_TABLE_ENTRY DataTableEntry;
  127. PKLDR_DATA_TABLE_ENTRY DumpTableEntry;
  128. LOGICAL Matched;
  129. ULONG OldDrivers;
  130. ULONG OldDriversNotVerifying;
  131. PMI_TRIAGE_STORAGE TriageInformation;
  132. if (LoaderBlock->Extension == NULL) {
  133. return FALSE;
  134. }
  135. if (LoaderBlock->Extension->Size < sizeof (LOADER_PARAMETER_EXTENSION)) {
  136. return FALSE;
  137. }
  138. TriageDumpBlock = LoaderBlock->Extension->TriageDumpBlock;
  139. Status = TriageGetBugcheckData (TriageDumpBlock,
  140. (PULONG)&BugCheckData[0],
  141. (PUINT_PTR) &BugCheckData[1],
  142. (PUINT_PTR) &BugCheckData[2],
  143. (PUINT_PTR) &BugCheckData[3],
  144. (PUINT_PTR) &BugCheckData[4]);
  145. if (!NT_SUCCESS (Status)) {
  146. return FALSE;
  147. }
  148. //
  149. // Always display at least the bugcheck data from the previous crash.
  150. //
  151. DbgPrint ("MiTriageSystem: Previous bugcheck was %x %p %p %p %p\n",
  152. BugCheckData[0],
  153. BugCheckData[1],
  154. BugCheckData[2],
  155. BugCheckData[3],
  156. BugCheckData[4]);
  157. if (TriageActUpon (TriageDumpBlock) == FALSE) {
  158. DbgPrint ("MiTriageSystem: Triage disabled in registry by administrator\n");
  159. return FALSE;
  160. }
  161. DbgPrint ("MiTriageSystem: Triage ENABLED in registry by administrator\n");
  162. //
  163. // See if the previous bugcheck was one where action can be taken.
  164. // If not, bail now. If so, then march on and verify all the loaded
  165. // module checksums before actually taking action on the bugcheck.
  166. //
  167. if (!MI_CAN_TRIAGE_BUGCHECK(BugCheckData[0])) {
  168. return FALSE;
  169. }
  170. TriageInformation = (PMI_TRIAGE_STORAGE) TriageGetMmInformation (TriageDumpBlock);
  171. if (TriageInformation == NULL) {
  172. return FALSE;
  173. }
  174. Status = TriageGetDriverCount (TriageDumpBlock, &ModuleCount);
  175. if (!NT_SUCCESS (Status)) {
  176. return FALSE;
  177. }
  178. //
  179. // Process module information from the triage dump.
  180. //
  181. #if DBG
  182. if (MiTriageDebug & 0x1) {
  183. DbgPrint ("MiTriageSystem: printing active drivers from triage crash...\n");
  184. }
  185. #endif
  186. OldDrivers = 0;
  187. OldDriversNotVerifying = 0;
  188. for (i = 0; i < ModuleCount; i += 1) {
  189. DumpTableEntry = TriageGetLoaderEntry (TriageDumpBlock, i);
  190. if (DumpTableEntry != NULL) {
  191. if ((DumpTableEntry->Flags & LDRP_ENTRY_NATIVE) == 0) {
  192. OldDrivers += 1;
  193. if ((DumpTableEntry->Flags & LDRP_IMAGE_VERIFYING) == 0) {
  194. //
  195. // An NT3 or NT4 driver is in the system and was not
  196. // running under the verifier.
  197. //
  198. OldDriversNotVerifying += 1;
  199. }
  200. }
  201. #if DBG
  202. if (MiTriageDebug & 0x1) {
  203. DbgPrint (" %wZ: base = %p, size = %lx, flags = %lx\n",
  204. &DumpTableEntry->BaseDllName,
  205. DumpTableEntry->DllBase,
  206. DumpTableEntry->SizeOfImage,
  207. DumpTableEntry->Flags);
  208. }
  209. #endif
  210. }
  211. }
  212. //
  213. // Ensure that every driver that is currently loaded is identical to
  214. // the one in the triage dump before proceeding.
  215. //
  216. NextEntry = LoaderBlock->LoadOrderListHead.Flink;
  217. while (NextEntry != &LoaderBlock->LoadOrderListHead) {
  218. DataTableEntry = CONTAINING_RECORD(NextEntry,
  219. KLDR_DATA_TABLE_ENTRY,
  220. InLoadOrderLinks);
  221. Matched = FALSE;
  222. for (i = 0; i < ModuleCount; i += 1) {
  223. DumpTableEntry = TriageGetLoaderEntry (TriageDumpBlock, i);
  224. if (DumpTableEntry != NULL) {
  225. if (DataTableEntry->CheckSum == DumpTableEntry->CheckSum) {
  226. Matched = TRUE;
  227. break;
  228. }
  229. }
  230. }
  231. if (Matched == FALSE) {
  232. DbgPrint ("Matching checksum for module %wZ not found in triage dump\n",
  233. &DataTableEntry->BaseDllName);
  234. #if DBG
  235. if (MiTriageRegardless == FALSE)
  236. #endif
  237. return FALSE;
  238. }
  239. NextEntry = NextEntry->Flink;
  240. }
  241. #if DBG
  242. if (MiTriageDebug & 0x1) {
  243. DbgPrint ("MiTriageSystem: OldDrivers = %u, without verification =%u\n",
  244. OldDrivers,
  245. OldDriversNotVerifying);
  246. }
  247. #endif
  248. //
  249. // All boot loaded drivers matched, take action on the triage dump now.
  250. //
  251. if (MI_HOLD_TRIAGE_BUGCHECK(BugCheckData[0])) {
  252. //
  253. // The last bugcheck was presumably triggered by either autotriage or
  254. // the admin's registry settings - so don't apply any new rules
  255. // and in addition, keep the old ones unaltered so it can reproduce.
  256. //
  257. MmTriageActionTaken = TriageInformation->MiTriageActionTaken;
  258. MmTriageActionTaken |= MI_KEEPING_PREVIOUS_SETTINGS;
  259. }
  260. else {
  261. switch (BugCheckData[0]) {
  262. case PROCESS_HAS_LOCKED_PAGES:
  263. //
  264. // Turn on locked pages tracking so this turns into bugcheck
  265. // DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS which shows the name
  266. // of the driver.
  267. //
  268. MmTriageActionTaken |= MI_TRACKING_LOCKED_PAGES;
  269. break;
  270. case DRIVER_CORRUPTED_SYSPTES:
  271. //
  272. // Turn on PTE tracking to trigger a SYSTEM_PTE_MISUSE bugcheck.
  273. //
  274. MmTriageActionTaken |= MI_TRACKING_PTES;
  275. break;
  276. case NO_MORE_SYSTEM_PTES:
  277. //
  278. // Turn on PTE tracking so the driver can be identified via a
  279. // DRIVER_USED_EXCESSIVE_PTES bugcheck.
  280. //
  281. if (BugCheckData[1] == SystemPteSpace) {
  282. MmTriageActionTaken |= MI_TRACKING_PTES;
  283. }
  284. break;
  285. case BAD_POOL_HEADER:
  286. case DRIVER_CORRUPTED_EXPOOL:
  287. //
  288. // Turn on the driver verifier and/or special pool.
  289. // Start by enabling it for every driver that isn't built for NT5.
  290. // Override any specified driver verifier options so that only
  291. // special pool is enabled to minimize the performance hit.
  292. //
  293. if (OldDrivers != 0) {
  294. if (OldDriversNotVerifying != 0) {
  295. MmTriageActionTaken |= MI_VERIFYING_PRENT5_DRIVERS;
  296. }
  297. }
  298. break;
  299. case DRIVER_CORRUPTED_MMPOOL:
  300. //
  301. // Protect freed nonpaged pool if the system had less than 128mb
  302. // of nonpaged pool anyway. This is to trigger a
  303. // DRIVER_CAUGHT_MODIFYING_FREED_POOL bugcheck.
  304. //
  305. #define MB128 ((ULONG_PTR)0x80000000 >> PAGE_SHIFT)
  306. if (TriageInformation->MmMaximumNonPagedPool < MB128) {
  307. MmTriageActionTaken |= MI_PROTECT_FREED_NONPAGED_POOL;
  308. }
  309. break;
  310. case IRQL_NOT_LESS_OR_EQUAL:
  311. case DRIVER_IRQL_NOT_LESS_OR_EQUAL:
  312. default:
  313. break;
  314. }
  315. }
  316. //
  317. // For now always show if action was taken from the bugcheck
  318. // data from the crash. This print and the space for the print strings
  319. // will be enabled for checked builds only prior to shipping.
  320. //
  321. if (MmTriageActionTaken != 0) {
  322. if (MmTriageActionTaken & MI_TRACKING_LOCKED_PAGES) {
  323. MmTrackLockedPages = TRUE;
  324. }
  325. if (MmTriageActionTaken & MI_TRACKING_PTES) {
  326. MmTrackPtes |= 0x1;
  327. }
  328. if (MmTriageActionTaken & MI_VERIFYING_PRENT5_DRIVERS) {
  329. MmVerifyDriverLevel &= ~DRIVER_VERIFIER_FORCE_IRQL_CHECKING;
  330. MmVerifyDriverLevel |= DRIVER_VERIFIER_SPECIAL_POOLING;
  331. }
  332. if (MmTriageActionTaken & MI_PROTECT_FREED_NONPAGED_POOL) {
  333. MmProtectFreedNonPagedPool = TRUE;
  334. }
  335. DbgPrint ("MiTriageSystem: enabling options below to find who caused the last crash\n");
  336. for (i = 0; i < 32; i += 1) {
  337. if (MmTriageActionTaken & (1 << i)) {
  338. DbgPrint (" %s\n", MiTriageActionStrings[i]);
  339. }
  340. }
  341. }
  342. return TRUE;
  343. }
  344. LOGICAL
  345. MiTriageAddDrivers (
  346. IN PLOADER_PARAMETER_BLOCK LoaderBlock
  347. )
  348. /*++
  349. Routine Description:
  350. This routine moves the names of any drivers that autotriage has determined
  351. need verifying from the LoaderBlock into pool.
  352. Arguments:
  353. LoaderBlock - Supplies a pointer to the system loader block.
  354. Return Value:
  355. TRUE if any drivers were added, FALSE if not.
  356. --*/
  357. {
  358. ULONG i;
  359. ULONG ModuleCount;
  360. NTSTATUS Status;
  361. PKLDR_DATA_TABLE_ENTRY DumpTableEntry;
  362. PVOID TriageDumpBlock;
  363. ULONG NameLength;
  364. LOGICAL Added;
  365. PMI_VERIFIER_DRIVER_ENTRY VerifierDriverEntry;
  366. if ((MmTriageActionTaken & MI_VERIFYING_PRENT5_DRIVERS) == 0) {
  367. return FALSE;
  368. }
  369. TriageDumpBlock = LoaderBlock->Extension->TriageDumpBlock;
  370. Status = TriageGetDriverCount (TriageDumpBlock, &ModuleCount);
  371. if (!NT_SUCCESS (Status)) {
  372. return FALSE;
  373. }
  374. Added = FALSE;
  375. for (i = 0; i < ModuleCount; i += 1) {
  376. DumpTableEntry = TriageGetLoaderEntry (TriageDumpBlock, i);
  377. if (DumpTableEntry == NULL) {
  378. continue;
  379. }
  380. if (DumpTableEntry->Flags & LDRP_ENTRY_NATIVE) {
  381. continue;
  382. }
  383. DbgPrint ("MiTriageAddDrivers: Marking %wZ for verification when it is loaded\n", &DumpTableEntry->BaseDllName);
  384. NameLength = DumpTableEntry->BaseDllName.Length;
  385. VerifierDriverEntry = (PMI_VERIFIER_DRIVER_ENTRY)ExAllocatePoolWithTag (
  386. NonPagedPool,
  387. sizeof (MI_VERIFIER_DRIVER_ENTRY) +
  388. NameLength,
  389. 'dLmM');
  390. if (VerifierDriverEntry == NULL) {
  391. continue;
  392. }
  393. VerifierDriverEntry->Loads = 0;
  394. VerifierDriverEntry->Unloads = 0;
  395. VerifierDriverEntry->BaseName.Buffer = (PWSTR)((PCHAR)VerifierDriverEntry +
  396. sizeof (MI_VERIFIER_DRIVER_ENTRY));
  397. VerifierDriverEntry->BaseName.Length = (USHORT)NameLength;
  398. VerifierDriverEntry->BaseName.MaximumLength = (USHORT)NameLength;
  399. RtlCopyMemory (VerifierDriverEntry->BaseName.Buffer,
  400. DumpTableEntry->BaseDllName.Buffer,
  401. NameLength);
  402. InsertHeadList (&MiSuspectDriverList, &VerifierDriverEntry->Links);
  403. Added = TRUE;
  404. }
  405. return Added;
  406. }
  407. #define MAX_UNLOADED_NAME_LENGTH 24
  408. typedef struct _DUMP_UNLOADED_DRIVERS {
  409. UNICODE_STRING Name;
  410. WCHAR DriverName[MAX_UNLOADED_NAME_LENGTH / sizeof (WCHAR)];
  411. PVOID StartAddress;
  412. PVOID EndAddress;
  413. } DUMP_UNLOADED_DRIVERS, *PDUMP_UNLOADED_DRIVERS;
  414. ULONG
  415. MmSizeOfUnloadedDriverInformation (
  416. VOID
  417. )
  418. /*++
  419. Routine Description:
  420. This routine returns the size of the Mm-internal unloaded driver
  421. information that is stored in the triage dump when (if?) the system crashes.
  422. Arguments:
  423. None.
  424. Return Value:
  425. Size of the Mm-internal unloaded driver information.
  426. --*/
  427. {
  428. if (MmUnloadedDrivers == NULL) {
  429. return sizeof (ULONG_PTR);
  430. }
  431. return sizeof(ULONG_PTR) + MI_UNLOADED_DRIVERS * sizeof(DUMP_UNLOADED_DRIVERS);
  432. }
  433. VOID
  434. MmWriteUnloadedDriverInformation (
  435. IN PVOID Destination
  436. )
  437. /*++
  438. Routine Description:
  439. This routine stores the Mm-internal unloaded driver information into
  440. the triage dump.
  441. Arguments:
  442. None.
  443. Return Value:
  444. None.
  445. --*/
  446. {
  447. ULONG i;
  448. ULONG Index;
  449. PUNLOADED_DRIVERS Unloaded;
  450. PDUMP_UNLOADED_DRIVERS DumpUnloaded;
  451. if (MmUnloadedDrivers == NULL) {
  452. *(PULONG)Destination = 0;
  453. }
  454. else {
  455. DumpUnloaded = (PDUMP_UNLOADED_DRIVERS)((PULONG_PTR)Destination + 1);
  456. Unloaded = MmUnloadedDrivers;
  457. //
  458. // Write the list with the most recently unloaded driver first to the
  459. // least recently unloaded driver last.
  460. //
  461. Index = MmLastUnloadedDriver - 1;
  462. for (i = 0; i < MI_UNLOADED_DRIVERS; i += 1) {
  463. if (Index >= MI_UNLOADED_DRIVERS) {
  464. Index = MI_UNLOADED_DRIVERS - 1;
  465. }
  466. Unloaded = &MmUnloadedDrivers[Index];
  467. DumpUnloaded->Name = Unloaded->Name;
  468. if (Unloaded->Name.Buffer == NULL) {
  469. break;
  470. }
  471. DumpUnloaded->StartAddress = Unloaded->StartAddress;
  472. DumpUnloaded->EndAddress = Unloaded->EndAddress;
  473. if (DumpUnloaded->Name.Length > MAX_UNLOADED_NAME_LENGTH) {
  474. DumpUnloaded->Name.Length = MAX_UNLOADED_NAME_LENGTH;
  475. }
  476. if (DumpUnloaded->Name.MaximumLength > MAX_UNLOADED_NAME_LENGTH) {
  477. DumpUnloaded->Name.MaximumLength = MAX_UNLOADED_NAME_LENGTH;
  478. }
  479. DumpUnloaded->Name.Buffer = DumpUnloaded->DriverName;
  480. RtlCopyMemory ((PVOID)DumpUnloaded->Name.Buffer,
  481. (PVOID)Unloaded->Name.Buffer,
  482. DumpUnloaded->Name.MaximumLength);
  483. DumpUnloaded += 1;
  484. Index -= 1;
  485. }
  486. *(PULONG)Destination = i;
  487. }
  488. }
  489. ULONG
  490. MmSizeOfTriageInformation (
  491. VOID
  492. )
  493. /*++
  494. Routine Description:
  495. This routine returns the size of the Mm-internal information that is
  496. stored in the triage dump when (if?) the system crashes.
  497. Arguments:
  498. None.
  499. Return Value:
  500. Size of the Mm-internal triage information.
  501. --*/
  502. {
  503. return sizeof (MI_TRIAGE_STORAGE);
  504. }
  505. VOID
  506. MmWriteTriageInformation (
  507. IN PVOID Destination
  508. )
  509. /*++
  510. Routine Description:
  511. This routine stores the Mm-internal information into the triage dump.
  512. Arguments:
  513. None.
  514. Return Value:
  515. None.
  516. --*/
  517. {
  518. MI_TRIAGE_STORAGE TriageInformation;
  519. TriageInformation.Version = 1;
  520. TriageInformation.Size = sizeof (MI_TRIAGE_STORAGE);
  521. TriageInformation.MmSpecialPoolTag = MmSpecialPoolTag;
  522. TriageInformation.MiTriageActionTaken = MmTriageActionTaken;
  523. TriageInformation.MmVerifyDriverLevel = MmVerifierData.Level;
  524. TriageInformation.KernelVerifier = KernelVerifier;
  525. TriageInformation.MmMaximumNonPagedPool = MmMaximumNonPagedPoolInBytes >> PAGE_SHIFT;
  526. TriageInformation.MmAllocatedNonPagedPool = MmAllocatedNonPagedPool;
  527. TriageInformation.PagedPoolMaximum = MmSizeOfPagedPoolInBytes >> PAGE_SHIFT;
  528. TriageInformation.PagedPoolAllocated = MmPagedPoolInfo.AllocatedPagedPool;
  529. TriageInformation.CommittedPages = MmTotalCommittedPages;
  530. TriageInformation.CommittedPagesPeak = MmPeakCommitment;
  531. TriageInformation.CommitLimitMaximum = MmTotalCommitLimitMaximum;
  532. RtlCopyMemory (Destination,
  533. (PVOID)&TriageInformation,
  534. sizeof (MI_TRIAGE_STORAGE));
  535. }