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.

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