1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/kernelhwsrv/kernel/eka/common/win32/seh.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,252 @@
1.4 +// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of the License "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +// e32\common\win32\seh.cpp
1.18 +//
1.19 +//
1.20 +
1.21 +#include "seh.h"
1.22 +
1.23 +// Fill in the blank types for TWin32SEHTrap
1.24 +#define __WIN32_SEH_TYPES_KNOWN__
1.25 +#define __UnknownWindowsType1 EXCEPTION_RECORD
1.26 +#define __UnknownWindowsType2 CONTEXT
1.27 +
1.28 +// Pretend we're tools to avoid clashes with Win32 headers
1.29 +#define __TOOLS__
1.30 +#define __IN_SEH_CPP__
1.31 +#include <e32cmn.h>
1.32 +#include <e32cmn_private.h>
1.33 +
1.34 +#include <emulator.h>
1.35 +
1.36 +#include <e32panic.h>
1.37 +GLREF_C void Panic(TCdtPanic);
1.38 +
1.39 +// magic value denoting the end of the SEH handler list
1.40 +static const TWin32SEHTrap* const KFencePost = (TWin32SEHTrap*)-1;
1.41 +
1.42 +//
1.43 +// Class TWin32SEHTrap
1.44 +//
1.45 +
1.46 +#ifdef __KERNEL_MODE__
1.47 +
1.48 +extern DWORD CallFinalSEHHandler(EXCEPTION_RECORD* aException, CONTEXT* aContext)
1.49 + {
1.50 + // Get the final SEH entry on the chain
1.51 + TWin32SEHTrap* finalHandler = TWin32SEHTrap::IterateForFinal();
1.52 +
1.53 + // Call the handler - ignoring return value
1.54 + (void)(*finalHandler->ExceptionHandler())(aException, finalHandler, aContext);
1.55 +
1.56 + // Explicitly tell Win32 the exception has been handled
1.57 + return ExceptionContinueExecution;
1.58 + }
1.59 +
1.60 +TWin32SEHTrap* TWin32SEHTrap::IterateForFinal()
1.61 + {
1.62 + TWin32SEHTrap* p = (TWin32SEHTrap*)Tib()->ExceptionList;
1.63 +
1.64 + // Iterate through the SEH chain to find the final SEH record that we wish to skip to
1.65 + for (; p && p!=KFencePost && p->iPrevExceptionRegistrationRecord!=KFencePost; p=p->iPrevExceptionRegistrationRecord)
1.66 + {}
1.67 + return p;
1.68 + }
1.69 +
1.70 +TWin32SEHExceptionHandler* TWin32SEHTrap::ExceptionHandler()
1.71 + {
1.72 + return iExceptionHandler;
1.73 + }
1.74 +
1.75 +#else // !__KERNEL_MODE__
1.76 +#include <u32exec.h>
1.77 +
1.78 +
1.79 +extern "C" void trap_check(TWin32SEHTrap* a)
1.80 + {
1.81 + TWin32SEHTrap* p = a->iPrevExceptionRegistrationRecord;
1.82 + if (p && p!=KFencePost && a->iExceptionHandler == p->iExceptionHandler && a->iExceptionHandler == &TWin32SEHTrap::ExceptionHandler)
1.83 + Exec::PushTrapFrame((TTrap*)p);
1.84 + else
1.85 + Exec::PushTrapFrame(0);
1.86 + }
1.87 +
1.88 +extern "C" void untrap_check()
1.89 + {
1.90 + // search back for consecutive TWin32SEHTrap and remember the second one
1.91 + TWin32SEHTrap* p = (TWin32SEHTrap*)Tib()->ExceptionList;
1.92 + TWin32SEHTrap* q = 0;
1.93 + TWin32SEHTrap* s = 0;
1.94 + if (p && p!=KFencePost)
1.95 + {
1.96 + for(;;)
1.97 + {
1.98 + q = p->iPrevExceptionRegistrationRecord;
1.99 + if (!q || q==KFencePost)
1.100 + break;
1.101 + if (p->iExceptionHandler == &TWin32SEHTrap::ExceptionHandler && q->iExceptionHandler == &TWin32SEHTrap::ExceptionHandler)
1.102 + {
1.103 + s = q;
1.104 + break;
1.105 + }
1.106 + p = q;
1.107 + }
1.108 + }
1.109 + Exec::PushTrapFrame((TTrap*)s);
1.110 + }
1.111 +
1.112 +// Use assembler to ensure no extra SEH frame is created by the compiler
1.113 +UEXPORT_C __NAKED__ void TWin32SEHTrap::Trap()
1.114 + {
1.115 + _asm mov eax, fs:[0]
1.116 + _asm mov [ecx], eax
1.117 + _asm mov fs:[0], ecx
1.118 + _asm push ecx
1.119 + _asm call trap_check
1.120 + _asm pop ecx
1.121 + _asm ret
1.122 + }
1.123 +
1.124 +extern "C" void panic_chain_corrupt()
1.125 + {
1.126 + Panic(EWin32SEHChainCorrupt);
1.127 + }
1.128 +
1.129 +// Use assembler to ensure no extra SEH frame is created by the compiler
1.130 +UEXPORT_C __NAKED__ void TWin32SEHTrap::UnTrap()
1.131 + {
1.132 + _asm mov eax, fs:[0]
1.133 + _asm cmp eax, ecx
1.134 + _asm ja untrap_0
1.135 + _asm jb untrap_error
1.136 + _asm mov eax, [ecx]
1.137 + _asm mov fs:[0], eax
1.138 + _asm xor eax, eax
1.139 + _asm mov [ecx], eax
1.140 + _asm call untrap_check
1.141 +untrap_0:
1.142 + _asm ret
1.143 +untrap_error:
1.144 + _asm jmp panic_chain_corrupt
1.145 + }
1.146 +
1.147 +UEXPORT_C TWin32SEHTrap::TWin32SEHTrap()
1.148 + : iPrevExceptionRegistrationRecord(NULL),
1.149 + iExceptionHandler(&ExceptionHandler)
1.150 + {
1.151 + }
1.152 +
1.153 +// Handler called whilst Win32 is walking the SEH chain
1.154 +DWORD TWin32SEHTrap::ExceptionHandler(EXCEPTION_RECORD* aException, TWin32SEHTrap* /*aRegistrationRecord*/, CONTEXT* aContext)
1.155 + {
1.156 + if (aException->ExceptionCode != EXCEPTION_MSCPP)
1.157 + {
1.158 + return Emulator::Win32SEHException(aException, aContext);
1.159 + }
1.160 + else
1.161 + {
1.162 + return ExceptionContinueSearch;
1.163 + }
1.164 + }
1.165 +
1.166 +#if defined(__LEAVE_EQUALS_THROW__) && defined(__WINS__)
1.167 +extern "C" TWin32SEHTrap* pop_trap_frame()
1.168 + {
1.169 + return (TWin32SEHTrap*)Exec::PopTrapFrame();
1.170 + }
1.171 +
1.172 +extern "C" void leave_end()
1.173 + {
1.174 + Exec::LeaveEnd();
1.175 + }
1.176 +
1.177 +
1.178 +EXPORT_C __NAKED__ TInt XLeaveException::GetReason() const
1.179 + {
1.180 + _asm push ecx
1.181 + _asm call pop_trap_frame
1.182 + _asm test eax, eax
1.183 + _asm jz no_nested_trap
1.184 +
1.185 + // eax points to TWin32SEHTrap to be restored
1.186 + // if current exception record is above eax on the stack just restore eax
1.187 + _asm cmp eax, esp
1.188 + _asm jbe nested_trap_error
1.189 + _asm mov edx, fs:[0]
1.190 + _asm cmp eax, edx
1.191 + _asm ja nested_trap_insert_in_middle
1.192 + _asm je no_nested_trap // we haven't been unwound after all
1.193 +
1.194 + // check we eventually reach current exception record from eax
1.195 + _asm mov ecx, eax
1.196 + _asm mov edx, [eax+4] // &TWin32SEHTrap::ExceptionHandler
1.197 +nested_trap_check:
1.198 + _asm mov ecx, [ecx]
1.199 + _asm cmp ecx, 0
1.200 + _asm jz nested_trap_error
1.201 + _asm cmp ecx, 0ffffffffh
1.202 + _asm jz nested_trap_error
1.203 + _asm cmp ecx, fs:[0]
1.204 + _asm jz nested_trap_check_ok
1.205 + _asm cmp edx, [ecx+4] // all intervening entries should be TWin32SEHTrap
1.206 + _asm jz nested_trap_check
1.207 + _asm jmp nested_trap_error
1.208 +
1.209 + // other SEH handlers have been added after we were unwound so we need to insert eax 'in the middle'
1.210 +nested_trap_insert_in_middle:
1.211 + _asm cmp eax, [edx]
1.212 + _asm je no_nested_trap // eax is still in the chain
1.213 + _asm jb nested_trap_insert_in_middle_found
1.214 + _asm mov edx, [edx]
1.215 + _asm jmp nested_trap_insert_in_middle
1.216 +
1.217 +nested_trap_insert_in_middle_found:
1.218 + _asm mov ecx, [edx] // first SEH above eax on stack
1.219 + _asm cmp ecx, 0ffffffffh
1.220 + _asm je nested_trap_error // reached end of SEH list
1.221 + _asm push edx
1.222 +
1.223 + // ECX should be reachable from EAX
1.224 + _asm mov edx, eax
1.225 +nested_trap_insert_in_middle_check:
1.226 + _asm mov edx, [edx]
1.227 + _asm cmp ecx, edx
1.228 + _asm je nested_trap_insert_in_middle_ok
1.229 + _asm cmp edx, 0ffffffffh
1.230 + _asm je nested_trap_error // reached end of SEH list
1.231 + _asm test edx, edx
1.232 + _asm jnz nested_trap_insert_in_middle_check
1.233 + _asm jmp nested_trap_error
1.234 +
1.235 +nested_trap_insert_in_middle_ok:
1.236 + _asm pop edx
1.237 + _asm mov [edx], eax // insert eax back into chain
1.238 + _asm jmp no_nested_trap
1.239 +
1.240 +nested_trap_check_ok:
1.241 + _asm mov fs:[0], eax // reinstall nested trap SEH handlers
1.242 +
1.243 +no_nested_trap:
1.244 + _asm call untrap_check // check for other nested TRAPs
1.245 + _asm call leave_end
1.246 + _asm pop ecx
1.247 + _asm mov eax, [ecx]XLeaveException.iR
1.248 + _asm ret
1.249 +
1.250 +nested_trap_error:
1.251 + _asm jmp panic_chain_corrupt
1.252 + }
1.253 +#endif // defined(__LEAVE_EQUALS_THROW__) && defined(__WINS__)
1.254 +
1.255 +#endif //__KERNEL_MODE__