os/kernelhwsrv/kernel/eka/drivers/debug/rmdebug/d_process_tracker.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
// Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of the License "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
// Purpose: The DProcessTracker object tracks which processes are being
sl@0
    15
// debugged. The DProcessTracker class uses a DTargetProcess object for
sl@0
    16
// each process being debugged.
sl@0
    17
// Note: Although TheDProcessTracker object is a global, it will be unique
sl@0
    18
// as only the Debug Security Server can load and use rm_debug.ldd.
sl@0
    19
// 
sl@0
    20
//
sl@0
    21
sl@0
    22
#include <e32def.h>
sl@0
    23
#include <e32def_private.h>
sl@0
    24
#include <e32cmn.h>
sl@0
    25
#include <e32cmn_private.h>
sl@0
    26
#include <kernel/kernel.h>
sl@0
    27
#include <kernel/kern_priv.h>
sl@0
    28
sl@0
    29
#include <rm_debug_api.h>
sl@0
    30
#include "debug_logging.h"
sl@0
    31
#include "d_process_tracker.h"
sl@0
    32
#include "debug_utils.h"
sl@0
    33
sl@0
    34
// Global Run-mode debugged process tracking object
sl@0
    35
DProcessTracker TheDProcessTracker;
sl@0
    36
sl@0
    37
// ctor
sl@0
    38
DProcessTracker::DProcessTracker()
sl@0
    39
	{
sl@0
    40
	}
sl@0
    41
sl@0
    42
/**
sl@0
    43
 * dtor
sl@0
    44
 * @internalTechnology
sl@0
    45
 */
sl@0
    46
DProcessTracker::~DProcessTracker()
sl@0
    47
	{
sl@0
    48
	// Forget about all the iProcesses
sl@0
    49
	iProcesses.ResetAndDestroy();
sl@0
    50
	}
sl@0
    51
sl@0
    52
/**
sl@0
    53
 * @internalTechnology
sl@0
    54
 *
sl@0
    55
 * Creates and stores an internal mapping of debug agent to debugged process.
sl@0
    56
 * Note that an individual process may be mapped to a number of debug agents.
sl@0
    57
 *
sl@0
    58
 * @param aProcessName - The fullly qualified path of the debugged process. E.g. z:\sys\bin\hello_world.exe
sl@0
    59
 * @param aAgentId - The process id of the debug agent which is attaching to aProcessName, as returned by RProcess.Id()
sl@0
    60
 * @return KErrNone if there are no errors. KErrArgument if the processname is too long/short for a valid filepath.
sl@0
    61
 *  KErrNoMemory if there is insufficient memory.
sl@0
    62
 */
sl@0
    63
