- Cleanup the /lib directory, by putting more 3rd-party libs in /3rdparty, and by...
[reactos.git] / reactos / lib / sdk / crt / except / i386 / seh.s
1 /* $Id$
2 *
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.
10 */
11
12 #define ExceptionContinueExecution 0
13 #define ExceptionContinueSearch 1
14 #define ExceptionNestedException 2
15 #define ExceptionCollidedUnwind 3
16
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
24
25 #define EXCEPTION_UNWIND_MODE \
26 ( EXCEPTION_UNWINDING \
27 | EXCEPTION_EXIT_UNWIND \
28 | EXCEPTION_TARGET_UNWIND \
29 | EXCEPTION_COLLIDED_UNWIND)
30
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
37
38 #define TRYLEVEL_NONE -1
39 #define TRYLEVEL_INVALID -2
40
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
47 #define ER_EBP 0x10
48
49 #define ST_TRYLEVEL 0x00
50 #define ST_FILTER 0x04
51 #define ST_HANDLER 0x08
52
53 #define CONTEXT_EDI 0x9C
54 #define CONTEXT_EBX 0xA4
55 #define CONTEXT_EIP 0xB8
56
57 .globl __local_unwind2
58 .globl __except_handler3
59 .globl __EH_prolog
60
61 // EAX = value to print
62 _do_debug:
63 pushal
64 pushl %eax
65 call _MsvcrtDebug@4
66 popal
67 ret
68
69 #define LU2_TRYLEVEL 0x08
70 #define LU2_REGFRAME 0x04
71
72 //
73 // void
74 // _local_unwind2(PEXCEPTION_REGISTRATION RegistrationFrame,
75 // LONG TryLevel)
76 //
77 // Parameters:
78 // [EDX+08h] - PEXCEPTION_REGISTRATION RegistrationFrame
79 // [EDX+04h] - LONG TryLevel
80 // Registers:
81 // EBP - EBP of call frame we are unwinding
82 // Returns:
83 // Nothing
84 // Notes:
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.
87 __local_unwind2:
88 // Setup our call frame so we can access parameters using EDX
89 //pushl %ebp
90 movl %esp, %edx
91
92 // FIXME: Setup an EXCEPTION_REGISTRATION entry to protect the
93 // unwinding in case something goes wrong
94
95 .lu2_next_scope:
96
97 // Keep a pointer to the exception registration in EBX
98 movl LU2_REGFRAME(%edx), %ebx
99
100 // If we have reached the end of the chain or we're asked to stop here
101 // by the caller then exit
102 test %ebx, %ebx
103 je .lu2_done
104
105 movl ER_TRYLEVEL(%ebx), %eax
106 cmpl $-1, %eax
107 je .lu2_done
108
109 cmpl LU2_TRYLEVEL(%edx), %eax
110 je .lu2_done
111
112 // Keep a pointer to the scopetable in ESI
113 movl ER_SCOPETABLE(%ebx), %esi
114
115 // Compute the offset of the entry in the scopetable that describes
116 // the scope that is to be unwound. Put the offset in EDI.
117 movl ST_TRYLEVEL(%esi), %edi
118 lea (%edi, %edi, 2), %edi
119 shll $2, %edi
120 addl %esi, %edi
121
122 // If this is not a termination handler then skip it
123 cmpl $0, ST_FILTER(%edi)
124 jne .lu2_next_scope
125
126 // Save the previous try-level in the exception registration structure
127 movl ST_TRYLEVEL(%edi), %eax
128 movl %eax, ER_TRYLEVEL(%ebx)
129
130 // Fetch the address of the termination handler
131 movl ST_HANDLER(%edi), %eax
132
133 // Termination handlers may trash all registers so save the
134 // important ones and then call the handler
135 pushl %edx
136 call *%eax
137
138 // Get our base pointer back
139 popl %edx
140
141 jmp .lu2_next_scope
142
143 .lu2_done:
144
145 // FIXME: Tear down the EXCEPTION_REGISTRATION entry setup to protect
146 // the unwinding
147
148 //movl %esi, %esp
149 //popl %ebp
150 ret
151
152 #define EH3_DISPCONTEXT 0x14
153 #define EH3_CONTEXT 0x10
154 #define EH3_REGFRAME 0x0C
155 #define EH3_ERECORD 0x08
156
157 // Parameters:
158 // [ESP+14h] - PVOID DispatcherContext
159 // [ESP+10h] - PCONTEXT Context
160 // [ESP+0Ch] - PEXCEPTION_REGISTRATION RegistrationFrame
161 // [ESP+08h] - PEXCEPTION_RECORD ExceptionRecord
162 // Registers:
163 // Unknown
164 // Returns:
165 // EXCEPTION_DISPOSITION - How this handler handled the exception
166 // Notes:
167 // Try to find an exception handler that will handle the exception.
168 // Traverse the entries in the scopetable that is associated with the
169 // exception registration passed as a parameter to this function.
170 // If an exception handler that will handle the exception is found, it
171 // is called and this function never returns
172 __except_handler3:
173 // Setup our call frame so we can access parameters using EBP
174 pushl %ebp // Standard ESP in frame (considered part of EXCEPTION_REGISTRATION)
175 movl %esp, %ebp
176
177 // Don't trust the direction flag to be cleared
178 cld
179
180 // Either we're called to handle an exception or we're called to unwind
181 movl EH3_ERECORD(%ebp), %eax
182 testl $EXCEPTION_UNWIND_MODE, EREC_FLAGS(%eax)
183 jnz .eh3_unwind
184
185 // Keep a pointer to the exception registration in EBX
186 movl EH3_REGFRAME(%ebp), %ebx
187
188 // Build an EXCEPTION_POINTERS structure on the stack and store it's
189 // address in the EXCEPTION_REGISTRATION structure
190 movl EH3_CONTEXT(%esp), %eax
191 pushl %ebx // Registration frame
192 pushl %eax // Context
193 movl %esp, ER_EPOINTERS(%ebx) // Pointer to EXCEPTION_REGISTRATION on the stack
194
195 // Keep current try-level in EDI
196 movl ER_TRYLEVEL(%ebx), %edi
197
198 // Keep a pointer to the scopetable in ESI
199 movl ER_SCOPETABLE(%ebx), %esi
200
201 .eh3_next_scope:
202
203 // If we have reached the end of the chain then exit
204 cmpl $-1, %edi
205 je .eh3_search
206
207 // Compute the offset of the entry in the scopetable and store
208 // the absolute address in EAX
209 lea (%edi, %edi, 2), %eax
210 shll $2, %eax
211 addl %esi, %eax
212
213 // Fetch the address of the filter routine
214 movl ST_FILTER(%eax), %eax
215
216 // If this is a termination handler then skip it
217 cmpl $0, %eax
218 je .eh3_continue
219
220 // Filter routines may trash all registers so save the important
221 // ones before restoring the call frame ebp and calling the handler
222 pushl %ebp
223 pushl %edi // Stop try-level
224 lea ER_EBP(%ebx), %ebp
225 call *%eax
226 popl %edi // Stop try-level
227 popl %ebp
228
229 // Reload EBX with registration frame address
230 movl EH3_REGFRAME(%ebp), %ebx
231
232 // Be more flexible here by checking if the return value is less than
233 // zero, equal to zero, or larger than zero instead of the defined
234 // values:
235 // -1 (EXCEPTION_CONTINUE_EXECUTION)
236 // 0 (EXCEPTION_CONTINUE_SEARCH)
237 // +1 (EXCEPTION_EXECUTE_HANDLER)
238 orl %eax, %eax
239 jz .eh3_continue
240 js .eh3_dismiss
241
242 // Filter returned: EXCEPTION_EXECUTE_HANDLER
243
244 // Ask the OS to perform global unwinding.
245 pushl %edi // Save stop try-level
246 pushl %ebx // Save registration frame address
247 pushl %ebx // Registration frame address
248 call __global_unwind2
249 popl %eax // Remove parameter to __global_unwind2
250 popl %ebx // Restore registration frame address
251 popl %edi // Restore stop try-level
252
253 // Change the context structure so _except_finish is called in the
254 // correct context since we return ExceptionContinueExecution.
255 movl EH3_CONTEXT(%ebp), %eax
256
257 movl %edi, CONTEXT_EDI(%eax) // Stop try-level
258 movl %ebx, CONTEXT_EBX(%eax) // Registration frame address
259 movl $_except_finish, CONTEXT_EIP(%eax)
260
261 movl $ExceptionContinueExecution, %eax
262 jmp .eh3_return
263
264 // Filter returned: EXCEPTION_CONTINUE_SEARCH
265 .eh3_continue:
266
267 // Reload ESI because the filter routine may have trashed it
268 movl ER_SCOPETABLE(%ebx), %esi
269
270 // Go one try-level closer to the top
271 lea (%edi, %edi, 2), %edi
272 shll $2, %edi
273 addl %esi, %edi
274 movl ST_TRYLEVEL(%edi), %edi
275
276 jmp .eh3_next_scope
277
278 // Filter returned: EXCEPTION_CONTINUE_EXECUTION
279 // Continue execution like nothing happened
280 .eh3_dismiss:
281 movl $ExceptionContinueExecution, %eax
282 jmp .eh3_return
283
284 // Tell the OS to search for another handler that will handle the exception
285 .eh3_search:
286
287 movl $ExceptionContinueSearch, %eax
288 jmp .eh3_return
289
290 // Perform local unwinding
291 .eh3_unwind:
292
293 testl $EXCEPTION_TARGET_UNWIND, EREC_FLAGS(%eax)
294 jnz .eh3_return
295
296 // Save some important registers
297 pushl %ebp
298
299 lea ER_EBP(%ebx), %ebp
300 pushl $-1
301 pushl %ebx
302 call __local_unwind2
303 addl $8, %esp
304
305 // Restore some important registers
306 popl %ebp
307
308 movl $ExceptionContinueSearch, %eax
309
310 // Get me out of here
311 .eh3_return:
312
313 movl %ebp, %esp
314 popl %ebp
315 ret
316
317 // Parameters:
318 // None
319 // Registers:
320 // EBX - Pointer to exception registration structure
321 // EDI - Stop try-level
322 // Returns:
323 // -
324 // Notes:
325 // -
326 _except_finish:
327
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
331
332 // Save some important registers
333 pushl %ebp
334 pushl %ebx
335 pushl %edi
336
337 // Stop try-level
338 pushl %edi
339
340 // Pointer to exception registration structure
341 pushl %ebx
342 call __local_unwind2
343 addl $8, %esp
344
345 // Restore some important registers
346 popl %edi
347 popl %ebx
348 popl %ebp
349
350 // Keep a pointer to the scopetable in ESI
351 movl ER_SCOPETABLE(%ebx), %esi
352
353 // Compute the offset of the entry in the scopetable and store
354 // the absolute address in EDI
355 lea (%edi, %edi, 2), %edi
356 shll $2, %edi
357 addl %esi, %edi
358
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
364
365 call *%eax
366
367 // We should never get here
368 ret
369
370 // Copied from Wine.
371 __EH_prolog:
372 pushl $-1
373 pushl %eax
374 pushl %fs:0
375 movl %esp, %fs:0
376 movl 12(%esp), %eax
377 movl %ebp, 12(%esp)
378 leal 12(%esp), %ebp
379 pushl %eax
380 ret