Update contrib.
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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
14 // e32test\debug\d_eventtracker.cpp
15 // LDD-based debug agent used to track kernel events. See
20 #include <kernel/kern_priv.h>
21 #include "reventtracker.h"
22 #include "d_eventtracker.h"
26 #include <kernel/kdebug.h>
30 static const char KPanicCat[] = "D_EVENTTRACKER";
32 _LIT(KClientPanicCat, "D_EVENTTRACKER");
34 DEventTracker* TheEventTracker;
36 //////////////////////////////////////////////////////////////////////////////
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.
43 TTrackedItem::TTrackedItem(const DBase* aObject)
44 : iObject(aObject), iAccountedFor(EFalse)
49 /** Subclass for DObjects being tracked */
51 TTrackedObject::TTrackedObject(DObject* aObject, TObjectType aType)
52 : TTrackedItem(aObject),
55 aObject->FullName(iFullName);
58 TBool TTrackedObject::CheckIntegrity(const TDesC& aName, TObjectType aType) const
64 if (aType == EThread || aType == EProcess)
66 ok = (iFullName == aName);
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);
84 /** Subclass for DCodeSegs being tracked */
86 TTrackedCodeSeg::TTrackedCodeSeg(const DCodeSeg* aCodeSeg)
87 : TTrackedItem(aCodeSeg),
88 iAccessCount(aCodeSeg ? aCodeSeg->iAccessCount : 0)
92 TBool TTrackedCodeSeg::CheckIntegrity(TInt aAccessCount) const
94 const TBool ok = (aAccessCount == iAccessCount);
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);
107 /** Event handler and container for all objects being tracked. */
109 DEventTracker::DEventTracker()
110 : DKernelEventHandler(EventHandler, this)
112 __ASSERT_DEBUG(!TheEventTracker, Kern::Fault(KPanicCat, __LINE__));
114 TheEventTracker = this;
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
129 TInt DEventTracker::Create(DLogicalDevice* aDevice, TBool aUseHook)
131 TInt err = aDevice->Open();
140 err = Kern::MutexCreate(iLock, _L("EventHandlerLock"), KMutexOrdNone);
146 // Find debugger info, if any
147 DDebuggerInfo* const debugInfo = Kern::SuperPage().iDebuggerInfo;
149 // Test stop-mode breakpoint if available
153 // Receive all events
154 for (TInt i = 0; i < ((EEventLimit + 31) >> 5); ++i)
156 debugInfo->iEventMask[i] = 0xffffffffu;
159 __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Copying breakpoint (0x%x) into handler (0x%x), size %d", &BranchToEventHandler, debugInfo->iEventHandlerBreakpoint, BreakPointSize()));
161 // Set up breakpoint to call handler
162 memcpy((TAny*)debugInfo->iEventHandlerBreakpoint, (TAny*) &BranchToEventHandler, BreakPointSize());
182 DEventTracker::~DEventTracker()
185 // Remove breakpoint, if any
186 DDebuggerInfo* const debugInfo = Kern::SuperPage().iDebuggerInfo;
189 CopyDummyHandler(debugInfo->iEventHandlerBreakpoint);
193 // clean-up tracking list
194 SDblQueLink* link = iItems.GetFirst();
197 delete _LOFF(link, TTrackedItem, iLink);
198 link = iItems.GetFirst();
208 iDevice->Close(NULL);
211 TheEventTracker = NULL;
215 TInt DEventTracker::Start()
217 TInt err = AddExistingObjects();
228 TInt DEventTracker::Stop()
230 NKern::ThreadEnterCS();
231 Kern::MutexWait(*iLock);
235 Kern::MutexSignal(*iLock);
236 NKern::ThreadLeaveCS();
240 return CheckIntegrity();
244 TUint DEventTracker::EventHandler(TKernelEvent aType, TAny* a1, TAny* a2, TAny* aThis)
246 return ((DEventTracker*)aThis)->HandleEvent(aType, a1, a2);
250 TUint DEventTracker::HandleEvent(TKernelEvent aType, TAny* a1, TAny* a2)
252 __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Handling event type 0x%x", aType));
254 Kern::MutexWait(*iLock);
262 case EEventAddProcess:
263 AddObject(EProcess, (DObject*)a1);
265 case EEventUpdateProcess:
266 // could be renaming or chunk addition/deletion
267 UpdateObject(EProcess, (DObject*)a1, EFalse);
269 case EEventRemoveProcess:
270 RemoveObject(EProcess, (DObject*)a1);
272 case EEventAddThread:
273 AddObject(EThread, (DObject*)a1);
275 case EEventUpdateThread:
276 UpdateObject(EThread, (DObject*)a1, ETrue);
278 case EEventRemoveThread:
279 RemoveObject(EThread, (DObject*)a1);
281 case EEventAddLibrary:
283 DLibrary* pL = (DLibrary*)a1;
284 if (pL->iMapCount == 1)
285 AddObject(ELibrary, pL);
288 case EEventRemoveLibrary:
290 DLibrary* pL = (DLibrary*)a1;
291 if (pL->iMapCount == 0)
292 RemoveObject(ELibrary, pL);
296 AddObject(EChunk, (DObject*)a1);
298 case EEventDeleteChunk:
299 RemoveObject(EChunk, (DObject*)a1);
301 case EEventAddCodeSeg:
303 AddCodeSeg((DCodeSeg*)a1, (DProcess*)a2);
306 case EEventRemoveCodeSeg:
308 RemoveCodeSeg((DCodeSeg*)a1, (DProcess*)a2);
311 case EEventLoadedProcess:
313 __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Process %O loaded", a1));
314 ProcessLoaded((DProcess*)a1);
317 case EEventUnloadingProcess:
318 __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Process %O unloaded", a1));
322 __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Handling default case"));
327 Kern::MutexSignal(*iLock);
329 // Allow other handlers to see this event
330 return DKernelEventHandler::ERunNext;
334 void DEventTracker::AddObject(TObjectType aType, DObject* aObject)
336 TTrackedObject* trackedObject = (TTrackedObject*)LookupItem(aObject);
340 Kern::Printf("EVENTTRACKER: Found orphaned object %O in tracking list while adding new object", aObject);
345 NKern::ThreadEnterCS();
346 trackedObject = new TTrackedObject(aObject, aType);
347 NKern::ThreadLeaveCS();
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);
363 void DEventTracker::RemoveObject(TObjectType aType, DObject* aObject)
365 TTrackedObject* const trackedObject = (TTrackedObject*)LookupItem(aObject);
370 aObject->FullName(name);
371 if (!trackedObject->CheckIntegrity(name, aType))
375 __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Removing %S (type %d) from tracking list", &name, aType));
376 trackedObject->iLink.Deque();
378 NKern::ThreadEnterCS();
379 delete trackedObject;
380 NKern::ThreadLeaveCS();
384 Kern::Printf("EVENTTRACKER: %O (type %d) removed but not in tracking list", aObject, aType);
390 void DEventTracker::UpdateObject(TObjectType aType, DObject* aObject, TBool aMustBeRenamed)
392 TTrackedObject* const trackedObject = (TTrackedObject*)LookupItem(aObject);
397 aObject->FullName(newName);
398 if (newName != trackedObject->iFullName)
400 __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Renaming %S --> %S (type %d)",
401 &trackedObject->iFullName, &newName));
402 trackedObject->iFullName = newName;
404 else if (aMustBeRenamed)
406 Kern::Printf("EVENTTRACKER: %O (type %d) renamed with same name", aObject, aType);
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);
418 void DEventTracker::AddCodeSeg(DCodeSeg* aCodeSeg, DProcess* aProcess)
420 TTrackedCodeSeg* trackedCodeSeg = (TTrackedCodeSeg*)LookupItem(aCodeSeg);
424 if (aProcess && (aProcess->iTempCodeSeg == aCodeSeg))
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;
432 if (trackedCodeSeg->iAccessCount != aCodeSeg->iAccessCount)
435 "EVENTTRACKER: Access count for %C (%d) does not match the tracking list (%d)",
437 aCodeSeg->iAccessCount,
438 trackedCodeSeg->iAccessCount
447 NKern::ThreadEnterCS();
448 trackedCodeSeg = new TTrackedCodeSeg(aCodeSeg);
449 NKern::ThreadLeaveCS();
453 __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Adding %C to tracking list", aCodeSeg));
454 iItems.Add(&trackedCodeSeg->iLink);
457 else // trackedCodeSeg
461 __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Updating access count for %C (%d), attaching to process %O", aCodeSeg, aCodeSeg->iAccessCount, aProcess));
465 Kern::Printf("EVENTTRACKER: Found orphaned code seg %C in tracking list while adding new code seg", aCodeSeg);
477 void DEventTracker::ProcessLoaded(DProcess* aProcess)
479 if (aProcess->iCodeSeg)
481 TTrackedCodeSeg* trackedCodeSeg = (TTrackedCodeSeg*)LookupItem(aProcess->iCodeSeg);
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;
493 void DEventTracker::RemoveCodeSeg(DCodeSeg* aCodeSeg, DProcess* aProcess)
495 TTrackedCodeSeg* const trackedCodeSeg = (TTrackedCodeSeg*)LookupItem(aCodeSeg);
499 if (!trackedCodeSeg->CheckIntegrity(aCodeSeg->iAccessCount))
504 if (aCodeSeg->iAccessCount == 1)
506 __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Removing %C from tracking list, process %O", aCodeSeg, aProcess));
507 trackedCodeSeg->iLink.Deque();
509 NKern::ThreadEnterCS();
510 delete trackedCodeSeg;
511 NKern::ThreadLeaveCS();
516 Kern::Printf("EVENTTRACKER: %C removed but not in tracking list. Removing from process %O", aCodeSeg, aProcess);
522 /** Add all objects from relevant containers into the tracking list. */
524 TInt DEventTracker::AddExistingObjects()
526 // Tracking can be started only after all containers read to avoid
528 __ASSERT_DEBUG(!iTracking, Kern::Fault(KPanicCat, __LINE__));
531 Kern::Printf("Adding processes");
532 err = AddObjectsFromContainer(EProcess);
537 Kern::Printf("Adding threads");
538 err = AddObjectsFromContainer(EThread);
543 Kern::Printf("Adding libraries");
544 err = AddObjectsFromContainer(ELibrary);
549 Kern::Printf("Adding chunks");
550 err = AddObjectsFromContainer(EChunk);
555 Kern::Printf("Adding LDDs");
556 err = AddObjectsFromContainer(ELogicalDevice);
561 Kern::Printf("Adding PDDs");
562 err = AddObjectsFromContainer(EPhysicalDevice);
567 Kern::Printf("Adding code segs");
568 return AddCodeSegsFromList();
571 /** Add all objects from specified container into tracking list. */
573 TInt DEventTracker::AddObjectsFromContainer(TObjectType aType)
575 DObjectCon* const container = Kern::Containers()[aType];
577 NKern::ThreadEnterCS();
580 const TInt count = container->Count();
583 for (TInt i = 0; (i < count && err == KErrNone); ++i)
585 DObject* const object = (*container)[i];
586 if (object->Open() == KErrNone)
588 AddObject(aType, object);
598 NKern::ThreadLeaveCS();
603 TInt DEventTracker::AddCodeSegsFromList()
607 const SDblQueLink* const anchor = &Kern::CodeSegList()->iA;
608 for (SDblQueLink* link = Kern::CodeSegList()->First(); link != anchor; link = link->iNext)
610 DCodeSeg* const codeSeg = _LOFF(link, DCodeSeg, iLink);
611 AddCodeSeg(codeSeg, NULL);
614 Kern::EndAccessCode();
620 /** Check that tracking list matches existing objects.
621 @return number of discrepancies found
624 TInt DEventTracker::CheckIntegrity()
626 // Tracking must be stopped to avoid race conditions.
627 __ASSERT_DEBUG(!iTracking, Kern::Fault(KPanicCat, __LINE__));
631 Kern::Printf("EVENTTRACKER: OOM during tracking");
634 CheckContainerIntegrity(EProcess);
635 CheckContainerIntegrity(EThread);
636 CheckContainerIntegrity(ELibrary);
637 CheckContainerIntegrity(EChunk);
638 CheckContainerIntegrity(ELogicalDevice);
639 CheckContainerIntegrity(EPhysicalDevice);
640 CheckCodeSegListIntegrity();
642 CheckAllAccountedFor();
646 Kern::Printf("EVENTTRACKER: %d error(s) found", iErrorCount);
653 /** Check all objects in specified container are in tracking list. */
655 void DEventTracker::CheckContainerIntegrity(TObjectType aType)
657 DObjectCon* const container = Kern::Containers()[aType];
659 NKern::ThreadEnterCS();
662 const TInt count = container->Count();
664 for (TInt i = 0; i < count; ++i)
666 DObject* const object = (*container)[i];
667 if (object->Open() == KErrNone)
670 object->FullName(name);
672 TTrackedObject* const trackedObject = (TTrackedObject*)LookupItem(object);
676 trackedObject->iAccountedFor = ETrue;
677 if (!trackedObject->CheckIntegrity(name, aType))
684 Kern::Printf("EVENTTRACKER: %S (type %d) is in container but not in tracking list", &name, aType);
693 NKern::ThreadLeaveCS();
696 void DEventTracker::CheckCodeSegListIntegrity()
700 const SDblQueLink* const anchor = &Kern::CodeSegList()->iA;
701 for (SDblQueLink* link = Kern::CodeSegList()->First(); link != anchor; link = link->iNext)
703 DCodeSeg* const codeSeg = _LOFF(link, DCodeSeg, iLink);
704 TTrackedCodeSeg* const trackedCodeSeg = (TTrackedCodeSeg*)LookupItem(codeSeg);
708 trackedCodeSeg->iAccountedFor = ETrue;
709 if (!trackedCodeSeg->CheckIntegrity(codeSeg->iAccessCount))
716 Kern::Printf("EVENTTRACKER: %C is in global list but not in tracking list", codeSeg);
721 Kern::EndAccessCode();
725 /** Check that all objects in tracking list have been accounted for. */
726 void DEventTracker::CheckAllAccountedFor()
728 const SDblQueLink* link = iItems.GetFirst();
731 TTrackedItem* const item = _LOFF(link, TTrackedItem, iLink);
732 if (!item->iAccountedFor)
735 "EVENTTRACKER: 0x%x is in tracking list but not in container / list",
740 link = iItems.GetFirst();
744 /** Look for specified object in the tracking list.
748 TTrackedItem* DEventTracker::LookupItem(DBase* aItem) const
750 const SDblQueLink* const anchor = &iItems.iA;
752 for (SDblQueLink* link = iItems.First(); link != anchor; link = link->iNext)
754 TTrackedItem* const item = _LOFF(link, TTrackedItem, iLink);
756 if (item->iObject == aItem)
766 void DEventTracker::DumpCounters() const
768 static const char* const KEventName[] =
796 Kern::Printf("EVENT USAGE STATISTICS:");
798 for (TInt i = 0; i < EEventLimit; ++i)
800 Kern::Printf("\t%s\t\t %d times", KEventName[i], iCounters[i]);
805 void DEventTracker::CopyDummyHandler(TLinAddr aLinAddr)
807 const TUint handlerSize = DummyHandlerSize();
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));
815 //////////////////////////////////////////////////////////////////////////////
817 class DTestChannel : public DLogicalChannelBase
820 virtual ~DTestChannel();
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);
826 DEventTracker* iHandler;
830 // called in thread critical section
831 TInt DTestChannel::DoCreate(TInt aUnit, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
834 return KErrNotSupported;
836 TBool useHook = aUnit;
838 iHandler = new DEventTracker;
845 return iHandler->Create(iDevice, useHook);
848 // called in thread critical section
849 DTestChannel::~DTestChannel()
858 TInt DTestChannel::Request(TInt aFunction, TAny* /*a1*/, TAny* /*a2*/)
863 case REventTracker::EStart:
866 case REventTracker::EStop:
870 Kern::PanicCurrentThread(KClientPanicCat, __LINE__);
877 //////////////////////////////////////////////////////////////////////////////
879 class DTestFactory : public DLogicalDevice
883 // from DLogicalDevice
884 virtual TInt Install();
885 virtual void GetCaps(TDes8& aDes) const;
886 virtual TInt Create(DLogicalChannelBase*& aChannel);
889 DTestFactory::DTestFactory()
891 iVersion = REventTracker::Version();
892 iParseMask = KDeviceAllowUnit;
896 TInt DTestFactory::Create(DLogicalChannelBase*& aChannel)
898 aChannel = new DTestChannel;
899 return (aChannel ? KErrNone : KErrNoMemory);
902 TInt DTestFactory::Install()
904 return SetName(&KTestLddName);
907 void DTestFactory::GetCaps(TDes8& /*aDes*/) const
911 //////////////////////////////////////////////////////////////////////////////
913 DECLARE_STANDARD_LDD()
915 return new DTestFactory;