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.
15 Signal handler implementation (map signals to exceptions)
21 #include "pal/dbgmsg.h"
22 SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do this first
24 #include "pal/corunix.hpp"
25 #include "pal/handleapi.hpp"
26 #include "pal/thread.hpp"
27 #include "pal/threadinfo.hpp"
28 #include "pal/threadsusp.hpp"
29 #include "pal/seh.hpp"
30 #include "pal/signal.hpp"
32 #include "pal/palinternal.h"
37 #if !HAVE_MACH_EXCEPTIONS
39 #include "pal/process.h"
40 #include "pal/debug.h"
41 #include "pal/virtual.h"
42 #include "pal/utils.h"
45 #include <sys/ucontext.h>
46 #include <sys/utsname.h>
50 #include "pal/context.h"
53 #define INJECT_ACTIVATION_SIGNAL SIGRTMIN
56 #if !defined(INJECT_ACTIVATION_SIGNAL) && defined(FEATURE_HIJACK)
57 #error FEATURE_HIJACK requires INJECT_ACTIVATION_SIGNAL to be defined
59 #endif // !HAVE_MACH_EXCEPTIONS
61 using namespace CorUnix;
63 /* local type definitions *****************************************************/
66 /* This allows us to compile on platforms that don't have siginfo_t.
67 * Exceptions will work poorly on those platforms. */
68 #warning Exceptions will work poorly on this platform
69 typedef void *siginfo_t;
70 #endif /* !HAVE_SIGINFO_T */
71 typedef void (*SIGFUNC)(int, siginfo_t *, void *);
73 #if !HAVE_MACH_EXCEPTIONS
74 // Return context and status for the signal_handler_worker.
75 struct SignalHandlerWorkerReturnPoint
77 bool returnFromHandler;
80 #endif // !HAVE_MACH_EXCEPTIONS
82 /* internal function declarations *********************************************/
84 static void sigterm_handler(int code, siginfo_t *siginfo, void *context);
85 #if !HAVE_MACH_EXCEPTIONS
86 static void sigill_handler(int code, siginfo_t *siginfo, void *context);
87 static void sigfpe_handler(int code, siginfo_t *siginfo, void *context);
88 static void sigsegv_handler(int code, siginfo_t *siginfo, void *context);
89 static void sigtrap_handler(int code, siginfo_t *siginfo, void *context);
90 static void sigbus_handler(int code, siginfo_t *siginfo, void *context);
91 static void sigint_handler(int code, siginfo_t *siginfo, void *context);
92 static void sigquit_handler(int code, siginfo_t *siginfo, void *context);
94 static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext, int numParams, ...);
96 #ifdef INJECT_ACTIVATION_SIGNAL
97 static void inject_activation_handler(int code, siginfo_t *siginfo, void *context);
99 #endif // !HAVE_MACH_EXCEPTIONS
101 static void handle_signal(int signal_id, SIGFUNC sigfunc, struct sigaction *previousAction, int additionalFlags = 0, bool skipIgnored = false);
102 static void restore_signal(int signal_id, struct sigaction *previousAction);
104 /* internal data declarations *********************************************/
106 static bool registered_sigterm_handler = false;
108 struct sigaction g_previous_sigterm;
109 #if !HAVE_MACH_EXCEPTIONS
110 struct sigaction g_previous_sigill;
111 struct sigaction g_previous_sigtrap;
112 struct sigaction g_previous_sigfpe;
113 struct sigaction g_previous_sigbus;
114 struct sigaction g_previous_sigsegv;
115 struct sigaction g_previous_sigint;
116 struct sigaction g_previous_sigquit;
118 #ifdef INJECT_ACTIVATION_SIGNAL
119 struct sigaction g_previous_activation;
122 // Offset of the local variable containing pointer to windows style context in the common_signal_handler function.
123 // This offset is relative to the frame pointer.
124 int g_common_signal_handler_context_locvar_offset = 0;
125 #endif // !HAVE_MACH_EXCEPTIONS
127 /* public function definitions ************************************************/
129 #if !HAVE_MACH_EXCEPTIONS
132 EnsureSignalAlternateStack
134 Ensure that alternate stack for signal handling is allocated for the current thread
140 TRUE in case of a success, FALSE otherwise
142 BOOL EnsureSignalAlternateStack()
146 // Query the current alternate signal stack
147 int st = sigaltstack(NULL, &oss);
149 if ((st == 0) && (oss.ss_flags == SS_DISABLE))
151 // There is no alternate stack for SIGSEGV handling installed yet so allocate one
153 // We include the size of the SignalHandlerWorkerReturnPoint in the alternate stack size since the
154 // context contained in it is large and the SIGSTKSZ was not sufficient on ARM64 during testing.
155 int altStackSize = SIGSTKSZ + ALIGN_UP(sizeof(SignalHandlerWorkerReturnPoint), 16) + GetVirtualPageSize();
157 // Asan also uses alternate stack so we increase its size on the SIGSTKSZ * 4 that enough for asan
158 // (see kAltStackSize in compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cc)
159 altStackSize += SIGSTKSZ * 4;
162 int st = posix_memalign(&altStack, GetVirtualPageSize(), altStackSize);
165 // create a guard page for the alternate stack
166 st = mprotect(altStack, GetVirtualPageSize(), PROT_NONE);
170 ss.ss_sp = (char*)altStack;
171 ss.ss_size = altStackSize;
173 st = sigaltstack(&ss, NULL);
176 // Installation of the alternate stack failed, so revert the guard page protection
177 int st2 = mprotect(altStack, GetVirtualPageSize(), PROT_READ | PROT_WRITE);
194 FreeSignalAlternateStack
196 Free alternate stack for signal handling
204 void FreeSignalAlternateStack()
207 ss.ss_flags = SS_DISABLE;
208 int st = sigaltstack(&ss, &oss);
209 if ((st == 0) && (oss.ss_flags != SS_DISABLE))
211 int st = mprotect(oss.ss_sp, GetVirtualPageSize(), PROT_READ | PROT_WRITE);
216 #endif // !HAVE_MACH_EXCEPTIONS
222 Set up signal handlers to catch signals and translate them to exceptions
228 TRUE in case of a success, FALSE otherwise
230 BOOL SEHInitializeSignals(DWORD flags)
232 TRACE("Initializing signal handlers\n");
234 #if !HAVE_MACH_EXCEPTIONS
235 /* we call handle_signal for every possible signal, even
236 if we don't provide a signal handler.
238 handle_signal will set SA_RESTART flag for specified signal.
239 Therefore, all signals will have SA_RESTART flag set, preventing
240 slow Unix system calls from being interrupted. On systems without
241 siginfo_t, SIGKILL and SIGSTOP can't be restarted, so we don't
242 handle those signals. Both the Darwin and FreeBSD man pages say
243 that SIGKILL and SIGSTOP can't be handled, but FreeBSD allows us
244 to register a handler for them anyway. We don't do that.
246 see sigaction man page for more details
248 handle_signal(SIGILL, sigill_handler, &g_previous_sigill);
249 handle_signal(SIGTRAP, sigtrap_handler, &g_previous_sigtrap);
250 handle_signal(SIGFPE, sigfpe_handler, &g_previous_sigfpe);
251 handle_signal(SIGBUS, sigbus_handler, &g_previous_sigbus);
252 // SIGSEGV handler runs on a separate stack so that we can handle stack overflow
253 handle_signal(SIGSEGV, sigsegv_handler, &g_previous_sigsegv, SA_ONSTACK);
254 // We don't setup a handler for SIGINT/SIGQUIT when those signals are ignored.
255 // Otherwise our child processes would reset to the default on exec causing them
256 // to terminate on these signals.
257 handle_signal(SIGINT, sigint_handler, &g_previous_sigint , 0 /* additionalFlags */, true /* skipIgnored */);
258 handle_signal(SIGQUIT, sigquit_handler, &g_previous_sigquit, 0 /* additionalFlags */, true /* skipIgnored */);
260 if (!EnsureSignalAlternateStack())
264 #endif // !HAVE_MACH_EXCEPTIONS
266 if (flags & PAL_INITIALIZE_REGISTER_SIGTERM_HANDLER)
268 handle_signal(SIGTERM, sigterm_handler, &g_previous_sigterm);
269 registered_sigterm_handler = true;
272 #if !HAVE_MACH_EXCEPTIONS
273 #ifdef INJECT_ACTIVATION_SIGNAL
274 handle_signal(INJECT_ACTIVATION_SIGNAL, inject_activation_handler, &g_previous_activation);
277 /* The default action for SIGPIPE is process termination.
278 Since SIGPIPE can be signaled when trying to write on a socket for which
279 the connection has been dropped, we need to tell the system we want
280 to ignore this signal.
282 Instead of terminating the process, the system call which would had
283 issued a SIGPIPE will, instead, report an error and set errno to EPIPE.
285 signal(SIGPIPE, SIG_IGN);
286 #endif // !HAVE_MACH_EXCEPTIONS
295 Restore default signal handlers
303 reason for this function is that during PAL_Terminate, we reach a point where
304 SEH isn't possible anymore (handle manager is off, etc). Past that point,
305 we can't avoid crashing on a signal.
307 void SEHCleanupSignals()
309 TRACE("Restoring default signal handlers\n");
311 #if !HAVE_MACH_EXCEPTIONS
312 restore_signal(SIGILL, &g_previous_sigill);
313 restore_signal(SIGTRAP, &g_previous_sigtrap);
314 restore_signal(SIGFPE, &g_previous_sigfpe);
315 restore_signal(SIGBUS, &g_previous_sigbus);
316 restore_signal(SIGSEGV, &g_previous_sigsegv);
317 restore_signal(SIGINT, &g_previous_sigint);
318 restore_signal(SIGQUIT, &g_previous_sigquit);
319 #endif // !HAVE_MACH_EXCEPTIONS
321 if (registered_sigterm_handler)
323 restore_signal(SIGTERM, &g_previous_sigterm);
326 #if !HAVE_MACH_EXCEPTIONS
327 #ifdef INJECT_ACTIVATION_SIGNAL
328 restore_signal(INJECT_ACTIVATION_SIGNAL, &g_previous_activation);
330 #endif // !HAVE_MACH_EXCEPTIONS
333 /* internal function definitions **********************************************/
335 #if !HAVE_MACH_EXCEPTIONS
340 handle SIGILL signal (EXCEPTION_ILLEGAL_INSTRUCTION, others?)
343 POSIX signal handler parameter list ("man sigaction" for details)
347 static void sigill_handler(int code, siginfo_t *siginfo, void *context)
349 if (PALIsInitialized())
351 if (common_signal_handler(code, siginfo, context, 0))
357 if (g_previous_sigill.sa_sigaction != NULL)
359 g_previous_sigill.sa_sigaction(code, siginfo, context);
363 // Restore the original or default handler and restart h/w exception
364 restore_signal(code, &g_previous_sigill);
367 PROCNotifyProcessShutdown();
368 PROCCreateCrashDumpIfEnabled();
375 handle SIGFPE signal (division by zero, floating point exception)
378 POSIX signal handler parameter list ("man sigaction" for details)
382 static void sigfpe_handler(int code, siginfo_t *siginfo, void *context)
384 if (PALIsInitialized())
386 if (common_signal_handler(code, siginfo, context, 0))
392 if (g_previous_sigfpe.sa_sigaction != NULL)
394 g_previous_sigfpe.sa_sigaction(code, siginfo, context);
398 // Restore the original or default handler and restart h/w exception
399 restore_signal(code, &g_previous_sigfpe);
402 PROCNotifyProcessShutdown();
403 PROCCreateCrashDumpIfEnabled();
408 signal_handler_worker
410 Handles signal on the original stack where the signal occured.
411 Invoked via setcontext.
414 POSIX signal handler parameter list ("man sigaction" for details)
415 returnPoint - context to which the function returns if the common_signal_handler returns
419 extern "C" void signal_handler_worker(int code, siginfo_t *siginfo, void *context, SignalHandlerWorkerReturnPoint* returnPoint)
421 // TODO: First variable parameter says whether a read (0) or write (non-0) caused the
422 // fault. We must disassemble the instruction at record.ExceptionAddress
423 // to correctly fill in this value.
425 // Unmask the activation signal now that we are running on the original stack of the thread
427 sigemptyset(&signal_set);
428 sigaddset(&signal_set, INJECT_ACTIVATION_SIGNAL);
430 int sigmaskRet = pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL);
433 ASSERT("pthread_sigmask failed; error number is %d\n", sigmaskRet);
436 returnPoint->returnFromHandler = common_signal_handler(code, siginfo, context, 2, (size_t)0, (size_t)siginfo->si_addr);
438 // We are going to return to the alternate stack, so block the activation signal again
439 sigmaskRet = pthread_sigmask(SIG_BLOCK, &signal_set, NULL);
442 ASSERT("pthread_sigmask failed; error number is %d\n", sigmaskRet);
445 RtlRestoreContext(&returnPoint->context, NULL);
452 handle SIGSEGV signal (EXCEPTION_ACCESS_VIOLATION, others)
455 POSIX signal handler parameter list ("man sigaction" for details)
459 static void sigsegv_handler(int code, siginfo_t *siginfo, void *context)
461 if (PALIsInitialized())
463 // First check if we have a stack overflow
464 size_t sp = (size_t)GetNativeContextSP((native_context_t *)context);
465 size_t failureAddress = (size_t)siginfo->si_addr;
467 // If the failure address is at most one page above or below the stack pointer,
468 // we have a stack overflow.
469 if ((failureAddress - (sp - GetVirtualPageSize())) < 2 * GetVirtualPageSize())
471 (void)write(STDERR_FILENO, StackOverflowMessage, sizeof(StackOverflowMessage) - 1);
475 // Now that we know the SIGSEGV didn't happen due to a stack overflow, execute the common
476 // hardware signal handler on the original stack.
478 // Establish a return point in case the common_signal_handler returns
480 if (GetCurrentPalThread())
482 volatile bool contextInitialization = true;
484 void *ptr = alloca(sizeof(SignalHandlerWorkerReturnPoint) + alignof(SignalHandlerWorkerReturnPoint) - 1);
485 SignalHandlerWorkerReturnPoint *pReturnPoint = (SignalHandlerWorkerReturnPoint *)ALIGN_UP(ptr, alignof(SignalHandlerWorkerReturnPoint));
486 RtlCaptureContext(&pReturnPoint->context);
488 // When the signal handler worker completes, it uses setcontext to return to this point
490 if (contextInitialization)
492 contextInitialization = false;
493 ExecuteHandlerOnOriginalStack(code, siginfo, context, pReturnPoint);
494 _ASSERTE(FALSE); // The ExecuteHandlerOnOriginalStack should never return
497 if (pReturnPoint->returnFromHandler)
504 // If thread isn't created by coreclr and has alternate signal stack GetCurrentPalThread() will return NULL too.
505 // But since in this case we don't handle hardware exceptions (IsSafeToHandleHardwareException returns false)
506 // we can call common_signal_handler on the alternate stack.
507 if (common_signal_handler(code, siginfo, context, 2, (size_t)0, (size_t)siginfo->si_addr))
514 if (g_previous_sigsegv.sa_sigaction != NULL)
516 g_previous_sigsegv.sa_sigaction(code, siginfo, context);
520 // Restore the original or default handler and restart h/w exception
521 restore_signal(code, &g_previous_sigsegv);
524 PROCNotifyProcessShutdown();
525 PROCCreateCrashDumpIfEnabled();
532 handle SIGTRAP signal (EXCEPTION_SINGLE_STEP, EXCEPTION_BREAKPOINT)
535 POSIX signal handler parameter list ("man sigaction" for details)
539 static void sigtrap_handler(int code, siginfo_t *siginfo, void *context)
541 if (PALIsInitialized())
543 if (common_signal_handler(code, siginfo, context, 0))
549 if (g_previous_sigtrap.sa_sigaction != NULL)
551 g_previous_sigtrap.sa_sigaction(code, siginfo, context);
555 // We abort instead of restore the original or default handler and returning
556 // because returning from a SIGTRAP handler continues execution past the trap.
560 PROCNotifyProcessShutdown();
561 PROCCreateCrashDumpIfEnabled();
568 handle SIGBUS signal (EXCEPTION_ACCESS_VIOLATION?)
571 POSIX signal handler parameter list ("man sigaction" for details)
575 static void sigbus_handler(int code, siginfo_t *siginfo, void *context)
577 if (PALIsInitialized())
579 // TODO: First variable parameter says whether a read (0) or write (non-0) caused the
580 // fault. We must disassemble the instruction at record.ExceptionAddress
581 // to correctly fill in this value.
582 if (common_signal_handler(code, siginfo, context, 2, (size_t)0, (size_t)siginfo->si_addr))
588 if (g_previous_sigbus.sa_sigaction != NULL)
590 g_previous_sigbus.sa_sigaction(code, siginfo, context);
594 // Restore the original or default handler and restart h/w exception
595 restore_signal(code, &g_previous_sigbus);
598 PROCNotifyProcessShutdown();
599 PROCCreateCrashDumpIfEnabled();
609 POSIX signal handler parameter list ("man sigaction" for details)
613 static void sigint_handler(int code, siginfo_t *siginfo, void *context)
615 PROCNotifyProcessShutdown();
617 // Restore the original or default handler and resend signal
618 restore_signal(code, &g_previous_sigint);
626 handle SIGQUIT signal
629 POSIX signal handler parameter list ("man sigaction" for details)
633 static void sigquit_handler(int code, siginfo_t *siginfo, void *context)
635 PROCNotifyProcessShutdown();
637 // Restore the original or default handler and resend signal
638 restore_signal(code, &g_previous_sigquit);
641 #endif // !HAVE_MACH_EXCEPTIONS
647 handle SIGTERM signal
650 POSIX signal handler parameter list ("man sigaction" for details)
654 static void sigterm_handler(int code, siginfo_t *siginfo, void *context)
656 if (PALIsInitialized())
658 // g_pSynchronizationManager shouldn't be null if PAL is initialized.
659 _ASSERTE(g_pSynchronizationManager != nullptr);
661 g_pSynchronizationManager->SendTerminationRequestToWorkerThread();
665 if (g_previous_sigterm.sa_sigaction != NULL)
667 g_previous_sigterm.sa_sigaction(code, siginfo, context);
672 #if !HAVE_MACH_EXCEPTIONS
673 #ifdef INJECT_ACTIVATION_SIGNAL
676 inject_activation_handler
678 Handle the INJECT_ACTIVATION_SIGNAL signal. This signal interrupts a running thread
679 so it can call the activation function that was specified when sending the signal.
682 POSIX signal handler parameter list ("man sigaction" for details)
686 static void inject_activation_handler(int code, siginfo_t *siginfo, void *context)
688 // Only accept activations from the current process
689 if (g_activationFunction != NULL && siginfo->si_pid == getpid())
691 _ASSERTE(g_safeActivationCheckFunction != NULL);
693 native_context_t *ucontext = (native_context_t *)context;
696 CONTEXTFromNativeContext(
699 CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT);
701 if (g_safeActivationCheckFunction(CONTEXTGetPC(&winContext), /* checkingCurrentThread */ TRUE))
703 g_activationFunction(&winContext);
704 // Activation function may have modified the context, so update it.
705 CONTEXTToNativeContext(&winContext, ucontext);
708 else if (g_previous_activation.sa_sigaction != NULL)
710 g_previous_activation.sa_sigaction(code, siginfo, context);
717 InjectActivationInternal
719 Interrupt the specified thread and have it call the activationFunction passed in
722 pThread - target PAL thread
723 activationFunction - function to call
727 PAL_ERROR InjectActivationInternal(CorUnix::CPalThread* pThread)
729 #ifdef INJECT_ACTIVATION_SIGNAL
730 int status = pthread_kill(pThread->GetPThreadSelf(), INJECT_ACTIVATION_SIGNAL);
733 // Failure to send the signal is fatal. There are only two cases when sending
734 // the signal can fail. First, if the signal ID is invalid and second,
735 // if the thread doesn't exist anymore.
741 return ERROR_CANCELLED;
747 signal_ignore_handler
749 Simple signal handler which does nothing
752 POSIX signal handler parameter list ("man sigaction" for details)
756 static void signal_ignore_handler(int code, siginfo_t *siginfo, void *context)
761 void PAL_IgnoreProfileSignal(int signalNum)
763 #if !HAVE_MACH_EXCEPTIONS
764 // Add a signal handler which will ignore signals
765 // This will allow signal to be used as a marker in perf recording.
766 // This will be used as an aid to synchronize recorded profile with
769 // signal(signalNum, SGN_IGN) can not be used here. It will ignore
770 // the signal in kernel space and therefore generate no recordable
771 // event for profiling. Preventing it being used for profile
774 // Since this is only used in rare circumstances no attempt to
775 // restore the old handler will be made
776 handle_signal(signalNum, signal_ignore_handler, 0);
785 specify whether the current thread is in a state where exception handling
786 of signals can be done safely
789 BOOL state : TRUE if the thread is safe, FALSE otherwise
793 void SEHSetSafeState(CPalThread *pthrCurrent, BOOL state)
795 if (NULL == pthrCurrent)
797 ASSERT( "Unable to get the thread object.\n" );
800 pthrCurrent->sehInfo.safe_state = state;
807 determine whether the current thread is in a state where exception handling
808 of signals can be done safely
813 TRUE if the thread is in a safe state, FALSE otherwise
815 BOOL SEHGetSafeState(CPalThread *pthrCurrent)
817 if (NULL == pthrCurrent)
819 ASSERT( "Unable to get the thread object.\n" );
822 return pthrCurrent->sehInfo.safe_state;
827 common_signal_handler
829 common code for all signal handlers
832 int code : signal received
833 siginfo_t *siginfo : siginfo passed to the signal handler
834 void *context : context structure passed to the signal handler
835 int numParams : number of variable parameters of the exception
836 ... : variable parameters of the exception (each of size_t type)
838 Returns true if the execution should continue or false if the exception was unhandled
840 the "pointers" parameter should contain a valid exception record pointer,
841 but the ContextRecord pointer will be overwritten.
843 __attribute__((noinline))
844 static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext, int numParams, ...)
847 CONTEXT signalContextRecord;
848 EXCEPTION_RECORD exceptionRecord;
849 native_context_t *ucontext;
851 ucontext = (native_context_t *)sigcontext;
852 g_common_signal_handler_context_locvar_offset = (int)((char*)&signalContextRecord - (char*)__builtin_frame_address(0));
854 exceptionRecord.ExceptionCode = CONTEXTGetExceptionCodeForSignal(siginfo, ucontext);
855 exceptionRecord.ExceptionFlags = EXCEPTION_IS_SIGNAL;
856 exceptionRecord.ExceptionRecord = NULL;
857 exceptionRecord.ExceptionAddress = GetNativeContextPC(ucontext);
858 exceptionRecord.NumberParameters = numParams;
861 va_start(params, numParams);
863 for (int i = 0; i < numParams; i++)
865 exceptionRecord.ExceptionInformation[i] = va_arg(params, size_t);
868 // Pre-populate context with data from current frame, because ucontext doesn't have some data (e.g. SS register)
869 // which is required for restoring context
870 RtlCaptureContext(&signalContextRecord);
872 ULONG contextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT;
875 contextFlags |= CONTEXT_XSTATE;
878 // Fill context record with required information. from pal.h:
879 // On non-Win32 platforms, the CONTEXT pointer in the
880 // PEXCEPTION_POINTERS will contain at least the CONTEXT_CONTROL registers.
881 CONTEXTFromNativeContext(ucontext, &signalContextRecord, contextFlags);
883 /* Unmask signal so we can receive it again */
884 sigemptyset(&signal_set);
885 sigaddset(&signal_set, code);
886 int sigmaskRet = pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL);
889 ASSERT("pthread_sigmask failed; error number is %d\n", sigmaskRet);
892 signalContextRecord.ContextFlags |= CONTEXT_EXCEPTION_ACTIVE;
894 // The exception object takes ownership of the exceptionRecord and contextRecord
895 PAL_SEHException exception(&exceptionRecord, &signalContextRecord, true);
897 if (SEHProcessException(&exception))
899 // Exception handling may have modified the context, so update it.
900 CONTEXTToNativeContext(exception.ExceptionPointers.ContextRecord, ucontext);
906 #endif // !HAVE_MACH_EXCEPTIONS
912 register handler for specified signal
915 int signal_id : signal to handle
916 SIGFUNC sigfunc : signal handler
917 previousAction : previous sigaction struct
921 note : if sigfunc is NULL, the default signal handler is restored
923 void handle_signal(int signal_id, SIGFUNC sigfunc, struct sigaction *previousAction, int additionalFlags, bool skipIgnored)
925 struct sigaction newAction;
927 newAction.sa_flags = SA_RESTART | additionalFlags;
929 newAction.sa_handler = NULL;
930 newAction.sa_sigaction = sigfunc;
931 newAction.sa_flags |= SA_SIGINFO;
932 #else /* HAVE_SIGINFO_T */
933 newAction.sa_handler = SIG_DFL;
934 #endif /* HAVE_SIGINFO_T */
935 sigemptyset(&newAction.sa_mask);
937 #ifdef INJECT_ACTIVATION_SIGNAL
938 if ((additionalFlags & SA_ONSTACK) != 0)
940 // A handler that runs on a separate stack should not be interrupted by the activation signal
941 // until it switches back to the regular stack, since that signal's handler would run on the
942 // limited separate stack and likely run into a stack overflow.
943 sigaddset(&newAction.sa_mask, INJECT_ACTIVATION_SIGNAL);
949 if (-1 == sigaction(signal_id, NULL, previousAction))
951 ASSERT("handle_signal: sigaction() call failed with error code %d (%s)\n",
952 errno, strerror(errno));
954 else if (previousAction->sa_handler == SIG_IGN)
960 if (-1 == sigaction(signal_id, &newAction, previousAction))
962 ASSERT("handle_signal: sigaction() call failed with error code %d (%s)\n",
963 errno, strerror(errno));
971 restore handler for specified signal
974 int signal_id : signal to handle
975 previousAction : previous sigaction struct to restore
979 void restore_signal(int signal_id, struct sigaction *previousAction)
981 if (-1 == sigaction(signal_id, previousAction, NULL))
983 ASSERT("restore_signal: sigaction() call failed with error code %d (%s)\n",
984 errno, strerror(errno));