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.

547 lines
11 KiB

  1. /*
  2. * debspew.c - Debug spew functions module.
  3. */
  4. /* Headers
  5. **********/
  6. #include "project.h"
  7. #pragma hdrstop
  8. #ifdef DEBUG
  9. /* Types
  10. ********/
  11. /* debug flags */
  12. typedef enum _debugdebugflags
  13. {
  14. DEBUG_DFL_ENABLE_TRACE_MESSAGES = 0x0001,
  15. DEBUG_DFL_LOG_TRACE_MESSAGES = 0x0002,
  16. DEBUG_DFL_DUMP_THREAD_ID = 0x0004,
  17. ALL_DEBUG_DFLAGS = (DEBUG_DFL_ENABLE_TRACE_MESSAGES |
  18. DEBUG_DFL_LOG_TRACE_MESSAGES |
  19. DEBUG_DFL_DUMP_THREAD_ID)
  20. }
  21. DEBUGDEBUGFLAGS;
  22. /* Module Constants
  23. *******************/
  24. #pragma data_seg(DATA_SEG_READ_ONLY)
  25. /* debug message output log file */
  26. PRIVATE_DATA CCHAR s_cszLogFile[] = "debug.log";
  27. #pragma data_seg()
  28. /* Global Variables
  29. *******************/
  30. #pragma data_seg(DATA_SEG_PER_INSTANCE)
  31. /* parameters used by SpewOut() */
  32. PUBLIC_DATA char SrgchSpewLeader[] = " ";
  33. PUBLIC_DATA DWORD g_dwSpewFlags = 0;
  34. PUBLIC_DATA UINT g_uSpewSev = 0;
  35. PUBLIC_DATA UINT g_uSpewLine = 0;
  36. PUBLIC_DATA PCSTR g_pcszSpewFile = NULL;
  37. #pragma data_seg()
  38. /* Module Variables
  39. *******************/
  40. #pragma data_seg(DATA_SEG_PER_INSTANCE)
  41. /* TLS slot used to store stack depth for SpewOut() indentation */
  42. PRIVATE_DATA DWORD s_dwStackDepthSlot = TLS_OUT_OF_INDEXES;
  43. /* hack stack depth counter used until s_dwStackDepthSlot is not available */
  44. PRIVATE_DATA ULONG s_ulcHackStackDepth = 0;
  45. #pragma data_seg(DATA_SEG_SHARED)
  46. /* debug flags */
  47. PRIVATE_DATA DWORD s_dwDebugModuleFlags = 0;
  48. #pragma data_seg(DATA_SEG_READ_ONLY)
  49. /* .ini file switch descriptions */
  50. PRIVATE_DATA CBOOLINISWITCH s_cbisEnableTraceMessages =
  51. {
  52. IST_BOOL,
  53. "EnableTraceMessages",
  54. &s_dwDebugModuleFlags,
  55. DEBUG_DFL_ENABLE_TRACE_MESSAGES
  56. };
  57. PRIVATE_DATA CBOOLINISWITCH s_cbisLogTraceMessages =
  58. {
  59. IST_BOOL,
  60. "LogTraceMessages",
  61. &s_dwDebugModuleFlags,
  62. DEBUG_DFL_LOG_TRACE_MESSAGES
  63. };
  64. PRIVATE_DATA CBOOLINISWITCH s_cbisDumpThreadID =
  65. {
  66. IST_BOOL,
  67. "DumpThreadID",
  68. &s_dwDebugModuleFlags,
  69. DEBUG_DFL_DUMP_THREAD_ID
  70. };
  71. PRIVATE_DATA const PCVOID s_rgcpcvisDebugModule[] =
  72. {
  73. &s_cbisLogTraceMessages,
  74. &s_cbisEnableTraceMessages,
  75. &s_cbisDumpThreadID
  76. };
  77. #pragma data_seg()
  78. /***************************** Private Functions *****************************/
  79. /* Module Prototypes
  80. ********************/
  81. PRIVATE_CODE BOOL LogOutputDebugString(PCSTR);
  82. PRIVATE_CODE BOOL IsValidSpewSev(UINT);
  83. /*
  84. ** LogOutputDebugString()
  85. **
  86. **
  87. **
  88. ** Arguments:
  89. **
  90. ** Returns:
  91. **
  92. ** Side Effects: none
  93. */
  94. PRIVATE_CODE BOOL LogOutputDebugString(PCSTR pcsz)
  95. {
  96. BOOL bResult = FALSE;
  97. UINT ucb;
  98. char rgchLogFile[MAX_PATH_LEN];
  99. ASSERT(IS_VALID_STRING_PTR(pcsz, CSTR));
  100. ucb = GetWindowsDirectory(rgchLogFile, sizeof(rgchLogFile));
  101. if (ucb > 0 && ucb < sizeof(rgchLogFile))
  102. {
  103. HANDLE hfLog;
  104. lstrcat(rgchLogFile, "\\");
  105. lstrcat(rgchLogFile, s_cszLogFile);
  106. hfLog = CreateFile(rgchLogFile, GENERIC_WRITE, 0, NULL, OPEN_ALWAYS,
  107. FILE_FLAG_WRITE_THROUGH, NULL);
  108. if (hfLog != INVALID_HANDLE_VALUE)
  109. {
  110. if (SetFilePointer(hfLog, 0, NULL, FILE_END) != INVALID_SEEK_POSITION)
  111. {
  112. DWORD dwcbWritten;
  113. bResult = WriteFile(hfLog, pcsz, lstrlen(pcsz), &dwcbWritten, NULL);
  114. if (! CloseHandle(hfLog) && bResult)
  115. bResult = FALSE;
  116. }
  117. }
  118. }
  119. return(bResult);
  120. }
  121. /*
  122. ** IsValidSpewSev()
  123. **
  124. **
  125. **
  126. ** Arguments:
  127. **
  128. ** Returns:
  129. **
  130. ** Side Effects: none
  131. */
  132. PRIVATE_CODE BOOL IsValidSpewSev(UINT uSpewSev)
  133. {
  134. BOOL bResult;
  135. switch (uSpewSev)
  136. {
  137. case SPEW_TRACE:
  138. case SPEW_WARNING:
  139. case SPEW_ERROR:
  140. case SPEW_FATAL:
  141. bResult = TRUE;
  142. break;
  143. default:
  144. ERROR_OUT(("IsValidSpewSev(): Invalid debug spew severity %u.",
  145. uSpewSev));
  146. bResult = FALSE;
  147. break;
  148. }
  149. return(bResult);
  150. }
  151. /****************************** Public Functions *****************************/
  152. /*
  153. ** SetDebugModuleIniSwitches()
  154. **
  155. **
  156. **
  157. ** Arguments:
  158. **
  159. ** Returns:
  160. **
  161. ** Side Effects: none
  162. */
  163. PUBLIC_CODE BOOL SetDebugModuleIniSwitches(void)
  164. {
  165. BOOL bResult;
  166. bResult = SetIniSwitches(s_rgcpcvisDebugModule,
  167. ARRAY_ELEMENTS(s_rgcpcvisDebugModule));
  168. ASSERT(FLAGS_ARE_VALID(s_dwDebugModuleFlags, ALL_DEBUG_DFLAGS));
  169. return(bResult);
  170. }
  171. /*
  172. ** InitDebugModule()
  173. **
  174. **
  175. **
  176. ** Arguments:
  177. **
  178. ** Returns:
  179. **
  180. ** Side Effects: none
  181. */
  182. PUBLIC_CODE BOOL InitDebugModule(void)
  183. {
  184. ASSERT(s_dwStackDepthSlot == TLS_OUT_OF_INDEXES);
  185. s_dwStackDepthSlot = TlsAlloc();
  186. if (s_dwStackDepthSlot != TLS_OUT_OF_INDEXES)
  187. {
  188. EVAL(TlsSetValue(s_dwStackDepthSlot, IntToPtr(s_ulcHackStackDepth)));
  189. TRACE_OUT(("InitDebugModule(): Using thread local storage slot %lu for debug stack depth counter.",
  190. s_dwStackDepthSlot));
  191. }
  192. else
  193. WARNING_OUT(("InitDebugModule(): TlsAlloc() failed to allocate thread local storage for debug stack depth counter."));
  194. return(TRUE);
  195. }
  196. /*
  197. ** ExitDebugModule()
  198. **
  199. **
  200. **
  201. ** Arguments:
  202. **
  203. ** Returns:
  204. **
  205. ** Side Effects: none
  206. */
  207. PUBLIC_CODE void ExitDebugModule(void)
  208. {
  209. if (s_dwStackDepthSlot != TLS_OUT_OF_INDEXES)
  210. {
  211. s_ulcHackStackDepth = PtrToUlong(TlsGetValue(s_dwStackDepthSlot));
  212. /* Leave s_ulcHackStackDepth == 0 if TlsGetValue() fails. */
  213. EVAL(TlsFree(s_dwStackDepthSlot));
  214. s_dwStackDepthSlot = TLS_OUT_OF_INDEXES;
  215. }
  216. return;
  217. }
  218. /*
  219. ** StackEnter()
  220. **
  221. **
  222. **
  223. ** Arguments:
  224. **
  225. ** Returns:
  226. **
  227. ** Side Effects: none
  228. */
  229. PUBLIC_CODE void StackEnter(void)
  230. {
  231. if (s_dwStackDepthSlot != TLS_OUT_OF_INDEXES)
  232. {
  233. ULONG ulcDepth;
  234. ulcDepth = PtrToUlong(TlsGetValue(s_dwStackDepthSlot));
  235. ASSERT(ulcDepth < ULONG_MAX);
  236. EVAL(TlsSetValue(s_dwStackDepthSlot, IntToPtr(ulcDepth + 1)));
  237. }
  238. else
  239. {
  240. ASSERT(s_ulcHackStackDepth < ULONG_MAX);
  241. s_ulcHackStackDepth++;
  242. }
  243. return;
  244. }
  245. /*
  246. ** StackLeave()
  247. **
  248. **
  249. **
  250. ** Arguments:
  251. **
  252. ** Returns:
  253. **
  254. ** Side Effects: none
  255. */
  256. PUBLIC_CODE void StackLeave(void)
  257. {
  258. if (s_dwStackDepthSlot != TLS_OUT_OF_INDEXES)
  259. {
  260. ULONG ulcDepth;
  261. ulcDepth = PtrToUlong(TlsGetValue(s_dwStackDepthSlot));
  262. if (EVAL(ulcDepth > 0))
  263. EVAL(TlsSetValue(s_dwStackDepthSlot, IntToPtr(ulcDepth - 1)));
  264. }
  265. else
  266. {
  267. if (EVAL(s_ulcHackStackDepth > 0))
  268. s_ulcHackStackDepth--;
  269. }
  270. return;
  271. }
  272. /*
  273. ** GetStackDepth()
  274. **
  275. **
  276. **
  277. ** Arguments:
  278. **
  279. ** Returns:
  280. **
  281. ** Side Effects: none
  282. */
  283. PUBLIC_CODE ULONG GetStackDepth(void)
  284. {
  285. ULONG ulcDepth;
  286. if (s_dwStackDepthSlot != TLS_OUT_OF_INDEXES)
  287. ulcDepth = PtrToUlong(TlsGetValue(s_dwStackDepthSlot));
  288. else
  289. ulcDepth = s_ulcHackStackDepth;
  290. return(ulcDepth);
  291. }
  292. /*
  293. ** SpewOut()
  294. **
  295. ** Spews out a formatted message to the debug terminal.
  296. **
  297. ** Arguments: pcszFormat - pointer to wvsprintf() format string
  298. ** ... - formatting arguments ala wvsprintf()
  299. **
  300. ** Returns: void
  301. **
  302. ** Side Effects: none
  303. **
  304. ** N.b., this function assumes the global variables g_dwSpewFlags, g_uSpewSev,
  305. ** g_pcszSpewModule, g_pcszSpewFile, and g_pcszSpewLine are filled in.
  306. **
  307. ** SpewOut() uses global variables to set the message parameters in order to
  308. ** permit printf()-style macro expansion.
  309. */
  310. PUBLIC_CODE void SpewOut(PCSTR pcszFormat, ...)
  311. {
  312. ASSERT(IS_VALID_STRING_PTR(pcszFormat, CSTR));
  313. ASSERT(FLAGS_ARE_VALID(g_dwSpewFlags, ALL_SPEW_FLAGS));
  314. ASSERT(IsValidSpewSev(g_uSpewSev));
  315. ASSERT(IS_FLAG_CLEAR(g_dwSpewFlags, SPEW_FL_SPEW_LOCATION) ||
  316. (IS_VALID_STRING_PTR(g_pcszSpewFile, CSTR) &&
  317. IS_VALID_STRING_PTR(g_pcszSpewModule, CSTR)));
  318. if (g_uSpewSev != SPEW_TRACE || IS_FLAG_SET(s_dwDebugModuleFlags, DEBUG_DFL_ENABLE_TRACE_MESSAGES))
  319. {
  320. int nMsgLen;
  321. char rgchMsg[1024];
  322. va_list nextArg;
  323. if (IS_FLAG_SET(g_dwSpewFlags, SPEW_FL_SPEW_PREFIX))
  324. {
  325. ULONG ulcStackDepth;
  326. char chReplaced;
  327. PSTR pszSpewLeaderEnd;
  328. PCSTR pcszSpewPrefix;
  329. /* Build spew message space leader string. */
  330. ulcStackDepth = GetStackDepth();
  331. if (ulcStackDepth < sizeof(SrgchSpewLeader))
  332. pszSpewLeaderEnd = SrgchSpewLeader + ulcStackDepth;
  333. else
  334. pszSpewLeaderEnd = SrgchSpewLeader + sizeof(SrgchSpewLeader) - 1;
  335. chReplaced = *pszSpewLeaderEnd;
  336. *pszSpewLeaderEnd = '\0';
  337. /* Determine spew prefix. */
  338. switch (g_uSpewSev)
  339. {
  340. case SPEW_TRACE:
  341. pcszSpewPrefix = "t";
  342. break;
  343. case SPEW_WARNING:
  344. pcszSpewPrefix = "w";
  345. break;
  346. case SPEW_ERROR:
  347. pcszSpewPrefix = "e";
  348. break;
  349. case SPEW_FATAL:
  350. pcszSpewPrefix = "f";
  351. break;
  352. default:
  353. pcszSpewPrefix = "u";
  354. ERROR_OUT(("SpewOut(): Invalid g_uSpewSev %u.",
  355. g_uSpewSev));
  356. break;
  357. }
  358. nMsgLen = wsprintf(rgchMsg, "%s%s %s ", SrgchSpewLeader, pcszSpewPrefix, g_pcszSpewModule);
  359. /* Restore spew leader. */
  360. *pszSpewLeaderEnd = chReplaced;
  361. ASSERT(nMsgLen < sizeof(rgchMsg));
  362. }
  363. else
  364. nMsgLen = 0;
  365. /* Append thread ID. */
  366. if (IS_FLAG_SET(s_dwDebugModuleFlags, DEBUG_DFL_DUMP_THREAD_ID))
  367. {
  368. nMsgLen += wsprintf(rgchMsg + nMsgLen, "%#lx ", GetCurrentThreadId());
  369. ASSERT(nMsgLen < sizeof(rgchMsg));
  370. }
  371. /* Build position string. */
  372. if (IS_FLAG_SET(g_dwSpewFlags, SPEW_FL_SPEW_LOCATION))
  373. {
  374. nMsgLen += wsprintf(rgchMsg + nMsgLen, "(%s line %u): ", g_pcszSpewFile, g_uSpewLine);
  375. ASSERT(nMsgLen < sizeof(rgchMsg));
  376. }
  377. /* Append message string. */
  378. va_start(nextArg, pcszFormat);
  379. nMsgLen += wvsprintf(rgchMsg + nMsgLen, pcszFormat, nextArg);
  380. va_end(nextArg);
  381. ASSERT(nMsgLen < sizeof(rgchMsg));
  382. if (g_uSpewSev == SPEW_ERROR ||
  383. g_uSpewSev == SPEW_FATAL)
  384. {
  385. nMsgLen += wsprintf(rgchMsg + nMsgLen, " (GetLastError() == %lu)", GetLastError());
  386. ASSERT(nMsgLen < sizeof(rgchMsg));
  387. }
  388. nMsgLen += wsprintf(rgchMsg + nMsgLen, "\r\n");
  389. ASSERT(nMsgLen < sizeof(rgchMsg));
  390. OutputDebugString(rgchMsg);
  391. if (IS_FLAG_SET(s_dwDebugModuleFlags, DEBUG_DFL_LOG_TRACE_MESSAGES))
  392. LogOutputDebugString(rgchMsg);
  393. }
  394. /* Break here on errors and fatal errors. */
  395. #ifndef MAINWIN
  396. if (g_uSpewSev == SPEW_ERROR || g_uSpewSev == SPEW_FATAL)
  397. DebugBreak();
  398. #endif
  399. return;
  400. }
  401. #endif /* DEBUG */