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