summaryrefslogtreecommitdiff
path: root/src/inc/palclr_win.h
blob: 18edc6c8f519f07ed0d0af72d35013b72f78f93f (plain)
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
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// ===========================================================================
// File: palclr.h
//
// Various macros and constants that are necessary to make the CLR portable.
//

// ===========================================================================

#ifndef __PALCLR_WIN_H__
#define __PALCLR_WIN_H__

// PAL SEH
// Macros for portable exception handling. The Win32 SEH is emulated using
// these macros and setjmp/longjmp on Unix
//
// Usage notes:
//
// - The filter has to be a function taking two parameters:
// LONG MyFilter(PEXCEPTION_POINTERS *pExceptionInfo, PVOID pv)
//
// - It is not possible to directly use the local variables in the filter.
// All the local information that the filter has to need to know about should
// be passed through pv parameter
//  
// - Do not use goto to jump out of the PAL_TRY block
// (jumping out of the try block is not a good idea even on Win32, because of
// it causes stack unwind)
//
//
// Simple examples:
//
// PAL_TRY {
//   ....
// } WIN_PAL_FINALLY {
//   ....
// }
// WIN_PAL_ENDTRY
//
//
// PAL_TRY {
//   ....
// } WIN_PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
//   ....
// }
// WIN_PAL_ENDTRY
// 
//
// LONG MyFilter(PEXCEPTION_POINTERS *pExceptionInfo, PVOID pv)
// {
// ...
// }
// PAL_TRY {
//   ....
// } WIN_PAL_EXCEPT_FILTER(MyFilter, NULL) {
//   ....
// }
// WIN_PAL_ENDTRY
//
//
// Complex example:
//
// struct MyParams
// {
//     ...
// } params;
//
// PAL_TRY {
//   PAL_TRY {
//       ...
//       if (error) goto Done;
//       ...
//   Done: ;
//   } WIN_PAL_EXCEPT_FILTER(OtherFilter, &params) {
//   ...
//   }
//   WIN_PAL_ENDTRY
// }
// WIN_PAL_FINALLY {
// }
// WIN_PAL_ENDTRY
//

#if !defined(FEATURE_CORECLR)

#include "staticcontract.h"

#define WIN_PAL_TRY_NAKED                                                       \
    {                                                                           \
        bool __exHandled; __exHandled = false;                                  \
        DWORD __exCode; __exCode = 0;                                           \
        __try                                                                   \
        {

#define WIN_PAL_TRY                                                             \
    {                                                                           \
        WIN_PAL_TRY_NAKED                                                       \
        WIN_PAL_TRY_HANDLER_DBG_BEGIN

#define WIN_PAL_TRY_FOR_DLLMAIN(_reason)                                        \
    {                                                                           \
        WIN_PAL_TRY_NAKED                                                       \
        WIN_PAL_TRY_HANDLER_DBG_BEGIN_DLLMAIN(_reason)

// Note: PAL_SEH_RESTORE_GUARD_PAGE is only ever defined in clrex.h, so we only restore guard pages automatically
// when these macros are used from within the VM.
#define WIN_PAL_SEH_RESTORE_GUARD_PAGE PAL_SEH_RESTORE_GUARD_PAGE
 
#define WIN_PAL_EXCEPT_NAKED(Disposition)                                       \
    } __except(__exCode = GetExceptionCode(), Disposition) {                    \
        __exHandled = true;                                                     \
        WIN_PAL_SEH_RESTORE_GUARD_PAGE

#define WIN_PAL_EXCEPT(Disposition)                                             \
        WIN_PAL_TRY_HANDLER_DBG_END                                             \
        WIN_PAL_EXCEPT_NAKED(Disposition)

#define WIN_PAL_EXCEPT_FILTER_NAKED(pfnFilter, pvFilterParameter)                                       \
    } __except(__exCode = GetExceptionCode(), pfnFilter(GetExceptionInformation(), pvFilterParameter)) {  \
        __exHandled = true;                                                     \
        WIN_PAL_SEH_RESTORE_GUARD_PAGE

#define WIN_PAL_EXCEPT_FILTER(pfnFilter, pvFilterParameter)                     \
        WIN_PAL_TRY_HANDLER_DBG_END                                             \
        WIN_PAL_EXCEPT_FILTER_NAKED(pfnFilter, pvFilterParameter)

#define WIN_PAL_FINALLY_NAKED                                                   \
    } __finally {                                                               \

#define WIN_PAL_FINALLY                                                             \
        WIN_PAL_TRY_HANDLER_DBG_END                                             \
        WIN_PAL_FINALLY_NAKED

#define WIN_PAL_ENDTRY_NAKED                                                    \
        }                                                                       \
    }                                                                           \

#define WIN_PAL_ENDTRY                                                          \
            }                                                                   \
            WIN_PAL_ENDTRY_NAKED_DBG                                            \
        }                                                                       \
    }

