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.

396 lines
10 KiB

  1. /*----------------------------------------------------------------------------
  2. / Title;
  3. / debug.cpp
  4. /
  5. / Authors;
  6. / David De Vorchik (daviddv)
  7. /
  8. / Notes;
  9. / Provides printf style debug output
  10. /----------------------------------------------------------------------------*/
  11. #include "pch.h"
  12. #include "stdio.h"
  13. #pragma hdrstop
  14. #ifdef DSUI_DEBUG
  15. /*-----------------------------------------------------------------------------
  16. / Locals & helper functions
  17. /----------------------------------------------------------------------------*/
  18. LONG g_cDepth = -1;
  19. DWORD g_dwTraceMask = 0;
  20. #define MAX_CALL_DEPTH 64
  21. struct
  22. {
  23. BOOL m_fTracedYet : 1;
  24. LPCTSTR m_pFunctionName;
  25. DWORD m_dwMask;
  26. }
  27. g_CallStack[MAX_CALL_DEPTH];
  28. #define BUFFER_SIZE 4096
  29. static TCHAR szIndentBuffer[BUFFER_SIZE];
  30. static TCHAR szTraceBuffer[BUFFER_SIZE];
  31. /*-----------------------------------------------------------------------------
  32. / _indent
  33. / -------
  34. / Output to the debug stream indented by n columns.
  35. /
  36. / In:
  37. / i = column to indent to.
  38. / pString -> string to be indented
  39. /
  40. / Out:
  41. / -
  42. /----------------------------------------------------------------------------*/
  43. void _indent(LONG i, LPCTSTR pString)
  44. {
  45. szIndentBuffer[0] = TEXT('\0');
  46. wsprintf(szIndentBuffer, TEXT("%08x "), GetCurrentThreadId());
  47. for ( ; i > 0 ; i-- )
  48. StrCat(szIndentBuffer, TEXT(" "));
  49. StrCat(szIndentBuffer, pString);
  50. StrCat(szIndentBuffer, TEXT("\n"));
  51. OutputDebugString(szIndentBuffer);
  52. }
  53. /*-----------------------------------------------------------------------------
  54. / _output_proc_name
  55. / -----------------
  56. / Handle the output of a procedure name, including indenting and handling
  57. / the opening braces.
  58. /
  59. / In:
  60. / iCallDepth = callstack depth, defines the indent and the name index
  61. / to be extracted.
  62. / fOpenBrace = suffix with opening brace.
  63. / Out:
  64. / -
  65. /----------------------------------------------------------------------------*/
  66. void _output_proc_name(LONG iCallDepth)
  67. {
  68. _indent(iCallDepth, g_CallStack[iCallDepth].m_pFunctionName);
  69. }
  70. /*-----------------------------------------------------------------------------
  71. / _trace_prolog
  72. / -------------
  73. / Handle the prolog to a prefix string, including outputting the
  74. / function name if we haven't already.
  75. /
  76. / In:
  77. / iDepth = depth in the call stack
  78. / fForce = ignore flags
  79. /
  80. / Out:
  81. / BOOL if trace output should be made
  82. /----------------------------------------------------------------------------*/
  83. BOOL _trace_prolog(LONG iDepth, BOOL fForce)
  84. {
  85. if ( (g_dwTraceMask & g_CallStack[iDepth].m_dwMask) || fForce )
  86. {
  87. if ( iDepth > 0 )
  88. {
  89. if ( !g_CallStack[iDepth-1].m_fTracedYet )
  90. _trace_prolog(iDepth-1, TRUE);
  91. }
  92. if ( !g_CallStack[iDepth].m_fTracedYet )
  93. {
  94. _output_proc_name(iDepth);
  95. g_CallStack[iDepth].m_fTracedYet = TRUE;
  96. }
  97. return TRUE;
  98. }
  99. return FALSE;
  100. }
  101. /*-----------------------------------------------------------------------------
  102. / DoTraceSetMask
  103. / --------------
  104. / Adjust the trace mask to reflect the state given.
  105. /
  106. / In:
  107. / dwMask = mask for enabling / disable trace output
  108. /
  109. / Out:
  110. / -
  111. /----------------------------------------------------------------------------*/
  112. EXTERN_C void DoTraceSetMask(DWORD dwMask)
  113. {
  114. g_dwTraceMask = dwMask;
  115. }
  116. /*-----------------------------------------------------------------------------
  117. / DoTraceSetMaskFromCLSID
  118. / -----------------------
  119. / Pick up the TraceMask value from the given CLSID value and
  120. / set the trace mask using that.
  121. /
  122. / In:
  123. / clsid = CLSID to query the value from
  124. /
  125. / Out:
  126. / -
  127. /----------------------------------------------------------------------------*/
  128. EXTERN_C void DoTraceSetMaskFromCLSID(REFCLSID rCLSID)
  129. {
  130. DWORD dwTraceMask;
  131. DWORD cbTraceMask = SIZEOF(dwTraceMask);
  132. HKEY hKey = NULL;
  133. if ( SUCCEEDED(GetKeyForCLSID(rCLSID, NULL, &hKey)) )
  134. {
  135. if ( ERROR_SUCCESS == RegQueryValueEx(hKey, TEXT("TraceMask"),
  136. NULL, NULL,
  137. (LPBYTE)&dwTraceMask, &cbTraceMask) )
  138. {
  139. TraceSetMask(dwTraceMask);
  140. }
  141. RegCloseKey(hKey);
  142. }
  143. }
  144. /*-----------------------------------------------------------------------------
  145. / DoTraceEnter
  146. / ------------
  147. / Set the debugging call stack up to indicate which function we are in.
  148. /
  149. / In:
  150. / pName -> function name to be displayed in subsequent trace output.
  151. /
  152. / Out:
  153. / -
  154. /----------------------------------------------------------------------------*/
  155. EXTERN_C void DoTraceEnter(DWORD dwMask, LPCTSTR pName)
  156. {
  157. g_cDepth++;
  158. if ( g_cDepth < MAX_CALL_DEPTH )
  159. {
  160. if ( !pName )
  161. pName = TEXT("<no name>"); // no function name given
  162. g_CallStack[g_cDepth].m_fTracedYet = FALSE;
  163. g_CallStack[g_cDepth].m_pFunctionName = pName;
  164. g_CallStack[g_cDepth].m_dwMask = dwMask;
  165. if ( (g_cDepth > 0) && ( g_cDepth < MAX_CALL_DEPTH ) )
  166. _trace_prolog(g_cDepth-1, FALSE);
  167. }
  168. }
  169. /*-----------------------------------------------------------------------------
  170. / DoTraceLeave
  171. / ------------
  172. / On exit from a function this will adjust the function stack pointer to
  173. / point to our previous function. If no trace output has been made then
  174. / we will output the function name on a single line (to indicate we went somewhere).
  175. /
  176. / In:
  177. / -
  178. / Out:
  179. / -
  180. /----------------------------------------------------------------------------*/
  181. EXTERN_C void DoTraceLeave(void)
  182. {
  183. if ( ( g_cDepth >= 0 ) && ( g_cDepth <= MAX_CALL_DEPTH ) )
  184. _trace_prolog(g_cDepth, FALSE);
  185. if ( !g_cDepth && g_CallStack[0].m_fTracedYet )
  186. OutputDebugString(TEXT("\n"));
  187. g_cDepth = max(g_cDepth-1, -1); // account for underflow
  188. }
  189. /*-----------------------------------------------------------------------------
  190. / DoTraceGetCurrentFn
  191. / -------------------
  192. / Peek the top of the call stack and return the current function name
  193. / pointer, or NULL if not defined.
  194. /
  195. / In:
  196. / Out:
  197. / LPCTSTR
  198. /----------------------------------------------------------------------------*/
  199. EXTERN_C LPCTSTR DoTraceGetCurrentFn(VOID)
  200. {
  201. return g_CallStack[g_cDepth].m_pFunctionName;
  202. }
  203. /*-----------------------------------------------------------------------------
  204. / DoTrace
  205. / -------
  206. / Perform printf formatting to the debugging stream. We indent the output
  207. / and stream the function name as required to give some indication of
  208. / call stack depth.
  209. /
  210. / In:
  211. / pFormat -> printf style formatting string
  212. / ... = arguments as required for the formatting
  213. /
  214. / Out:
  215. / -
  216. /----------------------------------------------------------------------------*/
  217. EXTERN_C void DoTrace(LPCTSTR pFormat, ...)
  218. {
  219. va_list va;
  220. if ( ( g_cDepth >= 0 ) && ( g_cDepth < MAX_CALL_DEPTH ) )
  221. {
  222. if ( _trace_prolog(g_cDepth, FALSE) )
  223. {
  224. va_start(va, pFormat);
  225. wvsprintf(szTraceBuffer, pFormat, va);
  226. va_end(va);
  227. _indent(g_cDepth+1, szTraceBuffer);
  228. }
  229. }
  230. }
  231. /*-----------------------------------------------------------------------------
  232. / DoTraceGuid
  233. / -----------
  234. / Given a GUID output it into the debug string, first we try and map it
  235. / to a name (ie. IShellFolder), if that didn't work then we convert it
  236. / to its human readable form.
  237. /
  238. / In:
  239. / pszPrefix -> prefix string
  240. / lpGuid -> guid to be streamed
  241. /
  242. / Out:
  243. / -
  244. /----------------------------------------------------------------------------*/
  245. #ifdef UNICODE
  246. #define MAP_GUID(x) &x, TEXT(""L#x)
  247. #else
  248. #define MAP_GUID(x) &x, TEXT(""#x)
  249. #endif
  250. #define MAP_GUID2(x,y) MAP_GUID(x), MAP_GUID(y)
  251. const struct
  252. {
  253. const GUID* m_pGUID;
  254. LPCTSTR m_pName;
  255. }
  256. _guid_map[] =
  257. {
  258. MAP_GUID(IID_IUnknown),
  259. MAP_GUID(IID_IClassFactory),
  260. MAP_GUID(IID_IDropTarget),
  261. MAP_GUID(IID_IDataObject),
  262. MAP_GUID(IID_IPersist),
  263. MAP_GUID(IID_IOleWindow),
  264. MAP_GUID2(IID_INewShortcutHookA, IID_INewShortcutHookW),
  265. MAP_GUID(IID_IShellBrowser),
  266. MAP_GUID(IID_IShellView),
  267. MAP_GUID(IID_IContextMenu),
  268. MAP_GUID(IID_IShellIcon),
  269. MAP_GUID(IID_IShellFolder),
  270. MAP_GUID(IID_IShellExtInit),
  271. MAP_GUID(IID_IShellPropSheetExt),
  272. MAP_GUID(IID_IPersistFolder),
  273. MAP_GUID2(IID_IExtractIconA, IID_IExtractIconW),
  274. MAP_GUID2(IID_IShellLinkA, IID_IShellLinkW),
  275. MAP_GUID2(IID_IShellCopyHookA, IID_IShellCopyHookW),
  276. MAP_GUID2(IID_IFileViewerA, IID_IFileViewerW),
  277. MAP_GUID(IID_ICommDlgBrowser),
  278. MAP_GUID(IID_IEnumIDList),
  279. MAP_GUID(IID_IFileViewerSite),
  280. MAP_GUID(IID_IContextMenu2),
  281. MAP_GUID2(IID_IShellExecuteHookA, IID_IShellExecuteHookW),
  282. MAP_GUID(IID_IPropSheetPage),
  283. MAP_GUID(IID_IShellView2),
  284. MAP_GUID(IID_IUniformResourceLocator),
  285. };
  286. EXTERN_C void DoTraceGUID(LPCTSTR pPrefix, REFGUID rGUID)
  287. {
  288. TCHAR szGUID[GUIDSTR_MAX];
  289. TCHAR szBuffer[1024];
  290. LPCTSTR pName = NULL;
  291. int i;
  292. if ( ( g_cDepth >= 0 ) && ( g_cDepth < MAX_CALL_DEPTH ) )
  293. {
  294. if ( _trace_prolog(g_cDepth, FALSE) )
  295. {
  296. for ( i = 0 ; i < ARRAYSIZE(_guid_map); i++ )
  297. {
  298. if ( IsEqualGUID(rGUID, *_guid_map[i].m_pGUID) )
  299. {
  300. pName = _guid_map[i].m_pName;
  301. break;
  302. }
  303. }
  304. if ( !pName )
  305. {
  306. GetStringFromGUID(rGUID, szGUID, ARRAYSIZE(szGUID));
  307. pName = szGUID;
  308. }
  309. wsprintf(szBuffer, TEXT("%s %s"), pPrefix, pName);
  310. _indent(g_cDepth+1, szBuffer);
  311. }
  312. }
  313. }
  314. /*-----------------------------------------------------------------------------
  315. / DoTraceAssert
  316. / -------------
  317. / Our assert handler, out faults it the trace mask as enabled assert
  318. / faulting.
  319. /
  320. / In:
  321. / iLine = line
  322. / pFilename -> filename of the file we asserted in
  323. /
  324. / Out:
  325. / -
  326. /----------------------------------------------------------------------------*/
  327. EXTERN_C void DoTraceAssert(int iLine, LPTSTR pFilename)
  328. {
  329. TCHAR szBuffer[1024];
  330. wsprintf(szBuffer, TEXT("Assert failed in %s, line %d"), pFilename, iLine);
  331. _trace_prolog(g_cDepth, TRUE); // nb: TRUE asserts always displabed
  332. _indent(g_cDepth+1, szBuffer);
  333. if ( g_dwTraceMask & TRACE_COMMON_ASSERT )
  334. DebugBreak();
  335. }
  336. #endif