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