|
1 // Copyright (c) 2004-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 // e32\common\win32\seh.cpp |
|
15 // |
|
16 // |
|
17 |
|
18 #include "seh.h" |
|
19 |
|
20 // Fill in the blank types for TWin32SEHTrap |
|
21 #define __WIN32_SEH_TYPES_KNOWN__ |
|
22 #define __UnknownWindowsType1 EXCEPTION_RECORD |
|
23 #define __UnknownWindowsType2 CONTEXT |
|
24 |
|
25 // Pretend we're tools to avoid clashes with Win32 headers |
|
26 #define __TOOLS__ |
|
27 #define __IN_SEH_CPP__ |
|
28 #include <e32cmn.h> |
|
29 #include <e32cmn_private.h> |
|
30 |
|
31 #include <emulator.h> |
|
32 |
|
33 #include <e32panic.h> |
|
34 GLREF_C void Panic(TCdtPanic); |
|
35 |
|
36 // magic value denoting the end of the SEH handler list |
|
37 static const TWin32SEHTrap* const KFencePost = (TWin32SEHTrap*)-1; |
|
38 |
|
39 // |
|
40 // Class TWin32SEHTrap |
|
41 // |
|
42 |
|
43 #ifdef __KERNEL_MODE__ |
|
44 |
|
45 extern DWORD CallFinalSEHHandler(EXCEPTION_RECORD* aException, CONTEXT* aContext) |
|
46 { |
|
47 // Get the final SEH entry on the chain |
|
48 TWin32SEHTrap* finalHandler = TWin32SEHTrap::IterateForFinal(); |
|
49 |
|
50 // Call the handler - ignoring return value |
|
51 (void)(*finalHandler->ExceptionHandler())(aException, finalHandler, aContext); |
|
52 |
|
53 // Explicitly tell Win32 the exception has been handled |
|
54 return ExceptionContinueExecution; |
|
55 } |
|
56 |
|
57 TWin32SEHTrap* TWin32SEHTrap::IterateForFinal() |
|
58 { |
|
59 TWin32SEHTrap* p = (TWin32SEHTrap*)Tib()->ExceptionList; |
|
60 |
|
61 // Iterate through the SEH chain to find the final SEH record that we wish to skip to |
|
62 for (; p && p!=KFencePost && p->iPrevExceptionRegistrationRecord!=KFencePost; p=p->iPrevExceptionRegistrationRecord) |
|
63 {} |
|
64 return p; |
|
65 } |
|
66 |
|
67 TWin32SEHExceptionHandler* TWin32SEHTrap::ExceptionHandler() |
|
68 { |
|
69 return iExceptionHandler; |
|
70 } |
|
71 |
|
72 #else // !__KERNEL_MODE__ |
|
73 #include <u32exec.h> |
|
74 |
|
75 |
|
76 extern "C" void trap_check(TWin32SEHTrap* a) |
|
77 { |
|
78 TWin32SEHTrap* p = a->iPrevExceptionRegistrationRecord; |
|
79 if (p && p!=KFencePost && a->iExceptionHandler == p->iExceptionHandler && a->iExceptionHandler == &TWin32SEHTrap::ExceptionHandler) |
|
80 Exec::PushTrapFrame((TTrap*)p); |
|
81 else |
|
82 Exec::PushTrapFrame(0); |
|
83 } |
|
84 |
|
85 extern "C" void untrap_check() |
|
86 { |
|
87 // search back for consecutive TWin32SEHTrap and remember the second one |
|
88 TWin32SEHTrap* p = (TWin32SEHTrap*)Tib()->ExceptionList; |
|
89 TWin32SEHTrap* q = 0; |
|
90 TWin32SEHTrap* s = 0; |
|
91 if (p && p!=KFencePost) |
|
92 { |
|
93 for(;;) |
|
94 { |
|
95 q = p->iPrevExceptionRegistrationRecord; |
|
96 if (!q || q==KFencePost) |
|
97 break; |
|
98 if (p->iExceptionHandler == &TWin32SEHTrap::ExceptionHandler && q->iExceptionHandler == &TWin32SEHTrap::ExceptionHandler) |
|
99 { |
|
100 s = q; |
|
101 break; |
|
102 } |
|
103 p = q; |
|
104 } |
|
105 } |
|
106 Exec::PushTrapFrame((TTrap*)s); |
|
107 } |
|
108 |
|
109 // Use assembler to ensure no extra SEH frame is created by the compiler |
|
110 UEXPORT_C __NAKED__ void TWin32SEHTrap::Trap() |
|
111 { |
|
112 _asm mov eax, fs:[0] |
|
113 _asm mov [ecx], eax |
|
114 _asm mov fs:[0], ecx |
|
115 _asm push ecx |
|
116 _asm call trap_check |
|
117 _asm pop ecx |
|
118 _asm ret |
|
119 } |
|
120 |
|
121 extern "C" void panic_chain_corrupt() |
|
122 { |
|
123 Panic(EWin32SEHChainCorrupt); |
|
124 } |
|
125 |
|
126 // Use assembler to ensure no extra SEH frame is created by the compiler |
|
127 UEXPORT_C __NAKED__ void TWin32SEHTrap::UnTrap() |
|
128 { |
|
129 _asm mov eax, fs:[0] |
|
130 _asm cmp eax, ecx |
|
131 _asm ja untrap_0 |
|
132 _asm jb untrap_error |
|
133 _asm mov eax, [ecx] |
|
134 _asm mov fs:[0], eax |
|
135 _asm xor eax, eax |
|
136 _asm mov [ecx], eax |
|
137 _asm call untrap_check |
|
138 untrap_0: |
|
139 _asm ret |
|
140 untrap_error: |
|
141 _asm jmp panic_chain_corrupt |
|
142 } |
|
143 |
|
144 UEXPORT_C TWin32SEHTrap::TWin32SEHTrap() |
|
145 : iPrevExceptionRegistrationRecord(NULL), |
|
146 iExceptionHandler(&ExceptionHandler) |
|
147 { |
|
148 } |
|
149 |
|
150 // Handler called whilst Win32 is walking the SEH chain |
|
151 DWORD TWin32SEHTrap::ExceptionHandler(EXCEPTION_RECORD* aException, TWin32SEHTrap* /*aRegistrationRecord*/, CONTEXT* aContext) |
|
152 { |
|
153 if (aException->ExceptionCode != EXCEPTION_MSCPP) |
|
154 { |
|
155 return Emulator::Win32SEHException(aException, aContext); |
|
156 } |
|
157 else |
|
158 { |
|
159 return ExceptionContinueSearch; |
|
160 } |
|
161 } |
|
162 |
|
163 #if defined(__LEAVE_EQUALS_THROW__) && defined(__WINS__) |
|
164 extern "C" TWin32SEHTrap* pop_trap_frame() |
|
165 { |
|
166 return (TWin32SEHTrap*)Exec::PopTrapFrame(); |
|
167 } |
|
168 |
|
169 extern "C" void leave_end() |
|
170 { |
|
171 Exec::LeaveEnd(); |
|
172 } |
|
173 |
|
174 |
|
175 EXPORT_C __NAKED__ TInt XLeaveException::GetReason() const |
|
176 { |
|
177 _asm push ecx |
|
178 _asm call pop_trap_frame |
|
179 _asm test eax, eax |
|
180 _asm jz no_nested_trap |
|
181 |
|
182 // eax points to TWin32SEHTrap to be restored |
|
183 // if current exception record is above eax on the stack just restore eax |
|
184 _asm cmp eax, esp |
|
185 _asm jbe nested_trap_error |
|
186 _asm mov edx, fs:[0] |
|
187 _asm cmp eax, edx |
|
188 _asm ja nested_trap_insert_in_middle |
|
189 _asm je no_nested_trap // we haven't been unwound after all |
|
190 |
|
191 // check we eventually reach current exception record from eax |
|
192 _asm mov ecx, eax |
|
193 _asm mov edx, [eax+4] // &TWin32SEHTrap::ExceptionHandler |
|
194 nested_trap_check: |
|
195 _asm mov ecx, [ecx] |
|
196 _asm cmp ecx, 0 |
|
197 _asm jz nested_trap_error |
|
198 _asm cmp ecx, 0ffffffffh |
|
199 _asm jz nested_trap_error |
|
200 _asm cmp ecx, fs:[0] |
|
201 _asm jz nested_trap_check_ok |
|
202 _asm cmp edx, [ecx+4] // all intervening entries should be TWin32SEHTrap |
|
203 _asm jz nested_trap_check |
|
204 _asm jmp nested_trap_error |
|
205 |
|
206 // other SEH handlers have been added after we were unwound so we need to insert eax 'in the middle' |
|
207 nested_trap_insert_in_middle: |
|
208 _asm cmp eax, [edx] |
|
209 _asm je no_nested_trap // eax is still in the chain |
|
210 _asm jb nested_trap_insert_in_middle_found |
|
211 _asm mov edx, [edx] |
|
212 _asm jmp nested_trap_insert_in_middle |
|
213 |
|
214 nested_trap_insert_in_middle_found: |
|
215 _asm mov ecx, [edx] // first SEH above eax on stack |
|
216 _asm cmp ecx, 0ffffffffh |
|
217 _asm je nested_trap_error // reached end of SEH list |
|
218 _asm push edx |
|
219 |
|
220 // ECX should be reachable from EAX |
|
221 _asm mov edx, eax |
|
222 nested_trap_insert_in_middle_check: |
|
223 _asm mov edx, [edx] |
|
224 _asm cmp ecx, edx |
|
225 _asm je nested_trap_insert_in_middle_ok |
|
226 _asm cmp edx, 0ffffffffh |
|
227 _asm je nested_trap_error // reached end of SEH list |
|
228 _asm test edx, edx |
|
229 _asm jnz nested_trap_insert_in_middle_check |
|
230 _asm jmp nested_trap_error |
|
231 |
|
232 nested_trap_insert_in_middle_ok: |
|
233 _asm pop edx |
|
234 _asm mov [edx], eax // insert eax back into chain |
|
235 _asm jmp no_nested_trap |
|
236 |
|
237 nested_trap_check_ok: |
|
238 _asm mov fs:[0], eax // reinstall nested trap SEH handlers |
|
239 |
|
240 no_nested_trap: |
|
241 _asm call untrap_check // check for other nested TRAPs |
|
242 _asm call leave_end |
|
243 _asm pop ecx |
|
244 _asm mov eax, [ecx]XLeaveException.iR |
|
245 _asm ret |
|
246 |
|
247 nested_trap_error: |
|
248 _asm jmp panic_chain_corrupt |
|
249 } |
|
250 #endif // defined(__LEAVE_EQUALS_THROW__) && defined(__WINS__) |
|
251 |
|
252 #endif //__KERNEL_MODE__ |