2 * msvcrt C++ exception handling
4 * Copyright 2002 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #ifndef __MSVCRT_CPPEXCEPT_H
22 #define __MSVCRT_CPPEXCEPT_H
27 #define CXX_FRAME_MAGIC_VC6 0x19930520
28 #define CXX_FRAME_MAGIC_VC7 0x19930521
29 #define CXX_FRAME_MAGIC_VC8 0x19930522
30 #define CXX_EXCEPTION 0xe06d7363
40 #define CXX_EXCEPTION_PARAMS 3
42 /* info about a single catch {} block */
45 UINT flags
; /* flags (see below) */
46 const type_info
*type_info
; /* C++ type caught by this block */
47 int offset
; /* stack offset to copy exception object to */
48 void * (*handler
)(void);/* catch block handler code */
51 /* info about a single try {} block */
54 int start_level
; /* start trylevel of that block */
55 int end_level
; /* end trylevel of that block */
56 int catch_level
; /* initial trylevel of the catch block */
57 unsigned int catchblock_count
; /* count of catch blocks in array */
58 const catchblock_info
*catchblock
; /* array of catch blocks */
61 /* info about the unwind handler for a given trylevel */
64 int prev
; /* prev trylevel unwind handler, to run after this one */
65 void * (*handler
)(void);/* unwind handler */
68 /* descriptor of all try blocks of a given function */
71 UINT magic
: 29; /* must be CXX_FRAME_MAGIC */
73 UINT unwind_count
; /* number of unwind handlers */
74 const unwind_info
*unwind_table
; /* array of unwind handlers */
75 UINT tryblock_count
; /* number of try blocks */
76 const tryblock_info
*tryblock
; /* array of try blocks */
78 const ipmap_info
*ipmap
;
79 const void *expect_list
; /* expected exceptions list when magic >= VC7 */
80 UINT flags
; /* flags when magic >= VC8 */
83 #else /* RTTI_USE_RVA */
85 #define CXX_EXCEPTION_PARAMS 4
103 UINT catchblock_count
;
126 } cxx_function_descr
;
128 #endif /* RTTI_USE_RVA */
130 #define FUNC_DESCR_SYNCHRONOUS 1 /* synchronous exceptions only (built with /EHs and /EHsc) */
131 #define FUNC_DESCR_NOEXCEPT 4 /* noexcept function */
133 #define CLASS_IS_SIMPLE_TYPE 1
134 #define CLASS_HAS_VIRTUAL_BASE_CLASS 4
136 #define TYPE_FLAG_CONST 1
137 #define TYPE_FLAG_VOLATILE 2
138 #define TYPE_FLAG_REFERENCE 8
140 void WINAPI
_CxxThrowException(void*,const cxx_exception_type
*);
142 static inline BOOL
is_cxx_exception( EXCEPTION_RECORD
*rec
)
144 if (rec
->ExceptionCode
!= CXX_EXCEPTION
) return FALSE
;
145 if (rec
->NumberParameters
!= CXX_EXCEPTION_PARAMS
) return FALSE
;
146 return (rec
->ExceptionInformation
[0] >= CXX_FRAME_MAGIC_VC6
&&
147 rec
->ExceptionInformation
[0] <= CXX_FRAME_MAGIC_VC8
);
152 EXCEPTION_RECORD
*rec
;
153 LONG
*ref
; /* not binary compatible with native msvcr100 */
156 void throw_exception(const char*);
157 void exception_ptr_from_record(exception_ptr
*,EXCEPTION_RECORD
*);
159 void __cdecl
__ExceptionPtrCreate(exception_ptr
*);
160 void __cdecl
__ExceptionPtrDestroy(exception_ptr
*);
161 void __cdecl
__ExceptionPtrRethrow(const exception_ptr
*);
163 BOOL __cdecl
__uncaught_exception(void);
165 static inline const char *dbgstr_type_info( const type_info
*info
)
167 if (!info
) return "{}";
168 return wine_dbg_sprintf( "{vtable=%p name=%s (%s)}",
169 info
->vtable
, info
->mangled
, info
->name
? info
->name
: "" );
172 /* compute the this pointer for a base class of a given type */
173 static inline void *get_this_pointer( const this_ptr_offsets
*off
, void *object
)
175 if (!object
) return NULL
;
177 if (off
->vbase_descr
>= 0)
181 /* move this ptr to vbase descriptor */
182 object
= (char *)object
+ off
->vbase_descr
;
183 /* and fetch additional offset from vbase descriptor */
184 offset_ptr
= (int *)(*(char **)object
+ off
->vbase_offset
);
185 object
= (char *)object
+ *offset_ptr
;
188 object
= (char *)object
+ off
->this_offset
;
192 #ifdef __ASM_USE_THISCALL_WRAPPER
193 extern void call_copy_ctor( void *func
, void *this, void *src
, int has_vbase
);
194 extern void call_dtor( void *func
, void *this );
196 static inline void call_copy_ctor( void *func
, void *this, void *src
, int has_vbase
)
199 ((void (__thiscall
*)(void*, void*, BOOL
))func
)(this, src
, 1);
201 ((void (__thiscall
*)(void*, void*))func
)(this, src
);
203 static inline void call_dtor( void *func
, void *this )
205 ((void (__thiscall
*)(void*))func
)( this );
209 /* check if the exception type is caught by a given catch block, and return the type that matched */
210 static inline const cxx_type_info
*find_caught_type( cxx_exception_type
*exc_type
, uintptr_t base
,
211 const type_info
*catch_ti
, UINT catch_flags
)
213 const cxx_type_info_table
*type_info_table
= rtti_rva( exc_type
->type_info_table
, base
);
216 for (i
= 0; i
< type_info_table
->count
; i
++)
218 const cxx_type_info
*type
= rtti_rva( type_info_table
->info
[i
], base
);
219 const type_info
*ti
= rtti_rva( type
->type_info
, base
);
221 if (!catch_ti
) return type
; /* catch(...) matches any type */
224 if (strcmp( catch_ti
->mangled
, ti
->mangled
)) continue;
226 /* type is the same, now check the flags */
227 if ((exc_type
->flags
& TYPE_FLAG_CONST
) &&
228 !(catch_flags
& TYPE_FLAG_CONST
)) continue;
229 if ((exc_type
->flags
& TYPE_FLAG_VOLATILE
) &&
230 !(catch_flags
& TYPE_FLAG_VOLATILE
)) continue;
231 return type
; /* it matched */
236 /* copy the exception object where the catch block wants it */
237 static inline void copy_exception( void *object
, void **dest
, UINT catch_flags
,
238 const cxx_type_info
*type
, uintptr_t base
)
240 if (catch_flags
& TYPE_FLAG_REFERENCE
)
242 *dest
= get_this_pointer( &type
->offsets
, object
);
244 else if (type
->flags
& CLASS_IS_SIMPLE_TYPE
)
246 memmove( dest
, object
, type
->size
);
247 /* if it is a pointer, adjust it */
248 if (type
->size
== sizeof(void*)) *dest
= get_this_pointer( &type
->offsets
, *dest
);
250 else /* copy the object */
253 call_copy_ctor( rtti_rva( type
->copy_ctor
, base
), dest
,
254 get_this_pointer( &type
->offsets
, object
),
255 (type
->flags
& CLASS_HAS_VIRTUAL_BASE_CLASS
) );
257 memmove( dest
, get_this_pointer( &type
->offsets
, object
), type
->size
);
261 #define TRACE_EXCEPTION_TYPE(type,base) do { \
262 const cxx_type_info_table *table = rtti_rva( type->type_info_table, base ); \
264 TRACE( "flags %x destr %p handler %p type info %p\n", \
265 type->flags, rtti_rva( type->destructor, base ), \
266 type->custom_handler ? rtti_rva( type->custom_handler, base ) : NULL, table ); \
267 for (i = 0; i < table->count; i++) \
269 const cxx_type_info *type = rtti_rva( table->info[i], base ); \
270 const type_info *info = rtti_rva( type->type_info, base ); \
271 TRACE( " %d: flags %x type %p %s offsets %d,%d,%d size %d copy ctor %p\n", \
272 i, type->flags, info, dbgstr_type_info( info ), \
273 type->offsets.this_offset, type->offsets.vbase_descr, type->offsets.vbase_offset, \
274 type->size, rtti_rva( type->copy_ctor, base )); \
278 extern void dump_function_descr( const cxx_function_descr
*descr
, uintptr_t base
);
279 extern void *find_catch_handler( void *object
, uintptr_t frame
, uintptr_t exc_base
,
280 const tryblock_info
*tryblock
,
281 cxx_exception_type
*exc_type
, uintptr_t image_base
);
282 extern int handle_fpieee_flt( __msvcrt_ulong exception_code
, EXCEPTION_POINTERS
*ep
,
283 int (__cdecl
*handler
)(_FPIEEE_RECORD
*) );
285 extern void *call_catch_handler( EXCEPTION_RECORD
*rec
);
286 extern void *call_unwind_handler( void *func
, uintptr_t frame
, DISPATCHER_CONTEXT
*dispatch
);
287 extern ULONG_PTR
get_exception_pc( DISPATCHER_CONTEXT
*dispatch
);
291 #define EXCEPTION_MANGLED_NAME ".?AVexception@std@@"
293 #define EXCEPTION_MANGLED_NAME ".?AVexception@@"
296 #define CREATE_EXCEPTION_OBJECT(exception_name) \
297 static exception* __exception_ctor(exception *this, const char *str, const vtable_ptr *vtbl) \
301 unsigned int len = strlen(str) + 1; \
302 this->name = malloc(len); \
303 memcpy(this->name, str, len); \
304 this->do_free = TRUE; \
309 this->do_free = FALSE; \
311 this->vtable = vtbl; \
315 static exception* __exception_copy_ctor(exception *this, const exception *rhs, const vtable_ptr *vtbl) \
319 __exception_ctor(this, rhs->name, vtbl); \
324 this->vtable = vtbl; \
328 extern const vtable_ptr exception_name ## _vtable; \
329 DEFINE_THISCALL_WRAPPER(exception_name ## _copy_ctor,8) \
330 exception* __thiscall exception_name ## _copy_ctor(exception *this, const exception *rhs) \
332 return __exception_copy_ctor(this, rhs, & exception_name ## _vtable); \
335 DEFINE_THISCALL_WRAPPER(exception_name ## _dtor,4) \
336 void __thiscall exception_name ## _dtor(exception *this) \
338 if (this->do_free) free(this->name); \
341 DEFINE_THISCALL_WRAPPER(exception_name ## _vector_dtor,8) \
342 void* __thiscall exception_name ## _vector_dtor(exception *this, unsigned int flags) \
346 INT_PTR i, *ptr = (INT_PTR *)this - 1; \
348 for (i = *ptr - 1; i >= 0; i--) exception_name ## _dtor(this + i); \
349 operator_delete(ptr); \
353 exception_name ## _dtor(this); \
354 if (flags & 1) operator_delete(this); \
359 DEFINE_THISCALL_WRAPPER(exception_name ## _what,4) \
360 const char* __thiscall exception_name ## _what(exception *this) \
362 return this->name ? this->name : "Unknown exception"; \
365 __ASM_BLOCK_BEGIN(exception_name ## _vtables) \
366 __ASM_VTABLE(exception_name, \
367 VTABLE_ADD_FUNC(exception_name ## _vector_dtor) \
368 VTABLE_ADD_FUNC(exception_name ## _what)); \
371 DEFINE_RTTI_DATA0(exception_name, 0, EXCEPTION_MANGLED_NAME)
373 #endif /* __MSVCRT_CPPEXCEPT_H */