sync with trunk r49322
[reactos.git] / lib / sdk / crt / except / i386 / seh.s
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS CRT
4 * FILE: lib/crt/misc/i386/seh.S
5 * PURPOSE: SEH Support for the CRT
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ndk/asm.h>
12 .intel_syntax noprefix
13
14 #define DISPOSITION_DISMISS 0
15 #define DISPOSITION_CONTINUE_SEARCH 1
16 #define DISPOSITION_COLLIDED_UNWIND 3
17
18 /* GLOBALS *******************************************************************/
19
20 .globl __global_unwind2
21 .globl __local_unwind2
22 .globl __abnormal_termination
23 .globl __except_handler2
24 .globl __except_handler3
25
26 /* FUNCTIONS *****************************************************************/
27
28 .func unwind_handler
29 _unwind_handler:
30
31 /* Check if we were unwinding and continue search if not */
32 mov ecx, [esp+4]
33 test dword ptr [ecx+4], EXCEPTION_EXIT_UNWIND + EXCEPTION_UNWINDING
34 mov eax, DISPOSITION_CONTINUE_SEARCH
35 jz unwind_handler_return
36
37 /* We have a collision, do a local unwind */
38 mov eax, [esp+20]
39 push ebp
40 mov ebp, [eax+16]
41 mov edx, [eax+40]
42 push edx
43 mov edx, [eax+36]
44 push edx
45 call __local_unwind2
46 add esp, 8
47 pop ebp
48
49 /* Set new try level */
50 mov eax, [esp+8]
51 mov edx, [esp+16]
52 mov [edx], eax
53
54 /* Return collided unwind */
55 mov eax, DISPOSITION_COLLIDED_UNWIND
56
57 unwind_handler_return:
58 ret
59 .endfunc
60
61 .func _global_unwind2
62 __global_unwind2:
63
64 /* Create stack and save all registers */
65 push ebp
66 mov ebp, esp
67 push ebx
68 push esi
69 push edi
70 push ebp
71
72 /* Call unwind */
73 push 0
74 push 0
75 push glu_return
76 push [ebp+8]
77 call _RtlUnwind@16
78
79 glu_return:
80 /* Restore registers and return */
81 pop ebp
82 pop edi
83 pop esi
84 pop ebx
85 mov esp, ebp
86 pop ebp
87 ret
88 .endfunc
89
90 .func _abnormal_termination
91 __abnormal_termination:
92
93 /* Assume false */
94 xor eax, eax
95
96 /* Check if the handler is the unwind handler */
97 mov ecx, fs:0
98 cmp dword ptr [ecx+4], offset _unwind_handler
99 jne short ab_return
100
101 /* Get the try level */
102 mov edx, [ecx+12]
103 mov edx, [edx+12]
104
105 /* Compare it */
106 cmp [ecx+8], edx
107 jne ab_return
108
109 /* Return true */
110 mov eax, 1
111
112 /* Return */
113 ab_return:
114 ret
115 .endfunc
116
117 .func _local_unwind2
118 __local_unwind2:
119
120 /* Save volatiles */
121 push ebx
122 push esi
123 push edi
124
125 /* Get the exception registration */
126 mov eax, [esp+16]
127
128 /* Setup SEH to protect the unwind */
129 push ebp
130 push eax
131 push -2
132 push offset _unwind_handler
133 push fs:0
134 mov fs:0, esp
135
136 unwind_loop:
137 /* Get the exception registration and try level */
138 mov eax, [esp+36]
139 mov ebx, [eax+8]
140 mov esi, [eax+12]
141
142 /* Validate the unwind */
143 cmp esi, -1
144 je unwind_return
145 cmp dword ptr [esp+40], -1
146 je unwind_ok
147 cmp esi, [esp+40]
148 jbe unwind_return
149
150 unwind_ok:
151 /* Get the new enclosing level and save it */
152 lea esi, [esi+esi*2]
153 mov ecx, [ebx+esi*4]
154 mov [esp+8], ecx
155 mov [eax+12], ecx
156
157 /* Check the filter type */
158 cmp dword ptr [ebx+esi*4+4], 0
159 jnz __NLG_Return2
160
161 /* FIXME: NLG Notification */
162
163 /* Call the handler */
164 call dword ptr [ebx+esi*4+8]
165
166 __NLG_Return2:
167 /* Unwind again */
168 jmp unwind_loop
169
170 unwind_return:
171 /* Cleanup SEH */
172 pop fs:0
173 add esp, 16
174 pop edi
175 pop esi
176 pop ebx
177 ret
178 .endfunc
179
180 .func _except_handler2
181 __except_handler2:
182
183 /* Setup stack and save volatiles */
184 push ebp
185 mov ebp, esp
186 sub esp, 8
187 push ebx
188 push esi
189 push edi
190 push ebp
191
192 /* Clear direction flag */
193 cld
194
195 /* Get exception registration and record */
196 mov ebx, [ebp+12]
197 mov eax, [ebp+8]
198
199 /* Check if this is an unwind */
200 test dword ptr [eax+4], EXCEPTION_EXIT_UNWIND + EXCEPTION_UNWINDING
201 jnz except_unwind2
202
203 /* Save exception pointers structure */
204 mov [ebp-8], eax
205 mov eax, [ebp+16]
206 mov [ebp-4], eax
207 lea eax, [ebp-8]
208 mov [ebx+20], eax
209
210 /* Get the try level and scope table */
211 mov esi, [ebx+12]
212 mov edi, [ebx+8]
213
214 except_loop2:
215 /* Validate try level */
216 cmp esi, -1
217 je except_search2
218
219 /* Check if this is the termination handler */
220 lea ecx, [esi+esi*2]
221 cmp dword ptr [edi+ecx*4+4], 0
222 jz except_continue2
223
224 /* Save registers and call filter, then restore them */
225 push esi
226 push ebp
227 mov ebp, [ebx+16]
228 call dword ptr [edi+ecx*4+4]
229 pop ebp
230 pop esi
231
232 /* Restore ebx and check the result */
233 mov ebx, [ebp+12]
234 or eax, eax
235 jz except_continue2
236 js except_dismiss2
237
238 /* So this is an accept, call the termination handlers */
239 mov edi, [ebx+8]
240 push ebx
241 call __global_unwind2
242 add esp, 4
243
244 /* Restore ebp */
245 mov ebp, [ebx+16]
246
247 /* Do local unwind */
248 push esi
249 push ebx
250 call __local_unwind2
251 add esp, 8
252
253 /* Set new try level */
254 lea ecx, [esi+esi*2]
255 mov eax, [edi+ecx*4]
256 mov [ebx+12], eax
257
258 /* Call except handler */
259 call [edi+ecx*4+8]
260
261 except_continue2:
262 /* Reload try level and except again */
263 mov edi, [ebx+8]
264 lea ecx, [esi+esi*2]
265 mov esi, [edi+ecx*4]
266 jmp except_loop2
267
268 except_dismiss2:
269 /* Dismiss it */
270 mov eax, DISPOSITION_DISMISS
271 jmp except_return2
272
273 except_search2:
274 /* Continue searching */
275 mov eax, DISPOSITION_CONTINUE_SEARCH
276 jmp except_return2
277
278 /* Do local unwind */
279 except_unwind2:
280 push ebp
281 mov ebp, [ebx+16]
282 push -1
283 push ebx
284 call __local_unwind2
285 add esp, 8
286
287 /* Retore EBP and set return disposition */
288 pop ebp
289 mov eax, DISPOSITION_CONTINUE_SEARCH
290
291 except_return2:
292 /* Restore registers and stack */
293 pop ebp
294 pop edi
295 pop esi
296 pop ebx
297 mov esp, ebp
298 pop ebp
299 ret
300 .endfunc
301
302 .func _except_handler3
303 __except_handler3:
304
305 /* Setup stack and save volatiles */
306 push ebp
307 mov ebp, esp
308 sub esp, 8
309 push ebx
310 push esi
311 push edi
312 push ebp
313
314 /* Clear direction flag */
315 cld
316
317 /* Get exception registration and record */
318 mov ebx, [ebp+12]
319 mov eax, [ebp+8]
320
321 /* Check if this is an unwind */
322 test dword ptr [eax+4], EXCEPTION_EXIT_UNWIND + EXCEPTION_UNWINDING
323 jnz except_unwind3
324
325 /* Save exception pointers structure */
326 mov [ebp-8], eax
327 mov eax, [ebp+16]
328 mov [ebp-4], eax
329 lea eax, [ebp-8]
330 mov [ebx-4], eax
331
332 /* Get the try level and scope table */
333 mov esi, [ebx+12]
334 mov edi, [ebx+8]
335
336 /* FIXME: Validate the SEH exception */
337
338 except_loop3:
339 /* Validate try level */
340 cmp esi, -1
341 je except_search3
342
343 /* Check if this is the termination handler */
344 lea ecx, [esi+esi*2]
345 mov eax, [edi+ecx*4+4]
346 or eax, eax
347 jz except_continue3
348
349 /* Save registers clear them all */
350 push esi
351 push ebp
352 lea ebp, [ebx+16]
353 xor ebx, ebx
354 xor ecx, ecx
355 xor edx, edx
356 xor esi, esi
357 xor edi, edi
358
359 /* Call the filter and restore our registers */
360 call eax
361 pop ebp
362 pop esi
363
364 /* Restore ebx and check the result */
365 mov ebx, [ebp+12]
366 or eax, eax
367 jz except_continue3
368 js except_dismiss3
369
370 /* So this is an accept, call the termination handlers */
371 mov edi, [ebx+8]
372 push ebx
373 call __global_unwind2
374 add esp, 4
375
376 /* Restore ebp */
377 lea ebp, [ebx+16]
378
379 /* Do local unwind */
380 push esi
381 push ebx
382 call __local_unwind2
383 add esp, 8
384
385 /* FIXME: Do NLG Notification */
386
387 /* Set new try level */
388 lea ecx, [esi+esi*2]
389 mov eax, [edi+ecx*4]
390 mov [ebx+12], eax
391
392 /* Clear registers and call except handler */
393 mov eax, [edi+ecx*4+8]
394 xor ebx, ebx
395 xor ecx, ecx
396 xor edx, edx
397 xor esi, esi
398 xor edi, edi
399 call eax
400
401 except_continue3:
402 /* Reload try level and except again */
403 mov edi, [ebx+8]
404 lea ecx, [esi+esi*2]
405 mov esi, [edi+ecx*4]
406 jmp except_loop3
407
408 except_dismiss3:
409 /* Dismiss it */
410 mov eax, DISPOSITION_DISMISS
411 jmp except_return3
412
413 except_search3:
414 /* Continue searching */
415 mov eax, DISPOSITION_CONTINUE_SEARCH
416 jmp except_return3
417
418 /* Do local unwind */
419 except_unwind3:
420 push ebp
421 mov ebp, [ebx+16]
422 push -1
423 push ebx
424 call __local_unwind2
425 add esp, 8
426
427 /* Retore EBP and set return disposition */
428 pop ebp
429 mov eax, DISPOSITION_CONTINUE_SEARCH
430
431 except_return3:
432 /* Restore registers and stack */
433 pop ebp
434 pop edi
435 pop esi
436 pop ebx
437 mov esp, ebp
438 pop ebp
439 ret
440 .endfunc