include/mscvpdb.h: Use flexible array members for the rest of structures.
[wine.git] / dlls / msvcrt / cppexcept.h
blobb6f962a62e0f62ced45006e0203b4957ad458f72
1 /*
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
24 #include <fpieee.h>
25 #include "cxx.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
32 typedef struct
34 UINT ip;
35 int state;
36 } ipmap_info;
38 #ifndef RTTI_USE_RVA
40 #define CXX_EXCEPTION_PARAMS 3
42 /* info about a single catch {} block */
43 typedef struct
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 */
49 } catchblock_info;
51 /* info about a single try {} block */
52 typedef struct
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 */
59 } tryblock_info;
61 /* info about the unwind handler for a given trylevel */
62 typedef struct
64 int prev; /* prev trylevel unwind handler, to run after this one */
65 void * (*handler)(void);/* unwind handler */
66 } unwind_info;
68 /* descriptor of all try blocks of a given function */
69 typedef struct
71 UINT magic : 29; /* must be CXX_FRAME_MAGIC */
72 UINT bbt_flags : 3;
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 */
77 UINT ipmap_count;
78 const ipmap_info *ipmap;
79 const void *expect_list; /* expected exceptions list when magic >= VC7 */
80 UINT flags; /* flags when magic >= VC8 */
81 } cxx_function_descr;
83 #else /* RTTI_USE_RVA */
85 #define CXX_EXCEPTION_PARAMS 4
87 typedef struct
89 UINT flags;
90 UINT type_info;
91 int offset;
92 UINT handler;
93 #ifdef _WIN64
94 UINT frame;
95 #endif
96 } catchblock_info;
98 typedef struct
100 int start_level;
101 int end_level;
102 int catch_level;
103 UINT catchblock_count;
104 UINT catchblock;
105 } tryblock_info;
107 typedef struct
109 int prev;
110 UINT handler;
111 } unwind_info;
113 typedef struct
115 UINT magic : 29;
116 UINT bbt_flags : 3;
117 UINT unwind_count;
118 UINT unwind_table;
119 UINT tryblock_count;
120 UINT tryblock;
121 UINT ipmap_count;
122 UINT ipmap;
123 int unwind_help;
124 UINT expect_list;
125 UINT flags;
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);
150 typedef struct
152 EXCEPTION_RECORD *rec;
153 LONG *ref; /* not binary compatible with native msvcr100 */
154 } exception_ptr;
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)
179 int *offset_ptr;
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;
189 return object;
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 );
195 #else
196 static inline void call_copy_ctor( void *func, void *this, void *src, int has_vbase )
198 if (has_vbase)
199 ((void (__thiscall*)(void*, void*, BOOL))func)(this, src, 1);
200 else
201 ((void (__thiscall*)(void*, void*))func)(this, src);
203 static inline void call_dtor( void *func, void *this )
205 ((void (__thiscall*)(void*))func)( this );
207 #endif
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 );
214 UINT i;
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 */
222 if (catch_ti != ti)
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 */
233 return NULL;
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 */
252 if (type->copy_ctor)
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) );
256 else
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 ); \
263 unsigned int i; \
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 )); \
276 } while(0)
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*) );
284 #ifndef __i386__
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 );
288 #endif
290 #if _MSVCR_VER >= 80
291 #define EXCEPTION_MANGLED_NAME ".?AVexception@std@@"
292 #else
293 #define EXCEPTION_MANGLED_NAME ".?AVexception@@"
294 #endif
296 #define CREATE_EXCEPTION_OBJECT(exception_name) \
297 static exception* __exception_ctor(exception *this, const char *str, const vtable_ptr *vtbl) \
299 if (str) \
301 unsigned int len = strlen(str) + 1; \
302 this->name = malloc(len); \
303 memcpy(this->name, str, len); \
304 this->do_free = TRUE; \
306 else \
308 this->name = NULL; \
309 this->do_free = FALSE; \
311 this->vtable = vtbl; \
312 return this; \
315 static exception* __exception_copy_ctor(exception *this, const exception *rhs, const vtable_ptr *vtbl) \
317 if (rhs->do_free) \
319 __exception_ctor(this, rhs->name, vtbl); \
321 else \
323 *this = *rhs; \
324 this->vtable = vtbl; \
326 return this; \
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) \
344 if (flags & 2) \
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); \
351 else \
353 exception_name ## _dtor(this); \
354 if (flags & 1) operator_delete(this); \
356 return 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)); \
369 __ASM_BLOCK_END \
371 DEFINE_RTTI_DATA0(exception_name, 0, EXCEPTION_MANGLED_NAME)
373 #endif /* __MSVCRT_CPPEXCEPT_H */