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.

769 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. #if 0 // ndef WIN95
  230. // This is DEADCODE, that is can be potentially used on NT ONLY to
  231. // bring up a debugging prompt. It requires linking with NTDLL.LIB
  232. char szInput[512];
  233. char *pIdx;
  234. int iIdx;
  235. static char szFlagCommands[] = "ahomu";
  236. for (;;)
  237. {
  238. ULONG uLen;
  239. uLen = DbgPrompt("[bgaAFhHmMoOrRuU] ", szInput, sizeof(szInput) - 1);
  240. if (uLen < 2)
  241. {
  242. Out("DbgPrompt failed\n");
  243. DebugBreak();
  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. DebugBreak();
  265. break;
  266. case 'g':
  267. return;
  268. case 'r':
  269. WriteReg();
  270. break;
  271. case 'R':
  272. ReadReg();
  273. break;
  274. case 'a':
  275. case 'A':
  276. case 'h':
  277. case 'H':
  278. case 'm':
  279. case 'M':
  280. case 'o':
  281. case 'O':
  282. case 'u':
  283. case 'U':
  284. char chLower;
  285. if (szInput[0] >= 'A' && szInput[0] <= 'Z')
  286. {
  287. chLower = szInput[0] - 'A' + 'a';
  288. }
  289. else
  290. {
  291. chLower = szInput[0];
  292. }
  293. pIdx = strchr(szFlagCommands, chLower);
  294. if (pIdx == NULL)
  295. {
  296. // Should never happen.
  297. break;
  298. }
  299. iIdx = (int)((ULONG_PTR)(pIdx - szFlagCommands));
  300. if (szInput[0] == chLower)
  301. {
  302. // Set.
  303. m_uFlags[iIdx] = ParseUint(szInput + 1, m_pModFlags[iIdx]);
  304. }
  305. // Set or Get.
  306. OutUint(g_pFlagNames[iIdx], m_pModFlags[iIdx], m_uFlags[iIdx]);
  307. break;
  308. case 'F':
  309. if (uLen < 2)
  310. {
  311. Out("'F' must be followed by a flag group specifier\n");
  312. break;
  313. }
  314. pIdx = strchr(szFlagCommands, szInput[1]);
  315. if (pIdx == NULL)
  316. {
  317. Out("Unknown flag group '%c'\n", szInput[1]);
  318. }
  319. else
  320. {
  321. iIdx = (int)((ULONG_PTR)(pIdx - szFlagCommands));
  322. ShowFlags(g_pFlagNames[iIdx], m_pModFlags[iIdx]);
  323. }
  324. break;
  325. default:
  326. Out("Unknown command '%c'\n", szInput[0]);
  327. break;
  328. }
  329. }
  330. #else
  331. OutUint("OutputMask", m_pModFlags[DBG_OUTPUT_MASK],
  332. m_uFlags[DBG_OUTPUT_MASK]);
  333. Out("Prompt not available\n");
  334. #if DBG
  335. DebugBreak();
  336. #endif
  337. #endif
  338. }
  339. //----------------------------------------------------------------------------
  340. //
  341. // DebugModule::OpenDebugKey
  342. //
  343. // Opens the Direct3D\Debug\m_pModule key.
  344. //
  345. //----------------------------------------------------------------------------
  346. HKEY DebugModule::OpenDebugKey(void)
  347. {
  348. HKEY hKey;
  349. char szKeyName[128];
  350. strcpy(szKeyName, "Software\\Microsoft\\Direct3D\\Debug\\");
  351. strcat(szKeyName, m_pModule);
  352. if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_ALL_ACCESS,
  353. &hKey) != ERROR_SUCCESS)
  354. {
  355. return NULL;
  356. }
  357. else
  358. {
  359. return hKey;
  360. }
  361. }
  362. //----------------------------------------------------------------------------
  363. //
  364. // DebugModule::GetRegUint
  365. //
  366. // Gets a UINT value from the given key.
  367. //
  368. //----------------------------------------------------------------------------
  369. UINT DebugModule::GetRegUint(HKEY hKey, char *pValue, UINT uDefault)
  370. {
  371. DWORD dwType, dwSize;
  372. DWORD dwVal;
  373. dwSize = sizeof(dwVal);
  374. if (RegQueryValueExA(hKey, pValue, NULL, &dwType, (BYTE *)&dwVal,
  375. &dwSize) != ERROR_SUCCESS ||
  376. dwType != REG_DWORD)
  377. {
  378. return uDefault;
  379. }
  380. else
  381. {
  382. return (UINT)dwVal;
  383. }
  384. }
  385. //----------------------------------------------------------------------------
  386. //
  387. // DebugModule::SetRegUint
  388. //
  389. // Sets a UINT value for the given key.
  390. //
  391. //----------------------------------------------------------------------------
  392. BOOL DebugModule::SetRegUint(HKEY hKey, char *pValue, UINT uValue)
  393. {
  394. return RegSetValueExA(hKey, pValue, NULL, REG_DWORD, (BYTE *)&uValue,
  395. sizeof(uValue)) == ERROR_SUCCESS;
  396. }
  397. //----------------------------------------------------------------------------
  398. //
  399. // DebugModule::ReadReg
  400. //
  401. // Reads settings from the registry.
  402. //
  403. //----------------------------------------------------------------------------
  404. void DebugModule::ReadReg(void)
  405. {
  406. HKEY hKey;
  407. hKey = OpenDebugKey();
  408. if (hKey != NULL)
  409. {
  410. int iIdx;
  411. for (iIdx = 0; iIdx < DBG_FLAGS_COUNT; iIdx++)
  412. {
  413. m_uFlags[iIdx] = GetRegUint(hKey, g_pFlagNames[iIdx],
  414. m_uFlags[iIdx]);
  415. }
  416. RegCloseKey(hKey);
  417. }
  418. }
  419. //----------------------------------------------------------------------------
  420. //
  421. // DebugModule::WriteReg
  422. //
  423. // Writes values to the registry.
  424. //
  425. //----------------------------------------------------------------------------
  426. void DebugModule::WriteReg(void)
  427. {
  428. HKEY hKey;
  429. hKey = OpenDebugKey();
  430. if (hKey != NULL)
  431. {
  432. int iIdx;
  433. for (iIdx = 0; iIdx < DBG_FLAGS_COUNT; iIdx++)
  434. {
  435. if (!SetRegUint(hKey, g_pFlagNames[iIdx], m_uFlags[iIdx]))
  436. {
  437. OutputDebugStringA("Error writing registry information\n");
  438. }
  439. }
  440. RegCloseKey(hKey);
  441. }
  442. }
  443. //----------------------------------------------------------------------------
  444. //
  445. // DebugModule::ParseUint
  446. //
  447. // Parses a string for a numeric value or a set of flag strings.
  448. //
  449. //----------------------------------------------------------------------------
  450. UINT DebugModule::ParseUint(char *pString, DebugModuleFlags *pFlags)
  451. {
  452. UINT uVal;
  453. uVal = 0;
  454. for (;;)
  455. {
  456. while (*pString != 0 &&
  457. (*pString == ' ' || *pString == '\t'))
  458. {
  459. pString++;
  460. }
  461. if (*pString == 0)
  462. {
  463. break;
  464. }
  465. char *pEnd;
  466. int iStepAfter;
  467. pEnd = pString;
  468. while (*pEnd != 0 && *pEnd != ' ' && *pEnd != '\t')
  469. {
  470. pEnd++;
  471. }
  472. iStepAfter = *pEnd != 0 ? 1 : 0;
  473. *pEnd = 0;
  474. if (*pString >= '0' && *pString <= '9')
  475. {
  476. uVal |= strtoul(pString, &pString, 0);
  477. if (*pString != 0 && *pString != ' ' && *pString != '\t')
  478. {
  479. Out("Unrecognized characters '%s' after number\n", pString);
  480. }
  481. }
  482. else if (pFlags != NULL)
  483. {
  484. DebugModuleFlags *pFlag;
  485. for (pFlag = pFlags; pFlag->uFlag != 0; pFlag++)
  486. {
  487. if (!_stricmp(pString, pFlag->pName))
  488. {
  489. break;
  490. }
  491. }
  492. if (pFlag->uFlag == 0)
  493. {
  494. Out("Unrecognized flag string '%s'\n", pString);
  495. }
  496. else
  497. {
  498. uVal |= pFlag->uFlag;
  499. }
  500. }
  501. else
  502. {
  503. Out("No flag definitions, unable to convert '%s'\n", pString);
  504. }
  505. pString = pEnd + iStepAfter;
  506. }
  507. return uVal;
  508. }
  509. //----------------------------------------------------------------------------
  510. //
  511. // DebugModule::OutUint
  512. //
  513. // Displays a UINT as a set of flag strings.
  514. //
  515. //----------------------------------------------------------------------------
  516. void DebugModule::OutUint(char *pName, DebugModuleFlags *pFlags, UINT uValue)
  517. {
  518. if (pFlags == NULL || uValue == 0)
  519. {
  520. Out("%s: 0x%08X\n", pName, uValue);
  521. return;
  522. }
  523. Out("%s:", pName);
  524. m_iStartCol = m_iModuleStartCol + strlen(pName) + 1;
  525. m_iCol = m_iStartCol;
  526. while (uValue != 0)
  527. {
  528. DebugModuleFlags *pFlag;
  529. for (pFlag = pFlags; pFlag->uFlag != 0; pFlag++)
  530. {
  531. if ((pFlag->uFlag & uValue) == pFlag->uFlag)
  532. {
  533. AdvanceCols(strlen(pFlag->pName) + 1);
  534. OutMask(DBG_MASK_FORCE_CONT, " %s", pFlag->pName);
  535. uValue &= ~pFlag->uFlag;
  536. break;
  537. }
  538. }
  539. if (pFlag->uFlag == 0)
  540. {
  541. AdvanceCols(11);
  542. OutMask(DBG_MASK_FORCE_CONT, " 0x%X", uValue);
  543. uValue = 0;
  544. }
  545. }
  546. OutVa(DBG_MASK_NO_PREFIX, "\n", NULLVA);
  547. }
  548. //----------------------------------------------------------------------------
  549. //
  550. // DebugModule::AdvanceCols
  551. //
  552. // Determines if there's enough space on the current line for
  553. // the given number of columns. If not, a new line is started.
  554. //
  555. //----------------------------------------------------------------------------
  556. void DebugModule::AdvanceCols(int iCols)
  557. {
  558. static char szSpaces[] = " ";
  559. m_iCol += iCols;
  560. if (m_iCol >= 79)
  561. {
  562. int iSpace;
  563. OutVa(DBG_MASK_NO_PREFIX, "\n", NULLVA);
  564. // Force a prefix to be printed to start the line.
  565. Out("");
  566. m_iCol = m_iModuleStartCol;
  567. while (m_iCol < m_iStartCol)
  568. {
  569. iSpace = (int)min(sizeof(szSpaces) - 1, m_iStartCol - m_iCol);
  570. OutMask(DBG_MASK_FORCE_CONT, "%.*s", iSpace, szSpaces);
  571. m_iCol += iSpace;
  572. }
  573. }
  574. }
  575. //----------------------------------------------------------------------------
  576. //
  577. // DebugModule::ShowFlags
  578. //
  579. // Shows the given flag set.
  580. //
  581. //----------------------------------------------------------------------------
  582. void DebugModule::ShowFlags(char *pName, DebugModuleFlags *pFlags)
  583. {
  584. DebugModuleFlags *pFlag;
  585. Out("%s:\n", pName);
  586. if (pFlags == NULL)
  587. {
  588. Out(" None defined\n");
  589. }
  590. else
  591. {
  592. for (pFlag = pFlags; pFlag->uFlag != 0; pFlag++)
  593. {
  594. Out(" 0x%08X - %s\n", pFlag->uFlag, pFlag->pName);
  595. }
  596. }
  597. }
  598. //----------------------------------------------------------------------------
  599. //
  600. // DebugModule::PathFile
  601. //
  602. // Returns the trailing filename component or NULL if the path is
  603. // only a filename.
  604. //
  605. //----------------------------------------------------------------------------
  606. char *DebugModule::PathFile(char *pPath)
  607. {
  608. char *pFile, *pSlash, *pBack, *pColon;
  609. pBack = strrchr(pPath, '\\');
  610. pSlash = strrchr(pPath, '/');
  611. pColon = strrchr(pPath, ':');
  612. pFile = pBack;
  613. if (pSlash > pFile)
  614. {
  615. pFile = pSlash;
  616. }
  617. if (pColon > pFile)
  618. {
  619. pFile = pColon;
  620. }
  621. return pFile != NULL ? pFile + 1 : NULL;
  622. }
  623. //----------------------------------------------------------------------------
  624. //
  625. // DebugModule::OutPathFile
  626. //
  627. // Outputs the given string plus a path and filename.
  628. // Returns whether the full path was output or not.
  629. //
  630. //----------------------------------------------------------------------------
  631. BOOL DebugModule::OutPathFile(char *pPrefix, UINT uFailureFlags)
  632. {
  633. char *pFile;
  634. if (uFailureFlags & DBG_FAILURE_FILENAME_ONLY)
  635. {
  636. pFile = PathFile(m_pFile);
  637. }
  638. else
  639. {
  640. pFile = NULL;
  641. }
  642. if (pFile == NULL)
  643. {
  644. Out("%s %s(%d)", pPrefix, m_pFile, m_iLine);
  645. return TRUE;
  646. }
  647. else
  648. {
  649. Out("%s <>\\%s(%d)", pPrefix, pFile, m_iLine);
  650. return FALSE;
  651. }
  652. }
  653. //----------------------------------------------------------------------------
  654. //
  655. // Global debug module.
  656. //
  657. //----------------------------------------------------------------------------
  658. DBG_DECLARE_ONCE(Global, G, NULL, 0, NULL, 0);
  659. #endif // #if DBG