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