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.

590 lines
14 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("RIPREP")
  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. static const TCHAR g_szNULL[] = TEXT("");
  21. static const TCHAR g_szTrue[] = TEXT("True");
  22. static const TCHAR g_szFalse[] = TEXT("False");
  23. static const TCHAR g_szFormat[] = TEXT("%-50s %-10.10s ");
  24. static 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. OutputDebugStringA( "| " );
  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. // TraceMessage()
  83. //
  84. void
  85. TraceMessage(
  86. LPCTSTR pszFile,
  87. const int uLine,
  88. LPCTSTR pszModule,
  89. DWORD dwCheckFlags,
  90. LPCTSTR pszFormat,
  91. ... )
  92. {
  93. va_list valist;
  94. if (( dwCheckFlags == TF_ALWAYS
  95. || !!( g_dwTraceFlags & dwCheckFlags ) ))
  96. {
  97. TCHAR szBuf[ DEBUG_OUTPUT_BUFFER_SIZE ];
  98. if ( !pszModule )
  99. {
  100. pszModule = g_szUnknown;
  101. }
  102. if ( !pszFile )
  103. {
  104. wsprintf( szBuf, g_szFormat, g_szNULL, pszModule );
  105. TERMINATE_BUFFER(szBuf);
  106. }
  107. else
  108. {
  109. TCHAR szFileLine[ DEBUG_OUTPUT_BUFFER_SIZE ];
  110. dbgmakefilelinestring( szFileLine, pszFile, uLine );
  111. wsprintf( szBuf, g_szFormat, szFileLine, pszModule );
  112. TERMINATE_BUFFER(szBuf);
  113. }
  114. dbgEnterCS( );
  115. OutputDebugString( szBuf );
  116. dbgspace( );
  117. va_start( valist, pszFormat );
  118. wvsprintf( szBuf, pszFormat, valist );
  119. TERMINATE_BUFFER(szBuf);
  120. va_end( valist );
  121. OutputDebugString( szBuf );
  122. dbgExitCS( );
  123. }
  124. }
  125. //
  126. // DebugMsg()
  127. //
  128. void
  129. DebugMsg(
  130. LPCSTR pszFormat,
  131. ... )
  132. {
  133. va_list valist;
  134. TCHAR szBuf[ DEBUG_OUTPUT_BUFFER_SIZE ];
  135. TCHAR szFormat[ DEBUG_OUTPUT_BUFFER_SIZE ];
  136. mbstowcs( szFormat, pszFormat, lstrlenA( pszFormat ) + 1 );
  137. va_start( valist, pszFormat );
  138. wvsprintf( szBuf, szFormat, valist);
  139. va_end( valist );
  140. dbgEnterCS( );
  141. OutputDebugString( szBuf );
  142. dbgExitCS( );
  143. }
  144. //
  145. // Displays a dialog box with the failed assertion. User has the option of
  146. // breaking.
  147. //
  148. BOOL
  149. AssertMessage(
  150. LPCTSTR pszFile,
  151. const int uLine,
  152. LPCTSTR pszModule,
  153. LPCTSTR pszfn,
  154. BOOL fTrue )
  155. {
  156. if ( !fTrue )
  157. {
  158. TCHAR szBuf[ DEBUG_OUTPUT_BUFFER_SIZE ];
  159. TCHAR szFileLine[ DEBUG_OUTPUT_BUFFER_SIZE ];
  160. // Make sure everything is cool before we blow up somewhere else.
  161. if ( pszFile == NULL )
  162. {
  163. pszFile = g_szNULL;
  164. }
  165. if ( pszModule == NULL )
  166. {
  167. pszModule = g_szNULL;
  168. }
  169. if ( pszfn == NULL )
  170. {
  171. pszfn = g_szNULL;
  172. }
  173. dbgmakefilelinestring( szFileLine, pszFile, uLine );
  174. wsprintf( szBuf, TEXT("%-50s %-10s ASSERT: %s\n"),
  175. szFileLine, pszModule, pszfn );
  176. dbgEnterCS( );
  177. OutputDebugString( szBuf );
  178. dbgExitCS( );
  179. 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?"),
  180. pszModule, uLine, pszFile, pszfn );
  181. TERMINATE_BUFFER(szBuf);
  182. if ( IDNO == MessageBox( NULL, szBuf, TEXT("Assertion Failed!"),
  183. MB_YESNO|MB_ICONWARNING ) )
  184. fTrue = !FALSE; // don't break
  185. }
  186. return !fTrue;
  187. }
  188. //
  189. // Traces HRESULT errors. A dialog will appear is there is an error
  190. // in the hr.
  191. //
  192. HRESULT
  193. TraceHR(
  194. LPCTSTR pszFile,
  195. const int uLine,
  196. LPCTSTR pszModule,
  197. LPCTSTR pszfn,
  198. HRESULT hr )
  199. {
  200. if ( hr )
  201. {
  202. TCHAR szBuf[ DEBUG_OUTPUT_BUFFER_SIZE ];
  203. TCHAR szFileLine[ DEBUG_OUTPUT_BUFFER_SIZE ];
  204. LPTSTR pszMsgBuf;
  205. switch ( hr )
  206. {
  207. case S_FALSE:
  208. pszMsgBuf = TEXT("S_FALSE\n");
  209. break;
  210. default:
  211. FormatMessage(
  212. FORMAT_MESSAGE_ALLOCATE_BUFFER
  213. | FORMAT_MESSAGE_FROM_SYSTEM,
  214. NULL,
  215. hr,
  216. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  217. (LPTSTR)&pszMsgBuf,
  218. 0,
  219. NULL
  220. );
  221. }
  222. // Make sure everything is cool before we blow up somewhere else.
  223. if ( pszMsgBuf == NULL )
  224. {
  225. pszMsgBuf = TEXT("<unknown error code returned>\n");
  226. }
  227. Assert( pszFile != NULL );
  228. Assert( pszModule != NULL );
  229. Assert( pszfn != NULL );
  230. dbgmakefilelinestring( szFileLine, pszFile, uLine );
  231. _snwprintf( szBuf, ARRAYSIZE(szBuf), TEXT("%-50s %-10s HRESULT: hr = 0x%08x - %s"),
  232. szFileLine, pszModule, hr, pszMsgBuf );
  233. TERMINATE_BUFFER(szBuf);
  234. dbgEnterCS( );
  235. OutputDebugString( szBuf );
  236. dbgExitCS( );
  237. _snwprintf( szBuf, ARRAYSIZE(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?"),
  238. pszModule, uLine, pszFile, pszfn, hr, pszMsgBuf );
  239. TERMINATE_BUFFER(szBuf);
  240. if ( IDYES == MessageBox( NULL, szBuf, TEXT("Trace HRESULT"),
  241. MB_YESNO|MB_ICONWARNING ) )
  242. DEBUG_BREAK;
  243. if ( hr != S_OK && hr != S_FALSE )
  244. {
  245. LocalFree( pszMsgBuf );
  246. }
  247. }
  248. return hr;
  249. }
  250. //
  251. // Memory allocation and tracking
  252. //
  253. typedef struct _MEMORYBLOCK {
  254. HGLOBAL hglobal;
  255. DWORD dwBytes;
  256. UINT uFlags;
  257. LPCTSTR pszFile;
  258. int uLine;
  259. LPCTSTR pszModule;
  260. LPCTSTR pszComment;
  261. _MEMORYBLOCK *pNext;
  262. } MEMORYBLOCK, *LPMEMORYBLOCK;
  263. //
  264. // Adds a MEMORYBLOCK to the memory tracking list.
  265. //
  266. HGLOBAL
  267. DebugMemoryAdd(
  268. HGLOBAL hglobal,
  269. LPCTSTR pszFile,
  270. const int uLine,
  271. LPCTSTR pszModule,
  272. UINT uFlags,
  273. DWORD dwBytes,
  274. LPCTSTR pszComment )
  275. {
  276. if ( hglobal )
  277. {
  278. LPMEMORYBLOCK pmbHead = (LPMEMORYBLOCK) TlsGetValue( g_TraceMemoryIndex );
  279. LPMEMORYBLOCK pmb = (LPMEMORYBLOCK) GlobalAlloc(
  280. GMEM_FIXED,
  281. sizeof(MEMORYBLOCK) );
  282. if ( !pmb )
  283. {
  284. GlobalFree( hglobal );
  285. return NULL;
  286. }
  287. pmb->hglobal = hglobal;
  288. pmb->dwBytes = dwBytes;
  289. pmb->uFlags = uFlags;
  290. pmb->pszFile = pszFile;
  291. pmb->uLine = uLine;
  292. pmb->pszModule = pszModule;
  293. pmb->pszComment = pszComment;
  294. pmb->pNext = pmbHead;
  295. TlsSetValue( g_TraceMemoryIndex, pmb );
  296. TraceMessage( pmb->pszFile,
  297. pmb->uLine,
  298. pmb->pszModule,
  299. TF_MEMORYALLOCS,
  300. L"Alloced %s - %u bytes at 0x%08x (pmb=0x%08x)\n",
  301. pszComment,
  302. dwBytes,
  303. pmb->hglobal,
  304. pmb );
  305. }
  306. return hglobal;
  307. }
  308. //
  309. // Removes a MEMORYBLOCK to the memory tracking list.
  310. //
  311. void
  312. DebugMemoryDelete(
  313. HGLOBAL hglobal )
  314. {
  315. if ( hglobal )
  316. {
  317. LPMEMORYBLOCK pmbHead = (LPMEMORYBLOCK) TlsGetValue( g_TraceMemoryIndex );
  318. LPMEMORYBLOCK pmbLast = NULL;
  319. while ( pmbHead && pmbHead->hglobal != hglobal )
  320. {
  321. pmbLast = pmbHead;
  322. pmbHead = pmbLast->pNext;
  323. }
  324. if ( pmbHead )
  325. {
  326. if ( pmbLast )
  327. {
  328. pmbLast->pNext = pmbHead->pNext;
  329. }
  330. else
  331. {
  332. TlsSetValue( g_TraceMemoryIndex, pmbHead->pNext );
  333. }
  334. TraceMessage( pmbHead->pszFile,
  335. pmbHead->uLine,
  336. pmbHead->pszModule,
  337. TF_MEMORYALLOCS,
  338. L"Freeing %s - %u bytes from 0x%08x (pmb=0x%08x)\n",
  339. pmbHead->pszComment,
  340. pmbHead->dwBytes,
  341. pmbHead->hglobal,
  342. pmbHead );
  343. memset( pmbHead->hglobal, 0xFA, pmbHead->dwBytes );
  344. memset( pmbHead, 0xFE, sizeof(*pmbHead) );
  345. GlobalFree( pmbHead );
  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. const int 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. dbgEnterCS( );
  385. while ( pmb )
  386. {
  387. LPVOID args[ 5 ];
  388. TCHAR szOutput[ DEBUG_OUTPUT_BUFFER_SIZE ];
  389. TCHAR szFileLine[ DEBUG_OUTPUT_BUFFER_SIZE ];
  390. if ( fFoundLeak == FALSE )
  391. {
  392. DebugMsg("\n******** Memory leak detected ******** ThreadID = 0x%08x ******** \n\n", GetCurrentThreadId( ) );
  393. //OutputDebugString("12345678901234567890123456789012345678901234567890 1234567890 X 0x12345678 12345 1...");
  394. OutputDebugString(TEXT("Filename(Line Number): Module Addr/HGLOBAL Size String\n"));
  395. fFoundLeak = TRUE;
  396. }
  397. dbgmakefilelinestring( szFileLine, pmb->pszFile, pmb->uLine );
  398. args[0] = (LPVOID) pmb->hglobal;
  399. args[1] = (LPVOID) &szFileLine;
  400. args[2] = (LPVOID) pmb->pszComment;
  401. args[3] = UlongToPtr(pmb->dwBytes);
  402. args[4] = (LPVOID) pmb->pszModule;
  403. if ( !!(pmb->uFlags & GMEM_MOVEABLE) )
  404. {
  405. FormatMessage(
  406. FORMAT_MESSAGE_FROM_STRING |
  407. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  408. TEXT("%2!-50s! %5!-10s! H 0x%1!08x! %4!-5u! \"%3\"\n"),
  409. 0, // error code
  410. 0, // default language
  411. (LPTSTR) &szOutput, // output buffer
  412. ARRAYSIZE( szOutput ), // size of buffer
  413. (va_list*) &args ); // arguments
  414. }
  415. else
  416. {
  417. FormatMessage(
  418. FORMAT_MESSAGE_FROM_STRING |
  419. FORMAT_MESSAGE_ARGUMENT_ARRAY,
  420. TEXT("%2!-50s! %5!-10s! A 0x%1!08x! %4!-5u! \"%3\"\n"),
  421. 0, // error code
  422. 0, // default language
  423. (LPTSTR) &szOutput, // output buffer
  424. ARRAYSIZE( szOutput ), // size of buffer
  425. (va_list*) &args ); // arguments
  426. }
  427. OutputDebugString( szOutput );
  428. pmb = pmb->pNext;
  429. }
  430. if ( fFoundLeak == TRUE )
  431. {
  432. OutputDebugString(TEXT("\n***************************** Memory leak detected *****************************\n\n"));
  433. }
  434. dbgExitCS( );
  435. Assert( !fFoundLeak );
  436. }
  437. //
  438. // Global Management Functions -
  439. //
  440. // These are in debug and retail but internally they change
  441. // depending on the build.
  442. //
  443. #undef new
  444. void* __cdecl operator new( size_t nSize, LPCTSTR pszFile, const int iLine, LPCTSTR pszModule )
  445. {
  446. return DebugAlloc( pszFile, iLine, pszModule, GPTR, nSize, TEXT("new()") );
  447. }
  448. void * __cdecl operator new(size_t t_size )
  449. {
  450. AssertMsg( 0, "Macro failure" );
  451. return NULL;
  452. }
  453. void __cdecl operator delete(void *pv)
  454. {
  455. TraceFree( pv );
  456. }
  457. int __cdecl _purecall(void)
  458. {
  459. return 0;
  460. }
  461. #else // ! DEBUG -- It's retail
  462. //
  463. // Global Management Functions -
  464. //
  465. // These are in debug and retail but are internally they change
  466. // depending on the build.
  467. //
  468. void * __cdecl operator new(size_t t_size )
  469. {
  470. return LocalAlloc( GPTR, t_size );
  471. }
  472. void __cdecl operator delete(void *pv)
  473. {
  474. LocalFree( pv );
  475. }
  476. int __cdecl _purecall(void)
  477. {
  478. return 0;
  479. }
  480. #endif // DEBUG