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".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
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.
23 #include <e32def_private.h>
25 #include <e32cmn_private.h>
26 #include <kernel/kernel.h>
27 #include <kernel/kern_priv.h>
29 #include <rm_debug_api.h>
31 #include "d_target_process.h"
32 #include "debug_logging.h"
33 #include "debug_utils.h"
36 DTargetProcess::DTargetProcess()
42 DTargetProcess::~DTargetProcess()
44 // Delete the space allocated for the name if any
45 if (iProcessName.Ptr() != 0)
47 NKern::ThreadEnterCS();
48 Kern::Free((TAny*)iProcessName.Ptr());
49 NKern::ThreadLeaveCS();
51 //Reset the array and delete the objects that its members point to
52 NKern::ThreadEnterCS();
53 iAgentList.ResetAndDestroy();
54 NKern::ThreadLeaveCS();
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)
60 return aFirst.iProcessName.Compare(aSecond.iProcessName);
63 // Set the name of the process we are tracking
64 TInt DTargetProcess::SetProcessName(const TDesC8& aProcessName)
67 if (aProcessName.Length() < 1)
72 // Allocate some memory to store the name
73 TUint length = aProcessName.Length();
75 NKern::ThreadEnterCS();
76 TUint8* buffer = (TUint8*)Kern::AllocZ(length);
77 NKern::ThreadLeaveCS();
84 // Set iProcessName to use the alloc'd buffer
85 iProcessName.Set(buffer,length,length);
87 // Store aProcessName within this object
88 iProcessName.Copy(aProcessName);
93 // Obtain the name of the process being tracked
94 const TPtr8& DTargetProcess::ProcessName(void)
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)
103 for(TInt i = 0; i < iAgentList.Count(); i++)
105 if (iAgentList[i]->Id() == aAgentId)
107 return iAgentList[i];
111 // what do we return if we don't have any agents?
115 // Adds aAgentId as a tracking agent for this process.
116 TInt DTargetProcess::AddAgent(TUint64 aAgentId)
118 LOG_MSG("DTargetProcess::AddAgent()");
119 DDebugAgent* agent = DDebugAgent::New(aAgentId);
122 LOG_MSG("DTargetProcess::AddAgent() couldn't allocate memory for DDebugAgent");
125 return iAgentList.Insert(agent,0);
128 // Stops tracking the process with this agent
129 TInt DTargetProcess::RemoveAgent(TUint64 aAgentId)
131 // We need to find and then remove the agent
132 for(TUint i = 0; i < iAgentList.Count(); i++)
134 if (iAgentList[i]->Id() == aAgentId)
136 delete iAgentList[i];
137 iAgentList.Remove(i);
145 // Index through the agents by position
146 DDebugAgent* DTargetProcess::operator[](TInt aIndex)
148 return iAgentList[aIndex];
151 // returns the number of agents tracking this process.
152 TInt DTargetProcess::AgentCount(void)
154 return iAgentList.Count();
158 Resume the specified thread
160 @param aThread thread to resume
162 @return KErrNone if the thread has previously been suspended and is resumed,
163 KErrNotFound if the thread has not previously been suspended
165 TInt DTargetProcess::ResumeThread(DThread* aThread)
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))
175 LOG_MSG2("DTargetProcess::ResumeThread() unexpected exit, err1: %d", err1);
178 //if resuming the frozen thread failed for an obscure reason return it
179 if((err2 != KErrNotFound) && (err2 != KErrNone))
181 LOG_MSG2("DTargetProcess::ResumeThread() unexpected exit, err2: %d", err2);
184 // if resuming the suspended thread succeeded in both cases, we have a consistency problem
185 if ((err1 == KErrNone) && (err2 == KErrNone))
187 LOG_MSG("DTargetProcess::ResumeThread() unexpected exit, err1 == err2 == KErrNone");
190 //if the thread was in neither list return KErrNotFound, otherwise KErrNone
191 return ((err1 == KErrNone) || (err2 == KErrNone)) ? KErrNone : KErrNotFound;
195 Resume the specified frozen thread
197 @param aThread thread to resume
199 @return KErrNone if the thread has previously been suspended and is resumed,
200 KErrNotFound if the thread has not previously been suspended
202 TInt DTargetProcess::ResumeFrozenThread(NThread& aThread)
204 for(TInt i=0; i<iFrozenThreadSemaphores.Count(); i++)
206 if(iFrozenThreadSemaphores[i]->iOwningThread == &aThread)
208 NKern::FSSignal(iFrozenThreadSemaphores[i]);
209 NKern::ThreadEnterCS();
210 delete iFrozenThreadSemaphores[i];
211 NKern::ThreadLeaveCS();
212 iFrozenThreadSemaphores.Remove(i);
220 Resume the specified suspended thread
222 @param aThread thread to resume
224 @return KErrNone if the thread has previously been suspended and is resumed,
225 KErrNotFound if the thread has not previously been suspended
227 TInt DTargetProcess::ResumeSuspendedThread(DThread* aThread)
229 TUint64 threadId = (TUint64)aThread->iId;
230 for(TInt i=0; i<iSuspendedThreads.Count(); i++)
232 if(iSuspendedThreads[i] == threadId)
234 iSuspendedThreads.Remove(i);
235 LOG_MSG2("DTargetProcess::ResumeSuspendedThread()> Kern::ThreadResume() 0x%x", aThread);
236 Kern::ThreadResume(*aThread);
244 Suspend the specified thread
246 @param aThread thread to suspend
248 @param aFreezeThread suspend the thread on a Fast Semaphore if
249 ETrue. EFalse means suspend by calling Kern::Suspend.
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
255 This function suspends a thread by calling Kern::Thread Suspend.
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)
263 TInt DTargetProcess::SuspendThread(DThread* aThread, TBool aFreezeThread)
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))
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;
274 return aFreezeThread ? FreezeThread() : DoSuspendThread(aThread);
278 Freeze the current thread
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
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.
288 TInt DTargetProcess::FreezeThread()
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);
300 Suspend the specified thread
302 @param aThread thread to suspend
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
308 TInt DTargetProcess::DoSuspendThread(DThread* aThread)
310 TUint64 threadId = (TUint64)aThread->iId;
312 // Don't suspend if this thread is already suspended (by FSWait or
313 // Kern::ThreadSuspend
314 if (CheckSuspended(aThread))
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;
321 // Add thread to the suspend list
322 TInt err = iSuspendedThreads.Append(threadId);
325 Kern::ThreadSuspend(*aThread, 1);
331 Waits the current thread on a Fast Semaphore.
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.
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
342 void DTargetProcess::FSWait()
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++)
348 if(iFrozenThreadSemaphores[i]->iOwningThread == currentThread)
350 LOG_MSG3("DTargetProcess::FSWait(): > FSWait frozen sem %d, curr thread=0x%x", i, currentThread);
351 NKern::FSWait(iFrozenThreadSemaphores[i]);
358 Checks that the thread has been suspended
360 @param aThread thread to check suspended
362 @return ETrue if the thread has been suspended,
363 EFalse if the thread has not been suspended
365 TBool DTargetProcess::CheckSuspended(DThread* aThread) const
371 //check if the thread is in the suspended threads list
372 for(TInt i=0; i<iSuspendedThreads.Count(); i++)
374 if(iSuspendedThreads[i] == (TUint64)aThread->iId)
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++)
383 if(iFrozenThreadSemaphores[i]->iOwningThread == nThread)
392 @return ETrue if the debug driver has suspended any of the process' threads, EFalse otherwise
394 TBool DTargetProcess::HasSuspendedThreads() const
396 return (iSuspendedThreads.Count() > 0) || (iFrozenThreadSemaphores.Count() > 0);
399 void DTargetProcess::NotifyEvent(const TDriverEventInfo& aEventInfo)
401 // Stuff the event info into all the tracking agents event queues
402 LOG_MSG2("DTargetProcess::NotifyEvent(): number of attached agents: %d", AgentCount());
404 for(TInt i = 0; i < AgentCount(); i++)
406 // Index through all the relevant debug agents
407 DDebugAgent* debugAgent = iAgentList[i];
408 if(debugAgent != NULL)
410 debugAgent->NotifyEvent(aEventInfo);