Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

796 lines
23 KiB

; Low-level support function for C++ EH
; The stack frame without EH
; -------------------
; | paramters |
; | |
; -------------------
; | return address |
; -------------------
;A6 -> | old A6 |
; -------------------
; | locals |
; | |
; -------------------
; The stack fram with swapper
; -------------------
; | paramters |
; | |
; -------------------
; | return address |
; -------------------
; | old A6 |
; -------------------
; | 1 |
; -------------------
;A6 -> | swapper record |
; | |
; | |
; -------------------
; | locals |
; | |
; -------------------
; The stack frame with EH
; -------------------
; | paramters |
; | |
; -------------------
; | return address |
; -------------------
; | 2 |
; -------------------
;A6 -> | old A6 |
; -------------------
; | EH record |
; | |
; -------------------
; | locals |
; | |
; -------------------
; The stack frame with EH and swapper
; -------------------
; | paramters |
; | |
; -------------------
; | return address |
; -------------------
; | old A6 |
; -------------------
; | 3 |
; -------------------
;A6 -> | swapper record |
; | |
; | |
; -------------------
; | EH record |
; | |
; -------------------
; | locals |
; | |
; -------------------
; For __stdcall & __cdecl calling convention,
; callee can trash a0, a1, d0, d1 and d2
#include <assert.a>
#define cbSwapperRecord 0x10
;struct _EH_REGISTRATION {
; void (*handler)(struct _EXCEPTION_RECORD*, struct _EXCEPTION_REGISTRATION*, PCONTEXT, struct _EXCEPTION_REGISTRATION*);
; int state;
; int _sp;
;};
#define cbEHRecord 0x8
#define ofsSP -0x4
#define ofsState 0x4
#define ofsHandler 0x0
#define ofsRNFromA6Number (0x4 + cbEHRecord)
#define ofsRNFromA6 cbEHRecord
#define ofsRNFromA6SwapNumber (cbSwapperRecord + cbEHRecord)
#define ofsRNFromA6Swap (cbEHRecord + cbSwapperRecord - 0x4)
#define ofsMarkFromA6 0x4
#define ofspException 0x4
;typedef struct EHExceptionRecord {
; DWORD ExceptionCode; // The code of this exception. (= EH_EXCEPTION_NUMBER)
; DWORD ExceptionFlags; // Flags determined by NT
; struct _EXCEPTION_RECORD *ExceptionRecord; // An extra exception record (not used)
; void * ExceptionAddress; // Address at which exception occurred
; DWORD NumberParameters; // Number of extended parameters. (= EH_EXCEPTION_PARAMETERS)
; struct EHParameters {
; DWORD magicNumber; // = EH_MAGIC_NUMBER1
; void * pExceptionObject; // Pointer to the actual object thrown
; ThrowInfo *pThrowInfo; // Description of thrown object
; } params;
;} EHExceptionRecord;
#define ofsExceptionFlags 0x4
#define EXCEPTION_UNWINDING 0x2
externC DestructExceptionObject
externC __terminate
#ifdef SWAPPER
externD ___psisA6Head
#endif
code
_pCurException:
dc.l 0
NULLDATA:
dc.l 0
cProc _NLG_Destination, PUBLIC,,0
cBegin nogen
dc.l 0
dc.l 0
dc.l 0
cEnd nogen
;
; public labels are for debugger support
; Use __cdecl calling convention
;
cProc CallSettingFrame, PUBLIC,,2
; parmD funclet ; funclet to call, 4(a7)
; parmD pRN ; EH record position on frame, 8(a7)
cBegin nogen
cEnd nogen
; d1 -- target A6
; a0 -- pRN
; figure out the target A6 is, depending on if it's swappable frame
move.l 8(a7), a0 ; load pRN
cmp.l #2, ofsRNFromA6Number(a0)
ifeq
move.l #ofsRNFromA6, d1
else
cmp.l #3, ofsRNFromA6SwapNumber(a0)
ifeq
move.l #ofsRNFromA6Swap, d1
else
Assert("stack being corruptted, we are not in a valid EH frame!");
endif
endif
add.l a0, d1 ; target a6 is pRN + ofsFromA6[Swap]
move.l 4(a7), a0 ;load funclet
;need to save registers here, for nested try/catch cases, some C(CatchIt) won't go through
;the register restore phase.
movem.l <a2-a4, d3-d7>, -(a7)
; set a6, call funclet
move.l a6, -(a7) ;save current a6
move.l d1, a6 ;set target a6
move.l a0, d0
jsr _NLG_Notify ;call NLG_Dispatch to notify debugger
jsr (a0) ;call catch handler, return in d0
cProc _NLG_Return, PUBLIC,,0
cBegin nogen
cEnd nogen
jsr _NLG_Notify ;notify debugger
move.l (a7)+, a6 ;restore current a6
movem.l (a7)+, <a2-a4, d3-d7>
rts
DebugSym(CallSettingFrame)
;debugger support for source stepping
cProc _NLG_Notify, PUBLIC,,0
cBegin nogen
cEnd nogen
lea _NLG_Destination(pc), a1
move.l d0, 4(a1) ;move funclet address to NLG_Destination
cProc _NLG_Dispatch, PUBLIC,,0
cBegin nogen
cEnd nogen
rts
;/////////////////////////////////////////////////////////////////////////////
;//
;// JumpToContinuation - sets up a7 and jumps to specified code address.
;//
;// Does not return.
;//
; need to public a label for debugger
; __cdecl calling convention
cProc JumpToContinuation,PUBLIC,,0
; parmD target ; 4(a7)
; parmD pRN ; 8(a7)
cBegin nogen
; d1 -- target address
; a0 -- pRN
; figure out the target A6 is, depending on if it's swappable frame
move.l 8(a7), a0 ; load pRN
cmp.l #2, ofsRNFromA6Number(a0)
ifeq
move.l #ofsRNFromA6, d1
else
cmp.l #3, ofsRNFromA6SwapNumber(a0)
ifeq
move.l #ofsRNFromA6Swap, d1
else
Assert("stack being corruptted, we are not in a valid EH frame!");
endif
endif
add.l a0, d1 ; target A6 is pRN + ofsFromA6[Swap]
#ifdef SWAPPER
movea.l ___psisA6Head(a5), a1 ; reset psisHead for the swapper
cmp.l #0, a1 ; if psis is null
beq out$
loop$:
cmp.l a1, d1
bgt poppsis$
move.l a1, ___psisA6Head(a5)
jmp out$
poppsis$:
move.l -12(a1), a1
cmp.l #0, a1 ; if psis is null
ifeq
move.l #0, ___psisA6Head:l
jmp out$
endif
jmp loop$
out$:
#endif
move.l d1, a6 ; reset a6
move.l 4(a7), d1 ; save the continuation address
move.l ofsSP(a0), a7 ; restore saved a7 from pRN
move.l d1, a0 ; load the continuation address
jmp (a0)
cEnd nogen
DebugSym(JumpToContinuation)
;/////////////////////////////////////////////////////////////////////////////
;//
;// CallMemberFunction0 - call a parameterless member function, Wings only support
;// stdcall calling convention, with 0 parameters.
;//
; the destructor call will be __stdcall in Wings compiler
; rebuild the stack by push this and then call destructor
; return to caller of this function
;
; enter the call:
;
; rtn
; pthis
; pmfn
;
; before jmp, (a0) = pmfn
;
; pthis
; rtn
; pthis
; pmfn
cProc CallMemberFunction0,PUBLIC,,0
; parmD pthis
; parmD pmfn
cBegin nogen
move.l 8(a7), a0 ; pmfn
move.l 4(a7), -(a7) ; return address will make it return to the caller of this function
jsr (a0)
; move.l (a7), 8(a7)
; addq.l #8, a7 ; clean up the stack, member function is __stdcall
rts
cEnd nogen
DebugSym(CallMemeberFunction0)
;/////////////////////////////////////////////////////////////////////////////
;//
;// CallMemberFunction1 - call a member function using stdcall
;// calling convention, with 1 parameter, see comments for previous function
;//
cProc CallMemberFunction1,PUBLIC,,0
; parmD pthis
; parmD pmfn
; parmD pthat
cBegin nogen
move.l 8(a7), a0 ; pmfn
move.l 12(a7), -(a7) ; push pthat
move.l 8(a7), -(a7) ; push pthis
jsr (a0)
; move.l (a7), 8(a7)
; add.l #8, a7
rts
cEnd nogen
DebugSym(CallMemberFunction1)
;/////////////////////////////////////////////////////////////////////////////
;//
;// CallMemberFunction2 - call a member function using stdcall
;// calling convention, with 1 parameter, see comments for previous function
;//
cProc CallMemberFunction2,PUBLIC,,0
; parmD pthis
; parmD pmfn
; parmD pthat
; parmd fvb
cBegin nogen
move.l 8(a7), a0 ; pmfn
move.l 16(a7), -(a7)
move.l 16(a7), -(a7) ; push pthat
move.l 12(a7), -(a7) ; push pthis
jsr (a0)
; move.l (a7), 8(a7)
; add.l #8, a7
rts
cEnd nogen
DebugSym(CallMemberFunction2)
;/////////////////////////////////////////////////////////////////////////////
;//
;// UnwindNestedFrames - Unwinding the stack. This only does
;// the object destruction.
;//
;//
;void __cdecl UnwindNestedFrames(
; EHRegistrationNode *pRN, // Unwind up to (but not including) this frame
; EHExceptionRecord *pExcept // The exception that initiated this unwind
;);
; searching through the A6 frames from current A6
; for EH frame, call the framehander for destructing the objects
; for non-EH frame, do nothing
; the actual frame will be deallocated only when we are at the point to call
; actual handler in catch block
cProc UnwindNestedFrames,PUBLIC,,0
parmD pRN
parmD pExcept
cBegin UnwindNestedFrames
; registers used
; a0 -- pRN
; d0 -- pointing to target frame
; a1 -- use as if a6, current a6
; d1 -- current EH frame's pRN
; d2 -- scratch, flag
; figure out the target A6 is, depending on if it's swappable frame
move.l pRN, a0
cmp.l #2, ofsRNFromA6Number(a0)
ifeq
move.l #ofsRNFromA6, d0
else
cmp.l #3, ofsRNFromA6SwapNumber(a0)
ifeq
move.l #ofsRNFromA6Swap, d0
else
Assert("stack being corruptted, we are not in a valid EH frame!");
endif
endif
add.l a0, d0 ; d0 is pRN + ofsFromA6[Swap], which is target a6 should be
move.l a6, a1
; REVIEW: add all the error checking here, odd address, trying to unwinding below the target frame, etc.
do
;skip the frame without EH
move.l #1, d2
do
cmp.l #0, a1
ifeq
jmp 10$ ; we are at the end of frame
endif
cmp.l #3, 4(a1)
ifhi
move.l (a1), a1 ; this is a frame without EH, skip the frame
else
;less or equal 3
cmp.l #1, 4(a1)
ifeq
move.l 8(a1), a1 ; this is a swapper frame without EH, skip the frame
else
; should be 2 or 3
cmp.l #0, 4(a1)
ifeq
jmp 10$
endif
move.l #0, d2 ; okay, we got a EH frame
endif
endif
cmp.l #0, d2
untileq
cmp.l a1, d0
ifeq
jmp 10$ ;we are done
else
; figure out current pRN in d1
cmp.l #2, 4(a1)
ifeq
move.l #-cbEHRecord, d1
else
move.l #-(cbSwapperRecord+cbEHRecord - 0x4), d1
endif
add.l a1, d1
;save registers
movem.l <a0-a1, d0-d2>, -(a7)
;a1 will be restored anyway
move.l pExcept, a1
or.l #EXCEPTION_UNWINDING, ofsExceptionFlags(a1)
move.l #0, -(a7) ; pDC
move.l #0, -(a7) ; pContext
move.l d1, -(a7) ; pRN
move.l a1, -(a7) ; pExceptionRecord
move.l d1, a0
move.l (a0), a0
jsr (a0) ; call frame handler
add.l #32, a7 ; clean up stack
;restore the stuff we saved, we don't care about return value in unwinding
movem.l (a7)+, <a0-a1, d0-d2>
; move.l #6, 4(a1) ; ???mark it to be non-EH frame to be save
endif
cmp.l #3, 4(a1)
ifeq
move.l 8(a1), a1
else
move.l (a1), a1
endif
cmp.l #0, a1 ; until end of stack
untileq
10$:
cEnd UnwindNestedFrames
;/////////////////////////////////////////////////////////////////////////////
;//
;// __CxxFrameHandler - Real entry point to the runtime; this thunk fixes up
;// the parameters, and then calls the workhorse.
;//
;extern "C" EXCEPTION_DISPOSITION __cdecl __InternalCxxFrameHandler(
; EHExceptionRecord *pExcept, // Information for this exception
; EHRegistrationNode *pRN, // Dynamic information for this frame
; void *pContext, // Context info (we don't care what's in it)
; DispatcherContext *pDC, // More dynamic info for this frame (ignored on Intel)
; FuncInfo *pFuncInfo, // Static information for this frame
; int CatchDepth, // How deeply nested are we?
; EHRegistrationNode *pMarkerRN, // Marker node for when checking inside
; // catch block
; BOOL recursive); // True if this is a translation exception
;extern "C" _CRTIMP __declspec(naked) EXCEPTION_DISPOSITION __cdecl __CxxFrameHandler(
;/*
; a0=FuncInfo *pFuncInfo, // Static information for this frame
;*/
; EHExceptionRecord *pExcept, // Information for this exception
; EHRegistrationNode *pRN, // Dynamic information for this frame
; void *pContext, // Context info (we don't care what's in it)
; DispatcherContext *pDC // More dynamic info for this frame (ignored on Intel)
;)
externC __InternalCxxFrameHandler
cProc __CxxFrameHandler, PUBLIC,,2
cBegin nogen
sub.l #16, a7 ; allocating another 4 parameters space
move.l 16(a7), (a7) ; set return address
move.l 20(a7), 4(a7) ; move up parameters on stack
move.l 24(a7), 8(a7) ; to set the paramters __Internal... needed
move.l 28(a7), 12(a7)
move.l 32(a7), 16(a7)
move.l a0, 20(a7) ; suppose compiler pushs FuncInfo in a0
move.l #0, 24(a7)
move.l #0, 28(a7)
move.l #0, 32(a7) ; ??? FALSE is zero
jmp __InternalCxxFrameHandler ; return to the caller of this function
; return value is in d0
cEnd nogen
DebugSym(__CxxFrameHandler)
;void *CallCatchBlock(
; EHExceptionRecord *pExcept;
; EHRegistrationNode *pRN, // Dynamic info of function with catch
; void *pContext, // ignored
; FuncInfo *pFuncInfo, // Static info of function with catch
; void *handlerAddress, // Code address of handler
; int CatchDepth // How deeply nested in catch blocks are we?
;);
; chain CallCatchBlocks, so that this function will handle destructing
; the exception objects, allocating a slot to store the ptr to previous exception
cProc CallCatchBlock,PUBLIC,,2
parmD pExcept
parmD pRN
parmD pContext
parmD pFuncInfo
parmD handlerAddress
parmD CatchDepth
cBegin CallCatchBlock
; store the return address for this pRN, because nested try/catch can destory the return for outer try/ctach level
move.l pRN, a0
move.l ofsSP(a0), -(a7)
;allocating a slot on stack to chain CallCathcBlock
lea _pCurException(pc), a0
; allocate a slot for actual CatchDepth
cmp.l #0, (a0)
ifeq
move.l #0, -(a7)
else
move.l (a0), a1
move.l pRN, d0
cmp.l 24(a1), d0 ; previous pRN (_pCurException, catchdepth, saved ret, old a6, ret, pExcept) off _pCurException
ifeq
move.l 4(a1), -(a7) ; previous CatchDepth
add.l #1, (a7) ; increse it
else
move.l #0, -(a7) ; always starts with 0
endif
endif
move.l (a0), -(a7)
move.l a7, (a0)
;call the actual handler
move.l pRN, -(a7)
move.l handlerAddress, -(a7)
jsr CallSettingFrame
addq.l #8, a7
;restore the return in pRN
move.l pRN, a1
move.l 8(a7), ofsSP(a1)
;destruct obj
move.l d0, -(a7) ; save continuation address in d0
move.l #1, -(a7)
move.l pExcept, -(a7)
lea pExcept, a0
move.l (a0), a0
cmp.l #0xffffffff, a0
ifne
jsr DestructExceptionObject
lea _pCurException(pc), a1 ;
move.l (a1), a0 ; goto previous CallCatchBlock
cmp.l #0, a0
ifne
move.l (a0), a0 ;
cmp.l #0, a0
ifne
move.l 24(a0), a0
cmp.l pRN, a0 ; if this is the same frame as before
ifeq
lea pExcept, a0
move.l (a0), d1 ; saved the destoryed object
move.l #0xffffffff, (a0) ; mark the object destoried ???
else
move.l pExcept, d1
endif
endif
endif
endif
add.l #8, a7
move.l (a7)+, d0 ; restore continuation address
;destructing exception objs in CallCatchBlocks above of pRN,
;if it is not a re-throw from anyone being destructed already
lea _pCurException(pc), a1 ;
move.l (a1), a0 ; goto previous CallCatchBlock
cmp.l #0, a0
ifeq
jmp 40$
endif
cmp.l (a0), a0
ifeq
move.l #0, (a0) ; dangling frame without clean up
endif
move.l (a0), a0
cmp.l #0, a0
ifeq
move.l #0, (a1)
jmp 40$
endif
move.l a0, (a1) ; update _pCurException
cmp.l pRN, a0
ifls
; move.l pExcept, d1
jmp 30$ ; we need to destruct previous thrown exception objs
else
; move.l #0, (a1)
jmp 40$ ; we done
endif
;d1 -- just destructed exception object
;d2 -- previous exception object
;a0 -- point to previous CallCatchBlock frame
do
move.l 20(a0), d2 ; previous pExcept, 20 bytes(saved ret, saved CatchDepth, saved _pCurException, olda6, ret)off _pCurException
cmp.l d1, d2
ifne
;this is not a re-throw
; if this is not the exceptions from the same pRN frame, if from same pRN, don't destruct, return will do that
; move.l 24(a0), d1
; cmp.l pRN, d1
; ifne
movem.l <a0-a1, d0-d2>, -(a7)
move.l #1, -(a7)
move.l d2, -(a7)
jsr DestructExceptionObject
add.l #8, a7 ;clean up stack
movem.l (a7)+, <a0-a1, d0-d2>
move.l 24(a0), d1
cmp.l pRN, d1
ifeq
move.l a0, d1 ; d1 -- scratch
lea 20(a0), a0
move.l #0xffffffff, (a0) ; mark the object destroied ???
move.l d1, a0
endif
move.l d2, d1
; endif
endif
move.l (a0), a0
move.l a0, (a1) ;update _pCurException
;if CallCatchBlock is below pRN, we done
cmp.l pRN, a0
ifhi
jmp 40$
endif
30$: cmp.l #0, a0
untileq
; clean up the allocated slot
40$: add.l #12, a7
cEnd CallCatchBlock
; void MacExceptionDispatch(pExceptionRecord);
; This function will start to search backwards on call frames with EH record,
; it will call each frame handler to try to find a handler that handles the
; exception.
cProc MacExceptionDispatch, PUBLIC,,0
parmD pExceptionRecord
cBegin MacExceptionDispatch
;a0 -- use as a6
;d0 -- flag
;a1 -- pRN
move.l a6, a0
do
;skip non-EH frame
move.l #1, d0
do
cmp.l #0, a0
ifeq
jmp 50$ ; we done, we are at the end of frame
endif
cmp.l #4, 4(a0) ;
ifhi
move.l (a0), a0 ; this is a frame without EH
else
cmp.l #1, 4(a0)
ifeq
move.l 8(a0), a0 ; this is a swapper frame without EH
else
move.l #0, d0 ; okay, we got a EH
endif
endif
cmp.l #0, d0
untileq
;okay, we got a frame with EH
;let's figure out the offset from A6 to EH record
cmp.l #2, 4(a0)
ifeq
move.l #-cbEHRecord, a1
else
move.l #-(cbSwapperRecord+cbEHRecord - 0x4), a1
endif
add.l a0, a1 ; start of EH record
movem.l <a0-a1, d0-d2>, -(a7) ; save regs
move.l #0, -(a7) ; pDC
move.l #0, -(a7) ; pContext
move.l a1, -(a7) ; pRN
move.l pExceptionRecord, -(a7) ;pExceptionRecord
move.l (a1), a1 ; get frame handler
jsr (a1)
add.l #32, a7 ; clean up the stack
movem.l (a7)+, <a0-a1, d0-d2>
; if returns, continue search for next frame
cmp.l #2, 4(a0)
ifeq
move.l (a0), a0
else
move.l 8(a0), a0
endif
cmp.l #0, a0
untileq
50$: Assert("we are at the end of frame, exit");
; we are exiting
jsr __terminate
cEnd MacExceptionDispatch
;void * OffsetToAddress( ptrdiff_t, EHRegistrationNode* );
;
;return the offset of Exception object from frame pointer (a6)
cProc OffsetToAddress, PUBLIC,,2
parmD off
parmD pRN
cBegin OffsetToAddress
;figure out the target A6 is, depending on if it's swappable frame
move.l pRN, a0 ; load pRN
cmp.l #2, ofsRNFromA6Number(a0)
ifeq
move.l #ofsRNFromA6, d0
else
cmp.l #3, ofsRNFromA6SwapNumber(a0)
ifeq
move.l #ofsRNFromA6Swap, d0
else
Assert("stack being corruptted, we are not in a valid EH frame!");
endif
endif
add.l a0, d0 ; target a6 is pRN + ofsFromA6[Swap]
add.l off, d0
cEnd OffsetToAddress
; int GetCatchDepth(void);
cProc GetCatchDepth, PUBLIC,,2
parmD pRN
cBegin GetCatchDepth
lea _pCurException(pc), a0
move.l (a0), a0
cmp.l #0, a0
ifne
move.l pRN, d0
cmp.l 24(a0), d0 ; previous pRN (_pCurException, catchdepth, saved ret, old a6, ret, pExcept) off _pCurException
ifeq ; nested try catch case
move.l 4(a0), d0
addq.l #1, d0
else
move.l 4(a0), d0
endif
else
move.l #0, d0
endif
cEnd GetCatchDepth