diff -r 000000000000 -r 96e5fb8b040d kerneltest/e32test/debug/t_context.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/debug/t_context.cpp Thu Dec 17 09:24:54 2009 +0200 @@ -0,0 +1,615 @@ +// Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32test\debug\t_context.cpp +// Overview: +// Exercise kernel-side functions to get, set user-side context and +// kernel-side exception handlers. +// API Information: +// RBusLogicalChannel, DLogicalChannel. +// Details: +// - Load the context logical device driver, open user side handle to +// a LDD channel and check software exception scheme when handle is +// not created. +// - Check user-side handler called when kernel-side handler is not +// created and exception is handled as expected. +// - Make a synchronous Kernel Executive type request to logical channel +// for a specific functionality and check that it is as expected. +// - Check that kernel-side handler is not triggered by IsExceptionHandler +// method. +// - Test user-side, kernel-side handlers are as expected. +// - In the context of thread taking hardware exception with synchronous +// and asynchronous killing: +// - check context captured in hardware exception hook and +// context captured in RemoveThread hook are as expected. +// - In the context of thread taking software exception with synchronous +// and asynchronous killing: +// - check context captured in software exception hook and +// context captured in RemoveThread hook are as expected. +// - In the context of thread blocked on WFAR: +// - check context captured while thread is blocked, +// context can be modified while thread is blocked, +// context captured in RemoveThread hook are as expected. +// - In the context of thread killed after being pre-empted by interrupt +// while in user mode: +// - check context captured while thread is spinning, context can be +// modified while thread is blocked, context captured in RemoveThread +// hook are as expected. +// - Check whether heap has been corrupted by all the tests. +// - Check that the system doesn't crash when the context of a dead thread is +// set or retrieved. +// Platforms/Drives/Compatibility: +// Hardware (Automatic). +// Assumptions/Requirement/Pre-requisites: +// Failures and causes: +// Base Port information: +// +// + +#define __E32TEST_EXTENSION__ +#include +#include +#include +#include +#include +#include "d_context.h" +#include "context.h" + +enum TKillMode + { + ESynchronousKill, // thread kills itself in exception handler + EAsynchronousKill // thread suspends itself in exception handler and is killed by main thread + }; + +_LIT(KUserExecPanic, "USER-EXEC"); + +RTest test(_L("T_CONTEXT")); + +TInt KernelExcCount; // incremented when user-side exception handler called +TInt UserExcCount; // incremented when kernel-side exception handler called +TExcType LastUserExcType; // set by user-side exception handler when called + +RContextLdd Channel; + + +TInt CallDeviceDriverAndSpin(TAny* aExpected) + { + TArmRegSet* expectedContext = (TArmRegSet*)aExpected; + expectedContext->iR13 = Channel.SpinInKernel(EFalse); + Channel.SpinInKernel(ETrue); + return 0; + } + +TInt UserRaiseExceptionThread(TAny* aExcType) + { + TExcType e = static_cast(reinterpret_cast(aExcType)); + User::RaiseException(e); + return 0; + } + +TInt RThreadRaiseExceptionThread(TAny* aExcType) + { + TExcType e = static_cast(reinterpret_cast(aExcType)); + User::RaiseException(e); + return 0; + } + +void UserExceptionHandler(TExcType aType) + { + // Check kernel-side handler was called before user-side one + if (Channel.IsHooked() && KernelExcCount != 1) + User::Invariant(); // force failure in RaiseExceptionHarness() + + LastUserExcType = aType; + UserExcCount++; + User::Panic(KUserExecPanic, ECausedException); + } + +TInt UserTrapExceptionThread(TAny* aExcType) + { + TInt r = User::SetExceptionHandler(UserExceptionHandler, 0xFFFFFFFF); + if (r != KErrNone) + return 0; // force failure in RaiseExceptionHarness() + TExcType e = static_cast(reinterpret_cast(aExcType)); + User::RaiseException(e); + return 0; + } + +TInt NaturalDeathFunc(TAny*) + {// Don't do too much but be sure to complete. + return KErrNone; + } + + +void RaiseExceptionHarness(TThreadFunction aFn, TExcType aType) + { + RThread t; + TInt r = t.Create(_L("RaiseException"), aFn, KDefaultStackSize, NULL, + reinterpret_cast(aType)); + test(r == KErrNone); + + TRequestStatus s; + t.Logon(s); + TBool oldJitSetting = User::JustInTime(); + User::SetJustInTime(EFalse); + t.Resume(); + User::WaitForRequest(s); + User::SetJustInTime(oldJitSetting); + + test(t.ExitType() == EExitPanic); + test(t.ExitCategory() == KUserExecPanic); + test(t.ExitReason() == ECausedException); + CLOSE_AND_WAIT(t); + } + + +void TestSwExcNoHandlers() + { + test.Next(_L("Check software exception scheme when no handler")); + + RaiseExceptionHarness(UserRaiseExceptionThread, EExcGeneral); + RaiseExceptionHarness(RThreadRaiseExceptionThread, EExcGeneral); + } + +void TestUserSwExcHandlerAlone() + { + test.Next(_L("Check user-side handler called when no kernel-side handler")); + + UserExcCount = 0; + RaiseExceptionHarness(UserTrapExceptionThread, EExcIntegerDivideByZero); + test(LastUserExcType == EExcIntegerDivideByZero); + test(UserExcCount == 1); + } + +void TestUserAndKernelSwExcHandlers() + { + test.Next(_L("Check kernel-side exception handler")); + test.Start(_L("Check kernel-side handler called")); + + KernelExcCount = 0; + RaiseExceptionHarness(UserRaiseExceptionThread, EExcUserInterrupt); + test(KernelExcCount == 1); + test(Channel.LastException() == EExcUserInterrupt); + + KernelExcCount = 0; + RaiseExceptionHarness(RThreadRaiseExceptionThread, EExcIntegerDivideByZero); + test(KernelExcCount == 1); + test(Channel.LastException() == EExcIntegerDivideByZero); + + test.Next(_L("Check kernel-side handler not triggered by IsExceptionHandler()")); + + KernelExcCount = 0; + (void) User::IsExceptionHandled(EExcUserInterrupt); + test(KernelExcCount == 0); + + test.Next(_L("Check user-side + kernel-side handler")); + + UserExcCount = 0; + KernelExcCount = 0; + RaiseExceptionHarness(UserTrapExceptionThread, EExcIntegerDivideByZero); + test(LastUserExcType == EExcIntegerDivideByZero); + test(UserExcCount == 1); + test(KernelExcCount == 1); + test(Channel.LastException() == EExcIntegerDivideByZero); + + test.End(); + } + + +////////////////////////////////////////////////////////////////////////////// + +void DumpContext(const TDesC& aTitle, TArmRegSet& aContext) + { + test.Printf(_L("%S\n"), &aTitle); + test.Printf(_L(" r0 =%08x r1 =%08x r2 =%08x r3 =%08x\n"),aContext.iR0,aContext.iR1,aContext.iR2,aContext.iR3); + test.Printf(_L(" r4 =%08x r5 =%08x r6 =%08x r7 =%08x\n"),aContext.iR4,aContext.iR5,aContext.iR6,aContext.iR7); + test.Printf(_L(" r8 =%08x r9 =%08x r10=%08x r11=%08x\n"),aContext.iR8,aContext.iR9,aContext.iR10,aContext.iR11); + test.Printf(_L(" r12=%08x r13=%08x r14=%08x r15=%08x\n"),aContext.iR12,aContext.iR13,aContext.iR14,aContext.iR15); + test.Printf(_L(" cpsr=%08x dacr=%08x\n"),aContext.iFlags, aContext.iDacr); + } + +void ModifyContext(TArmRegSet& aContext) + { + TArmReg* end = (TArmReg*)(&aContext+1); + for (TArmReg* p = (TArmReg*)&aContext; p