sl@0: // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32test\debug\d_eventtracker.cpp sl@0: // LDD-based debug agent used to track kernel events. See sl@0: // t_eventtracker.cpp sl@0: // sl@0: // sl@0: sl@0: #include sl@0: #include "reventtracker.h" sl@0: #include "d_eventtracker.h" sl@0: #include "nk_trace.h" sl@0: sl@0: #ifdef __MARM__ sl@0: #include sl@0: #endif //__MARM__ sl@0: sl@0: #ifdef _DEBUG sl@0: static const char KPanicCat[] = "D_EVENTTRACKER"; sl@0: #endif // _DEBUG sl@0: _LIT(KClientPanicCat, "D_EVENTTRACKER"); sl@0: sl@0: DEventTracker* TheEventTracker; sl@0: sl@0: ////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: /** Data about objects being tracked. sl@0: All tracked objects are kept in a tracking list. The object address sl@0: is a key and so must be unique. sl@0: */ sl@0: sl@0: TTrackedItem::TTrackedItem(const DBase* aObject) sl@0: : iObject(aObject), iAccountedFor(EFalse) sl@0: { sl@0: } sl@0: sl@0: sl@0: /** Subclass for DObjects being tracked */ sl@0: sl@0: TTrackedObject::TTrackedObject(DObject* aObject, TObjectType aType) sl@0: : TTrackedItem(aObject), sl@0: iType(aType) sl@0: { sl@0: aObject->FullName(iFullName); sl@0: } sl@0: sl@0: TBool TTrackedObject::CheckIntegrity(const TDesC& aName, TObjectType aType) const sl@0: { sl@0: TBool ok = EFalse; sl@0: sl@0: if (aType == iType) sl@0: { sl@0: if (aType == EThread || aType == EProcess) sl@0: { sl@0: ok = (iFullName == aName); sl@0: } sl@0: else sl@0: { sl@0: ok = ETrue; sl@0: } sl@0: } sl@0: sl@0: if (!ok) sl@0: { sl@0: Kern::Printf("EVENTTRACKER: container / tracking list mismatch (0x%08x)", iObject); sl@0: Kern::Printf("EVENTTRACKER: \tcontainer: %S (type %d)", &aName, aType); sl@0: Kern::Printf("EVENTTRACKER: \ttracking list: %S (type %d)", &iFullName, iType); sl@0: } sl@0: sl@0: return ok; sl@0: } sl@0: sl@0: /** Subclass for DCodeSegs being tracked */ sl@0: sl@0: TTrackedCodeSeg::TTrackedCodeSeg(const DCodeSeg* aCodeSeg) sl@0: : TTrackedItem(aCodeSeg), sl@0: iAccessCount(aCodeSeg ? aCodeSeg->iAccessCount : 0) sl@0: { sl@0: } sl@0: sl@0: TBool TTrackedCodeSeg::CheckIntegrity(TInt aAccessCount) const sl@0: { sl@0: const TBool ok = (aAccessCount == iAccessCount); sl@0: sl@0: if (!ok) sl@0: { sl@0: Kern::Printf("EVENTTRACKER: code seg list / tracking list mismatch (0x%08x)", iObject); sl@0: Kern::Printf("EVENTTRACKER: \tcode seg list: %d", aAccessCount); sl@0: Kern::Printf("EVENTTRACKER: \ttracking list: %d", iAccessCount); sl@0: } sl@0: sl@0: return ok; sl@0: } sl@0: sl@0: sl@0: /** Event handler and container for all objects being tracked. */ sl@0: sl@0: DEventTracker::DEventTracker() sl@0: : DKernelEventHandler(EventHandler, this) sl@0: { sl@0: __ASSERT_DEBUG(!TheEventTracker, Kern::Fault(KPanicCat, __LINE__)); sl@0: sl@0: TheEventTracker = this; sl@0: } sl@0: sl@0: sl@0: // sl@0: // If aUseHook is true, the event tracker hooks the stop-mode debugger sl@0: // breakpoint in preference to adding itself to the kernel event handler sl@0: // queue. In order to clean up on its destruction, it has to sl@0: // reset the breakpoint by installing a dummy nop breakpoint sl@0: // handler, which is cut-and-pasted from kdebug.dll in order to sl@0: // avoid a dependency on kdebug.dll. In order to use the event sl@0: // tracker using the stop-mode debugger breakpoint rather than sl@0: // the kernel event handler queue, kdebug.dll must be present in sl@0: // the ROM sl@0: // sl@0: TInt DEventTracker::Create(DLogicalDevice* aDevice, TBool aUseHook) sl@0: { sl@0: TInt err = aDevice->Open(); sl@0: sl@0: if (err) sl@0: { sl@0: return err; sl@0: } sl@0: sl@0: iDevice = aDevice; sl@0: sl@0: err = Kern::MutexCreate(iLock, _L("EventHandlerLock"), KMutexOrdNone); sl@0: sl@0: if (!err) sl@0: { sl@0: if (aUseHook) sl@0: { sl@0: // Find debugger info, if any sl@0: DDebuggerInfo* const debugInfo = Kern::SuperPage().iDebuggerInfo; sl@0: sl@0: // Test stop-mode breakpoint if available sl@0: if (debugInfo) sl@0: { sl@0: #ifdef __MARM__ sl@0: // Receive all events sl@0: for (TInt i = 0; i < ((EEventLimit + 31) >> 5); ++i) sl@0: { sl@0: debugInfo->iEventMask[i] = 0xffffffffu; sl@0: } sl@0: sl@0: __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Copying breakpoint (0x%x) into handler (0x%x), size %d", &BranchToEventHandler, debugInfo->iEventHandlerBreakpoint, BreakPointSize())); sl@0: sl@0: // Set up breakpoint to call handler sl@0: memcpy((TAny*)debugInfo->iEventHandlerBreakpoint, (TAny*) &BranchToEventHandler, BreakPointSize()); sl@0: #else // !__MARM__ sl@0: err = KErrNotFound; sl@0: #endif // __MARM__ sl@0: } sl@0: else sl@0: { sl@0: err = KErrNotFound; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: err = Add(); sl@0: } sl@0: } sl@0: sl@0: return err; sl@0: } sl@0: sl@0: sl@0: DEventTracker::~DEventTracker() sl@0: { sl@0: #ifdef __MARM__ sl@0: // Remove breakpoint, if any sl@0: DDebuggerInfo* const debugInfo = Kern::SuperPage().iDebuggerInfo; sl@0: if (debugInfo) sl@0: { sl@0: CopyDummyHandler(debugInfo->iEventHandlerBreakpoint); sl@0: } sl@0: #endif //__MARM__ sl@0: sl@0: // clean-up tracking list sl@0: SDblQueLink* link = iItems.GetFirst(); sl@0: while (link) sl@0: { sl@0: delete _LOFF(link, TTrackedItem, iLink); sl@0: link = iItems.GetFirst(); sl@0: } sl@0: sl@0: if (iLock) sl@0: { sl@0: iLock->Close(NULL); sl@0: } sl@0: sl@0: if (iDevice) sl@0: { sl@0: iDevice->Close(NULL); sl@0: } sl@0: sl@0: TheEventTracker = NULL; sl@0: } sl@0: sl@0: sl@0: TInt DEventTracker::Start() sl@0: { sl@0: TInt err = AddExistingObjects(); sl@0: sl@0: if (!err) sl@0: { sl@0: iTracking = ETrue; sl@0: } sl@0: sl@0: return err; sl@0: } sl@0: sl@0: sl@0: TInt DEventTracker::Stop() sl@0: { sl@0: NKern::ThreadEnterCS(); sl@0: Kern::MutexWait(*iLock); sl@0: sl@0: iTracking = EFalse; sl@0: sl@0: Kern::MutexSignal(*iLock); sl@0: NKern::ThreadLeaveCS(); sl@0: sl@0: DumpCounters(); sl@0: sl@0: return CheckIntegrity(); sl@0: } sl@0: sl@0: sl@0: TUint DEventTracker::EventHandler(TKernelEvent aType, TAny* a1, TAny* a2, TAny* aThis) sl@0: { sl@0: return ((DEventTracker*)aThis)->HandleEvent(aType, a1, a2); sl@0: } sl@0: sl@0: sl@0: TUint DEventTracker::HandleEvent(TKernelEvent aType, TAny* a1, TAny* a2) sl@0: { sl@0: __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Handling event type 0x%x", aType)); sl@0: sl@0: Kern::MutexWait(*iLock); sl@0: sl@0: if (iTracking) sl@0: { sl@0: ++iCounters[aType]; sl@0: sl@0: switch (aType) sl@0: { sl@0: case EEventAddProcess: sl@0: AddObject(EProcess, (DObject*)a1); sl@0: break; sl@0: case EEventUpdateProcess: sl@0: // could be renaming or chunk addition/deletion sl@0: UpdateObject(EProcess, (DObject*)a1, EFalse); sl@0: break; sl@0: case EEventRemoveProcess: sl@0: RemoveObject(EProcess, (DObject*)a1); sl@0: break; sl@0: case EEventAddThread: sl@0: AddObject(EThread, (DObject*)a1); sl@0: break; sl@0: case EEventUpdateThread: sl@0: UpdateObject(EThread, (DObject*)a1, ETrue); sl@0: break; sl@0: case EEventRemoveThread: sl@0: RemoveObject(EThread, (DObject*)a1); sl@0: break; sl@0: case EEventAddLibrary: sl@0: { sl@0: DLibrary* pL = (DLibrary*)a1; sl@0: if (pL->iMapCount == 1) sl@0: AddObject(ELibrary, pL); sl@0: } sl@0: break; sl@0: case EEventRemoveLibrary: sl@0: { sl@0: DLibrary* pL = (DLibrary*)a1; sl@0: if (pL->iMapCount == 0) sl@0: RemoveObject(ELibrary, pL); sl@0: } sl@0: break; sl@0: case EEventNewChunk: sl@0: AddObject(EChunk, (DObject*)a1); sl@0: break; sl@0: case EEventDeleteChunk: sl@0: RemoveObject(EChunk, (DObject*)a1); sl@0: break; sl@0: case EEventAddCodeSeg: sl@0: { sl@0: AddCodeSeg((DCodeSeg*)a1, (DProcess*)a2); sl@0: } sl@0: break; sl@0: case EEventRemoveCodeSeg: sl@0: { sl@0: RemoveCodeSeg((DCodeSeg*)a1, (DProcess*)a2); sl@0: } sl@0: break; sl@0: case EEventLoadedProcess: sl@0: { sl@0: __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Process %O loaded", a1)); sl@0: ProcessLoaded((DProcess*)a1); sl@0: } sl@0: break; sl@0: case EEventUnloadingProcess: sl@0: __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Process %O unloaded", a1)); sl@0: break; sl@0: default: sl@0: // no-op sl@0: __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Handling default case")); sl@0: break; sl@0: } sl@0: } sl@0: sl@0: Kern::MutexSignal(*iLock); sl@0: sl@0: // Allow other handlers to see this event sl@0: return DKernelEventHandler::ERunNext; sl@0: } sl@0: sl@0: sl@0: void DEventTracker::AddObject(TObjectType aType, DObject* aObject) sl@0: { sl@0: TTrackedObject* trackedObject = (TTrackedObject*)LookupItem(aObject); sl@0: sl@0: if (trackedObject) sl@0: { sl@0: Kern::Printf("EVENTTRACKER: Found orphaned object %O in tracking list while adding new object", aObject); sl@0: ++iErrorCount; sl@0: return; sl@0: } sl@0: sl@0: NKern::ThreadEnterCS(); sl@0: trackedObject = new TTrackedObject(aObject, aType); sl@0: NKern::ThreadLeaveCS(); sl@0: sl@0: if (trackedObject) sl@0: { sl@0: __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Adding %O (type %d) to tracking list", aObject, aType)); sl@0: __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: DBase ptr == 0x%x", trackedObject->iObject)); sl@0: iItems.Add(&trackedObject->iLink); sl@0: } sl@0: else sl@0: { sl@0: iOOM = ETrue; sl@0: ++iErrorCount; sl@0: } sl@0: } sl@0: sl@0: sl@0: void DEventTracker::RemoveObject(TObjectType aType, DObject* aObject) sl@0: { sl@0: TTrackedObject* const trackedObject = (TTrackedObject*)LookupItem(aObject); sl@0: sl@0: if (trackedObject) sl@0: { sl@0: TFullName name; sl@0: aObject->FullName(name); sl@0: if (!trackedObject->CheckIntegrity(name, aType)) sl@0: { sl@0: ++iErrorCount; sl@0: } sl@0: __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Removing %S (type %d) from tracking list", &name, aType)); sl@0: trackedObject->iLink.Deque(); sl@0: sl@0: NKern::ThreadEnterCS(); sl@0: delete trackedObject; sl@0: NKern::ThreadLeaveCS(); sl@0: } sl@0: else sl@0: { sl@0: Kern::Printf("EVENTTRACKER: %O (type %d) removed but not in tracking list", aObject, aType); sl@0: ++iErrorCount; sl@0: } sl@0: } sl@0: sl@0: sl@0: void DEventTracker::UpdateObject(TObjectType aType, DObject* aObject, TBool aMustBeRenamed) sl@0: { sl@0: TTrackedObject* const trackedObject = (TTrackedObject*)LookupItem(aObject); sl@0: sl@0: if (trackedObject) sl@0: { sl@0: TFullName newName; sl@0: aObject->FullName(newName); sl@0: if (newName != trackedObject->iFullName) sl@0: { sl@0: __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Renaming %S --> %S (type %d)", sl@0: &trackedObject->iFullName, &newName)); sl@0: trackedObject->iFullName = newName; sl@0: } sl@0: else if (aMustBeRenamed) sl@0: { sl@0: Kern::Printf("EVENTTRACKER: %O (type %d) renamed with same name", aObject, aType); sl@0: ++iErrorCount; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: Kern::Printf("EVENTTRACKER: %O (type %d) updated but not in tracking list", aObject, aType); sl@0: Kern::Printf("EVENTTRACKER: DBase ptr == 0x%x", (DBase*)aObject); sl@0: ++iErrorCount; sl@0: } sl@0: } sl@0: sl@0: void DEventTracker::AddCodeSeg(DCodeSeg* aCodeSeg, DProcess* aProcess) sl@0: { sl@0: TTrackedCodeSeg* trackedCodeSeg = (TTrackedCodeSeg*)LookupItem(aCodeSeg); sl@0: sl@0: if (trackedCodeSeg) sl@0: { sl@0: if (aProcess && (aProcess->iTempCodeSeg == aCodeSeg)) sl@0: { sl@0: // This is the exe code seg for a loading process sl@0: // and hence the access count is currently sl@0: // incremented by one sl@0: ++trackedCodeSeg->iAccessCount; sl@0: } sl@0: sl@0: if (trackedCodeSeg->iAccessCount != aCodeSeg->iAccessCount) sl@0: { sl@0: Kern::Printf( sl@0: "EVENTTRACKER: Access count for %C (%d) does not match the tracking list (%d)", sl@0: aCodeSeg, sl@0: aCodeSeg->iAccessCount, sl@0: trackedCodeSeg->iAccessCount sl@0: ); sl@0: ++iErrorCount; sl@0: return; sl@0: } sl@0: } sl@0: sl@0: if (!trackedCodeSeg) sl@0: { sl@0: NKern::ThreadEnterCS(); sl@0: trackedCodeSeg = new TTrackedCodeSeg(aCodeSeg); sl@0: NKern::ThreadLeaveCS(); sl@0: sl@0: if (trackedCodeSeg) sl@0: { sl@0: __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Adding %C to tracking list", aCodeSeg)); sl@0: iItems.Add(&trackedCodeSeg->iLink); sl@0: } sl@0: } sl@0: else // trackedCodeSeg sl@0: { sl@0: if (aProcess) sl@0: { sl@0: __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Updating access count for %C (%d), attaching to process %O", aCodeSeg, aCodeSeg->iAccessCount, aProcess)); sl@0: } sl@0: else // !aProcess sl@0: { sl@0: Kern::Printf("EVENTTRACKER: Found orphaned code seg %C in tracking list while adding new code seg", aCodeSeg); sl@0: ++iErrorCount; sl@0: } sl@0: } sl@0: sl@0: if (!trackedCodeSeg) sl@0: { sl@0: iOOM = ETrue; sl@0: ++iErrorCount; sl@0: } sl@0: } sl@0: sl@0: void DEventTracker::ProcessLoaded(DProcess* aProcess) sl@0: { sl@0: if (aProcess->iCodeSeg) sl@0: { sl@0: TTrackedCodeSeg* trackedCodeSeg = (TTrackedCodeSeg*)LookupItem(aProcess->iCodeSeg); sl@0: sl@0: if (trackedCodeSeg) sl@0: { sl@0: // This is the exe code seg for a process that sl@0: // has completed loading and hence the access sl@0: // count has just been decremented by one sl@0: --trackedCodeSeg->iAccessCount; sl@0: } sl@0: } sl@0: } sl@0: sl@0: void DEventTracker::RemoveCodeSeg(DCodeSeg* aCodeSeg, DProcess* aProcess) sl@0: { sl@0: TTrackedCodeSeg* const trackedCodeSeg = (TTrackedCodeSeg*)LookupItem(aCodeSeg); sl@0: sl@0: if (trackedCodeSeg) sl@0: { sl@0: if (!trackedCodeSeg->CheckIntegrity(aCodeSeg->iAccessCount)) sl@0: { sl@0: ++iErrorCount; sl@0: } sl@0: sl@0: if (aCodeSeg->iAccessCount == 1) sl@0: { sl@0: __KTRACE_OPT(KDEBUGGER, Kern::Printf("EVENTTRACKER: Removing %C from tracking list, process %O", aCodeSeg, aProcess)); sl@0: trackedCodeSeg->iLink.Deque(); sl@0: sl@0: NKern::ThreadEnterCS(); sl@0: delete trackedCodeSeg; sl@0: NKern::ThreadLeaveCS(); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: Kern::Printf("EVENTTRACKER: %C removed but not in tracking list. Removing from process %O", aCodeSeg, aProcess); sl@0: ++iErrorCount; sl@0: } sl@0: } sl@0: sl@0: sl@0: /** Add all objects from relevant containers into the tracking list. */ sl@0: sl@0: TInt DEventTracker::AddExistingObjects() sl@0: { sl@0: // Tracking can be started only after all containers read to avoid sl@0: // race conditions. sl@0: __ASSERT_DEBUG(!iTracking, Kern::Fault(KPanicCat, __LINE__)); sl@0: sl@0: TInt err = KErrNone; sl@0: Kern::Printf("Adding processes"); sl@0: err = AddObjectsFromContainer(EProcess); sl@0: if (err) sl@0: { sl@0: return err; sl@0: } sl@0: Kern::Printf("Adding threads"); sl@0: err = AddObjectsFromContainer(EThread); sl@0: if (err) sl@0: { sl@0: return err; sl@0: } sl@0: Kern::Printf("Adding libraries"); sl@0: err = AddObjectsFromContainer(ELibrary); sl@0: if (err) sl@0: { sl@0: return err; sl@0: } sl@0: Kern::Printf("Adding chunks"); sl@0: err = AddObjectsFromContainer(EChunk); sl@0: if (err) sl@0: { sl@0: return err; sl@0: } sl@0: Kern::Printf("Adding LDDs"); sl@0: err = AddObjectsFromContainer(ELogicalDevice); sl@0: if (err) sl@0: { sl@0: return err; sl@0: } sl@0: Kern::Printf("Adding PDDs"); sl@0: err = AddObjectsFromContainer(EPhysicalDevice); sl@0: if (err) sl@0: { sl@0: return err; sl@0: } sl@0: Kern::Printf("Adding code segs"); sl@0: return AddCodeSegsFromList(); sl@0: } sl@0: sl@0: /** Add all objects from specified container into tracking list. */ sl@0: sl@0: TInt DEventTracker::AddObjectsFromContainer(TObjectType aType) sl@0: { sl@0: DObjectCon* const container = Kern::Containers()[aType]; sl@0: sl@0: NKern::ThreadEnterCS(); sl@0: container->Wait(); sl@0: sl@0: const TInt count = container->Count(); sl@0: TInt err = KErrNone; sl@0: sl@0: for (TInt i = 0; (i < count && err == KErrNone); ++i) sl@0: { sl@0: DObject* const object = (*container)[i]; sl@0: if (object->Open() == KErrNone) sl@0: { sl@0: AddObject(aType, object); sl@0: if (iOOM) sl@0: { sl@0: err = KErrNoMemory; sl@0: } sl@0: object->Close(NULL); sl@0: } sl@0: } sl@0: sl@0: container->Signal(); sl@0: NKern::ThreadLeaveCS(); sl@0: sl@0: return err; sl@0: } sl@0: sl@0: TInt DEventTracker::AddCodeSegsFromList() sl@0: { sl@0: Kern::AccessCode(); sl@0: sl@0: const SDblQueLink* const anchor = &Kern::CodeSegList()->iA; sl@0: for (SDblQueLink* link = Kern::CodeSegList()->First(); link != anchor; link = link->iNext) sl@0: { sl@0: DCodeSeg* const codeSeg = _LOFF(link, DCodeSeg, iLink); sl@0: AddCodeSeg(codeSeg, NULL); sl@0: } sl@0: sl@0: Kern::EndAccessCode(); sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** Check that tracking list matches existing objects. sl@0: @return number of discrepancies found sl@0: */ sl@0: sl@0: TInt DEventTracker::CheckIntegrity() sl@0: { sl@0: // Tracking must be stopped to avoid race conditions. sl@0: __ASSERT_DEBUG(!iTracking, Kern::Fault(KPanicCat, __LINE__)); sl@0: sl@0: if (iOOM) sl@0: { sl@0: Kern::Printf("EVENTTRACKER: OOM during tracking"); sl@0: } sl@0: sl@0: CheckContainerIntegrity(EProcess); sl@0: CheckContainerIntegrity(EThread); sl@0: CheckContainerIntegrity(ELibrary); sl@0: CheckContainerIntegrity(EChunk); sl@0: CheckContainerIntegrity(ELogicalDevice); sl@0: CheckContainerIntegrity(EPhysicalDevice); sl@0: CheckCodeSegListIntegrity(); sl@0: sl@0: CheckAllAccountedFor(); sl@0: sl@0: if (iErrorCount) sl@0: { sl@0: Kern::Printf("EVENTTRACKER: %d error(s) found", iErrorCount); sl@0: return KErrGeneral; sl@0: } sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** Check all objects in specified container are in tracking list. */ sl@0: sl@0: void DEventTracker::CheckContainerIntegrity(TObjectType aType) sl@0: { sl@0: DObjectCon* const container = Kern::Containers()[aType]; sl@0: sl@0: NKern::ThreadEnterCS(); sl@0: container->Wait(); sl@0: sl@0: const TInt count = container->Count(); sl@0: sl@0: for (TInt i = 0; i < count; ++i) sl@0: { sl@0: DObject* const object = (*container)[i]; sl@0: if (object->Open() == KErrNone) sl@0: { sl@0: TFullName name; sl@0: object->FullName(name); sl@0: sl@0: TTrackedObject* const trackedObject = (TTrackedObject*)LookupItem(object); sl@0: sl@0: if (trackedObject) sl@0: { sl@0: trackedObject->iAccountedFor = ETrue; sl@0: if (!trackedObject->CheckIntegrity(name, aType)) sl@0: { sl@0: ++iErrorCount; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: Kern::Printf("EVENTTRACKER: %S (type %d) is in container but not in tracking list", &name, aType); sl@0: ++iErrorCount; sl@0: } sl@0: sl@0: object->Close(NULL); sl@0: } sl@0: } sl@0: sl@0: container->Signal(); sl@0: NKern::ThreadLeaveCS(); sl@0: } sl@0: sl@0: void DEventTracker::CheckCodeSegListIntegrity() sl@0: { sl@0: Kern::AccessCode(); sl@0: sl@0: const SDblQueLink* const anchor = &Kern::CodeSegList()->iA; sl@0: for (SDblQueLink* link = Kern::CodeSegList()->First(); link != anchor; link = link->iNext) sl@0: { sl@0: DCodeSeg* const codeSeg = _LOFF(link, DCodeSeg, iLink); sl@0: TTrackedCodeSeg* const trackedCodeSeg = (TTrackedCodeSeg*)LookupItem(codeSeg); sl@0: sl@0: if (trackedCodeSeg) sl@0: { sl@0: trackedCodeSeg->iAccountedFor = ETrue; sl@0: if (!trackedCodeSeg->CheckIntegrity(codeSeg->iAccessCount)) sl@0: { sl@0: ++iErrorCount; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: Kern::Printf("EVENTTRACKER: %C is in global list but not in tracking list", codeSeg); sl@0: ++iErrorCount; sl@0: } sl@0: } sl@0: sl@0: Kern::EndAccessCode(); sl@0: } sl@0: sl@0: sl@0: /** Check that all objects in tracking list have been accounted for. */ sl@0: void DEventTracker::CheckAllAccountedFor() sl@0: { sl@0: const SDblQueLink* link = iItems.GetFirst(); sl@0: while (link) sl@0: { sl@0: TTrackedItem* const item = _LOFF(link, TTrackedItem, iLink); sl@0: if (!item->iAccountedFor) sl@0: { sl@0: Kern::Printf( sl@0: "EVENTTRACKER: 0x%x is in tracking list but not in container / list", sl@0: &item->iObject sl@0: ); sl@0: ++iErrorCount; sl@0: } sl@0: link = iItems.GetFirst(); sl@0: } sl@0: } sl@0: sl@0: /** Look for specified object in the tracking list. sl@0: @pre iLock held sl@0: @post iLock held sl@0: */ sl@0: TTrackedItem* DEventTracker::LookupItem(DBase* aItem) const sl@0: { sl@0: const SDblQueLink* const anchor = &iItems.iA; sl@0: sl@0: for (SDblQueLink* link = iItems.First(); link != anchor; link = link->iNext) sl@0: { sl@0: TTrackedItem* const item = _LOFF(link, TTrackedItem, iLink); sl@0: sl@0: if (item->iObject == aItem) sl@0: { sl@0: return item; sl@0: } sl@0: } sl@0: sl@0: return NULL; sl@0: } sl@0: sl@0: sl@0: void DEventTracker::DumpCounters() const sl@0: { sl@0: static const char* const KEventName[] = sl@0: { sl@0: "SwExc ", sl@0: "HwExc ", sl@0: "AddProcess ", sl@0: "UpdateProcess ", sl@0: "RemoveProcess ", sl@0: "AddThread ", sl@0: "StartThread ", sl@0: "UpdateThread ", sl@0: "KillThread ", sl@0: "RemoveThread ", sl@0: "NewChunk ", sl@0: "UpdateChunk ", sl@0: "DeleteChunk ", sl@0: "AddLibrary ", sl@0: "RemoveLibrary ", sl@0: "LoadLdd ", sl@0: "UnloadLdd ", sl@0: "LoadPdd ", sl@0: "UnloadPdd ", sl@0: "UserTrace ", sl@0: "AddCodeSeg ", sl@0: "RemoveCodeSeg ", sl@0: "LoadedProcess ", sl@0: "UnloadingProcess" sl@0: }; sl@0: sl@0: Kern::Printf("EVENT USAGE STATISTICS:"); sl@0: sl@0: for (TInt i = 0; i < EEventLimit; ++i) sl@0: { sl@0: Kern::Printf("\t%s\t\t %d times", KEventName[i], iCounters[i]); sl@0: } sl@0: } sl@0: sl@0: #ifdef __MARM__ sl@0: void DEventTracker::CopyDummyHandler(TLinAddr aLinAddr) sl@0: { sl@0: const TUint handlerSize = DummyHandlerSize(); sl@0: sl@0: // Copy the breakpoint-able handler into RAM by copying from the one (possibly) in ROM sl@0: memcpy((TAny*)aLinAddr, (TAny*) &DummyHandler, handlerSize); sl@0: __KTRACE_OPT(KBOOT, Kern::Printf("Breakpoint-able handler copied from 0x%x to (va) 0x%x, size %d", &DummyHandler, aLinAddr, handlerSize)); sl@0: } sl@0: #endif sl@0: sl@0: ////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: class DTestChannel : public DLogicalChannelBase sl@0: { sl@0: public: sl@0: virtual ~DTestChannel(); sl@0: protected: sl@0: // from DLogicalChannelBase sl@0: virtual TInt DoCreate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer); sl@0: virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2); sl@0: private: sl@0: DEventTracker* iHandler; sl@0: }; sl@0: sl@0: sl@0: // called in thread critical section sl@0: TInt DTestChannel::DoCreate(TInt aUnit, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/) sl@0: { sl@0: if((TUint)aUnit>=2) sl@0: return KErrNotSupported; sl@0: sl@0: TBool useHook = aUnit; sl@0: sl@0: iHandler = new DEventTracker; sl@0: sl@0: if (!iHandler) sl@0: { sl@0: return KErrNoMemory; sl@0: } sl@0: sl@0: return iHandler->Create(iDevice, useHook); sl@0: } sl@0: sl@0: // called in thread critical section sl@0: DTestChannel::~DTestChannel() sl@0: { sl@0: if (iHandler) sl@0: { sl@0: iHandler->Close(); sl@0: } sl@0: } sl@0: sl@0: sl@0: TInt DTestChannel::Request(TInt aFunction, TAny* /*a1*/, TAny* /*a2*/) sl@0: { sl@0: TInt r = KErrNone; sl@0: switch (aFunction) sl@0: { sl@0: case REventTracker::EStart: sl@0: iHandler->Start(); sl@0: break; sl@0: case REventTracker::EStop: sl@0: iHandler->Stop(); sl@0: break; sl@0: default: sl@0: Kern::PanicCurrentThread(KClientPanicCat, __LINE__); sl@0: break; sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: sl@0: ////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: class DTestFactory : public DLogicalDevice sl@0: { sl@0: public: sl@0: DTestFactory(); sl@0: // from DLogicalDevice sl@0: virtual TInt Install(); sl@0: virtual void GetCaps(TDes8& aDes) const; sl@0: virtual TInt Create(DLogicalChannelBase*& aChannel); sl@0: }; sl@0: sl@0: DTestFactory::DTestFactory() sl@0: { sl@0: iVersion = REventTracker::Version(); sl@0: iParseMask = KDeviceAllowUnit; sl@0: iUnitsMask = 0x3; sl@0: } sl@0: sl@0: TInt DTestFactory::Create(DLogicalChannelBase*& aChannel) sl@0: { sl@0: aChannel = new DTestChannel; sl@0: return (aChannel ? KErrNone : KErrNoMemory); sl@0: } sl@0: sl@0: TInt DTestFactory::Install() sl@0: { sl@0: return SetName(&KTestLddName); sl@0: } sl@0: sl@0: void DTestFactory::GetCaps(TDes8& /*aDes*/) const sl@0: { sl@0: } sl@0: sl@0: ////////////////////////////////////////////////////////////////////////////// sl@0: sl@0: DECLARE_STANDARD_LDD() sl@0: { sl@0: return new DTestFactory; sl@0: }