--- 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