Port to 2.1: Fix alternate stack cleanup on MUSL (#18687)
[platform/upstream/coreclr.git] / src / pal / src / exception / signal.cpp
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
9 Module Name:
10
11     exception/signal.cpp
12
13 Abstract:
14
15     Signal handler implementation (map signals to exceptions)
16
17
18
19 --*/
20
21 #include "pal/dbgmsg.h"
22 SET_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
61 using 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
69 typedef void *siginfo_t;
70 #endif  /* !HAVE_SIGINFO_T */
71 typedef void (*SIGFUNC)(int, siginfo_t *, void *);
72
73 #if !HAVE_MACH_EXCEPTIONS
74 // Return context and status for the signal_handler_worker.
75 struct SignalHandlerWorkerReturnPoint
76 {
77     bool returnFromHandler;
78     CONTEXT context;
79 };
80 #endif // !HAVE_MACH_EXCEPTIONS
81
82 /* internal function declarations *********************************************/
83
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);
93
94 static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext, int numParams, ...);
95
96 #ifdef INJECT_ACTIVATION_SIGNAL
97 static void inject_activation_handler(int code, siginfo_t *siginfo, void *context);
98 #endif
99 #endif // !HAVE_MACH_EXCEPTIONS
100
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);
103
104 /* internal data declarations *********************************************/
105
106 static bool registered_sigterm_handler = false;
107
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;
117
118 #ifdef INJECT_ACTIVATION_SIGNAL
119 struct sigaction g_previous_activation;
120 #endif
121
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
126
127 /* public function definitions ************************************************/
128
129 #if !HAVE_MACH_EXCEPTIONS
130 /*++
131 Function :
132     EnsureSignalAlternateStack
133
134     Ensure that alternate stack for signal handling is allocated for the current thread
135
136 Parameters :
137     None
138
139 Return :
140     TRUE in case of a success, FALSE otherwise
141 --*/
142 BOOL EnsureSignalAlternateStack()
143 {
144     stack_t oss;
145
146     // Query the current alternate signal stack
147     int st = sigaltstack(NULL, &oss);
148
149     if ((st == 0) && (oss.ss_flags == SS_DISABLE))
150     {
151         // There is no alternate stack for SIGSEGV handling installed yet so allocate one
152
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();
156 #ifdef HAS_ASAN
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;
160 #endif
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)
164         {
165             // create a guard page for the alternate stack
166             st = mprotect(altStack, GetVirtualPageSize(), PROT_NONE);
167             if (st == 0)
168             {
169                 stack_t ss;
170                 ss.ss_sp = (char*)altStack;
171                 ss.ss_size = altStackSize;
172                 ss.ss_flags = 0;
173                 st = sigaltstack(&ss, NULL);
174             }
175
176             if (st != 0)
177             {
178                int st2 = munmap(altStack, altStackSize);
179                _ASSERTE(st2 == 0);
180             }
181         }
182     }
183
184     return (st == 0);
185 }
186
187 /*++
188 Function :
189     FreeSignalAlternateStack
190
191     Free alternate stack for signal handling
192
193 Parameters :
194     None
195
196 Return :
197     None
198 --*/
199 void FreeSignalAlternateStack()
200 {
201     stack_t ss, oss;
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))
209     {
210         int st = munmap(oss.ss_sp, oss.ss_size);
211         _ASSERTE(st == 0);
212     }
213 }
214 #endif // !HAVE_MACH_EXCEPTIONS
215
216 /*++
217 Function :
218     SEHInitializeSignals
219
220     Set up signal handlers to catch signals and translate them to exceptions
221
222 Parameters :
223     None
224
225 Return :
226     TRUE in case of a success, FALSE otherwise
227 --*/
228 BOOL SEHInitializeSignals(DWORD flags)
229 {
230     TRACE("Initializing signal handlers\n");
231
232 #if !HAVE_MACH_EXCEPTIONS
233     /* we call handle_signal for every possible signal, even
234        if we don't provide a signal handler.
235
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.
243
244        see sigaction man page for more details
245        */
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 */);
257
258     if (!EnsureSignalAlternateStack())
259     {
260         return FALSE;
261     }
262 #endif // !HAVE_MACH_EXCEPTIONS
263
264     if (flags & PAL_INITIALIZE_REGISTER_SIGTERM_HANDLER)
265     {
266         handle_signal(SIGTERM, sigterm_handler, &g_previous_sigterm);
267         registered_sigterm_handler = true;
268     }
269
270 #if !HAVE_MACH_EXCEPTIONS
271 #ifdef INJECT_ACTIVATION_SIGNAL
272     handle_signal(INJECT_ACTIVATION_SIGNAL, inject_activation_handler, &g_previous_activation);
273 #endif
274
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.
279
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.
282     */
283     signal(SIGPIPE, SIG_IGN);
284 #endif // !HAVE_MACH_EXCEPTIONS
285
286     return TRUE;
287 }
288
289 /*++
290 Function :
291     SEHCleanupSignals
292
293     Restore default signal handlers
294
295 Parameters :
296     None
297
298     (no return value)
299     
300 note :
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.
304 --*/
305 void SEHCleanupSignals()
306 {
307     TRACE("Restoring default signal handlers\n");
308
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
318
319     if (registered_sigterm_handler)
320     {
321         restore_signal(SIGTERM, &g_previous_sigterm);
322     }
323
324 #if !HAVE_MACH_EXCEPTIONS
325 #ifdef INJECT_ACTIVATION_SIGNAL
326     restore_signal(INJECT_ACTIVATION_SIGNAL, &g_previous_activation);
327 #endif
328 #endif // !HAVE_MACH_EXCEPTIONS
329 }
330
331 /* internal function definitions **********************************************/
332
333 #if !HAVE_MACH_EXCEPTIONS
334 /*++
335 Function :
336     sigill_handler
337
338     handle SIGILL signal (EXCEPTION_ILLEGAL_INSTRUCTION, others?)
339
340 Parameters :
341     POSIX signal handler parameter list ("man sigaction" for details)
342
343     (no return value)
344 --*/
345 static void sigill_handler(int code, siginfo_t *siginfo, void *context)
346 {
347     if (PALIsInitialized())
348     {
349         if (common_signal_handler(code, siginfo, context, 0))
350         {
351             return;
352         }
353     }
354
355     if (g_previous_sigill.sa_sigaction != NULL)
356     {
357         g_previous_sigill.sa_sigaction(code, siginfo, context);
358     }
359     else
360     {
361         // Restore the original or default handler and restart h/w exception
362         restore_signal(code, &g_previous_sigill);
363     }
364
365     PROCNotifyProcessShutdown();
366     PROCCreateCrashDumpIfEnabled();
367 }
368
369 /*++
370 Function :
371     sigfpe_handler
372
373     handle SIGFPE signal (division by zero, floating point exception)
374
375 Parameters :
376     POSIX signal handler parameter list ("man sigaction" for details)
377
378     (no return value)
379 --*/
380 static void sigfpe_handler(int code, siginfo_t *siginfo, void *context)
381 {
382     if (PALIsInitialized())
383     {
384         if (common_signal_handler(code, siginfo, context, 0))
385         {
386             return;
387         }
388     }
389
390     if (g_previous_sigfpe.sa_sigaction != NULL)
391     {
392         g_previous_sigfpe.sa_sigaction(code, siginfo, context);
393     }
394     else
395     {
396         // Restore the original or default handler and restart h/w exception
397         restore_signal(code, &g_previous_sigfpe);
398     }
399
400     PROCNotifyProcessShutdown();
401     PROCCreateCrashDumpIfEnabled();
402 }
403
404 /*++
405 Function :
406     signal_handler_worker
407
408     Handles signal on the original stack where the signal occured. 
409     Invoked via setcontext.
410
411 Parameters :
412     POSIX signal handler parameter list ("man sigaction" for details)
413     returnPoint - context to which the function returns if the common_signal_handler returns
414
415     (no return value)
416 --*/
417 extern "C" void signal_handler_worker(int code, siginfo_t *siginfo, void *context, SignalHandlerWorkerReturnPoint* returnPoint)
418 {
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.
422
423     // Unmask the activation signal now that we are running on the original stack of the thread
424     sigset_t signal_set;
425     sigemptyset(&signal_set);
426     sigaddset(&signal_set, INJECT_ACTIVATION_SIGNAL);
427
428     int sigmaskRet = pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL);
429     if (sigmaskRet != 0)
430     {
431         ASSERT("pthread_sigmask failed; error number is %d\n", sigmaskRet);
432     }
433
434     returnPoint->returnFromHandler = common_signal_handler(code, siginfo, context, 2, (size_t)0, (size_t)siginfo->si_addr);
435
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);
438     if (sigmaskRet != 0)
439     {
440         ASSERT("pthread_sigmask failed; error number is %d\n", sigmaskRet);
441     }
442
443     RtlRestoreContext(&returnPoint->context, NULL);
444 }
445
446 /*++
447 Function :
448     sigsegv_handler
449
450     handle SIGSEGV signal (EXCEPTION_ACCESS_VIOLATION, others)
451
452 Parameters :
453     POSIX signal handler parameter list ("man sigaction" for details)
454
455     (no return value)
456 --*/
457 static void sigsegv_handler(int code, siginfo_t *siginfo, void *context)
458 {
459     if (PALIsInitialized())
460     {
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;
464
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())
468         {
469             (void)write(STDERR_FILENO, StackOverflowMessage, sizeof(StackOverflowMessage) - 1);
470             PROCAbort();
471         }
472
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.
475
476         // Establish a return point in case the common_signal_handler returns
477
478         if (GetCurrentPalThread())
479         {
480             volatile bool contextInitialization = true;
481
482             void *ptr = alloca(sizeof(SignalHandlerWorkerReturnPoint) + alignof(SignalHandlerWorkerReturnPoint) - 1);
483             SignalHandlerWorkerReturnPoint *pReturnPoint = (SignalHandlerWorkerReturnPoint *)ALIGN_UP(ptr, alignof(SignalHandlerWorkerReturnPoint));
484             RtlCaptureContext(&pReturnPoint->context);
485
486             // When the signal handler worker completes, it uses setcontext to return to this point
487
488             if (contextInitialization)
489             {
490                 contextInitialization = false;
491                 ExecuteHandlerOnOriginalStack(code, siginfo, context, pReturnPoint);
492                 _ASSERTE(FALSE); // The ExecuteHandlerOnOriginalStack should never return
493             }
494
495             if (pReturnPoint->returnFromHandler)
496             {
497                 return;
498             }
499         }
500         else
501         {
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))
506             {
507                 return;
508             }
509         }
510     }
511
512     if (g_previous_sigsegv.sa_sigaction != NULL)
513     {
514         g_previous_sigsegv.sa_sigaction(code, siginfo, context);
515     }
516     else
517     {
518         // Restore the original or default handler and restart h/w exception
519         restore_signal(code, &g_previous_sigsegv);
520     }
521
522     PROCNotifyProcessShutdown();
523     PROCCreateCrashDumpIfEnabled();
524 }
525
526 /*++
527 Function :
528     sigtrap_handler
529
530     handle SIGTRAP signal (EXCEPTION_SINGLE_STEP, EXCEPTION_BREAKPOINT)
531
532 Parameters :
533     POSIX signal handler parameter list ("man sigaction" for details)
534
535     (no return value)
536 --*/
537 static void sigtrap_handler(int code, siginfo_t *siginfo, void *context)
538 {
539     if (PALIsInitialized())
540     {
541         if (common_signal_handler(code, siginfo, context, 0))
542         {
543             return;
544         }
545     }
546
547     if (g_previous_sigtrap.sa_sigaction != NULL)
548     {
549         g_previous_sigtrap.sa_sigaction(code, siginfo, context);
550     }
551     else
552     {
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.
555         PROCAbort();
556     }
557
558     PROCNotifyProcessShutdown();
559     PROCCreateCrashDumpIfEnabled();
560 }
561
562 /*++
563 Function :
564     sigbus_handler
565
566     handle SIGBUS signal (EXCEPTION_ACCESS_VIOLATION?)
567
568 Parameters :
569     POSIX signal handler parameter list ("man sigaction" for details)
570
571     (no return value)
572 --*/
573 static void sigbus_handler(int code, siginfo_t *siginfo, void *context)
574 {
575     if (PALIsInitialized())
576     {
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))
581         {
582             return;
583         }
584     }
585
586     if (g_previous_sigbus.sa_sigaction != NULL)
587     {
588         g_previous_sigbus.sa_sigaction(code, siginfo, context);
589     }
590     else
591     {
592         // Restore the original or default handler and restart h/w exception
593         restore_signal(code, &g_previous_sigbus);
594     }
595
596     PROCNotifyProcessShutdown();
597     PROCCreateCrashDumpIfEnabled();
598 }
599
600 /*++
601 Function :
602     sigint_handler
603
604     handle SIGINT signal
605
606 Parameters :
607     POSIX signal handler parameter list ("man sigaction" for details)
608
609     (no return value)
610 --*/
611 static void sigint_handler(int code, siginfo_t *siginfo, void *context)
612 {
613     PROCNotifyProcessShutdown();
614
615     // Restore the original or default handler and resend signal
616     restore_signal(code, &g_previous_sigint);
617     kill(gPID, code);
618 }
619
620 /*++
621 Function :
622     sigquit_handler
623
624     handle SIGQUIT signal
625
626 Parameters :
627     POSIX signal handler parameter list ("man sigaction" for details)
628
629     (no return value)
630 --*/
631 static void sigquit_handler(int code, siginfo_t *siginfo, void *context)
632 {
633     PROCNotifyProcessShutdown();
634
635     // Restore the original or default handler and resend signal
636     restore_signal(code, &g_previous_sigquit);
637     kill(gPID, code);
638 }
639 #endif // !HAVE_MACH_EXCEPTIONS
640
641 /*++
642 Function :
643     sigterm_handler
644
645     handle SIGTERM signal
646
647 Parameters :
648     POSIX signal handler parameter list ("man sigaction" for details)
649
650     (no return value)
651 --*/
652 static void sigterm_handler(int code, siginfo_t *siginfo, void *context)
653 {
654     if (PALIsInitialized())
655     {
656         // g_pSynchronizationManager shouldn't be null if PAL is initialized.
657         _ASSERTE(g_pSynchronizationManager != nullptr);
658
659         g_pSynchronizationManager->SendTerminationRequestToWorkerThread();
660     }
661     else
662     {
663         if (g_previous_sigterm.sa_sigaction != NULL)
664         {
665             g_previous_sigterm.sa_sigaction(code, siginfo, context);
666         }
667     }
668 }
669
670 #if !HAVE_MACH_EXCEPTIONS
671 #ifdef INJECT_ACTIVATION_SIGNAL
672 /*++
673 Function :
674     inject_activation_handler
675
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.
678
679 Parameters :
680     POSIX signal handler parameter list ("man sigaction" for details)
681
682 (no return value)
683 --*/
684 static void inject_activation_handler(int code, siginfo_t *siginfo, void *context)
685 {
686     // Only accept activations from the current process
687     if (g_activationFunction != NULL && siginfo->si_pid == getpid())
688     {
689         _ASSERTE(g_safeActivationCheckFunction != NULL);
690
691         native_context_t *ucontext = (native_context_t *)context;
692
693         CONTEXT winContext;
694         CONTEXTFromNativeContext(
695             ucontext, 
696             &winContext, 
697             CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT);
698
699         if (g_safeActivationCheckFunction(CONTEXTGetPC(&winContext), /* checkingCurrentThread */ TRUE))
700         {
701             g_activationFunction(&winContext);
702             // Activation function may have modified the context, so update it.
703             CONTEXTToNativeContext(&winContext, ucontext);
704         }
705     }
706     else if (g_previous_activation.sa_sigaction != NULL)
707     {
708         g_previous_activation.sa_sigaction(code, siginfo, context);
709     }
710 }
711 #endif
712
713 /*++
714 Function :
715     InjectActivationInternal
716
717     Interrupt the specified thread and have it call the activationFunction passed in
718
719 Parameters :
720     pThread            - target PAL thread
721     activationFunction - function to call 
722
723 (no return value)
724 --*/
725 PAL_ERROR InjectActivationInternal(CorUnix::CPalThread* pThread)
726 {
727 #ifdef INJECT_ACTIVATION_SIGNAL
728     int status = pthread_kill(pThread->GetPThreadSelf(), INJECT_ACTIVATION_SIGNAL);
729     if (status != 0)
730     {
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.
734         PROCAbort();
735     }
736
737     return NO_ERROR;
738 #else
739     return ERROR_CANCELLED;
740 #endif
741 }
742
743 /*++
744 Function :
745     signal_ignore_handler
746
747     Simple signal handler which does nothing
748
749 Parameters :
750     POSIX signal handler parameter list ("man sigaction" for details)
751
752 (no return value)
753 --*/
754 static void signal_ignore_handler(int code, siginfo_t *siginfo, void *context)
755 {
756 }
757
758
759 void PAL_IgnoreProfileSignal(int signalNum)
760 {
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
765     // test cases
766     //
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
770     // synchronization
771     //
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);
775 #endif
776 }
777
778
779 /*++
780 Function :
781     SEHSetSafeState
782
783     specify whether the current thread is in a state where exception handling 
784     of signals can be done safely
785
786 Parameters:
787     BOOL state : TRUE if the thread is safe, FALSE otherwise
788
789 (no return value)
790 --*/
791 void SEHSetSafeState(CPalThread *pthrCurrent, BOOL state)
792 {
793     if (NULL == pthrCurrent)
794     {
795         ASSERT( "Unable to get the thread object.\n" );
796         return;
797     }
798     pthrCurrent->sehInfo.safe_state = state;
799 }
800
801 /*++
802 Function :
803     SEHGetSafeState
804
805     determine whether the current thread is in a state where exception handling 
806     of signals can be done safely
807
808     (no parameters)
809
810 Return value :
811     TRUE if the thread is in a safe state, FALSE otherwise
812 --*/
813 BOOL SEHGetSafeState(CPalThread *pthrCurrent)
814 {
815     if (NULL == pthrCurrent)
816     {
817         ASSERT( "Unable to get the thread object.\n" );
818         return FALSE;
819     }
820     return pthrCurrent->sehInfo.safe_state;
821 }
822
823 /*++
824 Function :
825     common_signal_handler
826
827     common code for all signal handlers
828
829 Parameters :
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)
835
836     Returns true if the execution should continue or false if the exception was unhandled
837 Note:
838     the "pointers" parameter should contain a valid exception record pointer,
839     but the ContextRecord pointer will be overwritten.
840 --*/
841 __attribute__((noinline))
842 static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext, int numParams, ...)
843 {
844     sigset_t signal_set;
845     CONTEXT signalContextRecord;
846     EXCEPTION_RECORD exceptionRecord;
847     native_context_t *ucontext;
848
849     ucontext = (native_context_t *)sigcontext;
850     g_common_signal_handler_context_locvar_offset = (int)((char*)&signalContextRecord - (char*)__builtin_frame_address(0));
851
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;
857
858     va_list params;
859     va_start(params, numParams);
860
861     for (int i = 0; i < numParams; i++)
862     {
863         exceptionRecord.ExceptionInformation[i] = va_arg(params, size_t);
864     }
865
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);
869
870     ULONG contextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT;
871
872 #if defined(_AMD64_)
873     contextFlags |= CONTEXT_XSTATE;
874 #endif
875
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);
880
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);
885     if (sigmaskRet != 0)
886     {
887         ASSERT("pthread_sigmask failed; error number is %d\n", sigmaskRet);
888     }
889
890     signalContextRecord.ContextFlags |= CONTEXT_EXCEPTION_ACTIVE;
891
892     // The exception object takes ownership of the exceptionRecord and contextRecord
893     PAL_SEHException exception(&exceptionRecord, &signalContextRecord, true);
894
895     if (SEHProcessException(&exception))
896     {
897         // Exception handling may have modified the context, so update it.
898         CONTEXTToNativeContext(exception.ExceptionPointers.ContextRecord, ucontext);
899         return true;
900     }
901
902     return false;
903 }
904 #endif // !HAVE_MACH_EXCEPTIONS
905
906 /*++
907 Function :
908     handle_signal
909
910     register handler for specified signal
911
912 Parameters :
913     int signal_id : signal to handle
914     SIGFUNC sigfunc : signal handler
915     previousAction : previous sigaction struct
916
917     (no return value)
918     
919 note : if sigfunc is NULL, the default signal handler is restored    
920 --*/
921 void handle_signal(int signal_id, SIGFUNC sigfunc, struct sigaction *previousAction, int additionalFlags, bool skipIgnored)
922 {
923     struct sigaction newAction;
924
925     newAction.sa_flags = SA_RESTART | additionalFlags;
926 #if HAVE_SIGINFO_T
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);
934
935 #ifdef INJECT_ACTIVATION_SIGNAL
936     if ((additionalFlags & SA_ONSTACK) != 0)
937     {
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);
942     }
943 #endif
944
945     if (skipIgnored)
946     {
947         if (-1 == sigaction(signal_id, NULL, previousAction))
948         {
949             ASSERT("handle_signal: sigaction() call failed with error code %d (%s)\n",
950                 errno, strerror(errno));
951         }
952         else if (previousAction->sa_handler == SIG_IGN)
953         {
954             return;
955         }
956     }
957
958     if (-1 == sigaction(signal_id, &newAction, previousAction))
959     {
960         ASSERT("handle_signal: sigaction() call failed with error code %d (%s)\n",
961             errno, strerror(errno));
962     }
963 }
964
965 /*++
966 Function :
967     restore_signal
968
969     restore handler for specified signal
970
971 Parameters :
972     int signal_id : signal to handle
973     previousAction : previous sigaction struct to restore
974
975     (no return value)
976 --*/
977 void restore_signal(int signal_id, struct sigaction *previousAction)
978 {
979     if (-1 == sigaction(signal_id, previousAction, NULL))
980     {
981         ASSERT("restore_signal: sigaction() call failed with error code %d (%s)\n",
982             errno, strerror(errno));
983     }
984 }