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.

630 lines
15 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. #include <shlwapi.h>
  9. DEFINE_MODULE("Debug");
  10. #ifdef DEBUG
  11. // Constants
  12. #define DEBUG_OUTPUT_BUFFER_SIZE 512
  13. // Globals
  14. DWORD g_TraceMemoryIndex = 0;
  15. DWORD g_dwCounter = 0;
  16. DWORD g_dwTraceFlags = 0;
  17. CRITICAL_SECTION g_DebugCS;
  18. BOOL g_fDebugInitialized = FALSE;
  19. // Statics
  20. const TCHAR g_szNULL[] = TEXT("");
  21. const TCHAR g_szTrue[] = TEXT("True");
  22. const TCHAR g_szFalse[] = TEXT("False");
  23. const TCHAR g_szFormat[] = TEXT("%-50s %-10.10s ");
  24. const TCHAR g_szUnknown[] = TEXT("<unknown>");
  25. //
  26. // Adds 'g_dwCounter' spaces to debug spew
  27. //
  28. void
  29. dbgspace( void )
  30. {
  31. for( DWORD dw = 1; dw < g_dwCounter; dw++ )
  32. DebugMsg( "| " );
  33. }
  34. //
  35. // Makes sure multiple threads don't trample debugging output.
  36. //
  37. void
  38. dbgEnterCS( void )
  39. {
  40. if ( !g_fDebugInitialized )
  41. {
  42. //
  43. // There is NO matching DeleteCriticalSection( ) since
  44. // this is only used for debugging purposes.
  45. //
  46. InitializeCriticalSection( &g_DebugCS );
  47. g_fDebugInitialized = TRUE;
  48. }
  49. EnterCriticalSection( &g_DebugCS );
  50. }
  51. void
  52. dbgExitCS( void )
  53. {
  54. LeaveCriticalSection( &g_DebugCS );
  55. }
  56. //
  57. // Takes the filename and line number and put them into a string buffer.
  58. //
  59. // NOTE: the buffer is assumed to be of size DEBUG_OUTPUT_BUFFER_SIZE.
  60. //
  61. LPTSTR
  62. dbgmakefilelinestring(
  63. LPTSTR pszBuf,
  64. LPCTSTR pszFile,
  65. const int uLine )
  66. {
  67. LPVOID args[2];
  68. args[0] = (LPVOID) pszFile;
  69. args[1] = IntToPtr(uLine);
  70. FormatMessage(
  71. FORMAT_MESSAGE_FROM_STRING |
  72. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  73. TEXT("%1(%2!u!):"),
  74. 0, // error code
  75. 0, // default language
  76. (LPTSTR) pszBuf, // output buffer
  77. DEBUG_OUTPUT_BUFFER_SIZE, // size of buffer
  78. (va_list*) args ); // arguments
  79. return pszBuf;
  80. }
  81. //
  82. // TraceMsg() - ascii
  83. //
  84. void
  85. TraceMsg(
  86. DWORD dwCheckFlags,
  87. LPCSTR pszFormat,
  88. ... )
  89. {
  90. va_list valist;
  91. if (( dwCheckFlags == TF_ALWAYS
  92. || !!( g_dwTraceFlags & dwCheckFlags ) ))
  93. {
  94. TCHAR szBuf[ DEBUG_OUTPUT_BUFFER_SIZE ];
  95. TCHAR szFormat[ DEBUG_OUTPUT_BUFFER_SIZE ];
  96. mbstowcs( szFormat, pszFormat, lstrlenA( pszFormat ) + 1 );
  97. va_start( valist, pszFormat );
  98. wvsprintf( szBuf, szFormat, valist );
  99. va_end( valist );
  100. dbgEnterCS( );
  101. OutputDebugString( szBuf );
  102. dbgExitCS( );
  103. }
  104. }
  105. //
  106. // TraceMessage()
  107. //
  108. void
  109. TraceMessage(
  110. LPCTSTR pszFile,
  111. const int uLine,
  112. LPCTSTR pszModule,
  113. DWORD dwCheckFlags,
  114. LPCTSTR pszFormat,
  115. ... )
  116. {
  117. va_list valist;
  118. if (( dwCheckFlags == TF_ALWAYS
  119. || !!( g_dwTraceFlags & dwCheckFlags ) ))
  120. {
  121. TCHAR szBuf[ DEBUG_OUTPUT_BUFFER_SIZE ];
  122. if ( !pszModule )
  123. {
  124. pszModule = g_szUnknown;
  125. }
  126. if ( !pszFile )
  127. {
  128. wsprintf( szBuf, g_szFormat, g_szNULL, pszModule );
  129. }
  130. else
  131. {
  132. TCHAR szFileLine[ DEBUG_OUTPUT_BUFFER_SIZE ];
  133. dbgmakefilelinestring( szFileLine, pszFile, uLine );
  134. wsprintf( szBuf, g_szFormat, szFileLine, pszModule );
  135. }
  136. dbgEnterCS( );
  137. OutputDebugString( szBuf );
  138. dbgspace( );
  139. va_start( valist, pszFormat );
  140. wvsprintf( szBuf, pszFormat, valist );
  141. va_end( valist );
  142. OutputDebugString( szBuf );
  143. dbgExitCS( );
  144. }
  145. }
  146. //
  147. // DebugMsg()
  148. //
  149. void
  150. DebugMsg(
  151. LPCSTR pszFormat,
  152. ... )
  153. {
  154. va_list valist;
  155. TCHAR szBuf[ DEBUG_OUTPUT_BUFFER_SIZE ];
  156. TCHAR szFormat[ DEBUG_OUTPUT_BUFFER_SIZE ];
  157. mbstowcs( szFormat, pszFormat, lstrlenA( pszFormat ) + 1 );
  158. va_start( valist, pszFormat );
  159. wvsprintf( szBuf, szFormat, valist);
  160. va_end( valist );
  161. dbgEnterCS( );
  162. OutputDebugString( szBuf );
  163. dbgExitCS( );
  164. }
  165. //
  166. // Displays a dialog box with the failed assertion. User has the option of
  167. // breaking.
  168. //
  169. BOOL
  170. AssertMessage(
  171. LPCTSTR pszFile,
  172. const int uLine,
  173. LPCTSTR pszModule,
  174. LPCTSTR pszfn,
  175. BOOL fTrue )
  176. {
  177. if ( !fTrue )
  178. {
  179. TCHAR szBuf[ DEBUG_OUTPUT_BUFFER_SIZE ];
  180. TCHAR szFileLine[ DEBUG_OUTPUT_BUFFER_SIZE ];
  181. // Make sure everything is cool before we blow up somewhere else.
  182. if ( pszFile == NULL )
  183. {
  184. pszFile = g_szNULL;
  185. }
  186. if ( pszModule == NULL )
  187. {
  188. pszModule = g_szNULL;
  189. }
  190. if ( pszfn == NULL )
  191. {
  192. pszfn = g_szNULL;
  193. }
  194. dbgmakefilelinestring( szFileLine, pszFile, uLine );
  195. wsprintf( szBuf, TEXT("%-50s %-10s ASSERT: %s\n"),
  196. szFileLine, pszModule, pszfn );
  197. dbgEnterCS( );
  198. OutputDebugString( szBuf );
  199. dbgExitCS( );
  200. 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?"),
  201. pszModule, uLine, pszFile, pszfn );
  202. if ( IDNO == MessageBox( NULL, szBuf, TEXT("Assertion Failed!"),
  203. MB_YESNO|MB_ICONWARNING ) )
  204. fTrue = !FALSE; // don't break
  205. }
  206. return !fTrue;
  207. }
  208. //
  209. // Traces HRESULT errors. A dialog will appear is there is an error
  210. // in the hr.
  211. //
  212. HRESULT
  213. TraceHR(
  214. LPCTSTR pszFile,
  215. const int uLine,
  216. LPCTSTR pszModule,
  217. LPCTSTR pszfn,
  218. HRESULT hr )
  219. {
  220. static const LPTSTR pcszFalse = TEXT("S_FALSE\n");
  221. if ( !( g_dwTraceFlags & TF_HRESULTS ) )
  222. return hr; // bail
  223. if ( hr != NOERROR )
  224. {
  225. TCHAR szBuf[ DEBUG_OUTPUT_BUFFER_SIZE ];
  226. TCHAR szFileLine[ DEBUG_OUTPUT_BUFFER_SIZE ];
  227. PTSTR pszMsgBuf = NULL;
  228. switch ( hr )
  229. {
  230. case S_FALSE:
  231. pszMsgBuf = pcszFalse;
  232. break;
  233. default:
  234. FormatMessage(
  235. FORMAT_MESSAGE_ALLOCATE_BUFFER
  236. | FORMAT_MESSAGE_FROM_SYSTEM,
  237. NULL,
  238. hr,
  239. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  240. (LPTSTR)&pszMsgBuf,
  241. 0,
  242. NULL
  243. );
  244. }
  245. // Make sure everything is cool before we blow up somewhere else.
  246. if ( pszMsgBuf == NULL )
  247. {
  248. pszMsgBuf = TEXT("<unknown error code returned>\n");
  249. }
  250. Assert( pszFile != NULL );
  251. Assert( pszModule != NULL );
  252. Assert( pszfn != NULL );
  253. dbgmakefilelinestring( szFileLine, pszFile, uLine );
  254. wsprintf( szBuf, TEXT("%-50s %-10s HRESULT: hr = 0x%08x - %s"),
  255. szFileLine, pszModule, hr, pszMsgBuf );
  256. dbgEnterCS( );
  257. OutputDebugString( szBuf );
  258. dbgExitCS( );
  259. 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?"),
  260. pszModule, uLine, pszFile, pszfn, hr, pszMsgBuf );
  261. if ( IDYES == MessageBox( NULL, szBuf, TEXT("Trace HRESULT"),
  262. MB_YESNO|MB_ICONWARNING ) )
  263. DEBUG_BREAK;
  264. if ( pszMsgBuf != pcszFalse ) {
  265. LocalFree( pszMsgBuf );
  266. }
  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. const int 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. TraceMessage( pmb->pszFile,
  317. pmb->uLine,
  318. pmb->pszModule,
  319. TF_MEMORYALLOCS,
  320. L"Alloced %s - %u bytes at 0x%08x (pmb=0x%08x)\n",
  321. pszComment,
  322. dwBytes,
  323. pmb->hglobal,
  324. pmb );
  325. }
  326. return hglobal;
  327. }
  328. //
  329. // Removes a MEMORYBLOCK to the memory tracking list.
  330. //
  331. void
  332. DebugMemoryDelete(
  333. HGLOBAL hglobal )
  334. {
  335. if ( hglobal )
  336. {
  337. LPMEMORYBLOCK pmbHead = (LPMEMORYBLOCK) TlsGetValue( g_TraceMemoryIndex );
  338. LPMEMORYBLOCK pmbLast = NULL;
  339. while ( pmbHead && pmbHead->hglobal != hglobal )
  340. {
  341. pmbLast = pmbHead;
  342. pmbHead = pmbLast->pNext;
  343. }
  344. if ( pmbHead )
  345. {
  346. if ( pmbLast )
  347. {
  348. pmbLast->pNext = pmbHead->pNext;
  349. }
  350. else
  351. {
  352. TlsSetValue( g_TraceMemoryIndex, pmbHead->pNext );
  353. }
  354. TraceMessage( pmbHead->pszFile,
  355. pmbHead->uLine,
  356. pmbHead->pszModule,
  357. TF_MEMORYALLOCS,
  358. L"Freeing %s - %u bytes from 0x%08x (pmb=0x%08x)\n",
  359. pmbHead->pszComment,
  360. pmbHead->dwBytes,
  361. pmbHead->hglobal,
  362. pmbHead );
  363. GlobalFree( pmbHead );
  364. }
  365. else
  366. {
  367. DebugMsg( "\n**** Attempted to free memory at 0x%08x (ThreadID = 0x%08x) ****\n\n",
  368. hglobal, GetCurrentThreadId( ) );
  369. }
  370. }
  371. }
  372. //
  373. // Allocates memory and adds the MEMORYBLOCK to the memory tracking list.
  374. //
  375. HGLOBAL
  376. DebugAlloc(
  377. LPCTSTR pszFile,
  378. const int uLine,
  379. LPCTSTR pszModule,
  380. UINT uFlags,
  381. DWORD dwBytes,
  382. LPCTSTR pszComment )
  383. {
  384. HGLOBAL hglobal = GlobalAlloc( uFlags, dwBytes );
  385. return DebugMemoryAdd( hglobal, pszFile, uLine, pszModule, uFlags, dwBytes, pszComment );
  386. }
  387. //
  388. // Remove the MEMORYBLOCK to the memory tracking list, memsets the
  389. // memory to 0xFE and then frees the memory.
  390. //
  391. HGLOBAL
  392. DebugFree(
  393. HGLOBAL hglobal )
  394. {
  395. DebugMemoryDelete( hglobal );
  396. return GlobalFree( hglobal );
  397. }
  398. //
  399. // Checks the memory tracking list. If it is not empty, it will dump the
  400. // list and break.
  401. //
  402. void
  403. DebugMemoryCheck( )
  404. {
  405. BOOL fFoundLeak = FALSE;
  406. LPMEMORYBLOCK pmb = (LPMEMORYBLOCK) TlsGetValue( g_TraceMemoryIndex );
  407. dbgEnterCS( );
  408. while ( pmb )
  409. {
  410. LPVOID args[ 5 ];
  411. TCHAR szOutput[ DEBUG_OUTPUT_BUFFER_SIZE ];
  412. TCHAR szFileLine[ DEBUG_OUTPUT_BUFFER_SIZE ];
  413. if ( fFoundLeak == FALSE )
  414. {
  415. DebugMsg("\n******** Memory leak detected ******** ThreadID = 0x%08x ******** \n\n", GetCurrentThreadId( ) );
  416. //OutputDebugString("12345678901234567890123456789012345678901234567890 1234567890 X 0x12345678 12345 1...");
  417. OutputDebugString(TEXT("Filename(Line Number): Module Addr/HGLOBAL Size String\n"));
  418. fFoundLeak = TRUE;
  419. }
  420. if ( StrCmp( pmb->pszComment, TEXT("new( )" ) ) == 0 )
  421. {
  422. wsprintf(
  423. szFileLine,
  424. TEXT("Caller unknown - (Module %s, line %d)"),
  425. pmb->pszModule,
  426. pmb->uLine );
  427. }
  428. else
  429. {
  430. dbgmakefilelinestring( szFileLine, pmb->pszFile, pmb->uLine );
  431. }
  432. args[0] = (LPVOID) pmb->hglobal;
  433. args[1] = (LPVOID) szFileLine;
  434. args[2] = (LPVOID) pmb->pszComment;
  435. args[3] = UlongToPtr(pmb->dwBytes);
  436. args[4] = (LPVOID) pmb->pszModule;
  437. if ( !!(pmb->uFlags & GMEM_MOVEABLE) )
  438. {
  439. FormatMessage(
  440. FORMAT_MESSAGE_FROM_STRING |
  441. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  442. TEXT("%2!-50s! %5!-10s! H 0x%1!08x! %4!-5u! \"%3\"\n"),
  443. 0, // error code
  444. 0, // default language
  445. (LPTSTR) szOutput, // output buffer
  446. ARRAYSIZE( szOutput ), // size of buffer
  447. (va_list*) args ); // arguments
  448. }
  449. else
  450. {
  451. FormatMessage(
  452. FORMAT_MESSAGE_FROM_STRING |
  453. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  454. TEXT("%2!-50s! %5!-10s! A 0x%1!08x! %4!-5u! \"%3\"\n"),
  455. 0, // error code
  456. 0, // default language
  457. (LPTSTR) szOutput, // output buffer
  458. ARRAYSIZE( szOutput ), // size of buffer
  459. (va_list*) args ); // arguments
  460. }
  461. OutputDebugString( szOutput );
  462. pmb = pmb->pNext;
  463. }
  464. if ( fFoundLeak == TRUE )
  465. {
  466. OutputDebugString(TEXT("\n***************************** Memory leak detected *****************************\n\n"));
  467. }
  468. dbgExitCS( );
  469. Assert( !fFoundLeak );
  470. }
  471. //
  472. // Global Management Functions -
  473. //
  474. // These are in debug and retail but internally they change
  475. // depending on the build.
  476. //
  477. #undef new
  478. void* __cdecl operator new( size_t nSize, LPCTSTR pszFile, const int iLine, LPCTSTR pszModule )
  479. {
  480. return DebugAlloc( pszFile, iLine, pszModule, GPTR, (DWORD)nSize, TEXT("new( )") );
  481. }
  482. void * __cdecl operator new(size_t t_size )
  483. {
  484. UNREFERENCED_PARAMETER(t_size);
  485. AssertMsg( 0, "Macro failure" );
  486. return NULL;
  487. }
  488. void __cdecl operator delete(void *pv)
  489. {
  490. TraceFree( pv );
  491. }
  492. int __cdecl _purecall(void)
  493. {
  494. return 0;
  495. }
  496. #else // ! DEBUG -- It's retail
  497. //
  498. // Global Management Functions -
  499. //
  500. // These are in debug and retail but are internally they change
  501. // depending on the build.
  502. //
  503. void * __cdecl operator new(size_t t_size )
  504. {
  505. return LocalAlloc( GPTR, t_size );
  506. }
  507. void __cdecl operator delete(void *pv)
  508. {
  509. LocalFree( pv );
  510. }
  511. int __cdecl _purecall(void)
  512. {
  513. return 0;
  514. }
  515. #endif // DEBUG