os/kernelhwsrv/kerneltest/e32test/system/t_exc.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
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".
     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 	}