wined3d: Add one more FBO error status code.
[wine] / include / wine / exception.h
1 /*
2  * Wine exception handling
3  *
4  * Copyright (c) 1999 Alexandre Julliard
5  *
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.
10  *
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.
15  *
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
19  */
20
21 #ifndef __WINE_WINE_EXCEPTION_H
22 #define __WINE_WINE_EXCEPTION_H
23
24 #include <setjmp.h>
25 #include <windef.h>
26 #include <excpt.h>
27
28 /* The following definitions allow using exceptions in Wine and Winelib code
29  *
30  * They should be used like this:
31  *
32  * __TRY
33  * {
34  *     do some stuff that can raise an exception
35  * }
36  * __EXCEPT(filter_func,param)
37  * {
38  *     handle the exception here
39  * }
40  * __ENDTRY
41  *
42  * or
43  *
44  * __TRY
45  * {
46  *     do some stuff that can raise an exception
47  * }
48  * __FINALLY(finally_func,param)
49  *
50  * The filter_func must be defined with the WINE_EXCEPTION_FILTER
51  * macro, and return one of the EXCEPTION_* code; it can use
52  * GetExceptionInformation and GetExceptionCode to retrieve the
53  * exception info.
54  *
55  * The finally_func must be defined with the WINE_FINALLY_FUNC macro.
56  *
57  * Warning: inside a __TRY or __EXCEPT block, 'break' or 'continue' statements
58  *          break out of the current block. You cannot use 'return', 'goto'
59  *          or 'longjmp' to leave a __TRY block, as this will surely crash.
60  *          You can use them to leave a __EXCEPT block though.
61  *
62  * -- AJ
63  */
64
65 /* Define this if you want to use your compiler built-in __try/__except support.
66  * This is only useful when compiling to a native Windows binary, as the built-in
67  * compiler exceptions will most certainly not work under Winelib.
68  */
69 #ifdef USE_COMPILER_EXCEPTIONS
70
71 #define __TRY __try
72 #define __EXCEPT(func) __except((func)(GetExceptionInformation()))
73 #define __FINALLY(func) __finally { (func)(!AbnormalTermination()); }
74 #define __ENDTRY /*nothing*/
75 #define __EXCEPT_PAGE_FAULT __except(GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
76 #define __EXCEPT_ALL __except(EXCEPTION_EXECUTE_HANDLER)
77
78 #else  /* USE_COMPILER_EXCEPTIONS */
79
80 #ifndef __GNUC__
81 #define __attribute__(x) /* nothing */
82 #endif
83
84 #if defined(__MINGW32__) || defined(__CYGWIN__)
85 #define sigjmp_buf jmp_buf
86 #define sigsetjmp(buf,sigs) setjmp(buf)
87 #define siglongjmp(buf,val) longjmp(buf,val)
88 #endif
89
90 #define __TRY \
91     do { __WINE_FRAME __f; \
92          int __first = 1; \
93          for (;;) if (!__first) \
94          { \
95              do {
96
97 #define __EXCEPT(func) \
98              } while(0); \
99              __wine_pop_frame( &__f.frame ); \
100              break; \
101          } else { \
102              __f.frame.Handler = __wine_exception_handler; \
103              __f.u.filter = (func); \
104              if (sigsetjmp( __f.jmp, 0 )) { \
105                  const __WINE_FRAME * const __eptr __attribute__((unused)) = &__f; \
106                  do {
107
108 /* convenience handler for page fault exceptions */
109 #define __EXCEPT_PAGE_FAULT \
110              } while(0); \
111              __wine_pop_frame( &__f.frame ); \
112              break; \
113          } else { \
114              __f.frame.Handler = __wine_exception_handler_page_fault; \
115              if (sigsetjmp( __f.jmp, 0 )) { \
116                  const __WINE_FRAME * const __eptr __attribute__((unused)) = &__f; \
117                  do {
118
119 /* convenience handler for all exception */
120 #define __EXCEPT_ALL \
121              } while(0); \
122              __wine_pop_frame( &__f.frame ); \
123              break; \
124          } else { \
125              __f.frame.Handler = __wine_exception_handler_all; \
126              if (sigsetjmp( __f.jmp, 0 )) { \
127                  const __WINE_FRAME * const __eptr __attribute__((unused)) = &__f; \
128                  do {
129
130 #define __ENDTRY \
131                  } while (0); \
132                  break; \
133              } \
134              __wine_push_frame( &__f.frame ); \
135              __first = 0; \
136          } \
137     } while (0);
138
139 #define __FINALLY(func) \
140              } while(0); \
141              __wine_pop_frame( &__f.frame ); \
142              (func)(1); \
143              break; \
144          } else { \
145              __f.frame.Handler = __wine_finally_handler; \
146              __f.u.finally_func = (func); \
147              __wine_push_frame( &__f.frame ); \
148              __first = 0; \
149          } \
150     } while (0);
151
152
153 typedef LONG (CALLBACK *__WINE_FILTER)(PEXCEPTION_POINTERS);
154 typedef void (CALLBACK *__WINE_FINALLY)(BOOL);
155
156 #define GetExceptionInformation() (__eptr)
157 #define GetExceptionCode()        (__eptr->ExceptionRecord->ExceptionCode)
158 #define AbnormalTermination()     (!__normal)
159
160 typedef struct __tagWINE_FRAME
161 {
162     EXCEPTION_REGISTRATION_RECORD frame;
163     union
164     {
165         /* exception data */
166         __WINE_FILTER filter;
167         /* finally data */
168         __WINE_FINALLY finally_func;
169     } u;
170     sigjmp_buf jmp;
171     /* hack to make GetExceptionCode() work in handler */
172     DWORD ExceptionCode;
173     const struct __tagWINE_FRAME *ExceptionRecord;
174 } __WINE_FRAME;
175
176 #endif /* USE_COMPILER_EXCEPTIONS */
177
178 static inline EXCEPTION_REGISTRATION_RECORD *__wine_push_frame( EXCEPTION_REGISTRATION_RECORD *frame )
179 {
180 #if defined(__GNUC__) && defined(__i386__)
181     EXCEPTION_REGISTRATION_RECORD *prev;
182     __asm__ __volatile__(".byte 0x64\n\tmovl (0),%0"
183                          "\n\tmovl %0,(%1)"
184                          "\n\t.byte 0x64\n\tmovl %1,(0)"
185                          : "=&r" (prev) : "r" (frame) : "memory" );
186     return prev;
187 #else
188     NT_TIB *teb = (NT_TIB *)NtCurrentTeb();
189     frame->Prev = teb->ExceptionList;
190     teb->ExceptionList = frame;
191     return frame->Prev;
192 #endif
193 }
194
195 static inline EXCEPTION_REGISTRATION_RECORD *__wine_pop_frame( EXCEPTION_REGISTRATION_RECORD *frame )
196 {
197 #if defined(__GNUC__) && defined(__i386__)
198     __asm__ __volatile__(".byte 0x64\n\tmovl %0,(0)"
199                          : : "r" (frame->Prev) : "memory" );
200     return frame->Prev;
201
202 #else
203     NT_TIB *teb = (NT_TIB *)NtCurrentTeb();
204     teb->ExceptionList = frame->Prev;
205     return frame->Prev;
206 #endif
207 }
208
209 /* Exception handling flags - from OS/2 2.0 exception handling */
210
211 /* Win32 seems to use the same flags as ExceptionFlags in an EXCEPTION_RECORD */
212 #define EH_NONCONTINUABLE   0x01
213 #define EH_UNWINDING        0x02
214 #define EH_EXIT_UNWIND      0x04
215 #define EH_STACK_INVALID    0x08
216 #define EH_NESTED_CALL      0x10
217
218 /* Wine-specific exceptions codes */
219
220 #define EXCEPTION_WINE_STUB       0x80000100  /* stub entry point called */
221 #define EXCEPTION_WINE_ASSERTION  0x80000101  /* assertion failed */
222
223 /* unhandled return status from vm86 mode */
224 #define EXCEPTION_VM86_INTx       0x80000110
225 #define EXCEPTION_VM86_STI        0x80000111
226 #define EXCEPTION_VM86_PICRETURN  0x80000112
227
228 extern void __wine_enter_vm86( CONTEXT *context );
229
230 #ifndef USE_COMPILER_EXCEPTIONS
231
232 extern void WINAPI RtlUnwind(PVOID,PVOID,PEXCEPTION_RECORD,PVOID);
233
234 /* wrapper for RtlUnwind since it clobbers registers on Windows */
235 static inline void __wine_rtl_unwind( EXCEPTION_REGISTRATION_RECORD* frame, EXCEPTION_RECORD *record )
236 {
237 #if defined(__GNUC__) && defined(__i386__)
238     int dummy1, dummy2, dummy3;
239     __asm__ __volatile__("pushl %%ebp\n\t"
240                          "pushl %%ebx\n\t"
241                          "pushl $0\n\t"
242                          "pushl %2\n\t"
243                          "pushl $0\n\t"
244                          "pushl %1\n\t"
245                          "call *%0\n\t"
246                          "popl %%ebx\n\t"
247                          "popl %%ebp"
248                          : "=a" (dummy1), "=S" (dummy2), "=D" (dummy3)
249                          : "0" (RtlUnwind), "1" (frame), "2" (record)
250                          : "ecx", "edx", "memory" );
251 #else
252     RtlUnwind( frame, 0, record, 0 );
253 #endif
254 }
255
256 static inline void DECLSPEC_NORETURN __wine_unwind_frame( EXCEPTION_RECORD *record,
257                                                           EXCEPTION_REGISTRATION_RECORD *frame )
258 {
259     __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame;
260
261     /* hack to make GetExceptionCode() work in handler */
262     wine_frame->ExceptionCode   = record->ExceptionCode;
263     wine_frame->ExceptionRecord = wine_frame;
264
265     __wine_rtl_unwind( frame, record );
266     __wine_pop_frame( frame );
267     siglongjmp( wine_frame->jmp, 1 );
268 }
269
270 static inline DWORD __wine_exception_handler( EXCEPTION_RECORD *record,
271                                               EXCEPTION_REGISTRATION_RECORD *frame,
272                                               CONTEXT *context,
273                                               EXCEPTION_REGISTRATION_RECORD **pdispatcher )
274 {
275     __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame;
276     EXCEPTION_POINTERS ptrs;
277
278     if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND | EH_NESTED_CALL))
279         return ExceptionContinueSearch;
280
281     ptrs.ExceptionRecord = record;
282     ptrs.ContextRecord = context;
283     switch(wine_frame->u.filter( &ptrs ))
284     {
285     case EXCEPTION_CONTINUE_SEARCH:
286         return ExceptionContinueSearch;
287     case EXCEPTION_CONTINUE_EXECUTION:
288         return ExceptionContinueExecution;
289     case EXCEPTION_EXECUTE_HANDLER:
290         break;
291     }
292     __wine_unwind_frame( record, frame );
293 }
294
295 static inline DWORD __wine_exception_handler_page_fault( EXCEPTION_RECORD *record,
296                                                          EXCEPTION_REGISTRATION_RECORD *frame,
297                                                          CONTEXT *context,
298                                                          EXCEPTION_REGISTRATION_RECORD **pdispatcher )
299 {
300     if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND | EH_NESTED_CALL))
301         return ExceptionContinueSearch;
302     if (record->ExceptionCode != STATUS_ACCESS_VIOLATION)
303         return ExceptionContinueSearch;
304     __wine_unwind_frame( record, frame );
305 }
306
307 static inline DWORD __wine_exception_handler_all( EXCEPTION_RECORD *record,
308                                                   EXCEPTION_REGISTRATION_RECORD *frame,
309                                                   CONTEXT *context,
310                                                   EXCEPTION_REGISTRATION_RECORD **pdispatcher )
311 {
312     if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND | EH_NESTED_CALL))
313         return ExceptionContinueSearch;
314     __wine_unwind_frame( record, frame );
315 }
316
317 static inline DWORD __wine_finally_handler( EXCEPTION_RECORD *record,
318                                             EXCEPTION_REGISTRATION_RECORD *frame,
319                                             CONTEXT *context,
320                                             EXCEPTION_REGISTRATION_RECORD **pdispatcher )
321 {
322     if (record->ExceptionFlags & (EH_UNWINDING | EH_EXIT_UNWIND))
323     {
324         __WINE_FRAME *wine_frame = (__WINE_FRAME *)frame;
325         wine_frame->u.finally_func( FALSE );
326     }
327     return ExceptionContinueSearch;
328 }
329
330 #endif /* USE_COMPILER_EXCEPTIONS */
331
332 #endif  /* __WINE_WINE_EXCEPTION_H */