diff -r ca8a1b6995f6 -r 52e343bb8f80 debugsrv/runmodedebug/rmdriver/src/d_debug_agent.cpp --- 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 -#include -#include -#include -#include -#include -#include -#include - -#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; iConstruct()) - { - 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; iClose(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* 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