[RTL]
[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
13 #define DISPOSITION_DISMISS 0
14 #define DISPOSITION_CONTINUE_SEARCH 1
15 #define DISPOSITION_COLLIDED_UNWIND 3
16
17 #define EXCEPTION_EXIT_UNWIND 4
18 #define EXCEPTION_UNWINDING 2
19
20
21 EXTERN _RtlUnwind@16:PROC
22
23 /* GLOBALS *******************************************************************/
24
25 PUBLIC __global_unwind2
26 PUBLIC __local_unwind2
27 PUBLIC __abnormal_termination
28 PUBLIC __except_handler2
29 PUBLIC __except_handler3
30
31 /* FUNCTIONS *****************************************************************/
32
33 .code
34 _unwind_handler:
35
36 /* Check if we were unwinding and continue search if not */
37 mov ecx, [esp+4]
38 test dword ptr [ecx+4], EXCEPTION_EXIT_UNWIND + EXCEPTION_UNWINDING
39 mov eax, DISPOSITION_CONTINUE_SEARCH
40 jz unwind_handler_return
41
42 /* We have a collision, do a local unwind */
43 mov eax, [esp+20]
44 push ebp
45 mov ebp, [eax+16]
46 mov edx, [eax+40]
47 push edx
48 mov edx, [eax+36]
49 push edx
50 call __local_unwind2
51 add esp, 8
52 pop ebp
53
54 /* Set new try level */
55 mov eax, [esp+8]
56 mov edx, [esp+16]
57 mov [edx], eax
58
59 /* Return collided unwind */
60 mov eax, DISPOSITION_COLLIDED_UNWIND
61
62 unwind_handler_return:
63 ret
64
65
66 __global_unwind2:
67
68 /* Create stack and save all registers */
69 push ebp
70 mov ebp, esp
71 push ebx
72 push esi
73 push edi
74 push ebp
75
76 /* Call unwind */
77 push 0
78 push 0
79 push glu_return
80 push [ebp+8]
81 call _RtlUnwind@16
82
83 glu_return:
84 /* Restore registers and return */
85 pop ebp
86 pop edi
87 pop esi
88 pop ebx
89 mov esp, ebp
90 pop ebp
91 ret
92
93
94 __abnormal_termination:
95
96 /* Assume false */
97 xor eax, eax
98
99 /* Check if the handler is the unwind handler */
100 mov ecx, fs:0
101 cmp dword ptr [ecx+4], offset _unwind_handler
102 jne short ab_return
103
104 /* Get the try level */
105 mov edx, [ecx+12]
106 mov edx, [edx+12]
107
108 /* Compare it */
109 cmp [ecx+8], edx
110 jne ab_return
111
112 /* Return true */
113 mov eax, 1
114
115 /* Return */
116 ab_return:
117 ret
118
119
120 __local_unwind2:
121
122 /* Save volatiles */
123 push ebx
124 push esi
125 push edi
126
127 /* Get the exception registration */
128 mov eax, [esp+16]
129
130 /* Setup SEH to protect the unwind */
131 push ebp
132 push eax
133 push -2
134 push offset _unwind_handler
135 push fs:0
136 mov fs:0, esp
137
138 unwind_loop:
139 /* Get the exception registration and try level */
140 mov eax, [esp+36]
141 mov ebx, [eax+8]
142 mov esi, [eax+12]
143
144 /* Validate the unwind */
145 cmp esi, -1
146 je unwind_return
147 cmp dword ptr [esp+40], -1
148 je unwind_ok
149 cmp esi, [esp+40]
150 jbe unwind_return
151
152 unwind_ok:
153 /* Get the new enclosing level and save it */
154 lea esi, [esi+esi*2]
155 mov ecx, [ebx+esi*4]
156 mov [esp+8], ecx
157 mov [eax+12], ecx
158
159 /* Check the filter type */
160 cmp dword ptr [ebx+esi*4+4], 0
161 jnz __NLG_Return2
162
163 /* FIXME: NLG Notification */
164
165 /* Call the handler */
166 call dword ptr [ebx+esi*4+8]
167
168 __NLG_Return2:
169 /* Unwind again */
170 jmp unwind_loop
171
172 unwind_return:
173 /* Cleanup SEH */
174 pop fs:0
175 add esp, 16
176 pop edi
177 pop esi
178 pop ebx
179 ret
180
181
182 __except_handler2:
183
184 /* Setup stack and save volatiles */
185 push ebp
186 mov ebp, esp
187 sub esp, 8
188 push ebx
189 push esi
190 push edi
191 push ebp
192
193 /* Clear direction flag */
194 cld
195
196 /* Get exception registration and record */
197 mov ebx, [ebp+12]
198 mov eax, [ebp+8]
199
200 /* Check if this is an unwind */
201 test dword ptr [eax+4], EXCEPTION_EXIT_UNWIND + EXCEPTION_UNWINDING
202 jnz except_unwind2
203
204 /* Save exception pointers structure */
205 mov [ebp-8], eax
206 mov eax, [ebp+16]
207 mov [ebp-4], eax
208 lea eax, [ebp-8]
209 mov [ebx+20], eax
210
211 /* Get the try level and scope table */
212 mov esi, [ebx+12]
213 mov edi, [ebx+8]
214
215 except_loop2:
216 /* Validate try level */
217 cmp esi, -1
218 je except_search2
219
220 /* Check if this is the termination handler */
221 lea ecx, [esi+esi*2]
222 cmp dword ptr [edi+ecx*4+4], 0
223 jz except_continue2
224
225 /* Save registers and call filter, then restore them */
226 push esi
227 push ebp
228 mov ebp, [ebx+16]
229 call dword ptr [edi+ecx*4+4]
230 pop ebp
231 pop esi
232
233 /* Restore ebx and check the result */
234 mov ebx, [ebp+12]
235 or eax, eax
236 jz except_continue2
237 js except_dismiss2
238
239 /* So this is an accept, call the termination handlers */
240 mov edi, [ebx+8]
241 push ebx
242 call __global_unwind2
243 add esp, 4
244
245 /* Restore ebp */
246 mov ebp, [ebx+16]
247
248 /* Do local unwind */
249 push esi
250 push ebx
251 call __local_unwind2
252 add esp, 8
253
254 /* Set new try level */
255 lea ecx, [esi+esi*2]
256 mov eax, [edi+ecx*4]
257 mov [ebx+12], eax
258
259 /* Call except handler */
260 call dword ptr [edi+ecx*4+8]
261
262 except_continue2:
263 /* Reload try level and except again */
264 mov edi, [ebx+8]
265 lea ecx, [esi+esi*2]
266 mov esi, [edi+ecx*4]
267 jmp except_loop2
268
269 except_dismiss2:
270 /* Dismiss it */
271 mov eax, DISPOSITION_DISMISS
272 jmp except_return2
273
274 except_search2:
275 /* Continue searching */
276 mov eax, DISPOSITION_CONTINUE_SEARCH
277 jmp except_return2
278
279 /* Do local unwind */
280 except_unwind2:
281 push ebp
282 mov ebp, [ebx+16]
283 push -1
284 push ebx
285 call __local_unwind2
286 add esp, 8
287
288 /* Retore EBP and set return disposition */
289 pop ebp
290 mov eax, DISPOSITION_CONTINUE_SEARCH
291
292 except_return2:
293 /* Restore registers and stack */
294 pop ebp
295 pop edi
296 pop esi
297 pop ebx
298 mov esp, ebp
299 pop ebp
300 ret
301
302
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
441 END