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