Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

742 lines
22 KiB

  1. /****************************** Module Header ******************************\
  2. * Module Name: debugc.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * This module contains random debugging related functions.
  7. *
  8. * History:
  9. * 17-May-1991 DarrinM Created.
  10. * 22-Jan-1992 IanJa ANSI/Unicode neutral (all debug output is ANSI)
  11. * 11-Mar-1993 JerrySh Pulled functions from user\server.
  12. \***************************************************************************/
  13. #include "precomp.h"
  14. #if DBG
  15. extern DBGTAG gadbgtag[];
  16. #endif
  17. // common globals
  18. extern CONST ALWAYSZERO gZero;
  19. #if DBG
  20. CONST LPCSTR aszComponents[] = {
  21. "?", // 0x00000000
  22. "USER", // RIP_USER 0x00010000
  23. "WSRV", // RIP_USERSRV 0x00020000
  24. "URTL", // RIP_USERRTL 0x00030000
  25. "GDI", // RIP_GDI 0x00040000
  26. "GDIK", // RIP_GDIKRNL 0x00050000
  27. "GRTL", // RIP_GDIRTL 0x00060000
  28. "KRNL", // RIP_BASE 0x00070000
  29. "BSRV", // RIP_BASESRV 0x00080000
  30. "BRTL", // RIP_BASERTL 0x00090000
  31. "DISP", // RIP_DISPLAYDRV 0x000A0000
  32. "CONS", // RIP_CONSRV 0x000B0000
  33. "USRK", // RIP_USERKRNL 0x000C0000
  34. #ifdef FE_IME
  35. "IMM", // RIP_IMM 0x000D0000
  36. #else
  37. "?", // 0x000D0000
  38. #endif
  39. "?", // 0x000E0000
  40. "?", // 0x000F0000
  41. };
  42. BOOL IsNumChar(
  43. int c,
  44. int base)
  45. {
  46. return ('0' <= c && c <= '9') ||
  47. (base == 16 && (('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')));
  48. }
  49. NTSTATUS GetInteger(
  50. LPSTR psz,
  51. int base,
  52. int *pi,
  53. LPSTR *ppsz)
  54. {
  55. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  56. for (;;) {
  57. if (IsNumChar(*psz, base)) {
  58. Status = RtlCharToInteger(psz, base, pi);
  59. if (ppsz && NT_SUCCESS(Status)) {
  60. while (IsNumChar(*psz++, base)) {
  61. /* do nothing */;
  62. }
  63. *ppsz = psz;
  64. }
  65. break;
  66. }
  67. if (*psz != ' ' && *psz != '\t') {
  68. break;
  69. }
  70. psz++;
  71. }
  72. return Status;
  73. }
  74. /*
  75. * Use a separate debug assertion that doesn't cause recursion
  76. * into this code.
  77. */
  78. #define DebugAssertion(x) \
  79. do { \
  80. if (!(x)) { \
  81. if (TEST_RIPF(RIPF_PRINTONERROR)) { \
  82. KdPrint(("USER: Debug function assertion failure: %s \nFile %s line %ld\n", #x, __FILE__, __LINE__)); \
  83. } \
  84. if (TEST_RIPF(RIPF_PROMPTONERROR)) { \
  85. DbgBreakPoint(); \
  86. } \
  87. } \
  88. } while (FALSE)
  89. /***************************************************************************\
  90. * PrintAndPrompt
  91. *
  92. * Sets the last error, prints an error message, and prompts for
  93. * debug actions.
  94. *
  95. * History:
  96. * 11-Aug-1996 adams Created.
  97. \***************************************************************************/
  98. BOOL
  99. PrintAndPrompt(
  100. BOOL fPrint,
  101. BOOL fPrompt,
  102. DWORD idErr,
  103. DWORD flags,
  104. LPCSTR pszLevel,
  105. LPCSTR pszFile,
  106. int iLine,
  107. LPCSTR pszFunction,
  108. LPSTR pszErr,
  109. PEXCEPTION_POINTERS pexi)
  110. {
  111. static CONST CHAR *szLevels[8] = {
  112. "<none>",
  113. "Errors",
  114. "Warnings",
  115. "Errors and Warnings",
  116. "Verbose",
  117. "Errors and Verbose",
  118. "Warnings and Verbose",
  119. "Errors, Warnings, and Verbose"
  120. };
  121. #ifdef _USERK_
  122. static CONST CHAR *szSystem = "System";
  123. static CONST CHAR *szUnknown = "???";
  124. CONST CHAR *pszImage;
  125. extern ULONG gSessionId;
  126. #else
  127. static CONST WCHAR *wszUnknown = L"???";
  128. WCHAR *pwszImage;
  129. ULONG ulLenImage;
  130. #endif
  131. DWORD dwT;
  132. DWORD dwP;
  133. DWORD dwSession;
  134. char szT[512];
  135. BOOL fBreak = FALSE;
  136. /*
  137. * Set the last error, but don't clear it!
  138. */
  139. if (idErr) {
  140. UserSetLastError(idErr);
  141. }
  142. /*
  143. * Print the message.
  144. */
  145. if (!fPrint && !fPrompt) {
  146. return FALSE;
  147. }
  148. #ifdef _USERK_
  149. {
  150. PETHREAD pet;
  151. PEPROCESS pep;
  152. dwT = HandleToUlong(PsGetCurrentThreadId());
  153. dwP = HandleToUlong(PsGetCurrentProcessId());
  154. pszImage = PsGetCurrentProcessImageFileName();
  155. if (*pszImage == '\0') {
  156. pszImage = szSystem;
  157. }
  158. }
  159. #else
  160. {
  161. PTEB pteb;
  162. PPEB ppeb;
  163. if (pteb = NtCurrentTeb()) {
  164. dwT = HandleToUlong(pteb->ClientId.UniqueThread);
  165. dwP = HandleToUlong(pteb->ClientId.UniqueProcess);
  166. } else {
  167. dwT = dwP = 0;
  168. }
  169. if ((ppeb = NtCurrentPeb()) && ppeb->ProcessParameters != NULL) {
  170. /*
  171. * Get Pointers to the image path
  172. */
  173. pwszImage = ppeb->ProcessParameters->ImagePathName.Buffer;
  174. ulLenImage = (ppeb->ProcessParameters->ImagePathName.Length) / sizeof(WCHAR);
  175. /*
  176. * If the ProcessParameters haven't been normalized yet, then do it.
  177. */
  178. if (pwszImage != NULL && !(ppeb->ProcessParameters->Flags & RTL_USER_PROC_PARAMS_NORMALIZED)) {
  179. pwszImage = (PWSTR)((PCHAR)(pwszImage) + (ULONG_PTR)(ppeb->ProcessParameters));
  180. }
  181. /*
  182. * Munge out the path part.
  183. */
  184. if (pwszImage != NULL && ulLenImage != 0) {
  185. PWSTR pwszT = pwszImage + (ulLenImage - 1);
  186. ULONG ulLenT = 1;
  187. while (ulLenT != ulLenImage && *(pwszT-1) != L'\\') {
  188. pwszT--;
  189. ulLenT++;
  190. }
  191. pwszImage = pwszT;
  192. ulLenImage = ulLenT;
  193. }
  194. } else {
  195. pwszImage = (PWSTR)wszUnknown;
  196. ulLenImage = 3;
  197. }
  198. }
  199. #endif
  200. #ifdef _USERK_
  201. dwSession = gSessionId;
  202. #else
  203. {
  204. PPEB ppeb = NtCurrentPeb();
  205. dwSession = (ppeb != NULL ? ppeb->SessionId : 0);
  206. }
  207. #endif
  208. szT[0] = 'p';
  209. for (;;) {
  210. switch (szT[0] | (char)0x20) {
  211. /* print */
  212. case 'p':
  213. case ' ':
  214. if (!(flags & RIP_NONAME) && (!TEST_RIPF(RIPF_HIDEPID))) {
  215. #ifdef _USERK_
  216. KdPrint((
  217. "(s: %d %#lx.%lx %s) %s-[%s",
  218. dwSession,
  219. dwP,
  220. dwT,
  221. pszImage,
  222. aszComponents[(flags & RIP_COMPBITS) >> RIP_COMPBITSSHIFT],
  223. pszLevel));
  224. #else
  225. KdPrint((
  226. "(s: %d %#lx.%lx %*ws) %s-[%s",
  227. dwSession,
  228. dwP,
  229. dwT,
  230. ulLenImage,
  231. pwszImage,
  232. aszComponents[(flags & RIP_COMPBITS) >> RIP_COMPBITSSHIFT],
  233. pszLevel));
  234. #endif
  235. if (idErr) {
  236. KdPrint(("=%ld] ", idErr));
  237. } else {
  238. KdPrint(("] "));
  239. }
  240. }
  241. KdPrint(("%s", pszErr));
  242. if (!(flags & RIP_NONEWLINE)) {
  243. KdPrint(("\n"));
  244. }
  245. if (flags & RIP_THERESMORE) {
  246. fPrompt = FALSE;
  247. } else if (TEST_RIPF(RIPF_PRINTFILELINE) && (pexi == NULL)) {
  248. KdPrint(("File: %s, Line: %d in function %s\n", pszFile, iLine, pszFunction));
  249. }
  250. break;
  251. /* go */
  252. case 'g':
  253. fPrompt = FALSE;
  254. break;
  255. /* break */
  256. case 'b':
  257. KdPrint(("File: %s, Line: %d in function %s\n", pszFile, iLine, pszFunction));
  258. fBreak = TRUE;
  259. fPrompt = FALSE;
  260. break;
  261. /* display where this originated from */
  262. case 'w':
  263. if (pexi != NULL) {
  264. break;
  265. }
  266. KdPrint(("File: %s, Line: %d in function %s\n", pszFile, iLine, pszFunction));
  267. break;
  268. /* dump information about this exception */
  269. case 'i':
  270. /*
  271. * Dump some useful information about this exception, like its
  272. * address, and the contents of the interesting registers at
  273. * the time of the exception.
  274. */
  275. if (pexi == NULL) {
  276. break;
  277. }
  278. #if defined(i386) // legal
  279. /*
  280. * eip = instruction pointer
  281. * esp = stack pointer
  282. * ebp = stack frame pointer
  283. */
  284. KdPrint(("eip = %lx\n", pexi->ContextRecord->Eip));
  285. KdPrint(("esp = %lx\n", pexi->ContextRecord->Esp));
  286. KdPrint(("ebp = %lx\n", pexi->ContextRecord->Ebp));
  287. #elif defined(_IA64_)
  288. /*
  289. * StIIP = instruction pointer
  290. * IntSp = stack pointer
  291. * RsBSP = Rsestack pointer
  292. */
  293. KdPrint(("StIIP = %lx\n", pexi->ContextRecord->StIIP));
  294. KdPrint(("IntSp = %lx\n", pexi->ContextRecord->IntSp));
  295. KdPrint(("RsBsp = %lx\n", pexi->ContextRecord->RsBSP));
  296. #elif defined(_AMD64_)
  297. /*
  298. * rip = instruction pointer
  299. * rsp = stack pointer
  300. * rbp = stack frame pointer
  301. */
  302. KdPrint(("rip = %lx\n", pexi->ContextRecord->Rip));
  303. KdPrint(("rsp = %lx\n", pexi->ContextRecord->Rsp));
  304. KdPrint(("rbp = %lx\n", pexi->ContextRecord->Rbp));
  305. #else
  306. #error "No target architecture"
  307. #endif
  308. break;
  309. /* modify RIP flags */
  310. case 'f':
  311. {
  312. ULONG ulFlags;
  313. NTSTATUS status;
  314. DWORD dwRipFlags = GetRipFlags();
  315. szT[ARRAY_SIZE(szT) - 1] = 0; /* don't overflow buffer */
  316. status = GetInteger(szT + 1, 16, &ulFlags, NULL);
  317. if (NT_SUCCESS(status)) {
  318. SetRipFlags(ulFlags);
  319. }
  320. KdPrint(("Flags = %.3x\n", (dwRipFlags & RIPF_VALIDUSERFLAGS)));
  321. KdPrint((" Print Process/Component %sabled\n", (dwRipFlags & RIPF_HIDEPID) ? "dis" : "en"));
  322. KdPrint((" Print File/Line %sabled\n", (TEST_RIPF(RIPF_PRINTFILELINE)) ? "en" : "dis"));
  323. KdPrint((" Print on %s\n", szLevels[(dwRipFlags & RIPF_PRINT_MASK) >> RIPF_PRINT_SHIFT]));
  324. KdPrint((" Prompt on %s\n", szLevels[(dwRipFlags & RIPF_PROMPT_MASK) >> RIPF_PROMPT_SHIFT]));
  325. break;
  326. }
  327. /* modify tags */
  328. case 't':
  329. {
  330. NTSTATUS status;
  331. int tag;
  332. LPSTR psz;
  333. DWORD dwDBGTAGFlags;
  334. int i;
  335. int iStart, iEnd;
  336. szT[ARRAY_SIZE(szT) - 1] = 0; /* don't overflow buffer */
  337. status = GetInteger(szT + 1, 10, &tag, &psz);
  338. if (!NT_SUCCESS(status) || tag < 0 || DBGTAG_Max - 1 < tag) {
  339. tag = -1;
  340. } else {
  341. status = GetInteger(psz, 16, &dwDBGTAGFlags, NULL);
  342. if (NT_SUCCESS(status)) {
  343. SetDbgTag(tag, dwDBGTAGFlags);
  344. }
  345. }
  346. KdPrint(("%-5s%-7s%-*s%-*s\n",
  347. "Tag",
  348. "Flags",
  349. DBGTAG_NAMELENGTH,
  350. "Name",
  351. DBGTAG_DESCRIPTIONLENGTH,
  352. "Description"));
  353. for (i = 0; i < 12 + DBGTAG_NAMELENGTH + DBGTAG_DESCRIPTIONLENGTH; i++) {
  354. szT[i] = '-';
  355. }
  356. szT[i++] = '\n';
  357. szT[i] = 0;
  358. KdPrint((szT));
  359. if (tag != -1) {
  360. iStart = iEnd = tag;
  361. } else {
  362. iStart = 0;
  363. iEnd = DBGTAG_Max - 1;
  364. }
  365. for (i = iStart; i <= iEnd; i++) {
  366. KdPrint(("%-5d%-7d%-*s%-*s\n",
  367. i,
  368. GetDbgTagFlags(i) & DBGTAG_VALIDUSERFLAGS,
  369. DBGTAG_NAMELENGTH,
  370. gadbgtag[i].achName,
  371. DBGTAG_DESCRIPTIONLENGTH,
  372. gadbgtag[i].achDescription));
  373. }
  374. break;
  375. }
  376. /* display help */
  377. case '?':
  378. KdPrint(("g - GO, ignore the error and continue execution\n"));
  379. if (pexi != NULL) {
  380. KdPrint(("b - BREAK into the debugger at the location of the exception (part impl.)\n"));
  381. KdPrint(("i - INFO on instruction pointer and stack pointers\n"));
  382. KdPrint(("x - execute cleanup code and KILL the thread by returning EXECUTE_HANDLER\n"));
  383. } else {
  384. KdPrint(("b - BREAK into the debugger at the location of the error (part impl.)\n"));
  385. KdPrint(("w - display the source code location WHERE the error occured\n"));
  386. KdPrint(("x - KILL the offending thread by raising an exception\n"));
  387. }
  388. KdPrint(("p - PRINT this message again\n"));
  389. KdPrint(("f - FLAGS, enter debug flags in format <Detail><Print><Prompt>\n"));
  390. KdPrint((" <Detail> = [0-3] Print File/Line = 1, Hide PID/Component = 2\n"));
  391. KdPrint((" <Print> = [0-7] Errors = 1, Warnings = 2, Verbose = 4\n"));
  392. KdPrint((" <Prompt> = [0-7] Errors = 1, Warnings = 2, Verbose = 4\n"));
  393. KdPrint((" The default is 031\n"));
  394. KdPrint(("t - TAGS, display and modify tag flags\n"));
  395. KdPrint((" no argument displays all tags\n"));
  396. KdPrint((" <tag> displays one tag\n"));
  397. KdPrint((" <tag> <flags> modifies one tag\n"));
  398. KdPrint((" <tag> = 0 - %d\n", DBGTAG_Max - 1));
  399. KdPrint((" <flags> = [0-3] Disabled = 0, Enabled = 1, Print = 2, Prompt = 3\n"));
  400. break;
  401. /* prompt again on bad input */
  402. default:
  403. break;
  404. }
  405. /* Prompt the user */
  406. if (!fPrompt) {
  407. break;
  408. }
  409. if (pexi != NULL) {
  410. DbgPrompt("[gbipft?]", szT, ARRAY_SIZE(szT));
  411. } else {
  412. DbgPrompt("[gbwpft?]", szT, ARRAY_SIZE(szT));
  413. }
  414. }
  415. return fBreak;
  416. }
  417. /***************************************************************************\
  418. * VRipOutput
  419. *
  420. * Formats a variable argument string and calls RipOutput.
  421. *
  422. * History:
  423. * 19-Mar-1996 adams Created.
  424. \***************************************************************************/
  425. ULONG _cdecl VRipOutput(
  426. ULONG idErr,
  427. ULONG flags,
  428. LPSTR pszFile,
  429. int iLine,
  430. LPSTR pszFunction,
  431. LPSTR pszFmt,
  432. ...)
  433. {
  434. char szT[512];
  435. va_list arglist;
  436. va_start(arglist, pszFmt);
  437. _vsnprintf(szT, ARRAY_SIZE(szT) - 1, pszFmt, arglist);
  438. szT[ARRAY_SIZE(szT) - 1] = 0; /* ensure null termination */
  439. va_end(arglist);
  440. return RipOutput(idErr, flags, pszFile, iLine, pszFunction, szT, NULL);
  441. }
  442. /***************************************************************************\
  443. * RipOutput
  444. *
  445. * Sets the last error if it is non-zero, prints a message to
  446. * the debugger, and prompts for more debugging actions.
  447. *
  448. * History:
  449. * 01-23-91 DarrinM Created.
  450. * 04-15-91 DarrinM Added exception handling support.
  451. * 03-19-96 adams Made flags a separate argument, cleanup.
  452. \***************************************************************************/
  453. ULONG RipOutput(
  454. ULONG idErr,
  455. ULONG flags,
  456. LPSTR pszFile,
  457. int iLine,
  458. LPSTR pszFunction,
  459. LPSTR pszErr,
  460. PEXCEPTION_POINTERS pexi)
  461. {
  462. static CONST struct {
  463. LPSTR szLevel;
  464. DWORD dwPrint;
  465. DWORD dwPrompt;
  466. } aLevel[] = {
  467. "?", 0, 0,
  468. "Err", RIPF_PRINTONERROR, RIPF_PROMPTONERROR,
  469. "Wrn", RIPF_PRINTONWARNING, RIPF_PROMPTONWARNING,
  470. "Vrbs", RIPF_PRINTONVERBOSE, RIPF_PROMPTONVERBOSE,
  471. };
  472. int iLevel;
  473. DebugAssertion(flags & RIP_LEVELBITS);
  474. iLevel = ((flags & RIP_LEVELBITS) >> RIP_LEVELBITSSHIFT);
  475. DebugAssertion(!(flags & RIP_USERTAGBITS));
  476. return PrintAndPrompt(
  477. TEST_RIPF(aLevel[iLevel].dwPrint),
  478. TEST_RIPF(aLevel[iLevel].dwPrompt),
  479. idErr,
  480. flags,
  481. aLevel[iLevel].szLevel,
  482. pszFile,
  483. iLine,
  484. pszFunction,
  485. pszErr,
  486. pexi);
  487. }
  488. BOOL _cdecl VTagOutput(
  489. DWORD flags,
  490. LPSTR pszFile,
  491. int iLine,
  492. LPSTR pszFunction,
  493. LPSTR pszFmt,
  494. ...)
  495. {
  496. char szT[512];
  497. va_list arglist;
  498. int tag;
  499. DWORD dwDBGTAGFlags;
  500. tag = (flags & RIP_USERTAGBITS);
  501. DebugAssertion(tag < DBGTAG_Max);
  502. DebugAssertion(!(flags & RIP_LEVELBITS));
  503. dwDBGTAGFlags = GetDbgTagFlags(tag) & DBGTAG_VALIDUSERFLAGS;
  504. if (dwDBGTAGFlags < DBGTAG_PRINT) {
  505. return FALSE;
  506. }
  507. va_start(arglist, pszFmt);
  508. _vsnprintf(szT, ARRAY_SIZE(szT) - 1, pszFmt, arglist);
  509. szT[ARRAY_SIZE(szT) - 1] = 0; /* ensure null termination */
  510. va_end(arglist);
  511. return PrintAndPrompt(
  512. dwDBGTAGFlags >= DBGTAG_PRINT,
  513. dwDBGTAGFlags >= DBGTAG_PROMPT,
  514. 0,
  515. flags,
  516. gadbgtag[tag].achName,
  517. pszFile,
  518. iLine,
  519. pszFunction,
  520. szT,
  521. NULL);
  522. }
  523. #endif
  524. VOID UserSetLastError(
  525. DWORD dwErrCode)
  526. {
  527. /*
  528. * Check if NT Error is directly passed to UserSetLastError.
  529. * Raid #320555 note: some Win32 error could be
  530. * 0x4000XXXX, 0x8000XXXX or 0xC000XXXX etc.,
  531. * but they are still valid. E.g) STATUS_SEGMENT_NOTIFICATION,
  532. * STATUS_GUARD_PAGE_VIOLATION, etc.
  533. *
  534. * The mapper returns the equivalent W32 error value as NT error.
  535. * So we assert only if mapper routine returns the different w32 error code.
  536. */
  537. UserAssert((dwErrCode & 0xffff0000) == 0 || RtlNtStatusToDosError(dwErrCode) == dwErrCode);
  538. try {
  539. NtCurrentTeb()->LastErrorValue = dwErrCode;
  540. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  541. }
  542. }
  543. VOID SetLastNtError(
  544. NTSTATUS Status)
  545. {
  546. UserSetLastError(RtlNtStatusToDosError(Status));
  547. }
  548. #if DBG
  549. VOID ValidateZero(
  550. VOID)
  551. {
  552. static ALWAYSZERO z;
  553. UserAssert(RtlCompareMemory(&z, (void *)&gZero, sizeof(z)) == sizeof(z));
  554. }
  555. #endif
  556. /***************************************************************************\
  557. * W32ExceptionHandler
  558. *
  559. * To be called from except blocks.
  560. *
  561. * History:
  562. * 07-17-98 GerardoB Created.
  563. \***************************************************************************/
  564. ULONG _W32ExceptionHandler(
  565. NTSTATUS ExceptionCode)
  566. {
  567. SetLastNtError(ExceptionCode);
  568. return EXCEPTION_EXECUTE_HANDLER;
  569. }
  570. #if DBG
  571. ULONG DBGW32ExceptionHandler(
  572. PEXCEPTION_POINTERS pexi,
  573. BOOL fSetLastError,
  574. ULONG ulflags)
  575. {
  576. RIPMSG5(ulflags,
  577. "Exception %#x at address %#p. flags:%#x. .exr %#p .cxr %#p",
  578. pexi->ExceptionRecord->ExceptionCode,
  579. CONTEXT_TO_PROGRAM_COUNTER(pexi->ContextRecord),
  580. pexi->ExceptionRecord->ExceptionFlags,
  581. pexi->ExceptionRecord,
  582. pexi->ContextRecord);
  583. if (fSetLastError) {
  584. SetLastNtError(pexi->ExceptionRecord->ExceptionCode);
  585. }
  586. return EXCEPTION_EXECUTE_HANDLER;
  587. }
  588. #endif
  589. #if defined(PRERELEASE) || defined(USER_INSTRUMENTATION)
  590. /*
  591. * UserBreakIfDebugged(): software break point that *may* also be available in FRE.
  592. * Fre: breaks in only if there's a debugger attached.
  593. * Chk: always breaks in.
  594. */
  595. #if DBG
  596. #define UserBreakIfDebugged DbgBreakPoint
  597. #else
  598. #ifdef _USERK_
  599. #define IS_DEBUGGER_ATTACHED KD_DEBUGGER_ENABLED
  600. #else
  601. #define IS_DEBUGGER_ATTACHED IsDebuggerPresent()
  602. #endif
  603. VOID __inline UserBreakIfDebugged(VOID)
  604. {
  605. if (IS_DEBUGGER_ATTACHED) {
  606. DbgBreakPoint();
  607. }
  608. }
  609. #endif
  610. /*
  611. * Called by FRE_RIPMSGx. This is a partial implementation
  612. * of RIPMSGx. In the future (Blackcomb?), we'll revisit
  613. * this to have the fullest support of RIP.
  614. */
  615. VOID FreDbgPrint(
  616. ULONG flags,
  617. LPSTR pszFile,
  618. int iLine,
  619. LPSTR pszFunction,
  620. LPSTR pszFmt,
  621. ...)
  622. {
  623. static BOOL fSuppressFileLine;
  624. va_list arglist;
  625. if (!fSuppressFileLine) {
  626. DbgPrintEx(-1, 0, "File: %s, Line: %d in function %s\n -- ", pszFile, iLine, pszFunction);
  627. } else {
  628. fSuppressFileLine = FALSE;
  629. }
  630. va_start(arglist, pszFmt);
  631. vDbgPrintEx(-1, 0, pszFmt, arglist);
  632. if ((flags & RIP_NONEWLINE) != 0) {
  633. fSuppressFileLine = TRUE;
  634. } else {
  635. DbgPrintEx(-1, 0, "\n");
  636. }
  637. if ((flags & RIP_ERROR) != 0) {
  638. UserBreakIfDebugged();
  639. }
  640. }
  641. #endif