os/kernelhwsrv/kerneltest/e32utils/d_exc/minkda.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) 2002-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
// e32utils\d_exc\minkda.cpp
sl@0
    15
// Example of LDD implementing a minimal kernel-side debug agent.
sl@0
    16
// 
sl@0
    17
//
sl@0
    18
sl@0
    19
#include <kernel/kern_priv.h>
sl@0
    20
#ifdef __MARM__
sl@0
    21
#include <arm.h>
sl@0
    22
#endif
sl@0
    23
#include "minkda.h"
sl@0
    24
sl@0
    25
// Uncomment following lines to enable traces in UREL builds
sl@0
    26
//#undef __KTRACE_OPT
sl@0
    27
//#define __KTRACE_OPT(c,b) b
sl@0
    28
sl@0
    29
#ifdef _DEBUG
sl@0
    30
// Panic category used for internal errors
sl@0
    31
static const char KFault[] = "MINKDA-ERROR, line:";
sl@0
    32
#endif
sl@0
    33
sl@0
    34
// Panic category and codes used when detecting programming error in
sl@0
    35
// user-side clients.
sl@0
    36
_LIT(KClientPanic, "MINKDA");
sl@0
    37
enum TPanic
sl@0
    38
	{
sl@0
    39
	EPanicTrapWhileRequestPending,
sl@0
    40
	EPanicNoCrashedThread,
sl@0
    41
	EPanicUnsupportedRequest,
sl@0
    42
	};
sl@0
    43
sl@0
    44
// As this LDD allows to bypass platform security, we need to restrict
sl@0
    45
// access to a few trusted clients.
sl@0
    46
const TUint32 KDexecSid = 0x101F7770;
sl@0
    47
sl@0
    48
//////////////////////////////////////////////////////////////////////////////
sl@0
    49
sl@0
    50
//
sl@0
    51
// Callback invoked on thread panic/exception and associated state.
sl@0
    52
//
sl@0
    53
sl@0
    54
class DCrashHandler : public DKernelEventHandler
sl@0
    55
	{
sl@0
    56
public:
sl@0
    57
	// construction & destruction
sl@0
    58
	inline DCrashHandler();
sl@0
    59
	TInt Create(DLogicalDevice* aDevice);
sl@0
    60
	~DCrashHandler();
sl@0
    61
public:
sl@0
    62
	void Trap(TRequestStatus* aRs, TAny* aCrashInfo);
sl@0
    63
	void CancelTrap();
sl@0
    64
	void KillCrashedThread();
sl@0
    65
private:
sl@0
    66
	static TUint EventHandler(TKernelEvent aEvent, TAny* a1, TAny* a2, TAny* aThis);
sl@0
    67
	void HandleCrash(TAny* aContext);
sl@0
    68
	void GetCpuExcInfo(const TAny* aContext, TDbgCpuExcInfo& aInfo);
sl@0
    69
private:
sl@0
    70
	DMutex* iHandlerMutex;		// serialise access to crash handler
sl@0
    71
	NFastSemaphore iSuspendSem; // for suspending crashed thread
sl@0
    72
	DMutex* iDataMutex;			// serialise access to following members
sl@0
    73
	DThread* iClient;			// client to signal on crash or NULL
sl@0
    74
	TRequestStatus* iTrapRq;	// signalled on crash (NULL if none)
sl@0
    75
	TAny* iCrashInfo;			// user-side buffer filled when crash trapped
sl@0
    76
	DThread* iCrashedThread;	// thread which took exception (NULL if none)
sl@0
    77
	DLogicalDevice* iDevice;	// open reference to LDD for avoiding lifetime issues
sl@0
    78
	};
sl@0
    79
sl@0
    80
inline DCrashHandler::DCrashHandler()
sl@0
    81
	: DKernelEventHandler(EventHandler, this)
sl@0
    82
	{
sl@0
    83
	}
sl@0
    84
sl@0
    85
//
sl@0
    86
// second-phase c'tor.  Called in thread critical section.
sl@0
    87
//
sl@0
    88
sl@0
    89
