os/kernelhwsrv/kernel/eka/drivers/debug/rmdebug/d_target_process.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.
     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: The DProcessTracker object tracks which processes are being
    15 // debugged. The DProcessTracker class uses a DTargetProcess object for
    16 // each process being debugged.
    17 // Note: Although TheDProcessTracker object is a global, it should be unique
    18 // as only the Debug Security Server should load and use this driver.
    19 // 
    20 //
    21 
    22 #include <e32def.h>
    23 #include <e32def_private.h>
    24 #include <e32cmn.h>
    25 #include <e32cmn_private.h>
    26 #include <kernel/kernel.h>
    27 #include <kernel/kern_priv.h>
    28 #include "nk_priv.h"
    29 #include <rm_debug_api.h>
    30 
    31 #include "d_target_process.h"
    32 #include "debug_logging.h"
    33 #include "debug_utils.h"
    34 
    35 // ctor
    36 DTargetProcess::DTargetProcess()
    37 	:iProcessName(0,0,0)
    38 	{
    39 	}
    40 
    41 // dtor
    42 DTargetProcess::~DTargetProcess()
    43 	{
    44 	// Delete the space allocated for the name if any
    45 	if (iProcessName.Ptr() != 0)
    46 		{
    47 		NKern::ThreadEnterCS();
    48 		Kern::Free((TAny*)iProcessName.Ptr());
    49 		NKern::ThreadLeaveCS();
    50 		}
    51 	//Reset the array and delete the objects that its members point to
    52 	NKern::ThreadEnterCS();
    53 	iAgentList.ResetAndDestroy();
    54 	NKern::ThreadLeaveCS();
    55 	}
    56 
    57 // Compare two DTargetProcess items. They are the same if they have the same name.
    58 TInt DTargetProcess::Compare(const DTargetProcess& aFirst, const DTargetProcess& aSecond)
    59 	{
    60 	return aFirst.iProcessName.Compare(aSecond.iProcessName);
    61 	}
    62 
    63 // Set the name of the process we are tracking
    64 TInt DTargetProcess::SetProcessName(const TDesC8& aProcessName)
    65 	{
    66 	// Argument checking
    67 	if (aProcessName.Length() < 1)
    68 		{
    69 		return KErrArgument;
    70 		}
    71 
    72 	// Allocate some memory to store the name
    73 	TUint length = aProcessName.Length();
    74 
    75 	NKern::ThreadEnterCS();
    76 	TUint8* buffer = (TUint8*)Kern::AllocZ(length);
    77 	NKern::ThreadLeaveCS();
    78 	if (buffer==NULL)
    79 		{
    80 		// Out of memory
    81 		return KErrNoMemory;
    82 		}
    83 
    84 	// Set iProcessName to use the alloc'd buffer
    85 	iProcessName.Set(buffer,length,length);
    86 
    87 	// Store aProcessName within this object
    88 	iProcessName.Copy(aProcessName);
    89 
    90 	return KErrNone;
    91 	}
    92 
    93 // Obtain the name of the process being tracked
    94 const TPtr8& DTargetProcess::ProcessName(void)
    95 	{
    96 	return iProcessName;
    97 	}
    98 
    99 // Returns a pointer to the DDebugAgent with aAgentId.
   100 // If the agent is not in the list, it returns NULL.
   101 DDebugAgent* DTargetProcess::Agent(TUint64 aAgentId)
   102 	{
   103 	for(TInt i = 0; i < iAgentList.Count(); i++)
   104 	{
   105 		if (iAgentList[i]->Id() == aAgentId)
   106 		{
   107 			return iAgentList[i];
   108 		}
   109 	}
   110 
   111 	// what do we return if we don't have any agents?
   112 	return NULL;
   113 	}
   114 
   115 // Adds aAgentId as a tracking agent for this process.
   116 TInt DTargetProcess::AddAgent(TUint64 aAgentId)
   117 	{
   118 	LOG_MSG("DTargetProcess::AddAgent()");
   119 	DDebugAgent* agent = DDebugAgent::New(aAgentId);
   120 	if(agent == NULL)
   121 		{
   122 		LOG_MSG("DTargetProcess::AddAgent() couldn't allocate memory for DDebugAgent");
   123 		return KErrNoMemory;
   124 		}
   125 	return iAgentList.Insert(agent,0);
   126 	}
   127 
   128 // Stops tracking the process with this agent
   129 TInt DTargetProcess::RemoveAgent(TUint64 aAgentId)
   130 	{
   131 	// We need to find and then remove the agent
   132 	for(TUint i = 0; i < iAgentList.Count(); i++)
   133 		{
   134 		if (iAgentList[i]->Id() == aAgentId)
   135 			{
   136 			delete iAgentList[i];
   137 			iAgentList.Remove(i);
   138 			return KErrNone;
   139 			}
   140 		}
   141 
   142 	return KErrNotFound;
   143 	}
   144 
   145 // Index through the agents by position
   146 DDebugAgent* DTargetProcess::operator[](TInt aIndex)
   147 	{
   148 	return iAgentList[aIndex];
   149 	}
   150 
   151 // returns the number of agents tracking this process.
   152 TInt DTargetProcess::AgentCount(void)
   153 	{
   154 	return iAgentList.Count();
   155 	}
   156 
   157 /**
   158   Resume the specified thread
   159 
   160   @param aThread thread to resume
   161 
   162   @return KErrNone if the thread has previously been suspended and is resumed,
   163   KErrNotFound if the thread has not previously been suspended
   164   */
   165 TInt DTargetProcess::ResumeThread(DThread* aThread)
   166 	{
   167 	LOG_MSG2("DTargetProcess::ResumeSuspendedThread(): thread=0x%08x", aThread);
   168 	TInt err1 = ResumeSuspendedThread(aThread);
   169 	LOG_MSG2("DTargetProcess::ResumeSuspendedThread(): ret=%d)", err1); 
   170 	TInt err2 = ResumeFrozenThread(aThread->iNThread);
   171 	LOG_MSG2("DTargetProcess::ResumeFrozenThread(): ret=%d)", err2);
   172 	//if resuming the suspended thread failed for an obscure reason return it
   173 	if((err1 != KErrNotFound) && (err1 != KErrNone))
   174 		{
   175 		LOG_MSG2("DTargetProcess::ResumeThread() unexpected exit, err1: %d", err1);
   176 		return err1;
   177 		}
   178 	//if resuming the frozen thread failed for an obscure reason return it
   179 	if((err2 != KErrNotFound) && (err2 != KErrNone))
   180 		{
   181 		LOG_MSG2("DTargetProcess::ResumeThread() unexpected exit, err2: %d", err2);
   182 		return err2;
   183 		}
   184 	// if resuming the suspended thread succeeded in both cases, we have a consistency problem
   185 	if ((err1 == KErrNone) && (err2 == KErrNone))
   186 		{
   187 		LOG_MSG("DTargetProcess::ResumeThread() unexpected exit, err1 == err2 == KErrNone");
   188 		}
   189 
   190 	//if the thread was in neither list return KErrNotFound, otherwise KErrNone
   191 	return ((err1 == KErrNone) || (err2 == KErrNone)) ? KErrNone : KErrNotFound;
   192 	}
   193 
   194 /**
   195   Resume the specified frozen thread
   196 
   197   @param aThread thread to resume
   198 
   199   @return KErrNone if the thread has previously been suspended and is resumed,
   200   KErrNotFound if the thread has not previously been suspended
   201   */
   202 TInt DTargetProcess::ResumeFrozenThread(NThread& aThread)
   203 	{
   204 	for(TInt i=0; i<iFrozenThreadSemaphores.Count(); i++)
   205 		{
   206 		if(iFrozenThreadSemaphores[i]->iOwningThread == &aThread)
   207 			{
   208 			NKern::FSSignal(iFrozenThreadSemaphores[i]);
   209 			NKern::ThreadEnterCS();
   210 			delete iFrozenThreadSemaphores[i];
   211 			NKern::ThreadLeaveCS();
   212 			iFrozenThreadSemaphores.Remove(i);
   213 			return KErrNone;
   214 			}
   215 		}
   216 	return KErrNotFound;
   217 	}
   218 
   219 /**
   220   Resume the specified suspended thread
   221 
   222   @param aThread thread to resume
   223 
   224   @return KErrNone if the thread has previously been suspended and is resumed,
   225   KErrNotFound if the thread has not previously been suspended
   226   */
   227 TInt DTargetProcess::ResumeSuspendedThread(DThread* aThread)
   228 	{
   229 	TUint64 threadId = (TUint64)aThread->iId;
   230 	for(TInt i=0; i<iSuspendedThreads.Count(); i++)
   231 		{
   232 		if(iSuspendedThreads[i] == threadId)
   233 			{
   234 			iSuspendedThreads.Remove(i);
   235 			LOG_MSG2("DTargetProcess::ResumeSuspendedThread()> Kern::ThreadResume() 0x%x", aThread);
   236 			Kern::ThreadResume(*aThread);
   237 			return KErrNone;
   238 			}
   239 		}
   240 	return KErrNotFound;
   241 	}
   242 
   243 /**
   244   Suspend the specified thread
   245 
   246   @param aThread thread to suspend
   247 
   248   @param aFreezeThread suspend the thread on a Fast Semaphore if
   249   ETrue. EFalse means suspend by calling Kern::Suspend.
   250 
   251   @return KErrNone if the thread is successfully suspended,
   252   KErrAlreadyExists if the agent has already suspended the thread,
   253   or one of the other system wide error codes
   254   
   255    This function suspends a thread by calling Kern::Thread Suspend.
   256                                                                                                        
   257   An alternative means of suspending the _current_ thread only
   258   is by call DTargetProcess::FreezeThread. This will ensure that
   259   the current thread is suspended when exception processing for this
   260   thread completes (see rm_debug_eventhandler.cpp)
   261   
   262   */
   263 TInt DTargetProcess::SuspendThread(DThread* aThread, TBool aFreezeThread)
   264 	{
   265 	// should check if this thread is already suspended/frozen and return if so
   266 	// but just warn for the moment.
   267 	if (CheckSuspended(aThread))
   268 		{
   269 		// thread was already suspended, don't bother doing it again
   270 		LOG_MSG2("DTargetProcess::SuspendThread - Thread Id 0x%08x already suspended\n",aThread->iId);
   271 		//return KErrAlreadyExists;	
   272 		}
   273 
   274 	return aFreezeThread ? FreezeThread() : DoSuspendThread(aThread);
   275 	}
   276 
   277 /**
   278   Freeze the current thread
   279 
   280   @return KErrNone if the thread is successfully suspended,
   281   KErrAlreadyExists if the agent has already suspended the thread,
   282   or one of the other system wide error codes
   283 
   284   This marks the current thread for waiting on a Fast Semaphore
   285   when exception handling for this thread has completed - see
   286   rm_debug_eventhandler.cpp for details.
   287   */
   288 TInt DTargetProcess::FreezeThread()
   289 	{
   290 	// create and store a fast semaphore to stop the thread on
   291 	NKern::ThreadEnterCS();
   292 	NFastSemaphore* sem = new NFastSemaphore();
   293 	NKern::ThreadLeaveCS();
   294 	sem->iOwningThread = &(Kern::CurrentThread().iNThread);
   295 	LOG_EVENT_MSG2("DTargetProcess::FreezeThread(): new NFastSemaphore() curr thread=0x%x", sem->iOwningThread);
   296 	return iFrozenThreadSemaphores.Append(sem);
   297 	}
   298 
   299 /**
   300   Suspend the specified thread
   301 
   302   @param aThread thread to suspend
   303 
   304   @return KErrNone if the thread is successfully suspended,
   305   KErrAlreadyExists if the agent has already suspended the thread,
   306   or one of the other system wide error codes
   307   */
   308 TInt DTargetProcess::DoSuspendThread(DThread* aThread)
   309 	{
   310 	TUint64 threadId = (TUint64)aThread->iId;
   311 	
   312 	// Don't suspend if this thread is already suspended (by FSWait or
   313 	// Kern::ThreadSuspend
   314 	if (CheckSuspended(aThread))
   315 		{
   316 		// thread was already suspended, don't bother doing it again
   317 		LOG_MSG2("DTargetProcess::SuspendThread - Thread Id 0x%08x already suspended\n",threadId);
   318 		return KErrAlreadyExists;	
   319 		}
   320 
   321 	// Add thread to the suspend list
   322 	TInt err = iSuspendedThreads.Append(threadId);
   323 	if(err == KErrNone)
   324 		{
   325 		Kern::ThreadSuspend(*aThread, 1);
   326 		}
   327 	return err;
   328 	}
   329 
   330 /**
   331  Waits the current thread on a Fast Semaphore.
   332 
   333  This is useful for situations where the current thread
   334  has hit a breakpoint within a critical section, and
   335  otherwise could not be suspended at this point.
   336 
   337  Note that the Fast Semaphore structure on which the thread
   338  waits must be a member data item of this class instance,
   339  as it needs to be FSSignal()'d by another thread to resume
   340  again.
   341  */
   342 void DTargetProcess::FSWait()
   343 	{
   344 	LOG_MSG2("DTargetProcess::NotifyEvent(): number of attached agents: %d", AgentCount());
   345 	NThread* currentThread = &(Kern::CurrentThread().iNThread);
   346 	for(TInt i=0; i<iFrozenThreadSemaphores.Count(); i++)
   347 		{
   348 		if(iFrozenThreadSemaphores[i]->iOwningThread == currentThread)
   349 			{
   350 			LOG_MSG3("DTargetProcess::FSWait(): > FSWait frozen sem %d, curr thread=0x%x", i, currentThread);
   351 			NKern::FSWait(iFrozenThreadSemaphores[i]);
   352 			return;
   353 			}
   354 		}
   355 	}
   356 
   357 /**
   358   Checks that the thread has been suspended
   359 
   360   @param aThread thread to check suspended
   361 
   362   @return ETrue if the thread has been suspended,
   363   EFalse if the thread has not been suspended
   364   */
   365 TBool DTargetProcess::CheckSuspended(DThread* aThread) const
   366 	{
   367 	if(!aThread)
   368 		{
   369 		return EFalse;
   370 		}
   371 	//check if the thread is in the suspended threads list
   372 	for(TInt i=0; i<iSuspendedThreads.Count(); i++)
   373 		{
   374 		if(iSuspendedThreads[i] == (TUint64)aThread->iId)
   375 			{
   376 			return ETrue;
   377 			}
   378 		}
   379 	// not in the suspended threads list so check in the frozen threads list
   380 	NThread* nThread = &(aThread->iNThread);
   381 	for(TInt i=0; i<iFrozenThreadSemaphores.Count(); i++)
   382 		{
   383 		if(iFrozenThreadSemaphores[i]->iOwningThread == nThread)
   384 			{
   385 			return ETrue;
   386 			}
   387 		}
   388 	return EFalse;
   389 	}
   390 
   391 /*
   392 @return ETrue if the debug driver has suspended any of the process' threads, EFalse otherwise
   393 */
   394 TBool DTargetProcess::HasSuspendedThreads() const
   395 	{
   396 	return (iSuspendedThreads.Count() > 0) || (iFrozenThreadSemaphores.Count() > 0);
   397 	}
   398 
   399 void DTargetProcess::NotifyEvent(const TDriverEventInfo& aEventInfo)
   400 	{
   401 	// Stuff the event info into all the tracking agents event queues
   402 	LOG_MSG2("DTargetProcess::NotifyEvent(): number of attached agents: %d", AgentCount());
   403 
   404 	for(TInt i = 0; i < AgentCount(); i++)
   405 		{
   406 		// Index through all the relevant debug agents
   407 		DDebugAgent* debugAgent = iAgentList[i];
   408 		if(debugAgent != NULL)
   409 			{
   410 			debugAgent->NotifyEvent(aEventInfo);
   411 			}
   412 		}
   413 	}
   414