kernel/eka/drivers/debug/rmdebug/d_target_process.cpp
changeset 259 57b9594f5772
parent 247 d8d70de2bd36
child 260 a1a318fd91af
child 266 0008ccd16016
equal deleted inserted replaced
247:d8d70de2bd36 259:57b9594f5772
     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 	
       
   119 	DDebugAgent* agent = DDebugAgent::New(aAgentId);
       
   120 	LOG_MSG4("DTargetProcess::AddAgent(), agentId=%d, curr iAgentList.Count=%d, new agent=0x%08x",
       
   121 		I64LOW(aAgentId), iAgentList.Count(), agent );
       
   122 
       
   123 	if(agent == NULL)
       
   124 		{
       
   125 		LOG_MSG("DTargetProcess::AddAgent() couldn't allocate memory for DDebugAgent");
       
   126 		return KErrNoMemory;
       
   127 		}
       
   128 	return iAgentList.Insert(agent,0);
       
   129 	}
       
   130 
       
   131 // Stops tracking the process with this agent
       
   132 TInt DTargetProcess::RemoveAgent(TUint64 aAgentId)
       
   133 	{
       
   134 	// We need to find and then remove the agent
       
   135 	for(TUint i = 0; i < iAgentList.Count(); i++)
       
   136 		{
       
   137 		if (iAgentList[i]->Id() == aAgentId)
       
   138 			{
       
   139 			delete iAgentList[i];
       
   140 			iAgentList.Remove(i);
       
   141 			return KErrNone;
       
   142 			}
       
   143 		}
       
   144 
       
   145 	return KErrNotFound;
       
   146 	}
       
   147 
       
   148 // Index through the agents by position
       
   149 DDebugAgent* DTargetProcess::operator[](TInt aIndex)
       
   150 	{
       
   151 	return iAgentList[aIndex];
       
   152 	}
       
   153 
       
   154 // returns the number of agents tracking this process.
       
   155 TInt DTargetProcess::AgentCount(void)
       
   156 	{
       
   157 	return iAgentList.Count();
       
   158 	}
       
   159 
       
   160 /**
       
   161   Resume the specified thread
       
   162 
       
   163   @param aThread thread to resume
       
   164 
       
   165   @return KErrNone if the thread has previously been suspended and is resumed,
       
   166   KErrNotFound if the thread has not previously been suspended
       
   167   */
       
   168 TInt DTargetProcess::ResumeThread(DThread* aThread)
       
   169 	{
       
   170 	LOG_MSG2("DTargetProcess::ResumeSuspendedThread(): thread=0x%08x", aThread);
       
   171 	TInt err1 = ResumeSuspendedThread(aThread);
       
   172 	LOG_MSG2("DTargetProcess::ResumeSuspendedThread(): ret=%d)", err1); 
       
   173 	TInt err2 = ResumeFrozenThread(aThread->iNThread);
       
   174 	LOG_MSG2("DTargetProcess::ResumeFrozenThread(): ret=%d)", err2);
       
   175 	//if resuming the suspended thread failed for an obscure reason return it
       
   176 	if((err1 != KErrNotFound) && (err1 != KErrNone))
       
   177 		{
       
   178 		LOG_MSG2("DTargetProcess::ResumeThread() BUG : unexpected exit, err1: %d", err1);
       
   179 		return err1;
       
   180 		}
       
   181 	//if resuming the frozen thread failed for an obscure reason return it
       
   182 	if((err2 != KErrNotFound) && (err2 != KErrNone))
       
   183 		{
       
   184 		LOG_MSG2("DTargetProcess::ResumeThread() BUG : unexpected exit, err2: %d", err2);
       
   185 		return err2;
       
   186 		}
       
   187 	// if resuming the suspended thread succeeded in both cases, we have a consistency problem
       
   188 	if ((err1 == KErrNone) && (err2 == KErrNone))
       
   189 		{
       
   190 		LOG_MSG("DTargetProcess::ResumeThread() BUG : unexpected exit, err1 == err2 == KErrNone");
       
   191 		}
       
   192 
       
   193 	//if the thread was in neither list return KErrNotFound, otherwise KErrNone
       
   194 	return ((err1 == KErrNone) || (err2 == KErrNone)) ? KErrNone : KErrNotFound;
       
   195 	}
       
   196 
       
   197 /**
       
   198   Resume the specified frozen thread
       
   199 
       
   200   @param aThread thread to resume
       
   201 
       
   202   @return KErrNone if the thread has previously been suspended and is resumed,
       
   203   KErrNotFound if the thread has not previously been suspended
       
   204   */
       
   205 TInt DTargetProcess::ResumeFrozenThread(NThread& aThread)
       
   206 	{
       
   207 	for(TInt i=0; i<iFrozenThreadSemaphores.Count(); i++)
       
   208 		{
       
   209 		if(iFrozenThreadSemaphores[i]->iOwningThread == &aThread)
       
   210 			{
       
   211 			NKern::FSSignal(iFrozenThreadSemaphores[i]);
       
   212 			NKern::ThreadEnterCS();
       
   213 			delete iFrozenThreadSemaphores[i];
       
   214 			NKern::ThreadLeaveCS();
       
   215 			iFrozenThreadSemaphores.Remove(i);
       
   216 			return KErrNone;
       
   217 			}
       
   218 		}
       
   219 	return KErrNotFound;
       
   220 	}
       
   221 
       
   222 /**
       
   223   Resume the specified suspended thread
       
   224 
       
   225   @param aThread thread to resume
       
   226 
       
   227   @return KErrNone if the thread has previously been suspended and is resumed,
       
   228   KErrNotFound if the thread has not previously been suspended
       
   229   */
       
   230 TInt DTargetProcess::ResumeSuspendedThread(DThread* aThread)
       
   231 	{
       
   232 	TUint64 threadId = (TUint64)aThread->iId;
       
   233 	for(TInt i=0; i<iSuspendedThreads.Count(); i++)
       
   234 		{
       
   235 		if(iSuspendedThreads[i] == threadId)
       
   236 			{
       
   237 			iSuspendedThreads.Remove(i);
       
   238 			LOG_MSG2("DTargetProcess::ResumeSuspendedThread()> Kern::ThreadResume() 0x%08x", aThread);
       
   239 			Kern::ThreadResume(*aThread);
       
   240 			return KErrNone;
       
   241 			}
       
   242 		}
       
   243 	return KErrNotFound;
       
   244 	}
       
   245 
       
   246 /**
       
   247   Suspend the specified thread
       
   248 
       
   249   @param aThread thread to suspend
       
   250 
       
   251   @param aFreezeThread suspend the thread on a Fast Semaphore if
       
   252   ETrue. EFalse means suspend by calling Kern::Suspend.
       
   253 
       
   254   @return KErrNone if the thread is successfully suspended,
       
   255   KErrAlreadyExists if the agent has already suspended the thread,
       
   256   or one of the other system wide error codes
       
   257   
       
   258    This function suspends a thread by calling Kern::Thread Suspend.
       
   259                                                                                                        
       
   260   An alternative means of suspending the _current_ thread only
       
   261   is by call DTargetProcess::FreezeThread. This will ensure that
       
   262   the current thread is suspended when exception processing for this
       
   263   thread completes (see rm_debug_eventhandler.cpp)
       
   264   
       
   265   */
       
   266 TInt DTargetProcess::SuspendThread(DThread* aThread, TBool aFreezeThread)
       
   267 	{
       
   268 	// should check if this thread is already suspended/frozen and return if so
       
   269 	// but just warn for the moment.
       
   270 	if (CheckSuspended(aThread))
       
   271 		{
       
   272 		// thread was already suspended, don't bother doing it again
       
   273 		LOG_MSG2("DTargetProcess::SuspendThread - Thread Id 0x%08x already suspended\n",aThread->iId);
       
   274 		//return KErrAlreadyExists;	
       
   275 		}
       
   276 
       
   277 	return aFreezeThread ? FreezeThread() : DoSuspendThread(aThread);
       
   278 	}
       
   279 
       
   280 /**
       
   281   Freeze the current thread
       
   282 
       
   283   @return KErrNone if the thread is successfully suspended,
       
   284   KErrAlreadyExists if the agent has already suspended the thread,
       
   285   or one of the other system wide error codes
       
   286 
       
   287   This marks the current thread for waiting on a Fast Semaphore
       
   288   when exception handling for this thread has completed - see
       
   289   rm_debug_eventhandler.cpp for details.
       
   290   */
       
   291 TInt DTargetProcess::FreezeThread()
       
   292 	{
       
   293 	// create and store a fast semaphore to stop the thread on
       
   294 	NKern::ThreadEnterCS();
       
   295 	NFastSemaphore* sem = new NFastSemaphore();
       
   296 	NKern::ThreadLeaveCS();
       
   297 	sem->iOwningThread = &(Kern::CurrentThread().iNThread);
       
   298 	LOG_MSG3("DTargetProcess::FreezeThread(): new NFastSemaphore() owning thread==curr NThread=0x%08x, DThread=0x%08x", 
       
   299 		sem->iOwningThread, &(Kern::CurrentThread()) );
       
   300 	return iFrozenThreadSemaphores.Append(sem);
       
   301 	}
       
   302 
       
   303 /**
       
   304   Suspend the specified thread
       
   305 
       
   306   @param aThread thread to suspend
       
   307 
       
   308   @return KErrNone if the thread is successfully suspended,
       
   309   KErrAlreadyExists if the agent has already suspended the thread,
       
   310   or one of the other system wide error codes
       
   311   */
       
   312 TInt DTargetProcess::DoSuspendThread(DThread* aThread)
       
   313 	{
       
   314 	TUint64 threadId = (TUint64)aThread->iId;
       
   315 	
       
   316 	// Don't suspend if this thread is already suspended (by FSWait or
       
   317 	// Kern::ThreadSuspend
       
   318 	if (CheckSuspended(aThread))
       
   319 		{
       
   320 		// thread was already suspended, don't bother doing it again
       
   321 		LOG_MSG2("DTargetProcess::SuspendThread - Thread Id 0x%08x already suspended\n",threadId);
       
   322 		return KErrAlreadyExists;	
       
   323 		}
       
   324 
       
   325 	// Add thread to the suspend list
       
   326 	TInt err = iSuspendedThreads.Append(threadId);
       
   327 	if(err == KErrNone)
       
   328 		{
       
   329 		LOG_MSG2("DTargetProcess::DoSuspendThread >Kern::ThreadSuspend() 0x%08x", aThread ); 
       
   330 		Kern::ThreadSuspend(*aThread, 1);
       
   331 		}
       
   332 	return err;
       
   333 	}
       
   334 
       
   335 /**
       
   336  Waits the current thread on a Fast Semaphore.
       
   337 
       
   338  This is useful for situations where the current thread
       
   339  has hit a breakpoint within a critical section, and
       
   340  otherwise could not be suspended at this point.
       
   341 
       
   342  Note that the Fast Semaphore structure on which the thread
       
   343  waits must be a member data item of this class instance,
       
   344  as it needs to be FSSignal()'d by another thread to resume
       
   345  again.
       
   346  */
       
   347 void DTargetProcess::FSWait()
       
   348 	{
       
   349 	NThread* currentNThread = &(Kern::CurrentThread().iNThread);	
       
   350 	for(TInt i=0; i<iFrozenThreadSemaphores.Count(); i++)
       
   351 		{
       
   352 		if(iFrozenThreadSemaphores[i]->iOwningThread == currentNThread)
       
   353 			{
       
   354 			LOG_MSG4("DTargetProcess::FSWait(): > FSWait frozen sem %d, currentNThread=0x%08x, id=0x%x", 
       
   355 				i, currentNThread, Kern::CurrentThread().iId );
       
   356 			NKern::FSWait(iFrozenThreadSemaphores[i]);
       
   357 			return;
       
   358 			}
       
   359 		}
       
   360 	}
       
   361 
       
   362 /**
       
   363   Checks that the thread has been suspended
       
   364 
       
   365   @param aThread thread to check suspended
       
   366 
       
   367   @return ETrue if the thread has been suspended,
       
   368   EFalse if the thread has not been suspended
       
   369   */
       
   370 TBool DTargetProcess::CheckSuspended(DThread* aThread) const
       
   371 	{
       
   372 	if(!aThread)
       
   373 		{
       
   374 		return EFalse;
       
   375 		}
       
   376 	//check if the thread is in the suspended threads list
       
   377 	for(TInt i=0; i<iSuspendedThreads.Count(); i++)
       
   378 		{
       
   379 		if(iSuspendedThreads[i] == (TUint64)aThread->iId)
       
   380 			{
       
   381 			return ETrue;
       
   382 			}
       
   383 		}
       
   384 	// not in the suspended threads list so check in the frozen threads list
       
   385 	NThread* nThread = &(aThread->iNThread);
       
   386 	for(TInt i=0; i<iFrozenThreadSemaphores.Count(); i++)
       
   387 		{
       
   388 		if(iFrozenThreadSemaphores[i]->iOwningThread == nThread)
       
   389 			{
       
   390 			return ETrue;
       
   391 			}
       
   392 		}
       
   393 	return EFalse;
       
   394 	}
       
   395 
       
   396 /*
       
   397 @return ETrue if the debug driver has suspended any of the process' threads, EFalse otherwise
       
   398 */
       
   399 TBool DTargetProcess::HasSuspendedThreads() const
       
   400 	{
       
   401 	return (iSuspendedThreads.Count() > 0) || (iFrozenThreadSemaphores.Count() > 0);
       
   402 	}
       
   403 
       
   404 void DTargetProcess::NotifyEvent(const TDriverEventInfo& aEventInfo)
       
   405 	{
       
   406 	// Stuff the event info into all the tracking agents event queues
       
   407 	LOG_MSG4("DTargetProcess::NotifyEvent(): num attached agents: %d, iEventType=%d, this=0x%08x", 
       
   408 		AgentCount(), aEventInfo.iEventType, this);
       
   409 
       
   410 	for(TInt i = 0; i < AgentCount(); i++)
       
   411 		{
       
   412 		// Index through all the relevant debug agents
       
   413 		DDebugAgent* debugAgent = iAgentList[i];
       
   414 		if(debugAgent != NULL)
       
   415 			{
       
   416 			debugAgent->NotifyEvent(aEventInfo);
       
   417 			}
       
   418 		}
       
   419 	}
       
   420