TInt DCrashHandler::Create(DLogicalDevice* aDevice)
sl@0
    90
	{
sl@0
    91
	TInt r;
sl@0
    92
	r = aDevice->Open();
sl@0
    93
	if (r != KErrNone)
sl@0
    94
		return r;
sl@0
    95
	iDevice = aDevice;
sl@0
    96
	_LIT(KHandlerMutexName, "CtHandlerMutex");
sl@0
    97
	r = Kern::MutexCreate(iHandlerMutex, KHandlerMutexName, KMutexOrdDebug);
sl@0
    98
	if (r != KErrNone)
sl@0
    99
		return r;
sl@0
   100
	_LIT(KDataMutexName, "CtDataMutex");
sl@0
   101
	r = Kern::MutexCreate(iDataMutex, KDataMutexName, KMutexOrdDebug-1);
sl@0
   102
	if (r != KErrNone)
sl@0
   103
		return r;
sl@0
   104
	return Add();
sl@0
   105
	}
sl@0
   106
sl@0
   107
sl@0
   108
//
sl@0
   109
// Called when reference count reaches zero.  At that point no threads
sl@0
   110
// are in the handler anymore and the handler has been removed from
sl@0
   111
// the queue.
sl@0
   112
//
sl@0
   113
sl@0
   114
DCrashHandler::~DCrashHandler()
sl@0
   115
	{
sl@0
   116
	__KTRACE_OPT(KDEBUGGER, Kern::Printf("DCrashHandler::~DCrashHandler"));
sl@0
   117
	if (iDataMutex)
sl@0
   118
		iDataMutex->Close(NULL);
sl@0
   119
	if (iHandlerMutex)
sl@0
   120
		iHandlerMutex->Close(NULL);
sl@0
   121
	if (iDevice)
sl@0
   122
		iDevice->Close(NULL);
sl@0
   123
	}
sl@0
   124
sl@0
   125
inline TBool TookException(const DThread* aThread)
sl@0
   126
	{
sl@0
   127
    return aThread->iExitType == EExitPanic && 
sl@0
   128
			aThread->iExitReason == ECausedException && 
sl@0
   129
			aThread->iExitCategory == KLitKernExec;
sl@0
   130
	}
sl@0
   131
sl@0
   132
//
sl@0
   133
// Called by kernel when various kinds of events occur.  In thread critical
sl@0
   134
// section.
sl@0
   135
//
sl@0
   136
sl@0
   137
TUint DCrashHandler::EventHandler(TKernelEvent aEvent, TAny* a1, TAny* /*a2*/, TAny* aThis)
sl@0
   138
	{
sl@0
   139
	DThread* pC = &Kern::CurrentThread();
sl@0
   140
	switch (aEvent)
sl@0
   141
		{
sl@0
   142
	case EEventHwExc:
sl@0
   143
		((DCrashHandler*)aThis)->HandleCrash(a1);
sl@0
   144
		break;
sl@0
   145
	case EEventKillThread:
sl@0
   146
		if (pC->iExitType == EExitPanic && ! TookException(pC))
sl@0
   147
			((DCrashHandler*)aThis)->HandleCrash(NULL);
sl@0
   148
		break;
sl@0
   149
	default:
sl@0
   150
		// ignore other events
sl@0
   151
		break;
sl@0
   152
		}
sl@0
   153
	return ERunNext;
sl@0
   154
	}
sl@0
   155
sl@0
   156
//
sl@0
   157
// Called when an exception or panic occurs in context of thread which
sl@0
   158
// took the exception/panicked.  In thread critical section.
sl@0
   159
//
sl@0
   160
sl@0
   161
