debugsrv/runmodedebug/rmdriver/src/d_debug_agent.cpp
branchRCL_3
changeset 20 ca8a1b6995f6
equal deleted inserted replaced
19:07b41fa8d1dd 20:ca8a1b6995f6
       
     1 // Copyright (c) 2006-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".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Purpose: Kernel-side tracking of debug agent information associated
       
    15 // with each process being debugged.
       
    16 // 
       
    17 //
       
    18 
       
    19 #include <e32def.h>
       
    20 #include <e32def_private.h>
       
    21 #include <e32cmn.h>
       
    22 #include <e32cmn_private.h>
       
    23 #include <kernel/kernel.h> 
       
    24 #include <kernel/kern_priv.h>
       
    25 #include <nk_trace.h>
       
    26 #include <arm.h>
       
    27 
       
    28 #include "d_process_tracker.h"
       
    29 #include "debug_logging.h"
       
    30 
       
    31 #include "d_debug_agent.h"
       
    32 #include "debug_utils.h"
       
    33 
       
    34 #include "d_debug_agent.inl"
       
    35 
       
    36 using namespace Debug;
       
    37 
       
    38 // ctor
       
    39 DDebugAgent::DDebugAgent(TUint64 aId) :
       
    40 	iId(aId),
       
    41 	iRequestGetEventStatus(NULL),
       
    42 	iClientThread(0),
       
    43 	iEventQueue(KNumberOfEventsToQueue, 0),
       
    44 	iHead(0),
       
    45 	iTail(0),
       
    46 	iEventQueueLock(NULL),
       
    47 	iFreeSlots(KNumberOfEventsToQueue),
       
    48 	iIgnoringTrace(EFalse),
       
    49 	iEventBalance(0)
       
    50 	{
       
    51 	LOG_MSG2("DDebugAgent::DDebugAgent(), this=0x%x ", this);
       
    52 
       
    53 	// Initialize all the Event Actions to Ignore
       
    54 	for(TInt i=0; i<EEventsLast; i++)
       
    55 		{
       
    56 		iEventActions[i] = EActionIgnore;
       
    57 		}
       
    58 	}
       
    59 
       
    60 DDebugAgent* DDebugAgent::New(TUint64 aId)
       
    61 	{
       
    62 	LOG_MSG2("DDebugAgent::New(id=0x%lx)", aId);
       
    63 	DDebugAgent* agent = new DDebugAgent(aId);
       
    64 	if(agent == NULL)
       
    65 		{
       
    66 		return (NULL);
       
    67 		}
       
    68 	if(KErrNone != agent->Construct())
       
    69 		{
       
    70 		delete agent;
       
    71 		return (NULL);
       
    72 		}
       
    73 
       
    74 	// Use a semaphore to serialise access
       
    75 	TInt err = Kern::SemaphoreCreate(agent->iEventQueueLock, _L("RM_DebugAgentQueueLock"), 1 /* Initial count */);
       
    76 	if (err != KErrNone)
       
    77 		return NULL;
       
    78 
       
    79 	return agent;
       
    80 	}
       
    81 
       
    82 /** Standard contructor.
       
    83  * Fills event queue with empty events
       
    84  * @return : standard system error code
       
    85  */
       
    86 TInt DDebugAgent::Construct()
       
    87 	{
       
    88 	// Empty the event queue
       
    89 	TDriverEventInfo emptyEvent;
       
    90 	TInt err = KErrNone;
       
    91 
       
    92 	for (TInt i=0; i<KNumberOfEventsToQueue; i++)
       
    93 		{
       
    94 		err = iEventQueue.Append(emptyEvent);
       
    95 		if (err != KErrNone)
       
    96 			{
       
    97 			LOG_MSG("Error appending blank event entry");
       
    98 			return err;
       
    99 			}
       
   100 		}
       
   101 
       
   102 	err = Kern::CreateClientDataRequest(iRequestGetEventStatus);
       
   103 	if(err != KErrNone)
       
   104 		{
       
   105 		LOG_MSG("Error creating TClientDataRequest");
       
   106 		return err;
       
   107 		}
       
   108 
       
   109 	LOG_MSG2("DDebugAgent::Construct() iRequestGetEventStatus=0x%08x", iRequestGetEventStatus);
       
   110 
       
   111 	return err;
       
   112 	}
       
   113 
       
   114 // dtor
       
   115 DDebugAgent::~DDebugAgent()
       
   116 	{
       
   117 	iEventQueue.Reset();
       
   118 
       
   119 	if (iEventQueueLock)
       
   120 		iEventQueueLock->Close(NULL);
       
   121 	
       
   122 	if(iRequestGetEventStatus)
       
   123 		Kern::DestroyClientRequest(iRequestGetEventStatus);
       
   124 	
       
   125 	}
       
   126 
       
   127 // Associate an action with a particular kernel event
       
   128 TInt DDebugAgent::SetEventAction(TEventType aEvent, TKernelEventAction aEventAction)
       
   129 	{
       
   130 	// Valid Event?
       
   131 	if (aEvent >= EEventsLast)
       
   132 		{
       
   133 		LOG_MSG2("DDebugAgent::EventAction: Bad Event number %d",aEvent);
       
   134 		return KErrArgument;
       
   135 		}
       
   136 
       
   137 	iEventActions[aEvent] = aEventAction;
       
   138 
       
   139 	return KErrNone;
       
   140 	}
       
   141 
       
   142 /** Get the aEventAction associated with aEvent
       
   143  *
       
   144  * @return : aEventAction (always +ve), or KErrArgument.
       
   145  */
       
   146 TInt DDebugAgent::EventAction(TEventType aEvent)
       
   147 	{
       
   148 	// Validate the Event id
       
   149 	if (aEvent >= EEventsLast)
       
   150 		{
       
   151 		LOG_MSG2("DDebugAgent::EventAction: Bad Event number %d",aEvent);
       
   152 		return KErrArgument;
       
   153 		}
       
   154 
       
   155 	// Return the action associated with this event
       
   156 	return iEventActions[aEvent];
       
   157 	}
       
   158 
       
   159 /** Obtain the details of the latest kernel event (if it exists) and place the details in aEventInfo
       
   160  * If there is no event in the queue for this process+agent combination, store the details
       
   161  * so that it can be notified later when an event actually occurs.
       
   162  * 
       
   163  * @param aAsyncGetValueRequest - TClientDataRequest object used for pinning user memory
       
   164  * @param aClientThread - The ThreadId of the requesting user-side process. In this case the DSS.
       
   165  */
       
   166 void DDebugAgent::GetEvent(TClientDataRequest<TEventInfo>* aAsyncGetValueRequest, DThread* aClientThread)
       
   167 	{
       
   168 	LockEventQueue();
       
   169 
       
   170 	iRequestGetEventStatus->Reset();
       
   171 	TInt err = iRequestGetEventStatus->SetStatus( aAsyncGetValueRequest->StatusPtr() );
       
   172 	if (err != KErrNone)
       
   173 		{
       
   174 		LOG_MSG2("Error :iRequestGetEventStatus->SetStatus ret %d", err);
       
   175 		UnlockEventQueue();
       
   176 		return;
       
   177 		}
       
   178 	
       
   179 	iRequestGetEventStatus->SetDestPtr( aAsyncGetValueRequest->DestPtr() );
       
   180 
       
   181 	iEventBalance++;
       
   182 	
       
   183 	LOG_MSG5("DDebugAgent::GetEvent: this=0x%08x, iRequestGetEventStatus=0x%08x, iEventBalance=%d, destPrt=0x%08x", 
       
   184 		this, iRequestGetEventStatus, iEventBalance, aAsyncGetValueRequest->DestPtr() );
       
   185 	
       
   186 	iClientThread = aClientThread;
       
   187 	
       
   188 	if (BufferEmpty())
       
   189 		{
       
   190 		LOG_MSG2("Event buffer empty, iEventBalance=%d", iEventBalance);		
       
   191 		UnlockEventQueue();
       
   192 		return;
       
   193 		}
       
   194 
       
   195 	LOG_MSG5("Event already available at queue pos (tail)=%d, evType=%d, threadId=0x%x, actionTaken=%d", 
       
   196 	        iTail,	iEventQueue[iTail].iEventType,	
       
   197 	        iEventQueue[iTail].iThreadId, iEventQueue[iTail].iActionTaken );
       
   198 	
       
   199 	// returning the event to the client
       
   200 	err = iEventQueue[iTail].WriteEventToClientThread(iRequestGetEventStatus,iClientThread);
       
   201 	if (err != KErrNone)
       
   202 		{
       
   203 		LOG_MSG2("Error writing event info: %d", err);
       
   204 		UnlockEventQueue();
       
   205 		return;
       
   206 		}
       
   207 
       
   208 	// signal the DSS thread
       
   209 	Kern::QueueRequestComplete(iClientThread, iRequestGetEventStatus, KErrNone);
       
   210 	iEventBalance--;
       
   211 
       
   212 	iEventQueue[iTail].Reset();
       
   213 
       
   214 	// move to the next slot
       
   215 	IncrementTailPosition();
       
   216 
       
   217 	UnlockEventQueue();
       
   218 	}
       
   219 
       
   220 /**
       
   221  * Stop waiting for an event to occur. This means events will be placed 
       
   222  * in the iEventQueue (by setting iEventBalance to 0) until GetEvent is called. 
       
   223  */ 
       
   224 TInt DDebugAgent::CancelGetEvent(void)
       
   225 	{
       
   226 	LOG_MSG2("DDebugAgent::CancelGetEvent. iEventBalance=%d. > QueueRequestComplete", iEventBalance);
       
   227 	Kern::QueueRequestComplete(iClientThread, iRequestGetEventStatus, KErrCancel);
       
   228 	iEventBalance=0;
       
   229 	iClientThread = 0;
       
   230 	return KErrNone;
       
   231 	}
       
   232 
       
   233 /** Signal a kernel event to the user-side DSS when it occurs, or queue it for later
       
   234  * if the user-side has not called GetEvent (see above).
       
   235  * 
       
   236  * @param aEventInfo - the details of the event to queue.
       
   237  */
       
   238 void DDebugAgent::NotifyEvent(const TDriverEventInfo& aEventInfo)
       
   239 	{
       
   240 
       
   241 	if(aEventInfo.iEventType >= EEventsLast)
       
   242 		{
       
   243 		LOG_MSG3("DDebugAgent::NotifyEvent(),iEventType %d, this=0x%x. Ignoring since > EEventsLast", aEventInfo.iEventType, this);
       
   244 		return;
       
   245 		}
       
   246 
       
   247 	LockEventQueue();
       
   248 
       
   249 	DThread* currentThread = &Kern::CurrentThread();
       
   250 	
       
   251 
       
   252 	TKernelEventAction action = iEventActions[aEventInfo.iEventType];
       
   253 
       
   254 	if (aEventInfo.iProcessId == Id() &&
       
   255 		(aEventInfo.iEventType == EEventsSwExc || aEventInfo.iEventType == EEventsHwExc ||	aEventInfo.iEventType == EEventsKillThread))
       
   256 		{
       
   257 
       
   258 		// 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.
       
   259 		// 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
       
   260 		// tests.
       
   261 		//
       
   262 		// 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
       
   263 		// 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
       
   264 		// process is set as system critical
       
   265 		// This fixes the original problem with CDS's worker thread crashing, and doesn't wreck the t_rmdebug2 tests.
       
   266 
       
   267 		TBool problematic = (
       
   268 			(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
       
   269 			|| (aEventInfo.iThreadFlags & (KThreadFlagProcessPermanent|KThreadFlagSystemPermanent))
       
   270 			);
       
   271 
       
   272 		if (problematic)
       
   273 			{
       
   274 			LOG_MSG("Agent is dying - no further events will be delivered to it");
       
   275 			iAgentDying = ETrue;
       
   276 			}
       
   277 
       
   278 		}
       
   279 
       
   280 	if (iAgentDying && action == EActionSuspend)
       
   281 		{
       
   282 		LOG_MSG("Not delivering this event or suspending the thread because agent is dying");
       
   283 		action = EActionIgnore;
       
   284 		}
       
   285 
       
   286 	switch (action)
       
   287 		{
       
   288 		case EActionSuspend:
       
   289 			{
       
   290 			LOG_MSG5("DDebugAgent::NotifyEvent(), Suspend thread, iEventType %d, this=0x%x currThrd=0x%08x, iEventBalance=%d",
       
   291 				aEventInfo.iEventType, this, currentThread, iEventBalance );
       
   292 
       
   293 			switch(aEventInfo.iEventType)
       
   294 				{
       
   295 				case EEventsAddLibrary:
       
   296 				case EEventsRemoveLibrary:
       
   297 					// TomS: Anybody want to explain what is going on here??
       
   298 					currentThread = DebugUtils::OpenThreadHandle(aEventInfo.iThreadId);
       
   299 					if(currentThread)
       
   300 						{
       
   301 						currentThread->Close(NULL);
       
   302 						}
       
   303 					break;
       
   304 				default:
       
   305 					break;
       
   306 				}
       
   307 			
       
   308 			// Do not call suspend for breakpoints, since the breakpoint code that runs when deciding if an exception
       
   309 			// is a breakpoint will itself suspend the thread 
       
   310 			if( (aEventInfo.iEventType != EEventsBreakPoint) && (aEventInfo.iEventType != EEventsProcessBreakPoint) )
       
   311 			    {
       
   312                 TInt err = TheDProcessTracker.SuspendThread(currentThread, aEventInfo.FreezeOnSuspend());
       
   313                 if((err != KErrNone) && (err != KErrAlreadyExists))
       
   314                     {
       
   315                     // Is there anything we can do in the future to deal with this error having happened?
       
   316                     LOG_MSG2("DDebugAgent::NotifyEvent() Problem while suspending thread: %d", err);
       
   317                     }
       
   318 			    }
       
   319 
       
   320 			// now drop through to the continue case, which typically notifies
       
   321 			// the debug agent of the event
       
   322 			}
       
   323 		case EActionContinue:
       
   324 			{
       
   325 			if( action == EActionContinue )
       
   326 				{
       
   327 				LOG_MSG5("DDebugAgent::NotifyEvent(), Action continue, iEventType %d, this=0x%x currThrd=0x%08x, iEventBalance=%d",
       
   328 					aEventInfo.iEventType, this, currentThread, iEventBalance );
       
   329 				}
       
   330 
       
   331 			// Queue this event
       
   332 			TDriverEventInfo eventInfo = aEventInfo;
       
   333 			eventInfo.iActionTaken = action;
       
   334 			QueueEvent(eventInfo);
       
   335 
       
   336 			// Tell the user about the oldest event in the queue
       
   337 			if ( iClientThread )
       
   338 				{
       
   339 				if( iRequestGetEventStatus && (iEventBalance > 0) )
       
   340 					{
       
   341 					// Fill the event data
       
   342 					TInt err = iEventQueue[iTail].WriteEventToClientThread(iRequestGetEventStatus,iClientThread);
       
   343 					if (err != KErrNone)
       
   344 						{
       
   345 						LOG_MSG2("Error writing event info: %d", err);
       
   346 						}
       
   347 
       
   348 					// signal the debugger thread 
       
   349 					LOG_MSG4("> QueueRequestComplete iRequestGetEventStatus=0x%08x, iEventBalance=%d, iTail=%d",
       
   350 						iRequestGetEventStatus->iStatus, iEventBalance, iTail );
       
   351 					Kern::QueueRequestComplete(iClientThread, iRequestGetEventStatus, KErrNone);
       
   352 
       
   353 					iEventBalance--;
       
   354 
       
   355 					iEventQueue[iTail].Reset();
       
   356 
       
   357 					// move to the next slot
       
   358 					IncrementTailPosition();
       
   359 					}
       
   360 				else
       
   361 					{
       
   362 					if( !iRequestGetEventStatus )
       
   363 						{
       
   364 						LOG_MSG("iRequestGetEventStatus is NULL so not signalling client" );
       
   365 						}
       
   366 					else
       
   367 						{
       
   368 						LOG_MSG2("Queued event. iEventBalance=%d (unbalanced event requests vs notifications)", 
       
   369 							iEventBalance );
       
   370 						}
       
   371 					}
       
   372 				}
       
   373 			else
       
   374 				{
       
   375 				 LOG_MSG("DDebugAgent::NotifyEvent() : Not informing client since its thread is NULL");
       
   376 				}
       
   377 			break;
       
   378 			}
       
   379 		case EActionIgnore:
       
   380 		default:
       
   381 			// Ignore everything we don't understand.
       
   382 			break;
       
   383 		}
       
   384 
       
   385 	UnlockEventQueue();
       
   386 
       
   387 	}
       
   388 
       
   389 // Used to identify which Debug Agent this DDebugAgent is associated with.
       
   390 TUint64 DDebugAgent::Id(void)
       
   391 	{
       
   392 	return iId;
       
   393 	}
       
   394 
       
   395 /**
       
   396  * Used to add an event to the event queue for this debug agent if event 
       
   397  * queue is not at critical level. If it is at critical and it is trace event, 
       
   398  * we start ignoring trace events and insert a lost trace event.
       
   399  * If the buffer cannot store an event, only insert a buffer full event.
       
   400  * @see EEventsBufferFull
       
   401  * @see EEventsUserTracesLost
       
   402  * @see TDriverEventInfo
       
   403  * @see iEventQueue
       
   404  */
       
   405 void DDebugAgent::QueueEvent(const TDriverEventInfo& aEventInfo)
       
   406 	{
       
   407 	// Have we caught the tail?
       
   408 	if(BufferFull())
       
   409 		{
       
   410 		LOG_MSG("DDebugAgent::QueueEvent : BufferFull. Not queueing");
       
   411 		return;
       
   412 		}
       
   413 
       
   414 	// Assert if we think there is space but the slot is not marked empty
       
   415 	__NK_ASSERT_DEBUG(iEventQueue[iHead].iEventType == EEventsUnknown);
       
   416 
       
   417 	const TBool bufferAtCritical = BufferAtCriticalLevel();
       
   418 
       
   419 	if(!bufferAtCritical)
       
   420 		{
       
   421 		//reset the iIgnoringTrace flag as we are not at 
       
   422 		//critical level and can store event
       
   423 		iIgnoringTrace = EFalse; 
       
   424 		
       
   425 		// Insert the event into the ring buffer at iHead
       
   426 		iEventQueue[iHead] = aEventInfo;
       
   427 		IncrementHeadPosition();
       
   428 		}
       
   429 	else if(bufferAtCritical && BufferCanStoreEvent())
       
   430 		{
       
   431 		LOG_MSG("DDebugAgent::QueueEvent : BufferCritical");
       
   432 		if(aEventInfo.iEventType == EEventsUserTrace)
       
   433 			{
       
   434 			if(!iIgnoringTrace)
       
   435 				{
       
   436 				//if this is the first time we are ignoring trace events, 
       
   437 				//we need to issue a EEventsUserTracesLost event
       
   438 				iEventQueue[iHead].Reset();
       
   439 				iEventQueue[iHead].iEventType = EEventsUserTracesLost;
       
   440 				IncrementHeadPosition();
       
   441 
       
   442 				iIgnoringTrace = ETrue;
       
   443 				}
       
   444 			else
       
   445 				{
       
   446 				//otherwise, ignore this event
       
   447 				LOG_MSG("DDebugAgent::QueueEvent : Ignore EEventsUserTrace event");
       
   448 				}
       
   449 			}
       
   450 		else
       
   451 			{
       
   452 			// Store the event since its not a trace event
       
   453 			iEventQueue[iHead] = aEventInfo;
       
   454 			IncrementHeadPosition();
       
   455 			}
       
   456 		}
       
   457 	else
       
   458 		{
       
   459 		//At critical level and cannot store new events, so 
       
   460 		//only one space left. Store a EEventsBufferFull event
       
   461 		LOG_MSG("DDebugAgent::QueueEvent : Event Buffer Full, ignoring event");
       
   462 		iEventQueue[iHead].Reset();
       
   463 		iEventQueue[iHead].iEventType = EEventsBufferFull;
       
   464 		IncrementHeadPosition();
       
   465 		}
       
   466 	}
       
   467 
       
   468 // End of file - d_debug_agent.cpp