1 | // Licensed to the .NET Foundation under one or more agreements. |
---|---|
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | |
5 | #include "pal/dbgmsg.h" |
6 | SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do this first |
7 | |
8 | #include "pal/palinternal.h" |
9 | #include "pal/context.h" |
10 | #include "pal/signal.hpp" |
11 | #include "pal/utils.h" |
12 | #include <sys/ucontext.h> |
13 | |
14 | /*++ |
15 | Function : |
16 | signal_handler_worker |
17 | |
18 | Handles signal on the original stack where the signal occured. |
19 | Invoked via setcontext. |
20 | |
21 | Parameters : |
22 | POSIX signal handler parameter list ("man sigaction" for details) |
23 | returnPoint - context to which the function returns if the common_signal_handler returns |
24 | |
25 | (no return value) |
26 | --*/ |
27 | void ExecuteHandlerOnOriginalStack(int code, siginfo_t *siginfo, void *context, SignalHandlerWorkerReturnPoint* returnPoint) |
28 | { |
29 | ucontext_t *ucontext = (ucontext_t *)context; |
30 | size_t faultSp = (size_t)MCREG_Rsp(ucontext->uc_mcontext); |
31 | |
32 | _ASSERTE(IS_ALIGNED(faultSp, 8)); |
33 | |
34 | size_t fakeFrameReturnAddress; |
35 | |
36 | if (IS_ALIGNED(faultSp, 16)) |
37 | { |
38 | fakeFrameReturnAddress = (size_t)SignalHandlerWorkerReturnOffset0 + (size_t)CallSignalHandlerWrapper0; |
39 | } |
40 | else |
41 | { |
42 | fakeFrameReturnAddress = (size_t)SignalHandlerWorkerReturnOffset8 + (size_t)CallSignalHandlerWrapper8; |
43 | } |
44 | |
45 | // preserve 128 bytes long red zone and align stack pointer |
46 | size_t* sp = (size_t*)ALIGN_DOWN(faultSp - 128, 16); |
47 | |
48 | // Build fake stack frame to enable the stack unwinder to unwind from signal_handler_worker to the faulting instruction |
49 | *--sp = (size_t)MCREG_Rip(ucontext->uc_mcontext); |
50 | *--sp = (size_t)MCREG_Rbp(ucontext->uc_mcontext); |
51 | size_t fp = (size_t)sp; |
52 | *--sp = fakeFrameReturnAddress; |
53 | |
54 | // Switch the current context to the signal_handler_worker and the original stack |
55 | CONTEXT context2; |
56 | RtlCaptureContext(&context2); |
57 | |
58 | // We don't care about the other registers state since the stack unwinding restores |
59 | // them for the target frame directly from the signal context. |
60 | context2.Rsp = (size_t)sp; |
61 | context2.Rbx = (size_t)faultSp; |
62 | context2.Rbp = (size_t)fp; |
63 | context2.Rip = (size_t)signal_handler_worker; |
64 | context2.Rdi = code; |
65 | context2.Rsi = (size_t)siginfo; |
66 | context2.Rdx = (size_t)context; |
67 | context2.Rcx = (size_t)returnPoint; |
68 | |
69 | RtlRestoreContext(&context2, NULL); |
70 | } |
71 |