1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kernel/eka/drivers/debug/rmdebug/d_debug_agent.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,368 @@
1.4 +// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// Purpose: Kernel-side tracking of debug agent information associated
1.18 +// with each process being debugged.
1.19 +//
1.20 +//
1.21 +
1.22 +#include <e32def.h>
1.23 +#include <e32def_private.h>
1.24 +#include <e32cmn.h>
1.25 +#include <e32cmn_private.h>
1.26 +#include <kernel/kernel.h>
1.27 +#include <kernel/kern_priv.h>
1.28 +#include <nk_trace.h>
1.29 +#include <arm.h>
1.30 +
1.31 +#include "d_process_tracker.h"
1.32 +#include "debug_logging.h"
1.33 +
1.34 +#include "d_debug_agent.h"
1.35 +#include "debug_utils.h"
1.36 +
1.37 +using namespace Debug;
1.38 +
1.39 +#define NUMBER_OF_EVENTS_TO_QUEUE 100
1.40 +#define CRITICAL_BUFFER_SIZE (NUMBER_OF_EVENTS_TO_QUEUE - 50)
1.41 +
1.42 +// ctor
1.43 +DDebugAgent::DDebugAgent(TUint64 aId)
1.44 +: iId(aId),
1.45 + iEventInfo(NULL),
1.46 + iEventQueue(NUMBER_OF_EVENTS_TO_QUEUE, 0),
1.47 + iRequestGetEventStatus(NULL),
1.48 + iClientThread(0),
1.49 + iHead(0),
1.50 + iTail(0),
1.51 + iIgnoringTrace(EFalse)
1.52 + {
1.53 + LOG_MSG("DDebugAgent::DDebugAgent() ");
1.54 +
1.55 + // Initialize all the Event Actions to Ignore
1.56 + for(TInt i=0; i<EEventsLast; i++)
1.57 + {
1.58 + iEventActions[i] = EActionIgnore;
1.59 + }
1.60 + }
1.61 +
1.62 +DDebugAgent* DDebugAgent::New(TUint64 aId)
1.63 + {
1.64 + LOG_MSG("DDebugAgent::New()");
1.65 + DDebugAgent* agent = new DDebugAgent(aId);
1.66 + if(agent == NULL)
1.67 + {
1.68 + return (NULL);
1.69 + }
1.70 + if(KErrNone != agent->Construct())
1.71 + {
1.72 + delete agent;
1.73 + return (NULL);
1.74 + }
1.75 + return agent;
1.76 + }
1.77 +
1.78 +TInt DDebugAgent::Construct()
1.79 + {
1.80 + // Empty the event queue
1.81 + LOG_MSG("DDebugAgent::Construct()");
1.82 + TDriverEventInfo emptyEvent;
1.83 +
1.84 + for (TInt i=0; i<NUMBER_OF_EVENTS_TO_QUEUE; i++)
1.85 + {
1.86 + TInt err = iEventQueue.Append(emptyEvent);
1.87 + if (KErrNone != err)
1.88 + {
1.89 + LOG_MSG("Error appending blank event entry");
1.90 + return err;
1.91 + }
1.92 + }
1.93 + return KErrNone;
1.94 + }
1.95 +
1.96 +
1.97 +// dtor
1.98 +DDebugAgent::~DDebugAgent()
1.99 + {
1.100 + iEventQueue.Reset();
1.101 + }
1.102 +
1.103 +// Associate an action with a particular kernel event
1.104 +TInt DDebugAgent::SetEventAction(TEventType aEvent, TKernelEventAction aEventAction)
1.105 + {
1.106 + // Valid Event?
1.107 + if (aEvent >= EEventsLast)
1.108 + {
1.109 + LOG_MSG2("DDebugAgent::EventAction: Bad Event number %d",aEvent);
1.110 + return KErrArgument;
1.111 + }
1.112 +
1.113 + iEventActions[aEvent] = aEventAction;
1.114 +
1.115 + return KErrNone;
1.116 + }
1.117 +
1.118 +/* Get the aEventAction associated with aEvent
1.119 + *
1.120 + * Returns : aEventAction (always +ve), or KErrArgument.
1.121 + */
1.122 +TInt DDebugAgent::EventAction(TEventType aEvent)
1.123 + {
1.124 + // Validate the Event id
1.125 + if (aEvent >= EEventsLast)
1.126 + {
1.127 + LOG_MSG2("DDebugAgent::EventAction: Bad Event number %d",aEvent);
1.128 + return KErrArgument;
1.129 + }
1.130 +
1.131 + // Return the action associated with this event
1.132 + return iEventActions[aEvent];
1.133 + }
1.134 +
1.135 +// Obtain the details of the latest kernel event (if it exists) and place the details in aEventInfo
1.136 +// If there is no event in the queue for this process+agent combination, store the details
1.137 +// so that it can be notified later when an event actually occurs.
1.138 +//
1.139 +// @param aAsyncGetValueRequest - TClientDataRequest object used for pinning user memory
1.140 +// @param aEventInfo - Address of TEventInfo structure to place event data when available
1.141 +// @param aClientThread - The ThreadId of the requesting user-side process. In this case the DSS.
1.142 +void DDebugAgent::GetEvent(TClientDataRequest<TEventInfo>* aAsyncGetValueRequest, TEventInfo* aEventInfo, DThread* aClientThread)
1.143 + {
1.144 + iClientThread = aClientThread;
1.145 +
1.146 + if (BufferEmpty())
1.147 + {
1.148 + LOG_MSG("no events available");
1.149 +
1.150 + // store the pointer so we can modify it later
1.151 + iEventInfo = (TEventInfo *)aEventInfo;
1.152 + iRequestGetEventStatus = aAsyncGetValueRequest;
1.153 + return;
1.154 + }
1.155 +
1.156 + LOG_MSG("Event available");
1.157 +
1.158 + // returning the event to the client
1.159 + TInt err = iEventQueue[iTail].WriteEventToClientThread(aAsyncGetValueRequest,iClientThread);
1.160 + if (KErrNone != err)
1.161 + {
1.162 + LOG_MSG2("Error writing event info: %d", err);
1.163 + return;
1.164 + }
1.165 +
1.166 + // signal the DSS thread
1.167 + Kern::QueueRequestComplete(iClientThread, aAsyncGetValueRequest, KErrNone);
1.168 +
1.169 + iEventQueue[iTail].Reset();
1.170 +
1.171 + // move to the next slot
1.172 + IncrementPosition(iTail);
1.173 + }
1.174 +
1.175 +// Stop waiting for an event to occur. This means events will be placed in the iEventQueue
1.176 +// until GetEvent is called.
1.177 +TInt DDebugAgent::CancelGetEvent(void)
1.178 + {
1.179 + Kern::QueueRequestComplete(iClientThread, iRequestGetEventStatus, KErrCancel);
1.180 + iEventInfo = NULL;
1.181 + iRequestGetEventStatus = 0;
1.182 + iClientThread = 0;
1.183 +
1.184 + return KErrNone;
1.185 + }
1.186 +
1.187 +// Signal a kernel event to the user-side DSS when it occurs, or queue it for later
1.188 +// if the user-side has not called GetEvent (see above).
1.189 +//
1.190 +// @param aEventInfo - the details of the event to queue.
1.191 +void DDebugAgent::NotifyEvent(const TDriverEventInfo& aEventInfo)
1.192 + {
1.193 + LOG_MSG("DDebugAgent::NotifyEvent()");
1.194 + // Action depends on the TKernelEvent type in aEventInfo.iType
1.195 +
1.196 + // Added to fix the pass by value issue seen in Coverity.
1.197 + // Function is changed to pass by reference but temp object is explicitly created.
1.198 + TDriverEventInfo eventInfo = aEventInfo;
1.199 +
1.200 + if(aEventInfo.iEventType >= EEventsLast)
1.201 + {
1.202 + // unknown event type so return
1.203 + return;
1.204 + }
1.205 +
1.206 + TKernelEventAction action = iEventActions[eventInfo.iEventType];
1.207 +
1.208 + switch (action)
1.209 + {
1.210 + case EActionSuspend:
1.211 + {
1.212 + LOG_MSG("DDebugAgent::NotifyEvent() Suspend thread");
1.213 + DThread* currentThread = &Kern::CurrentThread();
1.214 + switch(eventInfo.iEventType)
1.215 + {
1.216 + case EEventsAddLibrary:
1.217 + case EEventsRemoveLibrary:
1.218 + currentThread = DebugUtils::OpenThreadHandle(eventInfo.iThreadId);
1.219 + if(currentThread)
1.220 + {
1.221 + currentThread->Close(NULL);
1.222 + }
1.223 + break;
1.224 + default:
1.225 + break;
1.226 + }
1.227 + TInt err = TheDProcessTracker.SuspendThread(currentThread, eventInfo.FreezeOnSuspend());
1.228 + if(!( (err == KErrNone) || (err == KErrAlreadyExists) ))
1.229 + {
1.230 + // Is there anything we can do in the future to deal with this error having happened?
1.231 + LOG_MSG2("DDebugAgent::NotifyEvent() Problem while suspending thread: %d", err);
1.232 + }
1.233 +
1.234 + // now drop through to the continue case, which typically notifies
1.235 + // the debug agent of the event
1.236 + }
1.237 + case EActionContinue:
1.238 + LOG_MSG("DDebugAgent::NotifyEvent() Continue");
1.239 +
1.240 + // Tell the user about this event
1.241 + if (iEventInfo && iClientThread)
1.242 + {
1.243 + LOG_MSG("Completing event\r\n");
1.244 +
1.245 + // returning the event to the client
1.246 + TInt err = eventInfo.WriteEventToClientThread(iRequestGetEventStatus,iClientThread);
1.247 + if (KErrNone != err)
1.248 + {
1.249 + LOG_MSG2("Error writing event info: %d", err);
1.250 + }
1.251 +
1.252 + // clear this since we've completed the request
1.253 + iEventInfo = NULL;
1.254 +
1.255 + // signal the debugger thread
1.256 + Kern::QueueRequestComplete(iClientThread, iRequestGetEventStatus, KErrNone);
1.257 + }
1.258 + else
1.259 + {
1.260 + LOG_MSG("Queuing event\r\n");
1.261 +
1.262 + QueueEvent(eventInfo);
1.263 +
1.264 + }
1.265 + break;
1.266 +
1.267 + case EActionIgnore:
1.268 + default:
1.269 + LOG_MSG("DDebugAgent::NotifyEvent() fallen through to default case");
1.270 + // Ignore everything we don't understand.
1.271 + return;
1.272 + }
1.273 +
1.274 + }
1.275 +
1.276 +// Used to identify which Debug Agent this DDebugAgent is associated with.
1.277 +TUint64 DDebugAgent::Id(void)
1.278 + {
1.279 + return iId;
1.280 + }
1.281 +
1.282 +// Used to add an event to the event queue for this debug agent
1.283 +void DDebugAgent::QueueEvent(TDriverEventInfo& aEventInfo)
1.284 + {
1.285 + // Have we caught the tail?
1.286 + if(BufferFull())
1.287 + {
1.288 + return;
1.289 + }
1.290 +
1.291 + //check to see if we wish to ignore this event - we dump trace events as they are lower priority than the other events
1.292 + if(BufferAtCriticalLevel())
1.293 + {
1.294 + if(aEventInfo.iEventType == EEventsUserTrace)
1.295 + {
1.296 + if(!iIgnoringTrace)
1.297 + {
1.298 + //if this is the first time we are ignoring trace events, we need to issue a EEventsUserTracesLost event
1.299 + aEventInfo.Reset();
1.300 + aEventInfo.iEventType = EEventsUserTracesLost;
1.301 +
1.302 + iIgnoringTrace = ETrue;
1.303 + }
1.304 + else
1.305 + {
1.306 + //otherwise, ignore this event
1.307 + return;
1.308 + }
1.309 + }
1.310 + }
1.311 + else
1.312 + {
1.313 + //reset the iIgnoringTrace flag as we are not at critical level
1.314 + iIgnoringTrace = EFalse;
1.315 + }
1.316 +
1.317 + // only one space left so store a EEventsBufferFull event
1.318 + if(!BufferCanStoreEvent())
1.319 + {
1.320 + aEventInfo.Reset();
1.321 + aEventInfo.iEventType = EEventsBufferFull;
1.322 + }
1.323 +
1.324 + __NK_ASSERT_DEBUG(iEventQueue[iHead].iEventType == EEventsUnknown); // we think there is space but the slot is not marked empty
1.325 +
1.326 + // Insert the event into the ring buffer at iHead
1.327 + iEventQueue[iHead] = aEventInfo;
1.328 + IncrementPosition(iHead);
1.329 + }
1.330 +
1.331 +// Checks whether the event queue is empty
1.332 +TBool DDebugAgent::BufferEmpty() const
1.333 + {
1.334 + return (NumberOfEmptySlots() == NUMBER_OF_EVENTS_TO_QUEUE);
1.335 + }
1.336 +
1.337 +// Checks whether the event queue is full
1.338 +TBool DDebugAgent::BufferFull() const
1.339 + {
1.340 + return (NumberOfEmptySlots() == 0);
1.341 + }
1.342 +
1.343 +// Checks whether there is room in the event queue to store an event (i.e. at least two free slots)
1.344 +TBool DDebugAgent::BufferCanStoreEvent() const
1.345 + {
1.346 + return (NumberOfEmptySlots() > 1);
1.347 + }
1.348 +
1.349 +//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)
1.350 +TBool DDebugAgent::BufferAtCriticalLevel() const
1.351 + {
1.352 + return (NumberOfEmptySlots() < NUMBER_OF_EVENTS_TO_QUEUE - CRITICAL_BUFFER_SIZE);
1.353 + }
1.354 +
1.355 +// increments aPosition, wrapping at NUMBER_OF_EVENTS_TO_QUEUE if necessary
1.356 +void DDebugAgent::IncrementPosition(TInt& aPosition)
1.357 + {
1.358 + aPosition = (aPosition + 1) % NUMBER_OF_EVENTS_TO_QUEUE;
1.359 + }
1.360 +
1.361 +// finds the number of empty slots in the event queue
1.362 +TInt DDebugAgent::NumberOfEmptySlots() const
1.363 + {
1.364 + if(iHead < iTail)
1.365 + {
1.366 + return (iTail - iHead) - 1;
1.367 + }
1.368 + // iHead >= iTail
1.369 + return NUMBER_OF_EVENTS_TO_QUEUE - (iHead - iTail);
1.370 + }
1.371 +