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;
161 altStackSize = ALIGN_UP(altStackSize, GetVirtualPageSize());
162 void* altStack = mmap(NULL, altStackSize, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_STACK | MAP_PRIVATE, -1, 0);
163 if (altStack != MAP_FAILED)
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);
178 int st2 = munmap(altStack, altStackSize);
189 FreeSignalAlternateStack
191 Free alternate stack for signal handling
199 void FreeSignalAlternateStack()
202 // The man page for sigaltstack says that when the ss.ss_flags is set to SS_DISABLE,
203 // all other ss fields are ignored. However, MUSL implementation checks that the
204 // ss_size is >= MINSIGSTKSZ even in this case.
205 ss.ss_size = MINSIGSTKSZ;
206 ss.ss_flags = SS_DISABLE;
207 int st = sigaltstack(&ss, &oss);
208 if ((st == 0) && (oss.ss_flags != SS_DISABLE))
210 int st = munmap(oss.ss_sp, oss.ss_size);
214 #endif // !HAVE_MACH_EXCEPTIONS
220 Set up signal handlers to catch signals and translate them to exceptions
226 TRUE in case of a success, FALSE otherwise
228 BOOL SEHInitializeSignals(DWORD flags)
230 TRACE("Initializing signal handlers\n");
232 #if !HAVE_MACH_EXCEPTIONS
233 /* we call handle_signal for every possible signal, even
234 if we don't provide a signal handler.
236 handle_signal will set SA_RESTART flag for specified signal.
237 Therefore, all signals will have SA_RESTART flag set, preventing
238 slow Unix system calls from being interrupted. On systems without
239 siginfo_t, SIGKILL and SIGSTOP can't be restarted, so we don't
240 handle those signals. Both the Darwin and FreeBSD man pages say
241 that SIGKILL and SIGSTOP can't be handled, but FreeBSD allows us
242 to register a handler for them anyway. We don't do that.
244 see sigaction man page for more details
246 handle_signal(SIGILL, sigill_handler, &g_previous_sigill);
247 handle_signal(SIGTRAP, sigtrap_handler, &g_previous_sigtrap);
248 handle_signal(SIGFPE, sigfpe_handler, &g_previous_sigfpe);
249 handle_signal(SIGBUS, sigbus_handler, &g_previous_sigbus);
250 // SIGSEGV handler runs on a separate stack so that we can handle stack overflow
251 handle_signal(SIGSEGV, sigsegv_handler, &g_previous_sigsegv, SA_ONSTACK);
252 // We don't setup a handler for SIGINT/SIGQUIT when those signals are ignored.
253 // Otherwise our child processes would reset to the default on exec causing them
254 // to terminate on these signals.
255 handle_signal(SIGINT, sigint_handler, &g_previous_sigint , 0 /* additionalFlags */, true /* skipIgnored */);
256 handle_signal(SIGQUIT, sigquit_handler, &g_previous_sigquit, 0 /* additionalFlags */, true /* skipIgnored */);
258 if (!EnsureSignalAlternateStack())
262 #endif // !HAVE_MACH_EXCEPTIONS
264 if (flags & PAL_INITIALIZE_REGISTER_SIGTERM_HANDLER)
266 handle_signal(SIGTERM, sigterm_handler, &g_previous_sigterm);
267 registered_sigterm_handler = true;
270 #if !HAVE_MACH_EXCEPTIONS
271 #ifdef INJECT_ACTIVATION_SIGNAL
272 handle_signal(INJECT_ACTIVATION_SIGNAL, inject_activation_handler, &g_previous_activation);
275 /* The default action for SIGPIPE is process termination.
276 Since SIGPIPE can be signaled when trying to write on a socket for which
277 the connection has been dropped, we need to tell the system we want
278 to ignore this signal.
280 Instead of terminating the process, the system call which would had
281 issued a SIGPIPE will, instead, report an error and set errno to EPIPE.
283 signal(SIGPIPE, SIG_IGN);
284 #endif // !HAVE_MACH_EXCEPTIONS
293 Restore default signal handlers
301 reason for this function is that during PAL_Terminate, we reach a point where
302 SEH isn't possible anymore (handle manager is off, etc). Past that point,
303 we can't avoid crashing on a signal.
305 void SEHCleanupSignals()
307 TRACE("Restoring default signal handlers\n");
309 #if !HAVE_MACH_EXCEPTIONS
310 restore_signal(SIGILL, &g_previous_sigill);
311 restore_signal(SIGTRAP, &g_previous_sigtrap);
312 restore_signal(SIGFPE, &g_previous_sigfpe);
313 restore_signal(SIGBUS, &g_previous_sigbus);
314 restore_signal(SIGSEGV, &g_previous_sigsegv);
315 restore_signal(SIGINT, &g_previous_sigint);
316 restore_signal(SIGQUIT, &g_previous_sigquit);
317 #endif // !HAVE_MACH_EXCEPTIONS
319 if (registered_sigterm_handler)
321 restore_signal(SIGTERM, &g_previous_sigterm);
324 #if !HAVE_MACH_EXCEPTIONS
325 #ifdef INJECT_ACTIVATION_SIGNAL
326 restore_signal(INJECT_ACTIVATION_SIGNAL, &g_previous_activation);
328 #endif // !HAVE_MACH_EXCEPTIONS
331 /* internal function definitions **********************************************/
333 #if !HAVE_MACH_EXCEPTIONS
338 handle SIGILL signal (EXCEPTION_ILLEGAL_INSTRUCTION, others?)
341 POSIX signal handler parameter list ("man sigaction" for details)
345 static void sigill_handler(int code, siginfo_t *siginfo, void *context)
347 if (PALIsInitialized())
349 if (common_signal_handler(code, siginfo, context, 0))
355 if (g_previous_sigill.sa_sigaction != NULL)
357 g_previous_sigill.sa_sigaction(code, siginfo, context);
361 // Restore the original or default handler and restart h/w exception
362 restore_signal(code, &g_previous_sigill);
365 PROCNotifyProcessShutdown();
366 PROCCreateCrashDumpIfEnabled();
373 handle SIGFPE signal (division by zero, floating point exception)
376 POSIX signal handler parameter list ("man sigaction" for details)
380 static void sigfpe_handler(int code, siginfo_t *siginfo, void *context)
382 if (PALIsInitialized())
384 if (common_signal_handler(code, siginfo, context, 0))
390 if (g_previous_sigfpe.sa_sigaction != NULL)
392 g_previous_sigfpe.sa_sigaction(code, siginfo, context);
396 // Restore the original or default handler and restart h/w exception
397 restore_signal(code, &g_previous_sigfpe);
400 PROCNotifyProcessShutdown();
401 PROCCreateCrashDumpIfEnabled();
406 signal_handler_worker
408 Handles signal on the original stack where the signal occured.
409 Invoked via setcontext.
412 POSIX signal handler parameter list ("man sigaction" for details)
413 returnPoint - context to which the function returns if the common_signal_handler returns
417 extern "C" void signal_handler_worker(int code, siginfo_t *siginfo, void *context, SignalHandlerWorkerReturnPoint* returnPoint)
419 // TODO: First variable parameter says whether a read (0) or write (non-0) caused the
420 // fault. We must disassemble the instruction at record.ExceptionAddress
421 // to correctly fill in this value.
423 // Unmask the activation signal now that we are running on the original stack of the thread
425 sigemptyset(&signal_set);
426 sigaddset(&signal_set, INJECT_ACTIVATION_SIGNAL);
428 int sigmaskRet = pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL);
431 ASSERT("pthread_sigmask failed; error number is %d\n", sigmaskRet);
434 returnPoint->returnFromHandler = common_signal_handler(code, siginfo, context, 2, (size_t)0, (size_t)siginfo->si_addr);
436 // We are going to return to the alternate stack, so block the activation signal again
437 sigmaskRet = pthread_sigmask(SIG_BLOCK, &signal_set, NULL);
440 ASSERT("pthread_sigmask failed; error number is %d\n", sigmaskRet);
443 RtlRestoreContext(&returnPoint->context, NULL);
450 handle SIGSEGV signal (EXCEPTION_ACCESS_VIOLATION, others)
453 POSIX signal handler parameter list ("man sigaction" for details)
457 static void sigsegv_handler(int code, siginfo_t *siginfo, void *context)
459 if (PALIsInitialized())
461 // First check if we have a stack overflow
462 size_t sp = (size_t)GetNativeContextSP((native_context_t *)context);
463 size_t failureAddress = (size_t)siginfo->si_addr;
465 // If the failure address is at most one page above or below the stack pointer,
466 // we have a stack overflow.
467 if ((failureAddress - (sp - GetVirtualPageSize())) < 2 * GetVirtualPageSize())
469 (void)write(STDERR_FILENO, StackOverflowMessage, sizeof(StackOverflowMessage) - 1);
473 // Now that we know the SIGSEGV didn't happen due to a stack overflow, execute the common
474 // hardware signal handler on the original stack.
476 // Establish a return point in case the common_signal_handler returns
478 if (GetCurrentPalThread())
480 volatile bool contextInitialization = true;
482 void *ptr = alloca(sizeof(SignalHandlerWorkerReturnPoint) + alignof(SignalHandlerWorkerReturnPoint) - 1);
483 SignalHandlerWorkerReturnPoint *pReturnPoint = (SignalHandlerWorkerReturnPoint *)ALIGN_UP(ptr, alignof(SignalHandlerWorkerReturnPoint));
484 RtlCaptureContext(&pReturnPoint->context);
486 // When the signal handler worker completes, it uses setcontext to return to this point
488 if (contextInitialization)
490 contextInitialization = false;
491 ExecuteHandlerOnOriginalStack(code, siginfo, context, pReturnPoint);
492 _ASSERTE(FALSE); // The ExecuteHandlerOnOriginalStack should never return
495 if (pReturnPoint->returnFromHandler)
502 // If thread isn't created by coreclr and has alternate signal stack GetCurrentPalThread() will return NULL too.
503 // But since in this case we don't handle hardware exceptions (IsSafeToHandleHardwareException returns false)
504 // we can call common_signal_handler on the alternate stack.
505 if (common_signal_handler(code, siginfo, context, 2, (size_t)0, (size_t)siginfo->si_addr))
512 if (g_previous_sigsegv.sa_sigaction != NULL)
514 g_previous_sigsegv.sa_sigaction(code, siginfo, context);
518 // Restore the original or default handler and restart h/w exception
519 restore_signal(code, &g_previous_sigsegv);
522 PROCNotifyProcessShutdown();
523 PROCCreateCrashDumpIfEnabled();
530 handle SIGTRAP signal (EXCEPTION_SINGLE_STEP, EXCEPTION_BREAKPOINT)
533 POSIX signal handler parameter list ("man sigaction" for details)
537 static void sigtrap_handler(int code, siginfo_t *siginfo, void *context)
539 if (PALIsInitialized())
541 if (common_signal_handler(code, siginfo, context, 0))
547 if (g_previous_sigtrap.sa_sigaction != NULL)
549 g_previous_sigtrap.sa_sigaction(code, siginfo, context);
553 // We abort instead of restore the original or default handler and returning
554 // because returning from a SIGTRAP handler continues execution past the trap.
558 PROCNotifyProcessShutdown();
559 PROCCreateCrashDumpIfEnabled();
566 handle SIGBUS signal (EXCEPTION_ACCESS_VIOLATION?)
569 POSIX signal handler parameter list ("man sigaction" for details)
573 static void sigbus_handler(int code, siginfo_t *siginfo, void *context)
575 if (PALIsInitialized())
577 // TODO: First variable parameter says whether a read (0) or write (non-0) caused the
578 // fault. We must disassemble the instruction at record.ExceptionAddress
579 // to correctly fill in this value.
580 if (common_signal_handler(code, siginfo, context, 2, (size_t)0, (size_t)siginfo->si_addr))
586 if (g_previous_sigbus.sa_sigaction != NULL)
588 g_previous_sigbus.sa_sigaction(code, siginfo, context);
592 // Restore the original or default handler and restart h/w exception
593 restore_signal(code, &g_previous_sigbus);
596 PROCNotifyProcessShutdown();
597 PROCCreateCrashDumpIfEnabled();
607 POSIX signal handler parameter list ("man sigaction" for details)
611 static void sigint_handler(int code, siginfo_t *siginfo, void *context)
613 PROCNotifyProcessShutdown();
615 // Restore the original or default handler and resend signal
616 restore_signal(code, &g_previous_sigint);
624 handle SIGQUIT signal
627 POSIX signal handler parameter list ("man sigaction" for details)
631 static void sigquit_handler(int code, siginfo_t *siginfo, void *context)
633 PROCNotifyProcessShutdown();
635 // Restore the original or default handler and resend signal
636 restore_signal(code, &g_previous_sigquit);
639 #endif // !HAVE_MACH_EXCEPTIONS
645 handle SIGTERM signal
648 POSIX signal handler parameter list ("man sigaction" for details)
652 static void sigterm_handler(int code, siginfo_t *siginfo, void *context)
654 if (PALIsInitialized())
656 // g_pSynchronizationManager shouldn't be null if PAL is initialized.
657 _ASSERTE(g_pSynchronizationManager != nullptr);
659 g_pSynchronizationManager->SendTerminationRequestToWorkerThread();
663 if (g_previous_sigterm.sa_sigaction != NULL)
665 g_previous_sigterm.sa_sigaction(code, siginfo, context);
670 #if !HAVE_MACH_EXCEPTIONS
671 #ifdef INJECT_ACTIVATION_SIGNAL
674 inject_activation_handler
676 Handle the INJECT_ACTIVATION_SIGNAL signal. This signal interrupts a running thread
677 so it can call the activation function that was specified when sending the signal.
680 POSIX signal handler parameter list ("man sigaction" for details)
684 static void inject_activation_handler(int code, siginfo_t *siginfo, void *context)
686 // Only accept activations from the current process
687 if (g_activationFunction != NULL && siginfo->si_pid == getpid())
689 _ASSERTE(g_safeActivationCheckFunction != NULL);
691 native_context_t *ucontext = (native_context_t *)context;
694 CONTEXTFromNativeContext(
697 CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT);
699 if (g_safeActivationCheckFunction(CONTEXTGetPC(&winContext), /* checkingCurrentThread */ TRUE))
701 g_activationFunction(&winContext);
702 // Activation function may have modified the context, so update it.
703 CONTEXTToNativeContext(&winContext, ucontext);
706 else if (g_previous_activation.sa_sigaction != NULL)
708 g_previous_activation.sa_sigaction(code, siginfo, context);
715 InjectActivationInternal
717 Interrupt the specified thread and have it call the activationFunction passed in
720 pThread - target PAL thread
721 activationFunction - function to call
725 PAL_ERROR InjectActivationInternal(CorUnix::CPalThread* pThread)
727 #ifdef INJECT_ACTIVATION_SIGNAL
728 int status = pthread_kill(pThread->GetPThreadSelf(), INJECT_ACTIVATION_SIGNAL);
731 // Failure to send the signal is fatal. There are only two cases when sending
732 // the signal can fail. First, if the signal ID is invalid and second,
733 // if the thread doesn't exist anymore.
739 return ERROR_CANCELLED;
745 signal_ignore_handler
747 Simple signal handler which does nothing
750 POSIX signal handler parameter list ("man sigaction" for details)
754 static void signal_ignore_handler(int code, siginfo_t *siginfo, void *context)
759 void PAL_IgnoreProfileSignal(int signalNum)
761 #if !HAVE_MACH_EXCEPTIONS
762 // Add a signal handler which will ignore signals
763 // This will allow signal to be used as a marker in perf recording.
764 // This will be used as an aid to synchronize recorded profile with
767 // signal(signalNum, SGN_IGN) can not be used here. It will ignore
768 // the signal in kernel space and therefore generate no recordable
769 // event for profiling. Preventing it being used for profile
772 // Since this is only used in rare circumstances no attempt to
773 // restore the old handler will be made
774 handle_signal(signalNum, signal_ignore_handler, 0);
783 specify whether the current thread is in a state where exception handling
784 of signals can be done safely
787 BOOL state : TRUE if the thread is safe, FALSE otherwise
791 void SEHSetSafeState(CPalThread *pthrCurrent, BOOL state)
793 if (NULL == pthrCurrent)
795 ASSERT( "Unable to get the thread object.\n" );
798 pthrCurrent->sehInfo.safe_state = state;
805 determine whether the current thread is in a state where exception handling
806 of signals can be done safely
811 TRUE if the thread is in a safe state, FALSE otherwise
813 BOOL SEHGetSafeState(CPalThread *pthrCurrent)
815 if (NULL == pthrCurrent)
817 ASSERT( "Unable to get the thread object.\n" );
820 return pthrCurrent->sehInfo.safe_state;
825 common_signal_handler
827 common code for all signal handlers
830 int code : signal received
831 siginfo_t *siginfo : siginfo passed to the signal handler
832 void *context : context structure passed to the signal handler
833 int numParams : number of variable parameters of the exception
834 ... : variable parameters of the exception (each of size_t type)
836 Returns true if the execution should continue or false if the exception was unhandled
838 the "pointers" parameter should contain a valid exception record pointer,
839 but the ContextRecord pointer will be overwritten.
841 __attribute__((noinline))
842 static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext, int numParams, ...)
845 CONTEXT signalContextRecord;
846 EXCEPTION_RECORD exceptionRecord;
847 native_context_t *ucontext;
849 ucontext = (native_context_t *)sigcontext;
850 g_common_signal_handler_context_locvar_offset = (int)((char*)&signalContextRecord - (char*)__builtin_frame_address(0));
852 exceptionRecord.ExceptionCode = CONTEXTGetExceptionCodeForSignal(siginfo, ucontext);
853 exceptionRecord.ExceptionFlags = EXCEPTION_IS_SIGNAL;
854 exceptionRecord.ExceptionRecord = NULL;
855 exceptionRecord.ExceptionAddress = GetNativeContextPC(ucontext);
856 exceptionRecord.NumberParameters = numParams;
859 va_start(params, numParams);
861 for (int i = 0; i < numParams; i++)
863 exceptionRecord.ExceptionInformation[i] = va_arg(params, size_t);
866 // Pre-populate context with data from current frame, because ucontext doesn't have some data (e.g. SS register)
867 // which is required for restoring context
868 RtlCaptureContext(&signalContextRecord);
870 ULONG contextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT;
873 contextFlags |= CONTEXT_XSTATE;
876 // Fill context record with required information. from pal.h:
877 // On non-Win32 platforms, the CONTEXT pointer in the
878 // PEXCEPTION_POINTERS will contain at least the CONTEXT_CONTROL registers.
879 CONTEXTFromNativeContext(ucontext, &signalContextRecord, contextFlags);
881 /* Unmask signal so we can receive it again */
882 sigemptyset(&signal_set);
883 sigaddset(&signal_set, code);
884 int sigmaskRet = pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL);
887 ASSERT("pthread_sigmask failed; error number is %d\n", sigmaskRet);
890 signalContextRecord.ContextFlags |= CONTEXT_EXCEPTION_ACTIVE;
892 // The exception object takes ownership of the exceptionRecord and contextRecord
893 PAL_SEHException exception(&exceptionRecord, &signalContextRecord, true);
895 if (SEHProcessException(&exception))
897 // Exception handling may have modified the context, so update it.
898 CONTEXTToNativeContext(exception.ExceptionPointers.ContextRecord, ucontext);
904 #endif // !HAVE_MACH_EXCEPTIONS
910 register handler for specified signal
913 int signal_id : signal to handle
914 SIGFUNC sigfunc : signal handler
915 previousAction : previous sigaction struct
919 note : if sigfunc is NULL, the default signal handler is restored
921 void handle_signal(int signal_id, SIGFUNC sigfunc, struct sigaction *previousAction, int additionalFlags, bool skipIgnored)
923 struct sigaction newAction;
925 newAction.sa_flags = SA_RESTART | additionalFlags;
927 newAction.sa_handler = NULL;
928 newAction.sa_sigaction = sigfunc;
929 newAction.sa_flags |= SA_SIGINFO;
930 #else /* HAVE_SIGINFO_T */
931 newAction.sa_handler = SIG_DFL;
932 #endif /* HAVE_SIGINFO_T */
933 sigemptyset(&newAction.sa_mask);
935 #ifdef INJECT_ACTIVATION_SIGNAL
936 if ((additionalFlags & SA_ONSTACK) != 0)
938 // A handler that runs on a separate stack should not be interrupted by the activation signal
939 // until it switches back to the regular stack, since that signal's handler would run on the
940 // limited separate stack and likely run into a stack overflow.
941 sigaddset(&newAction.sa_mask, INJECT_ACTIVATION_SIGNAL);
947 if (-1 == sigaction(signal_id, NULL, previousAction))
949 ASSERT("handle_signal: sigaction() call failed with error code %d (%s)\n",
950 errno, strerror(errno));
952 else if (previousAction->sa_handler == SIG_IGN)
958 if (-1 == sigaction(signal_id, &newAction, previousAction))
960 ASSERT("handle_signal: sigaction() call failed with error code %d (%s)\n",
961 errno, strerror(errno));
969 restore handler for specified signal
972 int signal_id : signal to handle
973 previousAction : previous sigaction struct to restore
977 void restore_signal(int signal_id, struct sigaction *previousAction)
979 if (-1 == sigaction(signal_id, previousAction, NULL))
981 ASSERT("restore_signal: sigaction() call failed with error code %d (%s)\n",
982 errno, strerror(errno));