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.

972 lines
23 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. vfbugcheck.c
  5. Abstract:
  6. This module implements support for verifier bugchecks.
  7. Author:
  8. Adrian J. Oney (adriao) 20-Apr-1998
  9. Environment:
  10. Kernel mode
  11. Revision History:
  12. AdriaO 02/21/2000 - Moved from ntos\io\ioassert.c
  13. --*/
  14. //
  15. // Disable W4 level warnings generated by public headers.
  16. //
  17. #include "vfpragma.h"
  18. #include "..\io\iop.h" // Includes vfdef.h
  19. #include "vibugcheck.h"
  20. #ifdef ALLOC_PRAGMA
  21. #pragma alloc_text(INIT, VfBugcheckInit)
  22. #pragma alloc_text(PAGEVRFY, VfBugcheckThrowIoException)
  23. #pragma alloc_text(PAGEVRFY, VfBugcheckThrowException)
  24. #pragma alloc_text(PAGEVRFY, ViBucheckProcessParams)
  25. #pragma alloc_text(PAGEVRFY, ViBugcheckProcessMessageText)
  26. #pragma alloc_text(PAGEVRFY, ViBugcheckApplyControl)
  27. #pragma alloc_text(PAGEVRFY, ViBugcheckHalt)
  28. #pragma alloc_text(PAGEVRFY, ViBugcheckPrintBuffer)
  29. #pragma alloc_text(PAGEVRFY, ViBugcheckPrintParamData)
  30. #pragma alloc_text(PAGEVRFY, ViBugcheckPrintUrl)
  31. #pragma alloc_text(PAGEVRFY, ViBugcheckPrompt)
  32. #endif // ALLOC_PRAGMA
  33. #ifdef ALLOC_DATA_PRAGMA
  34. #pragma data_seg("PAGEVRFD")
  35. #endif
  36. ULONG ViBugCheckInitialControl;
  37. ULONG ViBugCheckControlOverride;
  38. UNICODE_STRING ViBugCheckEmptyString;
  39. #ifdef ALLOC_DATA_PRAGMA
  40. #pragma const_seg("PAGEVRFC")
  41. #endif
  42. //
  43. // When invoking the driver check macro's, pass Irps first, Routines second,
  44. // DevObj's third, and any Status's last...
  45. //
  46. const DCPARAM_TYPE_ENTRY ViBugCheckParamTable[] = {
  47. { DCPARAM_ROUTINE, "Routine" },
  48. { DCPARAM_IRP, "Irp" },
  49. { DCPARAM_IRPSNAP, "Snapshot" },
  50. { DCPARAM_DEVOBJ, "DevObj" },
  51. { DCPARAM_STATUS, "Status" },
  52. { DCPARAM_ULONG, "Ulong" },
  53. { DCPARAM_PVOID, "Pvoid" }
  54. };
  55. VOID
  56. FASTCALL
  57. VfBugcheckInit(
  58. VOID
  59. )
  60. /*++
  61. Routine Description:
  62. This routine initializes the verifier bugcheck support routines.
  63. Arguments:
  64. None.
  65. Return Value:
  66. None.
  67. --*/
  68. {
  69. ViBugCheckInitialControl = 0;
  70. ViBugCheckControlOverride = 0;
  71. RtlInitUnicodeString(&ViBugCheckEmptyString, NULL);
  72. }
  73. NTSTATUS
  74. VfBugcheckThrowIoException(
  75. IN DCERROR_ID MessageID,
  76. IN ULONG MessageParameterMask,
  77. ...
  78. )
  79. /*++
  80. Description:
  81. This routine processes an assert and provides options for removing the
  82. breakpoint, changing to just a text-out, etc.
  83. DCPARAM_IRP*(count)+DCPARAM_ROUTINE*(count)+DCPARAM_DEVOBJ*(count),
  84. irp1,
  85. irp2,
  86. irp3,
  87. routine1,
  88. ..,
  89. ..,
  90. devobj1,
  91. count can be a max of 3.
  92. Notes:
  93. The text will automagically be formatted and printed as such:
  94. ASSERTION CLASS: ASSERTION TEXT ASSERTION TEXT ASSERTION
  95. TEXT ASSERTION TEXT ...
  96. --*/
  97. {
  98. PVFMESSAGE_TEMPLATE_TABLE ioVerifierTable;
  99. UCHAR paramFormat[9*3*ARRAY_COUNT(ViBugCheckParamTable)+1];
  100. ULONG paramType, paramMask, curMask;
  101. NTSTATUS status;
  102. va_list arglist;
  103. curMask = MessageParameterMask;
  104. paramFormat[0] = '\0';
  105. for(paramType=0; paramType<ARRAY_COUNT(ViBugCheckParamTable); paramType++) {
  106. paramMask = ViBugCheckParamTable[paramType].DcParamMask;
  107. while(curMask & (paramMask*3)) {
  108. strcat(
  109. (char *) paramFormat,
  110. ViBugCheckParamTable[paramType].DcParamName
  111. );
  112. curMask -= paramMask;
  113. }
  114. }
  115. VfMessageRetrieveInternalTable(
  116. VFMESSAGE_TABLE_IOVERIFIER,
  117. &ioVerifierTable
  118. );
  119. va_start(arglist, MessageParameterMask);
  120. status = VfBugcheckThrowException(
  121. ioVerifierTable,
  122. (VFMESSAGE_ERRORID) MessageID,
  123. (PCSTR) paramFormat,
  124. &arglist
  125. );
  126. va_end(arglist);
  127. return status;
  128. }
  129. NTSTATUS
  130. VfBugcheckThrowException(
  131. IN PVFMESSAGE_TEMPLATE_TABLE MessageTable OPTIONAL,
  132. IN VFMESSAGE_ERRORID MessageID,
  133. IN PCSTR MessageParamFormat,
  134. IN va_list * MessageParameters
  135. )
  136. /*++
  137. Description:
  138. This routine displays an assert and provides options for
  139. removing the breakpoint, changing to just a text-out, etc.
  140. Arguments:
  141. Notes:
  142. The text will automagically be formatted and printed as such:
  143. ASSERTION CLASS: ASSERTION TEXT ASSERTION TEXT ASSERTION
  144. TEXT ASSERTION TEXT ...
  145. --*/
  146. {
  147. UCHAR finalBuffer[512];
  148. NTSTATUS status;
  149. DC_CHECK_DATA dcCheckData;
  150. PVOID dcParamArray[3*ARRAY_COUNT(ViBugCheckParamTable)];
  151. BOOLEAN exitAssertion;
  152. //
  153. // Preinit
  154. //
  155. RtlZeroMemory(dcParamArray, sizeof(dcParamArray));
  156. //
  157. // Determine what our basic policy towards this check will be and fill out
  158. // the dcCheckData structure as well as we can.
  159. //
  160. ViBucheckProcessParams(
  161. MessageTable,
  162. MessageID,
  163. MessageParamFormat,
  164. MessageParameters,
  165. dcParamArray,
  166. &dcCheckData
  167. );
  168. if (!ViBugcheckApplyControl(&dcCheckData)) {
  169. //
  170. // Nothing to see here, just ignore the assert...
  171. //
  172. return STATUS_SUCCESS;
  173. }
  174. //
  175. // We are going to express our disatifaction somehow. Expand out the
  176. // message we've prepared for this scenario.
  177. //
  178. status = ViBugcheckProcessMessageText(
  179. sizeof(finalBuffer),
  180. (PSTR)finalBuffer,
  181. &dcCheckData
  182. );
  183. if (!NT_SUCCESS(status)) {
  184. ASSERT(0);
  185. //
  186. // Something went wrong with the index lookup!
  187. //
  188. return status;
  189. }
  190. do {
  191. ViBugcheckPrintBuffer(&dcCheckData);
  192. ViBugcheckPrintParamData(&dcCheckData);
  193. ViBugcheckPrintUrl(&dcCheckData);
  194. ViBugcheckHalt(&dcCheckData);
  195. ViBugcheckPrompt(&dcCheckData, &exitAssertion);
  196. } while (!exitAssertion);
  197. return status;
  198. }
  199. VOID
  200. ViBucheckProcessParams(
  201. IN PVFMESSAGE_TEMPLATE_TABLE MessageTable OPTIONAL,
  202. IN VFMESSAGE_ERRORID MessageID,
  203. IN PCSTR MessageParamFormat,
  204. IN va_list * MessageParameters,
  205. IN PVOID * DcParamArray,
  206. OUT PDC_CHECK_DATA DcCheckData
  207. )
  208. {
  209. PVOID culpritAddress;
  210. ULONG i, paramType, paramLen;
  211. char ansiDriverName[81];
  212. NTSTATUS status;
  213. ULONG paramIndices[ARRAY_COUNT(ViBugCheckParamTable)];
  214. PCSTR format;
  215. //
  216. // First we grab parameter off the stack and slot them appropriately into
  217. // our array of "things".
  218. //
  219. // The array is in groups of three for each possible member of a given type
  220. // (three irps, three routines, three device objects, etc). Items not
  221. // referenced in are set to NULL.
  222. //
  223. RtlZeroMemory(paramIndices, sizeof(paramIndices));
  224. format = MessageParamFormat;
  225. while(*format) {
  226. if ((format[0] == ' ')||(format[0] == '%')) {
  227. format++;
  228. continue;
  229. }
  230. for(paramType = 0;
  231. paramType < ARRAY_COUNT(ViBugCheckParamTable);
  232. paramType++) {
  233. paramLen = (ULONG)strlen(ViBugCheckParamTable[paramType].DcParamName);
  234. if (!_strnicmp(ViBugCheckParamTable[paramType].DcParamName, format, paramLen)) {
  235. //
  236. // Match! Advance the pointer...
  237. //
  238. format += paramLen;
  239. //
  240. // If the caller specified an index, grab it. Otherwise infer.
  241. //
  242. if ((format[0] >= '1') && (format[0] <= '3')) {
  243. i = format[0] - '1';
  244. format++;
  245. } else {
  246. i = paramIndices[paramType];
  247. ASSERT(i < 3);
  248. }
  249. if (i < 3) {
  250. //
  251. // Param number is within bounds.
  252. //
  253. DcParamArray[paramType*3+i] = va_arg(*MessageParameters, PVOID);
  254. }
  255. //
  256. // Update the current parameter index for the given type.
  257. //
  258. paramIndices[paramType] = i+1;
  259. //
  260. // Get out early
  261. //
  262. break;
  263. }
  264. }
  265. if (paramType == ARRAY_COUNT(ViBugCheckParamTable)) {
  266. //
  267. // We could'nt find an entry matching the format text. Bail.
  268. //
  269. ASSERT(paramType != ARRAY_COUNT(ViBugCheckParamTable));
  270. break;
  271. }
  272. }
  273. //
  274. // Pre-init unhelpful answers...
  275. //
  276. DcCheckData->DriverName = &ViBugCheckEmptyString;
  277. DcCheckData->OffsetIntoImage = 0;
  278. DcCheckData->InVerifierList = TRUE;
  279. culpritAddress = DcParamArray[0];
  280. //
  281. // Extract the culprit's name if possible...
  282. //
  283. if (culpritAddress) {
  284. status = KevUtilAddressToFileHeader(
  285. (PVOID) culpritAddress,
  286. (PUINT_PTR)(&DcCheckData->OffsetIntoImage),
  287. &DcCheckData->DriverName,
  288. &DcCheckData->InVerifierList
  289. );
  290. if (!NT_SUCCESS(status)) {
  291. //
  292. // IF we don't know who it is, assert anyway.
  293. //
  294. DcCheckData->InVerifierList = TRUE;
  295. }
  296. }
  297. //
  298. // Record
  299. //
  300. DcCheckData->CulpritAddress = culpritAddress;
  301. DcCheckData->DcParamArray = DcParamArray;
  302. DcCheckData->MessageID = MessageID;
  303. //
  304. // Get an ANSI version of the driver name.
  305. //
  306. KeBugCheckUnicodeToAnsi(
  307. DcCheckData->DriverName,
  308. ansiDriverName,
  309. sizeof(ansiDriverName)
  310. );
  311. //
  312. // Retrieve a pointer to the appropriate message data.
  313. //
  314. VfMessageRetrieveErrorData(
  315. MessageTable,
  316. MessageID,
  317. ansiDriverName,
  318. &DcCheckData->BugCheckMajor,
  319. &DcCheckData->AssertionClass,
  320. &DcCheckData->MessageTextTemplate,
  321. &DcCheckData->Control
  322. );
  323. }
  324. NTSTATUS
  325. FASTCALL
  326. ViBugcheckProcessMessageText(
  327. IN ULONG MaxOutputBufferSize,
  328. OUT PSTR OutputBuffer,
  329. IN OUT PDC_CHECK_DATA DcCheckData
  330. )
  331. {
  332. ULONG paramType, maxParameterTypes;
  333. ULONG arrayIndex, paramLength;
  334. char const* messageHead;
  335. PSTR newMessage;
  336. LONG charsRemaining, length;
  337. //
  338. // Get the message text.
  339. //
  340. messageHead = DcCheckData->MessageTextTemplate;
  341. //
  342. // Now manually build out the message.
  343. //
  344. newMessage = OutputBuffer;
  345. charsRemaining = (MaxOutputBufferSize/sizeof(UCHAR))-1;
  346. maxParameterTypes = ARRAY_COUNT(ViBugCheckParamTable);
  347. while(*messageHead != '\0') {
  348. if (charsRemaining <= 0) {
  349. return STATUS_BUFFER_OVERFLOW;
  350. }
  351. if (*messageHead != '%') {
  352. *newMessage = *messageHead;
  353. newMessage++;
  354. messageHead++;
  355. charsRemaining--;
  356. } else {
  357. for(paramType = 0; paramType < maxParameterTypes; paramType++) {
  358. paramLength = (ULONG)strlen(ViBugCheckParamTable[paramType].DcParamName);
  359. //
  360. // Do we have a match?
  361. //
  362. // N.B. - We don't do any case 'de-sensitizing' anywhere, so
  363. // everything's cases must match!
  364. //
  365. if (RtlCompareMemory(
  366. messageHead+1,
  367. ViBugCheckParamTable[paramType].DcParamName,
  368. paramLength*sizeof(UCHAR)) == paramLength*sizeof(UCHAR)) {
  369. arrayIndex = paramType*3;
  370. messageHead += (paramLength+1);
  371. //
  372. // Was an index passed in (ie, "3rd" irp requested)?
  373. //
  374. if ((*messageHead >= '1') && (*messageHead <= '3')) {
  375. //
  376. // Adjust table index appropriately.
  377. //
  378. arrayIndex += (*messageHead - '1') ;
  379. messageHead++;
  380. }
  381. if ((arrayIndex < 6) || (arrayIndex >=9)) {
  382. //
  383. // Normal param, print the pointer
  384. //
  385. length = _snprintf(
  386. newMessage,
  387. charsRemaining+1,
  388. "%p",
  389. DcCheckData->DcParamArray[arrayIndex]
  390. );
  391. } else {
  392. //
  393. // IRP Snapshot, extract the IRP and print that
  394. //
  395. length = _snprintf(
  396. newMessage,
  397. charsRemaining+1,
  398. "%p",
  399. ((PIRP_SNAPSHOT) DcCheckData->DcParamArray[arrayIndex])->Irp
  400. );
  401. }
  402. if (length == -1) {
  403. return STATUS_BUFFER_OVERFLOW;
  404. }
  405. charsRemaining -= length;
  406. newMessage += length;
  407. break;
  408. }
  409. }
  410. if (paramType == maxParameterTypes) {
  411. //
  412. // Either the message we looked up is malformed, we don't recognize
  413. // the %thing it is talking about, or this is %%!
  414. //
  415. *newMessage = *messageHead;
  416. messageHead++;
  417. newMessage++;
  418. charsRemaining--;
  419. if (*messageHead == '%') {
  420. messageHead++;
  421. }
  422. }
  423. }
  424. }
  425. //
  426. // Null-terminate it (we have room because we took one off the buffer size
  427. // above).
  428. //
  429. *newMessage = '\0';
  430. DcCheckData->ClassText = DcCheckData->AssertionClass->MessageClassText;
  431. DcCheckData->AssertionText = OutputBuffer;
  432. return STATUS_SUCCESS;
  433. }
  434. BOOLEAN
  435. FASTCALL
  436. ViBugcheckApplyControl(
  437. IN OUT PDC_CHECK_DATA DcCheckData
  438. )
  439. {
  440. ULONG assertionControl;
  441. if (ViBugCheckControlOverride) {
  442. assertionControl = ViBugCheckControlOverride;
  443. } else if (DcCheckData->Control) {
  444. //
  445. // Initialize the control if appropo
  446. //
  447. if (!((*DcCheckData->Control) & VFM_FLAG_INITIALIZED)) {
  448. *DcCheckData->Control |= (
  449. VFM_FLAG_INITIALIZED | ViBugCheckInitialControl |
  450. DcCheckData->AssertionClass->ClassFlags );
  451. }
  452. assertionControl = *DcCheckData->Control;
  453. } else {
  454. assertionControl =
  455. ( ViBugCheckInitialControl |
  456. DcCheckData->AssertionClass->ClassFlags );
  457. }
  458. if (assertionControl & VFM_FLAG_CLEARED) {
  459. //
  460. // If the breakpoint was cleared, then return, print/rip not.
  461. //
  462. return FALSE;
  463. }
  464. if ((!(assertionControl & VFM_IGNORE_DRIVER_LIST)) &&
  465. (!DcCheckData->InVerifierList)) {
  466. //
  467. // Not of interest, skip this one.
  468. //
  469. return FALSE;
  470. }
  471. //
  472. // If there is no debugger, don't halt the machine. We are probably
  473. // ripping like mad and the user just wants to be able to boot.
  474. // The one exception is if VFM_DEPLOYMENT_FAILURE is set. Then we shall
  475. // invoke the driver bugcheck...
  476. //
  477. if ((!KdDebuggerEnabled) && (!(assertionControl & VFM_DEPLOYMENT_FAILURE))) {
  478. return FALSE;
  479. }
  480. //
  481. // Record our intentions and continue.
  482. //
  483. DcCheckData->AssertionControl = assertionControl;
  484. return TRUE;
  485. }
  486. VOID
  487. FASTCALL
  488. ViBugcheckHalt(
  489. IN PDC_CHECK_DATA DcCheckData
  490. )
  491. {
  492. PVOID parameterArray[4];
  493. char captionBuffer[256];
  494. char ansiDriverName[81];
  495. //
  496. // Do not bugcheck if a kernel debugger is attached, nor if this isn't a
  497. // fatal error.
  498. //
  499. if (KdDebuggerEnabled ||
  500. (!(DcCheckData->AssertionControl & VFM_DEPLOYMENT_FAILURE))) {
  501. return;
  502. }
  503. //
  504. // We are here because VFM_DEPLOYMENT_FAILURE is set. We use
  505. // FATAL_UNHANDLED_HARD_ERROR so that we can give a
  506. // descriptive text string for the problem.
  507. //
  508. parameterArray[0] = (PVOID)(ULONG_PTR)(DcCheckData->MessageID);
  509. parameterArray[1] = DcCheckData->CulpritAddress;
  510. parameterArray[2] = DcCheckData->DcParamArray[3];
  511. parameterArray[3] = DcCheckData->DcParamArray[9];
  512. if (DcCheckData->BugCheckMajor == DRIVER_VERIFIER_IOMANAGER_VIOLATION) {
  513. KeBugCheckUnicodeToAnsi(
  514. DcCheckData->DriverName,
  515. ansiDriverName,
  516. sizeof(ansiDriverName)
  517. );
  518. _snprintf(
  519. captionBuffer,
  520. sizeof(captionBuffer),
  521. "IO SYSTEM VERIFICATION ERROR in %s (%s %x)\n[%s+%x at %p]\n",
  522. ansiDriverName,
  523. DcCheckData->ClassText,
  524. DcCheckData->MessageID,
  525. ansiDriverName,
  526. DcCheckData->OffsetIntoImage,
  527. DcCheckData->CulpritAddress
  528. );
  529. KeBugCheckEx(
  530. FATAL_UNHANDLED_HARD_ERROR,
  531. DcCheckData->BugCheckMajor,
  532. (ULONG_PTR) parameterArray,
  533. (ULONG_PTR) captionBuffer,
  534. (ULONG_PTR) "" // DcCheckData->AssertionText is too technical
  535. );
  536. } else {
  537. KeBugCheckEx(
  538. DcCheckData->BugCheckMajor,
  539. DcCheckData->MessageID,
  540. (ULONG_PTR) DcCheckData->DcParamArray[9],
  541. (ULONG_PTR) DcCheckData->DcParamArray[15],
  542. (ULONG_PTR) DcCheckData->DcParamArray[16]
  543. );
  544. }
  545. }
  546. VOID
  547. FASTCALL
  548. ViBugcheckPrintBuffer(
  549. IN PDC_CHECK_DATA DcCheckData
  550. )
  551. {
  552. UCHAR buffer[82];
  553. UCHAR classBuf[81];
  554. UCHAR callerBuf[81+40];
  555. UCHAR ansiDriverName[81];
  556. LONG lMargin, i, lMarginCur, rMargin=78;
  557. PSTR lineStart, lastWord, current, lMarginText;
  558. //
  559. // Put down a carriage return
  560. //
  561. DbgPrint("\n") ;
  562. //
  563. // Drop a banner if this is a fatal assert or a logo failure.
  564. //
  565. if (DcCheckData->AssertionControl &
  566. (VFM_DEPLOYMENT_FAILURE | VFM_LOGO_FAILURE)) {
  567. DbgPrint(
  568. "***********************************************************************\n"
  569. "* THIS VALIDATION BUG IS FATAL AND WILL CAUSE THE VERIFIER TO HALT *\n"
  570. "* WINDOWS (BUGCHECK) WHEN THE MACHINE IS NOT UNDER A KERNEL DEBUGGER! *\n"
  571. "***********************************************************************\n"
  572. "\n"
  573. );
  574. }
  575. //
  576. // Prepare left margin (ClassText)
  577. //
  578. if (DcCheckData->ClassText != NULL) {
  579. lMargin = (LONG)strlen(DcCheckData->ClassText)+2;
  580. DbgPrint("%s: ", DcCheckData->ClassText);
  581. } else {
  582. lMargin = 0;
  583. }
  584. if (lMargin+1>=rMargin) {
  585. lMargin=0;
  586. }
  587. for(i=0; i<lMargin; i++) classBuf[i] = ' ';
  588. classBuf[lMargin] = '\0';
  589. lMarginText = (PSTR)(classBuf+lMargin);
  590. lMarginCur = lMargin;
  591. lineStart = lastWord = current = DcCheckData->AssertionText;
  592. //
  593. // Print out culprit if we have him...
  594. //
  595. if (DcCheckData->CulpritAddress) {
  596. if (DcCheckData->DriverName->Length) {
  597. KeBugCheckUnicodeToAnsi(
  598. DcCheckData->DriverName,
  599. (PSTR)ansiDriverName,
  600. sizeof(ansiDriverName)
  601. );
  602. sprintf((PCHAR)callerBuf, "[%s @ 0x%p] ",
  603. ansiDriverName,
  604. DcCheckData->CulpritAddress
  605. );
  606. } else {
  607. sprintf((PCHAR)callerBuf, "[0x%p] ", DcCheckData->CulpritAddress);
  608. }
  609. DbgPrint("%s", callerBuf);
  610. lMarginCur += (LONG)strlen((PCHAR)callerBuf);
  611. }
  612. //
  613. // Format and print our assertion text
  614. //
  615. while(*current) {
  616. if (*current == ' ') {
  617. if ((current - lineStart) >= (rMargin-lMarginCur-1)) {
  618. DbgPrint("%s", lMarginText);
  619. lMarginText = (PSTR)classBuf;
  620. lMarginCur = lMargin;
  621. if ((lastWord-lineStart)<rMargin) {
  622. memcpy(buffer, lineStart, (ULONG)(lastWord-lineStart)*sizeof(UCHAR));
  623. buffer[lastWord-lineStart] = '\0';
  624. DbgPrint("%s\n", buffer);
  625. }
  626. lineStart = lastWord+1;
  627. }
  628. lastWord = current;
  629. }
  630. current++;
  631. }
  632. if ((current - lineStart) >= (rMargin-lMarginCur-1)) {
  633. DbgPrint("%s", lMarginText);
  634. lMarginText = (PSTR)classBuf;
  635. if ((lastWord-lineStart)<rMargin) {
  636. memcpy(buffer, lineStart, (ULONG)(lastWord-lineStart)*sizeof(UCHAR));
  637. buffer[lastWord-lineStart] = '\0';
  638. DbgPrint("%s\n", buffer);
  639. }
  640. lineStart = lastWord+1;
  641. }
  642. if (lineStart<current) {
  643. DbgPrint("%s%s\n", lMarginText, lineStart);
  644. }
  645. }
  646. VOID
  647. FASTCALL
  648. ViBugcheckPrintParamData(
  649. IN PDC_CHECK_DATA DcCheckData
  650. )
  651. {
  652. if (DcCheckData->DcParamArray[3]) {
  653. VfPrintDumpIrp((PIRP) DcCheckData->DcParamArray[3]);
  654. }
  655. if (DcCheckData->DcParamArray[6]) {
  656. VfPrintDumpIrpStack(
  657. &((PIRP_SNAPSHOT) DcCheckData->DcParamArray[6])->IoStackLocation
  658. );
  659. }
  660. }
  661. VOID
  662. FASTCALL
  663. ViBugcheckPrintUrl(
  664. IN PDC_CHECK_DATA DcCheckData
  665. )
  666. {
  667. DbgPrint(
  668. "http://www.microsoft.com/hwdq/bc/default.asp?os=%d.%d.%d&major=0x%x&minor=0x%x&lang=0x%x\n",
  669. VER_PRODUCTMAJORVERSION,
  670. VER_PRODUCTMINORVERSION,
  671. VER_PRODUCTBUILD,
  672. DcCheckData->BugCheckMajor,
  673. DcCheckData->MessageID,
  674. 9 // English
  675. );
  676. }
  677. VOID
  678. FASTCALL
  679. ViBugcheckPrompt(
  680. IN PDC_CHECK_DATA DcCheckData,
  681. OUT PBOOLEAN ExitAssertion
  682. )
  683. {
  684. char response[2];
  685. ULONG assertionControl;
  686. BOOLEAN waitForInput;
  687. assertionControl = DcCheckData->AssertionControl;
  688. *ExitAssertion = TRUE;
  689. //
  690. // Vocalize if so ordered.
  691. //
  692. if (assertionControl & VFM_FLAG_BEEP) {
  693. DbgPrint("%c", 7);
  694. }
  695. if (assertionControl & VFM_FLAG_ZAPPED) {
  696. return;
  697. }
  698. //
  699. // Wait for input...
  700. //
  701. waitForInput = TRUE;
  702. while(waitForInput) {
  703. if (DcCheckData->Control) {
  704. DbgPrompt( "Break, Ignore, Zap, Remove, Disable all (bizrd)? ", response, sizeof( response ));
  705. } else {
  706. DbgPrompt( "Break, Ignore, Disable all (bid)? ", response, sizeof( response ));
  707. }
  708. switch (response[0]) {
  709. case 'B':
  710. case 'b':
  711. DbgPrint("Breaking in... (press g<enter> to return to assert menu)\n");
  712. DbgBreakPoint();
  713. waitForInput = FALSE;
  714. *ExitAssertion = FALSE;
  715. break;
  716. case 'I':
  717. case 'i':
  718. waitForInput = FALSE;
  719. break;
  720. case 'Z':
  721. case 'z':
  722. if (DcCheckData->Control) {
  723. DbgPrint("Breakpoint zapped (OS will print text and return)\n");
  724. assertionControl |= VFM_FLAG_ZAPPED;
  725. assertionControl &=~ VFM_FLAG_BEEP;
  726. waitForInput = FALSE;
  727. }
  728. break;
  729. case 'D':
  730. case 'd':
  731. ViBugCheckControlOverride = VFM_FLAG_CLEARED;
  732. DbgPrint("Verification asserts disabled.\n");
  733. waitForInput = FALSE;
  734. break;
  735. case 'R':
  736. case 'r':
  737. if (DcCheckData->Control) {
  738. DbgPrint("Breakpoint removed\n") ;
  739. assertionControl |= VFM_FLAG_CLEARED;
  740. waitForInput = FALSE;
  741. }
  742. break;
  743. }
  744. }
  745. if (DcCheckData->Control) {
  746. *DcCheckData->Control = assertionControl;
  747. }
  748. }