os/kernelhwsrv/kernel/eka/drivers/debug/rmdebug/d_debug_agent.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     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