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.

722 lines
14 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. Debug.cxx
  6. Abstract:
  7. Debug support
  8. Author:
  9. Albert Ting (AlbertT) 28-May-1994
  10. Revision History:
  11. --*/
  12. #include "spllibp.hxx"
  13. #pragma hdrstop
  14. #include "trace.hxx"
  15. #define DEFAULT_TRACE_TYPE TBackTraceMem
  16. //#define DEFAULT_TRACE_TYPE TBackTraceFile // For tracing to file.
  17. #define DEFAULT_MEM_TRACE_TYPE TBackTraceMem
  18. extern HANDLE ghMemHeap;
  19. extern HANDLE ghDbgMemHeap;
  20. extern pfCreateThread gpfSafeCreateThread;
  21. #if DBG
  22. UINT gLogFilter = (UINT)-1;
  23. VBackTrace* gpbtErrLog;
  24. VBackTrace* gpbtTraceLog;
  25. MODULE_DEBUG_INIT( DBG_ERROR, DBG_ERROR );
  26. DBG_POINTERS gDbgPointers;
  27. PDBG_POINTERS gpDbgPointers;
  28. extern VBackTrace* gpbtAlloc;
  29. extern VBackTrace* gpbtFree;
  30. /********************************************************************
  31. Single thread checking.
  32. This is used to verify that a set of functions are called from
  33. only one thread. This is for debugging purposes only.
  34. ********************************************************************/
  35. VOID
  36. vDbgSingleThread(
  37. PDWORD pdwThreadId
  38. )
  39. {
  40. EnterCriticalSection( &gcsBackTrace );
  41. if (!*pdwThreadId) {
  42. *pdwThreadId = (DWORD)GetCurrentThreadId();
  43. }
  44. SPLASSERT( *pdwThreadId == (DWORD)GetCurrentThreadId() );
  45. LeaveCriticalSection( &gcsBackTrace );
  46. }
  47. VOID
  48. vDbgSingleThreadReset(
  49. PDWORD pdwThreadId
  50. )
  51. {
  52. *pdwThreadId = 0;
  53. }
  54. VOID
  55. vDbgSingleThreadNot(
  56. PDWORD pdwThreadId
  57. )
  58. {
  59. SPLASSERT( *pdwThreadId != (DWORD)GetCurrentThreadId() );
  60. }
  61. /********************************************************************
  62. TStatus automated error logging and codepath testing.
  63. ********************************************************************/
  64. TStatusBase&
  65. TStatusBase::
  66. pNoChk(
  67. VOID
  68. )
  69. {
  70. _pszFileA = NULL;
  71. return (TStatusBase&)*this;
  72. }
  73. TStatusBase&
  74. TStatusBase::
  75. pSetInfo(
  76. UINT uDbg,
  77. UINT uLine,
  78. LPCSTR pszFileA,
  79. LPCSTR pszModuleA
  80. )
  81. {
  82. _uDbg = uDbg;
  83. _uLine = uLine;
  84. _pszFileA = pszFileA;
  85. SPLASSERT( pszFileA );
  86. _pszModuleA = pszModuleA;
  87. return (TStatusBase&)*this;
  88. }
  89. DWORD
  90. TStatus::
  91. dwGetStatus(
  92. VOID
  93. )
  94. {
  95. //
  96. // For now, return error code. Later it will return the actual
  97. // error code.
  98. //
  99. return _dwStatus;
  100. }
  101. DWORD
  102. TStatusBase::
  103. operator=(
  104. DWORD dwStatus
  105. )
  106. {
  107. //
  108. // Check if we have an error, and it's not one of the two
  109. // accepted "safe" errors.
  110. //
  111. // If pszFileA is not set, then we can safely ignore the
  112. // error as one the client intended.
  113. //
  114. if( _pszFileA &&
  115. dwStatus != ERROR_SUCCESS &&
  116. dwStatus != _dwStatusSafe1 &&
  117. dwStatus != _dwStatusSafe2 &&
  118. dwStatus != _dwStatusSafe3 ){
  119. #ifdef DBGLOG
  120. //
  121. // An unexpected error occured. Log an error and continue.
  122. //
  123. vDbgLogError( _uDbg,
  124. _uDbgLevel,
  125. _uLine,
  126. _pszFileA,
  127. _pszModuleA,
  128. pszDbgAllocMsgA( "TStatus set to %d\nLine %d, %hs\n",
  129. dwStatus,
  130. _uLine,
  131. _pszFileA ));
  132. #else
  133. DBGMSG( DBG_WARN,
  134. ( "TStatus set to %d\nLine %d, %hs\n",
  135. dwStatus,
  136. _uLine,
  137. _pszFileA ));
  138. #endif
  139. }
  140. return _dwStatus = dwStatus;
  141. }
  142. /********************************************************************
  143. Same, but for HRESULTs.
  144. ********************************************************************/
  145. TStatusHBase&
  146. TStatusHBase::
  147. pNoChk(
  148. VOID
  149. )
  150. {
  151. _pszFileA = NULL;
  152. return (TStatusH&)*this;
  153. }
  154. TStatusHBase&
  155. TStatusHBase::
  156. pSetInfo(
  157. UINT uDbg,
  158. UINT uLine,
  159. LPCSTR pszFileA,
  160. LPCSTR pszModuleA
  161. )
  162. {
  163. _uDbg = uDbg;
  164. _uLine = uLine;
  165. _pszFileA = pszFileA;
  166. SPLASSERT( pszFileA );
  167. _pszModuleA = pszModuleA;
  168. return (TStatusH&)*this;
  169. }
  170. HRESULT
  171. TStatusHBase::
  172. operator=(
  173. HRESULT hrStatus
  174. )
  175. {
  176. //
  177. // Check if we have an error, and it's not one of the two
  178. // accepted "safe" errors.
  179. //
  180. // If pszFileA is not set, then we can safely ignore the
  181. // error as one the client intended.
  182. //
  183. if( _pszFileA &&
  184. FAILED(hrStatus) &&
  185. hrStatus != _hrStatusSafe1 &&
  186. hrStatus != _hrStatusSafe2 &&
  187. hrStatus != _hrStatusSafe3 ){
  188. #ifdef DBGLOG
  189. //
  190. // An unexpected error occured. Log an error and continue.
  191. //
  192. vDbgLogError( _uDbg,
  193. _uDbgLevel,
  194. _uLine,
  195. _pszFileA,
  196. _pszModuleA,
  197. pszDbgAllocMsgA( "TStatusH set to %x\nLine %d, %hs\n",
  198. hrStatus,
  199. _uLine,
  200. _pszFileA ));
  201. #else
  202. DBGMSG( DBG_WARN,
  203. ( "TStatusH set to %x\nLine %d, %hs\n",
  204. hrStatus,
  205. _uLine,
  206. _pszFileA ));
  207. #endif
  208. }
  209. return _hrStatus = hrStatus;
  210. }
  211. HRESULT
  212. TStatusH::
  213. hrGetStatus(
  214. VOID
  215. )
  216. {
  217. //
  218. // For now, return error code. Later it will return the actual
  219. // error code.
  220. //
  221. return _hrStatus;
  222. }
  223. /********************************************************************
  224. Same, but for BOOLs.
  225. ********************************************************************/
  226. TStatusBBase&
  227. TStatusBBase::
  228. pNoChk(
  229. VOID
  230. )
  231. {
  232. _pszFileA = NULL;
  233. return (TStatusBBase&)*this;
  234. }
  235. TStatusBBase&
  236. TStatusBBase::
  237. pSetInfo(
  238. UINT uDbg,
  239. UINT uLine,
  240. LPCSTR pszFileA,
  241. LPCSTR pszModuleA
  242. )
  243. {
  244. _uDbg = uDbg;
  245. _uLine = uLine;
  246. _pszFileA = pszFileA;
  247. SPLASSERT( pszFileA );
  248. _pszModuleA = pszModuleA;
  249. return (TStatusBBase&)*this;
  250. }
  251. BOOL
  252. TStatusB::
  253. bGetStatus(
  254. VOID
  255. )
  256. {
  257. //
  258. // For now, return error code. Later it will return the actual
  259. // error code.
  260. //
  261. return _bStatus;
  262. }
  263. BOOL
  264. TStatusBBase::
  265. operator=(
  266. BOOL bStatus
  267. )
  268. {
  269. //
  270. // Check if we have an error, and it's not one of the two
  271. // accepted "safe" errors.
  272. //
  273. // If pszFileA is not set, then we can safely ignore the
  274. // error as one the client intended.
  275. //
  276. if( _pszFileA && !bStatus ){
  277. DWORD dwLastError = GetLastError();
  278. if( dwLastError != _dwStatusSafe1 &&
  279. dwLastError != _dwStatusSafe2 &&
  280. dwLastError != _dwStatusSafe3 ){
  281. #ifdef DBGLOG
  282. //
  283. // An unexpected error occured. Log an error and continue.
  284. //
  285. vDbgLogError( _uDbg,
  286. _uDbgLevel,
  287. _uLine,
  288. _pszFileA,
  289. _pszModuleA,
  290. pszDbgAllocMsgA( "TStatusB set to FALSE, LastError = %d\nLine %d, %hs\n",
  291. GetLastError(),
  292. _uLine,
  293. _pszFileA ));
  294. #else
  295. DBGMSG( DBG_WARN,
  296. ( "TStatusB set to FALSE, LastError = %d\nLine %d, %hs\n",
  297. GetLastError(),
  298. _uLine,
  299. _pszFileA ));
  300. #endif
  301. }
  302. }
  303. return _bStatus = bStatus;
  304. }
  305. VOID
  306. vWarnInvalid(
  307. PVOID pvObject,
  308. UINT uDbg,
  309. UINT uLine,
  310. LPCSTR pszFileA,
  311. LPCSTR pszModuleA
  312. )
  313. /*++
  314. Routine Description:
  315. Warns that an object is invalid.
  316. Arguments:
  317. Return Value:
  318. --*/
  319. {
  320. #if DBGLOG
  321. vDbgLogError( uDbg,
  322. DBG_WARN,
  323. uLine,
  324. pszFileA,
  325. pszModuleA,
  326. pszDbgAllocMsgA( "Invalid Object %x LastError = %d\nLine %d, %hs\n",
  327. (ULONG_PTR)pvObject,
  328. GetLastError(),
  329. uLine,
  330. pszFileA ));
  331. #else
  332. DBGMSG( DBG_WARN,
  333. ( "Invalid Object %x LastError = %d\nLine %d, %hs\n",
  334. (DWORD)pvObject,
  335. GetLastError(),
  336. uLine,
  337. pszFileA ));
  338. #endif
  339. }
  340. /********************************************************************
  341. Generic Error logging package.
  342. ********************************************************************/
  343. VOID
  344. DbgMsg(
  345. LPCSTR pszMsgFormat,
  346. ...
  347. )
  348. {
  349. CHAR szMsgText[1024];
  350. va_list vargs;
  351. va_start( vargs, pszMsgFormat );
  352. wvsprintfA( szMsgText, pszMsgFormat, vargs );
  353. va_end( vargs );
  354. #ifndef DBGLOG
  355. //
  356. // Prefix the string if the first character isn't a space:
  357. //
  358. if( szMsgText[0] && szMsgText[0] != ' ' ){
  359. OutputDebugStringA( MODULE );
  360. }
  361. #endif
  362. OutputDebugStringA( szMsgText );
  363. }
  364. #ifdef DBGLOG
  365. LPSTR
  366. pszDbgAllocMsgA(
  367. LPCSTR pszMsgFormatA,
  368. ...
  369. )
  370. {
  371. CHAR szMsgTextA[1024];
  372. UINT cbStr;
  373. LPSTR pszMsgA;
  374. va_list vargs;
  375. va_start(vargs, pszMsgFormatA);
  376. __try
  377. {
  378. wvsprintfA( szMsgTextA, pszMsgFormatA, vargs );
  379. } __except(( GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ||
  380. GetExceptionCode() == EXCEPTION_DATATYPE_MISALIGNMENT) ?
  381. EXCEPTION_EXECUTE_HANDLER :
  382. EXCEPTION_CONTINUE_SEARCH )
  383. {
  384. OutputDebugStringA( "SPL: <Bad DbgMsg !!> " );
  385. OutputDebugStringA( pszMsgFormatA );
  386. }
  387. va_end(vargs);
  388. cbStr = ( lstrlenA( szMsgTextA ) + 1 ) * sizeof( szMsgTextA[0] );
  389. pszMsgA = (LPSTR)DbgAllocMem( cbStr );
  390. if( pszMsgA ){
  391. CopyMemory( pszMsgA, szMsgTextA, cbStr );
  392. }
  393. return pszMsgA;
  394. }
  395. VOID
  396. vDbgLogError(
  397. UINT uDbg,
  398. UINT uDbgLevel,
  399. UINT uLine,
  400. LPCSTR pszFileA,
  401. LPCSTR pszModuleA,
  402. LPCSTR pszMsgA
  403. )
  404. {
  405. DWORD dwLastError = GetLastError();
  406. VBackTrace* pBackTrace = gpbtTraceLog;
  407. if(( uDbgLevel & DBG_PRINT_MASK & uDbg ) && pszMsgA ){
  408. if( !( uDbgLevel & DBG_NOHEAD )){
  409. OutputDebugStringA( pszModuleA );
  410. }
  411. OutputDebugStringA( pszMsgA );
  412. }
  413. if(( uDbgLevel << DBG_BREAK_SHIFT ) & uDbg ){
  414. DebugBreak();
  415. }
  416. if( gLogFilter & uDbgLevel )
  417. {
  418. //
  419. // Log the failure.
  420. //
  421. //
  422. // Capture significant errors in separate error log.
  423. //
  424. if( uDbgLevel & DBG_ERRLOG_CAPTURE ){
  425. pBackTrace = gpbtErrLog;
  426. }
  427. if (pBackTrace)
  428. {
  429. pBackTrace->hCapture( (ULONG_PTR)pszMsgA,
  430. uLine | ( uDbgLevel << DBG_BREAK_SHIFT ),
  431. (ULONG_PTR)pszFileA );
  432. }
  433. else
  434. {
  435. //
  436. // Backtracing is not enabled, free the message string that is
  437. // passed in.
  438. //
  439. if(pszMsgA)
  440. {
  441. DbgFreeMem((PVOID)pszMsgA);
  442. }
  443. }
  444. }
  445. else
  446. {
  447. //
  448. // Just free up the memory if this line is not captured
  449. // actually this happens when uDbgLevel == DBG_NONE (0)
  450. //
  451. if( pszMsgA )
  452. {
  453. DbgFreeMem( (PVOID)pszMsgA );
  454. }
  455. }
  456. SetLastError( dwLastError );
  457. }
  458. #endif // def DBGLOG
  459. #endif // DBG
  460. /********************************************************************
  461. Initialization
  462. ********************************************************************/
  463. #if DBG
  464. BOOL
  465. bSplLibInit(
  466. pfCreateThread pfSafeCreateThread
  467. )
  468. {
  469. BOOL bValid;
  470. bValid = (ghMemHeap = HeapCreate( 0, 1024*4, 0 )) &&
  471. (ghDbgMemHeap = HeapCreate( 0, 1024*4, 0 )) &&
  472. (VBackTrace::bInit( )) &&
  473. #ifdef TRACE_ENABLED
  474. (gpbtAlloc = new DEFAULT_MEM_TRACE_TYPE) &&
  475. (gpbtFree = new DEFAULT_MEM_TRACE_TYPE) &&
  476. (gpbtErrLog = new DEFAULT_TRACE_TYPE( VBackTrace::kString )) &&
  477. (gpbtTraceLog = new DEFAULT_TRACE_TYPE( VBackTrace::kString )) &&
  478. #endif
  479. (MRefCom::gpcsCom = new MCritSec) &&
  480. MRefCom::gpcsCom->bValid();
  481. gpfSafeCreateThread = ( pfSafeCreateThread ) ? pfSafeCreateThread : CreateThread;
  482. if( bValid ){
  483. gDbgPointers.pfnAllocBackTrace = &DbgAllocBackTrace;
  484. gDbgPointers.pfnAllocBackTraceMem = &DbgAllocBackTraceMem;
  485. gDbgPointers.pfnAllocBackTraceFile = &DbgAllocBackTraceFile;
  486. gDbgPointers.pfnFreeBackTrace = &DbgFreeBackTrace;
  487. gDbgPointers.pfnCaptureBackTrace = &DbgCaptureBackTrace;
  488. gDbgPointers.pfnAllocCritSec = &DbgAllocCritSec;
  489. gDbgPointers.pfnFreeCritSec = &DbgFreeCritSec;
  490. gDbgPointers.pfnInsideCritSec = &DbgInsideCritSec;
  491. gDbgPointers.pfnOutsideCritSec = &DbgOutsideCritSec;
  492. gDbgPointers.pfnEnterCritSec = &DbgEnterCritSec;
  493. gDbgPointers.pfnLeaveCritSec = &DbgLeaveCritSec;
  494. gDbgPointers.pfnSetAllocFail = &DbgSetAllocFail;
  495. gDbgPointers.hMemHeap = ghMemHeap;
  496. gDbgPointers.hDbgMemHeap = ghDbgMemHeap;
  497. gDbgPointers.pbtAlloc = gpbtAlloc;
  498. gDbgPointers.pbtFree = gpbtFree;
  499. gDbgPointers.pbtErrLog = gpbtErrLog;
  500. gDbgPointers.pbtTraceLog = gpbtTraceLog;
  501. gpDbgPointers = &gDbgPointers;
  502. }
  503. return bValid;
  504. }
  505. VOID
  506. vSplLibFree(
  507. VOID
  508. )
  509. {
  510. SPLASSERT( MRefCom::gpcsCom->bOutside( ));
  511. delete MRefCom::gpcsCom;
  512. VBackTrace::vDone();
  513. if (ghMemHeap)
  514. {
  515. HeapDestroy( ghMemHeap );
  516. ghMemHeap = NULL;
  517. }
  518. if (ghDbgMemHeap)
  519. {
  520. HeapDestroy( ghDbgMemHeap );
  521. ghDbgMemHeap = NULL;
  522. }
  523. }
  524. #else
  525. BOOL
  526. bSplLibInit(
  527. pfCreateThread pfSafeCreateThread
  528. )
  529. {
  530. gpfSafeCreateThread = ( pfSafeCreateThread ) ? pfSafeCreateThread : CreateThread;
  531. return ( ghMemHeap = HeapCreate( 0, 1024*4, 0 )) ?
  532. TRUE : FALSE;
  533. }
  534. VOID
  535. vSplLibFree(
  536. VOID
  537. )
  538. {
  539. if (ghMemHeap)
  540. {
  541. HeapDestroy( ghMemHeap );
  542. ghMemHeap = NULL;
  543. }
  544. }
  545. #endif
  546. /********************************************************************
  547. Stub these out so non-debug builds will find them.
  548. ********************************************************************/
  549. #if !DBG
  550. #ifdef DBGLOG
  551. LPSTR
  552. pszDbgAllocMsgA(
  553. LPCSTR pszMsgFormatA,
  554. ...
  555. )
  556. {
  557. return NULL;
  558. }
  559. VOID
  560. vDbgLogError(
  561. UINT uDbg,
  562. UINT uDbgLevel,
  563. UINT uLine,
  564. LPCSTR pszFileA,
  565. LPCSTR pszModuleA,
  566. LPCSTR pszMsgA
  567. )
  568. {
  569. }
  570. #else
  571. VOID
  572. vDbgMsg2(
  573. LPCTSTR pszMsgFormat,
  574. ...
  575. )
  576. {
  577. }
  578. #endif // ndef DBGLOG
  579. #endif // !DBG