void DCrashHandler::HandleCrash(TAny* aContext)
sl@0
   162
	{
sl@0
   163
	DThread* pC = &Kern::CurrentThread();
sl@0
   164
	__KTRACE_OPT(KDEBUGGER, Kern::Printf("HandleCrash context=0x%08X thread=%O", aContext, pC));
sl@0
   165
sl@0
   166
	// Quick exit if crashed thread is debugger (i.e. client thread
sl@0
   167
	// which issued trap request).
sl@0
   168
	if (pC == iClient)
sl@0
   169
		{
sl@0
   170
		__KTRACE_OPT(KDEBUGGER, Kern::Printf("ignoring debugger crash"));
sl@0
   171
		return;
sl@0
   172
		}
sl@0
   173
sl@0
   174
	// Set realtime state to off to allow us to write to possibly paged debugger thread.  This is
sl@0
   175
	// reasonable as this thread has already crashed.
sl@0
   176
	Kern::SetRealtimeState(ERealtimeStateOff);
sl@0
   177
sl@0
   178
	// Ensure that, at any time, at most one thread executes the following
sl@0
   179
	// code.  This simplifies user-side API.
sl@0
   180
	Kern::MutexWait(*iHandlerMutex);
sl@0
   181
	__ASSERT_DEBUG(iCrashedThread == NULL, Kern::Fault(KFault, __LINE__));
sl@0
   182
sl@0
   183
	// If there is a pending trap request, store basic information
sl@0
   184
	// about the panic/exception in user-supplied buffer and
sl@0
   185
	// freeze the crashed thread so it can be inspected.
sl@0
   186
sl@0
   187
	Kern::MutexWait(*iDataMutex);
sl@0
   188
	if (iTrapRq != NULL)
sl@0
   189
		{
sl@0
   190
		iCrashedThread = pC;
sl@0
   191
		iSuspendSem.iOwningThread = &(iCrashedThread->iNThread);
sl@0
   192
sl@0
   193
		TDbgCrashInfo info;
sl@0
   194
		info.iTid = iCrashedThread->iId;
sl@0
   195
		if (aContext)
sl@0
   196
			{
sl@0
   197
			GetCpuExcInfo(aContext, info.iCpu);
sl@0
   198
			info.iType = TDbgCrashInfo::EException;
sl@0
   199
			}
sl@0
   200
		else
sl@0
   201
			info.iType = TDbgCrashInfo::EPanic;
sl@0
   202
		TInt r = Kern::ThreadRawWrite(iClient, iCrashInfo, &info, sizeof(info));
sl@0
   203
		Kern::RequestComplete(iClient, iTrapRq, r);
sl@0
   204
		iClient = NULL;
sl@0
   205
		}
sl@0
   206
	Kern::MutexSignal(*iDataMutex);
sl@0
   207
sl@0
   208
	if (iCrashedThread)
sl@0
   209
		{
sl@0
   210
		__KTRACE_OPT(KDEBUGGER, Kern::Printf("freezing crashed thread"));
sl@0
   211
		NKern::FSWait(&(iSuspendSem));
sl@0
   212
		__KTRACE_OPT(KDEBUGGER, Kern::Printf("resuming crashed thread"));
sl@0
   213
		Kern::MutexWait(*iDataMutex);
sl@0
   214
		// Must protect in case a cancel executes concurrently.
sl@0
   215
		iCrashedThread = NULL;
sl@0
   216
		Kern::MutexSignal(*iDataMutex);
sl@0
   217
		}
sl@0
   218
sl@0
   219
	Kern::MutexSignal(*iHandlerMutex);
sl@0
   220
	}
sl@0
   221
sl@0
   222
sl@0
   223
void DCrashHandler::Trap(TRequestStatus* aRs, TAny* aCrashInfo)
sl@0
   224
	{
sl@0
   225
	if (iTrapRq != NULL)
sl@0
   226
		Kern::PanicCurrentThread(KClientPanic, EPanicTrapWhileRequestPending);
sl@0
   227
	NKern::ThreadEnterCS();
sl@0
   228
	Kern::MutexWait(*iDataMutex);
sl@0
   229
	iClient = &Kern::CurrentThread();
sl@0
   230
	iCrashInfo = aCrashInfo;
sl@0
   231
	iTrapRq = aRs;
sl@0
   232
	Kern::MutexSignal(*iDataMutex);
sl@0
   233
	NKern::ThreadLeaveCS();
sl@0
   234
	}
sl@0
   235
sl@0
   236
sl@0
   237
void DCrashHandler::CancelTrap()
sl@0
   238
	{
sl@0
   239
	__KTRACE_OPT(KDEBUGGER, Kern::Printf(">DCrashHandler::CancelTrap"));
sl@0
   240
	NKern::ThreadEnterCS();
sl@0
   241
	Kern::MutexWait(*iDataMutex);
sl@0
   242
sl@0
   243
	__KTRACE_OPT(KDEBUGGER, Kern::Printf("cancel request (0x%08X)", iTrapRq));
sl@0
   244
	Kern::RequestComplete(iClient, iTrapRq, KErrCancel);
sl@0
   245
	iClient = NULL;
sl@0
   246
sl@0
   247
	if (iCrashedThread != NULL)
sl@0
   248
		{
sl@0
   249
		__KTRACE_OPT(KDEBUGGER, Kern::Printf("resume crashed thread"));
sl@0
   250
		NKern::FSSignal(&(iSuspendSem));
sl@0
   251
		}
sl@0
   252
sl@0
   253
	Kern::MutexSignal(*iDataMutex);
sl@0
   254
	NKern::ThreadLeaveCS();
sl@0
   255
	__KTRACE_OPT(KDEBUGGER, Kern::Printf("<DCrashHandler::CancelTrap"));
sl@0
   256
	}
