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.

881 lines
16 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. gbInitialized = InitializeCriticalSectionAndSpinCount(&gcsBackTrace, 0x80000000);
  299. gpBackTraceDB = new TBackTraceDB();
  300. return gbInitialized && (gpBackTraceDB != NULL);
  301. #else
  302. return TRUE;
  303. #endif
  304. }
  305. VOID
  306. VBackTrace::
  307. vDone(
  308. VOID
  309. )
  310. {
  311. #ifdef TRACE_ENABLED
  312. if( gbInitialized )
  313. {
  314. DeleteCriticalSection(&gcsBackTrace);
  315. }
  316. #endif
  317. }
  318. PLONG
  319. VBackTrace::
  320. plGetCount(
  321. HANDLE hData
  322. )
  323. {
  324. #ifdef TRACE_ENABLED
  325. return gpBackTraceDB->plGetCount( hData );
  326. #else
  327. return NULL;
  328. #endif
  329. }
  330. #ifndef TRACE_ENABLED
  331. HANDLE
  332. VBackTrace::
  333. hCapture(
  334. ULONG_PTR Info1,
  335. ULONG_PTR Info2,
  336. ULONG_PTR Info3,
  337. PULONG pHash
  338. )
  339. /*++
  340. Routine Description:
  341. In the case that tracing is disabled, this function is coded
  342. to return NULL.
  343. Arguments:
  344. Return Value:
  345. NULL
  346. --*/
  347. {
  348. return NULL;
  349. }
  350. #endif // ndef TRACE_ENABLED
  351. #ifdef TRACE_ENABLED
  352. /********************************************************************
  353. Back tracing to memory.
  354. ********************************************************************/
  355. TBackTraceMem::
  356. TBackTraceMem(
  357. ULONG_PTR fOptions1,
  358. ULONG_PTR fOptions2
  359. ) : VBackTrace( fOptions1, fOptions2 ), _uNextFree( 0 )
  360. {
  361. _pLines = new TLine[kMaxCall];
  362. if( _pLines ){
  363. ZeroMemory( _pLines, sizeof( TLine[kMaxCall] ));
  364. }
  365. }
  366. TBackTraceMem::
  367. ~TBackTraceMem(
  368. VOID
  369. )
  370. {
  371. UINT i;
  372. TLine* pLine;
  373. if( _pLines ){
  374. for( i=0, pLine = _pLines; i< kMaxCall; i++, pLine++ ){
  375. if( _fOptions1 & kString ){
  376. DbgFreeMem( (PVOID)pLine->_Info1 );
  377. }
  378. if( _fOptions2 & kString ){
  379. DbgFreeMem( (PVOID)pLine->_Info2 );
  380. }
  381. }
  382. delete [] _pLines;
  383. }
  384. }
  385. VOID
  386. TBackTraceMem::
  387. vCaptureLine(
  388. IN OUT TLine* pLine,
  389. IN ULONG_PTR Info1,
  390. IN ULONG_PTR Info2,
  391. IN ULONG_PTR Info3,
  392. OUT PVOID apvBackTrace[kMaxDepth+1], OPTIONAL
  393. OUT PULONG pulHash OPTIONAL
  394. )
  395. /*++
  396. Routine Description:
  397. Captures information into a TLine structure; freeing previous
  398. contents if necessary.
  399. Arguments:
  400. pLine - Fully initialized pLine structure. On output, everything
  401. _except_ _hTrace is filled in.
  402. ** Both apvBackTrace && pulHash must both be valid if either is valid **
  403. apvBackTrace - Buffer to receive backtrace.
  404. pulHash - Buffer to receive ulHash.
  405. Return Value:
  406. --*/
  407. {
  408. //
  409. // Free memory if necessary.
  410. //
  411. if( _fOptions1 & kString ) {
  412. DbgFreeMem( (PVOID)pLine->_Info1 );
  413. }
  414. if( _fOptions2 & kString ) {
  415. DbgFreeMem( (PVOID)pLine->_Info2 );
  416. }
  417. pLine->_TickCount = GetTickCount();
  418. pLine->_Info1 = Info1;
  419. pLine->_Info2 = Info2;
  420. pLine->_Info3 = Info3;
  421. pLine->_ThreadId = GetCurrentThreadId();
  422. pLine->_hTrace = NULL;
  423. #ifdef BACKTRACE_ENABLED
  424. if( apvBackTrace && pulHash ){
  425. ULONG ulHash;
  426. //
  427. // Capture a backtrace at this spot for debugging.
  428. //
  429. UINT uDepth = RtlCaptureStackBackTrace( 2,
  430. kMaxDepth,
  431. apvBackTrace,
  432. pulHash );
  433. //
  434. // NULL terminate.
  435. //
  436. apvBackTrace[uDepth] = NULL;
  437. }
  438. #else
  439. apvBackTrace[0] = NULL;
  440. *pulHash = 0;
  441. #endif
  442. }
  443. HANDLE
  444. TBackTraceMem::
  445. hCapture(
  446. ULONG_PTR Info1,
  447. ULONG_PTR Info2,
  448. ULONG_PTR Info3,
  449. PULONG pHash
  450. )
  451. {
  452. UINT uDepth;
  453. TLine* pLine;
  454. ULONG ulHash;
  455. PVOID apvBackTrace[kMaxDepth+1];
  456. if( !_pLines ){
  457. return NULL;
  458. }
  459. EnterCriticalSection( &gcsBackTrace );
  460. pLine = &_pLines[_uNextFree];
  461. vCaptureLine( pLine, Info1, Info2, Info3, apvBackTrace, &ulHash );
  462. pLine->_hTrace = gpBackTraceDB->hStore( ulHash, apvBackTrace );
  463. _uNextFree++;
  464. if( _uNextFree == kMaxCall )
  465. _uNextFree = 0;
  466. LeaveCriticalSection( &gcsBackTrace );
  467. if( pHash )
  468. {
  469. *pHash = ulHash;
  470. }
  471. return (PVOID)pLine->_hTrace;
  472. }
  473. /********************************************************************
  474. Backtracing to File.
  475. ********************************************************************/
  476. COUNT TBackTraceFile::gcInstances;
  477. TBackTraceFile::
  478. TBackTraceFile(
  479. ULONG_PTR fOptions1,
  480. ULONG_PTR fOptions2
  481. ) : VBackTrace( fOptions1, fOptions2 )
  482. {
  483. TCHAR szFile[kMaxPath];
  484. EnterCriticalSection( &gcsBackTrace );
  485. StringCchPrintf( szFile,
  486. COUNTOF(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. StringCchPrintfA(szLine,
  563. COUNTOF(szLine),
  564. "\n\t%08x: %08x %08x %08x threadid=%x tc=%x < %x >: ",
  565. this,
  566. Info1,
  567. Info2,
  568. Info3,
  569. GetCurrentThreadId(),
  570. GetTickCount(),
  571. Info1 + Info2 );
  572. if( _hFile )
  573. {
  574. WriteFile( _hFile, szLine, lstrlenA( szLine ), &cbWritten, NULL );
  575. }
  576. #ifdef BACKTRACE_ENABLED
  577. //
  578. // Print out the backtrace.
  579. //
  580. UINT i;
  581. szLine[0] = '\t';
  582. CHAR *pszLineEnd = &szLine[1];
  583. size_t cRemaining = COUNTOF(szLine)-1;
  584. for( i=0; i < uDepth; ++i )
  585. {
  586. StringCchPrintfAEx( pszLineEnd, cRemaining, pszLineEnd, cRemaining, "%08x ", apvBackTrace[i] );
  587. }
  588. if( _hFile && i )
  589. {
  590. //
  591. // Countof(szLine)-cRemaining is the number of characters that were copied to szLine.
  592. // We add 2 for the first character and the null character at the end.
  593. //
  594. WriteFile( _hFile, szLine, COUNTOF(szLine)-cRemaining+2, &cbWritten, NULL );
  595. }
  596. #endif
  597. //
  598. // Add extra blank line.
  599. //
  600. szLine[0] = '\n';
  601. WriteFile( _hFile, szLine, 1, &cbWritten, NULL );
  602. LeaveCriticalSection( &gcsBackTrace );
  603. //
  604. // Free memory if necessary.
  605. //
  606. if( _fOptions1 & kString )
  607. {
  608. DbgFreeMem( (PVOID)Info1 );
  609. }
  610. if( _fOptions2 & kString )
  611. {
  612. DbgFreeMem( (PVOID)Info2 );
  613. }
  614. #ifdef BACKTRACE_ENABLED
  615. if( pHash )
  616. {
  617. *pHash = ulHash;
  618. }
  619. #endif
  620. return NULL;
  621. }
  622. #endif // TRACE_ENABLED
  623. #endif // #ifdef DBG