xref: /reactos/sdk/lib/rtl/i386/except_asm.s (revision 4dedc8ff)
1c2c66affSColin Finck/*
2c2c66affSColin Finck * COPYRIGHT:       See COPYING in the top level directory
3c2c66affSColin Finck * PROJECT:         ReactOS Runtime Library (RTL)
4c2c66affSColin Finck * FILE:            lib/rtl/i386/except_asm.s
5c2c66affSColin Finck * PURPOSE:         User-mode exception support for IA-32
6c2c66affSColin Finck * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
7c2c66affSColin Finck *                  Stefan Ginsberg (stefan.ginsberg@reactos.org)
8c2c66affSColin Finck */
9c2c66affSColin Finck
10c2c66affSColin Finck/* INCLUDES ******************************************************************/
11c2c66affSColin Finck
12c2c66affSColin Finck#include <asm.inc>
13c2c66affSColin Finck#include <ks386.inc>
14c2c66affSColin Finck
15c2c66affSColin FinckEXTERN _RtlpCheckForActiveDebugger@0:PROC
16c2c66affSColin FinckEXTERN _RtlDispatchException@8:PROC
17c2c66affSColin FinckEXTERN _ZwContinue@8:PROC
18c2c66affSColin FinckEXTERN _ZwRaiseException@12:PROC
19c2c66affSColin Finck
20c2c66affSColin Finck#define ExceptionContinueSearch     1
21c2c66affSColin Finck#define ExceptionNestedException    2
22c2c66affSColin Finck#define ExceptionCollidedUnwind     3
23c2c66affSColin Finck
24c2c66affSColin Finck/* FUNCTIONS *****************************************************************/
25c2c66affSColin Finck
26c2c66affSColin Finck.code
27c2c66affSColin Finck
28c2c66affSColin FinckPUBLIC _RtlpGetExceptionList@0
29c2c66affSColin Finck_RtlpGetExceptionList@0:
30c2c66affSColin Finck
31c2c66affSColin Finck    /* Return the exception list */
32c2c66affSColin Finck    mov eax, fs:[TEB_EXCEPTION_LIST]
33c2c66affSColin Finck    ret
34c2c66affSColin Finck
35c2c66affSColin Finck
36c2c66affSColin FinckPUBLIC _RtlpSetExceptionList@4
37c2c66affSColin Finck_RtlpSetExceptionList@4:
38c2c66affSColin Finck
39c2c66affSColin Finck    /* Get the new list */
40c2c66affSColin Finck    mov ecx, [esp+4]
41c2c66affSColin Finck    mov ecx, [ecx]
42c2c66affSColin Finck
43c2c66affSColin Finck    /* Write it */
44c2c66affSColin Finck    mov fs:[TEB_EXCEPTION_LIST], ecx
45c2c66affSColin Finck
46c2c66affSColin Finck    /* Return */
47c2c66affSColin Finck    ret 4
48c2c66affSColin Finck
49c2c66affSColin Finck
50c2c66affSColin FinckPUBLIC _RtlCaptureContext@4
51c2c66affSColin Finck_RtlCaptureContext@4:
52c2c66affSColin Finck
53c2c66affSColin Finck    /* Preserve EBX and put the context in it */
54c2c66affSColin Finck    push ebx
55c2c66affSColin Finck    mov ebx, [esp+8]
56c2c66affSColin Finck
57c2c66affSColin Finck    /* Save the basic register context */
58c2c66affSColin Finck    mov [ebx+CONTEXT_EAX], eax
59c2c66affSColin Finck    mov [ebx+CONTEXT_ECX], ecx
60c2c66affSColin Finck    mov [ebx+CONTEXT_EDX], edx
61c2c66affSColin Finck    mov eax, [esp]
62c2c66affSColin Finck    mov [ebx+CONTEXT_EBX], eax
63c2c66affSColin Finck    mov [ebx+CONTEXT_ESI], esi
64c2c66affSColin Finck    mov [ebx+CONTEXT_EDI], edi
65c2c66affSColin Finck
66c2c66affSColin Finck    /* Capture the other regs */
67c2c66affSColin Finck    jmp CaptureRest
68c2c66affSColin Finck
69c2c66affSColin Finck
70c2c66affSColin FinckPUBLIC _RtlpCaptureContext@4
71c2c66affSColin Finck_RtlpCaptureContext@4:
72c2c66affSColin Finck
73c2c66affSColin Finck    /* Preserve EBX and put the context in it */
74c2c66affSColin Finck    push ebx
75c2c66affSColin Finck    mov ebx, [esp+8]
76c2c66affSColin Finck
77c2c66affSColin Finck    /* Clear the basic register context */
78c2c66affSColin Finck    mov dword ptr [ebx+CONTEXT_EAX], 0
79c2c66affSColin Finck    mov dword ptr [ebx+CONTEXT_ECX], 0
80c2c66affSColin Finck    mov dword ptr [ebx+CONTEXT_EDX], 0
81c2c66affSColin Finck    mov dword ptr [ebx+CONTEXT_EBX], 0
82c2c66affSColin Finck    mov dword ptr [ebx+CONTEXT_ESI], 0
83c2c66affSColin Finck    mov dword ptr [ebx+CONTEXT_EDI], 0
84c2c66affSColin Finck
85c2c66affSColin FinckCaptureRest:
86c2c66affSColin Finck    /* Capture the segment registers */
87c2c66affSColin Finck    mov [ebx+CONTEXT_SEGCS], cs
88c2c66affSColin Finck    mov [ebx+CONTEXT_SEGDS], ds
89c2c66affSColin Finck    mov [ebx+CONTEXT_SEGES], es
90c2c66affSColin Finck    mov [ebx+CONTEXT_SEGFS], fs
91c2c66affSColin Finck    mov [ebx+CONTEXT_SEGGS], gs
92c2c66affSColin Finck    mov [ebx+CONTEXT_SEGSS], ss
93c2c66affSColin Finck
94c2c66affSColin Finck    /* Capture flags */
95c2c66affSColin Finck    pushfd
96c2c66affSColin Finck    pop [ebx+CONTEXT_EFLAGS]
97c2c66affSColin Finck
98c2c66affSColin Finck    /* The return address should be in [ebp+4] */
99c2c66affSColin Finck    mov eax, [ebp+4]
100c2c66affSColin Finck    mov [ebx+CONTEXT_EIP], eax
101c2c66affSColin Finck
102c2c66affSColin Finck    /* Get EBP */
103c2c66affSColin Finck    mov eax, [ebp+0]
104c2c66affSColin Finck    mov [ebx+CONTEXT_EBP], eax
105c2c66affSColin Finck
106c2c66affSColin Finck    /* And get ESP */
107c2c66affSColin Finck    lea eax, [ebp+8]
108c2c66affSColin Finck    mov [ebx+CONTEXT_ESP], eax
109c2c66affSColin Finck
110c2c66affSColin Finck    /* Return to the caller */
111c2c66affSColin Finck    pop ebx
112c2c66affSColin Finck    ret 4
113c2c66affSColin Finck
114c2c66affSColin Finck
115c2c66affSColin FinckPUBLIC _RtlpExecuteHandlerForException@20
116c2c66affSColin Finck_RtlpExecuteHandlerForException@20:
117c2c66affSColin Finck
118c2c66affSColin Finck    /* Copy the routine in EDX */
119c2c66affSColin Finck    mov edx, offset _RtlpExceptionProtector
120c2c66affSColin Finck
121c2c66affSColin Finck    /* Jump to common routine */
122c2c66affSColin Finck    jmp _RtlpExecuteHandler@20
123c2c66affSColin Finck
124c2c66affSColin Finck
125c2c66affSColin FinckPUBLIC _RtlpExecuteHandlerForUnwind@20
126c2c66affSColin Finck_RtlpExecuteHandlerForUnwind@20:
127c2c66affSColin Finck    /* Copy the routine in EDX */
128c2c66affSColin Finck    mov edx, offset _RtlpUnwindProtector
129c2c66affSColin Finck
130c2c66affSColin Finck
131*4dedc8ffSThomas Faber.PROC _RtlpExecuteHandler@20
132*4dedc8ffSThomas Faber    FPO 0, 0, 0, 0, 0, FRAME_FPO
133c2c66affSColin Finck
134c2c66affSColin Finck    /* Save non-volatile */
135c2c66affSColin Finck    push ebx
136c2c66affSColin Finck    push esi
137c2c66affSColin Finck    push edi
138c2c66affSColin Finck
139c2c66affSColin Finck    /* Clear registers */
140c2c66affSColin Finck    xor eax, eax
141c2c66affSColin Finck    xor ebx, ebx
142c2c66affSColin Finck    xor esi, esi
143c2c66affSColin Finck    xor edi, edi
144c2c66affSColin Finck
145c2c66affSColin Finck    /* Call the 2nd-stage executer */
146c2c66affSColin Finck    push [esp+32]
147c2c66affSColin Finck    push [esp+32]
148c2c66affSColin Finck    push [esp+32]
149c2c66affSColin Finck    push [esp+32]
150c2c66affSColin Finck    push [esp+32]
151c2c66affSColin Finck    call _RtlpExecuteHandler2@20
152c2c66affSColin Finck
153c2c66affSColin Finck    /* Restore non-volatile */
154c2c66affSColin Finck    pop edi
155c2c66affSColin Finck    pop esi
156c2c66affSColin Finck    pop ebx
157c2c66affSColin Finck    ret 20
158c2c66affSColin Finck
159*4dedc8ffSThomas Faber.ENDP
160c2c66affSColin Finck
161c2c66affSColin FinckPUBLIC _RtlpExecuteHandler2@20
162c2c66affSColin Finck_RtlpExecuteHandler2@20:
163c2c66affSColin Finck
164c2c66affSColin Finck    /* Set up stack frame */
165c2c66affSColin Finck    push ebp
166c2c66affSColin Finck    mov ebp, esp
167c2c66affSColin Finck
168c2c66affSColin Finck    /* Save the Frame */
169c2c66affSColin Finck    push [ebp+12]
170c2c66affSColin Finck
171c2c66affSColin Finck    /* Push handler address */
172c2c66affSColin Finck    push edx
173c2c66affSColin Finck
174c2c66affSColin Finck    /* Push the exception list */
175c2c66affSColin Finck    push [fs:TEB_EXCEPTION_LIST]
176c2c66affSColin Finck
177c2c66affSColin Finck    /* Link us to it */
178c2c66affSColin Finck    mov [fs:TEB_EXCEPTION_LIST], esp
179c2c66affSColin Finck
180c2c66affSColin Finck    /* Call the handler */
181c2c66affSColin Finck    push [ebp+20]
182c2c66affSColin Finck    push [ebp+16]
183c2c66affSColin Finck    push [ebp+12]
184c2c66affSColin Finck    push [ebp+8]
185c2c66affSColin Finck    mov ecx, [ebp+24]
186c2c66affSColin Finck    call ecx
187c2c66affSColin Finck
188c2c66affSColin Finck    /* Unlink us */
189c2c66affSColin Finck    mov esp, [fs:TEB_EXCEPTION_LIST]
190c2c66affSColin Finck
191c2c66affSColin Finck    /* Restore it */
192c2c66affSColin Finck    pop [fs:TEB_EXCEPTION_LIST]
193c2c66affSColin Finck
194c2c66affSColin Finck    /* Undo stack frame and return */
195c2c66affSColin Finck    mov esp, ebp
196c2c66affSColin Finck    pop ebp
197c2c66affSColin Finck    ret 20
198c2c66affSColin Finck
199c2c66affSColin Finck
200c2c66affSColin Finck_RtlpExceptionProtector:
201c2c66affSColin Finck
202c2c66affSColin Finck    /* Assume we'll continue */
203c2c66affSColin Finck    mov eax, ExceptionContinueSearch
204c2c66affSColin Finck
205c2c66affSColin Finck    /* Put the exception record in ECX and check the Flags */
206c2c66affSColin Finck    mov ecx, [esp+4]
207c2c66affSColin Finck    test dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_FLAGS], EXCEPTION_UNWINDING + EXCEPTION_EXIT_UNWIND
208c2c66affSColin Finck    jnz return
209c2c66affSColin Finck
210c2c66affSColin Finck    /* Save the frame in ECX and Context in EDX */
211c2c66affSColin Finck    mov ecx, [esp+8]
212c2c66affSColin Finck    mov edx, [esp+16]
213c2c66affSColin Finck
214c2c66affSColin Finck    /* Get the nested frame */
215c2c66affSColin Finck    mov eax, [ecx+8]
216c2c66affSColin Finck
217c2c66affSColin Finck    /* Set it as the dispatcher context */
218c2c66affSColin Finck    mov [edx], eax
219c2c66affSColin Finck
220c2c66affSColin Finck    /* Return nested exception */
221c2c66affSColin Finck    mov eax, ExceptionNestedException
222c2c66affSColin Finck
223c2c66affSColin Finckreturn:
224c2c66affSColin Finck    ret 16
225c2c66affSColin Finck
226c2c66affSColin Finck
227c2c66affSColin Finck_RtlpUnwindProtector:
228c2c66affSColin Finck
229c2c66affSColin Finck    /* Assume we'll continue */
230c2c66affSColin Finck    mov eax, ExceptionContinueSearch
231c2c66affSColin Finck
232c2c66affSColin Finck    /* Put the exception record in ECX and check the Flags */
233c2c66affSColin Finck    mov ecx, [esp+4]
234c2c66affSColin Finck    test dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_FLAGS], EXCEPTION_UNWINDING + EXCEPTION_EXIT_UNWIND
235c2c66affSColin Finck    jz .return
236c2c66affSColin Finck
237c2c66affSColin Finck    /* Save the frame in ECX and Context in EDX */
238c2c66affSColin Finck    mov ecx, [esp+8]
239c2c66affSColin Finck    mov edx, [esp+16]
240c2c66affSColin Finck
241c2c66affSColin Finck    /* Get the nested frame */
242c2c66affSColin Finck    mov eax, [ecx+8]
243c2c66affSColin Finck
244c2c66affSColin Finck    /* Set it as the dispatcher context */
245c2c66affSColin Finck    mov [edx], eax
246c2c66affSColin Finck
247c2c66affSColin Finck    /* Return collided unwind */
248c2c66affSColin Finck    mov eax, ExceptionCollidedUnwind
249c2c66affSColin Finck
250c2c66affSColin Finck.return:
251c2c66affSColin Finck    ret 16
252c2c66affSColin Finck
253c2c66affSColin Finck
254c2c66affSColin FinckPUBLIC _RtlRaiseException@4
255c2c66affSColin Finck_RtlRaiseException@4:
256c2c66affSColin Finck
257c2c66affSColin Finck    /* Set up stack frame */
258c2c66affSColin Finck    push ebp
259c2c66affSColin Finck    mov ebp, esp
260c2c66affSColin Finck
261c2c66affSColin Finck    /*
262c2c66affSColin Finck     * Save the context while preserving everything but ESP and EBP.
263c2c66affSColin Finck     * This is vital because the caller will be restored with this context
264c2c66affSColin Finck     * in case the execution is continued, which means we must not clobber
265c2c66affSColin Finck     * the non-volatiles. We preserve the volatiles too because the context
266c2c66affSColin Finck     * could get passed to a debugger.
267c2c66affSColin Finck     */
268c2c66affSColin Finck    lea esp, [esp-CONTEXT_FRAME_LENGTH]
269c2c66affSColin Finck    push esp
270c2c66affSColin Finck    call _RtlCaptureContext@4
271c2c66affSColin Finck
272c2c66affSColin Finck    /* Adjust ESP to account for the argument that was passed */
273c2c66affSColin Finck    add dword ptr [esp+CONTEXT_ESP], 4
274c2c66affSColin Finck
275c2c66affSColin Finck    /* Save the exception address */
276c2c66affSColin Finck    mov edx, [ebp+4]
277c2c66affSColin Finck    mov eax, [ebp+8]
278c2c66affSColin Finck    mov [eax+EXCEPTION_RECORD_EXCEPTION_ADDRESS], edx
279c2c66affSColin Finck
280c2c66affSColin Finck    /* Write the context flag */
281c2c66affSColin Finck    mov dword ptr [esp+CONTEXT_FLAGS], CONTEXT_FULL
282c2c66affSColin Finck
283c2c66affSColin Finck    /* Check if user mode debugger is active */
284c2c66affSColin Finck    call _RtlpCheckForActiveDebugger@0
285c2c66affSColin Finck    test al, al
286c2c66affSColin Finck    jnz DebuggerActive1
287c2c66affSColin Finck
288c2c66affSColin Finck    /* Dispatch the exception */
289c2c66affSColin Finck    push esp
290c2c66affSColin Finck    push [ebp+8]
291c2c66affSColin Finck    call _RtlDispatchException@8
292c2c66affSColin Finck    test al, al
293c2c66affSColin Finck    jz RaiseException
294c2c66affSColin Finck
295c2c66affSColin Finck    /* Continue, go back to previous context */
296c2c66affSColin Finck    mov ecx, esp
297c2c66affSColin Finck    push 0
298c2c66affSColin Finck    push ecx
299c2c66affSColin Finck    call  _ZwContinue@8
300c2c66affSColin Finck    jmp RaiseStatus1
301c2c66affSColin Finck
302c2c66affSColin FinckDebuggerActive1:
303c2c66affSColin Finck
304c2c66affSColin Finck    /* Raise an exception immediately */
305c2c66affSColin Finck    mov ecx, esp
306c2c66affSColin Finck    push 1
307c2c66affSColin Finck    push ecx
308c2c66affSColin Finck    push [ebp+8]
309c2c66affSColin Finck    call _ZwRaiseException@12
310c2c66affSColin Finck    jmp RaiseStatus1
311c2c66affSColin Finck
312c2c66affSColin FinckRaiseException:
313c2c66affSColin Finck
314c2c66affSColin Finck    /* Raise the exception */
315c2c66affSColin Finck    mov ecx, esp
316c2c66affSColin Finck    push 0
317c2c66affSColin Finck    push ecx
318c2c66affSColin Finck    push [ebp+8]
319c2c66affSColin Finck    call _ZwRaiseException@12
320c2c66affSColin Finck
321c2c66affSColin FinckRaiseStatus1:
322c2c66affSColin Finck
323c2c66affSColin Finck    /* If we returned, raise a status */
324c2c66affSColin Finck    push eax
325c2c66affSColin Finck    call _RtlRaiseStatus@4
326c2c66affSColin Finck
327c2c66affSColin Finck
328c2c66affSColin FinckPUBLIC _RtlRaiseStatus@4
329c2c66affSColin Finck_RtlRaiseStatus@4:
330c2c66affSColin Finck
331c2c66affSColin Finck    /* Set up stack frame */
332c2c66affSColin Finck    push ebp
333c2c66affSColin Finck    mov ebp, esp
334c2c66affSColin Finck
335c2c66affSColin Finck    /*
336c2c66affSColin Finck     * Save the context while preserving everything but ESP and EBP.
337c2c66affSColin Finck     * This is vital because the caller will be restored with this context
338c2c66affSColin Finck     * in case the execution is continued, which means we must not clobber
339c2c66affSColin Finck     * the non-volatiles. We preserve the volatiles too because the context
340c2c66affSColin Finck     * could get passed to a debugger.
341c2c66affSColin Finck     */
342c2c66affSColin Finck    lea esp, [esp-CONTEXT_FRAME_LENGTH-EXCEPTION_RECORD_LENGTH]
343c2c66affSColin Finck    push esp
344c2c66affSColin Finck    call _RtlCaptureContext@4
345c2c66affSColin Finck
346c2c66affSColin Finck    /* Adjust ESP to account for the argument that was passed */
347c2c66affSColin Finck    add dword ptr [esp+CONTEXT_ESP], 4
348c2c66affSColin Finck
349c2c66affSColin Finck    /* Set up the exception record */
350c2c66affSColin Finck    lea ecx, [esp+CONTEXT_FRAME_LENGTH]
351c2c66affSColin Finck    mov eax, [ebp+8]
352c2c66affSColin Finck    mov dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_CODE], eax
353c2c66affSColin Finck    mov dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_FLAGS], EXCEPTION_NONCONTINUABLE
354c2c66affSColin Finck    and dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_RECORD], 0
355c2c66affSColin Finck    mov eax, [ebp+4]
356c2c66affSColin Finck    mov dword ptr [ecx+EXCEPTION_RECORD_EXCEPTION_ADDRESS], eax
357c2c66affSColin Finck    and dword ptr [ecx+EXCEPTION_RECORD_NUMBER_PARAMETERS], 0
358c2c66affSColin Finck
359c2c66affSColin Finck    /* Write the context flag */
360c2c66affSColin Finck    mov dword ptr [esp+CONTEXT_FLAGS], CONTEXT_FULL
361c2c66affSColin Finck
362c2c66affSColin Finck    /* Check if user mode debugger is active */
363c2c66affSColin Finck    call _RtlpCheckForActiveDebugger@0
364c2c66affSColin Finck
365c2c66affSColin Finck    /* Restore ECX and jump if debugger is active */
366c2c66affSColin Finck    lea ecx, [esp+CONTEXT_FRAME_LENGTH]
367c2c66affSColin Finck    test al, al
368c2c66affSColin Finck    jnz DebuggerActive2
369c2c66affSColin Finck
370c2c66affSColin Finck    /* Dispatch the exception */
371c2c66affSColin Finck    push esp
372c2c66affSColin Finck    push ecx
373c2c66affSColin Finck    call _RtlDispatchException@8
374c2c66affSColin Finck
375c2c66affSColin Finck    /* Raise exception if we got here */
376c2c66affSColin Finck    lea ecx, [esp+CONTEXT_FRAME_LENGTH]
377c2c66affSColin Finck    mov edx, esp
378c2c66affSColin Finck    push 0
379c2c66affSColin Finck    push edx
380c2c66affSColin Finck    push ecx
381c2c66affSColin Finck    call _ZwRaiseException@12
382c2c66affSColin Finck    jmp RaiseStatus2
383c2c66affSColin Finck
384c2c66affSColin FinckDebuggerActive2:
385c2c66affSColin Finck
386c2c66affSColin Finck    /* Raise an exception immediately */
387c2c66affSColin Finck    mov edx, esp
388c2c66affSColin Finck    push 1
389c2c66affSColin Finck    push edx
390c2c66affSColin Finck    push ecx
391c2c66affSColin Finck    call _ZwRaiseException@12
392c2c66affSColin Finck
393c2c66affSColin FinckRaiseStatus2:
394c2c66affSColin Finck
395c2c66affSColin Finck    /* If we returned, raise a status */
396c2c66affSColin Finck    push eax
397c2c66affSColin Finck    call _RtlRaiseStatus@4
398c2c66affSColin Finck
399c2c66affSColin FinckEND
400