Update contrib.
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 will be unique
18 // as only the Debug Security Server can load and use rm_debug.ldd.
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>
30 #include "debug_logging.h"
31 #include "d_process_tracker.h"
32 #include "debug_utils.h"
34 // Global Run-mode debugged process tracking object
35 DProcessTracker TheDProcessTracker;
38 DProcessTracker::DProcessTracker()
46 DProcessTracker::~DProcessTracker()
48 // Forget about all the iProcesses
49 iProcesses.ResetAndDestroy();
55 * Creates and stores an internal mapping of debug agent to debugged process.
56 * Note that an individual process may be mapped to a number of debug agents.
58 * @param aProcessName - The fullly qualified path of the debugged process. E.g. z:\sys\bin\hello_world.exe
59 * @param aAgentId - The process id of the debug agent which is attaching to aProcessName, as returned by RProcess.Id()
60 * @return KErrNone if there are no errors. KErrArgument if the processname is too long/short for a valid filepath.
61 * KErrNoMemory if there is insufficient memory.
63 TInt DProcessTracker::AttachProcess(const TDesC8& aProcessName,TUint64 aAgentId)
65 LOG_MSG("DProcessTracker::AttachProcess()");
68 if (aProcessName.Length() < 1 || aProcessName.Length() >= KMaxPath)
73 // Create an DTargetProcess to store
74 DTargetProcess* tmpProcess = new DTargetProcess;
82 err = tmpProcess->SetProcessName(aProcessName);
88 // Is this process being debugged (ie already attached?)
91 for(index=0;index<iProcesses.Count();index++)
93 const TPtr8& tmpPtr8(iProcesses[index]->ProcessName() );
95 if ( tmpPtr8.CompareF(aProcessName) == 0)
104 // Yes, it is being debugged
106 // Add the agent to the list of agents for this process
107 iProcesses[index]->AddAgent(aAgentId);
113 // No, it is not being debugged
115 // Add the agent to the list of agents for this process
116 tmpProcess->AddAgent(aAgentId);
118 // Add the process to the list of processes being debugged
119 return iProcesses.Insert(tmpProcess,0);
124 * @internalTechnology
126 * Removes a previously created mapping between a debug agent and a debugged process,
127 * as created by AttachProcess.
129 * @param aProcessName - The fully qualified path of the debugged process. E.g. z:\sys\bin\hello_world.exe
130 * @param aAgentId - The process id of the debug agent which is attaching to aProcessName, as returned by RProcess.Id()
131 * @return KErrNone if there are no problems. KErrArgument if the processname is too long/short for a valid filepath.
132 * KErrNotFound if the mapping does not exist (and therefore cannot be removed).
134 TInt DProcessTracker::DetachProcess(const TDesC8& aProcessName, TUint64 aAgentId)
136 // Valid ProcessName?
137 if (aProcessName.Length() < 1 || aProcessName.Length() >= KMaxPath)
142 // Are we debugging this process?
144 TBool found = EFalse;
145 DTargetProcess* foundProcess = 0;
146 for(i=0;i<iProcesses.Count();i++)
148 foundProcess = iProcesses[i];
150 const TPtr8& tmpPtr8( foundProcess->ProcessName() );
152 if ( tmpPtr8.CompareF(aProcessName) == 0)
164 // remove the agent from the process
165 iProcesses[i]->RemoveAgent(aAgentId);
167 // Found it, are there any more attached agents, or suspended threads in the process?
168 if ((iProcesses[i]->AgentCount() == 0) && !iProcesses[i]->HasSuspendedThreads() )
170 // Delete the process as no more agents are still attached
171 delete iProcesses[i];
173 // Remove the now obsolete pointer from our array.
174 iProcesses.Remove(i);
181 * @internalTechnology
183 * Detachs a debug agent from every process being debugged. Used when a debug agent is being detached
184 * from the debug security server and has not supplied a specific process name from which to detach.
186 TInt DProcessTracker::DetachAgent(const TUint64 aAgentId)
188 // Remove this agent from all the processes being tracked.
189 for(TInt i=0;i<iProcesses.Count();i++)
191 // remove the agent from the process (we don't care about the return code)
192 iProcesses[i]->RemoveAgent(aAgentId);
195 // Increment down through the array as we then don't have to worry about
196 // missing entries which have been shifted after deletes.
197 // The initial value of i correspnds to the index of the final element
199 for(TInt i = iProcesses.Count()-1; i>=0; i--)
201 if (iProcesses[i]->AgentCount() == 0)
203 // No agents remain for this process. Delete the
204 // process object and remove the pointer from the array
205 delete iProcesses[i];
206 iProcesses.Remove(i);
213 * @internalTechnology
215 * Returns a pointer to a DTargetProcess object representing the mapping of a debugged process
216 * with all the relevant debug agents interested in that process, as determined
219 * @param aProcessName - The fully qualified path of the debugged process. E.g. z:\sys\bin\hello_world.exe
220 * @return DTargetProcess* pointer to an object representing the internal mapping of a process to all associated
221 * debug agents. Returns 0 if the mapping cannot be found or the aProcessName is invalid.
223 DTargetProcess* DProcessTracker::FindProcess(const TDesC8& aProcessName)
225 // Valid ProcessName?
226 if (aProcessName.Length() < 1 || aProcessName.Length() >= KMaxPath)
228 return 0; // not found
231 // Can we find this in the array?
233 TBool found = EFalse;
234 DTargetProcess* foundProcess = 0;
235 for(i=0;i<iProcesses.Count();i++)
237 foundProcess = iProcesses[i];
239 const TPtr8& tmpPtr8( foundProcess->ProcessName() );
241 if ( tmpPtr8.CompareF(aProcessName) == 0)
250 return 0; // not found
257 * @internalTechnology
259 * Returns a pointer to a DTargetProcess object representing the mapping of a debugged process
260 * with all the relevant debug agents interested in that process, as determined
263 * Note: This does not attempt an exact match, because the AddProcess event does not provide
264 * a fully-qualified path, it provides something like [t_rmdebug_security0.exe].
266 * So for the purposes of dealing with this event, we need a "fuzzier" match which does not use the complete
269 * @param aProcessName - The fully qualified path of the debugged process. E.g. z:\sys\bin\hello_world.exe
270 * @return DTargetProcess* pointer to an object representing the internal mapping of a process to all associated
271 * debug agents. Returns 0 if the mapping cannot be found or the aProcessName is invalid.
273 DTargetProcess* DProcessTracker::FuzzyFindProcess(const TDesC8& aProcessName)
276 // Valid ProcessName?
277 if (aProcessName.Length() < 1 || aProcessName.Length() >= KMaxPath)
279 return 0; // not found
282 // Can we find this in the array?
284 TBool found = EFalse;
285 DTargetProcess* foundProcess = 0;
286 for(i=0;i<iProcesses.Count();i++)
288 foundProcess = iProcesses[i];
290 const TPtr8& tmpPtr8( foundProcess->ProcessName() );
292 if ( tmpPtr8.CompareF(aProcessName) == 0)
299 // need to compare centre of this string
302 // z:\sys\bin\foobar.exe
306 // Algorithm is start at the right side of foundProcess->ProcessName
307 // move left until we have some backslash, then finish.
308 TInt right= tmpPtr8.Size() - 1;
311 // search for the rightmost backslash
314 if(tmpPtr8[left] == (TUint8)'\\')
317 --left; // move left one character
320 // left = index of rightmost backslash in foundProcess->ProcessName()
321 // right = index of rightmost character in foundProcess->ProcessName()
323 // We must expect that the size of names matches
324 TInt foundSize = right - left; // == sizeof("foobar.exe")
325 TInt suppliedSize = aProcessName.Size();
327 if (foundSize != suppliedSize)
329 // must be something else
333 for(TInt i=0;i< foundSize;i++)
335 if (tmpPtr8[left+i] != aProcessName[1+i])
340 // All the characters match if we get here
347 return 0; // not found
353 TBool DProcessTracker::CheckSuspended(DThread* aTargetThread) const
355 //get the file name and return if NULL
356 HBuf* name = GetFileName(aTargetThread);
362 //iterate through the processes trying to match the name, and check suspended if found
363 for(TInt i=0; i<iProcesses.Count(); i++)
365 if(iProcesses[i]->ProcessName().CompareF(*name) == 0)
367 return iProcesses[i]->CheckSuspended(aTargetThread);
371 //couldn't find the process so return EFalse
375 TBool DProcessTracker::CheckSuspended(const TUint64 aTargetThreadId) const
377 //get a handle to the thread and return false if it's NULL
378 DThread* thread = DebugUtils::OpenThreadHandle(aTargetThreadId);
384 //check if the thread's suspended and then close the thread handle and return
385 TBool suspended = CheckSuspended(thread);
391 Attempts to suspend the specified thread
393 @param aTargetThread thread to suspend
395 @return KErrNone on success, KErrAlreadyExists if the thread is already suspended,
396 or one of the other system wide error codes
398 TInt DProcessTracker::SuspendThread(DThread* aTargetThread, TBool aFreezeThread)
400 LOG_MSG3("DProcessTracker::SuspendThread() Requesting suspend for: 0x%08x, freeze thread: %d", aTargetThread->iId, aFreezeThread?1:0);
402 //get the file name and return if NULL
403 HBuf* name = GetFileName(aTargetThread);
409 //iterate through the processes trying to match the name, try to suspend the thread if found
410 for(TInt i=0; i<iProcesses.Count(); i++)
412 if(iProcesses[i]->ProcessName().CompareF(*name) == 0)
414 return iProcesses[i]->SuspendThread(aTargetThread, aFreezeThread);
418 //couldn't find process so return error
419 return KErrPermissionDenied;
422 void DProcessTracker::FSWait()
424 for(TInt i=0; i<iProcesses.Count(); i++)
426 iProcesses[i]->FSWait();
431 Attempts to resume the specified thread
433 @param aTargetThread thread to resume
435 @return KErrNone on success, KErrInUse if the thread is not suspended,
436 or one of the other system wide error codes
438 TInt DProcessTracker::ResumeThread(DThread* aTargetThread)
440 LOG_MSG2("DProcessTracker::ResumeThread() Requesting resume for: 0x%08x", aTargetThread->iId);
442 //get the file name and return if NULL
443 HBuf* name = GetFileName(aTargetThread);
449 //iterate through the processes trying to match the name, try to resume the thread if found
450 for(TInt i=0; i<iProcesses.Count(); i++)
452 if(iProcesses[i]->ProcessName().CompareF(*name) == 0)
454 return iProcesses[i]->ResumeThread(aTargetThread);
458 //couldn't find process so return error
459 return KErrPermissionDenied;
463 Get a thread's originating file name
465 @param aThread the thread to get the file name for
467 @return a pointer to the thread's file name, if there are problems accessing
468 the file name then NULL will be returned
470 HBuf* DProcessTracker::GetFileName(DThread* aThread) const
472 //check if the thread is NULL and return if so
478 //get the owning process and return if it is NULL
479 DProcess* process = aThread->iOwningProcess;
485 //get the process' code seg and return if it is NULL
486 DCodeSeg* codeSeg = process->iCodeSeg;
492 //return the code seg's stored file name (which could theoretically be NULL)
493 return codeSeg->iFileName;