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