sl@0
   257
sl@0
   258
sl@0
   259
void DCrashHandler::KillCrashedThread()
sl@0
   260
	{
sl@0
   261
	if (iCrashedThread == NULL)
sl@0
   262
		Kern::PanicCurrentThread(KClientPanic, EPanicNoCrashedThread);
sl@0
   263
	NKern::FSSignal(&iSuspendSem);
sl@0
   264
	}
sl@0
   265
sl@0
   266
sl@0
   267
void DCrashHandler::GetCpuExcInfo(const TAny* aContext, TDbgCpuExcInfo& aInfo)
sl@0
   268
	{
sl@0
   269
#if defined(__MARM__)
sl@0
   270
	const TArmExcInfo* pE = (const TArmExcInfo*)aContext;
sl@0
   271
	aInfo.iFaultPc = pE->iR15;
sl@0
   272
	aInfo.iFaultAddress = pE->iFaultAddress;
sl@0
   273
	aInfo.iFaultStatus = pE->iFaultStatus;
sl@0
   274
	aInfo.iExcCode = (TDbgCpuExcInfo::TExcCode)pE->iExcCode;
sl@0
   275
	aInfo.iR13Svc = pE->iR13Svc;
sl@0
   276
	aInfo.iR14Svc = pE->iR14Svc;
sl@0
   277
	aInfo.iSpsrSvc = pE->iSpsrSvc;
sl@0
   278
#else
sl@0
   279
	(void) aContext; // silence warnings
sl@0
   280
	(void) aInfo;
sl@0
   281
#endif
sl@0
   282
	}
sl@0
   283
sl@0
   284
//////////////////////////////////////////////////////////////////////////////
sl@0
   285
sl@0
   286
//
sl@0
   287
// Channel initialisation and cleanup.  Dispatcher for user-side
sl@0
   288
// requests.  Crash-related requests are forwarded to DCrashHandler,
sl@0
   289
// others are implemented here.
sl@0
   290
//
sl@0
   291
sl@0
   292
class DKdaChannel : public DLogicalChannelBase
sl@0
   293
	{
sl@0
   294
public:
sl@0
   295
	~DKdaChannel();
sl@0
   296
protected:
sl@0
   297
	// from DLogicalChannelBase
sl@0
   298
	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion &aVer);
sl@0
   299
	virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2);
sl@0
   300
private:
sl@0
   301
	TInt ReadMem(RMinKda::TReadMemParams* aParams);
sl@0
   302
	TInt GetThreadInfo(TUint aTid, TAny* aInfo);
sl@0
   303
	void GetThreadCpuInfo(DThread* aThread, TDbgRegSet& aInfo);
sl@0
   304
	TInt GetCodeSegs(RMinKda::TCodeSnapshotParams* aParams);
sl@0
   305
	TInt GetCodeSegInfo(RMinKda::TCodeInfoParams* aParams);
sl@0
   306
	TInt OpenTempObject(TUint aId, TObjectType aType);
sl@0
   307
	void CloseTempObject();
sl@0
   308
private:
sl@0
   309
	DCrashHandler* iCrashHandler;
sl@0
   310
	DObject* iTempObj;			// automagically closed if abnormal termination
sl@0
   311
	};
sl@0
   312
sl@0
   313
sl@0
   314
//
sl@0
   315
// Called when user-side thread create new channel with LDD.  Called
sl@0
   316
// in context of that thread, in thread critical section.
sl@0
   317
//
sl@0
   318
sl@0
   319
TInt DKdaChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion &aVer)
sl@0
   320
	{
sl@0
   321
	if (Kern::CurrentThread().iOwningProcess->iS.iSecureId != KDexecSid)
sl@0
   322
		return KErrPermissionDenied;
sl@0
   323
	if (! Kern::QueryVersionSupported(KKdaLddVersion(), aVer))
sl@0
   324
		return KErrNotSupported;
sl@0
   325
sl@0
   326
	iCrashHandler = new DCrashHandler;
sl@0
   327
	if (iCrashHandler == NULL)
sl@0
   328
		return KErrNoMemory;
sl@0
   329
	return iCrashHandler->Create(iDevice);
sl@0
   330
	}
