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.
14 #define ExceptionContinueExecution 0
15 #define ExceptionContinueSearch 1
16 #define ExceptionNestedException 2
17 #define ExceptionCollidedUnwind 3
19 #define EXCEPTION_NONCONTINUABLE 0x01
20 #define EXCEPTION_UNWINDING 0x02
21 #define EXCEPTION_EXIT_UNWIND 0x04
22 #define EXCEPTION_STACK_INVALID 0x08
23 #define EXCEPTION_NESTED_CALL 0x10
24 #define EXCEPTION_TARGET_UNWIND 0x20
25 #define EXCEPTION_COLLIDED_UNWIND 0x40
27 #define EXCEPTION_UNWIND_MODE \
28 ( EXCEPTION_UNWINDING \
29 | EXCEPTION_EXIT_UNWIND \
30 | EXCEPTION_TARGET_UNWIND \
31 | EXCEPTION_COLLIDED_UNWIND)
33 #define EREC_CODE 0x00
34 #define EREC_FLAGS 0x04
35 #define EREC_RECORD 0x08
36 #define EREC_ADDRESS 0x0C
37 #define EREC_NUMPARAMS 0x10
38 #define EREC_INFO 0x14
40 #define TRYLEVEL_NONE -1
41 #define TRYLEVEL_INVALID -2
43 #define ER_STANDARDESP -0x08
44 #define ER_EPOINTERS -0x04
45 #define ER_PREVFRAME 0x00
46 #define ER_HANDLER 0x04
47 #define ER_SCOPETABLE 0x08
48 #define ER_TRYLEVEL 0x0C
51 #define ST_TRYLEVEL 0x00
52 #define ST_FILTER 0x04
53 #define ST_HANDLER 0x08
55 #define CONTEXT_EDI 0x9C
56 #define CONTEXT_EBX 0xA4
57 #define CONTEXT_EIP 0xB8
59 .globl __local_unwind2
60 .globl __except_handler3
62 // EAX = value to print
70 #define LU2_TRYLEVEL 0x08
71 #define LU2_REGFRAME 0x04
75 // _local_unwind2(PEXCEPTION_REGISTRATION RegistrationFrame,
79 // [EDX+08h] - PEXCEPTION_REGISTRATION RegistrationFrame
80 // [EDX+04h] - LONG TryLevel
82 // EBP - EBP of call frame we are unwinding
86 // Run all termination handlers for a call frame from the current
87 // try-level up to (but not including) the given stop try-level.
89 // Setup our call frame so we can access parameters using EDX
93 // FIXME: Setup an EXCEPTION_REGISTRATION entry to protect the
94 // unwinding in case something goes wrong
98 // Keep a pointer to the exception registration in EBX
99 movl LU2_REGFRAME(%edx), %ebx
101 // If we have reached the end of the chain or we're asked to stop here
102 // by the caller then exit
103 movl ER_TRYLEVEL(%ebx), %eax
108 cmpl LU2_TRYLEVEL(%edx), %eax
111 // Keep a pointer to the scopetable in ESI
112 movl ER_SCOPETABLE(%ebx), %esi
114 // Compute the offset of the entry in the scopetable that describes
115 // the scope that is to be unwound. Put the offset in EDI.
116 movl ST_TRYLEVEL(%esi), %edi
117 lea (%edi, %edi, 2), %edi
121 // If this is not a termination handler then skip it
122 cmpl $0, ST_FILTER(%edi)
125 // Save the previous try-level in the exception registration structure
126 movl ST_TRYLEVEL(%edi), %eax
127 movl %eax, ER_TRYLEVEL(%ebx)
129 // Fetch the address of the termination handler
130 movl ST_HANDLER(%edi), %eax
132 // Termination handlers may trash all registers so save the
133 // important ones and then call the handler
137 // Get our base pointer back
144 // FIXME: Tear down the EXCEPTION_REGISTRATION entry setup to protect
151 #define EH3_DISPCONTEXT 0x14
152 #define EH3_CONTEXT 0x10
153 #define EH3_REGFRAME 0x0C
154 #define EH3_ERECORD 0x08
157 // [ESP+14h] - PVOID DispatcherContext
158 // [ESP+10h] - PCONTEXT Context
159 // [ESP+0Ch] - PEXCEPTION_REGISTRATION RegistrationFrame
160 // [ESP+08h] - PEXCEPTION_RECORD ExceptionRecord
164 // EXCEPTION_DISPOSITION - How this handler handled the exception
166 // Try to find an exception handler that will handle the exception.
167 // Traverse the entries in the scopetable that is associated with the
168 // exception registration passed as a parameter to this function.
169 // If an exception handler that will handle the exception is found, it
170 // is called and this function never returns
172 // Setup our call frame so we can access parameters using EBP
173 pushl %ebp // Standard ESP in frame (considered part of EXCEPTION_REGISTRATION)
176 // Don't trust the direction flag to be cleared
179 // Either we're called to handle an exception or we're called to unwind
180 movl EH3_ERECORD(%ebp), %eax
181 testl $EXCEPTION_UNWIND_MODE, EREC_FLAGS(%eax)
184 // Keep a pointer to the exception registration in EBX
185 movl EH3_REGFRAME(%ebp), %ebx
187 // Build an EXCEPTION_POINTERS structure on the stack and store it's
188 // address in the EXCEPTION_REGISTRATION structure
189 movl EH3_CONTEXT(%esp), %eax
190 pushl %ebx // Registration frame
191 pushl %eax // Context
192 movl %esp, ER_EPOINTERS(%ebx) // Pointer to EXCEPTION_REGISTRATION on the stack
194 // Keep current try-level in EDI
195 movl ER_TRYLEVEL(%ebx), %edi
197 // Keep a pointer to the scopetable in ESI
198 movl ER_SCOPETABLE(%ebx), %esi
202 // If we have reached the end of the chain then exit
206 // Compute the offset of the entry in the scopetable and store
207 // the absolute address in EAX
208 lea (%edi, %edi, 2), %eax
212 // Fetch the address of the filter routine
213 movl ST_FILTER(%eax), %eax
215 // If this is a termination handler then skip it
219 // Filter routines may trash all registers so save the important
220 // ones before restoring the call frame ebp and calling the handler
222 pushl %edi // Stop try-level
223 lea ER_EBP(%ebx), %ebp
225 popl %edi // Stop try-level
228 // Reload EBX with registration frame address
229 movl EH3_REGFRAME(%ebp), %ebx
231 // Be more flexible here by checking if the return value is less than
232 // zero, equal to zero, or larger than zero instead of the defined
234 // -1 (EXCEPTION_CONTINUE_EXECUTION)
235 // 0 (EXCEPTION_CONTINUE_SEARCH)
236 // +1 (EXCEPTION_EXECUTE_HANDLER)
241 // Filter returned: EXCEPTION_EXECUTE_HANDLER
243 // Ask the OS to perform global unwinding.
244 pushl %edi // Save stop try-level
245 pushl %ebx // Save registration frame address
246 pushl %ebx // Registration frame address
247 call __global_unwind2
248 popl %eax // Remove parameter to __global_unwind2
249 popl %ebx // Restore registration frame address
250 popl %edi // Restore stop try-level
252 // Change the context structure so _except_finish is called in the
253 // correct context since we return ExceptionContinueExecution.
254 movl EH3_CONTEXT(%ebp), %eax
256 movl %edi, CONTEXT_EDI(%eax) // Stop try-level
257 movl %ebx, CONTEXT_EBX(%eax) // Registration frame address
258 movl $_except_finish, CONTEXT_EIP(%eax)
260 movl $ExceptionContinueExecution, %eax
263 // Filter returned: EXCEPTION_CONTINUE_SEARCH
266 // Reload ESI because the filter routine may have trashed it
267 movl ER_SCOPETABLE(%ebx), %esi
269 // Go one try-level closer to the top
270 lea (%edi, %edi, 2), %edi
273 movl ST_TRYLEVEL(%edi), %edi
277 // Filter returned: EXCEPTION_CONTINUE_EXECUTION
278 // Continue execution like nothing happened
280 movl $ExceptionContinueExecution, %eax
283 // Tell the OS to search for another handler that will handle the exception
286 movl $ExceptionContinueSearch, %eax
289 // Perform local unwinding
292 movl $ExceptionContinueSearch, %eax
293 testl $EXCEPTION_TARGET_UNWIND, EREC_FLAGS(%eax)
296 // Save some important registers
299 lea ER_EBP(%ebx), %ebp
305 // Restore some important registers
308 movl $ExceptionContinueSearch, %eax
310 // Get me out of here
320 // EBX - Pointer to exception registration structure
321 // EDI - Stop try-level
328 // Setup EBP for the exception handler. By doing this the exception
329 // handler can access local variables as normal
330 lea ER_EBP(%ebx), %ebp
332 // Save some important registers
340 // Pointer to exception registration structure
345 // Restore some important registers
350 // Keep a pointer to the scopetable in ESI
351 movl ER_SCOPETABLE(%ebx), %esi
353 // Compute the offset of the entry in the scopetable and store
354 // the absolute address in EDI
355 lea (%edi, %edi, 2), %edi
359 // Set the current try-level to the previous try-level and call
360 // the exception handler
361 movl ST_TRYLEVEL(%edi), %eax
362 movl %eax, ER_TRYLEVEL(%ebx)
363 movl ST_HANDLER(%edi), %eax
367 // We should never get here
370 .intel_syntax noprefix
371 .globl _RtlpGetStackLimits@8
372 _RtlpGetStackLimits@8:
374 /* Get the current thread */
375 mov eax, [fs:KPCR_CURRENT_THREAD]
377 /* Get the stack limits */
378 mov ecx, [eax+KTHREAD_STACK_LIMIT]
379 mov edx, [eax+KTHREAD_INITIAL_STACK]
380 sub edx, SIZEOF_FX_SAVE_AREA