kerneltest/e32test/debug/d_eventtracker.cpp
changeset 0 a41df078684a
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     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 	}