windows-nt/Source/XPSP1/NT/base/mspatch/api/i386/exsup.asm

300 lines
9.1 KiB
NASM
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
;***
;exsup.asm
;
; Copyright (c) 1993-1997, 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).
;
;*******************************************************************************
;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 save, 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
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
; 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