2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Runtime Library (RTL)
4 * FILE: lib/rtl/i386/except_asm.S
5 * PURPOSE: User-mode exception support for IA-32
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Stefan Ginsberg (stefan.ginsberg@reactos.org)
10 /* INCLUDES ******************************************************************/
15 EXTERN _RtlpCheckForActiveDebugger@0:PROC
16 EXTERN _RtlDispatchException@8:PROC
17 EXTERN _ZwContinue@8:PROC
18 EXTERN _ZwRaiseException@12:PROC
20 #define ExceptionContinueSearch 1
21 #define ExceptionNestedException 2
22 #define ExceptionCollidedUnwind 3
24 /* FUNCTIONS *****************************************************************/
28 PUBLIC _RtlpGetExceptionList@0
29 _RtlpGetExceptionList@0:
31 /* Return the exception list */
32 mov eax, fs:[TEB_EXCEPTION_LIST]
36 PUBLIC _RtlpSetExceptionList@4
37 _RtlpSetExceptionList@4:
39 /* Get the new list */
44 mov fs:[TEB_EXCEPTION_LIST], ecx
50 PUBLIC _RtlCaptureContext@4
53 /* Preserve EBX and put the context in it */
57 /* Save the basic register context */
58 mov [ebx+CONTEXT_EAX], eax
59 mov [ebx+CONTEXT_ECX], ecx
60 mov [ebx+CONTEXT_EDX], edx
62 mov [ebx+CONTEXT_EBX], eax
63 mov [ebx+CONTEXT_ESI], esi
64 mov [ebx+CONTEXT_EDI], edi
66 /* Capture the other regs */
70 PUBLIC _RtlpCaptureContext@4
71 _RtlpCaptureContext@4:
73 /* Preserve EBX and put the context in it */
77 /* Clear the basic register context */
78 mov dword ptr [ebx+CONTEXT_EAX], 0
79 mov dword ptr [ebx+CONTEXT_ECX], 0
80 mov dword ptr [ebx+CONTEXT_EDX], 0
81 mov dword ptr [ebx+CONTEXT_EBX], 0
82 mov dword ptr [ebx+CONTEXT_ESI], 0
83 mov dword ptr [ebx+CONTEXT_EDI], 0
86 /* Capture the segment registers */
87 mov [ebx+CONTEXT_SEGCS], cs
88 mov [ebx+CONTEXT_SEGDS], ds
89 mov [ebx+CONTEXT_SEGES], es
90 mov [ebx+CONTEXT_SEGFS], fs
91 mov [ebx+CONTEXT_SEGGS], gs
92 mov [ebx+CONTEXT_SEGSS], ss
96 pop [ebx+CONTEXT_EFLAGS]
98 /* The return address should be in [ebp+4] */
100 mov [ebx+CONTEXT_EIP], eax
104 mov [ebx+CONTEXT_EBP], eax
108 mov [ebx+CONTEXT_ESP], eax
110 /* Return to the caller */
115 PUBLIC _RtlpExecuteHandlerForException@20
116 _RtlpExecuteHandlerForException@20:
118 /* Copy the routine in EDX */
119 mov edx, offset _RtlpExceptionProtector
121 /* Jump to common routine */
122 jmp _RtlpExecuteHandler@20
125 PUBLIC _RtlpExecuteHandlerForUnwind@20
126 _RtlpExecuteHandlerForUnwind@20:
127 /* Copy the routine in EDX */
128 mov edx, offset _RtlpUnwindProtector
131 _RtlpExecuteHandler@20:
133 /* Save non-volatile */
138 /* Clear registers */
144 /* Call the 2nd-stage executer */
150 call _RtlpExecuteHandler2@20
152 /* Restore non-volatile */
159 PUBLIC _RtlpExecuteHandler2@20
160 _RtlpExecuteHandler2@20:
162 /* Set up stack frame */
169 /* Push handler address */
172 /* Push the exception list */
173 push [fs:TEB_EXCEPTION_LIST]
176 mov [fs:TEB_EXCEPTION_LIST], esp
178 /* Call the handler */
187 mov esp, [fs:TEB_EXCEPTION_LIST]
190 pop [fs:TEB_EXCEPTION_LIST]
192 /* Undo stack frame and return */
198 _RtlpExceptionProtector:
200 /* Assume we'll continue */
201 mov eax, ExceptionContinueSearch
203 /* Put the exception record in ECX and check the Flags */
205 test dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_FLAGS], EXCEPTION_UNWINDING + EXCEPTION_EXIT_UNWIND
208 /* Save the frame in ECX and Context in EDX */
212 /* Get the nested frame */
215 /* Set it as the dispatcher context */
218 /* Return nested exception */
219 mov eax, ExceptionNestedException
225 _RtlpUnwindProtector:
227 /* Assume we'll continue */
228 mov eax, ExceptionContinueSearch
230 /* Put the exception record in ECX and check the Flags */
232 test dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_FLAGS], EXCEPTION_UNWINDING + EXCEPTION_EXIT_UNWIND
235 /* Save the frame in ECX and Context in EDX */
239 /* Get the nested frame */
242 /* Set it as the dispatcher context */
245 /* Return collided unwind */
246 mov eax, ExceptionCollidedUnwind
252 PUBLIC _RtlRaiseException@4
253 _RtlRaiseException@4:
255 /* Set up stack frame */
260 * Save the context while preserving everything but ESP and EBP.
261 * This is vital because the caller will be restored with this context
262 * in case the execution is continued, which means we must not clobber
263 * the non-volatiles. We preserve the volatiles too because the context
264 * could get passed to a debugger.
266 lea esp, [esp-CONTEXT_FRAME_LENGTH]
268 call _RtlCaptureContext@4
270 /* Adjust ESP to account for the argument that was passed */
271 add dword ptr [esp+CONTEXT_ESP], 4
273 /* Save the exception address */
276 mov [eax+EXCEPTION_RECORD_EXCEPTION_ADDRESS], edx
278 /* Write the context flag */
279 mov dword ptr [esp+CONTEXT_FLAGS], CONTEXT_FULL
281 /* Check if user mode debugger is active */
282 call _RtlpCheckForActiveDebugger@0
286 /* Dispatch the exception */
289 call _RtlDispatchException@8
293 /* Continue, go back to previous context */
302 /* Raise an exception immediately */
307 call _ZwRaiseException@12
312 /* Raise the exception */
317 call _ZwRaiseException@12
321 /* If we returned, raise a status */
323 call _RtlRaiseStatus@4
326 PUBLIC _RtlRaiseStatus@4
329 /* Set up stack frame */
334 * Save the context while preserving everything but ESP and EBP.
335 * This is vital because the caller will be restored with this context
336 * in case the execution is continued, which means we must not clobber
337 * the non-volatiles. We preserve the volatiles too because the context
338 * could get passed to a debugger.
340 lea esp, [esp-CONTEXT_FRAME_LENGTH-EXCEPTION_RECORD_LENGTH]
342 call _RtlCaptureContext@4
344 /* Adjust ESP to account for the argument that was passed */
345 add dword ptr [esp+CONTEXT_ESP], 4
347 /* Set up the exception record */
348 lea ecx, [esp+CONTEXT_FRAME_LENGTH]
350 mov dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_CODE], eax
351 mov dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_FLAGS], EXCEPTION_NONCONTINUABLE
352 and dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_RECORD], 0
354 mov dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_ADDRESS], eax
355 and dword ptr [ecx+EXCEPTION_RECORD_NUMBER_PARAMETERS], 0
357 /* Write the context flag */
358 mov dword ptr [esp+CONTEXT_FLAGS], CONTEXT_FULL
360 /* Check if user mode debugger is active */
361 call _RtlpCheckForActiveDebugger@0
363 /* Restore ECX and jump if debugger is active */
364 lea ecx, [esp+CONTEXT_FRAME_LENGTH]
368 /* Dispatch the exception */
371 call _RtlDispatchException@8
373 /* Raise exception if we got here */
374 lea ecx, [esp+CONTEXT_FRAME_LENGTH]
379 call _ZwRaiseException@12
384 /* Raise an exception immediately */
389 call _ZwRaiseException@12
393 /* If we returned, raise a status */
395 call _RtlRaiseStatus@4