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.

875 lines
14 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. trace.cxx
  6. Abstract:
  7. Holds logging routines.
  8. Author:
  9. Albert Ting (AlbertT) 24-May-1996
  10. Revision History:
  11. --*/
  12. #include "spllibp.hxx"
  13. #pragma hdrstop
  14. #if DBG
  15. #include "trace.hxx"
  16. /*
  17. ** Turn off memory tracing. Turning this on keeps all the back traces in
  18. ** memory.
  19. #if i386
  20. #define BACKTRACE_ENABLED
  21. #endif
  22. */
  23. CRITICAL_SECTION gcsBackTrace;
  24. #ifdef TRACE_ENABLED
  25. TBackTraceDB* gpBackTraceDB;
  26. /********************************************************************
  27. BackTrace DB
  28. ********************************************************************/
  29. TBackTraceDB::
  30. TBackTraceDB(
  31. VOID
  32. ) : _pTraceHead( NULL )
  33. /*++
  34. Routine Description:
  35. Initialize the trace database.
  36. Generally you will have just one database that holds all the
  37. traces.
  38. Arguments:
  39. Return Value:
  40. --*/
  41. {
  42. _pMemBlock = new TMemBlock( kBlockSize, TMemBlock::kFlagGlobalNew );
  43. }
  44. TBackTraceDB::
  45. ~TBackTraceDB(
  46. VOID
  47. )
  48. /*++
  49. Routine Description:
  50. Destroy the back trace database.
  51. Arguments:
  52. Return Value:
  53. --*/
  54. {
  55. delete _pMemBlock;
  56. }
  57. BOOL
  58. TBackTraceDB::
  59. bValid(
  60. VOID
  61. )
  62. {
  63. return _pMemBlock && _pMemBlock->bValid();
  64. }
  65. HANDLE
  66. TBackTraceDB::
  67. hStore(
  68. IN ULONG ulHash,
  69. IN PVOID pvBackTrace
  70. )
  71. /*++
  72. Routine Description:
  73. Store a backtrace into the database.
  74. Arguments:
  75. ulHash - Hash for this backtrace.
  76. pvBackTrace - Actual backtrace; must be NULL terminated.
  77. Return Value:
  78. HANDLE - backtrace handle.
  79. --*/
  80. {
  81. TTrace *ptRet;
  82. TTrace **ppTrace;
  83. //
  84. // First see if we can find a backtrace. If we can't, then
  85. // pTrace will hold the slot where it should be.
  86. //
  87. ptRet = ptFind( ulHash, pvBackTrace, &ppTrace );
  88. if( !ptRet ){
  89. //
  90. // Didn't find one; add it.
  91. //
  92. ptRet = TTrace::pNew( this, ulHash, pvBackTrace, ppTrace );
  93. }
  94. return ptRet;
  95. }
  96. PLONG
  97. TBackTraceDB::
  98. plGetCount(
  99. HANDLE hData
  100. )
  101. /*++
  102. Routine Description:
  103. Get data from a HANDLE retrieved from hStore. There is one ULONG
  104. per stack backtrace.
  105. Arguments:
  106. hData - Returned from hStore.
  107. Return Value:
  108. PLONG.
  109. --*/
  110. {
  111. TTrace *ptTrace = static_cast<TTrace*>( hData );
  112. return &ptTrace->lCount();
  113. }
  114. TBackTraceDB::TTrace*
  115. TBackTraceDB::
  116. ptFind(
  117. IN ULONG ulHash,
  118. IN PVOID pvBackTrace,
  119. OUT TTrace ***pppTrace OPTIONAL
  120. )
  121. /*++
  122. Routine Description:
  123. Find a backtrace in the database. If one does not exist,
  124. then return NULL and a pointer to where it would exist
  125. in the database.
  126. Arguments:
  127. ulHash - Hash of the backtrace.
  128. pvBackTrace - Backtrace to find.
  129. pppTrace - If not found, this holds the address of where it should
  130. be stored in the database. Adding the trace here is sufficient
  131. to add it.
  132. Return Value:
  133. TTrace* the actual trace, NULL if not found.
  134. --*/
  135. {
  136. //
  137. // Traverse the binary tree until we find the end or the
  138. // right one.
  139. //
  140. TTrace **ppTrace = &_pTraceHead;
  141. while( *ppTrace ){
  142. //
  143. // Check if this one matches ours.
  144. //
  145. COMPARE Compare = (*ppTrace)->eCompareHash( ulHash );
  146. if( Compare == kEqual ){
  147. //
  148. // Now do slow compare in case the hash is a collision.
  149. //
  150. Compare = (*ppTrace)->eCompareBackTrace( pvBackTrace );
  151. if( Compare == kEqual ){
  152. //
  153. // Break out of while loop and quit.
  154. //
  155. break;
  156. }
  157. }
  158. ppTrace = ( Compare == kLess ) ?
  159. &(*ppTrace)->_pLeft :
  160. &(*ppTrace)->_pRight;
  161. }
  162. if( pppTrace ){
  163. *pppTrace = ppTrace;
  164. }
  165. return *ppTrace;
  166. }
  167. /********************************************************************
  168. TBackTraceDB::TTrace
  169. ********************************************************************/
  170. COMPARE
  171. TBackTraceDB::
  172. TTrace::
  173. eCompareHash(
  174. ULONG ulHash
  175. ) const
  176. /*++
  177. Routine Description:
  178. Quickly compare two trace hashes.
  179. Arguments:
  180. ulHash - Input hash.
  181. Return Value:
  182. --*/
  183. {
  184. if( _ulHash < ulHash ){
  185. return kLess;
  186. }
  187. if( _ulHash > ulHash ){
  188. return kGreater;
  189. }
  190. return kEqual;
  191. }
  192. COMPARE
  193. TBackTraceDB::
  194. TTrace::
  195. eCompareBackTrace(
  196. PVOID pvBackTrace
  197. ) const
  198. /*++
  199. Routine Description:
  200. Compare backtrace to one stored in this.
  201. Arguments:
  202. pvBackTrace - Must be NULL terminated.
  203. Return Value:
  204. COMAARE: kLess, kEqual, kGreater.
  205. --*/
  206. {
  207. PVOID *pSrc;
  208. PVOID *pDest;
  209. for( pSrc = (PVOID*)this, pDest = (PVOID*)&pvBackTrace;
  210. *pSrc && *pDest;
  211. pSrc++, pDest++ ) {
  212. if ( *pSrc != *pDest ){
  213. return (ULONG_PTR)*pSrc < (ULONG_PTR)*pDest ?
  214. kLess :
  215. kGreater;
  216. }
  217. }
  218. return kEqual;
  219. }
  220. TBackTraceDB::TTrace*
  221. TBackTraceDB::
  222. TTrace::
  223. pNew(
  224. IN TBackTraceDB *pBackTraceDB,
  225. IN ULONG ulHash,
  226. IN PVOID pvBackTrace,
  227. OUT TTrace ** ppTrace
  228. )
  229. /*++
  230. Routine Description:
  231. Constructs a new TTrace and puts it in pBackTraceDB.
  232. Assumes the trace does _not_ exist already, and ppTrace points
  233. to the place where it should be stored to ensure the database
  234. is kept consistent.
  235. Arguments:
  236. pBackTraceDB - Storage for the new trace.
  237. ulHash - Hash for the trace.
  238. pvBackTrace - The actual backtrace.
  239. ppTrace - Where the trace should be stored in the database.
  240. Return Value:
  241. TTrace* - New trace, NULL if failed.
  242. --*/
  243. {
  244. COUNT cCalls;
  245. PVOID *ppvCalls;
  246. //
  247. // Calculate size of backtrace. Start with cCalls = 1 so that
  248. // we include 1 extra for the NULL terminator.
  249. //
  250. for( ppvCalls = (PVOID*)pvBackTrace, cCalls = 1;
  251. *ppvCalls;
  252. ++ppvCalls, ++cCalls )
  253. ;
  254. ++cCalls;
  255. COUNTB cbSize = OFFSETOF( TTrace, apvBackTrace ) +
  256. cCalls * sizeof( PVOID );
  257. TTrace* pTrace = (TTrace*)pBackTraceDB->_pMemBlock->pvAlloc( cbSize );
  258. if( pTrace ){
  259. pTrace->_pLeft = NULL;
  260. pTrace->_pRight = NULL;
  261. pTrace->_ulHash = ulHash;
  262. pTrace->_lCount = -1;
  263. CopyMemory( pTrace->apvBackTrace,
  264. (PVOID*)pvBackTrace,
  265. cCalls * sizeof( PVOID ));
  266. //
  267. // Add it in the right spot into the database.
  268. //
  269. *ppTrace = pTrace;
  270. }
  271. return pTrace;
  272. }
  273. /********************************************************************
  274. Back tracing: abstract base class.
  275. ********************************************************************/
  276. BOOL VBackTrace::gbInitialized = FALSE;
  277. #endif // TRACE_ENABLED
  278. VBackTrace::
  279. VBackTrace(
  280. ULONG_PTR fOptions1,
  281. ULONG_PTR fOptions2
  282. ) : _fOptions1( fOptions1 ), _fOptions2( fOptions2 )
  283. {
  284. }
  285. VBackTrace::
  286. ~VBackTrace(
  287. VOID
  288. )
  289. {
  290. }
  291. BOOL
  292. VBackTrace::
  293. bInit(
  294. VOID
  295. )
  296. {
  297. #ifdef TRACE_ENABLED
  298. InitializeCriticalSection(&gcsBackTrace);
  299. gpBackTraceDB = new TBackTraceDB();
  300. gbInitialized = TRUE;
  301. return gpBackTraceDB != NULL;
  302. #else
  303. return TRUE;
  304. #endif
  305. }
  306. VOID
  307. VBackTrace::
  308. vDone(
  309. VOID
  310. )
  311. {
  312. #ifdef TRACE_ENABLED
  313. if( gbInitialized )
  314. {
  315. DeleteCriticalSection(&gcsBackTrace);
  316. }
  317. #endif
  318. }
  319. PLONG
  320. VBackTrace::
  321. plGetCount(
  322. HANDLE hData
  323. )
  324. {
  325. #ifdef TRACE_ENABLED
  326. return gpBackTraceDB->plGetCount( hData );
  327. #else
  328. return NULL;
  329. #endif
  330. }
  331. #ifndef TRACE_ENABLED
  332. HANDLE
  333. VBackTrace::
  334. hCapture(
  335. ULONG_PTR Info1,
  336. ULONG_PTR Info2,
  337. ULONG_PTR Info3,
  338. PULONG pHash
  339. )
  340. /*++
  341. Routine Description:
  342. In the case that tracing is disabled, this function is coded
  343. to return NULL.
  344. Arguments:
  345. Return Value:
  346. NULL
  347. --*/
  348. {
  349. return NULL;
  350. }
  351. #endif // ndef TRACE_ENABLED
  352. #ifdef TRACE_ENABLED
  353. /********************************************************************
  354. Back tracing to memory.
  355. ********************************************************************/
  356. TBackTraceMem::
  357. TBackTraceMem(
  358. ULONG_PTR fOptions1,
  359. ULONG_PTR fOptions2
  360. ) : VBackTrace( fOptions1, fOptions2 ), _uNextFree( 0 )
  361. {
  362. _pLines = new TLine[kMaxCall];
  363. if( _pLines ){
  364. ZeroMemory( _pLines, sizeof( TLine[kMaxCall] ));
  365. }
  366. }
  367. TBackTraceMem::
  368. ~TBackTraceMem(
  369. VOID
  370. )
  371. {
  372. UINT i;
  373. TLine* pLine;
  374. if( _pLines ){
  375. for( i=0, pLine = _pLines; i< kMaxCall; i++, pLine++ ){
  376. if( _fOptions1 & kString ){
  377. DbgFreeMem( (PVOID)pLine->_Info1 );
  378. }
  379. if( _fOptions2 & kString ){
  380. DbgFreeMem( (PVOID)pLine->_Info2 );
  381. }
  382. }
  383. delete [] _pLines;
  384. }
  385. }
  386. VOID
  387. TBackTraceMem::
  388. vCaptureLine(
  389. IN OUT TLine* pLine,
  390. IN ULONG_PTR Info1,
  391. IN ULONG_PTR Info2,
  392. IN ULONG_PTR Info3,
  393. OUT PVOID apvBackTrace[kMaxDepth+1], OPTIONAL
  394. OUT PULONG pulHash OPTIONAL
  395. )
  396. /*++
  397. Routine Description:
  398. Captures information into a TLine structure; freeing previous
  399. contents if necessary.
  400. Arguments:
  401. pLine - Fully initialized pLine structure. On output, everything
  402. _except_ _hTrace is filled in.
  403. ** Both apvBackTrace && pulHash must both be valid if either is valid **
  404. apvBackTrace - Buffer to receive backtrace.
  405. pulHash - Buffer to receive ulHash.
  406. Return Value:
  407. --*/
  408. {
  409. //
  410. // Free memory if necessary.
  411. //
  412. if( _fOptions1 & kString ) {
  413. DbgFreeMem( (PVOID)pLine->_Info1 );
  414. }
  415. if( _fOptions2 & kString ) {
  416. DbgFreeMem( (PVOID)pLine->_Info2 );
  417. }
  418. pLine->_TickCount = GetTickCount();
  419. pLine->_Info1 = Info1;
  420. pLine->_Info2 = Info2;
  421. pLine->_Info3 = Info3;
  422. pLine->_ThreadId = GetCurrentThreadId();
  423. pLine->_hTrace = NULL;
  424. #ifdef BACKTRACE_ENABLED
  425. if( apvBackTrace && pulHash ){
  426. ULONG ulHash;
  427. //
  428. // Capture a backtrace at this spot for debugging.
  429. //
  430. UINT uDepth = RtlCaptureStackBackTrace( 2,
  431. kMaxDepth,
  432. apvBackTrace,
  433. pulHash );
  434. //
  435. // NULL terminate.
  436. //
  437. apvBackTrace[uDepth] = NULL;
  438. }
  439. #else
  440. apvBackTrace[0] = NULL;
  441. *pulHash = 0;
  442. #endif
  443. }
  444. HANDLE
  445. TBackTraceMem::
  446. hCapture(
  447. ULONG_PTR Info1,
  448. ULONG_PTR Info2,
  449. ULONG_PTR Info3,
  450. PULONG pHash
  451. )
  452. {
  453. UINT uDepth;
  454. TLine* pLine;
  455. ULONG ulHash;
  456. PVOID apvBackTrace[kMaxDepth+1];
  457. if( !_pLines ){
  458. return NULL;
  459. }
  460. EnterCriticalSection( &gcsBackTrace );
  461. pLine = &_pLines[_uNextFree];
  462. vCaptureLine( pLine, Info1, Info2, Info3, apvBackTrace, &ulHash );
  463. pLine->_hTrace = gpBackTraceDB->hStore( ulHash, apvBackTrace );
  464. _uNextFree++;
  465. if( _uNextFree == kMaxCall )
  466. _uNextFree = 0;
  467. LeaveCriticalSection( &gcsBackTrace );
  468. if( pHash )
  469. {
  470. *pHash = ulHash;
  471. }
  472. return (PVOID)pLine->_hTrace;
  473. }
  474. /********************************************************************
  475. Backtracing to File.
  476. ********************************************************************/
  477. COUNT TBackTraceFile::gcInstances;
  478. TBackTraceFile::
  479. TBackTraceFile(
  480. ULONG_PTR fOptions1,
  481. ULONG_PTR fOptions2
  482. ) : VBackTrace( fOptions1, fOptions2 )
  483. {
  484. TCHAR szFile[kMaxPath];
  485. EnterCriticalSection( &gcsBackTrace );
  486. wsprintf( szFile,
  487. TEXT( "spl_%d.%d.log" ),
  488. GetCurrentProcessId(),
  489. gcInstances );
  490. ++gcInstances;
  491. LeaveCriticalSection( &gcsBackTrace );
  492. _hFile = CreateFile( szFile,
  493. GENERIC_WRITE,
  494. FILE_SHARE_READ,
  495. NULL,
  496. OPEN_ALWAYS,
  497. FILE_ATTRIBUTE_COMPRESSED,
  498. NULL );
  499. if( _hFile == INVALID_HANDLE_VALUE ){
  500. OutputDebugStringA( "SPLLIB: Unable to open file " );
  501. OutputDebugString( szFile );
  502. OutputDebugStringA( "\n" );
  503. return;
  504. }
  505. }
  506. TBackTraceFile::
  507. ~TBackTraceFile(
  508. VOID
  509. )
  510. {
  511. if( _hFile != INVALID_HANDLE_VALUE ){
  512. CloseHandle( _hFile );
  513. }
  514. }
  515. HANDLE
  516. TBackTraceFile::
  517. hCapture(
  518. ULONG_PTR Info1,
  519. ULONG_PTR Info2,
  520. ULONG_PTR Info3,
  521. PULONG pHash
  522. )
  523. {
  524. TLine Line;
  525. PVOID apvBackTrace[kMaxDepth+1];
  526. DWORD cbWritten;
  527. CHAR szLine[kMaxLineStr];
  528. szLine[0] = 0;
  529. #ifdef BACKTRACE_ENABLED
  530. ULONG ulHash;
  531. //
  532. // Capture a backtrace at this spot for debugging.
  533. //
  534. UINT uDepth = RtlCaptureStackBackTrace( 2,
  535. kMaxDepth,
  536. apvBackTrace,
  537. &ulHash );
  538. #endif
  539. EnterCriticalSection( &gcsBackTrace );
  540. //
  541. // Print out strings as appropriate.
  542. //
  543. if( _fOptions1 & kString )
  544. {
  545. WriteFile( _hFile,
  546. (LPCVOID)Info1,
  547. lstrlenA( (LPCSTR)Info1 ),
  548. &cbWritten,
  549. NULL );
  550. }
  551. if( _fOptions2 & kString )
  552. {
  553. WriteFile( _hFile,
  554. (LPCVOID)Info2,
  555. lstrlenA( (LPCSTR)Info2 ),
  556. &cbWritten,
  557. NULL );
  558. }
  559. //
  560. // Print out the hex info.
  561. //
  562. wsprintfA( szLine,
  563. "\n\t%08x: %08x %08x %08x threadid=%x tc=%x < %x >: ",
  564. this,
  565. Info1,
  566. Info2,
  567. Info3,
  568. GetCurrentThreadId(),
  569. GetTickCount(),
  570. Info1 + Info2 );
  571. if( _hFile )
  572. {
  573. WriteFile( _hFile, szLine, lstrlenA( szLine ), &cbWritten, NULL );
  574. }
  575. #ifdef BACKTRACE_ENABLED
  576. //
  577. // Print out the backtrace.
  578. //
  579. UINT i;
  580. UINT uLineEnd = 1;
  581. szLine[0] = '\t';
  582. for( i=0; i < uDepth; ++i )
  583. {
  584. uLineEnd += wsprintfA( szLine + uLineEnd, "%08x ", apvBackTrace[i] );
  585. }
  586. if( _hFile && i )
  587. {
  588. szLine[uLineEnd++] = '\n';
  589. WriteFile( _hFile, szLine, uLineEnd, &cbWritten, NULL );
  590. }
  591. #endif
  592. //
  593. // Add extra blank line.
  594. //
  595. szLine[0] = '\n';
  596. WriteFile( _hFile, szLine, 1, &cbWritten, NULL );
  597. LeaveCriticalSection( &gcsBackTrace );
  598. //
  599. // Free memory if necessary.
  600. //
  601. if( _fOptions1 & kString )
  602. {
  603. DbgFreeMem( (PVOID)Info1 );
  604. }
  605. if( _fOptions2 & kString )
  606. {
  607. DbgFreeMem( (PVOID)Info2 );
  608. }
  609. #ifdef BACKTRACE_ENABLED
  610. if( pHash )
  611. {
  612. *pHash = ulHash;
  613. }
  614. #endif
  615. return NULL;
  616. }
  617. #endif // TRACE_ENABLED
  618. #endif // #ifdef DBG