windows-nt/Source/XPSP1/NT/base/crts/crtw32/misc/i386/exsup3.asm

314 lines
9.6 KiB
NASM
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
;***
;exsup3.asm
;
; Copyright (c) 1994-2001, Microsoft Corporation. All rights reserved.
;
;Purpose:
; Exception handling for i386. This is just the C9.0 version of
; the language-specific exception handler. The C8.0 version is
; found in exsup2.asm, and the routines common to both C8 and C9
; are found in exsup.asm.
;
;Notes:
;
;Revision History:
; 01-10-94 PML Create VC/C++ 2.0 (C9.0) version from C8.0 original
; 01-11-95 SKS Remove MASM 5.X support
; 04-18-95 JWM Added NLG support
; 06-07-95 JWM __SetNLGCode() used, for multithread safety.
; 06-20-95 JWM __SetNLGCode() removed, code passed on stack (11803).
; 03-09-01 PML Add FPO directives for proper callstacks (vs7#221754)
;
;*******************************************************************************
;hnt = -D_WIN32 -Dsmall32 -Dflat32 -Mx $this;
;Define small32 and flat32 since these are not defined in the NT build process
small32 equ 1
flat32 equ 1
.xlist
include pversion.inc
?DFDATA = 1
?NODATA = 1
include cmacros.inc
include exsup.inc
.list
;REVIEW: can we get rid of _global_unwind2, and just use
; the C runtimes version, _global_unwind?
extrn __global_unwind2:near
extrn __local_unwind2:near
extrn __NLG_Notify:near
;typedef struct _EXCEPTION_REGISTRATION PEXCEPTION_REGISTRATION;
;struct _EXCEPTION_REGISTRATION{
;/* _esp, xpointers at negative offset */
; int _esp;
; PEXCEPTION_POINTERS xpointers;
; struct _EXCEPTION_REGISTRATION *prev;
; void (*handler)(PEXCEPTION_RECORD, PEXCEPTION_REGISTRATION, PCONTEXT, PEXCEPTION_RECORD);
; struct scopetable_entry *scopetable;
; int trylevel;
;};
;private (at negative offsets from node ptr)
_esp = -8
xpointers = -4
_C9_EXCEPTION_REGISTRATION struc ; C9.0 version
;public:
dd ? ; prev (common)
dd ? ; handler (common)
;private:
scopetable dd ?
trylevel dd ?
_C9_EXCEPTION_REGISTRATION ends
FRAME_EBP_OFFSET equ 16
;#define EXCEPTION_MAXIMUM_PARAMETERS 4
;typedef struct _EXCEPTION_RECORD EXCEPTION_RECORD;
;typedef EXCEPTION_RECORD *PEXCEPTION_RECORD;
;struct _EXCEPTION_RECORD{
; NTSTATUS ExceptionCode;
; ULONG ExceptionFlags;
; struct _EXCEPTION_RECORD *ExceptionRecord;
; PVOID ExceptionAddress;
; ULONG NumberParameters;
; ULONG ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
;};
_EXCEPTION_RECORD struc
exception_number dd ?
exception_flags dd ?
exception_record dd ?
exception_address dd ?
number_parameters dd ?
exception_information dd 4 dup(?)
_EXCEPTION_RECORD ends
SIZEOF_EXCEPTION_RECORD equ 36
;/* following is the structure returned by the _exception_info() intrinsic. */
;typedef struct _EXCEPTION_POINTERS EXCEPTION_POINTERS;
;typedef struct EXCEPTION_POINTERS *PEXCEPTION_POINTERS;
;struct _EXCEPTION_POINTERS{
; PEXCEPTION_RECORD ExceptionRecord;
; PCONTEXT Context;
;};
_EXCEPTION_POINTERS struc
ep_xrecord dd ?
ep_context dd ?
_EXCEPTION_POINTERS ends
SIZEOF_EXCEPTION_POINTERS equ 8
extern __NLG_Destination:_NLG_INFO
assumes DS,DATA
assumes FS,DATA
__except_list equ 0
;struct _SCOPETABLE_ENTRY{
; int enclosing_level; /* lexical level of enclosing scope */
; int (*filter)(PEXCEPTION_RECORD); /* NULL for a termination handler */
; void (*specific_handler)(void); /* xcpt or termination handler */
;};
;struct _SCOPETABLE_ENTRY Scopetable[NUMTRYS];
_SCOPETABLE_ENTRY struc
enclosing_level dd ?
filter dd ?
specific_handler dd ?
_SCOPETABLE_ENTRY ends
BeginCODE
;EXTERN C __SetNLGCode:near
;/* _EXCEPT_HANDLER3 - Try to find an exception handler listed in the scope
; * table associated with the given registration record, that wants to accept
; * the current exception. If we find one, run it (and never return).
; * RETURNS: (*if* it returns)
; * DISPOSITION_DISMISS - dismiss the exception.
; * DISPOSITION_CONTINUE_SEARCH - pass the exception up to enclosing handlers
; */
;int _except_handler3(
; PEXCEPTION_RECORD exception_record,
; PEXCEPTION_REGISTRATION registration,
; PCONTEXT context,
; PEXCEPTION_REGISTRATION dispatcher)
;{
; int ix, filter_result;
;
; for(ix=registration->trylevel; ix!=-1; ix=registration->xscope[ix].enclosing_level){
; /* if filter==NULL, then this is an entry for a termination handler */
; if(registration->xscope[ix].filter){
; /* NB: call to the filter may trash the callee save
; registers. (this is *not* a standard cdecl function) */
; filter_result=(*registration->xscope[ix].filter)(xinfo);
; if(filter_result==FILTER_DISMISS)
; return(-1); /* dismiss */
; if(filter_result==FILTER_ACCEPT){
; _global_unwind2(registration);
; _local_unwind2(registration, ix);
; (*registration->xscope[ix].specific_handler)(void);
; assert(UNREACHED); /*should never return from handler*/
; }
; assert(filter_result==FILTER_CONTINUE_SEARCH);
; }
; }
; return(0); /* didnt find one */
;}
db 'VC20' ;; VC/C++ 2.0/32-bit (C9.0) version
db 'XC00' ;; so debugger can recognize this proc (cuda:3936)
xrecord equ [ebp+8]
registration equ [ebp+12]
context equ [ebp+16]
dispatcher equ [ebp+20]
xp equ [ebp-8]
_except_handler3 proc C
; FPO = 0 dwords locals allocated in prolog
; 3 dword parameters
; 10 bytes in prolog
; 7 registers saved (includes locals to work around debugger bug)
; 1 EBP is used
; 0 frame type = FPO
.FPO (0,3,10,7,1,0)
push ebp
mov ebp, esp
sub esp, 8
push ebx
push esi
push edi
push ebp
;4*4b for callee saves + 4b return address + 4b param = 24
;DF in indeterminate state at time of exception, so clear it
cld
mov ebx, registration ;ebx= PEXCEPTION_REGISTRATION
mov eax, xrecord
test [eax.exception_flags], EXCEPTION_UNWIND_CONTEXT
jnz _lh_unwinding
;build the EXCEPTION_POINTERS locally store its address in the
; registration record. this is the pointer that is returned by
; the _eception_info intrinsic.
mov xp.ep_xrecord, eax
mov eax, context
mov xp.ep_context, eax
lea eax, xp
mov [ebx.xpointers], eax
mov esi, [ebx.trylevel] ;esi= try level
mov edi, [ebx.scopetable] ;edi= scope table base
_lh_top:
cmp esi, -1
je short _lh_bagit
lea ecx, [esi+esi*2] ;ecx= trylevel*3
cmp dword ptr [(edi+ecx*4).filter], 0
je short _lh_continue ;term handler, so keep looking
;filter may trash *all* registers, so save ebp and scopetable offset
push esi
push ebp
lea ebp, FRAME_EBP_OFFSET[ebx]
call [(edi+ecx*4).filter] ;call the filter
pop ebp
pop esi
;ebx may have been trashed by the filter, so we must reload
mov ebx, registration
; Accept <0, 0, >0 instead of just -1, 0, +1
or eax, eax
jz short _lh_continue
js short _lh_dismiss
;assert(eax==FILTER_ACCEPT)
;reload xscope base, cuz it was trashed by the filter call
mov edi, [ebx.scopetable]
;load handler address before we loose components of address mode
push ebx ;registration*
call __global_unwind2 ;run term handlers
add esp, 4
;setup ebp for the local unwinder and the specific handler
lea ebp, FRAME_EBP_OFFSET[ebx]
;the stop try level == accepting except level
push esi ;stop try level
push ebx ;registration*
call __local_unwind2
add esp, 8
lea ecx, [esi+esi*2] ;ecx=trylevel*3
push 01h
mov eax, [(edi+ecx*4).specific_handler]
call __NLG_Notify
; set the current trylevel to our enclosing level immediately
; before giving control to the handler. it is the enclosing
; level, if any, that guards the handler.
mov eax, [(edi+ecx*4).enclosing_level]
mov [ebx.trylevel], eax
call [(edi+ecx*4).specific_handler] ;call the except handler
;assert(0) ;(NB! should not return)
_lh_continue:
;reload the scope table base, possibly trashed by call to filter
mov edi, [ebx.scopetable]
lea ecx, [esi+esi*2]
mov esi, [edi+ecx*4+0] ;load the enclosing trylevel
jmp short _lh_top
_lh_dismiss:
mov eax, DISPOSITION_DISMISS ;dismiss the exception
jmp short _lh_return
_lh_bagit:
mov eax, DISPOSITION_CONTINUE_SEARCH
jmp short _lh_return
_lh_unwinding:
push ebp
lea ebp, FRAME_EBP_OFFSET[ebx]
push -1
push ebx
call __local_unwind2
add esp, 8
pop ebp
;the return value is not really relevent in an unwind context
mov eax, DISPOSITION_CONTINUE_SEARCH
_lh_return:
pop ebp
pop edi
pop esi
pop ebx
mov esp,ebp
pop ebp
ret
_except_handler3 endp
public __seh_longjmp_unwind@4
__seh_longjmp_unwind@4 proc near
push ebp
mov ecx, 8[esp]
mov ebp, [ecx.saved_ebp]
mov eax, [ecx.saved_trylevel]
push eax
mov eax, [ecx.saved_xregistration]
push eax
call __local_unwind2
add esp, 8
pop ebp
ret 4
__seh_longjmp_unwind@4 endp
EndCODE
END