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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
|
; 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.
; ==++==
;
;
; ==--==
include AsmMacros.inc
include asmconstants.inc
Thread__GetAbortContext equ ?GetAbortContext@Thread@@QEAAPEAU_CONTEXT@@XZ
extern FixContextHandler:proc
extern LinkFrameAndThrow:proc
extern GetCurrentSavedRedirectContext:proc
extern Thread__GetAbortContext:proc
extern HijackHandler:proc
extern ThrowControlForThread:proc
extern FixRedirectContextHandler:proc
;
; WARNING!! These functions immediately ruin thread unwindability. This is
; WARNING!! OK as long as there is a mechanism for saving the thread context
; WARNING!! prior to running these functions as well as a mechanism for
; WARNING!! restoring the context prior to any stackwalk. This means that
; WARNING!! we need to ensure that no GC can occur while the stack is
; WARNING!! unwalkable. This further means that we cannot allow any exception
; WARNING!! to occure when the stack is unwalkable
;
; If you edit this macro, make sure you update GetCONTEXTFromRedirectedStubStackFrame.
; This function is used by both the personality routine and the debugger to retrieve the original CONTEXT.
GenerateRedirectedHandledJITCaseStub macro reason
extern ?RedirectedHandledJITCaseFor&reason&@Thread@@CAXXZ:proc
NESTED_ENTRY RedirectedHandledJITCaseFor&reason&_Stub, _TEXT, FixRedirectContextHandler
;
; To aid debugging, we'll fake a call to this function. Allocate an
; extra stack slot that is hidden from the unwind info, where we can
; stuff the "return address". If we wanted to preserve full
; unwindability, we would need to copy all preserved registers.
; Ordinarily, rbp is used for the frame pointer, so since we're only
; interested is debugability, we'll just handle that common case.
;
push rax ; where to stuff the fake return address
push_nonvol_reg rbp ; save interrupted rbp for stack walk
alloc_stack 28h ; CONTEXT*, callee scratch area
set_frame rbp, 0
.errnz REDIRECTSTUB_ESTABLISHER_OFFSET_RBP, REDIRECTSTUB_ESTABLISHER_OFFSET_RBP has changed - update asm stubs
END_PROLOGUE
;
; Align rsp. rsp must misaligned at entry to any C function.
;
and rsp, -16
;
; Save a copy of the redirect CONTEXT* in case an exception occurs.
; The personality routine will use this to restore unwindability for
; the exception dispatcher.
;
call GetCurrentSavedRedirectContext
mov [rbp+20h], rax
.errnz REDIRECTSTUB_RBP_OFFSET_CONTEXT - 20h, REDIRECTSTUB_RBP_OFFSET_CONTEXT has changed - update asm stubs
;
; Fetch the interrupted rip and save it as our return address.
;
mov rax, [rax + OFFSETOF__CONTEXT__Rip]
mov [rbp+30h], rax
;
; Call target, which will do whatever we needed to do in the context
; of the target thread, and will RtlRestoreContext when it is done.
;
call ?RedirectedHandledJITCaseFor&reason&@Thread@@CAXXZ
int 3 ; target shouldn't return.
; Put a label here to tell the debugger where the end of this function is.
PATCH_LABEL RedirectedHandledJITCaseFor&reason&_StubEnd
NESTED_END RedirectedHandledJITCaseFor&reason&_Stub, _TEXT
endm
GenerateRedirectedHandledJITCaseStub GCThreadControl
GenerateRedirectedHandledJITCaseStub DbgThreadControl
GenerateRedirectedHandledJITCaseStub UserSuspend
GenerateRedirectedHandledJITCaseStub YieldTask
ifdef _DEBUG
ifdef HAVE_GCCOVER
GenerateRedirectedHandledJITCaseStub GCStress
endif
endif
; scratch area; padding; GSCookie
OFFSET_OF_FRAME = SIZEOF_MAX_OUTGOING_ARGUMENT_HOMES + 8 + SIZEOF_GSCookie
; force evaluation to avoid "expression is too complex errors"
SIZEOF__FaultingExceptionFrame = SIZEOF__FaultingExceptionFrame
GenerateRedirectedStubWithFrame macro STUB, FILTER, TARGET
altentry STUB&_RspAligned
NESTED_ENTRY STUB, _TEXT, FILTER
;
; IN: rcx: original IP before redirect
;
mov rdx, rsp
; This push of the return address must not be recorded in the unwind
; info. After this push, unwinding will work.
push rcx
test rsp, 0fh
jnz STUB&_FixRsp
STUB&_RspAligned:
; Any stack operations hereafter must be recorded in the unwind info, but
; only nonvolatile register locations are needed. Anything else is only
; a "sub rsp, 8" to the unwinder.
; m_ctx must be 16-byte aligned
.errnz (OFFSET_OF_FRAME + SIZEOF__FaultingExceptionFrame) MOD 16
alloc_stack OFFSET_OF_FRAME + SIZEOF__FaultingExceptionFrame
.errnz THROWSTUB_ESTABLISHER_OFFSET_FaultingExceptionFrame - OFFSET_OF_FRAME, THROWSTUB_ESTABLISHER_OFFSET_FaultingExceptionFrame has changed - update asm stubs
END_PROLOGUE
lea rcx, [rsp + OFFSET_OF_FRAME]
mov dword ptr [rcx], 0 ; Initialize vtbl (it is not strictly necessary)
mov dword ptr [rcx + OFFSETOF__FaultingExceptionFrame__m_fFilterExecuted], 0 ; Initialize BOOL for personality routine
call TARGET
; Target should not return.
int 3
NESTED_END STUB, _TEXT
; This function is used by the stub above to adjust the stack alignment. The
; stub can't conditionally push something on the stack because the unwind
; encodings have no way to express that.
;
; CONSIDER: we could move the frame pointer above the FaultingExceptionFrame,
; and detect the misalignment adjustment in
; GetFrameFromRedirectedStubStackFrame. This is probably less code and more
; straightforward.
LEAF_ENTRY STUB&_FixRsp, _TEXT
call STUB&_RspAligned
; Target should not return.
int 3
LEAF_END STUB&_FixRsp, _TEXT
endm
REDIRECT_FOR_THROW_CONTROL_FRAME_SIZE = SIZEOF_MAX_OUTGOING_ARGUMENT_HOMES + 8
NESTED_ENTRY RedirectForThrowControl2, _TEXT
; On entry
; rcx -> FaultingExceptionFrame
; rdx -> Original RSP
alloc_stack REDIRECT_FOR_THROW_CONTROL_FRAME_SIZE
save_reg_postrsp rcx, REDIRECT_FOR_THROW_CONTROL_FRAME_SIZE + 8h ; FaultingExceptionFrame
save_reg_postrsp rdx, REDIRECT_FOR_THROW_CONTROL_FRAME_SIZE + 10h ; Original RSP
END_PROLOGUE
; Fetch rip from a CONTEXT, and store it as our return address.
CALL_GETTHREAD
mov rcx, rax
call Thread__GetAbortContext
mov rax, [rax + OFFSETOF__CONTEXT__Rip]
mov rdx, [rsp + REDIRECT_FOR_THROW_CONTROL_FRAME_SIZE + 10h] ; Original RSP
mov [rdx - 8], rax
mov rcx, [rsp + REDIRECT_FOR_THROW_CONTROL_FRAME_SIZE + 8h] ; FaultingExceptionFrame
call ThrowControlForThread
; ThrowControlForThread doesn't return.
int 3
NESTED_END RedirectForThrowControl2, _TEXT
GenerateRedirectedStubWithFrame RedirectForThrowControl, HijackHandler, RedirectForThrowControl2
NAKED_THROW_HELPER_FRAME_SIZE = SIZEOF_MAX_OUTGOING_ARGUMENT_HOMES + 8
NESTED_ENTRY NakedThrowHelper2, _TEXT
; On entry
; rcx -> FaultingExceptionFrame
alloc_stack NAKED_THROW_HELPER_FRAME_SIZE
END_PROLOGUE
call LinkFrameAndThrow
; LinkFrameAndThrow doesn't return.
int 3
NESTED_END NakedThrowHelper2, _TEXT
GenerateRedirectedStubWithFrame NakedThrowHelper, FixContextHandler, NakedThrowHelper2
end
|