os/kernelhwsrv/kerneltest/e32test/debug/d_eventtracker.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     1 // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // e32test\debug\d_eventtracker.cpp
    15 // LDD-based debug agent used to track kernel events.  See
    16 // t_eventtracker.cpp
    17 // 
    18 //
    19 
    20 #include <kernel/kern_priv.h>
    21 #include "reventtracker.h"
    22 #include "d_eventtracker.h"
    23 #include "nk_trace.h"
    24 
    25 #ifdef __MARM__
    26 #include <kernel/kdebug.h>
    27 #endif //__MARM__
    28 
    29 #ifdef _DEBUG
    30 static const char KPanicCat[] = "D_EVENTTRACKER";
    31 #endif // _DEBUG
    32 _LIT(KClientPanicCat, "D_EVENTTRACKER");
    33 
    34 DEventTracker* TheEventTracker;
    35 
    36 //////////////////////////////////////////////////////////////////////////////
    37 
    38 /** Data about objects being tracked.
    39 	All tracked objects are kept in a tracking list.  The object address 
    40 	is a key and so must be unique.
    41  */
    42 
    43 TTrackedItem::TTrackedItem(const DBase* aObject)
    44 	: iObject(aObject), iAccountedFor(EFalse)
    45 	{
    46 	}
    47 	
    48 
    49 /** Subclass for DObjects being tracked */
    50 
    51 TTrackedObject::TTrackedObject(DObject* aObject, TObjectType aType)
    52 	:	TTrackedItem(aObject),
    53 		iType(aType)
    54 	{
    55 	aObject->FullName(iFullName);
    56 	}
    57 
    58 TBool TTrackedObject::CheckIntegrity(const TDesC& aName, TObjectType aType) const
    59 	{
    60 	TBool ok = EFalse;
    61 	
    62 	if (aType == iType)
    63 		{
    64 		if (aType == EThread || aType == EProcess)
    65 			{
    66 			ok = (iFullName == aName);
    67 			}
    68 		else
    69 			{
    70 			ok = ETrue;
    71 			}
    72 		}
    73 
    74 	if (!ok)
    75 		{
    76 		Kern::Printf("EVENTTRACKER: container / tracking list mismatch (0x%08x)", iObject);
    77 		Kern::Printf("EVENTTRACKER: \tcontainer: %S (type %d)", &aName, aType);
    78 		Kern::Printf("EVENTTRACKER: \ttracking list: %S (type %d)", &iFullName, iType);
    79 		}
    80 		
    81 	return ok;
    82 	}
    83 
    84 /** Subclass for DCodeSegs being tracked */
    85 
    86 TTrackedCodeSeg::TTrackedCodeSeg(const DCodeSeg* aCodeSeg)
    87 	:	TTrackedItem(aCodeSeg),
    88 		iAccessCount(aCodeSeg ? aCodeSeg->iAccessCount : 0)
    89 	{
    90 	}
    91 
    92 TBool TTrackedCodeSeg::CheckIntegrity(TInt aAccessCount) const
    93 	{
    94 	const TBool ok = (aAccessCount == iAccessCount);
    95 
    96 	if (!ok)
    97 		{
    98 		Kern::Printf("EVENTTRACKER: code seg list / tracking list mismatch (0x%08x)", iObject);
    99 		Kern::Printf("EVENTTRACKER: \tcode seg list: %d", aAccessCount);
   100 		Kern::Printf("EVENTTRACKER: \ttracking list: %d", iAccessCount);
   101 		}
   102 		
   103 	return ok;
   104 	}
   105 
   106 
   107 /** Event handler and container for all objects being tracked.  */
   108 
   109 DEventTracker::DEventTracker()
   110 	:	DKernelEventHandler(EventHandler, this)
   111 	{
   112 	__ASSERT_DEBUG(!TheEventTracker, Kern::Fault(KPanicCat, __LINE__));
   113 	
   114 	TheEventTracker = this;
   115 	}
   116 
   117 
   118 //
   119 // If aUseHook is true, the event tracker hooks the stop-mode debugger 
   120 // breakpoint in preference to adding itself to the kernel event handler
   121 // queue.  In order to clean up on its destruction, it has to
   122 // reset the breakpoint by installing a dummy nop breakpoint
   123 // handler, which is cut-and-pasted from kdebug.dll in order to
   124 // avoid a dependency on kdebug.dll.  In order to use the event
   125 // tracker using the stop-mode debugger breakpoint rather than
   126 // the kernel event handler queue, kdebug.dll must be present in
   127 // the ROM
   128 //
   129 TInt DEventTracker::Create(DLogicalDevice* aDevice, TBool aUseHook)
   130 	{
   131 	TInt err = aDevice->Open();
   132 
   133 	if (err)
   134 		{
   135 		return err;
   136 		}
   137 	
   138 	iDevice = aDevice;
   139 
   140 	err = Kern::MutexCreate(iLock, _L("EventHandlerLock"), KMutexOrdNone);
   141 
   142 	if (!err)
   143 		{
   144 		if (aUseHook)
   145 			{
   146 			// Find debugger info, if any
   147 			DDebuggerInfo* const debugInfo = Kern::SuperPage().iDebuggerInfo;
   148 
   149 			// Test stop-mode breakpoint if available
   150 			if (debugInfo)
   151 				{
   152 #ifdef __MARM__
   153 				// Receive all events
   154 				for (TInt i = 0; i < ((EEventLimit + 31) >> 5); ++i)
   155 					{
   156 					debugInfo->iEventMask[i] = 0xffffffffu;
   157 					}
   158 				
   159 				__KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Copying breakpoint (0x%x) into handler (0x%x), size %d", &BranchToEventHandler, debugInfo->iEventHandlerBreakpoint, BreakPointSize()));
   160 
   161 				// Set up breakpoint to call handler
   162 				memcpy((TAny*)debugInfo->iEventHandlerBreakpoint, (TAny*) &BranchToEventHandler, BreakPointSize());
   163 #else // !__MARM__
   164 				err = KErrNotFound;
   165 #endif // __MARM__
   166 				}
   167 			else
   168 				{
   169 				err = KErrNotFound;
   170 				}
   171 			}
   172 		else
   173 			{
   174 			err = Add();
   175 			}
   176 		}
   177 	
   178 	return err;
   179 	}
   180 
   181 
   182 DEventTracker::~DEventTracker()
   183 	{
   184 #ifdef __MARM__
   185 	// Remove breakpoint, if any
   186 	DDebuggerInfo* const debugInfo = Kern::SuperPage().iDebuggerInfo;
   187 	if (debugInfo)
   188 		{
   189 		CopyDummyHandler(debugInfo->iEventHandlerBreakpoint);
   190 		}
   191 #endif //__MARM__
   192 
   193 	// clean-up tracking list
   194 	SDblQueLink* link = iItems.GetFirst();
   195 	while (link)
   196 		{
   197 		delete _LOFF(link, TTrackedItem, iLink);
   198 		link = iItems.GetFirst();
   199 		}
   200 
   201 	if (iLock)
   202 		{
   203 		iLock->Close(NULL);
   204 		}
   205 
   206 	if (iDevice)
   207 		{
   208 		iDevice->Close(NULL);
   209 		}
   210 		
   211 	TheEventTracker = NULL;
   212 	}
   213 
   214 
   215 TInt DEventTracker::Start()
   216 	{
   217 	TInt err = AddExistingObjects();
   218 	
   219 	if (!err)
   220 		{
   221 		iTracking = ETrue;
   222 		}
   223 	
   224 	return err;
   225 	}
   226 
   227 
   228 TInt DEventTracker::Stop()
   229 	{
   230 	NKern::ThreadEnterCS();
   231 	Kern::MutexWait(*iLock);
   232 
   233 	iTracking = EFalse;
   234 
   235 	Kern::MutexSignal(*iLock);
   236 	NKern::ThreadLeaveCS();
   237 
   238 	DumpCounters();
   239 
   240 	return CheckIntegrity();
   241 	}
   242 
   243 
   244 TUint DEventTracker::EventHandler(TKernelEvent aType, TAny* a1, TAny* a2, TAny* aThis)
   245 	{
   246 	return ((DEventTracker*)aThis)->HandleEvent(aType, a1, a2);
   247 	}
   248 
   249 
   250 TUint DEventTracker::HandleEvent(TKernelEvent aType, TAny* a1, TAny* a2)
   251 	{ 
   252 	__KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Handling event type 0x%x", aType));
   253 
   254 	Kern::MutexWait(*iLock);
   255 
   256 	if (iTracking)
   257 		{
   258 		++iCounters[aType];
   259 
   260 		switch (aType)
   261 			{
   262 		case EEventAddProcess:
   263 			AddObject(EProcess, (DObject*)a1);
   264 			break;
   265 		case EEventUpdateProcess:
   266 			// could be renaming or chunk addition/deletion
   267 			UpdateObject(EProcess, (DObject*)a1, EFalse);
   268 			break;
   269 		case EEventRemoveProcess:
   270 			RemoveObject(EProcess, (DObject*)a1);
   271 			break;
   272 		case EEventAddThread:
   273 			AddObject(EThread, (DObject*)a1);
   274 			break;
   275 		case EEventUpdateThread:
   276 			UpdateObject(EThread, (DObject*)a1, ETrue);
   277 			break;
   278 		case EEventRemoveThread:
   279 			RemoveObject(EThread, (DObject*)a1);
   280 			break;
   281 		case EEventAddLibrary:
   282 			{
   283 			DLibrary* pL = (DLibrary*)a1;
   284 			if (pL->iMapCount == 1)
   285 				AddObject(ELibrary, pL);
   286 			}
   287 			break;
   288 		case EEventRemoveLibrary:
   289 			{
   290 			DLibrary* pL = (DLibrary*)a1;
   291 			if (pL->iMapCount == 0)
   292 				RemoveObject(ELibrary, pL);
   293 			}
   294 			break;
   295 		case EEventNewChunk:
   296 			AddObject(EChunk, (DObject*)a1);
   297 			break;
   298 		case EEventDeleteChunk:
   299 			RemoveObject(EChunk, (DObject*)a1);
   300 			break;
   301 		case EEventAddCodeSeg:
   302 			{
   303 			AddCodeSeg((DCodeSeg*)a1, (DProcess*)a2);
   304 			}
   305 			break;
   306 		case EEventRemoveCodeSeg:
   307 			{
   308 			RemoveCodeSeg((DCodeSeg*)a1, (DProcess*)a2);
   309 			}
   310 			break;
   311 		case EEventLoadedProcess:
   312 			{
   313 			__KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Process %O loaded", a1));
   314 			ProcessLoaded((DProcess*)a1);
   315 			}
   316 			break;
   317 		case EEventUnloadingProcess:
   318 			__KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Process %O unloaded", a1));
   319 			break;
   320 		default:
   321 			// no-op
   322 			__KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Handling default case"));
   323 			break;
   324 			}
   325 		}
   326 
   327 	Kern::MutexSignal(*iLock);
   328 
   329 	// Allow other handlers to see this event
   330 	return DKernelEventHandler::ERunNext;
   331 	}
   332 
   333 
   334 void DEventTracker::AddObject(TObjectType aType, DObject* aObject)
   335 	{
   336 	TTrackedObject* trackedObject = (TTrackedObject*)LookupItem(aObject);
   337 
   338 	if (trackedObject)
   339 		{
   340 		Kern::Printf("EVENTTRACKER: Found orphaned object %O in tracking list while adding new object", aObject);
   341 		++iErrorCount;
   342 		return;
   343 		}
   344 
   345 	NKern::ThreadEnterCS();
   346 	trackedObject = new TTrackedObject(aObject, aType);
   347 	NKern::ThreadLeaveCS();
   348 
   349 	if (trackedObject)
   350 		{
   351 		__KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Adding %O (type %d) to tracking list", aObject, aType));
   352 		__KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: DBase ptr == 0x%x", trackedObject->iObject));
   353 		iItems.Add(&trackedObject->iLink);
   354 		}
   355 	else
   356 		{
   357 		iOOM = ETrue;
   358 		++iErrorCount;
   359 		}
   360 	}
   361 
   362 
   363 void DEventTracker::RemoveObject(TObjectType aType, DObject* aObject)
   364 	{
   365 	TTrackedObject* const trackedObject = (TTrackedObject*)LookupItem(aObject);
   366 
   367 	if (trackedObject)
   368 		{
   369  		TFullName name;
   370 		aObject->FullName(name);
   371 		if (!trackedObject->CheckIntegrity(name, aType))
   372 			{
   373 			++iErrorCount;
   374 			}
   375 		__KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Removing %S (type %d) from tracking list", &name, aType));
   376 		trackedObject->iLink.Deque();
   377 
   378 		NKern::ThreadEnterCS();
   379 		delete trackedObject;
   380 		NKern::ThreadLeaveCS();
   381 		}
   382 	else
   383 		{
   384 		Kern::Printf("EVENTTRACKER: %O (type %d) removed but not in tracking list", aObject, aType);
   385 		++iErrorCount;
   386 		}
   387 	}
   388 
   389 
   390 void DEventTracker::UpdateObject(TObjectType aType, DObject* aObject, TBool aMustBeRenamed)
   391 	{
   392 	TTrackedObject* const trackedObject = (TTrackedObject*)LookupItem(aObject);
   393 
   394 	if (trackedObject)
   395 		{
   396 		TFullName newName;
   397 		aObject->FullName(newName);
   398 		if (newName != trackedObject->iFullName)
   399 			{
   400 			__KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Renaming %S --> %S (type %d)", 
   401 						&trackedObject->iFullName, &newName));
   402 			trackedObject->iFullName = newName;
   403 			}
   404 		else if (aMustBeRenamed)
   405 			{
   406 			Kern::Printf("EVENTTRACKER: %O (type %d) renamed with same name", aObject, aType);
   407 			++iErrorCount;
   408 			}
   409 		}
   410 	else
   411 		{
   412 		Kern::Printf("EVENTTRACKER: %O (type %d) updated but not in tracking list", aObject, aType);
   413 		Kern::Printf("EVENTTRACKER: DBase ptr == 0x%x", (DBase*)aObject);
   414 		++iErrorCount;
   415 		}
   416 	}
   417 
   418 void DEventTracker::AddCodeSeg(DCodeSeg* aCodeSeg, DProcess* aProcess)
   419 	{
   420 	TTrackedCodeSeg* trackedCodeSeg = (TTrackedCodeSeg*)LookupItem(aCodeSeg);
   421 
   422 	if (trackedCodeSeg)
   423 		{
   424 		if (aProcess && (aProcess->iTempCodeSeg == aCodeSeg))
   425 			{
   426 			// This is the exe code seg for a loading process
   427 			// and hence the access count is currently
   428 			// incremented by one
   429 			++trackedCodeSeg->iAccessCount;
   430 			}
   431 
   432 		if (trackedCodeSeg->iAccessCount != aCodeSeg->iAccessCount)
   433 			{
   434 			Kern::Printf(
   435 				"EVENTTRACKER: Access count for %C (%d) does not match the tracking list (%d)",
   436 				aCodeSeg,
   437 				aCodeSeg->iAccessCount,
   438 				trackedCodeSeg->iAccessCount
   439 				);
   440 			++iErrorCount;
   441 			return;
   442 			}
   443 		}
   444 
   445 	if (!trackedCodeSeg)
   446 		{
   447 		NKern::ThreadEnterCS();
   448 		trackedCodeSeg = new TTrackedCodeSeg(aCodeSeg);
   449 		NKern::ThreadLeaveCS();
   450 
   451 		if (trackedCodeSeg)
   452 			{
   453 			__KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Adding %C to tracking list", aCodeSeg));
   454 			iItems.Add(&trackedCodeSeg->iLink);
   455 			}
   456 		}
   457 	else // trackedCodeSeg
   458 		{
   459 		if (aProcess)
   460 			{
   461 			__KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Updating access count for %C (%d), attaching to process %O", aCodeSeg, aCodeSeg->iAccessCount, aProcess));
   462 			}
   463 		else // !aProcess
   464 			{
   465 			Kern::Printf("EVENTTRACKER: Found orphaned code seg %C in tracking list while adding new code seg", aCodeSeg);
   466 			++iErrorCount;
   467 			}
   468 		}
   469 
   470 	if (!trackedCodeSeg)
   471 		{
   472 		iOOM = ETrue;
   473 		++iErrorCount;
   474 		}
   475 	}
   476 
   477 void DEventTracker::ProcessLoaded(DProcess* aProcess)
   478 	{
   479 	if (aProcess->iCodeSeg)
   480 		{
   481 		TTrackedCodeSeg* trackedCodeSeg = (TTrackedCodeSeg*)LookupItem(aProcess->iCodeSeg);
   482 
   483 		if (trackedCodeSeg)
   484 			{
   485 			// This is the exe code seg for a process that
   486 			// has completed loading and hence the access
   487 			// count has just been decremented by one
   488 			--trackedCodeSeg->iAccessCount;
   489 			}
   490 		}
   491 	}
   492 
   493 void DEventTracker::RemoveCodeSeg(DCodeSeg* aCodeSeg, DProcess* aProcess)
   494 	{
   495 	TTrackedCodeSeg* const trackedCodeSeg = (TTrackedCodeSeg*)LookupItem(aCodeSeg);
   496 
   497 	if (trackedCodeSeg)
   498 		{
   499 		if (!trackedCodeSeg->CheckIntegrity(aCodeSeg->iAccessCount))
   500 			{
   501 			++iErrorCount;
   502 			}
   503 
   504 		if (aCodeSeg->iAccessCount == 1)
   505 			{
   506 			__KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Removing %C from tracking list, process %O", aCodeSeg, aProcess));
   507 			trackedCodeSeg->iLink.Deque();
   508 
   509 			NKern::ThreadEnterCS();
   510 			delete trackedCodeSeg;
   511 			NKern::ThreadLeaveCS();
   512 			}
   513 		}
   514 	else
   515 		{
   516 		Kern::Printf("EVENTTRACKER: %C removed but not in tracking list.  Removing from process %O", aCodeSeg, aProcess);
   517 		++iErrorCount;
   518 		}
   519 	}
   520 
   521 
   522 /** Add all objects from relevant containers into the tracking list.  */
   523 
   524 TInt DEventTracker::AddExistingObjects()
   525 	{
   526 	// Tracking can be started only after all containers read to avoid 
   527 	// race conditions.
   528 	__ASSERT_DEBUG(!iTracking, Kern::Fault(KPanicCat, __LINE__));
   529 
   530 	TInt err = KErrNone;
   531 	Kern::Printf("Adding processes");
   532 	err = AddObjectsFromContainer(EProcess);
   533 	if (err)
   534 		{
   535 		return err;
   536 		}
   537 	Kern::Printf("Adding threads");
   538 	err = AddObjectsFromContainer(EThread);
   539 	if (err)
   540 		{
   541 		return err;
   542 		}
   543 	Kern::Printf("Adding libraries");
   544 	err = AddObjectsFromContainer(ELibrary);
   545 	if (err)
   546 		{
   547 		return err;
   548 		}
   549 	Kern::Printf("Adding chunks");
   550 	err = AddObjectsFromContainer(EChunk);
   551 	if (err)
   552 		{
   553 		return err;
   554 		}
   555 	Kern::Printf("Adding LDDs");
   556 	err = AddObjectsFromContainer(ELogicalDevice);
   557 	if (err)
   558 		{
   559 		return err;
   560 		}
   561 	Kern::Printf("Adding PDDs");
   562 	err = AddObjectsFromContainer(EPhysicalDevice);
   563 	if (err)
   564 		{
   565 		return err;
   566 		}
   567 	Kern::Printf("Adding code segs");
   568 	return AddCodeSegsFromList();
   569 	}
   570 
   571 /** Add all objects from specified container into tracking list.  */
   572 
   573 TInt DEventTracker::AddObjectsFromContainer(TObjectType aType)
   574 	{
   575 	DObjectCon* const container = Kern::Containers()[aType];
   576 
   577 	NKern::ThreadEnterCS();
   578 	container->Wait();
   579 	
   580 	const TInt count = container->Count();
   581 	TInt err = KErrNone;
   582 	
   583 	for (TInt i = 0; (i < count && err == KErrNone); ++i)
   584 		{
   585 		DObject* const object = (*container)[i];
   586 		if (object->Open() == KErrNone)
   587 			{
   588 			AddObject(aType, object);
   589 			if (iOOM)
   590 				{
   591 				err = KErrNoMemory;
   592 				}
   593 			object->Close(NULL);
   594 			}
   595 		}
   596 
   597 	container->Signal();
   598 	NKern::ThreadLeaveCS();
   599 
   600 	return err;
   601 	}
   602 
   603 TInt DEventTracker::AddCodeSegsFromList()
   604 	{
   605 	Kern::AccessCode();
   606 
   607 	const SDblQueLink* const anchor = &Kern::CodeSegList()->iA;
   608 	for (SDblQueLink* link = Kern::CodeSegList()->First(); link != anchor; link = link->iNext)
   609 		{
   610 		DCodeSeg* const codeSeg = _LOFF(link, DCodeSeg, iLink);
   611 		AddCodeSeg(codeSeg, NULL);
   612 		}
   613 
   614 	Kern::EndAccessCode();
   615 
   616 	return KErrNone;
   617 	}
   618 
   619 
   620 /** Check that tracking list matches existing objects. 
   621 	@return number of discrepancies found
   622  */
   623 
   624 TInt DEventTracker::CheckIntegrity()
   625 	{
   626 	// Tracking must be stopped to avoid race conditions.
   627 	__ASSERT_DEBUG(!iTracking, Kern::Fault(KPanicCat, __LINE__));
   628 
   629 	if (iOOM)
   630 		{
   631 		Kern::Printf("EVENTTRACKER: OOM during tracking");
   632 		}
   633 
   634 	CheckContainerIntegrity(EProcess);
   635 	CheckContainerIntegrity(EThread);
   636 	CheckContainerIntegrity(ELibrary);
   637 	CheckContainerIntegrity(EChunk);
   638 	CheckContainerIntegrity(ELogicalDevice);
   639 	CheckContainerIntegrity(EPhysicalDevice);
   640 	CheckCodeSegListIntegrity();
   641 
   642 	CheckAllAccountedFor();
   643 
   644 	if (iErrorCount)
   645 		{
   646 		Kern::Printf("EVENTTRACKER: %d error(s) found", iErrorCount);
   647 		return KErrGeneral;
   648 		}
   649 
   650 	return KErrNone;
   651 	}
   652 
   653 /** Check all objects in specified container are in tracking list.  */
   654 
   655 void DEventTracker::CheckContainerIntegrity(TObjectType aType)
   656 	{
   657 	DObjectCon* const container = Kern::Containers()[aType];
   658 
   659 	NKern::ThreadEnterCS();
   660 	container->Wait();
   661 
   662 	const TInt count = container->Count();
   663 	
   664 	for (TInt i = 0; i < count; ++i)
   665 		{
   666 		DObject* const object = (*container)[i];
   667 		if (object->Open() == KErrNone)
   668 			{
   669 			TFullName name;
   670 			object->FullName(name);
   671 
   672 			TTrackedObject* const trackedObject = (TTrackedObject*)LookupItem(object);
   673 			
   674 			if (trackedObject)
   675 				{
   676 				trackedObject->iAccountedFor = ETrue;
   677 				if (!trackedObject->CheckIntegrity(name, aType))
   678 					{
   679 					++iErrorCount;
   680 					}
   681 				}
   682 			else
   683 				{
   684 				Kern::Printf("EVENTTRACKER: %S (type %d) is in container but not in tracking list", &name, aType);
   685 				++iErrorCount;
   686 				}
   687 
   688 			object->Close(NULL);
   689 			}
   690 		}
   691 
   692 	container->Signal();
   693 	NKern::ThreadLeaveCS();
   694 	}
   695 
   696 void DEventTracker::CheckCodeSegListIntegrity()
   697 	{
   698 	Kern::AccessCode();
   699 
   700 	const SDblQueLink* const anchor = &Kern::CodeSegList()->iA;
   701 	for (SDblQueLink* link = Kern::CodeSegList()->First(); link != anchor; link = link->iNext)
   702 		{
   703 		DCodeSeg* const codeSeg = _LOFF(link, DCodeSeg, iLink);
   704 		TTrackedCodeSeg* const trackedCodeSeg = (TTrackedCodeSeg*)LookupItem(codeSeg);
   705 
   706 		if (trackedCodeSeg)
   707 			{
   708 			trackedCodeSeg->iAccountedFor = ETrue;
   709 			if (!trackedCodeSeg->CheckIntegrity(codeSeg->iAccessCount))
   710 				{
   711 				++iErrorCount;
   712 				}
   713 			}
   714 		else
   715 			{
   716 			Kern::Printf("EVENTTRACKER: %C is in global list but not in tracking list", codeSeg);
   717 			++iErrorCount;
   718 			}
   719 		}
   720 
   721 	Kern::EndAccessCode();
   722 	}
   723 
   724 
   725 /** Check that all objects in tracking list have been accounted for. */
   726 void DEventTracker::CheckAllAccountedFor()
   727 	{
   728 	const SDblQueLink* link = iItems.GetFirst();
   729 	while (link)
   730 		{
   731 		TTrackedItem* const item = _LOFF(link, TTrackedItem, iLink);
   732 		if (!item->iAccountedFor)
   733 			{
   734 			Kern::Printf(
   735 				"EVENTTRACKER: 0x%x is in tracking list but not in container / list", 
   736 				&item->iObject
   737 				);
   738 			++iErrorCount;
   739 			}
   740 		link = iItems.GetFirst();
   741 		}
   742 	}
   743 
   744 /** Look for specified object in the tracking list. 
   745 	@pre iLock held
   746 	@post iLock held
   747  */
   748 TTrackedItem* DEventTracker::LookupItem(DBase* aItem) const
   749 	{
   750 	const SDblQueLink* const anchor = &iItems.iA;
   751 	
   752 	for (SDblQueLink* link = iItems.First(); link != anchor; link = link->iNext)
   753 		{
   754 		TTrackedItem* const item = _LOFF(link, TTrackedItem, iLink);
   755 
   756 		if (item->iObject == aItem)
   757 			{
   758 			return item;
   759 			}
   760 		}
   761 
   762 	return NULL;
   763 	}
   764 
   765 
   766 void DEventTracker::DumpCounters() const
   767 	{
   768 	static const char* const KEventName[] = 
   769 		{
   770 		"SwExc           ",
   771 		"HwExc           ",
   772 		"AddProcess      ",
   773 		"UpdateProcess   ",
   774 		"RemoveProcess   ",
   775 		"AddThread       ",
   776 		"StartThread     ",
   777 		"UpdateThread    ",
   778 		"KillThread      ",
   779 		"RemoveThread    ",
   780 		"NewChunk        ",
   781 		"UpdateChunk     ",
   782 		"DeleteChunk     ",
   783 		"AddLibrary      ",
   784 		"RemoveLibrary   ",
   785 		"LoadLdd         ",
   786 		"UnloadLdd       ",
   787 		"LoadPdd         ",
   788 		"UnloadPdd       ",
   789 		"UserTrace       ",
   790 		"AddCodeSeg      ",
   791 		"RemoveCodeSeg   ",
   792 		"LoadedProcess   ",
   793 		"UnloadingProcess"
   794 		};
   795 
   796 	Kern::Printf("EVENT USAGE STATISTICS:");
   797 
   798 	for (TInt i = 0; i < EEventLimit; ++i)
   799 		{
   800 		Kern::Printf("\t%s\t\t %d times", KEventName[i], iCounters[i]);
   801 		}
   802 	}
   803 
   804 #ifdef __MARM__
   805 void DEventTracker::CopyDummyHandler(TLinAddr aLinAddr)
   806 	{
   807 	const TUint handlerSize = DummyHandlerSize();
   808 
   809 	// Copy the breakpoint-able handler into RAM by copying from the one (possibly) in ROM
   810 	memcpy((TAny*)aLinAddr, (TAny*) &DummyHandler, handlerSize);
   811 	__KTRACE_OPT(KBOOT, Kern::Printf("Breakpoint-able handler copied from 0x%x to (va) 0x%x, size %d", &DummyHandler, aLinAddr, handlerSize));
   812 	}
   813 #endif
   814 	
   815 //////////////////////////////////////////////////////////////////////////////
   816 
   817 class DTestChannel : public DLogicalChannelBase
   818 	{
   819 public:
   820 	virtual ~DTestChannel();
   821 protected:
   822 	// from DLogicalChannelBase
   823 	virtual TInt DoCreate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer);
   824 	virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2);
   825 private:
   826 	DEventTracker* iHandler;
   827 	};
   828 
   829 
   830 // called in thread critical section
   831 TInt DTestChannel::DoCreate(TInt aUnit, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
   832 	{
   833 	if((TUint)aUnit>=2)
   834 		return KErrNotSupported;
   835 
   836 	TBool useHook = aUnit;
   837 
   838 	iHandler = new DEventTracker;
   839 
   840 	if (!iHandler)
   841 		{
   842 		return KErrNoMemory;
   843 		}
   844 
   845 	return iHandler->Create(iDevice, useHook);
   846 	}
   847 
   848 // called in thread critical section
   849 DTestChannel::~DTestChannel()
   850 	{
   851 	if (iHandler)
   852 		{
   853 		iHandler->Close();
   854 		}
   855 	}
   856 
   857 
   858 TInt DTestChannel::Request(TInt aFunction, TAny* /*a1*/, TAny* /*a2*/)
   859 	{
   860 	TInt r = KErrNone;
   861 	switch (aFunction)
   862 		{
   863 	case REventTracker::EStart:
   864 		iHandler->Start();
   865 		break;
   866 	case REventTracker::EStop:
   867 		iHandler->Stop();
   868 		break;
   869 	default:
   870 		Kern::PanicCurrentThread(KClientPanicCat, __LINE__);
   871 		break;
   872 		}
   873 	return r;
   874 	}
   875 
   876 
   877 //////////////////////////////////////////////////////////////////////////////
   878 
   879 class DTestFactory : public DLogicalDevice
   880 	{
   881 public:
   882 	DTestFactory();
   883 	// from DLogicalDevice
   884 	virtual TInt Install();
   885 	virtual void GetCaps(TDes8& aDes) const;
   886 	virtual TInt Create(DLogicalChannelBase*& aChannel);
   887 	};
   888 
   889 DTestFactory::DTestFactory()
   890     {
   891     iVersion = REventTracker::Version();
   892     iParseMask = KDeviceAllowUnit;
   893     iUnitsMask = 0x3;
   894     }
   895 
   896 TInt DTestFactory::Create(DLogicalChannelBase*& aChannel)
   897     {
   898 	aChannel = new DTestChannel;
   899 	return (aChannel ? KErrNone : KErrNoMemory);
   900     }
   901 
   902 TInt DTestFactory::Install()
   903     {
   904     return SetName(&KTestLddName);
   905     }
   906 
   907 void DTestFactory::GetCaps(TDes8& /*aDes*/) const
   908     {
   909     }
   910 
   911 //////////////////////////////////////////////////////////////////////////////
   912 
   913 DECLARE_STANDARD_LDD()
   914 	{
   915     return new DTestFactory;
   916 	}