3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS MSVCRT Runtime Library
5 * PURPOSE: Runtime library exception support for IA-32
6 * FILE: lib/msvcrt/except/seh.s
7 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * NOTES: This file is shared with ntoskrnl/rtl/i386/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 .globl __local_unwind2
58 .globl __except_handler3
61 // EAX = value to print
69 #define LU2_TRYLEVEL 0x08
70 #define LU2_REGFRAME 0x04
74 // _local_unwind2(PEXCEPTION_REGISTRATION RegistrationFrame,
78 // [EDX+08h] - PEXCEPTION_REGISTRATION RegistrationFrame
79 // [EDX+04h] - LONG TryLevel
81 // EBP - EBP of call frame we are unwinding
85 // Run all termination handlers for a call frame from the current
86 // try-level up to (but not including) the given stop try-level.
88 // Setup our call frame so we can access parameters using EDX
92 // FIXME: Setup an EXCEPTION_REGISTRATION entry to protect the
93 // unwinding in case something goes wrong
97 // Keep a pointer to the exception registration in EBX
98 movl LU2_REGFRAME(%edx), %ebx
100 // If we have reached the end of the chain or we're asked to stop here
101 // by the caller then exit
102 movl ER_TRYLEVEL(%ebx), %eax
107 cmpl LU2_TRYLEVEL(%edx), %eax
110 // Keep a pointer to the scopetable in ESI
111 movl ER_SCOPETABLE(%ebx), %esi
113 // Compute the offset of the entry in the scopetable that describes
114 // the scope that is to be unwound. Put the offset in EDI.
115 movl ST_TRYLEVEL(%esi), %edi
116 lea (%edi, %edi, 2), %edi
120 // If this is not a termination handler then skip it
121 cmpl $0, ST_FILTER(%edi)
124 // Save the previous try-level in the exception registration structure
125 movl ST_TRYLEVEL(%edi), %eax
126 movl %eax, ER_TRYLEVEL(%ebx)
128 // Fetch the address of the termination handler
129 movl ST_HANDLER(%edi), %eax
131 // Termination handlers may trash all registers so save the
132 // important ones and then call the handler
136 // Get our base pointer back
143 // FIXME: Tear down the EXCEPTION_REGISTRATION entry setup to protect
150 #define EH3_DISPCONTEXT 0x14
151 #define EH3_CONTEXT 0x10
152 #define EH3_REGFRAME 0x0C
153 #define EH3_ERECORD 0x08
156 // [ESP+14h] - PVOID DispatcherContext
157 // [ESP+10h] - PCONTEXT Context
158 // [ESP+0Ch] - PEXCEPTION_REGISTRATION RegistrationFrame
159 // [ESP+08h] - PEXCEPTION_RECORD ExceptionRecord
163 // EXCEPTION_DISPOSITION - How this handler handled the exception
165 // Try to find an exception handler that will handle the exception.
166 // Traverse the entries in the scopetable that is associated with the
167 // exception registration passed as a parameter to this function.
168 // If an exception handler that will handle the exception is found, it
169 // is called and this function never returns
171 // Setup our call frame so we can access parameters using EBP
172 pushl %ebp // Standard ESP in frame (considered part of EXCEPTION_REGISTRATION)
175 // Don't trust the direction flag to be cleared
178 // Either we're called to handle an exception or we're called to unwind
179 movl EH3_ERECORD(%ebp), %eax
180 testl $EXCEPTION_UNWIND_MODE, EREC_FLAGS(%eax)
183 // Keep a pointer to the exception registration in EBX
184 movl EH3_REGFRAME(%ebp), %ebx
186 // Build an EXCEPTION_POINTERS structure on the stack and store it's
187 // address in the EXCEPTION_REGISTRATION structure
188 movl EH3_CONTEXT(%esp), %eax
189 pushl %ebx // Registration frame
190 pushl %eax // Context
191 movl %esp, ER_EPOINTERS(%ebx) // Pointer to EXCEPTION_REGISTRATION on the stack
193 // Keep current try-level in EDI
194 movl ER_TRYLEVEL(%ebx), %edi
196 // Keep a pointer to the scopetable in ESI
197 movl ER_SCOPETABLE(%ebx), %esi
201 // If we have reached the end of the chain then exit
205 // Compute the offset of the entry in the scopetable and store
206 // the absolute address in EAX
207 lea (%edi, %edi, 2), %eax
211 // Fetch the address of the filter routine
212 movl ST_FILTER(%eax), %eax
214 // If this is a termination handler then skip it
218 // Filter routines may trash all registers so save the important
219 // ones before restoring the call frame ebp and calling the handler
221 pushl %edi // Stop try-level
222 lea ER_EBP(%ebx), %ebp
224 popl %edi // Stop try-level
227 // Reload EBX with registration frame address
228 movl EH3_REGFRAME(%ebp), %ebx
230 // Be more flexible here by checking if the return value is less than
231 // zero, equal to zero, or larger than zero instead of the defined
233 // -1 (EXCEPTION_CONTINUE_EXECUTION)
234 // 0 (EXCEPTION_CONTINUE_SEARCH)
235 // +1 (EXCEPTION_EXECUTE_HANDLER)
240 // Filter returned: EXCEPTION_EXECUTE_HANDLER
242 // Ask the OS to perform global unwinding.
243 pushl %edi // Save stop try-level
244 pushl %ebx // Save registration frame address
245 pushl %ebx // Registration frame address
246 call __global_unwind2
247 popl %eax // Remove parameter to __global_unwind2
248 popl %ebx // Restore registration frame address
249 popl %edi // Restore stop try-level
251 // Change the context structure so _except_finish is called in the
252 // correct context since we return ExceptionContinueExecution.
253 movl EH3_CONTEXT(%ebp), %eax
255 movl %edi, CONTEXT_EDI(%eax) // Stop try-level
256 movl %ebx, CONTEXT_EBX(%eax) // Registration frame address
257 movl $_except_finish, CONTEXT_EIP(%eax)
259 movl $ExceptionContinueExecution, %eax
262 // Filter returned: EXCEPTION_CONTINUE_SEARCH
265 // Reload ESI because the filter routine may have trashed it
266 movl ER_SCOPETABLE(%ebx), %esi
268 // Go one try-level closer to the top
269 lea (%edi, %edi, 2), %edi
272 movl ST_TRYLEVEL(%edi), %edi
276 // Filter returned: EXCEPTION_CONTINUE_EXECUTION
277 // Continue execution like nothing happened
279 movl $ExceptionContinueExecution, %eax
282 // Tell the OS to search for another handler that will handle the exception
285 movl $ExceptionContinueSearch, %eax
288 // Perform local unwinding
291 movl $ExceptionContinueSearch, %eax
292 testl $EXCEPTION_TARGET_UNWIND, EREC_FLAGS(%eax)
295 // Save some important registers
298 lea ER_EBP(%ebx), %ebp
304 // Restore some important registers
307 movl $ExceptionContinueSearch, %eax
309 // Get me out of here
319 // EBX - Pointer to exception registration structure
320 // EDI - Stop try-level
327 // Setup EBP for the exception handler. By doing this the exception
328 // handler can access local variables as normal
329 lea ER_EBP(%ebx), %ebp
331 // Save some important registers
339 // Pointer to exception registration structure
344 // Restore some important registers
349 // Keep a pointer to the scopetable in ESI
350 movl ER_SCOPETABLE(%ebx), %esi
352 // Compute the offset of the entry in the scopetable and store
353 // the absolute address in EDI
354 lea (%edi, %edi, 2), %edi
358 // Set the current try-level to the previous try-level and call
359 // the exception handler
360 movl ST_TRYLEVEL(%edi), %eax
361 movl %eax, ER_TRYLEVEL(%ebx)
362 movl ST_HANDLER(%edi), %eax
366 // We should never get here