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/*++
6
7
8
9Module Name:
10
11 exception/signal.cpp
12
13Abstract:
14
15 Signal handler implementation (map signals to exceptions)
16
17
18
19--*/
20
21#include "pal/dbgmsg.h"
22SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do this first
23
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"
31
32#include "pal/palinternal.h"
33
34#include <errno.h>
35#include <signal.h>
36
37#if !HAVE_MACH_EXCEPTIONS
38#include "pal/init.h"
39#include "pal/process.h"
40#include "pal/debug.h"
41#include "pal/virtual.h"
42#include "pal/utils.h"
43
44#include <string.h>
45#include <sys/ucontext.h>
46#include <sys/utsname.h>
47#include <unistd.h>
48#include <sys/mman.h>
49
50#include "pal/context.h"
51
52#ifdef SIGRTMIN
53#define INJECT_ACTIVATION_SIGNAL SIGRTMIN
54#endif
55
56#if !defined(INJECT_ACTIVATION_SIGNAL) && defined(FEATURE_HIJACK)
57#error FEATURE_HIJACK requires INJECT_ACTIVATION_SIGNAL to be defined
58#endif
59#endif // !HAVE_MACH_EXCEPTIONS
60
61using namespace CorUnix;
62
63/* local type definitions *****************************************************/
64
65#if !HAVE_SIGINFO_T
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
69typedef void *siginfo_t;
70#endif /* !HAVE_SIGINFO_T */
71typedef void (*SIGFUNC)(int, siginfo_t *, void *);
72
73/* internal function declarations *********************************************/
74
75static void sigterm_handler(int code, siginfo_t *siginfo, void *context);
76#if !HAVE_MACH_EXCEPTIONS
77static void sigill_handler(int code, siginfo_t *siginfo, void *context);
78static void sigfpe_handler(int code, siginfo_t *siginfo, void *context);
79static void sigsegv_handler(int code, siginfo_t *siginfo, void *context);
80static void sigtrap_handler(int code, siginfo_t *siginfo, void *context);
81static void sigbus_handler(int code, siginfo_t *siginfo, void *context);
82static void sigint_handler(int code, siginfo_t *siginfo, void *context);
83static void sigquit_handler(int code, siginfo_t *siginfo, void *context);
84
85static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext, int numParams, ...);
86
87#ifdef INJECT_ACTIVATION_SIGNAL
88static void inject_activation_handler(int code, siginfo_t *siginfo, void *context);
89#endif
90#endif // !HAVE_MACH_EXCEPTIONS
91
92static void handle_signal(int signal_id, SIGFUNC sigfunc, struct sigaction *previousAction, int additionalFlags = 0, bool skipIgnored = false);
93static void restore_signal(int signal_id, struct sigaction *previousAction);
94
95/* internal data declarations *********************************************/
96
97#if !HAVE_MACH_EXCEPTIONS
98bool g_registered_signal_handlers = false;
99#endif // !HAVE_MACH_EXCEPTIONS
100static bool g_registered_sigterm_handler = false;
101
102struct sigaction g_previous_sigterm;
103#if !HAVE_MACH_EXCEPTIONS
104struct sigaction g_previous_sigill;
105struct sigaction g_previous_sigtrap;
106struct sigaction g_previous_sigfpe;
107struct sigaction g_previous_sigbus;
108struct sigaction g_previous_sigsegv;
109struct sigaction g_previous_sigint;
110struct sigaction g_previous_sigquit;
111
112#ifdef INJECT_ACTIVATION_SIGNAL
113struct sigaction g_previous_activation;
114#endif
115
116// Offset of the local variable containing pointer to windows style context in the common_signal_handler function.
117// This offset is relative to the frame pointer.
118int g_common_signal_handler_context_locvar_offset = 0;
119#endif // !HAVE_MACH_EXCEPTIONS
120
121/* public function definitions ************************************************/
122
123/*++
124Function :
125 SEHInitializeSignals
126
127 Set up signal handlers to catch signals and translate them to exceptions
128
129Parameters :
130 None
131
132Return :
133 TRUE in case of a success, FALSE otherwise
134--*/
135BOOL SEHInitializeSignals(CorUnix::CPalThread *pthrCurrent, DWORD flags)
136{
137 TRACE("Initializing signal handlers\n");
138
139#if !HAVE_MACH_EXCEPTIONS
140 if (flags & PAL_INITIALIZE_REGISTER_SIGNALS)
141 {
142 g_registered_signal_handlers = true;
143
144 /* we call handle_signal for every possible signal, even
145 if we don't provide a signal handler.
146
147 handle_signal will set SA_RESTART flag for specified signal.
148 Therefore, all signals will have SA_RESTART flag set, preventing
149 slow Unix system calls from being interrupted. On systems without
150 siginfo_t, SIGKILL and SIGSTOP can't be restarted, so we don't
151 handle those signals. Both the Darwin and FreeBSD man pages say
152 that SIGKILL and SIGSTOP can't be handled, but FreeBSD allows us
153 to register a handler for them anyway. We don't do that.
154
155 see sigaction man page for more details
156 */
157 handle_signal(SIGILL, sigill_handler, &g_previous_sigill);
158 handle_signal(SIGTRAP, sigtrap_handler, &g_previous_sigtrap);
159 handle_signal(SIGFPE, sigfpe_handler, &g_previous_sigfpe);
160 handle_signal(SIGBUS, sigbus_handler, &g_previous_sigbus);
161 // SIGSEGV handler runs on a separate stack so that we can handle stack overflow
162 handle_signal(SIGSEGV, sigsegv_handler, &g_previous_sigsegv, SA_ONSTACK);
163 // We don't setup a handler for SIGINT/SIGQUIT when those signals are ignored.
164 // Otherwise our child processes would reset to the default on exec causing them
165 // to terminate on these signals.
166 handle_signal(SIGINT, sigint_handler, &g_previous_sigint, 0 /* additionalFlags */, true /* skipIgnored */);
167 handle_signal(SIGQUIT, sigquit_handler, &g_previous_sigquit, 0 /* additionalFlags */, true /* skipIgnored */);
168
169#ifdef INJECT_ACTIVATION_SIGNAL
170 handle_signal(INJECT_ACTIVATION_SIGNAL, inject_activation_handler, &g_previous_activation);
171#endif
172 if (!pthrCurrent->EnsureSignalAlternateStack())
173 {
174 return FALSE;
175 }
176 }
177
178 /* The default action for SIGPIPE is process termination.
179 Since SIGPIPE can be signaled when trying to write on a socket for which
180 the connection has been dropped, we need to tell the system we want
181 to ignore this signal.
182
183 Instead of terminating the process, the system call which would had
184 issued a SIGPIPE will, instead, report an error and set errno to EPIPE.
185 */
186 signal(SIGPIPE, SIG_IGN);
187#endif // !HAVE_MACH_EXCEPTIONS
188
189 if (flags & PAL_INITIALIZE_REGISTER_SIGTERM_HANDLER)
190 {
191 g_registered_sigterm_handler = true;
192 handle_signal(SIGTERM, sigterm_handler, &g_previous_sigterm);
193 }
194
195 return TRUE;
196}
197
198/*++
199Function :
200 SEHCleanupSignals
201
202 Restore default signal handlers
203
204Parameters :
205 None
206
207 (no return value)
208
209note :
210reason for this function is that during PAL_Terminate, we reach a point where
211SEH isn't possible anymore (handle manager is off, etc). Past that point,
212we can't avoid crashing on a signal.
213--*/
214void SEHCleanupSignals()
215{
216 TRACE("Restoring default signal handlers\n");
217
218#if !HAVE_MACH_EXCEPTIONS
219 if (g_registered_signal_handlers)
220 {
221 restore_signal(SIGILL, &g_previous_sigill);
222 restore_signal(SIGTRAP, &g_previous_sigtrap);
223 restore_signal(SIGFPE, &g_previous_sigfpe);
224 restore_signal(SIGBUS, &g_previous_sigbus);
225 restore_signal(SIGSEGV, &g_previous_sigsegv);
226 restore_signal(SIGINT, &g_previous_sigint);
227 restore_signal(SIGQUIT, &g_previous_sigquit);
228#ifdef INJECT_ACTIVATION_SIGNAL
229 restore_signal(INJECT_ACTIVATION_SIGNAL, &g_previous_activation);
230#endif
231 }
232#endif // !HAVE_MACH_EXCEPTIONS
233
234 if (g_registered_sigterm_handler)
235 {
236 restore_signal(SIGTERM, &g_previous_sigterm);
237 }
238}
239
240/* internal function definitions **********************************************/
241
242#if !HAVE_MACH_EXCEPTIONS
243/*++
244Function :
245 sigill_handler
246
247 handle SIGILL signal (EXCEPTION_ILLEGAL_INSTRUCTION, others?)
248
249Parameters :
250 POSIX signal handler parameter list ("man sigaction" for details)
251
252 (no return value)
253--*/
254static void sigill_handler(int code, siginfo_t *siginfo, void *context)
255{
256 if (PALIsInitialized())
257 {
258 if (common_signal_handler(code, siginfo, context, 0))
259 {
260 return;
261 }
262 }
263
264 if (g_previous_sigill.sa_sigaction != NULL)
265 {
266 g_previous_sigill.sa_sigaction(code, siginfo, context);
267 }
268 else
269 {
270 // Restore the original or default handler and restart h/w exception
271 restore_signal(code, &g_previous_sigill);
272 }
273
274 PROCNotifyProcessShutdown();
275 PROCCreateCrashDumpIfEnabled();
276}
277
278/*++
279Function :
280 sigfpe_handler
281
282 handle SIGFPE signal (division by zero, floating point exception)
283
284Parameters :
285 POSIX signal handler parameter list ("man sigaction" for details)
286
287 (no return value)
288--*/
289static void sigfpe_handler(int code, siginfo_t *siginfo, void *context)
290{
291 if (PALIsInitialized())
292 {
293 if (common_signal_handler(code, siginfo, context, 0))
294 {
295 return;
296 }
297 }
298
299 if (g_previous_sigfpe.sa_sigaction != NULL)
300 {
301 g_previous_sigfpe.sa_sigaction(code, siginfo, context);
302 }
303 else
304 {
305 // Restore the original or default handler and restart h/w exception
306 restore_signal(code, &g_previous_sigfpe);
307 }
308
309 PROCNotifyProcessShutdown();
310 PROCCreateCrashDumpIfEnabled();
311}
312
313/*++
314Function :
315 signal_handler_worker
316
317 Handles signal on the original stack where the signal occured.
318 Invoked via setcontext.
319
320Parameters :
321 POSIX signal handler parameter list ("man sigaction" for details)
322 returnPoint - context to which the function returns if the common_signal_handler returns
323
324 (no return value)
325--*/
326extern "C" void signal_handler_worker(int code, siginfo_t *siginfo, void *context, SignalHandlerWorkerReturnPoint* returnPoint)
327{
328 // TODO: First variable parameter says whether a read (0) or write (non-0) caused the
329 // fault. We must disassemble the instruction at record.ExceptionAddress
330 // to correctly fill in this value.
331
332 // Unmask the activation signal now that we are running on the original stack of the thread
333 sigset_t signal_set;
334 sigemptyset(&signal_set);
335 sigaddset(&signal_set, INJECT_ACTIVATION_SIGNAL);
336
337 int sigmaskRet = pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL);
338 if (sigmaskRet != 0)
339 {
340 ASSERT("pthread_sigmask failed; error number is %d\n", sigmaskRet);
341 }
342
343 returnPoint->returnFromHandler = common_signal_handler(code, siginfo, context, 2, (size_t)0, (size_t)siginfo->si_addr);
344
345 // We are going to return to the alternate stack, so block the activation signal again
346 sigmaskRet = pthread_sigmask(SIG_BLOCK, &signal_set, NULL);
347 if (sigmaskRet != 0)
348 {
349 ASSERT("pthread_sigmask failed; error number is %d\n", sigmaskRet);
350 }
351
352 RtlRestoreContext(&returnPoint->context, NULL);
353}
354
355/*++
356Function :
357 sigsegv_handler
358
359 handle SIGSEGV signal (EXCEPTION_ACCESS_VIOLATION, others)
360
361Parameters :
362 POSIX signal handler parameter list ("man sigaction" for details)
363
364 (no return value)
365--*/
366static void sigsegv_handler(int code, siginfo_t *siginfo, void *context)
367{
368 if (PALIsInitialized())
369 {
370 // First check if we have a stack overflow
371 size_t sp = (size_t)GetNativeContextSP((native_context_t *)context);
372 size_t failureAddress = (size_t)siginfo->si_addr;
373
374 // If the failure address is at most one page above or below the stack pointer,
375 // we have a stack overflow.
376 if ((failureAddress - (sp - GetVirtualPageSize())) < 2 * GetVirtualPageSize())
377 {
378 (void)write(STDERR_FILENO, StackOverflowMessage, sizeof(StackOverflowMessage) - 1);
379 PROCAbort();
380 }
381
382 // Now that we know the SIGSEGV didn't happen due to a stack overflow, execute the common
383 // hardware signal handler on the original stack.
384
385 // Establish a return point in case the common_signal_handler returns
386
387 if (GetCurrentPalThread())
388 {
389 volatile bool contextInitialization = true;
390
391 void *ptr = alloca(sizeof(SignalHandlerWorkerReturnPoint) + alignof(SignalHandlerWorkerReturnPoint) - 1);
392 SignalHandlerWorkerReturnPoint *pReturnPoint = (SignalHandlerWorkerReturnPoint *)ALIGN_UP(ptr, alignof(SignalHandlerWorkerReturnPoint));
393 RtlCaptureContext(&pReturnPoint->context);
394
395 // When the signal handler worker completes, it uses setcontext to return to this point
396
397 if (contextInitialization)
398 {
399 contextInitialization = false;
400 ExecuteHandlerOnOriginalStack(code, siginfo, context, pReturnPoint);
401 _ASSERTE(FALSE); // The ExecuteHandlerOnOriginalStack should never return
402 }
403
404 if (pReturnPoint->returnFromHandler)
405 {
406 return;
407 }
408 }
409 else
410 {
411 // If thread isn't created by coreclr and has alternate signal stack GetCurrentPalThread() will return NULL too.
412 // But since in this case we don't handle hardware exceptions (IsSafeToHandleHardwareException returns false)
413 // we can call common_signal_handler on the alternate stack.
414 if (common_signal_handler(code, siginfo, context, 2, (size_t)0, (size_t)siginfo->si_addr))
415 {
416 return;
417 }
418 }
419 }
420
421 if (g_previous_sigsegv.sa_sigaction != NULL)
422 {
423 g_previous_sigsegv.sa_sigaction(code, siginfo, context);
424 }
425 else
426 {
427 // Restore the original or default handler and restart h/w exception
428 restore_signal(code, &g_previous_sigsegv);
429 }
430
431 PROCNotifyProcessShutdown();
432 PROCCreateCrashDumpIfEnabled();
433}
434
435/*++
436Function :
437 sigtrap_handler
438
439 handle SIGTRAP signal (EXCEPTION_SINGLE_STEP, EXCEPTION_BREAKPOINT)
440
441Parameters :
442 POSIX signal handler parameter list ("man sigaction" for details)
443
444 (no return value)
445--*/
446static void sigtrap_handler(int code, siginfo_t *siginfo, void *context)
447{
448 if (PALIsInitialized())
449 {
450 if (common_signal_handler(code, siginfo, context, 0))
451 {
452 return;
453 }
454 }
455
456 if (g_previous_sigtrap.sa_sigaction != NULL)
457 {
458 g_previous_sigtrap.sa_sigaction(code, siginfo, context);
459 }
460 else
461 {
462 // We abort instead of restore the original or default handler and returning
463 // because returning from a SIGTRAP handler continues execution past the trap.
464 PROCAbort();
465 }
466
467 PROCNotifyProcessShutdown();
468 PROCCreateCrashDumpIfEnabled();
469}
470
471/*++
472Function :
473 sigbus_handler
474
475 handle SIGBUS signal (EXCEPTION_ACCESS_VIOLATION?)
476
477Parameters :
478 POSIX signal handler parameter list ("man sigaction" for details)
479
480 (no return value)
481--*/
482static void sigbus_handler(int code, siginfo_t *siginfo, void *context)
483{
484 if (PALIsInitialized())
485 {
486 // TODO: First variable parameter says whether a read (0) or write (non-0) caused the
487 // fault. We must disassemble the instruction at record.ExceptionAddress
488 // to correctly fill in this value.
489 if (common_signal_handler(code, siginfo, context, 2, (size_t)0, (size_t)siginfo->si_addr))
490 {
491 return;
492 }
493 }
494
495 if (g_previous_sigbus.sa_sigaction != NULL)
496 {
497 g_previous_sigbus.sa_sigaction(code, siginfo, context);
498 }
499 else
500 {
501 // Restore the original or default handler and restart h/w exception
502 restore_signal(code, &g_previous_sigbus);
503 }
504
505 PROCNotifyProcessShutdown();
506 PROCCreateCrashDumpIfEnabled();
507}
508
509/*++
510Function :
511 sigint_handler
512
513 handle SIGINT signal
514
515Parameters :
516 POSIX signal handler parameter list ("man sigaction" for details)
517
518 (no return value)
519--*/
520static void sigint_handler(int code, siginfo_t *siginfo, void *context)
521{
522 PROCNotifyProcessShutdown();
523
524 // Restore the original or default handler and resend signal
525 restore_signal(code, &g_previous_sigint);
526 kill(gPID, code);
527}
528
529/*++
530Function :
531 sigquit_handler
532
533 handle SIGQUIT signal
534
535Parameters :
536 POSIX signal handler parameter list ("man sigaction" for details)
537
538 (no return value)
539--*/
540static void sigquit_handler(int code, siginfo_t *siginfo, void *context)
541{
542 PROCNotifyProcessShutdown();
543
544 // Restore the original or default handler and resend signal
545 restore_signal(code, &g_previous_sigquit);
546 kill(gPID, code);
547}
548#endif // !HAVE_MACH_EXCEPTIONS
549
550/*++
551Function :
552 sigterm_handler
553
554 handle SIGTERM signal
555
556Parameters :
557 POSIX signal handler parameter list ("man sigaction" for details)
558
559 (no return value)
560--*/
561static void sigterm_handler(int code, siginfo_t *siginfo, void *context)
562{
563 if (PALIsInitialized())
564 {
565 // g_pSynchronizationManager shouldn't be null if PAL is initialized.
566 _ASSERTE(g_pSynchronizationManager != nullptr);
567
568 g_pSynchronizationManager->SendTerminationRequestToWorkerThread();
569 }
570 else
571 {
572 if (g_previous_sigterm.sa_sigaction != NULL)
573 {
574 g_previous_sigterm.sa_sigaction(code, siginfo, context);
575 }
576 }
577}
578
579#if !HAVE_MACH_EXCEPTIONS
580#ifdef INJECT_ACTIVATION_SIGNAL
581/*++
582Function :
583 inject_activation_handler
584
585 Handle the INJECT_ACTIVATION_SIGNAL signal. This signal interrupts a running thread
586 so it can call the activation function that was specified when sending the signal.
587
588Parameters :
589 POSIX signal handler parameter list ("man sigaction" for details)
590
591(no return value)
592--*/
593static void inject_activation_handler(int code, siginfo_t *siginfo, void *context)
594{
595 // Only accept activations from the current process
596 if (g_activationFunction != NULL && siginfo->si_pid == getpid())
597 {
598 _ASSERTE(g_safeActivationCheckFunction != NULL);
599
600 native_context_t *ucontext = (native_context_t *)context;
601
602 CONTEXT winContext;
603 CONTEXTFromNativeContext(
604 ucontext,
605 &winContext,
606 CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT);
607
608 if (g_safeActivationCheckFunction(CONTEXTGetPC(&winContext), /* checkingCurrentThread */ TRUE))
609 {
610 g_activationFunction(&winContext);
611 // Activation function may have modified the context, so update it.
612 CONTEXTToNativeContext(&winContext, ucontext);
613 }
614 }
615 else if (g_previous_activation.sa_sigaction != NULL)
616 {
617 g_previous_activation.sa_sigaction(code, siginfo, context);
618 }
619}
620#endif
621
622/*++
623Function :
624 InjectActivationInternal
625
626 Interrupt the specified thread and have it call the activationFunction passed in
627
628Parameters :
629 pThread - target PAL thread
630 activationFunction - function to call
631
632(no return value)
633--*/
634PAL_ERROR InjectActivationInternal(CorUnix::CPalThread* pThread)
635{
636#ifdef INJECT_ACTIVATION_SIGNAL
637 int status = pthread_kill(pThread->GetPThreadSelf(), INJECT_ACTIVATION_SIGNAL);
638 if (status != 0)
639 {
640 // Failure to send the signal is fatal. There are only two cases when sending
641 // the signal can fail. First, if the signal ID is invalid and second,
642 // if the thread doesn't exist anymore.
643 PROCAbort();
644 }
645
646 return NO_ERROR;
647#else
648 return ERROR_CANCELLED;
649#endif
650}
651
652/*++
653Function :
654 signal_ignore_handler
655
656 Simple signal handler which does nothing
657
658Parameters :
659 POSIX signal handler parameter list ("man sigaction" for details)
660
661(no return value)
662--*/
663static void signal_ignore_handler(int code, siginfo_t *siginfo, void *context)
664{
665}
666
667
668void PAL_IgnoreProfileSignal(int signalNum)
669{
670#if !HAVE_MACH_EXCEPTIONS
671 // Add a signal handler which will ignore signals
672 // This will allow signal to be used as a marker in perf recording.
673 // This will be used as an aid to synchronize recorded profile with
674 // test cases
675 //
676 // signal(signalNum, SGN_IGN) can not be used here. It will ignore
677 // the signal in kernel space and therefore generate no recordable
678 // event for profiling. Preventing it being used for profile
679 // synchronization
680 //
681 // Since this is only used in rare circumstances no attempt to
682 // restore the old handler will be made
683 handle_signal(signalNum, signal_ignore_handler, 0);
684#endif
685}
686
687
688/*++
689Function :
690 SEHSetSafeState
691
692 specify whether the current thread is in a state where exception handling
693 of signals can be done safely
694
695Parameters:
696 BOOL state : TRUE if the thread is safe, FALSE otherwise
697
698(no return value)
699--*/
700void SEHSetSafeState(CPalThread *pthrCurrent, BOOL state)
701{
702 if (NULL == pthrCurrent)
703 {
704 ASSERT( "Unable to get the thread object.\n" );
705 return;
706 }
707 pthrCurrent->sehInfo.safe_state = state;
708}
709
710/*++
711Function :
712 SEHGetSafeState
713
714 determine whether the current thread is in a state where exception handling
715 of signals can be done safely
716
717 (no parameters)
718
719Return value :
720 TRUE if the thread is in a safe state, FALSE otherwise
721--*/
722BOOL SEHGetSafeState(CPalThread *pthrCurrent)
723{
724 if (NULL == pthrCurrent)
725 {
726 ASSERT( "Unable to get the thread object.\n" );
727 return FALSE;
728 }
729 return pthrCurrent->sehInfo.safe_state;
730}
731
732/*++
733Function :
734 common_signal_handler
735
736 common code for all signal handlers
737
738Parameters :
739 int code : signal received
740 siginfo_t *siginfo : siginfo passed to the signal handler
741 void *context : context structure passed to the signal handler
742 int numParams : number of variable parameters of the exception
743 ... : variable parameters of the exception (each of size_t type)
744
745 Returns true if the execution should continue or false if the exception was unhandled
746Note:
747 the "pointers" parameter should contain a valid exception record pointer,
748 but the ContextRecord pointer will be overwritten.
749--*/
750__attribute__((noinline))
751static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext, int numParams, ...)
752{
753 sigset_t signal_set;
754 CONTEXT signalContextRecord;
755 EXCEPTION_RECORD exceptionRecord;
756 native_context_t *ucontext;
757
758 ucontext = (native_context_t *)sigcontext;
759 g_common_signal_handler_context_locvar_offset = (int)((char*)&signalContextRecord - (char*)__builtin_frame_address(0));
760
761 exceptionRecord.ExceptionCode = CONTEXTGetExceptionCodeForSignal(siginfo, ucontext);
762 exceptionRecord.ExceptionFlags = EXCEPTION_IS_SIGNAL;
763 exceptionRecord.ExceptionRecord = NULL;
764 exceptionRecord.ExceptionAddress = GetNativeContextPC(ucontext);
765 exceptionRecord.NumberParameters = numParams;
766
767 va_list params;
768 va_start(params, numParams);
769
770 for (int i = 0; i < numParams; i++)
771 {
772 exceptionRecord.ExceptionInformation[i] = va_arg(params, size_t);
773 }
774
775 // Pre-populate context with data from current frame, because ucontext doesn't have some data (e.g. SS register)
776 // which is required for restoring context
777 RtlCaptureContext(&signalContextRecord);
778
779 ULONG contextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT;
780
781#if defined(_AMD64_)
782 contextFlags |= CONTEXT_XSTATE;
783#endif
784
785 // Fill context record with required information. from pal.h:
786 // On non-Win32 platforms, the CONTEXT pointer in the
787 // PEXCEPTION_POINTERS will contain at least the CONTEXT_CONTROL registers.
788 CONTEXTFromNativeContext(ucontext, &signalContextRecord, contextFlags);
789
790 /* Unmask signal so we can receive it again */
791 sigemptyset(&signal_set);
792 sigaddset(&signal_set, code);
793 int sigmaskRet = pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL);
794 if (sigmaskRet != 0)
795 {
796 ASSERT("pthread_sigmask failed; error number is %d\n", sigmaskRet);
797 }
798
799 signalContextRecord.ContextFlags |= CONTEXT_EXCEPTION_ACTIVE;
800
801 // The exception object takes ownership of the exceptionRecord and contextRecord
802 PAL_SEHException exception(&exceptionRecord, &signalContextRecord, true);
803
804 if (SEHProcessException(&exception))
805 {
806 // Exception handling may have modified the context, so update it.
807 CONTEXTToNativeContext(exception.ExceptionPointers.ContextRecord, ucontext);
808 return true;
809 }
810
811 return false;
812}
813#endif // !HAVE_MACH_EXCEPTIONS
814
815/*++
816Function :
817 handle_signal
818
819 register handler for specified signal
820
821Parameters :
822 int signal_id : signal to handle
823 SIGFUNC sigfunc : signal handler
824 previousAction : previous sigaction struct
825
826 (no return value)
827
828note : if sigfunc is NULL, the default signal handler is restored
829--*/
830void handle_signal(int signal_id, SIGFUNC sigfunc, struct sigaction *previousAction, int additionalFlags, bool skipIgnored)
831{
832 struct sigaction newAction;
833
834 newAction.sa_flags = SA_RESTART | additionalFlags;
835#if HAVE_SIGINFO_T
836 newAction.sa_handler = NULL;
837 newAction.sa_sigaction = sigfunc;
838 newAction.sa_flags |= SA_SIGINFO;
839#else /* HAVE_SIGINFO_T */
840 newAction.sa_handler = SIG_DFL;
841#endif /* HAVE_SIGINFO_T */
842 sigemptyset(&newAction.sa_mask);
843
844#ifdef INJECT_ACTIVATION_SIGNAL
845 if ((additionalFlags & SA_ONSTACK) != 0)
846 {
847 // A handler that runs on a separate stack should not be interrupted by the activation signal
848 // until it switches back to the regular stack, since that signal's handler would run on the
849 // limited separate stack and likely run into a stack overflow.
850 sigaddset(&newAction.sa_mask, INJECT_ACTIVATION_SIGNAL);
851 }
852#endif
853
854 if (skipIgnored)
855 {
856 if (-1 == sigaction(signal_id, NULL, previousAction))
857 {
858 ASSERT("handle_signal: sigaction() call failed with error code %d (%s)\n",
859 errno, strerror(errno));
860 }
861 else if (previousAction->sa_handler == SIG_IGN)
862 {
863 return;
864 }
865 }
866
867 if (-1 == sigaction(signal_id, &newAction, previousAction))
868 {
869 ASSERT("handle_signal: sigaction() call failed with error code %d (%s)\n",
870 errno, strerror(errno));
871 }
872}
873
874/*++
875Function :
876 restore_signal
877
878 restore handler for specified signal
879
880Parameters :
881 int signal_id : signal to handle
882 previousAction : previous sigaction struct to restore
883
884 (no return value)
885--*/
886void restore_signal(int signal_id, struct sigaction *previousAction)
887{
888 if (-1 == sigaction(signal_id, previousAction, NULL))
889 {
890 ASSERT("restore_signal: sigaction() call failed with error code %d (%s)\n",
891 errno, strerror(errno));
892 }
893}
894