sl@0: // Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32test\system\t_exc.cpp sl@0: // In WINS T_EXC should be run from the command line only. sl@0: // T_EXC will not complete when run under the MSDEV debugger. sl@0: // Overview: sl@0: // Test and verify exception handling. sl@0: // API Information: sl@0: // User::SetExceptionHandler, User::RaiseException sl@0: // Details: sl@0: // - Create a global semaphore, verify success. sl@0: // - Test exceptions with no handlers: verify that divide by zero and sl@0: // User::RaiseException() panic as expected. sl@0: // - Test exceptions with handlers: verify that divide by zero and sl@0: // User::RaiseException() call their exception handlers as expected. sl@0: // - Test exception raised in exception handler: verify divide by zero sl@0: // causes exception and an exception in the exception handler causes sl@0: // a panic. sl@0: // - Verify the results are as expected when a thread causes a divide sl@0: // by zero exception. sl@0: // - Get context of interrupted thread, get context of thread waiting sl@0: // for request, get context of suspended thread. Verify results are sl@0: // as expected. sl@0: // Platforms/Drives/Compatibility: sl@0: // All. sl@0: // Assumptions/Requirement/Pre-requisites: sl@0: // Failures and causes: sl@0: // Base Port information: sl@0: // sl@0: // sl@0: sl@0: #include sl@0: #include sl@0: #include "u32std.h" sl@0: sl@0: #pragma warning( disable : 4723 ) // disable divide by zero warnings sl@0: sl@0: #ifdef __MARM__ sl@0: void UndefinedInstruction(); sl@0: #endif sl@0: sl@0: LOCAL_D RTest test(_L("T_EXC")); sl@0: RDebug debug; sl@0: sl@0: TInt gCount=0; sl@0: RSemaphore gSem; sl@0: TBool outsideExcSupported=ETrue; sl@0: sl@0: void excHandler(TExcType /*aType*/) sl@0: // sl@0: // An exception handler that does nothing sl@0: // sl@0: { sl@0: sl@0: gCount++; sl@0: } sl@0: sl@0: void excHandlerFault(TExcType aType) sl@0: // sl@0: // An exception handler that causes an exception sl@0: // sl@0: { sl@0: debug.Print(_L("Handling exception %d and causing exception in handler"), aType); sl@0: gCount++; sl@0: sl@0: #ifdef __MARM__ sl@0: // There is no Divide By Zero exception on the Arm sl@0: // Use undefined instruction instead sl@0: UndefinedInstruction(); sl@0: #else sl@0: // Cause a div by zero exception sl@0: volatile int i=0; sl@0: volatile int j=10; sl@0: int l=j/i; sl@0: for (i=0; i=10); sl@0: test.Next(_L("Kill the thread")); sl@0: t.Kill(666); sl@0: User::WaitForRequest(s); sl@0: test(t.ExitType()==EExitKill); sl@0: test(t.ExitReason()==666); sl@0: CLOSE_AND_WAIT(t); sl@0: // sl@0: test.Next(_L("Create a thread (raiseException2)")); sl@0: r=t.Create(_L("raiseException2"),raiseException2,KDefaultStackSize,KDefaultStackSize,KDefaultStackSize,NULL); sl@0: test(r==KErrNone); sl@0: t.Logon(s); sl@0: gCount=0; sl@0: test.Next(_L("Resume")); sl@0: t.Resume(); sl@0: test.Next(_L("Wait for thread to finish")); sl@0: User::WaitForRequest(s); sl@0: test.Next(_L("Test thread raised an exception on itself")); sl@0: test(gCount==1); sl@0: test(t.ExitType()==EExitKill); sl@0: test(t.ExitReason()==KErrNone); sl@0: CLOSE_AND_WAIT(t); sl@0: sl@0: test.End(); sl@0: } sl@0: sl@0: TInt divideByZero3(TAny *) sl@0: { sl@0: #ifdef __MARM__ sl@0: User::SetExceptionHandler(&excHandlerFault, KExceptionAbort|KExceptionFault|KExceptionUserInterrupt); sl@0: #else sl@0: User::SetExceptionHandler(&excHandlerFault, KExceptionInteger); sl@0: #endif sl@0: return divideByZero(0); sl@0: } sl@0: sl@0: void test3() sl@0: { sl@0: test.Start(_L("Create a thread (divideByZero3)")); sl@0: RThread t; sl@0: TRequestStatus s; sl@0: TInt r; sl@0: r=t.Create(_L("divideByZero3"),divideByZero3,KDefaultStackSize,KDefaultStackSize,KDefaultStackSize,NULL); sl@0: test(r==KErrNone); sl@0: t.Logon(s); sl@0: gCount=0; sl@0: test.Next(_L("Resume, and wait for thread to die")); sl@0: t.Resume(); sl@0: User::WaitForRequest(s); sl@0: test.Next(_L("Test thread raised one exception")); sl@0: test(gCount==1); sl@0: test.Next(_L("Test thread paniced on double exception")); sl@0: test(t.ExitType()==EExitPanic); sl@0: test(t.ExitReason()==ECausedException); sl@0: CLOSE_AND_WAIT(t); sl@0: // sl@0: test.End(); sl@0: } sl@0: sl@0: extern TInt dividebyzeroFn(TInt x) sl@0: { sl@0: volatile int i=x, j=10; sl@0: volatile int l=j/i; sl@0: for (i=0; i>=1) sl@0: { sl@0: if (!(v&1)) sl@0: continue; sl@0: TUint32 mask = KRegValidBitsMask[i]; sl@0: TUint32 actual = aRegs[i] & mask; sl@0: TUint32 exp = (i == KPCIndex) ? aPC&mask : aExpected.iValues[i]; sl@0: if (actual != exp) sl@0: { sl@0: test.Printf(_L("%d: Expected %08x but got %08x\n"), i, exp, actual); sl@0: ok = EFalse; sl@0: } sl@0: } sl@0: test(ok); sl@0: } sl@0: sl@0: void testContext() sl@0: { sl@0: sl@0: TUint32 regs[32]; sl@0: sl@0: test.Next(_L("Get context of interrupted thread")); sl@0: TInt tn; sl@0: for (tn=0; tn