}
func TestSignalForwardingExternal(t *testing.T) {
+ if GOOS == "freebsd" {
+ t.Skipf("skipping on %s/%s; signal always goes to the Go runtime", GOOS, GOARCH)
+ }
checkSignalForwardingTest(t)
defer func() {
}
const testar = `#!/usr/bin/env bash
-while expr $1 : '[-]' >/dev/null; do
+while [[ $1 == -* ]] >/dev/null; do
shift
done
echo "testar" > $1
printf("write(2) unexpectedly succeeded\n");
return 0;
}
+ printf("did not receieve SIGPIPE\n");
+ return 0;
}
default:
printf("Unknown test: %d\n", test);
createHeadersOnce(t)
- runCC(t, "-o", cmd, "main1.c", "-ldl")
+ if GOOS != "freebsd" {
+ runCC(t, "-o", cmd, "main1.c", "-ldl")
+ } else {
+ runCC(t, "-o", cmd, "main1.c")
+ }
adbPush(t, cmd)
defer os.Remove(bin)
"-o", libname, pkgname,
)
adbPush(t, libname)
- runCC(t, "-pthread", "-o", cmd, cfile, "-ldl")
+ if GOOS != "freebsd" {
+ runCC(t, "-pthread", "-o", cmd, cfile, "-ldl")
+ } else {
+ runCC(t, "-pthread", "-o", cmd, cfile)
+ }
adbPush(t, cmd)
bin := cmdToRun(cmd)
switch pair {
case "darwin-386", "darwin-amd64", "darwin-arm", "darwin-arm64",
"linux-amd64", "linux-386", "linux-ppc64le", "linux-s390x",
+ "freebsd-amd64",
"windows-amd64", "windows-386":
return true
}
switch pair {
case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x",
"darwin-amd64", "darwin-386",
+ "freebsd-amd64",
"android-arm", "android-arm64", "android-386",
"windows-amd64", "windows-386":
return true
} else {
switch platform {
case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/ppc64le", "linux/s390x",
- "android/amd64", "android/arm", "android/arm64", "android/386":
+ "android/amd64", "android/arm", "android/arm64", "android/386",
+ "freebsd/amd64":
codegenArg = "-shared"
case "darwin/amd64", "darwin/386":
case "windows/amd64", "windows/386":
log.Fatalf("unknown TLS base location for %v", ctxt.Headtype)
case objabi.Hlinux,
- objabi.Hnacl:
+ objabi.Hnacl, objabi.Hfreebsd:
if ctxt.Flag_shared {
// Note that this is not generating the same insns as the other cases.
// MOV TLS, dst
default:
log.Fatalf("unknown TLS base location for %v", ctxt.Headtype)
- case objabi.Hlinux:
+ case objabi.Hlinux, objabi.Hfreebsd:
if !ctxt.Flag_shared {
- log.Fatalf("unknown TLS base location for linux without -shared")
+ log.Fatalf("unknown TLS base location for linux/freebsd without -shared")
}
// Note that this is not generating the same insn as the other cases.
// MOV TLS, R_to
switch ctxt.Headtype {
case objabi.Hplan9, objabi.Hwindows:
return false
- case objabi.Hlinux:
+ case objabi.Hlinux, objabi.Hfreebsd:
return !ctxt.Flag_shared
}
case "c-archive":
switch objabi.GOOS {
case "darwin", "linux":
+ case "freebsd":
+ switch objabi.GOARCH {
+ case "amd64":
+ default:
+ return badmode()
+ }
case "windows":
switch objabi.GOARCH {
case "amd64", "386":
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !android,linux
+// +build !android,linux freebsd
#include <stdarg.h>
#include <stdio.h>
// license that can be found in the LICENSE file.
#include <sys/types.h>
+#include <errno.h>
#include <sys/signalvar.h>
#include <pthread.h>
#include <signal.h>
void
x_cgo_init(G *g, void (*setg)(void*))
{
- pthread_attr_t attr;
+ pthread_attr_t *attr;
size_t size;
+ // Deal with memory sanitizer/clang interaction.
+ // See gcc_linux_amd64.c for details.
setg_gcc = setg;
- pthread_attr_init(&attr);
- pthread_attr_getstacksize(&attr, &size);
+ attr = (pthread_attr_t*)malloc(sizeof *attr);
+ if (attr == NULL) {
+ fatalf("malloc failed: %s", strerror(errno));
+ }
+ pthread_attr_init(attr);
+ pthread_attr_getstacksize(attr, &size);
g->stacklo = (uintptr)&attr - size + 4096;
- pthread_attr_destroy(&attr);
+ pthread_attr_destroy(attr);
+ free(attr);
}
void
pthread_attr_init(&attr);
pthread_attr_getstacksize(&attr, &size);
-
// Leave stacklo=0 and set stackhi=size; mstart will do the rest.
ts->g->stackhi = size;
err = _cgo_try_pthread_create(&p, &attr, threadentry, ts);
pthread_sigmask(SIG_SETMASK, &oset, nil);
if (err != 0) {
- fprintf(stderr, "runtime/cgo: pthread_create failed: %s\n", strerror(err));
- abort();
+ fatalf("pthread_create failed: %s", strerror(err));
}
}
ThreadStart ts;
ts = *(ThreadStart*)v;
+ _cgo_tsan_acquire();
free(v);
+ _cgo_tsan_release();
/*
* Set specific keys.
--- /dev/null
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build freebsd,amd64
+
+#include <errno.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+#include <signal.h>
+
+#include "libcgo.h"
+
+// go_sigaction_t is a C version of the sigactiont struct from
+// os_freebsd.go. This definition — and its conversion to and from struct
+// sigaction — are specific to freebsd/amd64.
+typedef struct {
+ uint32_t __bits[_SIG_WORDS];
+} go_sigset_t;
+typedef struct {
+ uintptr_t handler;
+ int32_t flags;
+ go_sigset_t mask;
+} go_sigaction_t;
+
+int32_t
+x_cgo_sigaction(intptr_t signum, const go_sigaction_t *goact, go_sigaction_t *oldgoact) {
+ int32_t ret;
+ struct sigaction act;
+ struct sigaction oldact;
+ int i;
+
+ _cgo_tsan_acquire();
+
+ memset(&act, 0, sizeof act);
+ memset(&oldact, 0, sizeof oldact);
+
+ if (goact) {
+ if (goact->flags & SA_SIGINFO) {
+ act.sa_sigaction = (void(*)(int, siginfo_t*, void*))(goact->handler);
+ } else {
+ act.sa_handler = (void(*)(int))(goact->handler);
+ }
+ sigemptyset(&act.sa_mask);
+ for (i = 0; i < 8 * sizeof(goact->mask); i++) {
+ if (goact->mask.__bits[i/32] & ((uint32_t)(1)<<(i&31))) {
+ sigaddset(&act.sa_mask, i+1);
+ }
+ }
+ act.sa_flags = goact->flags;
+ }
+
+ ret = sigaction(signum, goact ? &act : NULL, oldgoact ? &oldact : NULL);
+ if (ret == -1) {
+ // runtime.sigaction expects _cgo_sigaction to return errno on error.
+ _cgo_tsan_release();
+ return errno;
+ }
+
+ if (oldgoact) {
+ if (oldact.sa_flags & SA_SIGINFO) {
+ oldgoact->handler = (uintptr_t)(oldact.sa_sigaction);
+ } else {
+ oldgoact->handler = (uintptr_t)(oldact.sa_handler);
+ }
+ for (i = 0 ; i < _SIG_WORDS; i++) {
+ oldgoact->mask.__bits[i] = 0;
+ }
+ for (i = 0; i < 8 * sizeof(oldgoact->mask); i++) {
+ if (sigismember(&oldact.sa_mask, i+1) == 1) {
+ oldgoact->mask.__bits[i/32] |= (uint32_t)(1)<<(i&31);
+ }
+ }
+ oldgoact->flags = oldact.sa_flags;
+ }
+
+ _cgo_tsan_release();
+ return ret;
+}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build linux,amd64
+// +build linux,amd64 freebsd,amd64
package cgo
// Support for memory sanitizer. See runtime/cgo/sigaction.go.
-// +build linux,amd64
+// +build linux,amd64 freebsd,amd64
package runtime
type mOS struct{}
//go:noescape
-func thr_new(param *thrparam, size int32)
+func thr_new(param *thrparam, size int32) int32
//go:noescape
func sigaltstack(new, old *stackt)
-//go:noescape
-func sigaction(sig uint32, new, old *sigactiont)
-
//go:noescape
func sigprocmask(how int32, new, old *sigset)
print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " thr_start=", funcPC(thr_start), " id=", mp.id, " ostk=", &mp, "\n")
}
- // NOTE(rsc): This code is confused. stackbase is the top of the stack
- // and is equal to stk. However, it's working, so I'm not changing it.
param := thrparam{
start_func: funcPC(thr_start),
arg: unsafe.Pointer(mp),
- stack_base: mp.g0.stack.hi,
- stack_size: uintptr(stk) - mp.g0.stack.hi,
+ stack_base: mp.g0.stack.lo,
+ stack_size: uintptr(stk) - mp.g0.stack.lo,
child_tid: unsafe.Pointer(&mp.procid),
parent_tid: nil,
tls_base: unsafe.Pointer(&mp.tls[0]),
var oset sigset
sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
// TODO: Check for error.
- thr_new(¶m, int32(unsafe.Sizeof(param)))
+ ret := thr_new(¶m, int32(unsafe.Sizeof(param)))
+ sigprocmask(_SIG_SETMASK, &oset, nil)
+ if ret < 0 {
+ print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", -ret, ")\n")
+ throw("newosproc")
+ }
+}
+
+// Version of newosproc that doesn't require a valid G.
+//go:nosplit
+func newosproc0(stacksize uintptr, fn unsafe.Pointer) {
+ stack := sysAlloc(stacksize, &memstats.stacks_sys)
+ if stack == nil {
+ write(2, unsafe.Pointer(&failallocatestack[0]), int32(len(failallocatestack)))
+ exit(1)
+ }
+ // This code "knows" it's being called once from the library
+ // initialization code, and so it's using the static m0 for the
+ // tls and procid (thread) pointers. thr_new() requires the tls
+ // pointers, though the tid pointers can be nil.
+ // However, newosproc0 is currently unreachable because builds
+ // utilizing c-shared/c-archive force external linking.
+ param := thrparam{
+ start_func: funcPC(fn),
+ arg: nil,
+ stack_base: uintptr(stack), //+stacksize?
+ stack_size: stacksize,
+ child_tid: unsafe.Pointer(&m0.procid),
+ parent_tid: nil,
+ tls_base: unsafe.Pointer(&m0.tls[0]),
+ tls_size: unsafe.Sizeof(m0.tls),
+ }
+
+ var oset sigset
+ sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
+ ret := thr_new(¶m, int32(unsafe.Sizeof(param)))
sigprocmask(_SIG_SETMASK, &oset, nil)
+ if ret < 0 {
+ write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
+ exit(1)
+ }
+}
+
+var failallocatestack = []byte("runtime: failed to allocate stack for the new OS thread\n")
+var failthreadcreate = []byte("runtime: failed to create new OS thread\n")
+
+// Called to do synchronous initialization of Go code built with
+// -buildmode=c-archive or -buildmode=c-shared.
+// None of the Go runtime is initialized.
+//go:nosplit
+//go:nowritebarrierrec
+func libpreinit() {
+ initsig(true)
}
func osinit() {
sa_mask sigset
}
+// See os_freebsd2.go, os_freebsd_amd64.go for setsig function
+
//go:nosplit
//go:nowritebarrierrec
-func setsig(i uint32, fn uintptr) {
+func setsigstack(i uint32) {
var sa sigactiont
- sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
- sa.sa_mask = sigset_all
- if fn == funcPC(sighandler) {
- fn = funcPC(sigtramp)
+ sigaction(i, nil, &sa)
+ if sa.sa_flags&_SA_ONSTACK != 0 {
+ return
}
- sa.sa_handler = fn
+ sa.sa_flags |= _SA_ONSTACK
sigaction(i, &sa, nil)
}
-//go:nosplit
-//go:nowritebarrierrec
-func setsigstack(i uint32) {
- throw("setsigstack")
-}
-
//go:nosplit
//go:nowritebarrierrec
func getsig(i uint32) uintptr {
archauxv(tag, val)
}
}
+
+// sysSigaction calls the sigaction system call.
+//go:nosplit
+func sysSigaction(sig uint32, new, old *sigactiont) {
+ // Use system stack to avoid split stack overflow on amd64
+ if asmSigaction(uintptr(sig), new, old) != 0 {
+ systemstack(func() {
+ throw("sigaction failed")
+ })
+ }
+}
+
+// asmSigaction is implemented in assembly.
+//go:noescape
+func asmSigaction(sig uintptr, new, old *sigactiont) int32
--- /dev/null
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build freebsd,!amd64
+
+package runtime
+
+//go:nosplit
+//go:nowritebarrierrec
+func setsig(i uint32, fn uintptr) {
+ var sa sigactiont
+ sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
+ sa.sa_mask = sigset_all
+ if fn == funcPC(sighandler) {
+ fn = funcPC(sigtramp)
+ }
+ sa.sa_handler = fn
+ sigaction(i, &sa, nil)
+}
--- /dev/null
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package runtime
+
+func cgoSigtramp()
+
+//go:nosplit
+//go:nowritebarrierrec
+func setsig(i uint32, fn uintptr) {
+ var sa sigactiont
+ sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
+ sa.sa_mask = sigset_all
+ if fn == funcPC(sighandler) {
+ if iscgo {
+ fn = funcPC(cgoSigtramp)
+ } else {
+ fn = funcPC(sigtramp)
+ }
+ }
+ sa.sa_handler = fn
+ sigaction(i, &sa, nil)
+}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build !amd64
+// +build linux,!amd64 freebsd,!amd64
package runtime
-// This version is used on Linux systems on which we don't use cgo to
-// call the C version of sigaction.
+// This version is used on Linux and FreeBSD systems on which we don't
+// use cgo to call the C version of sigaction.
//go:nosplit
//go:nowritebarrierrec
// re-installing sighandler. At this point we can just
// return and the signal will be re-raised and caught by
// the default handler with the correct context.
- if (isarchive || islibrary) && handler == _SIG_DFL && c.sigcode() != _SI_USER {
+ //
+ // On FreeBSD, the libthr sigaction code prevents
+ // this from working so we fall through to raise.
+ if GOOS != "freebsd" && (isarchive || islibrary) && handler == _SIG_DFL && c.sigcode() != _SI_USER {
return
}
TEXT runtime·thr_new(SB),NOSPLIT,$-4
MOVL $455, AX
INT $0x80
+ MOVL AX, ret+8(FP)
RET
TEXT runtime·thr_start(SB),NOSPLIT,$0
RET
-TEXT runtime·sigaction(SB),NOSPLIT,$-4
+TEXT runtime·asmSigaction(SB),NOSPLIT,$-4
MOVL $416, AX
INT $0x80
- JAE 2(PC)
- MOVL $0xf1, 0xf1 // crash
+ MOVL AX, ret+12(FP)
RET
TEXT runtime·sigfwd(SB),NOSPLIT,$12-16
MOVL size+8(FP), SI
MOVL $455, AX
SYSCALL
+ MOVL AX, ret+16(FP)
RET
TEXT runtime·thr_start(SB),NOSPLIT,$0
MOVQ AX, ret+0(FP)
RET
-TEXT runtime·sigaction(SB),NOSPLIT,$-8
- MOVL sig+0(FP), DI // arg 1 sig
+TEXT runtime·asmSigaction(SB),NOSPLIT,$0
+ MOVQ sig+0(FP), DI // arg 1 sig
MOVQ new+8(FP), SI // arg 2 act
MOVQ old+16(FP), DX // arg 3 oact
MOVL $416, AX
SYSCALL
JCC 2(PC)
- MOVL $0xf1, 0xf1 // crash
+ MOVL $-1, AX
+ MOVL AX, ret+24(FP)
+ RET
+
+TEXT runtime·callCgoSigaction(SB),NOSPLIT,$16
+ MOVQ sig+0(FP), DI // arg 1 sig
+ MOVQ new+8(FP), SI // arg 2 act
+ MOVQ old+16(FP), DX // arg 3 oact
+ MOVQ _cgo_sigaction(SB), AX
+ MOVQ SP, BX // callee-saved
+ ANDQ $~15, SP // alignment as per amd64 psABI
+ CALL AX
+ MOVQ BX, SP
+ MOVL AX, ret+24(FP)
RET
TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
MOVQ bx-8(SP), BX
RET
+// Used instead of sigtramp in programs that use cgo.
+// Arguments from kernel are in DI, SI, DX.
+TEXT runtime·cgoSigtramp(SB),NOSPLIT,$0
+ // If no traceback function, do usual sigtramp.
+ MOVQ runtime·cgoTraceback(SB), AX
+ TESTQ AX, AX
+ JZ sigtramp
+
+ // If no traceback support function, which means that
+ // runtime/cgo was not linked in, do usual sigtramp.
+ MOVQ _cgo_callers(SB), AX
+ TESTQ AX, AX
+ JZ sigtramp
+
+ // Figure out if we are currently in a cgo call.
+ // If not, just do usual sigtramp.
+ get_tls(CX)
+ MOVQ g(CX),AX
+ TESTQ AX, AX
+ JZ sigtrampnog // g == nil
+ MOVQ g_m(AX), AX
+ TESTQ AX, AX
+ JZ sigtramp // g.m == nil
+ MOVL m_ncgo(AX), CX
+ TESTL CX, CX
+ JZ sigtramp // g.m.ncgo == 0
+ MOVQ m_curg(AX), CX
+ TESTQ CX, CX
+ JZ sigtramp // g.m.curg == nil
+ MOVQ g_syscallsp(CX), CX
+ TESTQ CX, CX
+ JZ sigtramp // g.m.curg.syscallsp == 0
+ MOVQ m_cgoCallers(AX), R8
+ TESTQ R8, R8
+ JZ sigtramp // g.m.cgoCallers == nil
+ MOVL m_cgoCallersUse(AX), CX
+ TESTL CX, CX
+ JNZ sigtramp // g.m.cgoCallersUse != 0
+
+ // Jump to a function in runtime/cgo.
+ // That function, written in C, will call the user's traceback
+ // function with proper unwind info, and will then call back here.
+ // The first three arguments, and the fifth, are already in registers.
+ // Set the two remaining arguments now.
+ MOVQ runtime·cgoTraceback(SB), CX
+ MOVQ $runtime·sigtramp(SB), R9
+ MOVQ _cgo_callers(SB), AX
+ JMP AX
+
+sigtramp:
+ JMP runtime·sigtramp(SB)
+
+sigtrampnog:
+ // Signal arrived on a non-Go thread. If this is SIGPROF, get a
+ // stack trace.
+ CMPL DI, $27 // 27 == SIGPROF
+ JNZ sigtramp
+
+ // Lock sigprofCallersUse.
+ MOVL $0, AX
+ MOVL $1, CX
+ MOVQ $runtime·sigprofCallersUse(SB), R11
+ LOCK
+ CMPXCHGL CX, 0(R11)
+ JNZ sigtramp // Skip stack trace if already locked.
+
+ // Jump to the traceback function in runtime/cgo.
+ // It will call back to sigprofNonGo, which will ignore the
+ // arguments passed in registers.
+ // First three arguments to traceback function are in registers already.
+ MOVQ runtime·cgoTraceback(SB), CX
+ MOVQ $runtime·sigprofCallers(SB), R8
+ MOVQ $runtime·sigprofNonGo(SB), R9
+ MOVQ _cgo_callers(SB), AX
+ JMP AX
+
TEXT runtime·mmap(SB),NOSPLIT,$0
MOVQ addr+0(FP), DI // arg 1 addr
MOVQ n+8(FP), SI // arg 2 len
MOVW size+4(FP), R1
MOVW $SYS_thr_new, R7
SWI $0
+ MOVW R0, ret+8(FP)
RET
TEXT runtime·thr_start(SB),NOSPLIT,$0
MOVW R1, ret_hi+4(FP)
RET
-TEXT runtime·sigaction(SB),NOSPLIT|NOFRAME,$0
+TEXT runtime·asmSigaction(SB),NOSPLIT|NOFRAME,$0
MOVW sig+0(FP), R0 // arg 1 sig
MOVW new+4(FP), R1 // arg 2 act
MOVW old+8(FP), R2 // arg 3 oact
MOVW $SYS_sigaction, R7
SWI $0
- MOVW.CS $0, R8 // crash on syscall failure
- MOVW.CS R8, (R8)
+ MOVW.CS $-1, R0
+ MOVW R0, ret+12(FP)
RET
TEXT runtime·sigtramp(SB),NOSPLIT,$12