sl@0
   331
sl@0
   332
sl@0
   333
//
sl@0
   334
// Called when last reference to channel is closed, in context of
sl@0
   335
// closing thread, in thread critical section.
sl@0
   336
//
sl@0
   337
sl@0
   338
DKdaChannel::~DKdaChannel()
sl@0
   339
	{
sl@0
   340
	__KTRACE_OPT(KDEBUGGER, Kern::Printf("DKdaChannel::~DKdaChannel"));
sl@0
   341
	Kern::SafeClose(iTempObj, NULL);
sl@0
   342
	if (iCrashHandler)
sl@0
   343
		{
sl@0
   344
		iCrashHandler->CancelTrap();
sl@0
   345
		iCrashHandler->Close();
sl@0
   346
		}
sl@0
   347
	}
sl@0
   348
sl@0
   349
sl@0
   350
//
sl@0
   351
// Request dispatcher. Called in context of requesting thread.
sl@0
   352
//
sl@0
   353
sl@0
   354
TInt DKdaChannel::Request(TInt aFunction, TAny* a1, TAny* a2)
sl@0
   355
	{
sl@0
   356
	__KTRACE_OPT(KDEBUGGER, Kern::Printf(">DKdaChannel::Request function=%d a1=0x%08X a2=0x%08X", aFunction, a1, a2));
sl@0
   357
	
sl@0
   358
	TInt r = KErrNone;
sl@0
   359
	switch (aFunction)
sl@0
   360
		{
sl@0
   361
	case RMinKda::ETrap:
sl@0
   362
		iCrashHandler->Trap((TRequestStatus*)a1, a2);
sl@0
   363
		break;
sl@0
   364
	case RMinKda::ECancelTrap:
sl@0
   365
		iCrashHandler->CancelTrap();
sl@0
   366
		break;
sl@0
   367
	case RMinKda::EKillCrashedThread:
sl@0
   368
		iCrashHandler->KillCrashedThread();
sl@0
   369
		break;
sl@0
   370
	case RMinKda::EGetThreadInfo:
sl@0
   371
		r = GetThreadInfo((TUint)a1, a2);
sl@0
   372
		break;
sl@0
   373
	case RMinKda::EReadMem:
sl@0
   374
		r = ReadMem((RMinKda::TReadMemParams*)a1);
sl@0
   375
		break;
sl@0
   376
	case RMinKda::EGetCodeSegs:
sl@0
   377
		r = GetCodeSegs((RMinKda::TCodeSnapshotParams*)a1);
sl@0
   378
		break;
sl@0
   379
	case RMinKda::EGetCodeSegInfo:
sl@0
   380
		r = GetCodeSegInfo((RMinKda::TCodeInfoParams*)a1);
sl@0
   381
		break;
sl@0
   382
	default:
sl@0
   383
		Kern::PanicCurrentThread(KClientPanic, EPanicUnsupportedRequest);
sl@0
   384
		break;
sl@0
   385
		}
sl@0
   386
sl@0
   387
	__KTRACE_OPT(KDEBUGGER, Kern::Printf("<DKdaChannel::Request r=%d", r));
sl@0
   388
	return r;
sl@0
   389
	}
sl@0
   390
sl@0
   391
sl@0
   392
TInt DKdaChannel::ReadMem(RMinKda::TReadMemParams* aParams)
sl@0
   393
	{
sl@0
   394
	RMinKda::TReadMemParams params;
sl@0
   395
	umemget32(&params, aParams, sizeof(params));
sl@0
   396
sl@0
   397
	TInt destLen;
sl@0
   398
	TInt destMax;
sl@0
   399
	TUint8* destPtr = (TUint8*)Kern::KUDesInfo(*params.iDes, destLen, destMax);
sl@0
   400
sl@0
   401
	TInt r = OpenTempObject(params.iTid, EThread);
sl@0
   402
	if (r == KErrNone)
sl@0
   403
		{
sl@0
   404
		r = Kern::ThreadRawRead((DThread*)iTempObj, (TAny*)params.iAddr, destPtr, destMax);
sl@0
   405
sl@0
   406
		if (r == KErrNone)
sl@0
   407
			Kern::KUDesSetLength(*params.iDes, destMax);
sl@0
   408
sl@0
   409
		CloseTempObject();
sl@0
   410
		}
sl@0
   411
sl@0
   412
	return r;
sl@0
   413
	}