#endif // !PAL_WIN_SEH


#if defined(_DEBUG_IMPL) && !defined(JIT_BUILD) && !defined(JIT64_BUILD) && !defined(_ARM_) // @ARMTODO
#define WIN_PAL_TRY_HANDLER_DBG_BEGIN                                           \
    BOOL ___oldOkayToThrowValue = FALSE;                                        \
    BOOL ___oldSOTolerantState = FALSE;                                         \
    ClrDebugState *___pState = GetClrDebugState();                              \
    __try                                                                       \
    {                                                                           \
        ___oldOkayToThrowValue = ___pState->IsOkToThrow();                      \
        ___oldSOTolerantState = ___pState->IsSOTolerant();                      \
        ___pState->SetOkToThrow(TRUE);                                          \
        ANNOTATION_TRY_BEGIN;

// Special version that avoids touching the debug state after doing work in a DllMain for process or thread detach.
#define WIN_PAL_TRY_HANDLER_DBG_BEGIN_DLLMAIN(_reason)                          \
    BOOL ___oldOkayToThrowValue = FALSE;                                        \
    BOOL ___oldSOTolerantState = FALSE;                                         \
    ClrDebugState *___pState = CheckClrDebugState();                            \
    __try                                                                       \
    {                                                                           \
        if (___pState)                                                          \
        {                                                                       \
            ___oldOkayToThrowValue = ___pState->IsOkToThrow();                  \
            ___oldSOTolerantState = ___pState->IsSOTolerant();                  \
            ___pState->SetOkToThrow(TRUE);                                      \
        }                                                                       \
        if ((_reason == DLL_PROCESS_DETACH) || (_reason == DLL_THREAD_DETACH))  \
        {                                                                       \
            ___pState = NULL;                                                   \
        }                                                                       \
        ANNOTATION_TRY_BEGIN;

#define WIN_PAL_TRY_HANDLER_DBG_END                                             \
        ANNOTATION_TRY_END;                                                     \
    }                                                                           \
    __finally                                                                   \
    {                                                                           \
        if (___pState != NULL)                                                  \
        {                                                                       \
            _ASSERTE(___pState == CheckClrDebugState());                        \
            ___pState->SetOkToThrow(___oldOkayToThrowValue);                    \
            ___pState->SetSOTolerance(___oldSOTolerantState);                   \
        }                                                                       \
    }

#define WIN_PAL_ENDTRY_NAKED_DBG                                                \
    if (__exHandled)                                                            \
    {                                                                           \
        RESTORE_SO_TOLERANCE_STATE;                                             \
    }                                                                           \
    
#else
#define WIN_PAL_TRY_HANDLER_DBG_BEGIN                   ANNOTATION_TRY_BEGIN;
#define WIN_PAL_TRY_HANDLER_DBG_BEGIN_DLLMAIN(_reason)  ANNOTATION_TRY_BEGIN;
#define WIN_PAL_TRY_HANDLER_DBG_END                     ANNOTATION_TRY_END;
#define WIN_PAL_ENDTRY_NAKED_DBG                                                          
#endif // defined(ENABLE_CONTRACTS_IMPL) && !defined(JIT64_BUILD)

#endif	// __PALCLR_WIN_H__