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.

318 lines
7.9 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1998-1999 Microsoft Corporation
  4. *
  5. * Abstract:
  6. *
  7. * Debugging routines
  8. *
  9. * Revision History:
  10. *
  11. * 09/07/1999 agodfrey
  12. * Created it.
  13. *
  14. \**************************************************************************/
  15. #include "precomp.hpp"
  16. namespace Globals
  17. {
  18. DebugEventProc UserDebugEventProc = NULL;
  19. };
  20. #if DBG
  21. // GpDebugLevel is used to control the amount/severity of debugging messages
  22. // that are actually output.
  23. INT GpDebugLevel = DBG_TERSE;
  24. /**************************************************************************\
  25. *
  26. * Function Description:
  27. *
  28. * Removes the path portion of a pathname
  29. *
  30. * Arguments:
  31. *
  32. * [IN] str - pathname to strip
  33. *
  34. * Return Value:
  35. *
  36. * A pointer to the filename portion of the pathname
  37. *
  38. * History:
  39. *
  40. * 09/07/1999 agodfrey
  41. * Moved from Entry\Initialize.cpp
  42. *
  43. \**************************************************************************/
  44. const CHAR*
  45. StripDirPrefix(
  46. const CHAR* str
  47. )
  48. {
  49. const CHAR* p;
  50. p = strrchr(str, '\\');
  51. return p ? p+1 : str;
  52. }
  53. const int maxInputStringSize = 1024;
  54. /**************************************************************************\
  55. *
  56. * Function Description:
  57. *
  58. * Outputs to the debugger
  59. *
  60. * Arguments:
  61. *
  62. * [IN] format - printf-like format string and variable arguments
  63. *
  64. * Return Value:
  65. *
  66. * Zero. This is to conform to NTDLL's definition of DbgPrint.
  67. *
  68. * Notes:
  69. *
  70. * There will be no output if a debugger is not connected.
  71. *
  72. * History:
  73. *
  74. * 09/07/1999 agodfrey
  75. * Moved from Entry\Initialize.cpp
  76. *
  77. \**************************************************************************/
  78. ULONG _cdecl
  79. DbgPrint(
  80. CHAR* format,
  81. ...
  82. )
  83. {
  84. va_list arglist;
  85. va_start(arglist, format);
  86. char buf[maxInputStringSize];
  87. _vsnprintf(buf, maxInputStringSize, format, arglist);
  88. buf[maxInputStringSize-1]=0;
  89. OutputDebugStringA(buf);
  90. va_end(arglist);
  91. return 0;
  92. }
  93. // If we can't allocate memory for the debug string, we'll use this buffer
  94. // in desperation. It's not thread-safe. I *did* say 'desperation'.
  95. static CHAR desperationBuffer[maxInputStringSize];
  96. /**************************************************************************\
  97. *
  98. * Function Description:
  99. *
  100. * Creates a new string, and sprintf's to it.
  101. *
  102. * Arguments:
  103. *
  104. * [IN] format - printf-like format string and variable arguments
  105. *
  106. * Return Value:
  107. *
  108. * The probably-newly-allocated string result.
  109. *
  110. * Notes:
  111. *
  112. * This function is not intended for general use. It guards against memory
  113. * failure by using a global buffer. So, while the caller is responsible
  114. * for freeing the memory, the caller must also check for that buffer.
  115. * i.e. we only want DbgEmitMessage to call this.
  116. *
  117. * It's also only mostly thread-safe, because if we run out of memory,
  118. * we'll use that global buffer in a non-protected way.
  119. *
  120. * This is the only solution I could find so that I could move most of the
  121. * implementation details out of the header file. The root cause is that
  122. * macros don't handle multiple arguments natively, so we have to pass
  123. * the printf arguments as a single macro argument (in parentheses).
  124. * Which means, the function that consumes those arguments can have no
  125. * other arguments.
  126. *
  127. * History:
  128. *
  129. * 02/01/2000 agodfrey
  130. * Created it. Finally, I've found a way to get debug implementation
  131. * details out of the headers.
  132. *
  133. \**************************************************************************/
  134. CHAR * _cdecl
  135. GpParseDebugString(
  136. CHAR* format,
  137. ...
  138. )
  139. {
  140. va_list arglist;
  141. va_start(arglist, format);
  142. // Don't use GpMalloc here so that we can use ASSERT and WARNING in
  143. // our memory allocation routines.
  144. char *newBuf = static_cast<char *>(LocalAlloc(LMEM_FIXED, maxInputStringSize));
  145. if (!newBuf)
  146. {
  147. newBuf = desperationBuffer;
  148. }
  149. _vsnprintf(newBuf, maxInputStringSize, format, arglist);
  150. // Nuke the last byte, because MSDN isn't clear on what _vsnprintf does
  151. // in that case.
  152. newBuf[maxInputStringSize-1]=0;
  153. va_end(arglist);
  154. return newBuf;
  155. }
  156. /**************************************************************************\
  157. *
  158. * Function Description:
  159. *
  160. * Processes a debug event. Frees the message string.
  161. *
  162. * Arguments:
  163. *
  164. * level - The debug level of the event
  165. * file - Should be __FILE__
  166. * line - Should be __LINE__
  167. * message - The debug message.
  168. *
  169. * Notes:
  170. *
  171. * You don't want to call this directly. That would be error-prone.
  172. * Use ASSERT, WARNING, etc.
  173. *
  174. * Depending on the debug level, an identifying prefix will be output.
  175. *
  176. * If the debug level is DBG_RIP, will suspend execution (e.g. by
  177. * hitting a breakpoint.)
  178. *
  179. * Note on the "debug event" callback:
  180. *
  181. * We optionally pass WARNINGs and ASSERTs to a reporting function
  182. * provided by the user, instead of to the debugger.
  183. * (e.g. their function may pop up a dialog or throw an exception).
  184. * Lesser events will still be sent to the debugger.
  185. *
  186. * History:
  187. *
  188. * 02/01/2000 agodfrey
  189. * Created it.
  190. *
  191. \**************************************************************************/
  192. VOID _cdecl
  193. GpLogDebugEvent(
  194. INT level,
  195. CHAR *file,
  196. UINT line,
  197. CHAR *message
  198. )
  199. {
  200. // We may want to add things to the passed-in message. So we need
  201. // a temporary buffer
  202. const int maxOutputStringSize = maxInputStringSize + 100;
  203. CHAR tempBuffer[maxOutputStringSize+1];
  204. // MSDN's _vsnprintf doc isn't clear on this, so just in case:
  205. tempBuffer[maxOutputStringSize] = 0;
  206. INT callbackEventType = -1;
  207. CHAR *prefix = "";
  208. if (GpDebugLevel <= (level))
  209. {
  210. switch (level)
  211. {
  212. case DBG_WARNING:
  213. prefix = "WRN ";
  214. if (Globals::UserDebugEventProc)
  215. {
  216. callbackEventType = DebugEventLevelWarning;
  217. }
  218. break;
  219. case DBG_RIP:
  220. prefix = "RIP ";
  221. if (Globals::UserDebugEventProc)
  222. {
  223. callbackEventType = DebugEventLevelFatal;
  224. }
  225. break;
  226. }
  227. // The convention is that we append the trailing \n, not the caller.
  228. // Two reasons:
  229. // 1) Callers tend to forget it.
  230. // 2) More importantly, it encourages the caller to think of each
  231. // call as a separate event. This is important in some cases - e.g.
  232. // when the user's "debug event" callback produces a popup for
  233. // each event.
  234. _snprintf(
  235. tempBuffer,
  236. maxOutputStringSize,
  237. "%s%s(%d): %s\n",
  238. prefix,
  239. StripDirPrefix(file),
  240. line,
  241. message
  242. );
  243. if (callbackEventType >= 0)
  244. {
  245. // Wrap the following call in an exception handler in case the
  246. // initial component who set the debug event proc uninitializes
  247. // on another thread, resulting in UserDebugEventProc being set
  248. // to NULL.
  249. __try
  250. {
  251. Globals::UserDebugEventProc((DebugEventLevel) callbackEventType, tempBuffer);
  252. }
  253. __except(EXCEPTION_EXECUTE_HANDLER)
  254. {
  255. OutputDebugStringA(tempBuffer);
  256. }
  257. }
  258. else
  259. {
  260. OutputDebugStringA(tempBuffer);
  261. }
  262. }
  263. // Free the message buffer
  264. if (message != desperationBuffer)
  265. {
  266. LocalFree(message);
  267. }
  268. // Force a breakpoint, if it's warranted.
  269. if ((GpDebugLevel <= DBG_RIP) && (level == DBG_RIP) && (callbackEventType < 0))
  270. {
  271. DebugBreak();
  272. }
  273. }
  274. #endif // DBG