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
|