sl@0
   414
sl@0
   415
sl@0
   416
TInt DKdaChannel::GetThreadInfo(TUint aTid, TAny* aInfo)
sl@0
   417
	{
sl@0
   418
	TInt r = OpenTempObject(aTid, EThread);
sl@0
   419
	if (r == KErrNone)
sl@0
   420
		{
sl@0
   421
		DThread* pT = (DThread*)iTempObj;
sl@0
   422
		TDbgThreadInfo info;
sl@0
   423
		pT->FullName(info.iFullName);
sl@0
   424
		info.iPid = pT->iOwningProcess->iId;
sl@0
   425
		info.iStackBase = pT->iUserStackRunAddress;
sl@0
   426
		info.iStackSize = pT->iUserStackSize;
sl@0
   427
		info.iExitCategory = pT->iExitCategory;
sl@0
   428
		info.iExitReason = pT->iExitReason;
sl@0
   429
		GetThreadCpuInfo(pT, info.iCpu);
sl@0
   430
		umemput32(aInfo, &info, sizeof(info));
sl@0
   431
		CloseTempObject();
sl@0
   432
		}
sl@0
   433
	return r;
sl@0
   434
	}
sl@0
   435
sl@0
   436
// :FIXME: improve API
sl@0
   437
TInt DKdaChannel::GetCodeSegs(RMinKda::TCodeSnapshotParams* aParams)
sl@0
   438
	{
sl@0
   439
	RMinKda::TCodeSnapshotParams params;
sl@0
   440
	umemget32(&params, aParams, sizeof(params));
sl@0
   441
sl@0
   442
	TInt maxcount;
sl@0
   443
	umemget32(&maxcount, params.iCountPtr, sizeof(maxcount));
sl@0
   444
sl@0
   445
	__KTRACE_OPT(KDEBUGGER, Kern::Printf(">DKdaChannel::GetCodeSegs pid=%d maxcount=%d", params.iPid, maxcount));
sl@0
   446
	
sl@0
   447
	__ASSERT_DEBUG(! iTempObj, Kern::Fault(KFault, __LINE__));
sl@0
   448
	TInt r = OpenTempObject(params.iPid, EProcess);
sl@0
   449
	if (r != KErrNone)
sl@0
   450
		{
sl@0
   451
		__KTRACE_OPT(KDEBUGGER, Kern::Printf("<DKdaChannel::GetCodeSegs process not found"));
sl@0
   452
		return r;
sl@0
   453
		}
sl@0
   454
		
sl@0
   455
	DProcess* pP = (DProcess*)iTempObj;
sl@0
   456
sl@0
   457
	Kern::AccessCode();
sl@0
   458
sl@0
   459
	SDblQue q;
sl@0
   460
	TInt actcount = pP->TraverseCodeSegs(&q, NULL, DCodeSeg::EMarkDebug, DProcess::ETraverseFlagAdd);
sl@0
   461
sl@0
   462
	CloseTempObject();
sl@0
   463
sl@0
   464
	TInt n = Min(actcount, maxcount);
sl@0
   465
	SDblQueLink* pL = q.iA.iNext;
sl@0
   466
	r = KErrNone;
sl@0
   467
	for (TInt i=0; i<n; ++i, pL = pL->iNext)
sl@0
   468
		{
sl@0
   469
		DCodeSeg* pS = _LOFF(pL, DCodeSeg, iTempLink);
sl@0
   470
		XTRAP(r, XT_DEFAULT, umemput32(params.iHandles + i, &pS, sizeof(TAny*)));
sl@0
   471
		if (r != KErrNone)
sl@0
   472
			break;
sl@0
   473
		}
sl@0
   474
sl@0
   475
	DCodeSeg::EmptyQueue(q, DCodeSeg::EMarkDebug);
sl@0
   476
sl@0
   477
	Kern::EndAccessCode();
sl@0
   478
sl@0
   479
	if (r == KErrBadDescriptor)
sl@0
   480
		Kern::PanicCurrentThread(KLitKernExec, ECausedException);
sl@0
   481
	umemput32(params.iCountPtr, &actcount, sizeof(actcount));
sl@0
   482
sl@0
   483
	__KTRACE_OPT(KDEBUGGER, Kern::Printf("<DKdaChannel::GetCodeSegs actcount=%d", actcount));
sl@0
   484
	return r;
sl@0
   485
	}
