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.

433 lines
11 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. /* File: debug.cpp
  3. Description: Provides debugging macros to support tracing, debugger print
  4. statements, error message debugger output and assertions.
  5. I'm sure you're saying "why ANOTHER debugger output implementation".
  6. There are many around but I haven't found one that is as flexible and
  7. consistent as I would like. This library suports the concept of
  8. both functional "masks" and detail "levels" to control the quantity
  9. of debugger output.
  10. Masks let you control debugger output based on program function. For
  11. instance, if you tag a DBGPRINT statement with the mask DM_XYZ, it
  12. will only be activated if the global variable DebugParams::PrintMask
  13. has the DM_XYZ bit set.
  14. Levels let you control debugger output based on a level of desired
  15. detail. Sometimes you just want to see the basic functions happening
  16. but other times, you need to see everything that's going on. This
  17. leveling allows you to specify at which level a macro is enabled.
  18. The library is designed to be activated with the DBG macro.
  19. If DBG is not defined as 1, there is no trace of this code in your
  20. product.
  21. Revision History:
  22. Date Description Programmer
  23. -------- --------------------------------------------------- ----------
  24. 01/19/98 Replaced with version from CSC cache viewer. BrianAu
  25. */
  26. ///////////////////////////////////////////////////////////////////////////////
  27. #include "pch.h"
  28. #pragma hdrstop
  29. #if DBG
  30. //
  31. // Defaults for the DebugParams members.
  32. // By default, tracing and printing should be silent (no output).
  33. // The default mask values of 0 ensure this.
  34. // Also, printing and tracing are not verbose by default.
  35. // Note that errors and asserts are always active when DBG is defined as 1.
  36. // Errors and asserts are also always verbose.
  37. //
  38. LPCTSTR DebugParams::m_pszModule = TEXT("");
  39. UINT DebugParams::TraceLevel = 0;
  40. UINT DebugParams::PrintLevel = 0;
  41. bool DebugParams::TraceVerbose = false;
  42. bool DebugParams::PrintVerbose = false;
  43. bool DebugParams::TraceOnExit = true;
  44. ULONGLONG DebugParams::TraceMask = 0;
  45. ULONGLONG DebugParams::PrintMask = 0;
  46. //
  47. // Static default values for DebugPrint and DebugTrace classes.
  48. //
  49. const ULONGLONG DebugPrint::DEFMASK = (ULONGLONG)-1;
  50. const UINT DebugPrint::DEFLEVEL = 0;
  51. const ULONGLONG DebugTrace::DEFMASK = (ULONGLONG)-1;
  52. const UINT DebugTrace::DEFLEVEL = 0;
  53. LPCTSTR
  54. DebugParams::SetModule(
  55. LPCTSTR pszModule
  56. )
  57. {
  58. LPCTSTR pszModulePrev = m_pszModule;
  59. m_pszModule = pszModule;
  60. return pszModulePrev;
  61. }
  62. void
  63. DebugParams::SetDebugMask(
  64. ULONGLONG llMask
  65. )
  66. {
  67. TraceMask = PrintMask = llMask;
  68. }
  69. void
  70. DebugParams::SetDebugLevel(
  71. UINT uLevel
  72. )
  73. {
  74. TraceLevel = PrintLevel = uLevel;
  75. }
  76. void
  77. DebugParams::SetDebugVerbose(
  78. bool bVerbose
  79. )
  80. {
  81. TraceVerbose = PrintVerbose = bVerbose;
  82. }
  83. void
  84. DebugParams::SetTraceOnExit(
  85. bool bTrace
  86. )
  87. {
  88. TraceOnExit = bTrace;
  89. }
  90. void *
  91. DebugParams::GetItemPtr(
  92. DebugParams::Item item,
  93. DebugParams::Type type
  94. )
  95. {
  96. //
  97. // Assertions are active for all levels, any program function (mask = -1)
  98. // and are always verbose.
  99. //
  100. static bool bAssertVerbose = true;
  101. static UINT uAssertLevel = 0;
  102. static ULONGLONG llAssertMask = DM_ALL;
  103. //
  104. // This array just eliminates the need for a lot of code when setting
  105. // or reading the various global DebugParam members.
  106. //
  107. static void *rgpMember[eTypeMax][eItemMax] = { { &TraceMask, &TraceLevel, &TraceVerbose },
  108. { &PrintMask, &PrintLevel, &PrintVerbose },
  109. { &llAssertMask, &uAssertLevel, &bAssertVerbose }
  110. };
  111. return rgpMember[type][item];
  112. }
  113. ULONGLONG
  114. DebugParams::SetMask(
  115. ULONGLONG llMask,
  116. DebugParams::Type type
  117. )
  118. {
  119. ULONGLONG *pllMask = (ULONGLONG *)GetItemPtr(DebugParams::eMask, type);
  120. ULONGLONG llMaskPrev = *pllMask;
  121. *pllMask = llMask;
  122. return llMaskPrev;
  123. }
  124. UINT
  125. DebugParams::SetLevel(
  126. UINT uLevel,
  127. DebugParams::Type type
  128. )
  129. {
  130. UINT *puLevel = (UINT *)GetItemPtr(DebugParams::eLevel, type);
  131. UINT uLevelPrev = *puLevel;
  132. *puLevel = uLevel;
  133. return uLevelPrev;
  134. }
  135. bool
  136. DebugParams::SetVerbose(
  137. bool bVerbose,
  138. DebugParams::Type type
  139. )
  140. {
  141. bool *pbVerbose = (bool *)GetItemPtr(DebugParams::eVerbose, type);
  142. bool bVerbosePrev = *pbVerbose;
  143. *pbVerbose = bVerbose;
  144. return bVerbosePrev;
  145. }
  146. DebugTrace::DebugTrace(
  147. LPCTSTR pszFile,
  148. INT iLineNo
  149. ) : m_pszFile(pszFile),
  150. m_iLineNo(iLineNo),
  151. m_llMask(0),
  152. m_uLevel(0)
  153. {
  154. //
  155. // Do nothing.
  156. //
  157. }
  158. void
  159. DebugTrace::Enter(
  160. ULONGLONG llMask,
  161. UINT uLevel,
  162. LPCTSTR pszBlockName
  163. ) const
  164. {
  165. DebugPrint(DebugParams::eTrace, m_pszFile, m_iLineNo).Print(m_llMask = llMask, m_uLevel = uLevel, TEXT("++ ENTER %s"), m_pszBlockName = pszBlockName);
  166. }
  167. void
  168. DebugTrace::Enter(
  169. ULONGLONG llMask,
  170. UINT uLevel,
  171. LPCTSTR pszBlockName,
  172. LPCTSTR pszFmt,
  173. ...
  174. ) const
  175. {
  176. va_list args;
  177. va_start(args, pszFmt);
  178. TCHAR szMsg[1024];
  179. wvsprintf(szMsg, pszFmt, args);
  180. va_end(args);
  181. DebugPrint(DebugParams::eTrace, m_pszFile, m_iLineNo).Print(m_llMask = llMask, m_uLevel = uLevel, TEXT("++ ENTER %s: %s"), m_pszBlockName = pszBlockName, szMsg);
  182. }
  183. void
  184. DebugTrace::Enter(
  185. LPCTSTR pszBlockName
  186. ) const
  187. {
  188. Enter(DebugTrace::DEFMASK, DebugTrace::DEFLEVEL, pszBlockName);
  189. }
  190. void
  191. DebugTrace::Enter(
  192. LPCTSTR pszBlockName,
  193. LPCTSTR pszFmt,
  194. ...
  195. ) const
  196. {
  197. va_list args;
  198. va_start(args, pszFmt);
  199. TCHAR szMsg[1024];
  200. wvsprintf(szMsg, pszFmt, args);
  201. va_end(args);
  202. DebugPrint(DebugParams::eTrace, m_pszFile, m_iLineNo).Print(m_llMask = DebugTrace::DEFMASK, m_uLevel = DebugTrace::DEFLEVEL, TEXT("++ ENTER %s: %s"), m_pszBlockName = pszBlockName, szMsg);
  203. }
  204. DebugTrace::~DebugTrace(void)
  205. {
  206. if (DebugParams::TraceOnExit)
  207. DebugPrint(DebugParams::eTrace, m_pszFile, m_iLineNo).Print(m_llMask, m_uLevel, TEXT("-- LEAVE %s"), m_pszBlockName);
  208. }
  209. DebugPrint::DebugPrint(
  210. DebugParams::Type type,
  211. LPCTSTR pszFile,
  212. INT iLineNo
  213. ) : m_pszFile(pszFile),
  214. m_iLineNo(iLineNo),
  215. m_type(type)
  216. {
  217. //
  218. // Do nothing.
  219. //
  220. }
  221. void
  222. DebugPrint::Print(
  223. LPCTSTR pszFmt,
  224. ...
  225. ) const
  226. {
  227. va_list args;
  228. va_start(args, pszFmt);
  229. Print(DebugPrint::DEFMASK, DebugPrint::DEFLEVEL, pszFmt, args);
  230. va_end(args);
  231. }
  232. void
  233. DebugPrint::Print(
  234. ULONGLONG llMask,
  235. UINT uLevel,
  236. LPCTSTR pszFmt,
  237. ...
  238. ) const
  239. {
  240. va_list args;
  241. va_start(args, pszFmt);
  242. Print(llMask, uLevel, pszFmt, args);
  243. va_end(args);
  244. }
  245. //
  246. // Determine if there are any corresponding bits set in two ULONGLONG
  247. // values. Can't just do a simple bitwise AND operation because the compiler
  248. // truncates the operands to integer size.
  249. //
  250. bool
  251. DebugPrint::AnyBitSet(
  252. ULONGLONG llMask,
  253. ULONGLONG llTest
  254. )
  255. {
  256. ULARGE_INTEGER ulMask, ulTest;
  257. ulMask.QuadPart = llMask;
  258. ulTest.QuadPart = llTest;
  259. return (ulMask.LowPart & ulTest.LowPart) || (ulMask.HighPart & ulTest.HighPart);
  260. }
  261. //
  262. // Internal [private] print function.
  263. // All other print functions end up here.
  264. //
  265. void
  266. DebugPrint::Print(
  267. ULONGLONG llMask,
  268. UINT uLevel,
  269. LPCTSTR pszFmt,
  270. va_list args
  271. ) const
  272. {
  273. //
  274. // Crude check to make sure we haven't overflowed the text buffer.
  275. // It's 1K so I don't expect it. But if we do, it needs to be
  276. // announced somehow so either the buffer can be enlarged or the
  277. // message text reduced. I can't use DBGASSERT because that will
  278. // cause recursion.
  279. //
  280. #define CHECKOVERFLOW \
  281. if (pszWrite >= (pszEnd - 3)) {\
  282. OutputDebugString(TEXT("Buffer overflow in DebugPrint::Print, File:")TEXT(__FILE__)TEXT(" Line:")TEXT("#__LINE__")); \
  283. DebugBreak(); }
  284. //
  285. // Retrieve the global DebugParam members for the "type" being printed.
  286. // i.e. ePrint, eAssert or eTrace.
  287. //
  288. ULONGLONG *pllMask = (ULONGLONG *)DebugParams::GetItemPtr(DebugParams::eMask, m_type);
  289. UINT *puLevel = (UINT *)DebugParams::GetItemPtr(DebugParams::eLevel, m_type);
  290. bool *pbVerbose = (bool *)DebugParams::GetItemPtr(DebugParams::eVerbose, m_type);
  291. if ((uLevel <= *puLevel) && AnyBitSet(llMask, *pllMask))
  292. {
  293. //
  294. // The statement is both "mask" and "level" enabled.
  295. // Generate debugger output.
  296. //
  297. TCHAR szText[1024];
  298. LPTSTR pszWrite = szText;
  299. LPCTSTR pszEnd = pszWrite + ARRAYSIZE(szText);
  300. //
  301. // Each message has "[<module>:<thread>]" prefix.
  302. //
  303. pszWrite += wsprintf(pszWrite,
  304. TEXT("[%s:%d] "),
  305. DebugParams::m_pszModule,
  306. GetCurrentThreadId());
  307. CHECKOVERFLOW;
  308. //
  309. // Append the message text (formatted).
  310. //
  311. pszWrite += wvsprintf(pszWrite, pszFmt, args);
  312. CHECKOVERFLOW;
  313. if (*pbVerbose)
  314. {
  315. //
  316. // Verbose output is desired. Add the filename/line number pair
  317. // indented on the next line.
  318. //
  319. pszWrite += wsprintf(pszWrite, TEXT("\n\r\t+->File: %s, Line: %d"), m_pszFile, m_iLineNo);
  320. }
  321. CHECKOVERFLOW;
  322. //
  323. // Append a CRLF.
  324. //
  325. lstrcpy(pszWrite, TEXT("\n\r"));
  326. OutputDebugString(szText);
  327. }
  328. }
  329. DebugError::DebugError(
  330. LPCTSTR pszFile,
  331. INT iLineNo
  332. ) : DebugPrint(DebugParams::ePrint, pszFile, iLineNo)
  333. {
  334. //
  335. // Do nothing.
  336. //
  337. }
  338. void
  339. DebugError::Error(
  340. LPCTSTR pszFmt,
  341. ...
  342. ) const
  343. {
  344. va_list args;
  345. va_start(args, pszFmt);
  346. ULONGLONG llMaskSaved = DebugParams::PrintMask;
  347. UINT uLevelSaved = DebugParams::PrintLevel;
  348. DebugParams::PrintMask = (ULONGLONG)-1;
  349. DebugParams::PrintLevel = 99999;
  350. Print((ULONGLONG)-1, 0, pszFmt, args);
  351. DebugParams::PrintLevel = uLevelSaved;
  352. DebugParams::PrintMask = llMaskSaved;
  353. va_end(args);
  354. }
  355. DebugAssert::DebugAssert(
  356. LPCTSTR pszFile,
  357. INT iLineNo,
  358. LPCTSTR pszTest
  359. )
  360. {
  361. DebugPrint PrintThis(DebugParams::eAssert, pszFile, iLineNo);
  362. ULONGLONG llMaskSaved = DebugParams::PrintMask;
  363. UINT uLevelSaved = DebugParams::PrintLevel;
  364. DebugParams::PrintMask = (ULONGLONG)-1;
  365. DebugParams::PrintLevel = 99999;
  366. PrintThis.Print((ULONGLONG)-1, 0, pszTest);
  367. DebugParams::PrintLevel = uLevelSaved;
  368. DebugParams::PrintMask = llMaskSaved;
  369. DebugBreak();
  370. }
  371. #endif // DBG