debugsrv/runmodedebug/rmdriver/src/d_debug_agent.cpp
branchRCL_3
changeset 21 52e343bb8f80
parent 20 ca8a1b6995f6
child 22 e26895079d7c
--- a/debugsrv/runmodedebug/rmdriver/src/d_debug_agent.cpp	Tue Aug 31 16:45:49 2010 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,468 +0,0 @@
-// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
-// All rights reserved.
-// This component and the accompanying materials are made available
-// under the terms of the License "Eclipse Public License v1.0"
-// which accompanies this distribution, and is available
-// at the URL "http://www.eclipse.org/legal/epl-v10.html".
-//
-// Initial Contributors:
-// Nokia Corporation - initial contribution.
-//
-// Contributors:
-//
-// Description:
-// Purpose: Kernel-side tracking of debug agent information associated
-// with each process being debugged.
-// 
-//
-
-#include <e32def.h>
-#include <e32def_private.h>
-#include <e32cmn.h>
-#include <e32cmn_private.h>
-#include <kernel/kernel.h> 
-#include <kernel/kern_priv.h>
-#include <nk_trace.h>
-#include <arm.h>
-
-#include "d_process_tracker.h"
-#include "debug_logging.h"
-
-#include "d_debug_agent.h"
-#include "debug_utils.h"
-
-#include "d_debug_agent.inl"
-
-using namespace Debug;
-
-// ctor
-DDebugAgent::DDebugAgent(TUint64 aId) :
-	iId(aId),
-	iRequestGetEventStatus(NULL),
-	iClientThread(0),
-	iEventQueue(KNumberOfEventsToQueue, 0),
-	iHead(0),
-	iTail(0),
-	iEventQueueLock(NULL),
-	iFreeSlots(KNumberOfEventsToQueue),
-	iIgnoringTrace(EFalse),
-	iEventBalance(0)
-	{
-	LOG_MSG2("DDebugAgent::DDebugAgent(), this=0x%x ", this);
-
-	// Initialize all the Event Actions to Ignore
-	for(TInt i=0; i<EEventsLast; i++)
-		{
-		iEventActions[i] = EActionIgnore;
-		}
-	}
-
-DDebugAgent* DDebugAgent::New(TUint64 aId)
-	{
-	LOG_MSG2("DDebugAgent::New(id=0x%lx)", aId);
-	DDebugAgent* agent = new DDebugAgent(aId);
-	if(agent == NULL)
-		{
-		return (NULL);
-		}
-	if(KErrNone != agent->Construct())
-		{
-		delete agent;
-		return (NULL);
-		}
-
-	// Use a semaphore to serialise access
-	TInt err = Kern::SemaphoreCreate(agent->iEventQueueLock, _L("RM_DebugAgentQueueLock"), 1 /* Initial count */);
-	if (err != KErrNone)
-		return NULL;
-
-	return agent;
-	}
-
-/** Standard contructor.
- * Fills event queue with empty events
- * @return : standard system error code
- */
-TInt DDebugAgent::Construct()
-	{
-	// Empty the event queue
-	TDriverEventInfo emptyEvent;
-	TInt err = KErrNone;
-
-	for (TInt i=0; i<KNumberOfEventsToQueue; i++)
-		{
-		err = iEventQueue.Append(emptyEvent);
-		if (err != KErrNone)
-			{
-			LOG_MSG("Error appending blank event entry");
-			return err;
-			}
-		}
-
-	err = Kern::CreateClientDataRequest(iRequestGetEventStatus);
-	if(err != KErrNone)
-		{
-		LOG_MSG("Error creating TClientDataRequest");
-		return err;
-		}
-
-	LOG_MSG2("DDebugAgent::Construct() iRequestGetEventStatus=0x%08x", iRequestGetEventStatus);
-
-	return err;
-	}
-
-// dtor
-DDebugAgent::~DDebugAgent()
-	{
-	iEventQueue.Reset();
-
-	if (iEventQueueLock)
-		iEventQueueLock->Close(NULL);
-	
-	if(iRequestGetEventStatus)
-		Kern::DestroyClientRequest(iRequestGetEventStatus);
-	
-	}
-
-// Associate an action with a particular kernel event
-TInt DDebugAgent::SetEventAction(TEventType aEvent, TKernelEventAction aEventAction)
-	{
-	// Valid Event?
-	if (aEvent >= EEventsLast)
-		{
-		LOG_MSG2("DDebugAgent::EventAction: Bad Event number %d",aEvent);
-		return KErrArgument;
-		}
-
-	iEventActions[aEvent] = aEventAction;
-
-	return KErrNone;
-	}
-
-/** Get the aEventAction associated with aEvent
- *
- * @return : aEventAction (always +ve), or KErrArgument.
- */
-TInt DDebugAgent::EventAction(TEventType aEvent)
-	{
-	// Validate the Event id
-	if (aEvent >= EEventsLast)
-		{
-		LOG_MSG2("DDebugAgent::EventAction: Bad Event number %d",aEvent);
-		return KErrArgument;
-		}
-
-	// Return the action associated with this event
-	return iEventActions[aEvent];
-	}
-
-/** Obtain the details of the latest kernel event (if it exists) and place the details in aEventInfo
- * If there is no event in the queue for this process+agent combination, store the details
- * so that it can be notified later when an event actually occurs.
- * 
- * @param aAsyncGetValueRequest - TClientDataRequest object used for pinning user memory
- * @param aClientThread - The ThreadId of the requesting user-side process. In this case the DSS.
- */
-void DDebugAgent::GetEvent(TClientDataRequest<TEventInfo>* aAsyncGetValueRequest, DThread* aClientThread)
-	{
-	LockEventQueue();
-
-	iRequestGetEventStatus->Reset();
-	TInt err = iRequestGetEventStatus->SetStatus( aAsyncGetValueRequest->StatusPtr() );
-	if (err != KErrNone)
-		{
-		LOG_MSG2("Error :iRequestGetEventStatus->SetStatus ret %d", err);
-		UnlockEventQueue();
-		return;
-		}
-	
-	iRequestGetEventStatus->SetDestPtr( aAsyncGetValueRequest->DestPtr() );
-
-	iEventBalance++;
-	
-	LOG_MSG5("DDebugAgent::GetEvent: this=0x%08x, iRequestGetEventStatus=0x%08x, iEventBalance=%d, destPrt=0x%08x", 
-		this, iRequestGetEventStatus, iEventBalance, aAsyncGetValueRequest->DestPtr() );
-	
-	iClientThread = aClientThread;
-	
-	if (BufferEmpty())
-		{
-		LOG_MSG2("Event buffer empty, iEventBalance=%d", iEventBalance);		
-		UnlockEventQueue();
-		return;
-		}
-
-	LOG_MSG5("Event already available at queue pos (tail)=%d, evType=%d, threadId=0x%x, actionTaken=%d", 
-	        iTail,	iEventQueue[iTail].iEventType,	
-	        iEventQueue[iTail].iThreadId, iEventQueue[iTail].iActionTaken );
-	
-	// returning the event to the client
-	err = iEventQueue[iTail].WriteEventToClientThread(iRequestGetEventStatus,iClientThread);
-	if (err != KErrNone)
-		{
-		LOG_MSG2("Error writing event info: %d", err);
-		UnlockEventQueue();
-		return;
-		}
-
-	// signal the DSS thread
-	Kern::QueueRequestComplete(iClientThread, iRequestGetEventStatus, KErrNone);
-	iEventBalance--;
-
-	iEventQueue[iTail].Reset();
-
-	// move to the next slot
-	IncrementTailPosition();
-
-	UnlockEventQueue();
-	}
-
-/**
- * Stop waiting for an event to occur. This means events will be placed 
- * in the iEventQueue (by setting iEventBalance to 0) until GetEvent is called. 
- */ 
-TInt DDebugAgent::CancelGetEvent(void)
-	{
-	LOG_MSG2("DDebugAgent::CancelGetEvent. iEventBalance=%d. > QueueRequestComplete", iEventBalance);
-	Kern::QueueRequestComplete(iClientThread, iRequestGetEventStatus, KErrCancel);
-	iEventBalance=0;
-	iClientThread = 0;
-	return KErrNone;
-	}
-
-/** Signal a kernel event to the user-side DSS when it occurs, or queue it for later
- * if the user-side has not called GetEvent (see above).
- * 
- * @param aEventInfo - the details of the event to queue.
- */
-void DDebugAgent::NotifyEvent(const TDriverEventInfo& aEventInfo)
-	{
-
-	if(aEventInfo.iEventType >= EEventsLast)
-		{
-		LOG_MSG3("DDebugAgent::NotifyEvent(),iEventType %d, this=0x%x. Ignoring since > EEventsLast", aEventInfo.iEventType, this);
-		return;
-		}
-
-	LockEventQueue();
-
-	DThread* currentThread = &Kern::CurrentThread();
-	
-
-	TKernelEventAction action = iEventActions[aEventInfo.iEventType];
-
-	if (aEventInfo.iProcessId == Id() &&
-		(aEventInfo.iEventType == EEventsSwExc || aEventInfo.iEventType == EEventsHwExc ||	aEventInfo.iEventType == EEventsKillThread))
-		{
-
-		// It might be nice not to deliver *any* events about the debug agent to the agent itself, but this is a bit too drastic a change to make.
-		// There's a risk it might completely break TRK or similar, and at a more practical level it would require major rewriting of the t_rmdebug2
-		// tests.
-		//
-		// So instead, we only don't suspend&deliver events about the debug agent IF it's a thread crash event AND the thread is process
-		// critical/permanent AND (in the case of a critical thread) it's an abnormal exit. We're not worrying (yet) about the case where the entire
-		// process is set as system critical
-		// This fixes the original problem with CDS's worker thread crashing, and doesn't wreck the t_rmdebug2 tests.
-
-		TBool problematic = (
-			(aEventInfo.iThreadFlags & (KThreadFlagProcessCritical|KThreadFlagSystemCritical) && (aEventInfo.iEventType != EEventsKillThread || aEventInfo.iExitType != EExitKill)) // process or system critical, and either an exception (not a EEventsKillThread) or a non EExitKill exit
-			|| (aEventInfo.iThreadFlags & (KThreadFlagProcessPermanent|KThreadFlagSystemPermanent))
-			);
-
-		if (problematic)
-			{
-			LOG_MSG("Agent is dying - no further events will be delivered to it");
-			iAgentDying = ETrue;
-			}
-
-		}
-
-	if (iAgentDying && action == EActionSuspend)
-		{
-		LOG_MSG("Not delivering this event or suspending the thread because agent is dying");
-		action = EActionIgnore;
-		}
-
-	switch (action)
-		{
-		case EActionSuspend:
-			{
-			LOG_MSG5("DDebugAgent::NotifyEvent(), Suspend thread, iEventType %d, this=0x%x currThrd=0x%08x, iEventBalance=%d",
-				aEventInfo.iEventType, this, currentThread, iEventBalance );
-
-			switch(aEventInfo.iEventType)
-				{
-				case EEventsAddLibrary:
-				case EEventsRemoveLibrary:
-					// TomS: Anybody want to explain what is going on here??
-					currentThread = DebugUtils::OpenThreadHandle(aEventInfo.iThreadId);
-					if(currentThread)
-						{
-						currentThread->Close(NULL);
-						}
-					break;
-				default:
-					break;
-				}
-			
-			// Do not call suspend for breakpoints, since the breakpoint code that runs when deciding if an exception
-			// is a breakpoint will itself suspend the thread 
-			if( (aEventInfo.iEventType != EEventsBreakPoint) && (aEventInfo.iEventType != EEventsProcessBreakPoint) )
-			    {
-                TInt err = TheDProcessTracker.SuspendThread(currentThread, aEventInfo.FreezeOnSuspend());
-                if((err != KErrNone) && (err != KErrAlreadyExists))
-                    {
-                    // Is there anything we can do in the future to deal with this error having happened?
-                    LOG_MSG2("DDebugAgent::NotifyEvent() Problem while suspending thread: %d", err);
-                    }
-			    }
-
-			// now drop through to the continue case, which typically notifies
-			// the debug agent of the event
-			}
-		case EActionContinue:
-			{
-			if( action == EActionContinue )
-				{
-				LOG_MSG5("DDebugAgent::NotifyEvent(), Action continue, iEventType %d, this=0x%x currThrd=0x%08x, iEventBalance=%d",
-					aEventInfo.iEventType, this, currentThread, iEventBalance );
-				}
-
-			// Queue this event
-			TDriverEventInfo eventInfo = aEventInfo;
-			eventInfo.iActionTaken = action;
-			QueueEvent(eventInfo);
-
-			// Tell the user about the oldest event in the queue
-			if ( iClientThread )
-				{
-				if( iRequestGetEventStatus && (iEventBalance > 0) )
-					{
-					// Fill the event data
-					TInt err = iEventQueue[iTail].WriteEventToClientThread(iRequestGetEventStatus,iClientThread);
-					if (err != KErrNone)
-						{
-						LOG_MSG2("Error writing event info: %d", err);
-						}
-
-					// signal the debugger thread 
-					LOG_MSG4("> QueueRequestComplete iRequestGetEventStatus=0x%08x, iEventBalance=%d, iTail=%d",
-						iRequestGetEventStatus->iStatus, iEventBalance, iTail );
-					Kern::QueueRequestComplete(iClientThread, iRequestGetEventStatus, KErrNone);
-
-					iEventBalance--;
-
-					iEventQueue[iTail].Reset();
-
-					// move to the next slot
-					IncrementTailPosition();
-					}
-				else
-					{
-					if( !iRequestGetEventStatus )
-						{
-						LOG_MSG("iRequestGetEventStatus is NULL so not signalling client" );
-						}
-					else
-						{
-						LOG_MSG2("Queued event. iEventBalance=%d (unbalanced event requests vs notifications)", 
-							iEventBalance );
-						}
-					}
-				}
-			else
-				{
-				 LOG_MSG("DDebugAgent::NotifyEvent() : Not informing client since its thread is NULL");
-				}
-			break;
-			}
-		case EActionIgnore:
-		default:
-			// Ignore everything we don't understand.
-			break;
-		}
-
-	UnlockEventQueue();
-
-	}
-
-// Used to identify which Debug Agent this DDebugAgent is associated with.
-TUint64 DDebugAgent::Id(void)
-	{
-	return iId;
-	}
-
-/**
- * Used to add an event to the event queue for this debug agent if event 
- * queue is not at critical level. If it is at critical and it is trace event, 
- * we start ignoring trace events and insert a lost trace event.
- * If the buffer cannot store an event, only insert a buffer full event.
- * @see EEventsBufferFull
- * @see EEventsUserTracesLost
- * @see TDriverEventInfo
- * @see iEventQueue
- */
-void DDebugAgent::QueueEvent(const TDriverEventInfo& aEventInfo)
-	{
-	// Have we caught the tail?
-	if(BufferFull())
-		{
-		LOG_MSG("DDebugAgent::QueueEvent : BufferFull. Not queueing");
-		return;
-		}
-
-	// Assert if we think there is space but the slot is not marked empty
-	__NK_ASSERT_DEBUG(iEventQueue[iHead].iEventType == EEventsUnknown);
-
-	const TBool bufferAtCritical = BufferAtCriticalLevel();
-
-	if(!bufferAtCritical)
-		{
-		//reset the iIgnoringTrace flag as we are not at 
-		//critical level and can store event
-		iIgnoringTrace = EFalse; 
-		
-		// Insert the event into the ring buffer at iHead
-		iEventQueue[iHead] = aEventInfo;
-		IncrementHeadPosition();
-		}
-	else if(bufferAtCritical && BufferCanStoreEvent())
-		{
-		LOG_MSG("DDebugAgent::QueueEvent : BufferCritical");
-		if(aEventInfo.iEventType == EEventsUserTrace)
-			{
-			if(!iIgnoringTrace)
-				{
-				//if this is the first time we are ignoring trace events, 
-				//we need to issue a EEventsUserTracesLost event
-				iEventQueue[iHead].Reset();
-				iEventQueue[iHead].iEventType = EEventsUserTracesLost;
-				IncrementHeadPosition();
-
-				iIgnoringTrace = ETrue;
-				}
-			else
-				{
-				//otherwise, ignore this event
-				LOG_MSG("DDebugAgent::QueueEvent : Ignore EEventsUserTrace event");
-				}
-			}
-		else
-			{
-			// Store the event since its not a trace event
-			iEventQueue[iHead] = aEventInfo;
-			IncrementHeadPosition();
-			}
-		}
-	else
-		{
-		//At critical level and cannot store new events, so 
-		//only one space left. Store a EEventsBufferFull event
-		LOG_MSG("DDebugAgent::QueueEvent : Event Buffer Full, ignoring event");
-		iEventQueue[iHead].Reset();
-		iEventQueue[iHead].iEventType = EEventsBufferFull;
-		IncrementHeadPosition();
-		}
-	}
-
-// End of file - d_debug_agent.cpp