migrate substitution keywords to SVN
[reactos.git] / reactos / ntoskrnl / rtl / i386 / seh.s
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * PURPOSE: Runtime library exception support for IA-32
6 * FILE: ntoskrnl/rtl/i386/seh.s
7 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * NOTES: This file is shared with lib/msvcrt/except/seh.s.
9 * Please keep them in sync.
10 */
11
12 #define ExceptionContinueExecution 0
13 #define ExceptionContinueSearch 1
14 #define ExceptionNestedException 2
15 #define ExceptionCollidedUnwind 3
16
17 #define EXCEPTION_NONCONTINUABLE 0x01
18 #define EXCEPTION_UNWINDING 0x02
19 #define EXCEPTION_EXIT_UNWIND 0x04
20 #define EXCEPTION_STACK_INVALID 0x08
21 #define EXCEPTION_NESTED_CALL 0x10
22 #define EXCEPTION_TARGET_UNWIND 0x20
23 #define EXCEPTION_COLLIDED_UNWIND 0x40
24
25 #define EXCEPTION_UNWIND_MODE \
26 ( EXCEPTION_UNWINDING \
27 | EXCEPTION_EXIT_UNWIND \
28 | EXCEPTION_TARGET_UNWIND \
29 | EXCEPTION_COLLIDED_UNWIND)
30
31 #define EREC_CODE 0x00
32 #define EREC_FLAGS 0x04
33 #define EREC_RECORD 0x08
34 #define EREC_ADDRESS 0x0C
35 #define EREC_NUMPARAMS 0x10
36 #define EREC_INFO 0x14
37
38 #define TRYLEVEL_NONE -1
39 #define TRYLEVEL_INVALID -2
40
41 #define ER_STANDARDESP -0x08
42 #define ER_EPOINTERS -0x04
43 #define ER_PREVFRAME 0x00
44 #define ER_HANDLER 0x04
45 #define ER_SCOPETABLE 0x08
46 #define ER_TRYLEVEL 0x0C
47 #define ER_EBP 0x10
48
49 #define ST_TRYLEVEL 0x00
50 #define ST_FILTER 0x04
51 #define ST_HANDLER 0x08
52
53 #define CONTEXT_EDI 0x9C
54 #define CONTEXT_EBX 0xA4
55 #define CONTEXT_EIP 0xB8
56
57 .globl __local_unwind2
58 .globl __except_handler3
59
60 // EAX = value to print
61 _do_debug:
62 pushal
63 pushl %eax
64 call _MsvcrtDebug@4
65 popal
66 ret
67
68 #define LU2_TRYLEVEL 0x08
69 #define LU2_REGFRAME 0x04
70
71 //
72 // void
73 // _local_unwind2(PEXCEPTION_REGISTRATION RegistrationFrame,
74 // LONG TryLevel)
75 //
76 // Parameters:
77 // [EDX+08h] - PEXCEPTION_REGISTRATION RegistrationFrame
78 // [EDX+04h] - LONG TryLevel
79 // Registers:
80 // EBP - EBP of call frame we are unwinding
81 // Returns:
82 // Nothing
83 // Notes:
84 // Run all termination handlers for a call frame from the current
85 // try-level up to (but not including) the given stop try-level.
86 __local_unwind2:
87 // Setup our call frame so we can access parameters using EDX
88 //pushl %ebp
89 movl %esp, %edx
90
91 // FIXME: Setup an EXCEPTION_REGISTRATION entry to protect the
92 // unwinding in case something goes wrong
93
94 .lu2_next_scope:
95
96 // Keep a pointer to the exception registration in EBX
97 movl LU2_REGFRAME(%edx), %ebx
98
99 // If we have reached the end of the chain or we're asked to stop here
100 // by the caller then exit
101 movl ER_TRYLEVEL(%ebx), %eax
102
103 cmpl $-1, %eax
104 je .lu2_done
105
106 cmpl LU2_TRYLEVEL(%edx), %eax
107 je .lu2_done
108
109 // Keep a pointer to the scopetable in ESI
110 movl ER_SCOPETABLE(%ebx), %esi
111
112 // Compute the offset of the entry in the scopetable that describes
113 // the scope that is to be unwound. Put the offset in EDI.
114 movl ST_TRYLEVEL(%esi), %edi
115 lea (%edi, %edi, 2), %edi
116 shll $2, %edi
117 addl %esi, %edi
118
119 // If this is not a termination handler then skip it
120 cmpl $0, ST_FILTER(%edi)
121 jne .lu2_next_scope
122
123 // Save the previous try-level in the exception registration structure
124 movl ST_TRYLEVEL(%edi), %eax
125 movl %eax, ER_TRYLEVEL(%ebx)
126
127 // Fetch the address of the termination handler
128 movl ST_HANDLER(%edi), %eax
129
130 // Termination handlers may trash all registers so save the
131 // important ones and then call the handler
132 pushl %edx
133 call *%eax
134
135 // Get our base pointer back
136 popl %edx
137
138 jmp .lu2_next_scope
139
140 .lu2_done:
141
142 // FIXME: Tear down the EXCEPTION_REGISTRATION entry setup to protect
143 // the unwinding
144
145 //movl %esi, %esp
146 //popl %ebp
147 ret
148
149 #define EH3_DISPCONTEXT 0x14
150 #define EH3_CONTEXT 0x10
151 #define EH3_REGFRAME 0x0C
152 #define EH3_ERECORD 0x08
153
154 // Parameters:
155 // [ESP+14h] - PVOID DispatcherContext
156 // [ESP+10h] - PCONTEXT Context
157 // [ESP+0Ch] - PEXCEPTION_REGISTRATION RegistrationFrame
158 // [ESP+08h] - PEXCEPTION_RECORD ExceptionRecord
159 // Registers:
160 // Unknown
161 // Returns:
162 // EXCEPTION_DISPOSITION - How this handler handled the exception
163 // Notes:
164 // Try to find an exception handler that will handle the exception.
165 // Traverse the entries in the scopetable that is associated with the
166 // exception registration passed as a parameter to this function.
167 // If an exception handler that will handle the exception is found, it
168 // is called and this function never returns
169 __except_handler3:
170 // Setup our call frame so we can access parameters using EBP
171 pushl %ebp // Standard ESP in frame (considered part of EXCEPTION_REGISTRATION)
172 movl %esp, %ebp
173
174 // Don't trust the direction flag to be cleared
175 cld
176
177 // Either we're called to handle an exception or we're called to unwind
178 movl EH3_ERECORD(%ebp), %eax
179 testl $EXCEPTION_UNWIND_MODE, EREC_FLAGS(%eax)
180 jnz .eh3_unwind
181
182 // Keep a pointer to the exception registration in EBX
183 movl EH3_REGFRAME(%ebp), %ebx
184
185 // Build an EXCEPTION_POINTERS structure on the stack and store it's
186 // address in the EXCEPTION_REGISTRATION structure
187 movl EH3_CONTEXT(%esp), %eax
188 pushl %ebx // Registration frame
189 pushl %eax // Context
190 movl %esp, ER_EPOINTERS(%ebx) // Pointer to EXCEPTION_REGISTRATION on the stack
191
192 // Keep current try-level in EDI
193 movl ER_TRYLEVEL(%ebx), %edi
194
195 // Keep a pointer to the scopetable in ESI
196 movl ER_SCOPETABLE(%ebx), %esi
197
198 .eh3_next_scope:
199
200 // If we have reached the end of the chain then exit
201 cmpl $-1, %edi
202 je .eh3_search
203
204 // Compute the offset of the entry in the scopetable and store
205 // the absolute address in EAX
206 lea (%edi, %edi, 2), %eax
207 shll $2, %eax
208 addl %esi, %eax
209
210 // Fetch the address of the filter routine
211 movl ST_FILTER(%eax), %eax
212
213 // If this is a termination handler then skip it
214 cmpl $0, %eax
215 je .eh3_continue
216
217 // Filter routines may trash all registers so save the important
218 // ones before restoring the call frame ebp and calling the handler
219 pushl %ebp
220 pushl %edi // Stop try-level
221 lea ER_EBP(%ebx), %ebp
222 call *%eax
223 popl %edi // Stop try-level
224 popl %ebp
225
226 // Reload EBX with registration frame address
227 movl EH3_REGFRAME(%ebp), %ebx
228
229 // Be more flexible here by checking if the return value is less than
230 // zero, equal to zero, or larger than zero instead of the defined
231 // values:
232 // -1 (EXCEPTION_CONTINUE_EXECUTION)
233 // 0 (EXCEPTION_CONTINUE_SEARCH)
234 // +1 (EXCEPTION_EXECUTE_HANDLER)
235 orl %eax, %eax
236 jz .eh3_continue
237 js .eh3_dismiss
238
239 // Filter returned: EXCEPTION_EXECUTE_HANDLER
240
241 // Ask the OS to perform global unwinding.
242 pushl %edi // Save stop try-level
243 pushl %ebx // Save registration frame address
244 pushl %ebx // Registration frame address
245 call __global_unwind2
246 popl %eax // Remove parameter to __global_unwind2
247 popl %ebx // Restore registration frame address
248 popl %edi // Restore stop try-level
249
250 // Change the context structure so _except_finish is called in the
251 // correct context since we return ExceptionContinueExecution.
252 movl EH3_CONTEXT(%ebp), %eax
253
254 movl %edi, CONTEXT_EDI(%eax) // Stop try-level
255 movl %ebx, CONTEXT_EBX(%eax) // Registration frame address
256 movl $_except_finish, CONTEXT_EIP(%eax)
257
258 movl $ExceptionContinueExecution, %eax
259 jmp .eh3_return
260
261 // Filter returned: EXCEPTION_CONTINUE_SEARCH
262 .eh3_continue:
263
264 // Reload ESI because the filter routine may have trashed it
265 movl ER_SCOPETABLE(%ebx), %esi
266
267 // Go one try-level closer to the top
268 lea (%edi, %edi, 2), %edi
269 shll $2, %edi
270 addl %esi, %edi
271 movl ST_TRYLEVEL(%edi), %edi
272
273 jmp .eh3_next_scope
274
275 // Filter returned: EXCEPTION_CONTINUE_EXECUTION
276 // Continue execution like nothing happened
277 .eh3_dismiss:
278 movl $ExceptionContinueExecution, %eax
279 jmp .eh3_return
280
281 // Tell the OS to search for another handler that will handle the exception
282 .eh3_search:
283
284 movl $ExceptionContinueSearch, %eax
285 jmp .eh3_return
286
287 // Perform local unwinding
288 .eh3_unwind:
289
290 movl $ExceptionContinueSearch, %eax
291 testl $EXCEPTION_TARGET_UNWIND, EREC_FLAGS(%eax)
292 jnz .eh3_return
293
294 // Save some important registers
295 pushl %ebp
296
297 lea ER_EBP(%ebx), %ebp
298 pushl $-1
299 pushl %ebx
300 call __local_unwind2
301 addl $8, %esp
302
303 // Restore some important registers
304 popl %ebp
305
306 movl $ExceptionContinueSearch, %eax
307
308 // Get me out of here
309 .eh3_return:
310
311 movl %ebp, %esp
312 popl %ebp
313 ret
314
315 // Parameters:
316 // None
317 // Registers:
318 // EBX - Pointer to exception registration structure
319 // EDI - Stop try-level
320 // Returns:
321 // -
322 // Notes:
323 // -
324 _except_finish:
325
326 // Setup EBP for the exception handler. By doing this the exception
327 // handler can access local variables as normal
328 lea ER_EBP(%ebx), %ebp
329
330 // Save some important registers
331 pushl %ebp
332 pushl %ebx
333 pushl %edi
334
335 // Stop try-level
336 pushl %edi
337
338 // Pointer to exception registration structure
339 pushl %ebx
340 call __local_unwind2
341 addl $8, %esp
342
343 // Restore some important registers
344 popl %edi
345 popl %ebx
346 popl %ebp
347
348 // Keep a pointer to the scopetable in ESI
349 movl ER_SCOPETABLE(%ebx), %esi
350
351 // Compute the offset of the entry in the scopetable and store
352 // the absolute address in EDI
353 lea (%edi, %edi, 2), %edi
354 shll $2, %edi
355 addl %esi, %edi
356
357 // Set the current try-level to the previous try-level and call
358 // the exception handler
359 movl ST_TRYLEVEL(%edi), %eax
360 movl %eax, ER_TRYLEVEL(%ebx)
361 movl ST_HANDLER(%edi), %eax
362
363 call *%eax
364
365 // We should never get here
366 ret