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.

578 lines
15 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1992.
  5. //
  6. // File: otrack.cxx
  7. //
  8. // Contents: Object tracking system
  9. //
  10. // Classes: ObjectTracker
  11. //
  12. // History: 06-Apr-92 MikeSe Created
  13. // 30-Sep-93 KyleP DEVL obsolete
  14. // 15-Jul-94 DonCl grabbed from common put in forms.
  15. // absolutely minimal changes to
  16. // get it working.
  17. //
  18. //--------------------------------------------------------------------------
  19. #include "dswarn.h"
  20. #include <ADs.hxx>
  21. #include "symtrans.h"
  22. #include "otrackp.hxx"
  23. // This is all unused in the retail build
  24. #if DBG == 1
  25. CRITICAL_SECTION g_csOT;
  26. // this is a dummy item used as the head of the doubly-linked list
  27. // of TrackLinks, and a mutex to protect it
  28. static TrackLink tlHead = { &tlHead, &tlHead };
  29. // this is a dummy item used as the head of the doubly-linked list
  30. // of NameEntrys
  31. static NameEntry neHead = { &neHead, &neHead };
  32. static char * apszTypes[] = {"Create", "AddRef", "Release"};
  33. // initialize class static data
  34. int ObjectTracker::_TrackAll = GetProfileInt(L"Object Track",L"DEFAULT",1);
  35. // standard debugging stuff
  36. DECLARE_INFOLEVEL(Ot)
  37. extern void RecordAction ( TrackLink *tl, FrameType ft, ULONG cRefCount );
  38. extern void _cdecl EstablishHistory ( FrameRecord * fr, int nSkip );
  39. extern void DumpHistory ( unsigned long fDebugMask, TrackLink *tl );
  40. //+-------------------------------------------------------------------------
  41. //
  42. // Member: ObjectTracker::ObjectTracker, protected
  43. //
  44. // Synopsis: Contructor
  45. //
  46. // Effects: Allocates TrackLink structure and initialises it.
  47. //
  48. // Arguments: None
  49. //
  50. // History: 6-Apr-92 MikeSe Created
  51. //
  52. // Notes:
  53. //
  54. //--------------------------------------------------------------------------
  55. EXPORTIMP
  56. ObjectTracker::ObjectTracker ()
  57. :_ulRefs(1)
  58. {
  59. // Allocate the structure which maintains the tracking history.
  60. // We also make space for the first FrameRecord.
  61. HRESULT hr = MemAlloc ( sizeof(TrackLink) + sizeof(FrameRecord),
  62. (void**)&_tl);
  63. if ( FAILED(hr) )
  64. {
  65. OtDebugOut ((DEB_OT_ERRORS,
  66. "Unable to establish tracking for %lx\n",
  67. this ));
  68. }
  69. else
  70. {
  71. _tl->potr = this;
  72. _tl->ulSig = TRACK_LINK_SIGNATURE;
  73. _tl->pszName = NULL;
  74. FrameRecord * fr = (FrameRecord*) ( _tl + 1 );
  75. if ( OtInfoLevel & DEB_OT_CALLERS )
  76. {
  77. EstablishHistory ( fr, 1 );
  78. }
  79. fr->ft = FT_CREATE;
  80. fr->cRefCount = 1;
  81. fr->frNext = NULL;
  82. _tl->frFirst = _tl->frLast = fr;
  83. // insert at end of list, with concurrency control
  84. EnterCriticalSection(&g_csOT);
  85. TrackLink * tll = tlHead.tlPrev;
  86. tll->tlNext = tlHead.tlPrev = _tl;
  87. _tl->tlNext = &tlHead;
  88. _tl->tlPrev = tll;
  89. LeaveCriticalSection(&g_csOT);
  90. OtDebugOut ((DEB_OT_ACTIONS, "New object at %lx\n", this ));
  91. }
  92. }
  93. //+-------------------------------------------------------------------------
  94. //
  95. // Member: ObjectTracker::TrackClassName, protected
  96. //
  97. // Synopsis: Records class name for tracked object
  98. //
  99. // Arguments: [pszName] -- class name
  100. //
  101. // History: 6-Apr-92 MikeSe Created
  102. //
  103. // Notes:
  104. //
  105. //--------------------------------------------------------------------------
  106. EXPORTIMP void
  107. ObjectTracker::TrackClassName (
  108. char * pszName )
  109. {
  110. if ( _tl != NULL )
  111. {
  112. OtAssert (( _tl->ulSig == TRACK_LINK_SIGNATURE ));
  113. // Copy the class name so we don't lose it if the class DLL is
  114. // unloaded.
  115. ULONG cBytes = strlen ( pszName ) + 1;
  116. HRESULT hr = MemAlloc ( cBytes, (void**)&(_tl->pszName) );
  117. if ( SUCCEEDED(hr) )
  118. {
  119. memcpy ( _tl->pszName, pszName, cBytes );
  120. }
  121. else
  122. {
  123. OtDebugOut((DEB_OT_ERRORS,"Memory allocation failure %lx\n",hr));
  124. _tl->pszName = "Name lost";
  125. }
  126. _tl->fTrack = IsClassTracking(pszName);
  127. }
  128. }
  129. //+-------------------------------------------------------------------------
  130. //
  131. // Member: ObjectTracker::StdAddRef, public
  132. //
  133. // Synopsis: Standard implementation of AddRef for tracked objects
  134. //
  135. // Effects: Increments ref count, records history
  136. //
  137. // Returns: S_OK
  138. //
  139. // Modifies: _ulRefs
  140. //
  141. // Derivation: Never
  142. //
  143. // History: 31-Jul-92 MikeSe Created
  144. //
  145. // Notes:
  146. //
  147. //--------------------------------------------------------------------------
  148. EXPORTIMP ULONG
  149. ObjectTracker::StdAddRef()
  150. {
  151. InterlockedIncrement ( (LONG*)&_ulRefs );
  152. if (_tl->fTrack)
  153. {
  154. OtDebugOut ((DEB_OT_ACTIONS, "AddRef [%d] of object at %lx (%s)\n",
  155. _ulRefs, this, _tl->pszName ));
  156. RecordAction ( _tl, FT_ADDREF, _ulRefs );
  157. }
  158. return _ulRefs;
  159. }
  160. //+-------------------------------------------------------------------------
  161. //
  162. // Member: ObjectTracker::StdRelease, public
  163. //
  164. // Synopsis: Helper function for standard implementation of Release()
  165. //
  166. // Effects: Decrements ref count, records history
  167. //
  168. // Returns: SUCCESS_NO_MORE iff ref count reached zero.
  169. // Otherwise S_OK or an error.
  170. //
  171. // History: 31-Jul-92 MikeSe Created
  172. //
  173. // Notes:
  174. //
  175. //--------------------------------------------------------------------------
  176. EXPORTIMP ULONG
  177. ObjectTracker::StdRelease ()
  178. {
  179. LONG lResult = InterlockedDecrement((LONG*)&_ulRefs);
  180. if (_tl->fTrack)
  181. {
  182. OtDebugOut ((DEB_OT_ACTIONS, "Release [%d] of object at %lx (%s)\n",
  183. _ulRefs, this, _tl->pszName ));
  184. RecordAction ( _tl, FT_RELEASE, _ulRefs );
  185. }
  186. return (lResult==0)?0:_ulRefs;
  187. }
  188. //+-------------------------------------------------------------------------
  189. //
  190. // Member: ObjectTracker::~ObjectTracker, protected
  191. //
  192. // Synopsis: Destructor
  193. //
  194. // Effects: Remove this item, along with all history, from the
  195. // tracking list
  196. //
  197. // History: 6-Apr-92 MikeSe Created
  198. //
  199. // Notes:
  200. //
  201. //--------------------------------------------------------------------------
  202. EXPORTIMP
  203. ObjectTracker::~ObjectTracker()
  204. {
  205. if ( _tl != NULL )
  206. {
  207. OtDebugOut ((DEB_OT_ACTIONS, "Delete of object at %lx [%s]\n",
  208. this, _tl->pszName ));
  209. OtAssert (( _tl->ulSig == TRACK_LINK_SIGNATURE ));
  210. // OtAssert ( _ulRefs == 0 );
  211. // unlink, with concurrency control
  212. EnterCriticalSection(&g_csOT);
  213. TrackLink * tlp = _tl->tlPrev;
  214. TrackLink * tln = _tl->tlNext;
  215. tln->tlPrev = tlp;
  216. tlp->tlNext = tln;
  217. LeaveCriticalSection(&g_csOT);
  218. if ((_tl->fTrack) && (OtInfoLevel & DEB_OT_DELETE))
  219. {
  220. DumpHistory ( DEB_OT_DELETE, _tl );
  221. }
  222. if (_tl->pszName) {
  223. MemFree(_tl->pszName);
  224. }
  225. MemFree ( _tl );
  226. }
  227. }
  228. //+-------------------------------------------------------------------------
  229. //
  230. // Member: ObjectTracker::DumpTrackingInfo, public
  231. //
  232. // Synopsis: Dumps out the tracking list
  233. //
  234. // History: 6-Apr-92 MikeSe Created
  235. //
  236. // Notes:
  237. //
  238. //--------------------------------------------------------------------------
  239. EXPORTIMP void
  240. ObjectTracker::DumpTrackingInfo (
  241. int fDeleteNode)
  242. {
  243. TrackLink * tl = tlHead.tlNext;
  244. BOOL fHeader = FALSE;
  245. while ( tl != &tlHead )
  246. {
  247. // This is an unreleased item. Print out the history info
  248. if ( !fHeader )
  249. {
  250. OtDebugOut((DEB_OT_OBJECTS, "****************************\n"));
  251. OtDebugOut((DEB_OT_OBJECTS, "* Unreleased objects found *\n"));
  252. OtDebugOut((DEB_OT_OBJECTS, "****************************\n"));
  253. fHeader = TRUE;
  254. }
  255. OtDebugOut ((DEB_OT_OBJECTS,
  256. "Object at %lx (%s)\n",
  257. tl->potr,
  258. tl->pszName ));
  259. OtDebugOut ((DEB_OT_OBJECTS,
  260. " Reference count = %d\n",
  261. tl->potr->GetRefCount() ));
  262. DumpHistory ( DEB_OT_CALLERS, tl );
  263. if (fDeleteNode)
  264. {
  265. // unlink, with concurrency control
  266. EnterCriticalSection(&g_csOT);
  267. tl->potr->_tl = NULL;
  268. TrackLink * tlp = tl->tlPrev;
  269. TrackLink * tln = tl->tlNext;
  270. tln->tlPrev = tlp;
  271. tlp->tlNext = tln;
  272. LeaveCriticalSection(&g_csOT);
  273. MemFree ( tl );
  274. tl = tln;
  275. }
  276. else
  277. {
  278. tl = tl->tlNext;
  279. }
  280. }
  281. // delete all the name entries
  282. if (fDeleteNode)
  283. {
  284. EnterCriticalSection(&g_csOT);
  285. // find the entry if there is one
  286. NameEntry *ne = neHead.neNext;
  287. while (ne != &neHead)
  288. {
  289. // unlink, with concurrency control
  290. NameEntry * nep = ne->nePrev;
  291. NameEntry * nen = ne->neNext;
  292. nen->nePrev = nep;
  293. nep->neNext = nen;
  294. MemFree ( ne );
  295. ne = nen;
  296. }
  297. LeaveCriticalSection(&g_csOT);
  298. }
  299. }
  300. //+-------------------------------------------------------------------------
  301. //
  302. // Member: TrackClass
  303. //
  304. // Synopsis: Tells the object tracker to start/stop tracking the specified
  305. // class of objects.
  306. //
  307. // Arguments: [fTrack -- debug mask controlling the output
  308. // [pszName] -- TrackLink record
  309. //
  310. // History: 14-Apr-93 Rickhi Created
  311. //
  312. // Notes:
  313. //
  314. //--------------------------------------------------------------------------
  315. EXPORTIMP
  316. void ObjectTracker::TrackClass(int fTrack, char * pszClassName)
  317. {
  318. if (pszClassName == NULL)
  319. {
  320. // set default for ALL classes
  321. _TrackAll = fTrack;
  322. return;
  323. }
  324. // find the entry if there is one
  325. NameEntry *ne = neHead.neNext;
  326. while (ne != &neHead)
  327. {
  328. if (!strcmp(ne->pszName, pszClassName))
  329. {
  330. // found our entry, update the flag
  331. ne->fTrack = fTrack;
  332. return;
  333. }
  334. ne = ne->neNext;
  335. }
  336. // its not in the list
  337. HRESULT hr = MemAlloc( sizeof(NameEntry), (void **)&ne);
  338. if ( FAILED(hr) )
  339. {
  340. OtDebugOut((DEB_OT_ERRORS,
  341. "Unable to record class for tracking %s\n",
  342. pszClassName));
  343. }
  344. else
  345. {
  346. ne->pszName = pszClassName;
  347. ne->fTrack = fTrack;
  348. // insert at end of list, with concurrency control
  349. EnterCriticalSection(&g_csOT);
  350. NameEntry *neH = neHead.nePrev;
  351. neH->neNext = neHead.nePrev = ne;
  352. ne->neNext = &neHead;
  353. ne->nePrev = ne;
  354. LeaveCriticalSection(&g_csOT);
  355. }
  356. }
  357. //+-------------------------------------------------------------------------
  358. //
  359. // Member: IhrlassTracking, private
  360. //
  361. // Synopsis: returns TRUE if the object is currently tracked
  362. //
  363. // Arguments: [pszClassName] -- class name
  364. //
  365. // History: 14-Apr-93 Rickhi Created
  366. //
  367. // Notes:
  368. //
  369. //--------------------------------------------------------------------------
  370. EXPORTIMP
  371. int ObjectTracker::IsClassTracking(char * pszClassName)
  372. {
  373. // find the entry if there is one
  374. NameEntry *ne = neHead.neNext;
  375. while (ne != &neHead)
  376. {
  377. if (!strcmp(ne->pszName, pszClassName))
  378. {
  379. return ne->fTrack;
  380. }
  381. ne = ne->neNext;
  382. }
  383. return GetProfileIntA("Object Track",pszClassName,_TrackAll);
  384. }
  385. //+-------------------------------------------------------------------------
  386. //
  387. // Function: DumpHistory
  388. //
  389. // Synopsis: Dumps the call history represented by a particular TrackLink
  390. //
  391. // Arguments: [fDebugMask] -- debug mask controlling the output
  392. // [tl] -- TrackLink record
  393. //
  394. // History: 28-Jul-92 MikeSe Created
  395. //
  396. // Notes:
  397. //
  398. //--------------------------------------------------------------------------
  399. void DumpHistory ( unsigned long fDebugMask, TrackLink * tl )
  400. {
  401. // we can't call TranslateAddress without access to NT header files
  402. #ifndef MSVC
  403. #ifndef WIN95
  404. //
  405. // Only do all of this work if it will output anything!
  406. //
  407. if (OtInfoLevel & fDebugMask)
  408. {
  409. OtDebugOut ((fDebugMask, " Call history follows:\n" ));
  410. FrameRecord * fr = tl->frFirst;
  411. while ( fr != NULL )
  412. {
  413. char achBuffer[MAX_TRANSLATED_LEN];
  414. OtDebugOut ((fDebugMask,
  415. "\t%s [%d]\n",
  416. apszTypes[fr->ft],
  417. fr->cRefCount ));
  418. for ( int I=0; (I < MAX_CALLERS) && (fr->callers[I]); I++ )
  419. {
  420. TranslateAddress ( fr->callers[I], achBuffer );
  421. OtDebugOut ((fDebugMask, "\t %s\n", achBuffer));
  422. }
  423. fr = fr->frNext;
  424. }
  425. }
  426. #endif
  427. #endif
  428. }
  429. //+-------------------------------------------------------------------------
  430. //
  431. // Function: RecordAction
  432. //
  433. // Synopsis: Record an AddRef/Release
  434. //
  435. // Effects: Allocates and fills in a new frame record
  436. //
  437. // Arguments: [tl] -- TrackLink for object being tracked
  438. // [ft] -- Frame type (FT_ADDREF, FT_RELEASE)
  439. // [cRefCount] -- current ref count
  440. //
  441. // History: 6-Apr-92 MikeSe Created
  442. //
  443. // Notes:
  444. //
  445. //--------------------------------------------------------------------------
  446. void RecordAction ( TrackLink * tl, FrameType ft, ULONG cRefCount )
  447. {
  448. // Record the activity only if DEB_OT_CALLERS is set
  449. if ( tl != NULL && (OtInfoLevel & DEB_OT_CALLERS))
  450. {
  451. OtAssert(tl->ulSig == TRACK_LINK_SIGNATURE );
  452. FrameRecord * fr;
  453. HRESULT hr;
  454. hr = MemAlloc(sizeof(FrameRecord), (void **)&fr);
  455. if ( FAILED(hr) )
  456. {
  457. OtDebugOut((DEB_OT_ERRORS,
  458. "Unable to record history for %lx\n",
  459. tl->potr));
  460. }
  461. else
  462. {
  463. // Save call history
  464. EstablishHistory ( fr, 2 );
  465. fr->ft = ft;
  466. fr->cRefCount = cRefCount;
  467. fr->frNext = NULL;
  468. // Add to list, with concurrency control
  469. EnterCriticalSection(&g_csOT);
  470. FrameRecord * frl = tl->frLast;
  471. frl->frNext = tl->frLast = fr;
  472. LeaveCriticalSection(&g_csOT);
  473. }
  474. }
  475. }
  476. //+-------------------------------------------------------------------------
  477. //
  478. // Function: EstablishHistory
  479. //
  480. // Synopsis: Records calling history for an operation
  481. //
  482. // Effects: Walks back through call frames recording caller addresses.
  483. //
  484. // Arguments: [fr] -- FrameRecord in which to save history
  485. // [nFramesSkip] -- number of frames to skip before
  486. // recording.
  487. //
  488. // History: 6-Apr-92 MikeSe Created [from PaulC's imalloc code]
  489. // 19-Apr-94 MikeSe Converted to use RtlCaptureStackBacktrace
  490. //
  491. // Notes:
  492. //
  493. //--------------------------------------------------------------------------
  494. void _cdecl
  495. EstablishHistory (
  496. FrameRecord * fr,
  497. int nFramesSkip
  498. )
  499. {
  500. #if (defined(i386) && !defined(WIN95))
  501. memset ( fr->callers, 0, MAX_CALLERS * sizeof(void*) );
  502. ULONG ulHash;
  503. RtlCaptureStackBackTrace ( nFramesSkip, MAX_CALLERS,
  504. fr->callers, &ulHash );
  505. #endif // i386
  506. }
  507. #endif // DBG == 1