TInt DProcessTracker::AttachProcess(const TDesC8& aProcessName,TUint64 aAgentId)
sl@0
    64
	{
sl@0
    65
	LOG_MSG("DProcessTracker::AttachProcess()");
sl@0
    66
sl@0
    67
	// Valid ProcessName?
sl@0
    68
	if (aProcessName.Length() < 1 || aProcessName.Length() >= KMaxPath)
sl@0
    69
		{
sl@0
    70
		return KErrArgument;
sl@0
    71
		}
sl@0
    72
sl@0
    73
	// Create an DTargetProcess to store
sl@0
    74
	DTargetProcess* tmpProcess = new DTargetProcess;
sl@0
    75
	if (tmpProcess == 0)
sl@0
    76
		{
sl@0
    77
		return KErrNoMemory;
sl@0
    78
		}
sl@0
    79
sl@0
    80
	// Set the name
sl@0
    81
	TInt err = KErrNone;
sl@0
    82
	err = tmpProcess->SetProcessName(aProcessName);
sl@0
    83
	if (err != KErrNone)
sl@0
    84
		{
sl@0
    85
		return err;
sl@0
    86
		}
sl@0
    87
sl@0
    88
	// Is this process being debugged (ie already attached?)
sl@0
    89
	TInt index;
sl@0
    90
	TBool found = EFalse;
sl@0
    91
	for(index=0;index<iProcesses.Count();index++)
sl@0
    92
		{
sl@0
    93
		const TPtr8& tmpPtr8(iProcesses[index]->ProcessName() );
sl@0
    94
sl@0
    95
		if ( tmpPtr8.CompareF(aProcessName) == 0)
sl@0
    96
			{
sl@0
    97
			found = ETrue;
sl@0
    98
			break;
sl@0
    99
			}
sl@0
   100
		}
sl@0
   101
sl@0
   102
	if (found)
sl@0
   103
		{
sl@0
   104
		// Yes, it is being debugged
sl@0
   105
sl@0
   106
		// Add the agent to the list of agents for this process
sl@0
   107
		iProcesses[index]->AddAgent(aAgentId);
sl@0
   108
sl@0
   109
		return KErrNone;
sl@0
   110
		}
sl@0
   111
	else
sl@0
   112
		{
sl@0
   113
		// No, it is not being debugged
sl@0
   114
			
sl@0
   115
		// Add the agent to the list of agents for this process
sl@0
   116
		tmpProcess->AddAgent(aAgentId);
sl@0
   117
sl@0
   118
		// Add the process to the list of processes being debugged
sl@0
   119
		return iProcesses.Insert(tmpProcess,0);
sl@0
   120
		}
sl@0
   121
	}
sl@0
   122
sl@0
   123
/**
sl@0
   124
 * @internalTechnology
sl@0
   125
 * 
sl@0
   126
 * Removes a previously created mapping between a debug agent and a debugged process,
sl@0
   127
 * as created by AttachProcess.
sl@0
   128
 *
sl@0
   129
 * @param aProcessName - The fully qualified path of the debugged process. E.g. z:\sys\bin\hello_world.exe
sl@0
   130
 * @param aAgentId - The process id of the debug agent which is attaching to aProcessName, as returned by RProcess.Id()
sl@0
   131
 * @return KErrNone if there are no problems. KErrArgument if the processname is too long/short for a valid filepath.
sl@0
   132
 * KErrNotFound if the mapping does not exist (and therefore cannot be removed).
sl@0
   133
 */
sl@0
   134
TInt DProcessTracker::DetachProcess(const TDesC8& aProcessName, TUint64 aAgentId)
sl@0
   135
	{
sl@0
   136
	// Valid ProcessName?
sl@0
   137
	if (aProcessName.Length() < 1 || aProcessName.Length() >= KMaxPath)
sl@0
   138
		{
sl@0
   139
		return KErrArgument;
sl@0
   140
		};
sl@0
   141
sl@0
   142
	// Are we debugging this process?
sl@0
   143
	TInt i;
sl@0
   144
	TBool found = EFalse;
sl@0
   145
	DTargetProcess* foundProcess = 0;
sl@0
   146
	for(i=0;i<iProcesses.Count();i++)
sl@0
   147
		{
sl@0
   148
		foundProcess = iProcesses[i];
sl@0
   149
sl@0
   150
		const TPtr8& tmpPtr8( foundProcess->ProcessName() );
sl@0
   151
sl@0
   152
		if ( tmpPtr8.CompareF(aProcessName) == 0)
sl@0
   153
			{
sl@0
   154
			found = ETrue;
sl@0
   155
			break;
sl@0
   156
			}
sl@0
   157
		}
sl@0
   158
sl@0
   159
	if (found == EFalse)
sl@0
   160
		{
sl@0
   161
		return KErrNotFound;
sl@0
   162
		}
sl@0
   163
sl@0
   164
	// remove the agent from the process
sl@0
   165
	iProcesses[i]->RemoveAgent(aAgentId);
sl@0
   166
sl@0
   167
	// Found it, are there any more attached agents, or suspended threads in the process?
sl@0
   168
	if ((iProcesses[i]->AgentCount() == 0) && !iProcesses[i]->HasSuspendedThreads() )
sl@0
   169
		{
sl@0
   170
		// Delete the process as no more agents are still attached
sl@0
   171
		delete iProcesses[i];
sl@0
   172
sl@0
   173
		// Remove the now obsolete pointer from our array.
sl@0
   174
		iProcesses.Remove(i);
sl@0
   175
		}
sl@0
   176
sl@0
   177
	return KErrNone;
sl@0
   178
	}
