Windows NT 4.0 source code leak
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.

714 lines
12 KiB

4 years ago
  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. #if i386 && !FPO
  17. #define BACKTRACE_ENABLED
  18. #endif
  19. CRITICAL_SECTION gcsBackTrace;
  20. /********************************************************************
  21. BackTrace DB
  22. ********************************************************************/
  23. TBackTraceDB::
  24. TBackTraceDB(
  25. VOID
  26. ) : _pTraceHead( NULL )
  27. /*++
  28. Routine Description:
  29. Initialize the trace database.
  30. Generally you will have just one database that holds all the
  31. traces.
  32. Arguments:
  33. Return Value:
  34. --*/
  35. {
  36. _pMemBlock = new TMemBlock( kBlockSize, TMemBlock::kFlagGlobalNew );
  37. }
  38. TBackTraceDB::
  39. ~TBackTraceDB(
  40. VOID
  41. )
  42. /*++
  43. Routine Description:
  44. Destroy the back trace database.
  45. Arguments:
  46. Return Value:
  47. --*/
  48. {
  49. delete _pMemBlock;
  50. }
  51. BOOL
  52. TBackTraceDB::
  53. bValid(
  54. VOID
  55. )
  56. {
  57. return _pMemBlock && _pMemBlock->bValid();
  58. }
  59. HANDLE
  60. TBackTraceDB::
  61. hStore(
  62. IN ULONG ulHash,
  63. IN PVOID pvBackTrace
  64. )
  65. /*++
  66. Routine Description:
  67. Store a backtrace into the database.
  68. Arguments:
  69. ulHash - Hash for this backtrace.
  70. pvBackTrace - Actual backtrace; must be NULL terminated.
  71. Return Value:
  72. HANDLE - backtrace handle.
  73. --*/
  74. {
  75. TTrace *ptRet;
  76. TTrace **ppTrace;
  77. //
  78. // First see if we can find a backtrace. If we can't, then
  79. // pTrace will hold the slot where it should be.
  80. //
  81. ptRet = ptFind( ulHash, pvBackTrace, &ppTrace );
  82. if( !ptRet ){
  83. //
  84. // Didn't find one; add it.
  85. //
  86. ptRet = TTrace::pNew( this, ulHash, pvBackTrace, ppTrace );
  87. }
  88. return ptRet;
  89. }
  90. TBackTraceDB::TTrace*
  91. TBackTraceDB::
  92. ptFind(
  93. IN ULONG ulHash,
  94. IN PVOID pvBackTrace,
  95. OUT TTrace ***pppTrace
  96. )
  97. /*++
  98. Routine Description:
  99. Find a backtrace in the database. If one does not exist,
  100. then return NULL and a pointer to where it would exist
  101. in the database.
  102. Arguments:
  103. ulHash - Hash of the backtrace.
  104. pvBackTrace - Backtrace to find.
  105. ppTrace - If not found, this holds the address of where it should
  106. be stored in the database. Adding the trace here is sufficient
  107. to add it.
  108. Return Value:
  109. TTrace* the actual trace, NULL if not found.
  110. --*/
  111. {
  112. //
  113. // Traverse the binary tree until we find the end or the
  114. // right one.
  115. //
  116. TTrace **ppTrace = &_pTraceHead;
  117. while( *ppTrace ){
  118. //
  119. // Check if this one matches ours.
  120. //
  121. COMPARE Compare = (*ppTrace)->eCompareHash( ulHash );
  122. if( Compare == kEqual ){
  123. //
  124. // Now do slow compare in case the hash is a collision.
  125. //
  126. Compare = (*ppTrace)->eCompareBackTrace( pvBackTrace );
  127. if( Compare == kEqual ){
  128. //
  129. // Break out of while loop and quit.
  130. //
  131. break;
  132. }
  133. }
  134. ppTrace = ( Compare == kLess ) ?
  135. &(*ppTrace)->_pLeft :
  136. &(*ppTrace)->_pRight;
  137. }
  138. *pppTrace = ppTrace;
  139. return *ppTrace;
  140. }
  141. /********************************************************************
  142. TBackTraceDB::TTrace
  143. ********************************************************************/
  144. COMPARE
  145. TBackTraceDB::
  146. TTrace::
  147. eCompareHash(
  148. ULONG ulHash
  149. ) const
  150. /*++
  151. Routine Description:
  152. Quickly compare two trace hashes.
  153. Arguments:
  154. ulHash - Input hash.
  155. Return Value:
  156. --*/
  157. {
  158. if( _ulHash < ulHash ){
  159. return kLess;
  160. }
  161. if( _ulHash > ulHash ){
  162. return kGreater;
  163. }
  164. return kEqual;
  165. }
  166. COMPARE
  167. TBackTraceDB::
  168. TTrace::
  169. eCompareBackTrace(
  170. PVOID pvBackTrace
  171. ) const
  172. /*++
  173. Routine Description:
  174. Compare backtrace to one stored in this.
  175. Arguments:
  176. pvBackTrace - Must be NULL terminated.
  177. Return Value:
  178. COMAARE: kLess, kEqual, kGreater.
  179. --*/
  180. {
  181. PVOID *pSrc;
  182. PVOID *pDest;
  183. for( pSrc = (PVOID*)this, pDest = (PVOID*)&pvBackTrace;
  184. *pSrc && *pDest;
  185. pSrc++, pDest++ ) {
  186. if ( *pSrc != *pDest ){
  187. return (DWORD)*pSrc < (DWORD)*pDest ?
  188. kLess :
  189. kGreater;
  190. }
  191. }
  192. return kEqual;
  193. }
  194. TBackTraceDB::TTrace*
  195. TBackTraceDB::
  196. TTrace::
  197. pNew(
  198. IN TBackTraceDB *pBackTraceDB,
  199. IN ULONG ulHash,
  200. IN PVOID pvBackTrace,
  201. OUT TTrace ** ppTrace
  202. )
  203. /*++
  204. Routine Description:
  205. Constructs a new TTrace and puts it in pBackTraceDB.
  206. Assumes the trace does _not_ exist already, and ppTrace points
  207. to the place where it should be stored to ensure the database
  208. is kept consistent.
  209. Arguments:
  210. pBackTraceDB - Storage for the new trace.
  211. ulHash - Hash for the trace.
  212. pvBackTrace - The actual backtrace.
  213. ppTrace - Where the trace should be stored in the database.
  214. Return Value:
  215. TTrace* - New trace, NULL if failed.
  216. --*/
  217. {
  218. COUNT cCalls;
  219. PVOID *ppvCalls;
  220. //
  221. // Calculate size of backtrace.
  222. //
  223. for( ppvCalls = (PVOID*)pvBackTrace, cCalls = 0;
  224. *ppvCalls;
  225. ++ppvCalls, ++cCalls )
  226. ;
  227. COUNTB cbSize = OFFSETOF( TTrace, apvBackTrace ) +
  228. cCalls * sizeof( PVOID );
  229. TTrace* pTrace = (TTrace*)pBackTraceDB->_pMemBlock->pvAlloc( cbSize );
  230. if( pTrace ){
  231. pTrace->_pLeft = NULL;
  232. pTrace->_pRight = NULL;
  233. pTrace->_ulHash = ulHash;
  234. CopyMemory( pTrace->apvBackTrace,
  235. (PVOID*)pvBackTrace,
  236. cCalls * sizeof( PVOID ));
  237. //
  238. // Add it in the right spot into the database.
  239. //
  240. *ppTrace = pTrace;
  241. }
  242. return pTrace;
  243. }
  244. /********************************************************************
  245. Back tracing: abstract base class.
  246. ********************************************************************/
  247. VBackTrace::
  248. VBackTrace(
  249. DWORD fdwOptions1,
  250. DWORD fdwOptions2
  251. ) : _fdwOptions1( fdwOptions1 ), _fdwOptions2( fdwOptions2 )
  252. {
  253. }
  254. VBackTrace::
  255. ~VBackTrace(
  256. VOID
  257. )
  258. {
  259. }
  260. BOOL
  261. VBackTrace::
  262. bInit(
  263. VOID
  264. )
  265. {
  266. InitializeCriticalSection( &gcsBackTrace );
  267. return TRUE;
  268. }
  269. /********************************************************************
  270. Back tracing to memory.
  271. ********************************************************************/
  272. TBackTraceMem::
  273. TBackTraceMem(
  274. DWORD fdwOptions1,
  275. DWORD fdwOptions2
  276. ) : VBackTrace( fdwOptions1, fdwOptions2 ), _uNextFree( 0 )
  277. {
  278. _pLines = new TLine[kMaxCall];
  279. if( _pLines ){
  280. ZeroMemory( _pLines, sizeof( TLine[kMaxCall] ));
  281. }
  282. }
  283. TBackTraceMem::
  284. ~TBackTraceMem(
  285. VOID
  286. )
  287. {
  288. UINT i;
  289. TLine* pLine;
  290. if( _pLines ){
  291. for( i=0, pLine = _pLines; i< kMaxCall; i++, pLine++ ){
  292. if( _fdwOptions1 & kString ){
  293. DbgFreeMem( (PVOID)pLine->_dwInfo1 );
  294. }
  295. if( _fdwOptions2 & kString ){
  296. DbgFreeMem( (PVOID)pLine->_dwInfo2 );
  297. }
  298. }
  299. delete [] _pLines;
  300. }
  301. }
  302. VOID
  303. TBackTraceMem::
  304. vCaptureLine(
  305. IN OUT TLine* pLine,
  306. IN DWORD dwInfo1,
  307. IN DWORD dwInfo2,
  308. IN DWORD dwInfo3
  309. )
  310. /*++
  311. Routine Description:
  312. Captures information into a TLine structure; freeing previous
  313. contents if necessary.
  314. Arguments:
  315. pLine - Fully initialized pLine structure. On output, everything
  316. _except_ _hTrace is filled in.
  317. ** Both apvBackTrace && pulHash must both be valid if either is valid **
  318. apvBackTrace - Buffer to receive backtrace.
  319. pulHash - Buffer to receive ulHash.
  320. Return Value:
  321. --*/
  322. {
  323. //
  324. // Free memory if necessary.
  325. //
  326. if( _fdwOptions1 & kString ) {
  327. DbgFreeMem( (PVOID)pLine->_dwInfo1 );
  328. }
  329. if( _fdwOptions2 & kString ) {
  330. DbgFreeMem( (PVOID)pLine->_dwInfo2 );
  331. }
  332. pLine->_dwTickCount = GetTickCount();
  333. pLine->_dwInfo1 = dwInfo1;
  334. pLine->_dwInfo2 = dwInfo2;
  335. pLine->_dwInfo3 = dwInfo3;
  336. pLine->_dwThreadId = GetCurrentThreadId();
  337. pLine->_hTrace = NULL;
  338. #ifdef BACKTRACE_ENABLED
  339. ULONG ulHash;
  340. //
  341. // Capture a backtrace at this spot for debugging.
  342. //
  343. UINT uDepth = RtlCaptureStackBackTrace( 2,
  344. kMaxDepth,
  345. pLine->_apvBackTrace,
  346. &ulHash );
  347. //
  348. // NULL terminate.
  349. //
  350. pLine->_apvBackTrace[uDepth] = NULL;
  351. #else
  352. pLine->_apvBackTrace[0] = NULL;
  353. #endif
  354. }
  355. PVOID
  356. TBackTraceMem::
  357. pvCapture(
  358. DWORD dwInfo1,
  359. DWORD dwInfo2,
  360. DWORD dwInfo3
  361. )
  362. {
  363. UINT uDepth;
  364. TLine* pLine;
  365. if( !_pLines ){
  366. return NULL;
  367. }
  368. EnterCriticalSection( &gcsBackTrace );
  369. pLine = &_pLines[_uNextFree];
  370. vCaptureLine( pLine, dwInfo1, dwInfo2, dwInfo3 );
  371. _uNextFree++;
  372. if( _uNextFree == kMaxCall )
  373. _uNextFree = 0;
  374. LeaveCriticalSection( &gcsBackTrace );
  375. return (PVOID)pLine->_hTrace;
  376. }
  377. /********************************************************************
  378. Backtracing to File.
  379. ********************************************************************/
  380. COUNT TBackTraceFile::gcInstances;
  381. TBackTraceFile::
  382. TBackTraceFile(
  383. DWORD fdwOptions1,
  384. DWORD fdwOptions2
  385. ) : VBackTrace( fdwOptions1, fdwOptions2 )
  386. {
  387. TCHAR szFile[kMaxPath];
  388. EnterCriticalSection( &gcsBackTrace );
  389. wsprintf( szFile,
  390. TEXT( "spl_%d.%d.log" ),
  391. GetCurrentProcessId(),
  392. gcInstances );
  393. ++gcInstances;
  394. LeaveCriticalSection( &gcsBackTrace );
  395. _hFile = CreateFile( szFile,
  396. GENERIC_WRITE,
  397. FILE_SHARE_READ,
  398. NULL,
  399. OPEN_ALWAYS,
  400. FILE_ATTRIBUTE_COMPRESSED,
  401. NULL );
  402. if( _hFile == INVALID_HANDLE_VALUE ){
  403. OutputDebugStringA( "SPLLIB: Unable to open file " );
  404. OutputDebugString( szFile );
  405. OutputDebugStringA( "\n" );
  406. return;
  407. }
  408. }
  409. TBackTraceFile::
  410. ~TBackTraceFile(
  411. VOID
  412. )
  413. {
  414. if( _hFile != INVALID_HANDLE_VALUE ){
  415. CloseHandle( _hFile );
  416. }
  417. }
  418. PVOID
  419. TBackTraceFile::
  420. pvCapture(
  421. DWORD dwInfo1,
  422. DWORD dwInfo2,
  423. DWORD dwInfo3
  424. )
  425. {
  426. TLine Line;
  427. PVOID apvBackTrace[kMaxDepth+1];
  428. DWORD dwWritten;
  429. CHAR szLine[kMaxLineStr];
  430. szLine[0] = 0;
  431. #ifdef BACKTRACE_ENABLED
  432. ULONG ulHash;
  433. //
  434. // Capture a backtrace at this spot for debugging.
  435. //
  436. UINT uDepth = RtlCaptureStackBackTrace( 2,
  437. kMaxDepth,
  438. apvBackTrace,
  439. &ulHash );
  440. #endif
  441. EnterCriticalSection( &gcsBackTrace );
  442. //
  443. // Print out strings as appropriate.
  444. //
  445. if( _fdwOptions1 & kString ){
  446. WriteFile( _hFile,
  447. (LPCVOID)dwInfo1,
  448. lstrlenA( (LPCSTR)dwInfo1 ),
  449. &dwWritten,
  450. NULL );
  451. }
  452. if( _fdwOptions2 & kString ){
  453. WriteFile( _hFile,
  454. (LPCVOID)dwInfo2,
  455. lstrlenA( (LPCSTR)dwInfo2 ),
  456. &dwWritten,
  457. NULL );
  458. }
  459. //
  460. // Print out the hex info.
  461. //
  462. wsprintfA( szLine,
  463. "\n\t%08x %08x %08x threadid=%x tc=%x < %x >\n",
  464. dwInfo1,
  465. dwInfo2,
  466. dwInfo3,
  467. GetCurrentThreadId(),
  468. GetTickCount(),
  469. dwInfo1 + dwInfo2 );
  470. if( _hFile ){
  471. WriteFile( _hFile, szLine, lstrlenA( szLine ), &dwWritten, NULL );
  472. }
  473. #ifdef BACKTRACE_ENABLED
  474. //
  475. // Print out the backtrace.
  476. //
  477. UINT i;
  478. UINT uLineEnd = 1;
  479. szLine[0] = '\t';
  480. for( i=0; i < uDepth; ++i ){
  481. uLineEnd += wsprintfA( szLine + uLineEnd, "%08x ", apvBackTrace[i] );
  482. }
  483. if( _hFile && i ){
  484. szLine[uLineEnd++] = '\n';
  485. WriteFile( _hFile, szLine, uLineEnd, &dwWritten, NULL );
  486. }
  487. #endif
  488. //
  489. // Add extra blank line.
  490. //
  491. szLine[0] = '\n';
  492. WriteFile( _hFile, szLine, 1, &dwWritten, NULL );
  493. LeaveCriticalSection( &gcsBackTrace );
  494. //
  495. // Free memory if necessary.
  496. //
  497. if( _fdwOptions1 & kString ) {
  498. DbgFreeMem( (PVOID)dwInfo1 );
  499. }
  500. if( _fdwOptions2 & kString ) {
  501. DbgFreeMem( (PVOID)dwInfo2 );
  502. }
  503. return NULL;
  504. }
  505. #endif // #ifdef DBG