Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 6ccf4e2

Browse files
committed
Merge pull request #435 from janvorli/nested-exception-handling
Add support for exceptions crossing native frames
2 parents 8f57480 + f8f4293 commit 6ccf4e2

File tree

9 files changed

+296
-113
lines changed

9 files changed

+296
-113
lines changed

src/debug/di/amd64/floatconversion.S

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
//
55

66
.intel_syntax noprefix
7-
#include "../../../vm/amd64/unixasmmacros.inc"
7+
#include <unixasmmacros.inc>
88

99
LEAF_ENTRY FPFillR8, _TEXT
1010
movdqa xmm0, [rdi]

src/vm/amd64/unixasmmacros.inc renamed to src/pal/inc/unixasmmacros.inc

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@
2626

2727
#if defined(__APPLE__)
2828
#define C_FUNC(name) _##name
29+
#define EXTERNAL_C_FUNC(name) C_FUNC(name)
2930
#define LOCAL_LABEL(name) L##name
3031
#else
3132
#define C_FUNC(name) name
33+
#define EXTERNAL_C_FUNC(name) C_FUNC(name)@plt
3234
#define LOCAL_LABEL(name) .L##name
3335
#endif
3436

@@ -131,13 +133,16 @@ C_FUNC(\Name\()_End):
131133
.macro save_xmm128_postrsp Reg, Offset
132134
__Offset = \Offset
133135
movdqa [rsp + __Offset], \Reg
134-
.cfi_rel_offset \Reg, __Offset
136+
// NOTE: We cannot use ".cfi_rel_offset \Reg, __Offset" here,
137+
// the xmm registers are not supported by the libunwind
135138
.endm
136139

137140
.macro restore_xmm128 Reg, ofs
138141
__Offset = \ofs
139142
movdqa \Reg, [rsp + __Offset]
140-
.cfi_restore \Reg
143+
// NOTE: We cannot use ".cfi_restore \Reg" here,
144+
// the xmm registers are not supported by the libunwind
145+
141146
.endm
142147

143148
.macro POP_CALLEE_SAVED_REGISTERS
@@ -156,6 +161,11 @@ C_FUNC(\Name\()_End):
156161
.cfi_adjust_cfa_offset 8
157162
.endm
158163

164+
.macro push_eflags
165+
pushfq
166+
.cfi_adjust_cfa_offset 8
167+
.endm
168+
159169
.macro push_argument_register Reg
160170
push_register \Reg
161171
.endm

src/pal/src/arch/i386/context2.S

Lines changed: 63 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,21 @@
88
// and is always apply to the current thread.
99
//
1010

11-
#include "macros.inc"
11+
.intel_syntax noprefix
12+
#include "unixasmmacros.inc"
1213

1314
#ifdef BIT64
1415

16+
#define CONTEXT_AMD64 0x100000
17+
1518
#define CONTEXT_CONTROL 1 // SegSs, Rsp, SegCs, Rip, and EFlags
1619
#define CONTEXT_INTEGER 2 // Rax, Rcx, Rdx, Rbx, Rbp, Rsi, Rdi, R8-R15
1720
#define CONTEXT_SEGMENTS 4 // SegDs, SegEs, SegFs, SegGs
1821
#define CONTEXT_FLOATING_POINT 8
1922
#define CONTEXT_DEBUG_REGISTERS 16 // Dr0-Dr3 and Dr6-Dr7
2023

