Update contrib.
1 // Copyright (c) 2003-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 // e32test\debug\d_context.cpp
15 // Test LDD exercising hardware/software exception hooks
16 // and get/set user context APIs.
21 #include <kernel/kern_priv.h>
22 #include "kern_test.h"
23 #include "d_context.h"
25 _LIT(KClientPanicCat, "D_CONTEXT");
27 extern TUint32 SpinInKernel(TBool);
29 DThread* ThreadFromId(TUint aId)
31 // This is risky because the thread could die on us an the DThread* become invalid.
32 // We are relying on this never happening in our test code.
33 NKern::ThreadEnterCS();
34 DObjectCon& threads=*Kern::Containers()[EThread];
36 DThread* thread = Kern::ThreadFromId(aId);
38 NKern::ThreadLeaveCS();
42 void ModifyContext(TArmRegSet& aContext)
44 TArmReg* end = (TArmReg*)(&aContext+1);
45 for (TArmReg* p = (TArmReg*)&aContext; p<end; ++p)
49 void DumpContext(TArmRegSet& aContext)
51 Kern::Printf(" r0 =%08x r1 =%08x r2 =%08x r3 =%08x",aContext.iR0,aContext.iR1,aContext.iR2,aContext.iR3);
52 Kern::Printf(" r4 =%08x r5 =%08x r6 =%08x r7 =%08x",aContext.iR4,aContext.iR5,aContext.iR6,aContext.iR7);
53 Kern::Printf(" r8 =%08x r9 =%08x r10=%08x r11=%08x",aContext.iR8,aContext.iR9,aContext.iR10,aContext.iR11);
54 Kern::Printf(" r12=%08x r13=%08x r14=%08x r15=%08x",aContext.iR12,aContext.iR13,aContext.iR14,aContext.iR15);
55 Kern::Printf(" cpsr=%08x dacr=%08x",aContext.iFlags, aContext.iDacr);
58 inline TBool IsRegisterAvailable(TInt aReg, TUint32 aMask)
60 return aMask & (1<<aReg);
63 TInt CheckSetContext(const TArmRegSet& aSetContext, const TArmRegSet& aContextAfterSet, TUint32 aAvailMask)
65 Kern::Printf("Checking all available registers have been modified (0%08x)", aAvailMask);
67 const TArmReg* pSet = (const TArmReg*)&aSetContext;
68 const TArmReg* pAfterSet = (const TArmReg*)&aContextAfterSet;
70 for (int i=0; i<=EArmPc; ++i)
72 if (pAfterSet[i] == 0 && IsRegisterAvailable(i, aAvailMask) && pSet[i] != 0)
74 Kern::Printf("Register %d not set (expected %08x actual %08x)", i, pSet[i], pAfterSet[i]);
77 if (pAfterSet[i] != 0 && ! IsRegisterAvailable(i, aAvailMask))
79 Kern::Printf("Register %d incorrectly set (expected %08x actual %08x)", i, 0, pAfterSet[i]);
87 //////////////////////////////////////////////////////////////////////////////
89 class DEventHandler : public DKernelEventHandler
93 TInt Create(DLogicalDevice* aDevice);
97 static TUint EventHandler(TKernelEvent aEvent, TAny* a1, TAny* a2, TAny* aThis);
98 TUint HandleEvent(TKernelEvent aType, TAny* a1, TAny* a2);
99 TBool HandleException(TRequestStatus*& aStatusPtr, TClientRequest*& aRequestPtr);
100 void HandleThreadDeath();
103 DThread* iClientThread;
104 DMutex* iLock; // serialise calls to handler
106 DLogicalDevice* iDevice; // open reference to LDD for avoiding lifetime issues
107 // software exception fields
108 TExcType iSwExcLastType;
109 TInt* iSwExcCounterPtr;
110 TRequestStatus* iSwExcStatusPtr;
111 TClientRequest* iClientRequestSwExc;
112 // hardware exception fields
113 TRequestStatus* iHwExcStatusPtr;
114 TClientRequest* iClientRequestHwExc;
115 // fields used for both hardware and software exceptions
117 TAny* iExcContextPtr;
118 TBool iExcKillThread;
119 // thread death event fields
120 TUint iDeathThreadId;
121 TRequestStatus* iDeathStatusPtr;
122 TAny* iDeathContextPtr;
123 TClientRequest* iClientRequestDeath;
127 DEventHandler::DEventHandler()
128 : DKernelEventHandler(EventHandler, this)
133 TInt DEventHandler::Create(DLogicalDevice* aDevice)
140 iClientThread = &Kern::CurrentThread();
141 r = Kern::CreateClientRequest(iClientRequestSwExc);
144 r = Kern::CreateClientRequest(iClientRequestHwExc);
147 r = Kern::CreateClientRequest(iClientRequestDeath);
150 r = Kern::MutexCreate(iLock, _L("EventHandlerLock"), KMutexOrdDebug);
159 void DEventHandler::Cleanup()
164 iDevice->Close(NULL);
165 if (iClientRequestSwExc)
167 Kern::DestroyClientRequest(iClientRequestSwExc);
168 iClientRequestSwExc = NULL;
170 if (iClientRequestHwExc)
172 Kern::DestroyClientRequest(iClientRequestHwExc);
173 iClientRequestHwExc = NULL;
175 if (iClientRequestDeath)
177 Kern::DestroyClientRequest(iClientRequestDeath);
178 iClientRequestDeath = NULL;
182 DEventHandler::~DEventHandler()
188 void DEventHandler::Cancel()
190 Kern::MutexWait(*iLock);
193 Kern::QueueRequestComplete(iClientThread, iClientRequestHwExc, KErrCancel);
194 iHwExcStatusPtr = NULL;
198 Kern::QueueRequestComplete(iClientThread, iClientRequestSwExc, KErrCancel);
199 iSwExcStatusPtr = NULL;
201 Kern::MutexSignal(*iLock);
205 TUint DEventHandler::EventHandler(TKernelEvent aEvent, TAny* a1, TAny* a2, TAny* aThis)
207 return ((DEventHandler*)aThis)->HandleEvent(aEvent, a1, a2);
211 // called in thread CS
212 TUint DEventHandler::HandleEvent(TKernelEvent aType, TAny* a1, TAny* a2)
214 // Ensure handler always called in thread critical section
215 NThread& nt = Kern::CurrentThread().iNThread;
216 __ASSERT_ALWAYS(nt.iCsCount != 0, (NKern::Lock(),*(TInt*)0xfaece5=0));
218 TUint r = DKernelEventHandler::ERunNext;
223 // HACK, EVIL UNSAFE MEMORY ACCESS FOLLOWS...
225 // folowing will kill system if memory is bad (because we're in a critical section)
226 umemget32(&counter, iSwExcCounterPtr, sizeof(TInt*));
228 umemput32(iSwExcCounterPtr, &counter, sizeof(TInt));
230 Kern::MutexWait(*iLock);
231 iSwExcLastType = (TExcType)(TInt)a1;
233 HandleException(iSwExcStatusPtr, iClientRequestSwExc);
234 Kern::MutexSignal(*iLock);
237 Kern::MutexWait(*iLock);
239 if (HandleException(iHwExcStatusPtr, iClientRequestHwExc))
240 r |= (TUint)EExcHandled;
241 Kern::MutexSignal(*iLock);
243 case EEventKillThread:
244 Kern::MutexWait(*iLock);
246 Kern::MutexSignal(*iLock);
257 // called in thread CS
258 TBool DEventHandler::HandleException(TRequestStatus*& aStatusPtr, TClientRequest*& aRequestPtr)
260 DThread& t = Kern::CurrentThread();
261 TBool handled = EFalse;
263 if (iExcThreadId == t.iId)
265 Kern::Printf("Trapped exception");
268 NKern::ThreadGetUserContext(&t.iNThread, &context1, availmask);
269 XTRAPD(r, XT_DEFAULT, umemput(iExcContextPtr, &context1, sizeof(context1)));
275 // We must preserve PC for software exceptions because execution
276 // goes back user-side and only then is the thread panicked.
277 TArmReg r15usr = context1.iR15;
278 ModifyContext(context1);
279 context1.iR15 = r15usr;
280 NKern::ThreadSetUserContext(&t.iNThread, &context1);
283 memclr(&context2, sizeof context2);
284 NKern::ThreadGetUserContext(&t.iNThread, &context2, availmask);
285 r = CheckSetContext(context1, context2, availmask);
289 Kern::ThreadSuspend(t, 1);
293 Kern::QueueRequestComplete(iClientThread, aRequestPtr, r);
300 // called in thread CS
301 void DEventHandler::HandleThreadDeath()
303 DThread& t = Kern::CurrentThread();
304 if (iDeathStatusPtr && iDeathThreadId == t.iId)
306 Kern::Printf("Trapping thread death: %O", &t);
309 NKern::ThreadGetUserContext(&t.iNThread, &context, unused);
310 XTRAPD(r, XT_DEFAULT, umemput(iDeathContextPtr, &context, sizeof(context)));
311 Kern::QueueRequestComplete(iClientThread, iClientRequestDeath, r);
312 iDeathStatusPtr = NULL;
316 //////////////////////////////////////////////////////////////////////////////
318 class DTestChannel : public DLogicalChannelBase
321 virtual ~DTestChannel();
323 // from DLogicalChannelBase
324 virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
325 virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2);
327 TInt SetAndGetBackContext(TUint aId, TAny* aContext);
328 TInt SetAndGetFullContext(TUint aId, TAny* aContext);
329 void GetContext(TUint aId, TAny* aContext);
330 void GetKernelContext(TUint aId, TAny* aContext);
331 void AddUserCallback(TUint aId, TUserCallbackState aCallback);
333 DEventHandler* iHandler;
337 // called in thread critical section
338 TInt DTestChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
343 // called in thread critical section
344 DTestChannel::~DTestChannel()
353 TInt DTestChannel::Request(TInt aFunction, TAny* a1, TAny* a2)
355 RContextLdd::TTrapInfo info;
360 case RContextLdd::EHook:
361 NKern::ThreadEnterCS();
362 iHandler = new DEventHandler;
367 r = iHandler->Create(iDevice);
368 iHandler->iSwExcCounterPtr = (TInt*)a1;
370 NKern::ThreadLeaveCS();
372 case RContextLdd::EGetLastExc:
373 r = iHandler->iSwExcLastType;
375 case RContextLdd::ETrapNextSwExc:
376 case RContextLdd::ETrapNextHwExc:
377 umemget(&info, a1, sizeof(info));
378 if (aFunction == RContextLdd::ETrapNextHwExc)
380 __ASSERT_ALWAYS(iHandler->iSwExcStatusPtr==NULL, Kern::PanicCurrentThread(KClientPanicCat, __LINE__));
381 iHandler->iHwExcStatusPtr = info.iStatusPtr;
382 r = iHandler->iClientRequestHwExc->SetStatus(iHandler->iHwExcStatusPtr);
383 __ASSERT_ALWAYS(r==KErrNone, Kern::PanicCurrentThread(KClientPanicCat, __LINE__));
387 __ASSERT_ALWAYS(iHandler->iHwExcStatusPtr==NULL, Kern::PanicCurrentThread(KClientPanicCat, __LINE__));
388 iHandler->iSwExcStatusPtr = info.iStatusPtr;
389 r = iHandler->iClientRequestSwExc->SetStatus(iHandler->iSwExcStatusPtr);
390 __ASSERT_ALWAYS(r==KErrNone, Kern::PanicCurrentThread(KClientPanicCat, __LINE__));
392 iHandler->iExcThreadId = info.iThreadId;
393 iHandler->iExcContextPtr = info.iContextPtr;
394 iHandler->iExcKillThread = info.iKillThread;
396 case RContextLdd::ETrapNextDeath:
397 umemget(&info, a1, sizeof(info));
398 iHandler->iDeathThreadId = info.iThreadId;
399 iHandler->iDeathContextPtr = info.iContextPtr;
400 iHandler->iDeathStatusPtr = info.iStatusPtr;
401 r = iHandler->iClientRequestDeath->SetStatus(iHandler->iDeathStatusPtr);
402 __ASSERT_ALWAYS(r==KErrNone, Kern::PanicCurrentThread(KClientPanicCat, __LINE__));
404 case RContextLdd::EGetContext:
405 GetContext((TUint)a1, a2);
407 case RContextLdd::ESetGetContext:
408 r = SetAndGetBackContext((TUint)a1, a2);
410 case RContextLdd::ESetGetFullContext:
411 r = SetAndGetFullContext((TUint)a1, a2);
413 case RContextLdd::EGetKernelContext:
414 GetKernelContext((TUint)a1, a2);
416 case RContextLdd::ESpinInKernel:
417 r = SpinInKernel((TBool)a1);
419 case RContextLdd::EAddUserCallback:
420 AddUserCallback((TUint)a1, (TUserCallbackState)(TUint)a2);
422 case RContextLdd::EResumeTrappedThread:
423 pT = ThreadFromId((TUint)a1);
424 Kern::ThreadResume(*pT);
427 Kern::PanicCurrentThread(KClientPanicCat, __LINE__);
434 TInt DTestChannel::SetAndGetBackContext(TUint aId, TAny* aContext)
436 DThread* pT = ThreadFromId(aId);
437 __ASSERT_ALWAYS(pT!=NULL, Kern::PanicCurrentThread(KClientPanicCat, __LINE__));
439 // The following code assumes the inspected thread does not run between the
440 // set context and get context call.
443 umemget(&context1, aContext, sizeof context1);
444 NKern::ThreadSetUserContext(&pT->iNThread, &context1);
447 memclr(&context2, sizeof context2);
449 NKern::ThreadGetUserContext(&pT->iNThread, &context2, availmask);
450 umemput(aContext, &context2, sizeof context2);
452 return CheckSetContext(context1, context2, availmask);
459 static TBool IsDead(NThreadBase* aT)
460 { return aT->iWaitState.ThreadIsDead(); }
464 TInt DTestChannel::SetAndGetFullContext(TUint aId, TAny* aContext)
466 DThread* pT = ThreadFromId(aId);
467 __ASSERT_ALWAYS(pT != NULL, Kern::PanicCurrentThread(KClientPanicCat, __LINE__));
470 dead = NKTest::IsDead(&pT->iNThread);
472 dead = pT->iNThread.iSpare1 == NThreadBase::EDead;
474 __ASSERT_ALWAYS(dead, Kern::PanicCurrentThread(KClientPanicCat, __LINE__));
476 TArmFullContext contextData;
477 umemget(&contextData, aContext, sizeof contextData);
478 NKern::ThreadSetUserContext(&pT->iNThread, &contextData.iUserContext);
480 NKern::ThreadGetUserContext(&pT->iNThread, &contextData.iUserContext, contextData.iUserAvail);
481 NKern::ThreadGetSystemContext(&pT->iNThread, &contextData.iSystemContext, contextData.iSystemAvail);
483 umemput(aContext, &contextData, sizeof contextData);
488 void DTestChannel::GetContext(TUint aId, TAny* aContext)
490 DThread* pT = ThreadFromId(aId);
491 __ASSERT_ALWAYS(pT!=NULL, Kern::PanicCurrentThread(KClientPanicCat, __LINE__));
494 memclr(&context, sizeof context);
496 NKern::ThreadGetUserContext(&pT->iNThread, &context, unused);
497 umemput(aContext, &context, sizeof context);
500 void DTestChannel::GetKernelContext(TUint aId, TAny* aContext)
502 DThread* pT = ThreadFromId(aId);
503 __ASSERT_ALWAYS(pT!=NULL, Kern::PanicCurrentThread(KClientPanicCat, __LINE__));
506 memclr(&context, sizeof context);
508 NKern::ThreadGetSystemContext(&pT->iNThread, &context, unused);
509 umemput(aContext, &context, sizeof context);
512 void DTestChannel::AddUserCallback(TUint aId, TUserCallbackState aCallback)
514 DThread* pT = ThreadFromId(aId);
515 __ASSERT_ALWAYS(pT!=NULL, Kern::PanicCurrentThread(KClientPanicCat, __LINE__));
519 case ESpinningCallback:
520 KernTest::Test(KernTest::EUserModeCallbackSpin, pT);
522 case ESleepingCallback:
523 KernTest::Test(KernTest::EUserModeCallbackSleep, pT);
526 Kern::PanicCurrentThread(KClientPanicCat, __LINE__);
530 //////////////////////////////////////////////////////////////////////////////
532 class DTestFactory : public DLogicalDevice
536 // from DLogicalDevice
537 virtual TInt Install();
538 virtual void GetCaps(TDes8& aDes) const;
539 virtual TInt Create(DLogicalChannelBase*& aChannel);
542 DTestFactory::DTestFactory()
544 iVersion = RContextLdd::Version();
545 // iParseMask = 0; // no unit, no info, no PDD
546 // iUnitsMask = 0; // only one thing
549 TInt DTestFactory::Create(DLogicalChannelBase*& aChannel)
551 aChannel=new DTestChannel;
552 return aChannel ? KErrNone : KErrNoMemory;
555 TInt DTestFactory::Install()
557 return SetName(&KTestLddName);
560 void DTestFactory::GetCaps(TDes8& /*aDes*/) const
564 //////////////////////////////////////////////////////////////////////////////
566 DECLARE_STANDARD_LDD()
568 return new DTestFactory;