sl@0
   179
sl@0
   180
/**
sl@0
   181
 * @internalTechnology
sl@0
   182
 *
sl@0
   183
 * Detachs a debug agent from every process being debugged. Used when a debug agent is being detached
sl@0
   184
 * from the debug security server and has not supplied a specific process name from which to detach.
sl@0
   185
 */
sl@0
   186
TInt DProcessTracker::DetachAgent(const TUint64 aAgentId)
sl@0
   187
	{
sl@0
   188
	// Remove this agent from all the processes being tracked.
sl@0
   189
	for(TInt i=0;i<iProcesses.Count();i++)
sl@0
   190
		{
sl@0
   191
		// remove the agent from the process (we don't care about the return code)
sl@0
   192
		iProcesses[i]->RemoveAgent(aAgentId);
sl@0
   193
		}
sl@0
   194
sl@0
   195
	// Increment down through the array as we then don't have to worry about
sl@0
   196
	// missing entries which have been shifted after deletes.
sl@0
   197
	// The initial value of i correspnds to the index of the final element 
sl@0
   198
	// in the array.
sl@0
   199
	for(TInt i = iProcesses.Count()-1; i>=0; i--)
sl@0
   200
		{
sl@0
   201
		if (iProcesses[i]->AgentCount() == 0)
sl@0
   202
			{
sl@0
   203
			// No agents remain for this process. Delete the
sl@0
   204
			// process object and remove the pointer from the array
sl@0
   205
			delete iProcesses[i];
sl@0
   206
			iProcesses.Remove(i);
sl@0
   207
			}
sl@0
   208
		}
sl@0
   209
	return KErrNone;
sl@0
   210
	}
sl@0
   211
sl@0
   212
/**
sl@0
   213
 * @internalTechnology
sl@0
   214
 *
sl@0
   215
 * Returns a pointer to a DTargetProcess object representing the mapping of a debugged process
sl@0
   216
 * with all the relevant debug agents interested in that process, as determined
sl@0
   217
 * by AttachProcess.
sl@0
   218
 *
sl@0
   219
 * @param aProcessName - The fully qualified path of the debugged process. E.g. z:\sys\bin\hello_world.exe
sl@0
   220
 * @return DTargetProcess* pointer to an object representing the internal mapping of a process to all associated
sl@0
   221
 * debug agents. Returns 0 if the mapping cannot be found or the aProcessName is invalid.
sl@0
   222
 */
sl@0
   223
DTargetProcess* DProcessTracker::FindProcess(const TDesC8& aProcessName)
sl@0
   224
	{
sl@0
   225
	// Valid ProcessName?
sl@0
   226
	if (aProcessName.Length() < 1 || aProcessName.Length() >= KMaxPath)
sl@0
   227
		{
sl@0
   228
		return 0;	// not found
sl@0
   229
		};
sl@0
   230
sl@0
   231
	// Can we find this in the array?
sl@0
   232
	TInt i;
sl@0
   233
	TBool found = EFalse;
sl@0
   234
	DTargetProcess* foundProcess = 0;
sl@0
   235
	for(i=0;i<iProcesses.Count();i++)
sl@0
   236
		{
sl@0
   237
		foundProcess = iProcesses[i];
sl@0
   238
sl@0
   239
		const TPtr8& tmpPtr8( foundProcess->ProcessName() );
sl@0
   240
sl@0
   241
		if ( tmpPtr8.CompareF(aProcessName) == 0)
sl@0
   242
			{
sl@0
   243
			found = ETrue;
sl@0
   244
			break;
sl@0
   245
			}
sl@0
   246
		}
sl@0
   247
sl@0
   248
	if (found == EFalse)
sl@0
   249
		{
sl@0
   250
		return 0;	// not found
sl@0
   251
		}
sl@0
   252
sl@0
   253
	return foundProcess;
sl@0
   254
	}
