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.

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