source: trunk/include/excpt.h@ 21654

Last change on this file since 21654 was 21636, checked in by dmik, 14 years ago

SEH: Preserve EDX before try just in case if the compiler happens to store something important in it when optimizing (it should normally not though).

File size: 11.3 KB
RevLine 
[4]1/*
[21381]2 * Project Odin Software License can be found in LICENSE.TXT
[4]3 *
[21381]4 * Compiler-level Win32 SEH support for OS/2
[4]5 *
[21605]6 * Copyright 2010 Dmitriy Kuminov
[4]7 */
8
[21448]9/*
10 * NOTE: This __try/__except and __try/__finally/__leave implementation is not
11 * backed up by the low level compiler support and therefore the following
12 * limitations exist comparing to the MSVC implementation (breaking them will
13 * crash the application):
14 *
[21474]15 * 1. You cannot use the return statement within __try or __except or __finally
16 * blocks.
[21448]17 *
[21474]18 * 2. You cannot use the goto statement or the longjmp() function within __try
19 * or __except or __finally blocks if it passes control outside these blocks.
20 *
[21448]21 * 2. If you use __try and friends inside a do/while/for/switch block, you will
22 * lose the meaning of break and continue statements and must not use them.
23 *
24 * 3. The scopes of C and C++ exception blocks may not overlap (i.e. you cannot
25 * use try/catch inside __try/__except and vice versa).
26 *
27 * 4. There may be some other (yet unknown) limitations.
28 *
29 * Fortunately, in most cases, these limitations may be worked around by
30 * slightly changing the original source code.
31 */
32
[21381]33#ifndef __EXCPT_H__
34#define __EXCPT_H__
35
[21387]36#include <windows.h>
[21381]37
38#ifdef __cplusplus
39extern "C" {
40#endif
41
42#if defined(__GNUC__)
43
[21474]44struct ___seh_EXCEPTION_FRAME;
[21381]45typedef int (*__seh_PEXCEPTION_HANDLER)(PEXCEPTION_RECORD,
[21474]46 struct ___seh_EXCEPTION_FRAME *,
[21381]47 PCONTEXT, PVOID);
48
[21474]49#pragma pack(1)
50
51typedef struct ___seh_EXCEPTION_FRAME
[21381]52{
[21474]53 /* + 0 */ struct ___seh_EXCEPTION_FRAME *pPrev;
54 /* + 4 */ __seh_PEXCEPTION_HANDLER pHandler;
55 /* + 8 */ void *pFilterCallback;
56 /* +12 */ void *pHandlerCallback;
57 /* +16 */ void *pHandlerContext;
58 /* +20 */ int filterResult;
59 /* +24 */ DWORD EBX;
60 /* +28 */ DWORD ESI;
61 /* +32 */ DWORD EDI;
62 /* +36 */ DWORD EBP;
63 /* +40 */ DWORD ESP;
64 /* +44 */ DWORD pPrevFrameOS2;
65 /* +48 */ EXCEPTION_POINTERS Pointers;
66 /* +56 */ int state;
67 /* +60 */ DWORD pPrevFrameWin32;
[21633]68 /* +64 */ DWORD Win32FS;
[21381]69}
[21474]70__seh_EXCEPTION_FRAME;
[21381]71
[21474]72#pragma pack()
[21381]73
[21474]74extern int __seh_handler(PEXCEPTION_RECORD pRec,
75 struct ___seh_EXCEPTION_FRAME *pFrame,
76 PCONTEXT pContext, PVOID pVoid);
77
[21387]78#define _exception_code() (__seh_frame.Pointers.ExceptionRecord->ExceptionCode)
[21474]79#define _exception_info() ((void *)&__seh_frame.Pointers)
[21381]80
[21474]81#define exception_code _exception_code
82#define exception_info (PEXCEPTION_POINTERS)_exception_info
83
[21387]84#define GetExceptionCode _exception_code
[21474]85#define GetExceptionInformation (PEXCEPTION_POINTERS)_exception_info
[21387]86
[21381]87#define __try \
[21474]88 volatile __seh_EXCEPTION_FRAME __seh_frame; \
89 __seh_frame.pHandler = __seh_handler; \
[21427]90 __seh_frame.Pointers.ExceptionRecord = NULL; \
91 __seh_frame.Pointers.ContextRecord = NULL; \
[21382]92 __seh_frame.state = 0; \
[21636]93 /* install exception handler, both Win32 and OS/2 chains (note: EDX is in \
94 * clobber too since it may carry any value when we jump back to \
95 * pFilterCallback from the handler */ \
96 __asm__ ("leal %0, %%ecx; " \
97 "movl %%fs, %%eax; " \
98 "andl $0x0000FFFF, %%eax; " \
99 "movl %%eax, 64(%%ecx); " \
100 "movl %%fs:0, %%eax; " \
101 "movl %%eax, 0(%%ecx); " \
102 "movl %%eax, 60(%%ecx); " \
103 "movl $0f, 8(%%ecx); " \
104 \
105 "movl %%ebx, 24(%%ecx); " \
106 "movl %%esi, 28(%%ecx); " \
107 "movl %%edi, 32(%%ecx); " \
108 "movl %%ebp, 36(%%ecx); " \
109 "movl %%esp, 40(%%ecx); " \
110 \
111 "pushl %%fs; " \
112 "pushl $Dos32TIB; " \
113 "popl %%fs; " \
114 "movl %%fs:0, %%eax; " \
115 "movl %%eax, 44(%%ecx); " \
116 "movl %%ecx, %%fs:0; " \
117 "popl %%fs; " \
118 \
119 "movl %%ecx, %%fs:0; " \
120 \
121 "\n0: /* pFilterCallback */ \n" \
122 \
123 : : "m" (__seh_frame) \
124 : "%eax", "%ecx", "%edx"); \
[21382]125 for (; __seh_frame.state <= 3; ++__seh_frame.state) \
[21381]126 if (__seh_frame.state == 0) \
127 { \
128 {
129
130#define __except(filter_expr) \
131 } \
[21448]132 /* cause the next state to be 3 */ \
[21381]133 __seh_frame.state = 2; \
134 } \
135 else if (__seh_frame.state == 1) { \
[21448]136 /* execption caught, call filter expression */ \
[21381]137 __seh_frame.filterResult = (filter_expr); \
138 __asm__("leal %0, %%ebx; jmp *%1" \
139 : : "m"(__seh_frame), "m"(__seh_frame.pHandlerCallback) \
140 : "%ebx"); \
141 } \
142 else if (__seh_frame.state == 3) \
[21633]143 /* remove exception handler (note that for some reason SMP kernel \
144 * seems to garbage the Win32FS:[0] cell with the OS/2 exception \
145 * registration record, so use the original __seh_frame value) */ \
146 __asm__ ("leal %0, %%ecx; " \
[21636]147 \
[21633]148 "movl 64(%%ecx), %%eax; " \
149 "movl %%eax, %%fs; " \
[21636]150 \
[21474]151 "movl 60(%%ecx), %%eax; " \
[21381]152 "movl %%eax, %%fs:0; " \
[21636]153 \
[21474]154 "pushl %%fs; " \
155 "pushl $Dos32TIB; " \
156 "popl %%fs; " \
157 "movl 44(%%ecx), %%eax; " \
158 "movl %%eax, %%fs:0; " \
159 "popl %%fs; " \
[21633]160 : : "m"(__seh_frame) \
[21474]161 : "%eax", "%ecx"); \
[21448]162 else /* __seh_frame.state == 2 -> execute except block */
[21381]163
[21448]164#define __finally \
165 } \
166 /* cause the next state to be 2 */ \
167 __seh_frame.state = 1; \
168 } \
169 else if (__seh_frame.state == 1) { \
170 /* execption caught, handle and proceed to the filally block */ \
171 __seh_frame.filterResult = EXCEPTION_EXECUTE_HANDLER; \
172 __asm__("leal %0, %%ebx; jmp *%1" \
173 : : "m"(__seh_frame), "m"(__seh_frame.pHandlerCallback) \
174 : "%ebx"); \
175 } \
176 else if (__seh_frame.state == 3) \
[21633]177 /* remove exception handler (note that for some reason SMP kernel \
178 * seems to garbage the Win32FS:[0] cell with the OS/2 exception \
179 * registration record, so use the original __seh_frame value) */ \
180 __asm__ ("leal %0, %%ecx; " \
[21636]181 \
[21633]182 "movl 64(%%ecx), %%eax; " \
183 "movl %%eax, %%fs; " \
[21636]184 \
[21474]185 "movl 60(%%ecx), %%eax; " \
[21448]186 "movl %%eax, %%fs:0; " \
[21636]187 \
[21474]188 "pushl %%fs; " \
189 "pushl $Dos32TIB; " \
190 "popl %%fs; " \
191 "movl 44(%%ecx), %%eax; " \
192 "movl %%eax, %%fs:0; " \
193 "popl %%fs; " \
[21633]194 : : "m"(__seh_frame) \
[21474]195 : "%eax", "%ecx"); \
[21448]196 else /* __seh_frame.state == 2 -> execute finally block */
197
198#define __leave \
199 /* cause the next state to be 2 */ \
200 __seh_frame.state = 1; \
201 continue;
202
[21381]203#else /* defined(__GNUC__) */
204
205#warning "Structured exception handling is not supported for this compiler!"
206
207#endif /* defined(__GNUC__) */
208
209#ifdef __cplusplus
210}
211#endif
212
213#endif /* __EXCPT_H__ */
[21387]214
Note: See TracBrowser for help on using the repository browser.