sl@0
   486
sl@0
   487
sl@0
   488
// :FIXME: improve API
sl@0
   489
TInt DKdaChannel::GetCodeSegInfo(RMinKda::TCodeInfoParams* aParams)
sl@0
   490
	{
sl@0
   491
	RMinKda::TCodeInfoParams params;
sl@0
   492
	umemget32(&params, aParams, sizeof(params));
sl@0
   493
sl@0
   494
	// :FIXME: Currently code segments are always loaded at the same
sl@0
   495
	// location in every address space.  Consequently we can ignore
sl@0
   496
	// the PID provided by the client.
sl@0
   497
	DProcess* pP = NULL;
sl@0
   498
sl@0
   499
	TInt r = KErrNotFound;
sl@0
   500
	TFileName	nameBuffer;
sl@0
   501
	nameBuffer.Zero();
sl@0
   502
	Kern::AccessCode();
sl@0
   503
	DCodeSeg* pS = DCodeSeg::VerifyHandle(params.iHandle);
sl@0
   504
	if (pS)
sl@0
   505
		{
sl@0
   506
		TModuleMemoryInfo mmi;
sl@0
   507
		r = pS->GetMemoryInfo(mmi, pP);
sl@0
   508
		if (r == KErrNone)
sl@0
   509
			{
sl@0
   510
			params.iCodeBase = mmi.iCodeBase;
sl@0
   511
			params.iCodeSize = mmi.iCodeSize;
sl@0
   512
			XTRAP(r, XT_DEFAULT, nameBuffer.Append(*(pS->iFileName)));
sl@0
   513
			}
sl@0
   514
		}
sl@0
   515
	Kern::EndAccessCode();
sl@0
   516
	Kern::KUDesPut(*(params.iPathPtr), nameBuffer);
sl@0
   517
	if (r == KErrBadDescriptor)
sl@0
   518
		Kern::PanicCurrentThread(KLitKernExec, ECausedException);
sl@0
   519
sl@0
   520
	if (r == KErrNone)
sl@0
   521
		umemput32(aParams, &params, sizeof(params));
sl@0
   522
sl@0
   523
	return r;
sl@0
   524
	}
sl@0
   525
sl@0
   526
//
sl@0
   527
// Lookup a thread or process id and open the corresponding object.
sl@0
   528
//
sl@0
   529
// The object is stored in DKdaChannel::iTempObj to ensure it will be
sl@0
   530
// closed even if the client thread terminates unexpectedly.  The
sl@0
   531
// caller must call CloseTempObject() when it is finished with it.
sl@0
   532
//
sl@0
   533
sl@0
   534
TInt DKdaChannel::OpenTempObject(TUint aId, TObjectType aType)
sl@0
   535
	{
sl@0
   536
	__ASSERT_DEBUG(aType == EProcess || aType == EThread, Kern::Fault(KFault, __LINE__));
sl@0
   537
	__ASSERT_DEBUG(! iTempObj, Kern::Fault(KFault, __LINE__));
sl@0
   538
sl@0
   539
	DObjectCon* pC = Kern::Containers()[aType];
sl@0
   540
	NKern::ThreadEnterCS();
sl@0
   541
	pC->Wait();
sl@0
   542
	DObject* tempObj = (aType == EProcess) ? (DObject*)Kern::ProcessFromId(aId) : (DObject*)Kern::ThreadFromId(aId);
sl@0
   543
	NKern::LockSystem();
sl@0
   544
	iTempObj = tempObj;
sl@0
   545
	TInt r = KErrNotFound;
sl@0
   546
	if (iTempObj)
sl@0
   547
		r = iTempObj->Open();
sl@0
   548
sl@0
   549
	NKern::UnlockSystem();
sl@0
   550
	pC->Signal();
sl@0
   551
	NKern::ThreadLeaveCS();
sl@0
   552
	return r;
sl@0
   553
	}
sl@0
   554
sl@0
   555
void DKdaChannel::CloseTempObject()
sl@0
   556
	{
sl@0
   557
	__ASSERT_DEBUG(iTempObj, Kern::Fault(KFault, __LINE__));
sl@0
   558
	NKern::ThreadEnterCS();
sl@0
   559
	iTempObj->Close(NULL);
sl@0
   560
	iTempObj = NULL;
sl@0
   561
	NKern::ThreadLeaveCS();
sl@0
   562
	}
