1// Copyright 2016 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
6
7package runtime
8
9import (
10	"unsafe"
11)
12
13// Functions for gccgo to support signal handling. In the gc runtime
14// these are written in OS-specific files and in assembler.
15
16//go:noescape
17//extern sigaction
18func sigaction(signum uint32, act *_sigaction, oact *_sigaction) int32
19
20//go:noescape
21//extern sigprocmask
22func sigprocmask(how int32, set *sigset, oldset *sigset) int32
23
24//go:noescape
25//extern sigfillset
26func sigfillset(set *sigset) int32
27
28//go:noescape
29//extern sigemptyset
30func sigemptyset(set *sigset) int32
31
32//go:noescape
33//extern sigaddset
34func c_sigaddset(set *sigset, signum uint32) int32
35
36//go:noescape
37//extern sigdelset
38func c_sigdelset(set *sigset, signum uint32) int32
39
40//go:noescape
41//extern sigaltstack
42func sigaltstack(ss *_stack_t, oss *_stack_t) int32
43
44//extern raise
45func raise(sig uint32) int32
46
47//extern getpid
48func getpid() _pid_t
49
50//extern kill
51func kill(pid _pid_t, sig uint32) int32
52
53//go:noescape
54//extern setitimer
55func setitimer(which int32, new *_itimerval, old *_itimerval) int32
56
57type sigctxt struct {
58	info *_siginfo_t
59	ctxt unsafe.Pointer
60}
61
62func (c *sigctxt) sigcode() uint64 {
63	if c.info == nil {
64		// This can happen on Solaris 10.  We don't know the
65		// code, just avoid a misleading value.
66		return _SI_USER + 1
67	}
68	return uint64(c.info.si_code)
69}
70
71//go:nosplit
72//go:nowritebarrierrec
73func setsig(i uint32, fn uintptr) {
74	var sa _sigaction
75	sa.sa_flags = _SA_SIGINFO | _SA_RESTART
76
77	// For gccgo we do not set SA_ONSTACK for a signal that can
78	// cause a panic.  Instead, we trust that the split stack has
79	// enough room to start the signal handler.  This is because
80	// otherwise we have no good way to switch back to the
81	// original stack before panicing.
82	if sigtable[i].flags&_SigPanic == 0 {
83		sa.sa_flags |= _SA_ONSTACK
84	}
85
86	sigfillset((*sigset)(unsafe.Pointer(&sa.sa_mask)))
87	setSigactionHandler(&sa, fn)
88	sigaction(i, &sa, nil)
89}
90
91//go:nosplit
92//go:nowritebarrierrec
93func setsigstack(i uint32) {
94	var sa _sigaction
95	sigaction(i, nil, &sa)
96	handler := getSigactionHandler(&sa)
97	if handler == 0 || handler == _SIG_DFL || handler == _SIG_IGN || sa.sa_flags&_SA_ONSTACK != 0 {
98		return
99	}
100	if sigtable[i].flags&_SigPanic != 0 {
101		return
102	}
103	sa.sa_flags |= _SA_ONSTACK
104	sigaction(i, &sa, nil)
105}
106
107//go:nosplit
108//go:nowritebarrierrec
109func getsig(i uint32) uintptr {
110	var sa _sigaction
111	if sigaction(i, nil, &sa) < 0 {
112		// On GNU/Linux glibc rejects attempts to call
113		// sigaction with signal 32 (SIGCANCEL) or 33 (SIGSETXID).
114		if GOOS == "linux" && (i == 32 || i == 33) {
115			return _SIG_DFL
116		}
117		throw("sigaction read failure")
118	}
119	return getSigactionHandler(&sa)
120}
121
122func signalstack(p unsafe.Pointer, n uintptr)
123
124//go:nosplit
125//go:nowritebarrierrec
126func raiseproc(sig uint32) {
127	kill(getpid(), sig)
128}
129
130//go:nosplit
131//go:nowritebarrierrec
132func sigfwd(fn uintptr, sig uint32, info *_siginfo_t, ctx unsafe.Pointer) {
133	f1 := [1]uintptr{fn}
134	f2 := &f1
135	f3 := *(*func(uint32, *_siginfo_t, unsafe.Pointer))(unsafe.Pointer(&f2))
136	f3(sig, info, ctx)
137}
138
139//go:nosplit
140//go:nowritebarrierrec
141func sigaddset(mask *sigset, i int) {
142	c_sigaddset(mask, uint32(i))
143}
144
145func sigdelset(mask *sigset, i int) {
146	c_sigdelset(mask, uint32(i))
147}
148