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.
12 #define ExceptionContinueExecution 0
13 #define ExceptionContinueSearch 1
14 #define ExceptionNestedException 2
15 #define ExceptionCollidedUnwind 3
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
25 #define EXCEPTION_UNWIND_MODE \
26 ( EXCEPTION_UNWINDING \
27 | EXCEPTION_EXIT_UNWIND \
28 | EXCEPTION_TARGET_UNWIND \
29 | EXCEPTION_COLLIDED_UNWIND)
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
38 #define TRYLEVEL_NONE -1
39 #define TRYLEVEL_INVALID -2
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
49 #define ST_TRYLEVEL 0x00
50 #define ST_FILTER 0x04
51 #define ST_HANDLER 0x08
53 #define CONTEXT_EDI 0x9C
54 #define CONTEXT_EBX 0xA4
55 #define CONTEXT_EIP 0xB8
57 #define __local_unwind2 _local_unwind2 /* LIBCAPTIVE */
58 #define __except_handler3 _except_handler3 /* LIBCAPTIVE */
59 #define __global_unwind2 _global_unwind2 /* LIBCAPTIVE */
61 #if 0 /* LIBCAPTIVE */
62 .globl __local_unwind2
63 #endif /* LIBCAPTIVE */
64 .globl __except_handler3
66 #if 0 /* LIBCAPTIVE */
68 // EAX = value to print
76 #endif /* LIBCAPTIVE */
78 #define LU2_TRYLEVEL 0x08
79 #define LU2_REGFRAME 0x04
83 // _local_unwind2(PEXCEPTION_REGISTRATION RegistrationFrame,LONG TryLevel)
86 // [EDX+08h] - LONG TryLevel
87 // [EDX+04h] - PEXCEPTION_REGISTRATION RegistrationFrame
89 // EBP - EBP of call frame we are unwinding
93 // Run all termination handlers for a call frame from the current
94 // try-level up to (but not including) the given stop try-level.
97 // Setup our call frame so we can access parameters using EDX
101 // FIXME: Setup an EXCEPTION_REGISTRATION entry to protect the
102 // unwinding in case something goes wrong
106 // Keep a pointer to the exception registration in EBX
107 movl LU2_REGFRAME(%edx), %ebx
109 // If we have reached the end of the chain or we're asked to stop here
110 // by the caller then exit
111 movl ER_TRYLEVEL(%ebx), %eax
116 cmpl LU2_TRYLEVEL(%edx), %eax
119 // Keep a pointer to the scopetable in ESI
120 movl ER_SCOPETABLE(%ebx), %esi
122 // Compute the offset of the entry in the scopetable that describes
123 // the scope that is to be unwound. Put the offset in EDI.
124 movl ST_TRYLEVEL(%esi), %edi
125 lea (%edi, %edi, 2), %edi
129 // If this is not a termination handler then skip it
130 cmpl $0, ST_FILTER(%edi)
133 // Save the previous try-level in the exception registration structure
134 movl ST_TRYLEVEL(%edi), %eax
135 movl %eax, ER_TRYLEVEL(%ebx)
137 // Fetch the address of the termination handler
138 movl ST_HANDLER(%edi), %eax
140 // Termination handlers may trash all registers so save the
141 // important ones and then call the handler
145 // Get our base pointer back
152 // FIXME: Tear down the EXCEPTION_REGISTRATION entry setup to protect
160 #define EH3_DISPCONTEXT 0x14
161 #define EH3_CONTEXT 0x10
162 #define EH3_REGFRAME 0x0C
163 #define EH3_ERECORD 0x08
166 // [ESP+14h] - PVOID DispatcherContext
167 // [ESP+10h] - PCONTEXT Context
168 // [ESP+0Ch] - PEXCEPTION_REGISTRATION RegistrationFrame
169 // [ESP+08h] - PEXCEPTION_RECORD ExceptionRecord
173 // EXCEPTION_DISPOSITION - How this handler handled the exception
175 // Try to find an exception handler that will handle the exception.
176 // Traverse the entries in the scopetable that is associated with the
177 // exception registration passed as a parameter to this function.
178 // If an exception handler that will handle the exception is found, it
179 // is called and this function never returns
181 // Setup our call frame so we can access parameters using EBP
182 pushl %ebp // Standard ESP in frame (considered part of EXCEPTION_REGISTRATION)
184 pushl %ebx /* LIBCAPTIVE */
185 pushl %esi /* LIBCAPTIVE */
186 pushl %edi /* LIBCAPTIVE */
188 // Don't trust the direction flag to be cleared
191 // Keep a pointer to the exception registration in EBX
192 movl EH3_REGFRAME(%ebp), %ebx
194 // Either we're called to handle an exception or we're called to unwind
195 movl EH3_ERECORD(%ebp), %eax
196 testl $EXCEPTION_UNWIND_MODE, EREC_FLAGS(%eax)
199 // Build an EXCEPTION_POINTERS structure on the stack and store it's
200 // address in the EXCEPTION_REGISTRATION structure
201 movl EH3_CONTEXT(%ebp), %eax
202 pushl %ebx // Registration frame
203 pushl %eax // Context
204 movl %esp, ER_EPOINTERS(%ebx) // Pointer to EXCEPTION_REGISTRATION on the stack
206 // Keep current try-level in EDI
207 movl ER_TRYLEVEL(%ebx), %edi
209 // Keep a pointer to the scopetable in ESI
210 movl ER_SCOPETABLE(%ebx), %esi
214 // If we have reached the end of the chain then exit
218 // Compute the offset of the entry in the scopetable and store
219 // the absolute address in EAX
220 lea (%edi, %edi, 2), %eax
224 // Fetch the address of the filter routine
225 movl ST_FILTER(%eax), %eax
227 // If this is a termination handler then skip it
231 // Filter routines may trash all registers so save the important
232 // ones before restoring the call frame ebp and calling the handler
234 pushl %edi // Stop try-level
235 lea ER_EBP(%ebx), %ebp
237 popl %edi // Stop try-level
240 // Reload EBX with registration frame address
241 movl EH3_REGFRAME(%ebp), %ebx
243 // Be more flexible here by checking if the return value is less than
244 // zero, equal to zero, or larger than zero instead of the defined
246 // -1 (EXCEPTION_CONTINUE_EXECUTION)
247 // 0 (EXCEPTION_CONTINUE_SEARCH)
248 // +1 (EXCEPTION_EXECUTE_HANDLER)
253 // Filter returned: EXCEPTION_EXECUTE_HANDLER
255 // Ask the OS to perform global unwinding.
256 pushl %edi // Save stop try-level
257 pushl %ebx // Save registration frame address
258 pushl %ebx // Registration frame address
259 call __global_unwind2
260 popl %eax // Remove parameter to __global_unwind2
261 popl %ebx // Restore registration frame address
262 popl %edi // Restore stop try-level
264 // Change the context structure so _except_finish is called in the
265 // correct context since we return ExceptionContinueExecution.
266 #if 0 /* LIBCAPTIVE */
267 movl EH3_CONTEXT(%ebp), %eax
269 movl %edi, CONTEXT_EDI(%eax) // Stop try-level
270 movl %ebx, CONTEXT_EBX(%eax) // Registration frame address
271 movl $_except_finish, CONTEXT_EIP(%eax)
273 movl $ExceptionContinueExecution, %eax
275 #else /* !LIBCAPTIVE */
279 #endif /* LIBCAPTIVE */
281 // Filter returned: EXCEPTION_CONTINUE_SEARCH
284 // Reload ESI because the filter routine may have trashed it
285 movl ER_SCOPETABLE(%ebx), %esi
287 // Go one try-level closer to the top
288 lea (%edi, %edi, 2), %edi
291 movl ST_TRYLEVEL(%edi), %edi
295 // Filter returned: EXCEPTION_CONTINUE_EXECUTION
296 // Continue execution like nothing happened
298 movl $ExceptionContinueExecution, %eax
301 // Tell the OS to search for another handler that will handle the exception
304 movl $ExceptionContinueSearch, %eax
307 // Perform local unwinding
310 testl $EXCEPTION_TARGET_UNWIND, EREC_FLAGS(%eax)
311 movl $ExceptionContinueSearch, %eax
314 // Save some important registers
317 lea ER_EBP(%ebx), %ebp
321 #if 0 /* LIBCAPTIVE */
323 #else /* !LIBCAPTIVE */
324 .extern _local_unwind2_addr
325 movl _local_unwind2_addr,%eax
327 #endif /* LIBCAPTIVE */
331 // Restore some important registers
334 movl $ExceptionContinueSearch, %eax
336 // Get me out of here
339 lea -3*4(%ebp),%esp /* LIBCAPTIVE */
340 popl %edi /* LIBCAPTIVE */
341 popl %esi /* LIBCAPTIVE */
342 popl %ebx /* LIBCAPTIVE */
343 #if 0 /* LIBCAPTIVE */
345 #endif /* LIBCAPTIVE */
352 // EBX - Pointer to exception registration structure
353 // EDI - Stop try-level
360 // Setup EBP for the exception handler. By doing this the exception
361 // handler can access local variables as normal
362 lea ER_EBP(%ebx), %ebp
364 // Save some important registers
372 // Pointer to exception registration structure
375 #if 0 /* LIBCAPTIVE */
377 #else /* !LIBCAPTIVE */
378 .extern _local_unwind2_addr
379 movl _local_unwind2_addr,%eax
381 #endif /* LIBCAPTIVE */
385 // Restore some important registers
390 // Keep a pointer to the scopetable in ESI
391 movl ER_SCOPETABLE(%ebx), %esi
393 // Compute the offset of the entry in the scopetable and store
394 // the absolute address in EDI
395 lea (%edi, %edi, 2), %edi
399 // Set the current try-level to the previous try-level and call
400 // the exception handler
401 movl ST_TRYLEVEL(%edi), %eax
402 movl %eax, ER_TRYLEVEL(%ebx)
403 movl ST_HANDLER(%edi), %eax
407 // We should never get here