24+
#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT)
25+
2126
#define CONTEXT_ContextFlags 6*8
2227
#define CONTEXT_SegCs CONTEXT_ContextFlags+8
2328
#define CONTEXT_SegDs CONTEXT_SegCs+2
@@ -78,66 +83,75 @@
7883
// Incoming:
7984
// RDI: Context*
8085
//
81-
.globl C_FUNC(CONTEXT_CaptureContext)
82-
C_FUNC(CONTEXT_CaptureContext):
83-
testb $CONTEXT_INTEGER, CONTEXT_ContextFlags(%rdi)
84-
je 0f
85-
mov %rdi, CONTEXT_Rdi(%rdi)
86-
mov %rsi, CONTEXT_Rsi(%rdi)
87-
mov %rbx, CONTEXT_Rbx(%rdi)
88-
mov %rdx, CONTEXT_Rdx(%rdi)
89-
mov %rcx, CONTEXT_Rcx(%rdi)
90-
mov %rax, CONTEXT_Rax(%rdi)
91-
mov %rbp, CONTEXT_Rbp(%rdi)
92-
mov %r8, CONTEXT_R8(%rdi)
93-
mov %r9, CONTEXT_R9(%rdi)
94-
mov %r10, CONTEXT_R10(%rdi)
95-
mov %r11, CONTEXT_R11(%rdi)
96-
mov %r12, CONTEXT_R12(%rdi)
97-
mov %r13, CONTEXT_R13(%rdi)
98-
mov %r14, CONTEXT_R14(%rdi)
99-
mov %r15, CONTEXT_R15(%rdi)
100-
jmp 1f
86+
LEAF_ENTRY CONTEXT_CaptureContext, _TEXT
87+
test BYTE PTR [rdi + CONTEXT_ContextFlags], CONTEXT_INTEGER
88+
je 0f
89+
mov [rdi + CONTEXT_Rdi], rdi
90+
mov [rdi + CONTEXT_Rsi], rsi
91+
mov [rdi + CONTEXT_Rbx], rbx
92+
mov [rdi + CONTEXT_Rdx], rdx
93+
mov [rdi + CONTEXT_Rcx], rcx
94+
mov [rdi + CONTEXT_Rax], rax
95+
mov [rdi + CONTEXT_Rbp], rbp
96+
mov [rdi + CONTEXT_R8], r8
97+
mov [rdi + CONTEXT_R9], r9
98+
mov [rdi + CONTEXT_R10], r10
99+
mov [rdi + CONTEXT_R11], r11
100+
mov [rdi + CONTEXT_R12], r12
101+
mov [rdi + CONTEXT_R13], r13
102+
mov [rdi + CONTEXT_R14], r14
103+
mov [rdi + CONTEXT_R15], r15
104+
jmp 1f
101105
0:
102106
nop
103107
1:
104-
testb $CONTEXT_CONTROL, CONTEXT_ContextFlags(%rdi)
105-
je 2f
108+
test BYTE PTR [rdi + CONTEXT_ContextFlags], CONTEXT_CONTROL
109+
je 2f
106110

107111
// Return address is @ RSP
108-
mov (%rsp), %rdx
109-
mov %rdx, CONTEXT_Rip(%rdi)
110-
mov %cs, CONTEXT_SegCs(%rdi)
111-
pushfq
112-
pop %rdx
113-
mov %edx, CONTEXT_EFlags(%rdi)
114-
lea 8(%rsp), %rdx
115-
mov %rdx, CONTEXT_Rsp(%rdi)
116-
mov %ss, CONTEXT_SegSs(%rdi)
112+
mov rdx, [rsp]
113+
mov [rdi + CONTEXT_Rip], rdx
114+
.att_syntax
115+
mov %cs, CONTEXT_SegCs(%rdi)
116+
.intel_syntax noprefix
117+
push_eflags
118+
pop_register rdx
119+
mov [rdi + CONTEXT_EFlags], edx
120+
lea rdx, [rsp + 8]
121+
mov [rdi + CONTEXT_Rsp], rdx
122+
.att_syntax
123+
mov %ss, CONTEXT_SegSs(%rdi)
124+
.intel_syntax noprefix
117125
2:
118126
// Need to double check this is producing the right result
119127
// also that FFSXR (fast save/restore) is not turned on
120128
// otherwise it omits the xmm registers.
121-
testb $CONTEXT_FLOATING_POINT, CONTEXT_ContextFlags(%rdi)
122-
je 3f
123-
fxsave CONTEXT_FltSave(%rdi)
129+
test BYTE PTR [rdi + CONTEXT_ContextFlags], CONTEXT_FLOATING_POINT
130+
je 3f
131+
fxsave [rdi + CONTEXT_FltSave]
124132
3:
125-
testb $CONTEXT_DEBUG_REGISTERS, CONTEXT_ContextFlags(%rdi)
126-
je 4f
127-
mov %dr0, %rdx
128-
mov %rdx, CONTEXT_Dr0(%rdi)
129-
mov %dr1, %rdx
130-
mov %rdx, CONTEXT_Dr1(%rdi)
131-
mov %dr2, %rdx
132-
mov %rdx, CONTEXT_Dr2(%rdi)
133-
mov %dr3, %rdx
134-
mov %rdx, CONTEXT_Dr3(%rdi)
135-
mov %dr6, %rdx
136-
mov %rdx, CONTEXT_Dr6(%rdi)
137-
mov %dr7, %rdx
138-
mov %rdx, CONTEXT_Dr7(%rdi)
133+
test BYTE PTR [rdi + CONTEXT_ContextFlags], CONTEXT_DEBUG_REGISTERS
134+
je 4f
135+
mov rdx, dr0
136+
mov [rdi + CONTEXT_Dr0], rdx
137+
mov rdx, dr1
138+
mov [rdi + CONTEXT_Dr1], rdx
139+
mov rdx, dr2
140+
mov [rdi + CONTEXT_Dr2], rdx
141+
mov rdx, dr3
142+
mov [rdi + CONTEXT_Dr3], rdx
143+
mov rdx, dr6
144+
mov [rdi + CONTEXT_Dr6], rdx
145+
mov rdx, dr7
146+
mov [rdi + CONTEXT_Dr7], rdx
139147
4:
140148
ret
149+
LEAF_END CONTEXT_CaptureContext, _TEXT
150+
151+
LEAF_ENTRY RtlCaptureContext, _TEXT
152+
mov DWORD PTR [rdi + CONTEXT_ContextFlags], (CONTEXT_AMD64 | CONTEXT_FULL | CONTEXT_SEGMENTS)
153+
jmp C_FUNC(CONTEXT_CaptureContext)
154+
LEAF_END RtlCaptureContext, _TEXT
141155

