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.

771 lines
19 KiB

  1. //----------------------------------------------------------------------------
  2. //
  3. // cppdbg.cpp
  4. //
  5. // C++-only debugging support.
  6. //
  7. // Copyright (C) Microsoft Corporation, 1997.
  8. //
  9. //----------------------------------------------------------------------------
  10. #include "pch.cpp"
  11. #pragma hdrstop
  12. #if DBG
  13. #include "cppdbg.hpp"
  14. #ifdef _ALPHA_
  15. // On Alpha va_list is a structure so it's not compatible with NULL.
  16. static va_list NULLVA;
  17. #else
  18. #define NULLVA NULL
  19. #endif
  20. static DebugModuleFlags g_FailureFlags[] =
  21. {
  22. DBG_DECLARE_MODFLAG(DBG_FAILURE, BREAK),
  23. DBG_DECLARE_MODFLAG(DBG_FAILURE, OUTPUT),
  24. DBG_DECLARE_MODFLAG(DBG_FAILURE, PROMPT),
  25. DBG_DECLARE_MODFLAG(DBG_FAILURE, FILENAME_ONLY),
  26. 0, NULL,
  27. };
  28. static DebugModuleFlags g_OutputFlags[] =
  29. {
  30. DBG_DECLARE_MODFLAG(DBG_OUTPUT, SUPPRESS),
  31. DBG_DECLARE_MODFLAG(DBG_OUTPUT, ALL_MATCH),
  32. 0, NULL,
  33. };
  34. static char *g_pFlagNames[] =
  35. {
  36. "AssertFlags",
  37. "HrFlags",
  38. "OutputFlags",
  39. "OutputMask",
  40. "UserFlags"
  41. };
  42. //----------------------------------------------------------------------------
  43. //
  44. // DebugModule::DebugModule
  45. //
  46. //----------------------------------------------------------------------------
  47. DebugModule::DebugModule(char *pModule, char *pPrefix,
  48. DebugModuleFlags *pOutputMasks, UINT uOutputMask,
  49. DebugModuleFlags *pUserFlags, UINT uUserFlags)
  50. {
  51. m_pModule = pModule;
  52. m_iModuleStartCol = strlen(m_pModule) + 2;
  53. m_pPrefix = pPrefix;
  54. m_pModFlags[DBG_ASSERT_FLAGS] = g_FailureFlags;
  55. m_pModFlags[DBG_HR_FLAGS] = g_FailureFlags;
  56. m_pModFlags[DBG_OUTPUT_FLAGS] = g_OutputFlags;
  57. m_pModFlags[DBG_OUTPUT_MASK] = pOutputMasks;
  58. m_pModFlags[DBG_USER_FLAGS] = pUserFlags;
  59. m_uFlags[DBG_ASSERT_FLAGS] = DBG_FAILURE_OUTPUT | DBG_FAILURE_BREAK |
  60. DBG_FAILURE_FILENAME_ONLY;
  61. m_uFlags[DBG_HR_FLAGS] = DBG_FAILURE_OUTPUT |
  62. DBG_FAILURE_FILENAME_ONLY;
  63. m_uFlags[DBG_OUTPUT_FLAGS] = 0;
  64. m_uFlags[DBG_OUTPUT_MASK] = uOutputMask;
  65. m_uFlags[DBG_USER_FLAGS] = uUserFlags;
  66. ReadReg();
  67. }
  68. //----------------------------------------------------------------------------
  69. //
  70. // DebugModule::OutVa
  71. //
  72. // Base debug output method.
  73. //
  74. //----------------------------------------------------------------------------
  75. void DebugModule::OutVa(UINT uMask, char *pFmt, va_list Args)
  76. {
  77. if (m_uFlags[DBG_OUTPUT_FLAGS] & DBG_OUTPUT_SUPPRESS)
  78. {
  79. return;
  80. }
  81. if ((uMask & DBG_MASK_NO_PREFIX) == 0)
  82. {
  83. OutputDebugStringA(m_pModule);
  84. OutputDebugStringA(": ");
  85. }
  86. char chMsg[1024];
  87. _vsnprintf(chMsg, sizeof(chMsg), pFmt, Args);
  88. OutputDebugStringA(chMsg);
  89. }
  90. //----------------------------------------------------------------------------
  91. //
  92. // DebugModule::Out
  93. //
  94. // Always-output debug output method.
  95. //
  96. //----------------------------------------------------------------------------
  97. void DebugModule::Out(char *pFmt, ...)
  98. {
  99. va_list Args;
  100. va_start(Args, pFmt);
  101. OutVa(0, pFmt, Args);
  102. va_end(Args);
  103. }
  104. //----------------------------------------------------------------------------
  105. //
  106. // DebugModule::AssertFailedVa
  107. //
  108. // Handles assertion failure output and interface.
  109. //
  110. //----------------------------------------------------------------------------
  111. void DebugModule::AssertFailedVa(char *pFmt, va_list Args, BOOL bNewLine)
  112. {
  113. if (m_uFlags[DBG_ASSERT_FLAGS] & DBG_FAILURE_OUTPUT)
  114. {
  115. if (OutPathFile("Assertion failed", m_uFlags[DBG_ASSERT_FLAGS]))
  116. {
  117. OutVa(DBG_MASK_NO_PREFIX, ":\n ", NULLVA);
  118. }
  119. else
  120. {
  121. OutVa(DBG_MASK_NO_PREFIX, ": ", NULLVA);
  122. }
  123. OutVa(DBG_MASK_NO_PREFIX, pFmt, Args);
  124. if (bNewLine)
  125. {
  126. OutVa(DBG_MASK_NO_PREFIX, "\n", NULLVA);
  127. }
  128. }
  129. if (m_uFlags[DBG_ASSERT_FLAGS] & DBG_FAILURE_BREAK)
  130. {
  131. #if DBG
  132. DebugBreak();
  133. #endif
  134. }
  135. else if (m_uFlags[DBG_ASSERT_FLAGS] & DBG_FAILURE_PROMPT)
  136. {
  137. Prompt(NULL);
  138. }
  139. }
  140. //----------------------------------------------------------------------------
  141. //
  142. // DebugModule::AssertFailed
  143. //
  144. // Handles simple expression assertion failures.
  145. //
  146. //----------------------------------------------------------------------------
  147. void DebugModule::AssertFailed(char *pExp)
  148. {
  149. AssertFailedVa(pExp, NULLVA, TRUE);
  150. }
  151. //----------------------------------------------------------------------------
  152. //
  153. // DebugModule::AssertFailedMsg
  154. //
  155. // Handles assertion failures with arbitrary debug output.
  156. //
  157. //----------------------------------------------------------------------------
  158. void DebugModule::AssertFailedMsg(char *pFmt, ...)
  159. {
  160. va_list Args;
  161. va_start(Args, pFmt);
  162. AssertFailedVa(pFmt, Args, FALSE);
  163. va_end(Args);
  164. }
  165. //----------------------------------------------------------------------------
  166. //
  167. // DebugModule::HrFailure
  168. //
  169. // Handles HRESULT failures.
  170. //
  171. //----------------------------------------------------------------------------
  172. void DebugModule::HrFailure(HRESULT hr, char *pPrefix)
  173. {
  174. if (m_uFlags[DBG_HR_FLAGS] & DBG_FAILURE_OUTPUT)
  175. {
  176. OutPathFile(pPrefix, m_uFlags[DBG_HR_FLAGS]);
  177. OutMask(DBG_MASK_FORCE_CONT, ": %s\n", HrString(hr));
  178. }
  179. if (m_uFlags[DBG_HR_FLAGS] & DBG_FAILURE_BREAK)
  180. {
  181. #if DBG
  182. DebugBreak();
  183. #endif
  184. }
  185. else if (m_uFlags[DBG_HR_FLAGS] & DBG_FAILURE_PROMPT)
  186. {
  187. Prompt(NULL);
  188. }
  189. }
  190. //----------------------------------------------------------------------------
  191. //
  192. // DebugModule::HrStmtFailed
  193. //
  194. // Handles statement-style HRESULT failures.
  195. //
  196. //----------------------------------------------------------------------------
  197. void DebugModule::HrStmtFailed(HRESULT hr)
  198. {
  199. HrFailure(hr, "HR test fail");
  200. }
  201. //----------------------------------------------------------------------------
  202. //
  203. // DebugModule::ReturnHr
  204. //
  205. // Handles expression-style HRESULT failures.
  206. //
  207. //----------------------------------------------------------------------------
  208. HRESULT DebugModule::HrExpFailed(HRESULT hr)
  209. {
  210. HrFailure(hr, "HR expr fail");
  211. return hr;
  212. }
  213. //----------------------------------------------------------------------------
  214. //
  215. // DebugModule::Prompt
  216. //
  217. // Allows control over debug options via interactive input.
  218. //
  219. //----------------------------------------------------------------------------
  220. void DebugModule::Prompt(char *pFmt, ...)
  221. {
  222. va_list Args;
  223. if (pFmt != NULL)
  224. {
  225. va_start(Args, pFmt);
  226. OutVa(0, pFmt, Args);
  227. va_end(Args);
  228. }
  229. #ifdef WINNT
  230. char szInput[512];
  231. char *pIdx;
  232. int iIdx;
  233. static char szFlagCommands[] = "ahomu";
  234. for (;;)
  235. {
  236. ULONG uLen;
  237. uLen = DbgPrompt("[bgaAFhHmMoOrRuU] ", szInput, sizeof(szInput) - 1);
  238. if (uLen < 2)
  239. {
  240. Out("DbgPrompt failed\n");
  241. #if DBG
  242. DebugBreak();
  243. #endif
  244. return;
  245. }
  246. // ATTENTION - Currently DbgPrompt returns a length that is two
  247. // greater than the actual number of characters. Presumably this
  248. // is an artifact of the Unicode/ANSI conversion and should
  249. // really only be one greater, so attempt to handle both.
  250. uLen -= 2;
  251. if (szInput[uLen] != 0)
  252. {
  253. uLen++;
  254. szInput[uLen] = 0;
  255. }
  256. if (uLen < 1)
  257. {
  258. Out("Empty command ignored\n");
  259. continue;
  260. }
  261. switch(szInput[0])
  262. {
  263. case 'b':
  264. #if DBG
  265. DebugBreak();
  266. #endif
  267. break;
  268. case 'g':
  269. return;
  270. case 'r':
  271. WriteReg();
  272. break;
  273. case 'R':
  274. ReadReg();
  275. break;
  276. case 'a':
  277. case 'A':
  278. case 'h':
  279. case 'H':
  280. case 'm':
  281. case 'M':
  282. case 'o':
  283. case 'O':
  284. case 'u':
  285. case 'U':
  286. char chLower;
  287. if (szInput[0] >= 'A' && szInput[0] <= 'Z')
  288. {
  289. chLower = szInput[0] - 'A' + 'a';
  290. }
  291. else
  292. {
  293. chLower = szInput[0];
  294. }
  295. pIdx = strchr(szFlagCommands, chLower);
  296. if (pIdx == NULL)
  297. {
  298. // Should never happen.
  299. break;
  300. }
  301. iIdx = (int)((ULONG_PTR)(pIdx - szFlagCommands));
  302. if (szInput[0] == chLower)
  303. {
  304. // Set.
  305. m_uFlags[iIdx] = ParseUint(szInput + 1, m_pModFlags[iIdx]);
  306. }
  307. // Set or Get.
  308. OutUint(g_pFlagNames[iIdx], m_pModFlags[iIdx], m_uFlags[iIdx]);
  309. break;
  310. case 'F':
  311. if (uLen < 2)
  312. {
  313. Out("'F' must be followed by a flag group specifier\n");
  314. break;
  315. }
  316. pIdx = strchr(szFlagCommands, szInput[1]);
  317. if (pIdx == NULL)
  318. {
  319. Out("Unknown flag group '%c'\n", szInput[1]);
  320. }
  321. else
  322. {
  323. iIdx = (int)((ULONG_PTR)(pIdx - szFlagCommands));
  324. ShowFlags(g_pFlagNames[iIdx], m_pModFlags[iIdx]);
  325. }
  326. break;
  327. default:
  328. Out("Unknown command '%c'\n", szInput[0]);
  329. break;
  330. }
  331. }
  332. #else
  333. OutUint("OutputMask", m_pModFlags[DBG_OUTPUT_MASK],
  334. m_uFlags[DBG_OUTPUT_MASK]);
  335. Out("Prompt not available\n");
  336. #if DBG
  337. DebugBreak();
  338. #endif
  339. #endif
  340. }
  341. //----------------------------------------------------------------------------
  342. //
  343. // DebugModule::OpenDebugKey
  344. //
  345. // Opens the Direct3D\Debug\m_pModule key.
  346. //
  347. //----------------------------------------------------------------------------
  348. HKEY DebugModule::OpenDebugKey(void)
  349. {
  350. HKEY hKey;
  351. char szKeyName[128];
  352. strcpy(szKeyName, "Software\\Microsoft\\Direct3D\\Debug\\");
  353. strcat(szKeyName, m_pModule);
  354. if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_ALL_ACCESS,
  355. &hKey) != ERROR_SUCCESS)
  356. {
  357. return NULL;
  358. }
  359. else
  360. {
  361. return hKey;
  362. }
  363. }
  364. //----------------------------------------------------------------------------
  365. //
  366. // DebugModule::GetRegUint
  367. //
  368. // Gets a UINT value from the given key.
  369. //
  370. //----------------------------------------------------------------------------
  371. UINT DebugModule::GetRegUint(HKEY hKey, char *pValue, UINT uDefault)
  372. {
  373. DWORD dwType, dwSize;
  374. DWORD dwVal;
  375. dwSize = sizeof(dwVal);
  376. if (RegQueryValueExA(hKey, pValue, NULL, &dwType, (BYTE *)&dwVal,
  377. &dwSize) != ERROR_SUCCESS ||
  378. dwType != REG_DWORD)
  379. {
  380. return uDefault;
  381. }
  382. else
  383. {
  384. return (UINT)dwVal;
  385. }
  386. }
  387. //----------------------------------------------------------------------------
  388. //
  389. // DebugModule::SetRegUint
  390. //
  391. // Sets a UINT value for the given key.
  392. //
  393. //----------------------------------------------------------------------------
  394. BOOL DebugModule::SetRegUint(HKEY hKey, char *pValue, UINT uValue)
  395. {
  396. return RegSetValueExA(hKey, pValue, NULL, REG_DWORD, (BYTE *)&uValue,
  397. sizeof(uValue)) == ERROR_SUCCESS;
  398. }
  399. //----------------------------------------------------------------------------
  400. //
  401. // DebugModule::ReadReg
  402. //
  403. // Reads settings from the registry.
  404. //
  405. //----------------------------------------------------------------------------
  406. void DebugModule::ReadReg(void)
  407. {
  408. HKEY hKey;
  409. hKey = OpenDebugKey();
  410. if (hKey != NULL)
  411. {
  412. int iIdx;
  413. for (iIdx = 0; iIdx < DBG_FLAGS_COUNT; iIdx++)
  414. {
  415. m_uFlags[iIdx] = GetRegUint(hKey, g_pFlagNames[iIdx],
  416. m_uFlags[iIdx]);
  417. }
  418. RegCloseKey(hKey);
  419. }
  420. }
  421. //----------------------------------------------------------------------------
  422. //
  423. // DebugModule::WriteReg
  424. //
  425. // Writes values to the registry.
  426. //
  427. //----------------------------------------------------------------------------
  428. void DebugModule::WriteReg(void)
  429. {
  430. HKEY hKey;
  431. hKey = OpenDebugKey();
  432. if (hKey != NULL)
  433. {
  434. int iIdx;
  435. for (iIdx = 0; iIdx < DBG_FLAGS_COUNT; iIdx++)
  436. {
  437. if (!SetRegUint(hKey, g_pFlagNames[iIdx], m_uFlags[iIdx]))
  438. {
  439. OutputDebugStringA("Error writing registry information\n");
  440. }
  441. }
  442. RegCloseKey(hKey);
  443. }
  444. }
  445. //----------------------------------------------------------------------------
  446. //
  447. // DebugModule::ParseUint
  448. //
  449. // Parses a string for a numeric value or a set of flag strings.
  450. //
  451. //----------------------------------------------------------------------------
  452. UINT DebugModule::ParseUint(char *pString, DebugModuleFlags *pFlags)
  453. {
  454. UINT uVal;
  455. uVal = 0;
  456. for (;;)
  457. {
  458. while (*pString != 0 &&
  459. (*pString == ' ' || *pString == '\t'))
  460. {
  461. pString++;
  462. }
  463. if (*pString == 0)
  464. {
  465. break;
  466. }
  467. char *pEnd;
  468. int iStepAfter;
  469. pEnd = pString;
  470. while (*pEnd != 0 && *pEnd != ' ' && *pEnd != '\t')
  471. {
  472. pEnd++;
  473. }
  474. iStepAfter = *pEnd != 0 ? 1 : 0;
  475. *pEnd = 0;
  476. if (*pString >= '0' && *pString <= '9')
  477. {
  478. uVal |= strtoul(pString, &pString, 0);
  479. if (*pString != 0 && *pString != ' ' && *pString != '\t')
  480. {
  481. Out("Unrecognized characters '%s' after number\n", pString);
  482. }
  483. }
  484. else if (pFlags != NULL)
  485. {
  486. DebugModuleFlags *pFlag;
  487. for (pFlag = pFlags; pFlag->uFlag != 0; pFlag++)
  488. {
  489. if (!_stricmp(pString, pFlag->pName))
  490. {
  491. break;
  492. }
  493. }
  494. if (pFlag->uFlag == 0)
  495. {
  496. Out("Unrecognized flag string '%s'\n", pString);
  497. }
  498. else
  499. {
  500. uVal |= pFlag->uFlag;
  501. }
  502. }
  503. else
  504. {
  505. Out("No flag definitions, unable to convert '%s'\n", pString);
  506. }
  507. pString = pEnd + iStepAfter;
  508. }
  509. return uVal;
  510. }
  511. //----------------------------------------------------------------------------
  512. //
  513. // DebugModule::OutUint
  514. //
  515. // Displays a UINT as a set of flag strings.
  516. //
  517. //----------------------------------------------------------------------------
  518. void DebugModule::OutUint(char *pName, DebugModuleFlags *pFlags, UINT uValue)
  519. {
  520. if (pFlags == NULL || uValue == 0)
  521. {
  522. Out("%s: 0x%08X\n", pName, uValue);
  523. return;
  524. }
  525. Out("%s:", pName);
  526. m_iStartCol = m_iModuleStartCol + strlen(pName) + 1;
  527. m_iCol = m_iStartCol;
  528. while (uValue != 0)
  529. {
  530. DebugModuleFlags *pFlag;
  531. for (pFlag = pFlags; pFlag->uFlag != 0; pFlag++)
  532. {
  533. if ((pFlag->uFlag & uValue) == pFlag->uFlag)
  534. {
  535. AdvanceCols(strlen(pFlag->pName) + 1);
  536. OutMask(DBG_MASK_FORCE_CONT, " %s", pFlag->pName);
  537. uValue &= ~pFlag->uFlag;
  538. break;
  539. }
  540. }
  541. if (pFlag->uFlag == 0)
  542. {
  543. AdvanceCols(11);
  544. OutMask(DBG_MASK_FORCE_CONT, " 0x%X", uValue);
  545. uValue = 0;
  546. }
  547. }
  548. OutVa(DBG_MASK_NO_PREFIX, "\n", NULLVA);
  549. }
  550. //----------------------------------------------------------------------------
  551. //
  552. // DebugModule::AdvanceCols
  553. //
  554. // Determines if there's enough space on the current line for
  555. // the given number of columns. If not, a new line is started.
  556. //
  557. //----------------------------------------------------------------------------
  558. void DebugModule::AdvanceCols(int iCols)
  559. {
  560. static char szSpaces[] = " ";
  561. m_iCol += iCols;
  562. if (m_iCol >= 79)
  563. {
  564. int iSpace;
  565. OutVa(DBG_MASK_NO_PREFIX, "\n", NULLVA);
  566. // Force a prefix to be printed to start the line.
  567. Out("");
  568. m_iCol = m_iModuleStartCol;
  569. while (m_iCol < m_iStartCol)
  570. {
  571. iSpace = (int)min(sizeof(szSpaces) - 1, m_iStartCol - m_iCol);
  572. OutMask(DBG_MASK_FORCE_CONT, "%.*s", iSpace, szSpaces);
  573. m_iCol += iSpace;
  574. }
  575. }
  576. }
  577. //----------------------------------------------------------------------------
  578. //
  579. // DebugModule::ShowFlags
  580. //
  581. // Shows the given flag set.
  582. //
  583. //----------------------------------------------------------------------------
  584. void DebugModule::ShowFlags(char *pName, DebugModuleFlags *pFlags)
  585. {
  586. DebugModuleFlags *pFlag;
  587. Out("%s:\n", pName);
  588. if (pFlags == NULL)
  589. {
  590. Out(" None defined\n");
  591. }
  592. else
  593. {
  594. for (pFlag = pFlags; pFlag->uFlag != 0; pFlag++)
  595. {
  596. Out(" 0x%08X - %s\n", pFlag->uFlag, pFlag->pName);
  597. }
  598. }
  599. }
  600. //----------------------------------------------------------------------------
  601. //
  602. // DebugModule::PathFile
  603. //
  604. // Returns the trailing filename component or NULL if the path is
  605. // only a filename.
  606. //
  607. //----------------------------------------------------------------------------
  608. char *DebugModule::PathFile(char *pPath)
  609. {
  610. char *pFile, *pSlash, *pBack, *pColon;
  611. pBack = strrchr(pPath, '\\');
  612. pSlash = strrchr(pPath, '/');
  613. pColon = strrchr(pPath, ':');
  614. pFile = pBack;
  615. if (pSlash > pFile)
  616. {
  617. pFile = pSlash;
  618. }
  619. if (pColon > pFile)
  620. {
  621. pFile = pColon;
  622. }
  623. return pFile != NULL ? pFile + 1 : NULL;
  624. }
  625. //----------------------------------------------------------------------------
  626. //
  627. // DebugModule::OutPathFile
  628. //
  629. // Outputs the given string plus a path and filename.
  630. // Returns whether the full path was output or not.
  631. //
  632. //----------------------------------------------------------------------------
  633. BOOL DebugModule::OutPathFile(char *pPrefix, UINT uFailureFlags)
  634. {
  635. char *pFile;
  636. if (uFailureFlags & DBG_FAILURE_FILENAME_ONLY)
  637. {
  638. pFile = PathFile(m_pFile);
  639. }
  640. else
  641. {
  642. pFile = NULL;
  643. }
  644. if (pFile == NULL)
  645. {
  646. Out("%s %s(%d)", pPrefix, m_pFile, m_iLine);
  647. return TRUE;
  648. }
  649. else
  650. {
  651. Out("%s <>\\%s(%d)", pPrefix, pFile, m_iLine);
  652. return FALSE;
  653. }
  654. }
  655. //----------------------------------------------------------------------------
  656. //
  657. // Global debug module.
  658. //
  659. //----------------------------------------------------------------------------
  660. DBG_DECLARE_ONCE(Global, G, NULL, 0, NULL, 0);
  661. #endif // #if DBG