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.

554 lines
12 KiB

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