sl@0
   255
sl@0
   256
/**
sl@0
   257
 * @internalTechnology
sl@0
   258
 *
sl@0
   259
 * Returns a pointer to a DTargetProcess object representing the mapping of a debugged process
sl@0
   260
 * with all the relevant debug agents interested in that process, as determined
sl@0
   261
 * by AttachProcess.
sl@0
   262
 *
sl@0
   263
 * Note: This does not attempt an exact match, because the AddProcess event does not provide
sl@0
   264
 * a fully-qualified path, it provides something like [t_rmdebug_security0.exe].
sl@0
   265
 *
sl@0
   266
 * So for the purposes of dealing with this event, we need a "fuzzier" match which does not use the complete
sl@0
   267
 * path.
sl@0
   268
 *
sl@0
   269
 * @param aProcessName - The fully qualified path of the debugged process. E.g. z:\sys\bin\hello_world.exe
sl@0
   270
 * @return DTargetProcess* pointer to an object representing the internal mapping of a process to all associated
sl@0
   271
 * debug agents. Returns 0 if the mapping cannot be found or the aProcessName is invalid.
sl@0
   272
 */
sl@0
   273
DTargetProcess*	DProcessTracker::FuzzyFindProcess(const TDesC8& aProcessName)
sl@0
   274
	{
sl@0
   275
sl@0
   276
	// Valid ProcessName?
sl@0
   277
	if (aProcessName.Length() < 1 || aProcessName.Length() >= KMaxPath)
sl@0
   278
		{
sl@0
   279
		return 0;	// not found
sl@0
   280
		};
sl@0
   281
sl@0
   282
	// Can we find this in the array?
sl@0
   283
	TInt i;
sl@0
   284
	TBool found = EFalse;
sl@0
   285
	DTargetProcess* foundProcess = 0;
sl@0
   286
	for(i=0;i<iProcesses.Count();i++)
sl@0
   287
		{
sl@0
   288
		foundProcess = iProcesses[i];
sl@0
   289
sl@0
   290
		const TPtr8& tmpPtr8( foundProcess->ProcessName() );
sl@0
   291
sl@0
   292
		if ( tmpPtr8.CompareF(aProcessName) == 0)
sl@0
   293
			{
sl@0
   294
			found = ETrue;
sl@0
   295
			break;
sl@0
   296
			}
sl@0
   297
		else
sl@0
   298
			{
sl@0
   299
			// need to compare centre of this string
sl@0
   300
			//
sl@0
   301
			// e.g. 
sl@0
   302
			//		z:\sys\bin\foobar.exe
sl@0
   303
			// might be seen as:
sl@0
   304
			//		foobar.exe
sl@0
   305
			//
sl@0
   306
			// Algorithm is start at the right side of foundProcess->ProcessName
sl@0
   307
			// move left until we have some backslash, then finish.
sl@0
   308
			TInt right= tmpPtr8.Size() - 1;
sl@0
   309
			TInt left = right;
sl@0
   310
sl@0
   311
			// search for the rightmost backslash
sl@0
   312
			while(left > 0)
sl@0
   313
				{
sl@0
   314
				if(tmpPtr8[left] == (TUint8)'\\')
sl@0
   315
					break;
sl@0
   316
				
sl@0
   317
				--left;	// move left one character
sl@0
   318
				}
sl@0
   319
			// now we have
sl@0
   320
			// left = index of rightmost backslash in foundProcess->ProcessName()
sl@0
   321
			// right = index of rightmost character in foundProcess->ProcessName()
sl@0
   322
sl@0
   323
			// We must expect that the size of names matches
sl@0
   324
			TInt foundSize = right - left;	// == sizeof("foobar.exe")
sl@0
   325
			TInt suppliedSize = aProcessName.Size();		
sl@0
   326
sl@0
   327
			if (foundSize != suppliedSize)
sl@0
   328
				{
sl@0
   329
				// must be something else
sl@0
   330
				break;
sl@0
   331
				}
sl@0
   332
sl@0
   333
			for(TInt i=0;i< foundSize;i++)
sl@0
   334
				{
sl@0
   335
				if (tmpPtr8[left+i] != aProcessName[1+i])
sl@0
   336
					{
sl@0
   337
					break;
sl@0
   338
					}
sl@0
   339
				}
sl@0
   340
			// All the characters match if we get here
sl@0
   341
			found = ETrue;
sl@0
   342
			}
sl@0
   343
		}
sl@0
   344
sl@0
   345
	if (found == EFalse)
sl@0
   346
		{
sl@0
   347
		return 0;	// not found
sl@0
   348
		}
sl@0
   349
sl@0
   350
	return foundProcess;
sl@0
   351
	}
