summaryrefslogtreecommitdiffstats
path: root/private/crt32/misc/i386/exsup3.asm
blob: ff8a91dfac0f0c2db030fca8a03f05359291709f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
;***
;exsup3.asm
;
;	Copyright (c) 1994 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
;
;*******************************************************************************

;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

ifdef _WIN32_
_WIN32_OR_POSIX_ equ 1
endif
ifdef _POSIX_
_WIN32_OR_POSIX_ equ 1
endif

.xlist
include pversion.inc
?DFDATA =	1
?NODATA =	1
include cmacros.mas
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

;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

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
if	@Version LT 600
ifdef _WIN32_OR_POSIX_
;this needs to go here to work around a masm5 bug. (emits wrong fixup)
assumes CS,FLAT
else
assumes CS,CODE
endif
endif

;/* _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)
cProc _except_handler3,<C,PUBLIC>,<IBX,ISI,IDI,IBP>
        parmDP  xrecord
        parmDP  registration
        parmDP  context
        parmDP  dispatcher
        localV  xp,SIZEOF_EXCEPTION_POINTERS
cBegin
	;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     short _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
; 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:
cEnd

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