windows-nt/Source/XPSP1/NT/base/crts/crtw32/misc/i386/exsup.asm
2020-09-26 16:20:57 +08:00

303 lines
8.9 KiB
NASM

;***
;exsup.asm
;
; Copyright (c) 1993-2001, Microsoft Corporation. All rights reserved.
;
;Purpose:
; Exception handling for i386. This file contains those routines
; common to both C8.0 and C9.0.
;
;Notes:
;
;Revision History:
; 04-13-93 JWM setjmp(), longjmp() & raisex() moved to setjmp.asm;
; common data definitions moved to exsup.inc.
; 10-18-93 GJF Ensure direction flag is clear in _except_handler2
; 12-16-93 PML Accept <0,0,>0 from except filter, not just -1,0,+1
; 01-10-94 PML Moved C8-specific __except_handler2 to exsup2.inc.
; Only C8/C9 common routines left here.
; 01-20-94 GJF Gave _EXCEPTION_REGISTRATION a _COMMON suffix (fix
; from SteveWo).
; 02-10-94 GJF -1 is the end-of-exception-handler chain marker, not 0.
; 01-11-95 SKS Remove MASM 5.X support
; 04-18-95 JWM Added NLG support
; 04-21-95 JWM NLG routines moved from setjmp.asm, NLG data from
; frame.cpp.
; 04-25-95 JWM Added __NLG_Return2 label.
; 06-07-95 JWM NLG now multithread safe.
; 06-20-95 JWM dwCode passed on stack (11803).
; 07-11-95 JWM unwanted prologue removed from NLG_Notify (11803).
; 07-21-95 JWM Added new entry point, _NLG_Notify1 (16585).
; 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?
ifndef _BUILD_DLL_LIB_
extrn _RtlUnwind@16:near
endif ; _BUILD_DLL_LIB_
;typedef struct _EXCEPTION_REGISTRATION PEXCEPTION_REGISTRATION;
;struct _EXCEPTION_REGISTRATION{
; struct _EXCEPTION_REGISTRATION *prev;
; void (*handler)(PEXCEPTION_RECORD, PEXCEPTION_REGISTRATION, PCONTEXT, PEXCEPTION_RECORD);
; struct scopetable_entry *scopetable;
; int trylevel;
;};
_EXCEPTION_REGISTRATION_COMMON struc ; C8.0/C9.0 common only
dd ? ; prev (OS-req, def'd in exsup.inc)
dd ? ; handler (ditto)
;private:
scopetable dd ? ; C8/C9 common
trylevel dd ? ; C8/C9 common
_EXCEPTION_REGISTRATION_COMMON ends
;#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
assumes DS,DATA
assumes FS,DATA
public __except_list
__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
BeginDATA
__NLG_Destination _NLG_INFO <>
PUBLIC __NLG_Destination
EndDATA
BeginCODE
ifndef _BUILD_DLL_LIB_
;NB: call to RtlUnwind appears to trash ebx! and possibly others so just
; to be safe, we save all callee save regs.
cProc _global_unwind2,<C,PUBLIC>,<IBX,ISI,IDI,IBP>
parmDP stop
cBegin
push 0 ; ReturnValue
push 0 ; ExceptionRecord
push offset flat:_gu_return ; TargetIp
push stop ; TargetFrame
call _RtlUnwind@16
_gu_return:
cEnd
endif ; _BUILD_DLL_LIB_
;_unwind_handler(
; PEXCEPTION_RECORD xr,
; PREGISTRATION_RECORD establisher,
; PCONTEXT context,
; PREGISTRATION_RECORD dispatcher);
;
;this is a special purpose handler used to guard our local unwinder.
; its job is to catch collided unwinds.
;
;NB: this code is basically stolen from the NT routine xcptmisc.asm
; and is basically the same method used by the system unwinder (RtlUnwind).
;
cProc _unwind_handler,<C>
cBegin
mov ecx, dword ptr [esp+4]
test dword ptr [ecx.exception_flags], EXCEPTION_UNWIND_CONTEXT
mov eax, DISPOSITION_CONTINUE_SEARCH
jz short _uh_return
; We collide in a _local_unwind. We set the dispatched to the
; establisher just before the local handler so we can unwind
; any future local handlers.
mov eax, [esp+8] ; Our establisher is the one
; in front of the local one
mov edx, [esp+16]
mov [edx], eax ; set dispatcher to local_unwind2
mov eax, DISPOSITION_COLLIDED_UNWIND
_uh_return:
cEnd
;/* _LOCAL_UNWIND2 - run all termination handlers listed in the scope table
; * associated with the given registration record, from the current lexical
; * level through enclosing levels up to, but not including the given 'stop'
; * level.
; */
;void _local_unwind2(PEXCEPTION_REGISTRATION xr, int stop)
;{
; int ix;
;
; for(ix=xr->trylevel; ix!=-1 && ix!=stop; ix=xr->xscope[i].enclosing_level){
; /* NULL indicates that this entry is for a termination handler */
; if(xr->xscope[i].filter==NULL){
; /* NB: call to the termination handler may trash callee save regs */
; (*xr->xscope[i].specific_handler)();
; }
; }
; xr->trylevel=stop;
;}
;/* NOTE: frame (ebp) is setup by caller of __local_unwind2 */
PUBLIC __NLG_Return2
cProc _local_unwind2,<C,PUBLIC>
cBegin
.FPO (0,2,3,3,0,0)
push ebx
push esi
push edi ;call to the handler may trash, so we must save it
mov eax, [esp+16] ; (eax) = PEXCEPTION_REGISTRATION
;link in a handler to guard our unwind
push eax
push TRYLEVEL_INVALID
push OFFSET FLAT:__unwind_handler
push fs:__except_list
mov fs:__except_list, esp
_lu_top:
mov eax, [esp+32] ; (eax) = PEXCEPTION_REGISTRATION
mov ebx, [eax.scopetable]
mov esi, [eax.trylevel]
cmp esi, -1 ; REVIEW: do we need this extra check?
je short _lu_done
cmp esi, [esp+36]
je short _lu_done
lea esi, [esi+esi*2] ; esi*= 3
mov ecx, [(ebx+esi*4).enclosing_level]
mov [esp+8], ecx ; save enclosing level
mov [eax.trylevel], ecx
cmp dword ptr [(ebx+esi*4).filter], 0
jnz short _lu_continue
push 0101h
mov eax, [(ebx+esi*4).specific_handler]
call _NLG_Notify
call [(ebx+esi*4).specific_handler]
__NLG_Return2::
_lu_continue:
jmp short _lu_top
_lu_done:
pop fs:__except_list
add esp, 4*3 ; cleanup stack
pop edi ; restore c-runtime registers
pop esi
pop ebx
cEnd
;/* _ABNORMAL_TERMINATION - return TRUE if __finally clause entered via
; * _local_unwind2.
; */
;BOOLEAN _abnormal_termination(void);
cProc _abnormal_termination,<C,PUBLIC>
cBegin
.FPO (0,0,0,0,0,0)
xor eax, eax ; assume FALSE
mov ecx, fs:__except_list
cmp [ecx.handler], offset FLAT:__unwind_handler
jne short _at_done ; UnwindHandler first?
mov edx, [ecx+12] ; establisher of local_unwind2
mov edx, [edx.trylevel] ; is trylevel the same as the
cmp [ecx+8], edx ; local_unwind level?
jne short _at_done ; no - then FALSE
mov eax, 1 ; currently in _abnormal_termination
_at_done:
cEnd
;
; NLG entrypoints, for debugger support
; On entry: address of non-local goto in eax
;
public __NLG_Dispatch
OPTION PROLOGUE:NONE
OPTION EPILOGUE:NONE
_NLG_Notify1 PROC C PUBLIC
push ebx
push ecx
mov ebx, OFFSET __NLG_Destination
jmp __NLG_go ; ecx is already set
_NLG_Notify1 ENDP
_NLG_Notify PROC C PUBLIC, dwInCode:DWORD
push ebx
push ecx
mov ebx, OFFSET __NLG_Destination
mov ecx, dwInCode
__NLG_Go:
mov [ebx.dwCode], ecx
mov [ebx.uoffDestination], eax
mov [ebx.uoffFramePointer], ebp
__NLG_Dispatch::
pop ecx
pop ebx
ret 4
_NLG_Notify ENDP
OPTION PROLOGUE:PROLOGUEDEF
OPTION EPILOGUE:EPILOGUEDEF
EndCODE
END