sl@0
   563
sl@0
   564
#ifdef __MARM__
sl@0
   565
sl@0
   566
void DKdaChannel::GetThreadCpuInfo(DThread* aThread, TDbgRegSet& aInfo)
sl@0
   567
	{
sl@0
   568
	__ASSERT_DEBUG(aThread != &Kern::CurrentThread(), Kern::Fault(KFault, __LINE__));
sl@0
   569
sl@0
   570
	TArmRegSet regSet;
sl@0
   571
	TUint32 unused;
sl@0
   572
	NKern::ThreadGetUserContext(&(aThread->iNThread), &regSet, unused);
sl@0
   573
	aInfo.iRn[0] = regSet.iR0;
sl@0
   574
	aInfo.iRn[1] = regSet.iR1;
sl@0
   575
	aInfo.iRn[2] = regSet.iR2;
sl@0
   576
	aInfo.iRn[3] = regSet.iR3;
sl@0
   577
	aInfo.iRn[4] = regSet.iR4;
sl@0
   578
	aInfo.iRn[5] = regSet.iR5;
sl@0
   579
	aInfo.iRn[6] = regSet.iR6;
sl@0
   580
	aInfo.iRn[7] = regSet.iR7;
sl@0
   581
	aInfo.iRn[8] = regSet.iR8;
sl@0
   582
	aInfo.iRn[9] = regSet.iR9;
sl@0
   583
	aInfo.iRn[10] = regSet.iR10;
sl@0
   584
	aInfo.iRn[11] = regSet.iR11;
sl@0
   585
	aInfo.iRn[12] = regSet.iR12;
sl@0
   586
	aInfo.iRn[13] = regSet.iR13;
sl@0
   587
	aInfo.iRn[14] = regSet.iR14;
sl@0
   588
	aInfo.iRn[15] = regSet.iR15;
sl@0
   589
	aInfo.iCpsr = regSet.iFlags;
sl@0
   590
	}
sl@0
   591
sl@0
   592
#else
sl@0
   593
sl@0
   594
void DKdaChannel::GetThreadCpuInfo(DThread* /*aThread*/, TDbgRegSet& /*aInfo*/)
sl@0
   595
	{
sl@0
   596
	}
sl@0
   597
sl@0
   598
#endif
sl@0
   599
sl@0
   600
sl@0
   601
//////////////////////////////////////////////////////////////////////////////
sl@0
   602
sl@0
   603
class DCtDevice : public DLogicalDevice
sl@0
   604
	{
sl@0
   605
public:
sl@0
   606
	DCtDevice();
sl@0
   607
	// from DLogicalDevice
sl@0
   608
	virtual TInt Install();
sl@0
   609
	virtual void GetCaps(TDes8& aDes) const;
sl@0
   610
	virtual TInt Create(DLogicalChannelBase*& aChannel);
sl@0
   611
	};
sl@0
   612
sl@0
   613
DCtDevice::DCtDevice()
sl@0
   614
	{
sl@0
   615
	// iParseMask = 0;
sl@0
   616
	// iUnitsMask = 0;
sl@0
   617
	iVersion = KKdaLddVersion();
sl@0
   618
	}
sl@0
   619
sl@0
   620
TInt DCtDevice::Install()
sl@0
   621
	{
sl@0
   622
	return SetName(&KKdaLddName);
sl@0
   623
	}
sl@0
   624
sl@0
   625
void DCtDevice::GetCaps(TDes8& /*aDes*/) const
sl@0
   626
	{
sl@0
   627
	}
sl@0
   628
sl@0
   629
TInt DCtDevice::Create(DLogicalChannelBase*& aChannel)
sl@0
   630
	{
sl@0
   631
	aChannel = new DKdaChannel;
sl@0
   632
	return (aChannel != NULL) ? KErrNone : KErrNoMemory;
sl@0
   633
	}
sl@0
   634
sl@0
   635
//////////////////////////////////////////////////////////////////////////////
sl@0
   636
sl@0
   637
DECLARE_STANDARD_LDD()
sl@0
   638
	{
sl@0
   639
	return new DCtDevice;
sl@0
   640
	}
sl@0
   641