sl@0
   352
sl@0
   353
TBool DProcessTracker::CheckSuspended(DThread* aTargetThread) const
sl@0
   354
	{
sl@0
   355
	//get the file name and return if NULL
sl@0
   356
	HBuf* name = GetFileName(aTargetThread);
sl@0
   357
	if(!name)
sl@0
   358
		{
sl@0
   359
		return EFalse;
sl@0
   360
		}
sl@0
   361
sl@0
   362
	//iterate through the processes trying to match the name, and check suspended if found
sl@0
   363
	for(TInt i=0; i<iProcesses.Count(); i++)
sl@0
   364
		{
sl@0
   365
		if(iProcesses[i]->ProcessName().CompareF(*name) == 0)
sl@0
   366
			{
sl@0
   367
			return iProcesses[i]->CheckSuspended(aTargetThread);
sl@0
   368
			}
sl@0
   369
		}
sl@0
   370
sl@0
   371
	//couldn't find the process so return EFalse
sl@0
   372
	return EFalse;
sl@0
   373
	}
sl@0
   374
sl@0
   375
TBool DProcessTracker::CheckSuspended(const TUint64 aTargetThreadId) const
sl@0
   376
	{
sl@0
   377
	//get a handle to the thread and return false if it's NULL
sl@0
   378
	DThread* thread = DebugUtils::OpenThreadHandle(aTargetThreadId);
sl@0
   379
	if(!thread)
sl@0
   380
		{
sl@0
   381
		return EFalse;
sl@0
   382
		}
sl@0
   383
sl@0
   384
	//check if the thread's suspended and then close the thread handle and return
sl@0
   385
	TBool suspended = CheckSuspended(thread);
sl@0
   386
	thread->Close(NULL);
sl@0
   387
	return suspended;
sl@0
   388
	}
sl@0
   389
sl@0
   390
/**
sl@0
   391
  Attempts to suspend the specified thread
sl@0
   392
sl@0
   393
  @param aTargetThread thread to suspend
sl@0
   394
sl@0
   395
  @return KErrNone on success, KErrAlreadyExists if the thread is already suspended,
sl@0
   396
  or one of the other system wide error codes
sl@0
   397
  */
sl@0
   398
TInt DProcessTracker::SuspendThread(DThread* aTargetThread, TBool aFreezeThread)
sl@0
   399
	{
sl@0
   400
	LOG_MSG3("DProcessTracker::SuspendThread() Requesting suspend for: 0x%08x, freeze thread: %d", aTargetThread->iId, aFreezeThread?1:0);
sl@0
   401
sl@0
   402
	//get the file name and return if NULL
sl@0
   403
	HBuf* name = GetFileName(aTargetThread);
sl@0
   404
	if(!name)
sl@0
   405
		{
sl@0
   406
		return KErrNotFound;
sl@0
   407
		}
sl@0
   408
sl@0
   409
	//iterate through the processes trying to match the name, try to suspend the thread if found
sl@0
   410
	for(TInt i=0; i<iProcesses.Count(); i++)
sl@0
   411
		{
sl@0
   412
		if(iProcesses[i]->ProcessName().CompareF(*name) == 0)
sl@0
   413
			{
sl@0
   414
			return iProcesses[i]->SuspendThread(aTargetThread, aFreezeThread);
sl@0
   415
			}
sl@0
   416
		}
sl@0
   417
sl@0
   418
	//couldn't find process so return error
sl@0
   419
	return KErrPermissionDenied;
sl@0
   420
	}
