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.

549 lines
12 KiB

  1. /****************************************************************************
  2. Copyright (c) Microsoft Corporation 1997
  3. All rights reserved
  4. File: DEBUG.CPP
  5. Debugging utilities
  6. ***************************************************************************/
  7. #include "pch.h"
  8. DEFINE_MODULE("Debugging");
  9. #ifdef DEBUG
  10. // Constants
  11. #define DEBUG_OUTPUT_BUFFER_SIZE 512
  12. // Globals
  13. DWORD g_TraceMemoryIndex = 0;
  14. DWORD g_dwCounter = 0;
  15. DWORD g_dwTraceFlags = TF_FUNC | TF_CALLS;
  16. // Statics
  17. static const TCHAR g_szNULL[] = TEXT("");
  18. static const TCHAR g_szTrue[] = TEXT("True");
  19. static const TCHAR g_szFalse[] = TEXT("False");
  20. static const TCHAR g_szFormat[] = TEXT("%-40s %-10.10s ");
  21. static const TCHAR g_szUnknown[] = TEXT("<unknown>");
  22. //
  23. // Debugging strrchr( )
  24. //
  25. LPCTSTR
  26. dbgstrrchr( LPCTSTR lpsz, char ch )
  27. {
  28. LPCTSTR psz = lpsz;
  29. while ( *psz )
  30. ++psz;
  31. while ( psz >= lpsz && *psz != ch )
  32. --psz;
  33. return psz;
  34. }
  35. //
  36. // Adds 'g_dwCounter' spaces to debug spew
  37. //
  38. void
  39. dbgspace( void )
  40. {
  41. for( DWORD dw = 1; dw < g_dwCounter; dw++ )
  42. DebugMsg( TEXT("| ") );
  43. }
  44. //
  45. // Takes the filename and line number and put them into a string buffer.
  46. //
  47. // NOTE: the buffer is assumed to be of size DEBUG_OUTPUT_BUFFER_SIZE.
  48. //
  49. LPTSTR
  50. dbgmakefilelinestring(
  51. LPTSTR pszBuf,
  52. LPCTSTR pszFile,
  53. UINT uLine )
  54. {
  55. LPVOID args[2];
  56. args[0] = (LPVOID) pszFile;
  57. args[1] = (LPVOID) uLine;
  58. FormatMessage(
  59. FORMAT_MESSAGE_FROM_STRING |
  60. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  61. TEXT("%1(%2!u!):"),
  62. 0, // error code
  63. 0, // default language
  64. (LPTSTR) pszBuf, // output buffer
  65. DEBUG_OUTPUT_BUFFER_SIZE, // size of buffer
  66. (char**) &args ); // arguments
  67. return pszBuf;
  68. }
  69. //
  70. // TraceMsg()
  71. //
  72. void
  73. TraceMsg(
  74. DWORD dwCheckFlags,
  75. LPCTSTR pszFormat,
  76. ... )
  77. {
  78. va_list valist;
  79. if (( dwCheckFlags == TF_ALWAYS
  80. || !!( g_dwTraceFlags & dwCheckFlags ) ))
  81. {
  82. TCHAR szBuf[ DEBUG_OUTPUT_BUFFER_SIZE ];
  83. va_start( valist, pszFormat );
  84. wvsprintf( szBuf, pszFormat, valist );
  85. va_end( valist );
  86. OutputDebugString( szBuf );
  87. }
  88. }
  89. //
  90. // TraceMessage()
  91. //
  92. void
  93. TraceMessage(
  94. LPCTSTR pszFile,
  95. UINT uLine,
  96. LPCTSTR pszModule,
  97. DWORD dwCheckFlags,
  98. LPCTSTR pszFormat,
  99. ... )
  100. {
  101. va_list valist;
  102. if (( dwCheckFlags == TF_ALWAYS
  103. || !!( g_dwTraceFlags & dwCheckFlags ) ))
  104. {
  105. TCHAR szBuf[ DEBUG_OUTPUT_BUFFER_SIZE ];
  106. if ( !pszModule )
  107. {
  108. pszModule = g_szUnknown;
  109. }
  110. if ( !pszFile )
  111. {
  112. wsprintf( szBuf, g_szFormat, g_szNULL, pszModule );
  113. }
  114. else
  115. {
  116. TCHAR szFileLine[ DEBUG_OUTPUT_BUFFER_SIZE ];
  117. dbgmakefilelinestring( szFileLine, pszFile, uLine );
  118. wsprintf( szBuf, g_szFormat, szFileLine, pszModule );
  119. }
  120. OutputDebugString( szBuf );
  121. dbgspace( );
  122. va_start( valist, pszFormat );
  123. wvsprintf( szBuf, pszFormat, valist );
  124. va_end( valist );
  125. OutputDebugString( szBuf );
  126. }
  127. }
  128. //
  129. // DebugMessage()
  130. //
  131. void
  132. DebugMessage(
  133. LPCTSTR pszFile,
  134. UINT uLine,
  135. LPCTSTR pszModule,
  136. LPCTSTR pszFormat,
  137. ... )
  138. {
  139. va_list valist;
  140. TCHAR szBuf[ DEBUG_OUTPUT_BUFFER_SIZE ];
  141. if ( !pszModule )
  142. {
  143. pszModule = g_szUnknown;
  144. }
  145. if ( !pszFile )
  146. {
  147. wsprintf( szBuf, g_szFormat, g_szNULL, pszModule );
  148. }
  149. else
  150. {
  151. TCHAR szFileLine[ DEBUG_OUTPUT_BUFFER_SIZE ];
  152. dbgmakefilelinestring( szFileLine, pszFile, uLine );
  153. wsprintf( szBuf, g_szFormat, szFileLine, pszModule );
  154. }
  155. OutputDebugString( szBuf );
  156. dbgspace( );
  157. va_start( valist, pszFormat );
  158. wvsprintf( szBuf, pszFormat, valist );
  159. va_end( valist );
  160. OutputDebugString( szBuf );
  161. }
  162. //
  163. // DebugMsg()
  164. //
  165. void
  166. DebugMsg(
  167. LPCTSTR pszFormat,
  168. ... )
  169. {
  170. va_list valist;
  171. TCHAR szBuf[ DEBUG_OUTPUT_BUFFER_SIZE ];
  172. va_start( valist, pszFormat );
  173. wvsprintf( szBuf, pszFormat, valist);
  174. va_end( valist );
  175. OutputDebugString( szBuf );
  176. }
  177. //
  178. // Displays a dialog box with the failed assertion. User has the option of
  179. // breaking.
  180. //
  181. BOOL
  182. AssertMessage(
  183. LPCTSTR pszFile,
  184. UINT uLine,
  185. LPCTSTR pszModule,
  186. LPCTSTR pszfn,
  187. BOOL fTrue )
  188. {
  189. if ( !fTrue )
  190. {
  191. TCHAR szBuf[ DEBUG_OUTPUT_BUFFER_SIZE ];
  192. TCHAR szFileLine[ DEBUG_OUTPUT_BUFFER_SIZE ];
  193. // Make sure everything is cool before we blow up somewhere else.
  194. if ( pszFile == NULL )
  195. {
  196. pszFile = g_szNULL;
  197. }
  198. if ( pszModule == NULL )
  199. {
  200. pszModule = g_szNULL;
  201. }
  202. if ( pszfn == NULL )
  203. {
  204. pszfn = g_szNULL;
  205. }
  206. dbgmakefilelinestring( szFileLine, pszFile, uLine );
  207. wsprintf( szBuf, TEXT("%-40s %-10s ASSERT: %s\n"),
  208. szFileLine, pszModule, pszfn );
  209. OutputDebugString( szBuf );
  210. wsprintf( szBuf, TEXT("Module:\t%s\t\nLine:\t%u\t\nFile:\t%s\t\n\nAssertion:\t%s\t\n\nDo you want to break here?"),
  211. pszModule, uLine, pszFile, pszfn );
  212. if ( IDNO == MessageBox( NULL, szBuf, TEXT("Assertion Failed!"),
  213. MB_YESNO|MB_ICONWARNING ) )
  214. return FALSE; // don't break
  215. }
  216. return !fTrue;
  217. }
  218. //
  219. // Traces HRESULT errors. A dialog will appear is there is an error
  220. // in the hr.
  221. //
  222. HRESULT
  223. TraceHR(
  224. LPCTSTR pszFile,
  225. UINT uLine,
  226. LPCTSTR pszModule,
  227. LPCTSTR pszfn,
  228. HRESULT hr )
  229. {
  230. if ( hr )
  231. {
  232. TCHAR szBuf[ DEBUG_OUTPUT_BUFFER_SIZE ];
  233. TCHAR szFileLine[ DEBUG_OUTPUT_BUFFER_SIZE ];
  234. LPTSTR pszMsgBuf;
  235. switch ( hr )
  236. {
  237. case S_FALSE:
  238. pszMsgBuf = TEXT("S_FALSE\n");
  239. break;
  240. default:
  241. FormatMessage(
  242. FORMAT_MESSAGE_ALLOCATE_BUFFER
  243. | FORMAT_MESSAGE_FROM_SYSTEM,
  244. NULL,
  245. hr,
  246. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  247. (LPTSTR)&pszMsgBuf,
  248. 0,
  249. NULL
  250. );
  251. }
  252. // Make sure everything is cool before we blow up somewhere else.
  253. Assert( pszMsgBuf != NULL );
  254. Assert( pszFile != NULL );
  255. Assert( pszModule != NULL );
  256. Assert( pszfn != NULL );
  257. dbgmakefilelinestring( szFileLine, pszFile, uLine );
  258. wsprintf( szBuf, TEXT("%-40s %-10s HRESULT: hr = 0x%08x - %s"),
  259. szFileLine, pszModule, hr, pszMsgBuf );
  260. OutputDebugString( szBuf );
  261. wsprintf( szBuf, TEXT("Module:\t%s\t\nLine:\t%u\t\nFile:\t%s\t\n\nFunction:\t%s\t\nhr =\t0x%08x - %s\t\nDo you want to break here?"),
  262. pszModule, uLine, pszFile, pszfn, hr, pszMsgBuf );
  263. if ( IDYES == MessageBox( NULL, szBuf, TEXT("Trace HRESULT"),
  264. MB_YESNO|MB_ICONWARNING ) )
  265. DEBUG_BREAK;
  266. LocalFree( pszMsgBuf );
  267. }
  268. return hr;
  269. }
  270. //
  271. // Memory allocation and tracking
  272. //
  273. typedef struct _MEMORYBLOCK {
  274. HGLOBAL hglobal;
  275. DWORD dwBytes;
  276. UINT uFlags;
  277. LPCTSTR pszFile;
  278. UINT uLine;
  279. LPCTSTR pszModule;
  280. LPCTSTR pszComment;
  281. _MEMORYBLOCK *pNext;
  282. } MEMORYBLOCK, *LPMEMORYBLOCK;
  283. //
  284. // Adds a MEMORYBLOCK to the memory tracking list.
  285. //
  286. HGLOBAL
  287. DebugMemoryAdd(
  288. HGLOBAL hglobal,
  289. LPCTSTR pszFile,
  290. UINT uLine,
  291. LPCTSTR pszModule,
  292. UINT uFlags,
  293. DWORD dwBytes,
  294. LPCTSTR pszComment )
  295. {
  296. if ( hglobal )
  297. {
  298. LPMEMORYBLOCK pmbHead = (LPMEMORYBLOCK) TlsGetValue( g_TraceMemoryIndex );
  299. LPMEMORYBLOCK pmb = (LPMEMORYBLOCK) GlobalAlloc(
  300. GMEM_FIXED,
  301. sizeof(MEMORYBLOCK) );
  302. if ( !pmb )
  303. {
  304. GlobalFree( hglobal );
  305. return NULL;
  306. }
  307. pmb->hglobal = hglobal;
  308. pmb->dwBytes = dwBytes;
  309. pmb->uFlags = uFlags;
  310. pmb->pszFile = pszFile;
  311. pmb->uLine = uLine;
  312. pmb->pszModule = pszModule;
  313. pmb->pszComment = pszComment;
  314. pmb->pNext = pmbHead;
  315. TlsSetValue( g_TraceMemoryIndex, pmb );
  316. }
  317. return hglobal;
  318. }
  319. //
  320. // Removes a MEMORYBLOCK to the memory tracking list.
  321. //
  322. void
  323. DebugMemoryDelete(
  324. HGLOBAL hglobal )
  325. {
  326. if ( hglobal )
  327. {
  328. LPMEMORYBLOCK pmbHead = (LPMEMORYBLOCK) TlsGetValue( g_TraceMemoryIndex );
  329. LPMEMORYBLOCK pmbLast = NULL;
  330. while ( pmbHead && pmbHead->hglobal != hglobal )
  331. {
  332. pmbLast = pmbHead;
  333. pmbHead = pmbLast->pNext;
  334. }
  335. if ( pmbHead )
  336. {
  337. if ( pmbLast )
  338. {
  339. pmbLast->pNext = pmbHead->pNext;
  340. }
  341. else
  342. {
  343. TlsSetValue( g_TraceMemoryIndex, pmbHead->pNext );
  344. }
  345. }
  346. }
  347. }
  348. //
  349. // Allocates memory and adds the MEMORYBLOCK to the memory tracking list.
  350. //
  351. HGLOBAL
  352. DebugAlloc(
  353. LPCTSTR pszFile,
  354. UINT uLine,
  355. LPCTSTR pszModule,
  356. UINT uFlags,
  357. DWORD dwBytes,
  358. LPCTSTR pszComment )
  359. {
  360. HGLOBAL hglobal = GlobalAlloc( uFlags, dwBytes );
  361. return DebugMemoryAdd( hglobal, pszFile, uLine, pszModule, uFlags, dwBytes, pszComment );
  362. }
  363. //
  364. // Remove the MEMORYBLOCK to the memory tracking list, memsets the
  365. // memory to 0xFE and then frees the memory.
  366. //
  367. HGLOBAL
  368. DebugFree(
  369. HGLOBAL hglobal )
  370. {
  371. DebugMemoryDelete( hglobal );
  372. return GlobalFree( hglobal );
  373. }
  374. //
  375. // Checks the memory tracking list. If it is not empty, it will dump the
  376. // list and break.
  377. //
  378. void
  379. DebugMemoryCheck( )
  380. {
  381. BOOL fFoundLeak = FALSE;
  382. LPMEMORYBLOCK pmb = (LPMEMORYBLOCK) TlsGetValue( g_TraceMemoryIndex );
  383. while ( pmb )
  384. {
  385. LPVOID args[ 5 ];
  386. TCHAR szOutput[ DEBUG_OUTPUT_BUFFER_SIZE ];
  387. TCHAR szFileLine[ DEBUG_OUTPUT_BUFFER_SIZE ];
  388. if ( fFoundLeak == FALSE )
  389. {
  390. OutputDebugString(TEXT("\n***************************** Memory leak detected *****************************\n\n"));
  391. //OutputDebugString("1234567890123456789012345678901234567890 1234567890 X 0x12345678 12345 1...");
  392. OutputDebugString(TEXT("Filename(Line Number): Module Addr/HGLOBAL Size String\n"));
  393. fFoundLeak = TRUE;
  394. }
  395. args[0] = (LPVOID) pmb->hglobal;
  396. args[1] = (LPVOID) &szFileLine;
  397. args[2] = (LPVOID) pmb->pszComment;
  398. args[3] = (LPVOID) pmb->dwBytes;
  399. args[4] = (LPVOID) pmb->pszModule;
  400. dbgmakefilelinestring( szFileLine, pmb->pszFile, pmb->uLine );
  401. if ( !!(pmb->uFlags & GMEM_MOVEABLE) )
  402. {
  403. FormatMessage(
  404. FORMAT_MESSAGE_FROM_STRING |
  405. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  406. TEXT("%2!-40s! %5!-10s! H 0x%1!08x! %4!-5u! \"%3\"\n"),
  407. 0, // error code
  408. 0, // default language
  409. (LPTSTR) &szOutput, // output buffer
  410. ARRAYSIZE( szOutput ), // size of buffer
  411. (char**) &args ); // arguments
  412. }
  413. else
  414. {
  415. FormatMessage(
  416. FORMAT_MESSAGE_FROM_STRING |
  417. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  418. TEXT("%2!-40s! %5!-10s! A 0x%1!08x! %4!-5u! \"%3\"\n"),
  419. 0, // error code
  420. 0, // default language
  421. (LPTSTR) &szOutput, // output buffer
  422. ARRAYSIZE( szOutput ), // size of buffer
  423. (char**) &args ); // arguments
  424. }
  425. OutputDebugString( szOutput );
  426. pmb = pmb->pNext;
  427. }
  428. if ( fFoundLeak == TRUE )
  429. {
  430. OutputDebugString(TEXT("\n***************************** Memory leak detected *****************************\n\n"));
  431. }
  432. Assert( !fFoundLeak );
  433. }
  434. #endif // DEBUG
  435. //
  436. // Global Management Functions -
  437. //
  438. // These are in debug and retail but are internally they change
  439. // depending on the build.
  440. //
  441. void * __cdecl operator new(unsigned int t_size )
  442. {
  443. return DebugAlloc( TEXT(__FILE__), __LINE__, g_szModule, GPTR, t_size, TEXT("new()") );
  444. }
  445. void __cdecl operator delete(void *pv)
  446. {
  447. TraceFree( pv );
  448. }