1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kernel/eka/drivers/debug/rmdebug/d_process_tracker.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,495 @@
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: The DProcessTracker object tracks which processes are being
1.18 +// debugged. The DProcessTracker class uses a DTargetProcess object for
1.19 +// each process being debugged.
1.20 +// Note: Although TheDProcessTracker object is a global, it will be unique
1.21 +// as only the Debug Security Server can load and use rm_debug.ldd.
1.22 +//
1.23 +//
1.24 +
1.25 +#include <e32def.h>
1.26 +#include <e32def_private.h>
1.27 +#include <e32cmn.h>
1.28 +#include <e32cmn_private.h>
1.29 +#include <kernel/kernel.h>
1.30 +#include <kernel/kern_priv.h>
1.31 +
1.32 +#include <rm_debug_api.h>
1.33 +#include "debug_logging.h"
1.34 +#include "d_process_tracker.h"
1.35 +#include "debug_utils.h"
1.36 +
1.37 +// Global Run-mode debugged process tracking object
1.38 +DProcessTracker TheDProcessTracker;
1.39 +
1.40 +// ctor
1.41 +DProcessTracker::DProcessTracker()
1.42 + {
1.43 + }
1.44 +
1.45 +/**
1.46 + * dtor
1.47 + * @internalTechnology
1.48 + */
1.49 +DProcessTracker::~DProcessTracker()
1.50 + {
1.51 + // Forget about all the iProcesses
1.52 + iProcesses.ResetAndDestroy();
1.53 + }
1.54 +
1.55 +/**
1.56 + * @internalTechnology
1.57 + *
1.58 + * Creates and stores an internal mapping of debug agent to debugged process.
1.59 + * Note that an individual process may be mapped to a number of debug agents.
1.60 + *
1.61 + * @param aProcessName - The fullly qualified path of the debugged process. E.g. z:\sys\bin\hello_world.exe
1.62 + * @param aAgentId - The process id of the debug agent which is attaching to aProcessName, as returned by RProcess.Id()
1.63 + * @return KErrNone if there are no errors. KErrArgument if the processname is too long/short for a valid filepath.
1.64 + * KErrNoMemory if there is insufficient memory.
1.65 + */
1.66 +TInt DProcessTracker::AttachProcess(const TDesC8& aProcessName,TUint64 aAgentId)
1.67 + {
1.68 + LOG_MSG("DProcessTracker::AttachProcess()");
1.69 +
1.70 + // Valid ProcessName?
1.71 + if (aProcessName.Length() < 1 || aProcessName.Length() >= KMaxPath)
1.72 + {
1.73 + return KErrArgument;
1.74 + }
1.75 +
1.76 + // Create an DTargetProcess to store
1.77 + DTargetProcess* tmpProcess = new DTargetProcess;
1.78 + if (tmpProcess == 0)
1.79 + {
1.80 + return KErrNoMemory;
1.81 + }
1.82 +
1.83 + // Set the name
1.84 + TInt err = KErrNone;
1.85 + err = tmpProcess->SetProcessName(aProcessName);
1.86 + if (err != KErrNone)
1.87 + {
1.88 + return err;
1.89 + }
1.90 +
1.91 + // Is this process being debugged (ie already attached?)
1.92 + TInt index;
1.93 + TBool found = EFalse;
1.94 + for(index=0;index<iProcesses.Count();index++)
1.95 + {
1.96 + const TPtr8& tmpPtr8(iProcesses[index]->ProcessName() );
1.97 +
1.98 + if ( tmpPtr8.CompareF(aProcessName) == 0)
1.99 + {
1.100 + found = ETrue;
1.101 + break;
1.102 + }
1.103 + }
1.104 +
1.105 + if (found)
1.106 + {
1.107 + // Yes, it is being debugged
1.108 +
1.109 + // Add the agent to the list of agents for this process
1.110 + iProcesses[index]->AddAgent(aAgentId);
1.111 +
1.112 + return KErrNone;
1.113 + }
1.114 + else
1.115 + {
1.116 + // No, it is not being debugged
1.117 +
1.118 + // Add the agent to the list of agents for this process
1.119 + tmpProcess->AddAgent(aAgentId);
1.120 +
1.121 + // Add the process to the list of processes being debugged
1.122 + return iProcesses.Insert(tmpProcess,0);
1.123 + }
1.124 + }
1.125 +
1.126 +/**
1.127 + * @internalTechnology
1.128 + *
1.129 + * Removes a previously created mapping between a debug agent and a debugged process,
1.130 + * as created by AttachProcess.
1.131 + *
1.132 + * @param aProcessName - The fully qualified path of the debugged process. E.g. z:\sys\bin\hello_world.exe
1.133 + * @param aAgentId - The process id of the debug agent which is attaching to aProcessName, as returned by RProcess.Id()
1.134 + * @return KErrNone if there are no problems. KErrArgument if the processname is too long/short for a valid filepath.
1.135 + * KErrNotFound if the mapping does not exist (and therefore cannot be removed).
1.136 + */
1.137 +TInt DProcessTracker::DetachProcess(const TDesC8& aProcessName, TUint64 aAgentId)
1.138 + {
1.139 + // Valid ProcessName?
1.140 + if (aProcessName.Length() < 1 || aProcessName.Length() >= KMaxPath)
1.141 + {
1.142 + return KErrArgument;
1.143 + };
1.144 +
1.145 + // Are we debugging this process?
1.146 + TInt i;
1.147 + TBool found = EFalse;
1.148 + DTargetProcess* foundProcess = 0;
1.149 + for(i=0;i<iProcesses.Count();i++)
1.150 + {
1.151 + foundProcess = iProcesses[i];
1.152 +
1.153 + const TPtr8& tmpPtr8( foundProcess->ProcessName() );
1.154 +
1.155 + if ( tmpPtr8.CompareF(aProcessName) == 0)
1.156 + {
1.157 + found = ETrue;
1.158 + break;
1.159 + }
1.160 + }
1.161 +
1.162 + if (found == EFalse)
1.163 + {
1.164 + return KErrNotFound;
1.165 + }
1.166 +
1.167 + // remove the agent from the process
1.168 + iProcesses[i]->RemoveAgent(aAgentId);
1.169 +
1.170 + // Found it, are there any more attached agents, or suspended threads in the process?
1.171 + if ((iProcesses[i]->AgentCount() == 0) && !iProcesses[i]->HasSuspendedThreads() )
1.172 + {
1.173 + // Delete the process as no more agents are still attached
1.174 + delete iProcesses[i];
1.175 +
1.176 + // Remove the now obsolete pointer from our array.
1.177 + iProcesses.Remove(i);
1.178 + }
1.179 +
1.180 + return KErrNone;
1.181 + }
1.182 +
1.183 +/**
1.184 + * @internalTechnology
1.185 + *
1.186 + * Detachs a debug agent from every process being debugged. Used when a debug agent is being detached
1.187 + * from the debug security server and has not supplied a specific process name from which to detach.
1.188 + */
1.189 +TInt DProcessTracker::DetachAgent(const TUint64 aAgentId)
1.190 + {
1.191 + // Remove this agent from all the processes being tracked.
1.192 + for(TInt i=0;i<iProcesses.Count();i++)
1.193 + {
1.194 + // remove the agent from the process (we don't care about the return code)
1.195 + iProcesses[i]->RemoveAgent(aAgentId);
1.196 + }
1.197 +
1.198 + // Increment down through the array as we then don't have to worry about
1.199 + // missing entries which have been shifted after deletes.
1.200 + // The initial value of i correspnds to the index of the final element
1.201 + // in the array.
1.202 + for(TInt i = iProcesses.Count()-1; i>=0; i--)
1.203 + {
1.204 + if (iProcesses[i]->AgentCount() == 0)
1.205 + {
1.206 + // No agents remain for this process. Delete the
1.207 + // process object and remove the pointer from the array
1.208 + delete iProcesses[i];
1.209 + iProcesses.Remove(i);
1.210 + }
1.211 + }
1.212 + return KErrNone;
1.213 + }
1.214 +
1.215 +/**
1.216 + * @internalTechnology
1.217 + *
1.218 + * Returns a pointer to a DTargetProcess object representing the mapping of a debugged process
1.219 + * with all the relevant debug agents interested in that process, as determined
1.220 + * by AttachProcess.
1.221 + *
1.222 + * @param aProcessName - The fully qualified path of the debugged process. E.g. z:\sys\bin\hello_world.exe
1.223 + * @return DTargetProcess* pointer to an object representing the internal mapping of a process to all associated
1.224 + * debug agents. Returns 0 if the mapping cannot be found or the aProcessName is invalid.
1.225 + */
1.226 +DTargetProcess* DProcessTracker::FindProcess(const TDesC8& aProcessName)
1.227 + {
1.228 + // Valid ProcessName?
1.229 + if (aProcessName.Length() < 1 || aProcessName.Length() >= KMaxPath)
1.230 + {
1.231 + return 0; // not found
1.232 + };
1.233 +
1.234 + // Can we find this in the array?
1.235 + TInt i;
1.236 + TBool found = EFalse;
1.237 + DTargetProcess* foundProcess = 0;
1.238 + for(i=0;i<iProcesses.Count();i++)
1.239 + {
1.240 + foundProcess = iProcesses[i];
1.241 +
1.242 + const TPtr8& tmpPtr8( foundProcess->ProcessName() );
1.243 +
1.244 + if ( tmpPtr8.CompareF(aProcessName) == 0)
1.245 + {
1.246 + found = ETrue;
1.247 + break;
1.248 + }
1.249 + }
1.250 +
1.251 + if (found == EFalse)
1.252 + {
1.253 + return 0; // not found
1.254 + }
1.255 +
1.256 + return foundProcess;
1.257 + }
1.258 +
1.259 +/**
1.260 + * @internalTechnology
1.261 + *
1.262 + * Returns a pointer to a DTargetProcess object representing the mapping of a debugged process
1.263 + * with all the relevant debug agents interested in that process, as determined
1.264 + * by AttachProcess.
1.265 + *
1.266 + * Note: This does not attempt an exact match, because the AddProcess event does not provide
1.267 + * a fully-qualified path, it provides something like [t_rmdebug_security0.exe].
1.268 + *
1.269 + * So for the purposes of dealing with this event, we need a "fuzzier" match which does not use the complete
1.270 + * path.
1.271 + *
1.272 + * @param aProcessName - The fully qualified path of the debugged process. E.g. z:\sys\bin\hello_world.exe
1.273 + * @return DTargetProcess* pointer to an object representing the internal mapping of a process to all associated
1.274 + * debug agents. Returns 0 if the mapping cannot be found or the aProcessName is invalid.
1.275 + */
1.276 +DTargetProcess* DProcessTracker::FuzzyFindProcess(const TDesC8& aProcessName)
1.277 + {
1.278 +
1.279 + // Valid ProcessName?
1.280 + if (aProcessName.Length() < 1 || aProcessName.Length() >= KMaxPath)
1.281 + {
1.282 + return 0; // not found
1.283 + };
1.284 +
1.285 + // Can we find this in the array?
1.286 + TInt i;
1.287 + TBool found = EFalse;
1.288 + DTargetProcess* foundProcess = 0;
1.289 + for(i=0;i<iProcesses.Count();i++)
1.290 + {
1.291 + foundProcess = iProcesses[i];
1.292 +
1.293 + const TPtr8& tmpPtr8( foundProcess->ProcessName() );
1.294 +
1.295 + if ( tmpPtr8.CompareF(aProcessName) == 0)
1.296 + {
1.297 + found = ETrue;
1.298 + break;
1.299 + }
1.300 + else
1.301 + {
1.302 + // need to compare centre of this string
1.303 + //
1.304 + // e.g.
1.305 + // z:\sys\bin\foobar.exe
1.306 + // might be seen as:
1.307 + // foobar.exe
1.308 + //
1.309 + // Algorithm is start at the right side of foundProcess->ProcessName
1.310 + // move left until we have some backslash, then finish.
1.311 + TInt right= tmpPtr8.Size() - 1;
1.312 + TInt left = right;
1.313 +
1.314 + // search for the rightmost backslash
1.315 + while(left > 0)
1.316 + {
1.317 + if(tmpPtr8[left] == (TUint8)'\\')
1.318 + break;
1.319 +
1.320 + --left; // move left one character
1.321 + }
1.322 + // now we have
1.323 + // left = index of rightmost backslash in foundProcess->ProcessName()
1.324 + // right = index of rightmost character in foundProcess->ProcessName()
1.325 +
1.326 + // We must expect that the size of names matches
1.327 + TInt foundSize = right - left; // == sizeof("foobar.exe")
1.328 + TInt suppliedSize = aProcessName.Size();
1.329 +
1.330 + if (foundSize != suppliedSize)
1.331 + {
1.332 + // must be something else
1.333 + break;
1.334 + }
1.335 +
1.336 + for(TInt i=0;i< foundSize;i++)
1.337 + {
1.338 + if (tmpPtr8[left+i] != aProcessName[1+i])
1.339 + {
1.340 + break;
1.341 + }
1.342 + }
1.343 + // All the characters match if we get here
1.344 + found = ETrue;
1.345 + }
1.346 + }
1.347 +
1.348 + if (found == EFalse)
1.349 + {
1.350 + return 0; // not found
1.351 + }
1.352 +
1.353 + return foundProcess;
1.354 + }
1.355 +
1.356 +TBool DProcessTracker::CheckSuspended(DThread* aTargetThread) const
1.357 + {
1.358 + //get the file name and return if NULL
1.359 + HBuf* name = GetFileName(aTargetThread);
1.360 + if(!name)
1.361 + {
1.362 + return EFalse;
1.363 + }
1.364 +
1.365 + //iterate through the processes trying to match the name, and check suspended if found
1.366 + for(TInt i=0; i<iProcesses.Count(); i++)
1.367 + {
1.368 + if(iProcesses[i]->ProcessName().CompareF(*name) == 0)
1.369 + {
1.370 + return iProcesses[i]->CheckSuspended(aTargetThread);
1.371 + }
1.372 + }
1.373 +
1.374 + //couldn't find the process so return EFalse
1.375 + return EFalse;
1.376 + }
1.377 +
1.378 +TBool DProcessTracker::CheckSuspended(const TUint64 aTargetThreadId) const
1.379 + {
1.380 + //get a handle to the thread and return false if it's NULL
1.381 + DThread* thread = DebugUtils::OpenThreadHandle(aTargetThreadId);
1.382 + if(!thread)
1.383 + {
1.384 + return EFalse;
1.385 + }
1.386 +
1.387 + //check if the thread's suspended and then close the thread handle and return
1.388 + TBool suspended = CheckSuspended(thread);
1.389 + thread->Close(NULL);
1.390 + return suspended;
1.391 + }
1.392 +
1.393 +/**
1.394 + Attempts to suspend the specified thread
1.395 +
1.396 + @param aTargetThread thread to suspend
1.397 +
1.398 + @return KErrNone on success, KErrAlreadyExists if the thread is already suspended,
1.399 + or one of the other system wide error codes
1.400 + */
1.401 +TInt DProcessTracker::SuspendThread(DThread* aTargetThread, TBool aFreezeThread)
1.402 + {
1.403 + LOG_MSG3("DProcessTracker::SuspendThread() Requesting suspend for: 0x%08x, freeze thread: %d", aTargetThread->iId, aFreezeThread?1:0);
1.404 +
1.405 + //get the file name and return if NULL
1.406 + HBuf* name = GetFileName(aTargetThread);
1.407 + if(!name)
1.408 + {
1.409 + return KErrNotFound;
1.410 + }
1.411 +
1.412 + //iterate through the processes trying to match the name, try to suspend the thread if found
1.413 + for(TInt i=0; i<iProcesses.Count(); i++)
1.414 + {
1.415 + if(iProcesses[i]->ProcessName().CompareF(*name) == 0)
1.416 + {
1.417 + return iProcesses[i]->SuspendThread(aTargetThread, aFreezeThread);
1.418 + }
1.419 + }
1.420 +
1.421 + //couldn't find process so return error
1.422 + return KErrPermissionDenied;
1.423 + }
1.424 +
1.425 +void DProcessTracker::FSWait()
1.426 + {
1.427 + for(TInt i=0; i<iProcesses.Count(); i++)
1.428 + {
1.429 + iProcesses[i]->FSWait();
1.430 + }
1.431 + }
1.432 +
1.433 +/**
1.434 + Attempts to resume the specified thread
1.435 +
1.436 + @param aTargetThread thread to resume
1.437 +
1.438 + @return KErrNone on success, KErrInUse if the thread is not suspended,
1.439 + or one of the other system wide error codes
1.440 + */
1.441 +TInt DProcessTracker::ResumeThread(DThread* aTargetThread)
1.442 + {
1.443 + LOG_MSG2("DProcessTracker::ResumeThread() Requesting resume for: 0x%08x", aTargetThread->iId);
1.444 +
1.445 + //get the file name and return if NULL
1.446 + HBuf* name = GetFileName(aTargetThread);
1.447 + if(!name)
1.448 + {
1.449 + return KErrNotFound;
1.450 + }
1.451 +
1.452 + //iterate through the processes trying to match the name, try to resume the thread if found
1.453 + for(TInt i=0; i<iProcesses.Count(); i++)
1.454 + {
1.455 + if(iProcesses[i]->ProcessName().CompareF(*name) == 0)
1.456 + {
1.457 + return iProcesses[i]->ResumeThread(aTargetThread);
1.458 + }
1.459 + }
1.460 +
1.461 + //couldn't find process so return error
1.462 + return KErrPermissionDenied;
1.463 + }
1.464 +
1.465 +/**
1.466 + Get a thread's originating file name
1.467 +
1.468 + @param aThread the thread to get the file name for
1.469 +
1.470 + @return a pointer to the thread's file name, if there are problems accessing
1.471 + the file name then NULL will be returned
1.472 + */
1.473 +HBuf* DProcessTracker::GetFileName(DThread* aThread) const
1.474 + {
1.475 + //check if the thread is NULL and return if so
1.476 + if(!aThread)
1.477 + {
1.478 + return NULL;
1.479 + }
1.480 +
1.481 + //get the owning process and return if it is NULL
1.482 + DProcess* process = aThread->iOwningProcess;
1.483 + if(!process)
1.484 + {
1.485 + return NULL;
1.486 + }
1.487 +
1.488 + //get the process' code seg and return if it is NULL
1.489 + DCodeSeg* codeSeg = process->iCodeSeg;
1.490 + if(!codeSeg)
1.491 + {
1.492 + return NULL;
1.493 + }
1.494 +
1.495 + //return the code seg's stored file name (which could theoretically be NULL)
1.496 + return codeSeg->iFileName;
1.497 + }
1.498 +