kernel/eka/drivers/debug/rmdebug/d_debug_agent.cpp
changeset 0 a41df078684a
child 21 e7d2d738d3c2
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     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 using namespace Debug;
       
    35 
       
    36 #define NUMBER_OF_EVENTS_TO_QUEUE 100
       
    37 #define CRITICAL_BUFFER_SIZE (NUMBER_OF_EVENTS_TO_QUEUE - 50)
       
    38 
       
    39 // ctor
       
    40 DDebugAgent::DDebugAgent(TUint64 aId)
       
    41 : iId(aId),
       
    42   iEventInfo(NULL),
       
    43   iEventQueue(NUMBER_OF_EVENTS_TO_QUEUE, 0),
       
    44   iRequestGetEventStatus(NULL),
       
    45   iClientThread(0),
       
    46   iHead(0),
       
    47   iTail(0),
       
    48   iIgnoringTrace(EFalse)
       
    49 	{
       
    50 	LOG_MSG("DDebugAgent::DDebugAgent() ");
       
    51 
       
    52 	// Initialize all the Event Actions to Ignore
       
    53 	for(TInt i=0; i<EEventsLast; i++)
       
    54 		{
       
    55 		iEventActions[i] = EActionIgnore;
       
    56 		}
       
    57 	}
       
    58 
       
    59 DDebugAgent* DDebugAgent::New(TUint64 aId)
       
    60 	{
       
    61 	LOG_MSG("DDebugAgent::New()");
       
    62 	DDebugAgent* agent = new DDebugAgent(aId);
       
    63 	if(agent == NULL)
       
    64 		{
       
    65 		return (NULL);
       
    66 		}
       
    67 	if(KErrNone != agent->Construct())
       
    68 		{
       
    69 		delete agent;
       
    70 		return (NULL);
       
    71 		}
       
    72 	return agent;
       
    73 	}
       
    74 
       
    75 TInt DDebugAgent::Construct()
       
    76 	{
       
    77 	// Empty the event queue
       
    78 	LOG_MSG("DDebugAgent::Construct()");
       
    79 	TDriverEventInfo emptyEvent;
       
    80 
       
    81 	for (TInt i=0; i<NUMBER_OF_EVENTS_TO_QUEUE; i++)
       
    82 		{
       
    83 		TInt err = iEventQueue.Append(emptyEvent);
       
    84 		if (KErrNone != err)
       
    85 			{
       
    86 			LOG_MSG("Error appending blank event entry");
       
    87 			return err;
       
    88 			}
       
    89 		}
       
    90 	return KErrNone;
       
    91 	}
       
    92 
       
    93 
       
    94 // dtor
       
    95 DDebugAgent::~DDebugAgent()
       
    96 	{
       
    97 	iEventQueue.Reset();
       
    98 	}
       
    99 
       
   100 // Associate an action with a particular kernel event
       
   101 TInt DDebugAgent::SetEventAction(TEventType aEvent, TKernelEventAction aEventAction)
       
   102 	{
       
   103 	// Valid Event?
       
   104 	if (aEvent >= EEventsLast)
       
   105 		{
       
   106 		LOG_MSG2("DDebugAgent::EventAction: Bad Event number %d",aEvent);
       
   107 		return KErrArgument;
       
   108 		}
       
   109 
       
   110 	iEventActions[aEvent] = aEventAction;
       
   111 
       
   112 	return KErrNone;
       
   113 	}
       
   114 
       
   115 /* Get the aEventAction associated with aEvent
       
   116  *
       
   117  * Returns : aEventAction (always +ve), or KErrArgument.
       
   118  */
       
   119 TInt DDebugAgent::EventAction(TEventType aEvent)
       
   120 	{
       
   121 	// Validate the Event id
       
   122 	if (aEvent >= EEventsLast)
       
   123 		{
       
   124 		LOG_MSG2("DDebugAgent::EventAction: Bad Event number %d",aEvent);
       
   125 		return KErrArgument;
       
   126 		}
       
   127 
       
   128 	// Return the action associated with this event
       
   129 	return iEventActions[aEvent];
       
   130 	}
       
   131 
       
   132 // Obtain the details of the latest kernel event (if it exists) and place the details in aEventInfo
       
   133 // If there is no event in the queue for this process+agent combination, store the details
       
   134 // so that it can be notified later when an event actually occurs.
       
   135 //
       
   136 // @param aAsyncGetValueRequest - TClientDataRequest object used for pinning user memory
       
   137 // @param aEventInfo - Address of TEventInfo structure to place event data when available
       
   138 // @param aClientThread - The ThreadId of the requesting user-side process. In this case the DSS.
       
   139 void DDebugAgent::GetEvent(TClientDataRequest<TEventInfo>* aAsyncGetValueRequest, TEventInfo* aEventInfo, DThread* aClientThread)
       
   140 	{
       
   141 	iClientThread = aClientThread;
       
   142 
       
   143 	if (BufferEmpty())
       
   144 		{
       
   145 		LOG_MSG("no events available");
       
   146 
       
   147 		// store the pointer so we can modify it later
       
   148 		iEventInfo = (TEventInfo *)aEventInfo;
       
   149 		iRequestGetEventStatus = aAsyncGetValueRequest;
       
   150 		return;
       
   151 		}
       
   152 
       
   153 	LOG_MSG("Event available");
       
   154 
       
   155 	// returning the event to the client
       
   156 	TInt err = iEventQueue[iTail].WriteEventToClientThread(aAsyncGetValueRequest,iClientThread);
       
   157 	if (KErrNone != err)
       
   158 		{
       
   159 		LOG_MSG2("Error writing event info: %d", err);
       
   160 		return;
       
   161 		}
       
   162 
       
   163 	// signal the DSS thread
       
   164 	Kern::QueueRequestComplete(iClientThread, aAsyncGetValueRequest, KErrNone);
       
   165 
       
   166 	iEventQueue[iTail].Reset();
       
   167 
       
   168 	// move to the next slot
       
   169 	IncrementPosition(iTail);
       
   170 	}
       
   171 
       
   172 // Stop waiting for an event to occur. This means events will be placed in the iEventQueue
       
   173 // until GetEvent is called.
       
   174 TInt DDebugAgent::CancelGetEvent(void)
       
   175 	{
       
   176 	Kern::QueueRequestComplete(iClientThread, iRequestGetEventStatus, KErrCancel);
       
   177 	iEventInfo = NULL;
       
   178     iRequestGetEventStatus = 0;
       
   179 	iClientThread = 0;
       
   180 
       
   181 	return KErrNone;
       
   182 	}
       
   183 
       
   184 // Signal a kernel event to the user-side DSS when it occurs, or queue it for later
       
   185 // if the user-side has not called GetEvent (see above).
       
   186 //
       
   187 // @param aEventInfo - the details of the event to queue.
       
   188 void DDebugAgent::NotifyEvent(const TDriverEventInfo& aEventInfo)
       
   189 	{
       
   190 	LOG_MSG("DDebugAgent::NotifyEvent()");
       
   191 	// Action depends on the TKernelEvent type in aEventInfo.iType
       
   192 	
       
   193 	// Added to fix the pass by value issue seen in Coverity.  
       
   194 	// Function is changed to pass by reference but temp object is explicitly created.
       
   195 	TDriverEventInfo eventInfo = aEventInfo;
       
   196 
       
   197 	if(aEventInfo.iEventType >= EEventsLast)
       
   198 		{
       
   199 		// unknown event type so return
       
   200 		return;
       
   201 		}
       
   202 
       
   203 	TKernelEventAction action = iEventActions[eventInfo.iEventType];
       
   204 
       
   205 	switch (action)
       
   206 		{
       
   207 		case EActionSuspend:
       
   208 			{
       
   209 			LOG_MSG("DDebugAgent::NotifyEvent() Suspend thread");
       
   210 			DThread* currentThread = &Kern::CurrentThread();
       
   211 			switch(eventInfo.iEventType)
       
   212 				{
       
   213 				case EEventsAddLibrary:
       
   214 				case EEventsRemoveLibrary:
       
   215 					currentThread = DebugUtils::OpenThreadHandle(eventInfo.iThreadId);
       
   216 					if(currentThread)
       
   217 						{
       
   218 						currentThread->Close(NULL);
       
   219 						}
       
   220 					break;
       
   221 				default:
       
   222 					break;
       
   223 				}
       
   224 			TInt err = TheDProcessTracker.SuspendThread(currentThread, eventInfo.FreezeOnSuspend());
       
   225 			if(!( (err == KErrNone) || (err == KErrAlreadyExists) ))
       
   226 				{
       
   227 				// Is there anything we can do in the future to deal with this error having happened?
       
   228 				LOG_MSG2("DDebugAgent::NotifyEvent() Problem while suspending thread: %d", err);
       
   229 				}
       
   230 
       
   231 			// now drop through to the continue case, which typically notifies
       
   232 			// the debug agent of the event
       
   233 			}
       
   234 		case EActionContinue:
       
   235 			LOG_MSG("DDebugAgent::NotifyEvent() Continue");
       
   236 
       
   237 			// Tell the user about this event
       
   238 			if (iEventInfo && iClientThread)
       
   239 			{
       
   240 				LOG_MSG("Completing event\r\n");
       
   241 
       
   242 				// returning the event to the client
       
   243 				TInt err = eventInfo.WriteEventToClientThread(iRequestGetEventStatus,iClientThread);
       
   244 				if (KErrNone != err)
       
   245 				{
       
   246 					LOG_MSG2("Error writing event info: %d", err);
       
   247 				}
       
   248 
       
   249 				// clear this since we've completed the request
       
   250 				iEventInfo = NULL;
       
   251 
       
   252 				// signal the debugger thread
       
   253 				Kern::QueueRequestComplete(iClientThread, iRequestGetEventStatus, KErrNone);
       
   254 			}
       
   255 			else
       
   256 			{
       
   257 				LOG_MSG("Queuing event\r\n");
       
   258 
       
   259 				QueueEvent(eventInfo);
       
   260 
       
   261 			}
       
   262 			break;
       
   263 
       
   264 		case EActionIgnore:
       
   265 		default:
       
   266 			LOG_MSG("DDebugAgent::NotifyEvent() fallen through to default case");
       
   267 			// Ignore everything we don't understand.
       
   268 			return;
       
   269 		}
       
   270 
       
   271 	}
       
   272 
       
   273 // Used to identify which Debug Agent this DDebugAgent is associated with.
       
   274 TUint64 DDebugAgent::Id(void)
       
   275 	{
       
   276 	return iId;
       
   277 	}
       
   278 
       
   279 // Used to add an event to the event queue for this debug agent
       
   280 void DDebugAgent::QueueEvent(TDriverEventInfo& aEventInfo)
       
   281 	{
       
   282 	// Have we caught the tail?
       
   283 	if(BufferFull())
       
   284 		{
       
   285 		return;
       
   286 		}
       
   287 	
       
   288 	//check to see if we wish to ignore this event - we dump trace events as they are lower priority than the other events
       
   289 	if(BufferAtCriticalLevel())
       
   290 		{
       
   291 		if(aEventInfo.iEventType == EEventsUserTrace)
       
   292 			{
       
   293 			if(!iIgnoringTrace)
       
   294 				{
       
   295 				//if this is the first time we are ignoring trace events, we need to issue a EEventsUserTracesLost event
       
   296 				aEventInfo.Reset();
       
   297 				aEventInfo.iEventType = EEventsUserTracesLost;
       
   298 				
       
   299 				iIgnoringTrace = ETrue;
       
   300 				}
       
   301 			else
       
   302 				{
       
   303 				//otherwise, ignore this event
       
   304 				return;
       
   305 				}
       
   306 			}
       
   307 		}
       
   308 	else
       
   309 		{
       
   310 		//reset the iIgnoringTrace flag as we are not at critical level
       
   311 		iIgnoringTrace = EFalse; 
       
   312 		}	
       
   313 
       
   314 	// only one space left so store a EEventsBufferFull event
       
   315 	if(!BufferCanStoreEvent())
       
   316 		{
       
   317 		aEventInfo.Reset();
       
   318 		aEventInfo.iEventType = EEventsBufferFull;
       
   319 		}
       
   320 
       
   321 	__NK_ASSERT_DEBUG(iEventQueue[iHead].iEventType == EEventsUnknown); // we think there is space but the slot is not marked empty
       
   322 
       
   323 	// Insert the event into the ring buffer at iHead
       
   324 	iEventQueue[iHead] = aEventInfo;
       
   325 	IncrementPosition(iHead);
       
   326 	}
       
   327 
       
   328 // Checks whether the event queue is empty
       
   329 TBool DDebugAgent::BufferEmpty() const
       
   330 	{
       
   331 	return (NumberOfEmptySlots() == NUMBER_OF_EVENTS_TO_QUEUE);
       
   332 	}
       
   333 
       
   334 // Checks whether the event queue is full
       
   335 TBool DDebugAgent::BufferFull() const
       
   336 	{
       
   337 	return (NumberOfEmptySlots() == 0);
       
   338 	}
       
   339 
       
   340 // Checks whether there is room in the event queue to store an event (i.e. at least two free slots)
       
   341 TBool DDebugAgent::BufferCanStoreEvent() const
       
   342 	{
       
   343 	return (NumberOfEmptySlots() > 1);
       
   344 	}
       
   345 
       
   346 //This looks to see if the buffer is close to being full and should only accept higher priority debug events (user trace is the only low priority event) 
       
   347 TBool DDebugAgent::BufferAtCriticalLevel() const
       
   348 	{
       
   349 	return (NumberOfEmptySlots() < NUMBER_OF_EVENTS_TO_QUEUE - CRITICAL_BUFFER_SIZE);
       
   350 	}
       
   351 
       
   352 // increments aPosition, wrapping at NUMBER_OF_EVENTS_TO_QUEUE if necessary
       
   353 void DDebugAgent::IncrementPosition(TInt& aPosition)
       
   354 	{
       
   355 	aPosition = (aPosition + 1) % NUMBER_OF_EVENTS_TO_QUEUE;
       
   356 	}
       
   357 
       
   358 // finds the number of empty slots in the event queue
       
   359 TInt DDebugAgent::NumberOfEmptySlots() const
       
   360 	{
       
   361 	if(iHead < iTail)
       
   362 		{
       
   363 		return (iTail - iHead) - 1;
       
   364 		}
       
   365 	// iHead >= iTail
       
   366 	return NUMBER_OF_EVENTS_TO_QUEUE - (iHead - iTail);
       
   367 	}
       
   368