kerneltest/e32test/system/t_exc.cpp
changeset 0 a41df078684a
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     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".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    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.
       
    17 // Overview:
       
    18 // Test and verify exception handling.
       
    19 // API Information:
       
    20 // User::SetExceptionHandler, User::RaiseException
       
    21 // Details:
       
    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 
       
    29 // a panic.
       
    30 // - Verify the results are as expected when a thread causes a divide
       
    31 // by zero exception.
       
    32 // - Get context of interrupted thread, get context of thread waiting 
       
    33 // for request, get context of suspended thread. Verify results are
       
    34 // as expected.
       
    35 // Platforms/Drives/Compatibility:
       
    36 // All.
       
    37 // Assumptions/Requirement/Pre-requisites:
       
    38 // Failures and causes:
       
    39 // Base Port information:
       
    40 // 
       
    41 //
       
    42 
       
    43 #include <e32test.h>
       
    44 #include <e32svr.h>
       
    45 #include "u32std.h"
       
    46 
       
    47 #pragma warning( disable : 4723 ) // disable divide by zero warnings
       
    48 
       
    49 #ifdef __MARM__
       
    50 void UndefinedInstruction();
       
    51 #endif
       
    52 
       
    53 LOCAL_D RTest test(_L("T_EXC"));
       
    54 RDebug debug;
       
    55 
       
    56 TInt gCount=0;
       
    57 RSemaphore gSem;
       
    58 TBool outsideExcSupported=ETrue;
       
    59 
       
    60 void excHandler(TExcType /*aType*/)
       
    61 //
       
    62 // An exception handler that does nothing
       
    63 //
       
    64 	{
       
    65 
       
    66 	gCount++;
       
    67 	}
       
    68 
       
    69 void excHandlerFault(TExcType aType)
       
    70 //
       
    71 // An exception handler that causes an exception
       
    72 //
       
    73 	{
       
    74 	debug.Print(_L("Handling exception %d and causing exception in handler"), aType);
       
    75 	gCount++;
       
    76 
       
    77 #ifdef __MARM__
       
    78 	// There is no Divide By Zero exception on the Arm
       
    79 	// Use undefined instruction instead
       
    80 	UndefinedInstruction();
       
    81 #else
       
    82 	// Cause a div by zero exception
       
    83 	volatile int i=0;
       
    84 	volatile int j=10;
       
    85 	int l=j/i;
       
    86 	for (i=0; i<l; i++)
       
    87 		;
       
    88 #endif
       
    89 	}
       
    90 
       
    91 TInt waitSemaphore(TAny *)
       
    92 //
       
    93 // Sleep
       
    94 //
       
    95 	{
       
    96 	RSemaphore s;
       
    97 	TInt r=s.OpenGlobal(_L("A SEMAPHORE"));
       
    98 	test(r==KErrNone);
       
    99 	s.Wait();
       
   100 	return KErrNone;
       
   101 	}
       
   102 
       
   103 TInt garfield(TAny *)
       
   104 //
       
   105 // Sleep for a long time
       
   106 //
       
   107 	{
       
   108 
       
   109 	User::After(10000000);
       
   110 	return KErrNone;
       
   111 	}
       
   112 
       
   113 TInt odie(TAny *)
       
   114 //
       
   115 // Run round in circles
       
   116 //
       
   117 	{
       
   118 	FOREVER
       
   119 		;
       
   120 	}
       
   121 
       
   122 TInt divideByZero(TAny *)
       
   123 //
       
   124 // Divide by zero
       
   125 //
       
   126 	{
       
   127 #ifdef __MARM__
       
   128 	// There is no Divide By Zero exception on the Arm
       
   129 	// Use undefined instruction instead
       
   130 	UndefinedInstruction();
       
   131 	return(KErrNone);
       
   132 #else
       
   133 #ifdef __WINS__
       
   134 #pragma warning( disable : 4189 )	// local variable is initialized but not referenced
       
   135 #endif
       
   136 	volatile int i=0, j=10;
       
   137 	volatile int l=j/i;
       
   138 	FOREVER
       
   139 		;
       
   140 #endif
       
   141 	}
       
   142 #pragma warning( default : 4723 )
       
   143 
       
   144 TInt raiseException(TAny *)
       
   145 //
       
   146 // Raise an exception
       
   147 //
       
   148 	{
       
   149 
       
   150 	User::RaiseException(EExcIntegerDivideByZero);
       
   151 	User::After(500000);
       
   152 	return KErrNone;
       
   153 	}
       
   154 
       
   155 void test1()
       
   156 	{
       
   157 
       
   158 	test.Start(_L("Create a thread (divideByZero)"));
       
   159 	User::SetJustInTime(EFalse);
       
   160 	RThread t;
       
   161 	TRequestStatus s;
       
   162 	TInt r;
       
   163 	r=t.Create(_L("divideByZero"),divideByZero,KDefaultStackSize,KDefaultStackSize,KDefaultStackSize,NULL);
       
   164 	test(r==KErrNone);
       
   165 	t.Logon(s);
       
   166 	test.Next(_L("Resume and wait for div by zero exception"));
       
   167 	t.Resume();
       
   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);
       
   172 	CLOSE_AND_WAIT(t);
       
   173 //
       
   174 	
       
   175 	test.Next(_L("Create a thread (raiseException)"));
       
   176 	r=t.Create(_L("raiseException"),raiseException,KDefaultStackSize,KDefaultStackSize,KDefaultStackSize,NULL);
       
   177 	test(r==KErrNone);
       
   178 	t.Logon(s);
       
   179 	test.Next(_L("Resume, and wait for raise exception"));
       
   180 	t.Resume();
       
   181 	User::WaitForRequest(s);
       
   182 	test(t.ExitType()==EExitPanic);
       
   183 	test(t.ExitReason()==ECausedException);
       
   184 	CLOSE_AND_WAIT(t);
       
   185 
       
   186 	test.End();
       
   187 	}
       
   188 
       
   189 TInt divideByZero2(TAny *)
       
   190 	{
       
   191 #ifdef __MARM__
       
   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);
       
   194 #else
       
   195 	User::SetExceptionHandler(&excHandler, KExceptionInteger);
       
   196 #endif
       
   197 	return divideByZero(0);
       
   198 	}
       
   199 
       
   200 TInt raiseException2(TAny *)
       
   201 	{
       
   202 	User::SetExceptionHandler(&excHandler, KExceptionInteger);
       
   203 	return raiseException(0);
       
   204 	}
       
   205 
       
   206 void test2()
       
   207 	{
       
   208 
       
   209 	test.Start(_L("Create a thread (odie)"));
       
   210 	RThread t;
       
   211 	TRequestStatus s;
       
   212 	TInt r;
       
   213 
       
   214 	test.Next(_L("Create a thread (divideByZero)"));
       
   215 	r=t.Create(_L("divideByZero"),divideByZero2,KDefaultStackSize,KDefaultStackSize,KDefaultStackSize,NULL);
       
   216 	test(r==KErrNone);
       
   217 	t.Logon(s);
       
   218 	gCount=0;
       
   219 
       
   220 	test.Next(_L("Resume, and wait for 10 divide by zero exceptions"));
       
   221 	t.Resume();
       
   222 	while (gCount<10)
       
   223 		User::After(500000);
       
   224 	test(gCount>=10);
       
   225 	test.Next(_L("Kill the thread"));
       
   226 	t.Kill(666);
       
   227 	User::WaitForRequest(s);
       
   228 	test(t.ExitType()==EExitKill);
       
   229 	test(t.ExitReason()==666);
       
   230 	CLOSE_AND_WAIT(t);
       
   231 //
       
   232 	test.Next(_L("Create a thread (raiseException2)"));
       
   233 	r=t.Create(_L("raiseException2"),raiseException2,KDefaultStackSize,KDefaultStackSize,KDefaultStackSize,NULL);
       
   234 	test(r==KErrNone);
       
   235 	t.Logon(s);
       
   236 	gCount=0;
       
   237 	test.Next(_L("Resume"));
       
   238 	t.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"));
       
   242 	test(gCount==1);
       
   243 	test(t.ExitType()==EExitKill);
       
   244 	test(t.ExitReason()==KErrNone);
       
   245 	CLOSE_AND_WAIT(t);
       
   246 
       
   247 	test.End();
       
   248 	}
       
   249 
       
   250 TInt divideByZero3(TAny *)
       
   251 	{
       
   252 #ifdef __MARM__
       
   253 	User::SetExceptionHandler(&excHandlerFault, KExceptionAbort|KExceptionFault|KExceptionUserInterrupt);
       
   254 #else
       
   255 	User::SetExceptionHandler(&excHandlerFault, KExceptionInteger);
       
   256 #endif
       
   257 	return divideByZero(0);
       
   258 	}
       
   259 
       
   260 void test3()
       
   261 	{
       
   262 	test.Start(_L("Create a thread (divideByZero3)"));
       
   263 	RThread t;
       
   264 	TRequestStatus s;
       
   265 	TInt r;
       
   266 	r=t.Create(_L("divideByZero3"),divideByZero3,KDefaultStackSize,KDefaultStackSize,KDefaultStackSize,NULL);
       
   267 	test(r==KErrNone);
       
   268 	t.Logon(s);
       
   269 	gCount=0;
       
   270 	test.Next(_L("Resume, and wait for thread to die"));
       
   271 	t.Resume();
       
   272 	User::WaitForRequest(s);
       
   273 	test.Next(_L("Test thread raised one exception"));
       
   274 	test(gCount==1);
       
   275 	test.Next(_L("Test thread paniced on double exception"));
       
   276 	test(t.ExitType()==EExitPanic);
       
   277 	test(t.ExitReason()==ECausedException);
       
   278 	CLOSE_AND_WAIT(t);
       
   279 //
       
   280 	test.End();
       
   281 	}
       
   282 
       
   283 extern TInt dividebyzeroFn(TInt x)
       
   284 	{
       
   285 	volatile int i=x, j=10;
       
   286 	volatile int l=j/i;
       
   287 	for (i=0; i<l; i++)
       
   288 		;
       
   289 	return KErrNone;
       
   290 	}
       
   291 
       
   292 TInt dividebyzeroThread(TAny *)
       
   293 	{
       
   294 	return dividebyzeroFn(0);
       
   295 	}
       
   296 
       
   297 void testDivException()
       
   298 	{
       
   299 	RThread t;
       
   300 	TRequestStatus s;
       
   301 	test.Next(_L("Create divide by zero thread"));
       
   302 	TInt r=t.Create(_L("drop dead"),dividebyzeroThread,KDefaultStackSize,KDefaultStackSize,KDefaultStackSize,NULL);
       
   303 	test(r==KErrNone);
       
   304 	t.Logon(s);
       
   305 	test.Next(_L("Resume"));
       
   306 	t.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);
       
   311 	CLOSE_AND_WAIT(t);
       
   312 	}
       
   313 
       
   314 #ifndef __EPOC32__
       
   315 TInt ContextThread0(TAny *)
       
   316 	{
       
   317 	FOREVER;
       
   318 	}
       
   319 #else
       
   320 TInt ContextThread0(TAny *);
       
   321 #endif
       
   322 
       
   323 #ifndef __EPOC32__
       
   324 TInt ContextThread1(TAny *)
       
   325 	{
       
   326 	FOREVER;
       
   327 	}
       
   328 #else
       
   329 TInt ContextThread1(TAny *);
       
   330 #endif
       
   331 
       
   332 #ifndef __EPOC32__
       
   333 TInt ContextThread2(TAny *)
       
   334 	{
       
   335 	FOREVER;
       
   336 	}
       
   337 #else
       
   338 TInt ContextThread2(TAny *);
       
   339 #endif
       
   340 
       
   341 TUint32 RunContextThread(TThreadFunction aFunction, TUint32* aRegs)
       
   342 	{
       
   343 #ifdef __EPOC32__
       
   344 	TUint32 pc = (TUint32)aFunction((TAny*)0x80000000);
       
   345 #else
       
   346 	TUint32 pc = 0;
       
   347 #endif
       
   348 	RThread t;
       
   349 	TRequestStatus s;
       
   350 	TInt r=t.Create(_L("Context"),aFunction,KDefaultStackSize,NULL,NULL);
       
   351 	test(r==KErrNone);
       
   352 	t.Logon(s);
       
   353 	t.Resume();
       
   354 	User::After(100000);
       
   355 
       
   356 	TPtr8 buf((TUint8*)aRegs, 32*4, 32*4);
       
   357 	TInt i;
       
   358 	for (i=0; i<32; i++)
       
   359 		aRegs[i]=0xbad00bad;
       
   360 	t.Context(buf);
       
   361 	if (buf.Length()==0)
       
   362 		pc = 0;	// not supported
       
   363 	t.Kill(KErrNone);
       
   364 	User::WaitForRequest(s);
       
   365 	CLOSE_AND_WAIT(t);
       
   366 	return pc;
       
   367 	}
       
   368 
       
   369 struct SRegValues
       
   370 	{
       
   371 	TUint32		iValidMask;
       
   372 	TUint32		iValues[32];
       
   373 	};
       
   374 
       
   375 const TInt KNumContextTests = 3;
       
   376 
       
   377 static const TThreadFunction ContextTestFn[KNumContextTests] =
       
   378 	{
       
   379 	&ContextThread0,
       
   380 	&ContextThread1,
       
   381 	&ContextThread2
       
   382 	};
       
   383 
       
   384 #if defined(__CPU_ARM)
       
   385 const TInt KPCIndex = 15;
       
   386 static const SRegValues ExpectedRegs[KNumContextTests] =
       
   387 	{
       
   388 		{0x1ffff,
       
   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
       
   391 			}
       
   392 		},
       
   393 		{0x0eff0,
       
   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
       
   396 			}
       
   397 		},
       
   398 		{0x0eff0,
       
   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
       
   401 			}
       
   402 		}
       
   403 	};
       
   404 
       
   405 static const TUint32 KRegValidBitsMask[32] =
       
   406 	{
       
   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
       
   411 	};
       
   412 
       
   413 #elif defined(__CPU_X86)
       
   414 const TInt KPCIndex = 15;
       
   415 static const SRegValues ExpectedRegs[KNumContextTests] =
       
   416 	{
       
   417 		{0xe7ff,
       
   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
       
   422 			}
       
   423 		},
       
   424 		{0xe7ff,
       
   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
       
   429 			}
       
   430 		},
       
   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
       
   436 			}
       
   437 		}
       
   438 	};
       
   439 
       
   440 static const TUint32 KRegValidBitsMask[32] =
       
   441 	{
       
   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
       
   446 	};
       
   447 
       
   448 #endif
       
   449 
       
   450 void CheckContextValues(TUint32* aRegs, const SRegValues& aExpected, TUint32 aPC)
       
   451 	{
       
   452 	test.Printf(_L("PC=%08x Context returned:\n"), aPC);
       
   453 	TInt i;
       
   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;
       
   458 	TBool ok = ETrue;
       
   459 	for (i=0; i<32; ++i, v>>=1)
       
   460 		{
       
   461 		if (!(v&1))
       
   462 			continue;
       
   463 		TUint32 mask = KRegValidBitsMask[i];
       
   464 		TUint32 actual = aRegs[i] & mask;
       
   465 		TUint32 exp = (i == KPCIndex) ? aPC&mask : aExpected.iValues[i];
       
   466 		if (actual != exp)
       
   467 			{
       
   468 			test.Printf(_L("%d: Expected %08x but got %08x\n"), i, exp, actual);
       
   469 			ok = EFalse;
       
   470 			}
       
   471 		}
       
   472 	test(ok);
       
   473 	}
       
   474 
       
   475 void testContext()
       
   476 	{
       
   477 
       
   478 	TUint32 regs[32];
       
   479 
       
   480 	test.Next(_L("Get context of interrupted thread"));
       
   481 	TInt tn;
       
   482 	for (tn=0; tn<KNumContextTests; ++tn)
       
   483 		{
       
   484 		test.Printf(_L("Context test %d\n"), tn);
       
   485 		TUint32 pc = RunContextThread(ContextTestFn[tn], regs);
       
   486 		if (pc)
       
   487 			{
       
   488 			CheckContextValues(regs, ExpectedRegs[tn], pc);
       
   489 			}
       
   490 		}
       
   491 	}
       
   492 
       
   493 GLDEF_C TInt E32Main()
       
   494 //
       
   495 // __KHEAP_SETFAIL etc. not available in release mode, so don't test
       
   496 //
       
   497 	{
       
   498 
       
   499 	test.Title();
       
   500 	test.Start(_L("Create a semaphore"));
       
   501 	TInt r=gSem.CreateGlobal(_L("A SEMAPHORE"),0);
       
   502 	test(r==KErrNone);
       
   503 	test.Next(_L("Test exceptions with no handlers"));
       
   504 	test1();
       
   505 	test.Next(_L("Test exceptions with handlers"));
       
   506 	test2();
       
   507 	test.Next(_L("Test exception raised in exception handler"));
       
   508 	test3();
       
   509 	test.Next(_L("Divide by zero exception"));
       
   510 	testDivException();
       
   511 	test.Next(_L("Test Context"));
       
   512 	testContext();
       
   513 	test.End();
       
   514 	return(KErrNone);
       
   515 	}