sl@0
   421
sl@0
   422
void DProcessTracker::FSWait()
sl@0
   423
	{
sl@0
   424
	for(TInt i=0; i<iProcesses.Count(); i++)
sl@0
   425
		{
sl@0
   426
		iProcesses[i]->FSWait();
sl@0
   427
		}
sl@0
   428
	}
sl@0
   429
sl@0
   430
/**
sl@0
   431
  Attempts to resume the specified thread
sl@0
   432
sl@0
   433
  @param aTargetThread thread to resume
sl@0
   434
sl@0
   435
  @return KErrNone on success, KErrInUse if the thread is not suspended,
sl@0
   436
  or one of the other system wide error codes
sl@0
   437
  */
sl@0
   438
TInt DProcessTracker::ResumeThread(DThread* aTargetThread)
sl@0
   439
	{
sl@0
   440
	LOG_MSG2("DProcessTracker::ResumeThread() Requesting resume for: 0x%08x", aTargetThread->iId);
sl@0
   441
sl@0
   442
	//get the file name and return if NULL
sl@0
   443
	HBuf* name = GetFileName(aTargetThread);
sl@0
   444
	if(!name)
sl@0
   445
		{
sl@0
   446
		return KErrNotFound;
sl@0
   447
		}
sl@0
   448
sl@0
   449
	//iterate through the processes trying to match the name, try to resume the thread if found
sl@0
   450
	for(TInt i=0; i<iProcesses.Count(); i++)
sl@0
   451
		{
sl@0
   452
		if(iProcesses[i]->ProcessName().CompareF(*name) == 0)
sl@0
   453
			{
sl@0
   454
			return iProcesses[i]->ResumeThread(aTargetThread);
sl@0
   455
			}
sl@0
   456
		}
sl@0
   457
sl@0
   458
	//couldn't find process so return error
sl@0
   459
	return KErrPermissionDenied;
sl@0
   460
	}
sl@0
   461
sl@0
   462
/**
sl@0
   463
  Get a thread's originating file name
sl@0
   464
sl@0
   465
  @param aThread the thread to get the file name for
sl@0
   466
sl@0
   467
  @return a pointer to the thread's file name, if there are problems accessing
sl@0
   468
  the file name then NULL will be returned
sl@0
   469
  */
sl@0
   470
HBuf* DProcessTracker::GetFileName(DThread* aThread) const
sl@0
   471
	{
sl@0
   472
	//check if the thread is NULL and return if so
sl@0
   473
	if(!aThread)
sl@0
   474
		{
sl@0
   475
		return NULL;
sl@0
   476
		}
sl@0
   477
sl@0
   478
	//get the owning process and return if it is NULL
sl@0
   479
	DProcess* process = aThread->iOwningProcess;
sl@0
   480
	if(!process)
sl@0
   481
		{
sl@0
   482
		return NULL;
sl@0
   483
		}
sl@0
   484
sl@0
   485
	//get the process' code seg and return if it is NULL
sl@0
   486
	DCodeSeg* codeSeg = process->iCodeSeg;
sl@0
   487
	if(!codeSeg)
sl@0
   488
		{
sl@0
   489
		return NULL;
sl@0
   490
		}
sl@0
   491
sl@0
   492
	//return the code seg's stored file name (which could theoretically be NULL)
sl@0
   493
	return codeSeg->iFileName;
sl@0
   494
	}
sl@0
   495