142156
#else
143157

src/pal/src/arch/i386/macros.inc

Lines changed: 0 additions & 6 deletions
This file was deleted.

src/pal/src/debug/debug.cpp

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -518,15 +518,6 @@ SetThreadContext(
518518
return ret;
519519
}
520520

521-
VOID
522-
PALAPI
523-
RtlCaptureContext(
524-
OUT PCONTEXT ContextRecord
525-
)
526-
{
527-
ASSERT("UNIXTODO: Implement this");
528-
}
529-
530521
VOID
531522
PALAPI
532523
RtlRestoreContext(

src/vm/amd64/unixasmhelpers.S

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,3 +190,41 @@ NullObject:
190190
jmp C_FUNC(JIT_InternalThrow)
191191
192192
LEAF_END SinglecastDelegateInvokeStub, _TEXT
193+
194+
//////////////////////////////////////////////////////////////////////////
195+
//
196+
// This function initiates unwinding of native frames during the unwinding of a managed
197+
// exception. The managed exception can be propagated over several managed / native ranges
198+
// until it is finally handled by a managed handler or leaves the stack unhandled and
199+
// aborts the current process.
200+
// It creates a stack frame right below the target frame, restores all callee saved registers
201+
// from the passed in context and finally sets the RSP to that frame and sets the return
202+
// address to the target frame's RIP.
203+
//
204+
// EXTERN_C void StartUnwindingNativeFrames(CONTEXT* context);
205+
LEAF_ENTRY StartUnwindingNativeFrames, _TEXT
206+
// Save the RBP to the stack so that the unwind can work at the instruction after
207+
// loading the RBP from the context, but before loading the RSP from the context.
208+
push_nonvol_reg rbp
209+
mov r12, [rdi + OFFSETOF__CONTEXT__R12]
210+
mov r13, [rdi + OFFSETOF__CONTEXT__R13]
211+
mov r14, [rdi + OFFSETOF__CONTEXT__R14]
212+
mov r15, [rdi + OFFSETOF__CONTEXT__R15]
213+
mov rbx, [rdi + OFFSETOF__CONTEXT__Rbx]
214+
mov rbp, [rdi + OFFSETOF__CONTEXT__Rbp]
215+
mov rsp, [rdi + OFFSETOF__CONTEXT__Rsp]
216+
// The RSP was set to the target frame's value, so the current function's
217+
// CFA is now right at the RSP.
218+
.cfi_def_cfa_offset 0
219+
220+
// Indicate that now that we have moved the RSP to the target address,
221+
// the RBP is no longer saved in the current stack frame.
222+
.cfi_restore rbp
223+
224+
mov rax, [rdi + OFFSETOF__CONTEXT__Rip]
225+
226+
// Store return address to the stack
227+
push_register rax
228+
call EXTERNAL_C_FUNC(__cxa_rethrow)
229+
LEAF_END StartUnwindingNativeFrames, _TEXT
230+

0 commit comments

Comments
 (0)