First public contribution.
1 // Copyright (c) 1996-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\system\t_exc.cpp
15 // In WINS T_EXC should be run from the command line only.
16 // T_EXC will not complete when run under the MSDEV debugger.
18 // Test and verify exception handling.
20 // User::SetExceptionHandler, User::RaiseException
22 // - Create a global semaphore, verify success.
23 // - Test exceptions with no handlers: verify that divide by zero and
24 // User::RaiseException() panic as expected.
25 // - Test exceptions with handlers: verify that divide by zero and
26 // User::RaiseException() call their exception handlers as expected.
27 // - Test exception raised in exception handler: verify divide by zero
28 // causes exception and an exception in the exception handler causes
30 // - Verify the results are as expected when a thread causes a divide
32 // - Get context of interrupted thread, get context of thread waiting
33 // for request, get context of suspended thread. Verify results are
35 // Platforms/Drives/Compatibility:
37 // Assumptions/Requirement/Pre-requisites:
38 // Failures and causes:
39 // Base Port information:
47 #pragma warning( disable : 4723 ) // disable divide by zero warnings
50 void UndefinedInstruction();
53 LOCAL_D RTest test(_L("T_EXC"));
58 TBool outsideExcSupported=ETrue;
60 void excHandler(TExcType /*aType*/)
62 // An exception handler that does nothing
69 void excHandlerFault(TExcType aType)
71 // An exception handler that causes an exception
74 debug.Print(_L("Handling exception %d and causing exception in handler"), aType);
78 // There is no Divide By Zero exception on the Arm
79 // Use undefined instruction instead
80 UndefinedInstruction();
82 // Cause a div by zero exception
91 TInt waitSemaphore(TAny *)
97 TInt r=s.OpenGlobal(_L("A SEMAPHORE"));
103 TInt garfield(TAny *)
105 // Sleep for a long time
109 User::After(10000000);
115 // Run round in circles
122 TInt divideByZero(TAny *)
128 // There is no Divide By Zero exception on the Arm
129 // Use undefined instruction instead
130 UndefinedInstruction();
134 #pragma warning( disable : 4189 ) // local variable is initialized but not referenced
136 volatile int i=0, j=10;
142 #pragma warning( default : 4723 )
144 TInt raiseException(TAny *)
146 // Raise an exception
150 User::RaiseException(EExcIntegerDivideByZero);
158 test.Start(_L("Create a thread (divideByZero)"));
159 User::SetJustInTime(EFalse);
163 r=t.Create(_L("divideByZero"),divideByZero,KDefaultStackSize,KDefaultStackSize,KDefaultStackSize,NULL);
166 test.Next(_L("Resume and wait for div by zero exception"));
168 User::WaitForRequest(s);
169 test.Printf(_L("Exit Type %d\r\n"),(TInt)t.ExitType());
170 test(t.ExitType()==EExitPanic);
171 test(t.ExitReason()==ECausedException);
175 test.Next(_L("Create a thread (raiseException)"));
176 r=t.Create(_L("raiseException"),raiseException,KDefaultStackSize,KDefaultStackSize,KDefaultStackSize,NULL);
179 test.Next(_L("Resume, and wait for raise exception"));
181 User::WaitForRequest(s);
182 test(t.ExitType()==EExitPanic);
183 test(t.ExitReason()==ECausedException);
189 TInt divideByZero2(TAny *)
192 // There is no Div By Zero exception on the Arm so we use a data abort instead
193 User::SetExceptionHandler(&excHandler, KExceptionAbort|KExceptionFault|KExceptionUserInterrupt);
195 User::SetExceptionHandler(&excHandler, KExceptionInteger);
197 return divideByZero(0);
200 TInt raiseException2(TAny *)
202 User::SetExceptionHandler(&excHandler, KExceptionInteger);
203 return raiseException(0);
209 test.Start(_L("Create a thread (odie)"));
214 test.Next(_L("Create a thread (divideByZero)"));
215 r=t.Create(_L("divideByZero"),divideByZero2,KDefaultStackSize,KDefaultStackSize,KDefaultStackSize,NULL);
220 test.Next(_L("Resume, and wait for 10 divide by zero exceptions"));
225 test.Next(_L("Kill the thread"));
227 User::WaitForRequest(s);
228 test(t.ExitType()==EExitKill);
229 test(t.ExitReason()==666);
232 test.Next(_L("Create a thread (raiseException2)"));
233 r=t.Create(_L("raiseException2"),raiseException2,KDefaultStackSize,KDefaultStackSize,KDefaultStackSize,NULL);
237 test.Next(_L("Resume"));
239 test.Next(_L("Wait for thread to finish"));
240 User::WaitForRequest(s);
241 test.Next(_L("Test thread raised an exception on itself"));
243 test(t.ExitType()==EExitKill);
244 test(t.ExitReason()==KErrNone);
250 TInt divideByZero3(TAny *)
253 User::SetExceptionHandler(&excHandlerFault, KExceptionAbort|KExceptionFault|KExceptionUserInterrupt);
255 User::SetExceptionHandler(&excHandlerFault, KExceptionInteger);
257 return divideByZero(0);
262 test.Start(_L("Create a thread (divideByZero3)"));
266 r=t.Create(_L("divideByZero3"),divideByZero3,KDefaultStackSize,KDefaultStackSize,KDefaultStackSize,NULL);
270 test.Next(_L("Resume, and wait for thread to die"));
272 User::WaitForRequest(s);
273 test.Next(_L("Test thread raised one exception"));
275 test.Next(_L("Test thread paniced on double exception"));
276 test(t.ExitType()==EExitPanic);
277 test(t.ExitReason()==ECausedException);
283 extern TInt dividebyzeroFn(TInt x)
285 volatile int i=x, j=10;
292 TInt dividebyzeroThread(TAny *)
294 return dividebyzeroFn(0);
297 void testDivException()
301 test.Next(_L("Create divide by zero thread"));
302 TInt r=t.Create(_L("drop dead"),dividebyzeroThread,KDefaultStackSize,KDefaultStackSize,KDefaultStackSize,NULL);
305 test.Next(_L("Resume"));
307 User::WaitForRequest(s);
308 test.Next(_L("Test thread died because of EExcDivideByZero"));
309 test(t.ExitType()==EExitPanic);
310 test(t.ExitReason()==ECausedException);
315 TInt ContextThread0(TAny *)
320 TInt ContextThread0(TAny *);
324 TInt ContextThread1(TAny *)
329 TInt ContextThread1(TAny *);
333 TInt ContextThread2(TAny *)
338 TInt ContextThread2(TAny *);
341 TUint32 RunContextThread(TThreadFunction aFunction, TUint32* aRegs)
344 TUint32 pc = (TUint32)aFunction((TAny*)0x80000000);
350 TInt r=t.Create(_L("Context"),aFunction,KDefaultStackSize,NULL,NULL);
356 TPtr8 buf((TUint8*)aRegs, 32*4, 32*4);
362 pc = 0; // not supported
364 User::WaitForRequest(s);
375 const TInt KNumContextTests = 3;
377 static const TThreadFunction ContextTestFn[KNumContextTests] =
384 #if defined(__CPU_ARM)
385 const TInt KPCIndex = 15;
386 static const SRegValues ExpectedRegs[KNumContextTests] =
389 { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x00,
390 0xa0000010, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
394 { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x00,
395 0xa0000010, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
399 { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x00,
400 0xa0000010, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
405 static const TUint32 KRegValidBitsMask[32] =
407 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu,
408 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu,
409 0xf00000ffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu,
410 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu
413 #elif defined(__CPU_X86)
414 const TInt KPCIndex = 15;
415 static const SRegValues ExpectedRegs[KNumContextTests] =
418 { 0xaaaaaaaa, 0xbbbbbbbb, 0xcccccccc, 0xdddddddd, 0xe50e50e5, 0xeb0eb0eb, 0xe51e51e5, 0xed1ed1ed,
419 0x0000001b, 0x00000023, 0x00000023, 0x00000023, 0x00000023, 0x00000023, 0x00000cd5, 0x00000000,
420 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
421 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
425 { 0x00000000, 0xbbbbbbbb, 0xcccccccc, 0xdddddddd, 0xe50e50e5, 0xeb0eb0eb, 0xe51e51e5, 0xed1ed1ed,
426 0x0000001b, 0x00000023, 0x00000023, 0x00000023, 0x00000023, 0x00000023, 0x00000cd5, 0x00000000,
427 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
428 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
431 {0xe7fa, // EAX=exec number, ECX trashed by preprocess handler
432 { 0xaaaaaaaa, 0xbbbbbbbb, 0xffff8001, 0xdddddddd, 0xe50e50e5, 0xeb0eb0eb, 0xe51e51e5, 0xed1ed1ed,
433 0x0000001b, 0x00000023, 0x00000023, 0x00000023, 0x00000023, 0x00000023, 0x00000cd5, 0x00000000,
434 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
435 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000
440 static const TUint32 KRegValidBitsMask[32] =
442 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu,
443 0x0000ffffu, 0x0000ffffu, 0x0000ffffu, 0x0000ffffu, 0x0000ffffu, 0x0000ffffu, 0x00000cd5u, 0xffffffffu,
444 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu,
445 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu, 0xffffffffu
450 void CheckContextValues(TUint32* aRegs, const SRegValues& aExpected, TUint32 aPC)
452 test.Printf(_L("PC=%08x Context returned:\n"), aPC);
454 const TUint32* s = aRegs;
455 for (i=0; i<8; ++i, s+=4)
456 test.Printf(_L("%08x %08x %08x %08x\n"), s[0], s[1], s[2], s[3]);
457 TUint32 v = aExpected.iValidMask;
459 for (i=0; i<32; ++i, v>>=1)
463 TUint32 mask = KRegValidBitsMask[i];
464 TUint32 actual = aRegs[i] & mask;
465 TUint32 exp = (i == KPCIndex) ? aPC&mask : aExpected.iValues[i];
468 test.Printf(_L("%d: Expected %08x but got %08x\n"), i, exp, actual);
480 test.Next(_L("Get context of interrupted thread"));
482 for (tn=0; tn<KNumContextTests; ++tn)
484 test.Printf(_L("Context test %d\n"), tn);
485 TUint32 pc = RunContextThread(ContextTestFn[tn], regs);
488 CheckContextValues(regs, ExpectedRegs[tn], pc);
493 GLDEF_C TInt E32Main()
495 // __KHEAP_SETFAIL etc. not available in release mode, so don't test
500 test.Start(_L("Create a semaphore"));
501 TInt r=gSem.CreateGlobal(_L("A SEMAPHORE"),0);
503 test.Next(_L("Test exceptions with no handlers"));
505 test.Next(_L("Test exceptions with handlers"));
507 test.Next(_L("Test exception raised in exception handler"));
509 test.Next(_L("Divide by zero exception"));
511 test.Next(_L("Test Context"));