]> Cypherpunks repositories - gostls13.git/commitdiff
all: enable c-shared/c-archive support for freebsd/amd64
authorTim Wright <tenortim@gmail.com>
Wed, 14 Feb 2018 03:00:17 +0000 (19:00 -0800)
committerIan Lance Taylor <iant@golang.org>
Wed, 21 Mar 2018 21:56:20 +0000 (21:56 +0000)
Fixes #14327
Much of the code is based on the linux/amd64 code that implements these
build modes, and code is shared where possible.

Change-Id: Ia510f2023768c0edbc863aebc585929ec593b332
Reviewed-on: https://go-review.googlesource.com/93875
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
21 files changed:
misc/cgo/testcarchive/carchive_test.go
misc/cgo/testcarchive/main5.c
misc/cgo/testcshared/cshared_test.go
src/cmd/dist/test.go
src/cmd/go/internal/work/init.go
src/cmd/internal/obj/x86/asm6.go
src/cmd/internal/obj/x86/obj6.go
src/cmd/link/internal/ld/config.go
src/runtime/cgo/gcc_fatalf.c
src/runtime/cgo/gcc_freebsd_amd64.c
src/runtime/cgo/gcc_freebsd_sigaction.c [new file with mode: 0644]
src/runtime/cgo/sigaction.go
src/runtime/cgo_sigaction.go
src/runtime/os_freebsd.go
src/runtime/os_freebsd2.go [new file with mode: 0644]
src/runtime/os_freebsd_amd64.go [new file with mode: 0644]
src/runtime/sigaction.go [moved from src/runtime/sigaction_linux.go with 65% similarity]
src/runtime/signal_unix.go
src/runtime/sys_freebsd_386.s
src/runtime/sys_freebsd_amd64.s
src/runtime/sys_freebsd_arm.s

index 79633659da6c01c94927d29bfc626c60e70e9ebd..06e74fa2fee26ce0ac0230334ea281e79430136d 100644 (file)
@@ -260,6 +260,9 @@ func TestSignalForwarding(t *testing.T) {
 }
 
 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() {
@@ -433,7 +436,7 @@ func TestSigaltstack(t *testing.T) {
 }
 
 const testar = `#!/usr/bin/env bash
-while expr $1 : '[-]' >/dev/null; do
+while [[ $1 == -* ]] >/dev/null; do
   shift
 done
 echo "testar" > $1
index 2437bf07c58f8f530bf42e5b6dac9396fdf26b34..897b70d2fa6d5f1919e41e275f586adf60ae991d 100644 (file)
@@ -85,6 +85,8 @@ int main(int argc, char** argv) {
                                printf("write(2) unexpectedly succeeded\n");
                                return 0;
                        }
+                       printf("did not receieve SIGPIPE\n");
+                       return 0;
                }
                default:
                        printf("Unknown test: %d\n", test);
index e43422de6e6a599e2dbbaf0ef04b8e0dc7f153f3..77cefc5a66a368278f70315f6a5be4b63ea6be37 100644 (file)
@@ -322,7 +322,11 @@ func TestExportedSymbolsWithDynamicLoad(t *testing.T) {
 
        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)
@@ -411,7 +415,11 @@ func testSignalHandlers(t *testing.T, pkgname, cfile, cmd string) {
                "-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)
index fe9dcc216ee571909f7dc7cdf6ff3ee8dcd3ca23..1c1d8b6ffbd490e1347e51ae7aa72aec200a6093 100644 (file)
@@ -912,6 +912,7 @@ func (t *tester) supportedBuildmode(mode string) bool {
                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
                }
@@ -920,6 +921,7 @@ func (t *tester) supportedBuildmode(mode string) bool {
                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
index 7f894f5c6dce20c2019044fea34505ebe1ceb877..527e81103e1035e3a574c445557d63ea093f9a11 100644 (file)
@@ -98,7 +98,8 @@ func buildModeInit() {
                } 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":
index 0fbc552ddab492d4a3fd339e9c677aa05009e6ce..783252a551ca3544c0a0bd883488c92a9e932cad 100644 (file)
@@ -4615,7 +4615,7 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
                                                        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
@@ -4687,9 +4687,9 @@ func (asmbuf *AsmBuf) doasm(ctxt *obj.Link, cursym *obj.LSym, p *obj.Prog) {
                                        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
index 7c17514e869006a97d7065f8e8f69f42234701ec..2ff92ccca4aadc85ca5ed65540a987b242edea9a 100644 (file)
@@ -64,7 +64,7 @@ func CanUse1InsnTLS(ctxt *obj.Link) bool {
        switch ctxt.Headtype {
        case objabi.Hplan9, objabi.Hwindows:
                return false
-       case objabi.Hlinux:
+       case objabi.Hlinux, objabi.Hfreebsd:
                return !ctxt.Flag_shared
        }
 
index cc95392d772e767670dfe5a1e349d3c37131ea41..302dabecb7873f023b4017923808e9cdc78666e8 100644 (file)
@@ -52,6 +52,12 @@ func (mode *BuildMode) Set(s string) error {
        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":
index 5ac419b412084de1a04ac856e0ec779a5beba305..fdcf6f5e52460b8f78a430e18d8df62bb7cc8b00 100644 (file)
@@ -2,7 +2,7 @@
 // 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>
index d25db91900071aea15e9ceaa4c46a245f73bbb43..514a2f8a235ee78c2c1f2e5e75e9ecc01ea49eac 100644 (file)
@@ -3,6 +3,7 @@
 // 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>
@@ -16,14 +17,21 @@ static void (*setg_gcc)(void*);
 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
@@ -40,7 +48,6 @@ _cgo_sys_thread_start(ThreadStart *ts)
 
        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);
@@ -48,8 +55,7 @@ _cgo_sys_thread_start(ThreadStart *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));
        }
 }
 
@@ -59,7 +65,9 @@ threadentry(void *v)
        ThreadStart ts;
 
        ts = *(ThreadStart*)v;
+       _cgo_tsan_acquire();
        free(v);
+       _cgo_tsan_release();
 
        /*
         * Set specific keys.
diff --git a/src/runtime/cgo/gcc_freebsd_sigaction.c b/src/runtime/cgo/gcc_freebsd_sigaction.c
new file mode 100644 (file)
index 0000000..d1bf3c0
--- /dev/null
@@ -0,0 +1,80 @@
+// 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;
+}
index 30d3f14c14122a464507fe40e10cb43a7a7e3388..e25f4ff2f3e340886340359e1d05493579423782 100644 (file)
@@ -2,7 +2,7 @@
 // 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
 
index 0908f863a49439b342b9d528a7fae8ba4e55bc16..9832d35f03b6d1fc88f372511b12b2bfda4d949c 100644 (file)
@@ -4,7 +4,7 @@
 
 // Support for memory sanitizer. See runtime/cgo/sigaction.go.
 
-// +build linux,amd64
+// +build linux,amd64 freebsd,amd64
 
 package runtime
 
index 230da3e755cf179914a28629dbb824cd3baebdda..b09dc0443389d90420d341b07e9aeadd07da50c8 100644 (file)
@@ -12,14 +12,11 @@ import (
 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)
 
@@ -185,13 +182,11 @@ func newosproc(mp *m, stk unsafe.Pointer) {
                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]),
@@ -201,8 +196,59 @@ func newosproc(mp *m, stk unsafe.Pointer) {
        var oset sigset
        sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
        // TODO: Check for error.
-       thr_new(&param, int32(unsafe.Sizeof(param)))
+       ret := thr_new(&param, 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(&param, 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() {
@@ -274,25 +320,20 @@ type sigactiont struct {
        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 {
@@ -354,3 +395,18 @@ func sysauxv(auxv []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
diff --git a/src/runtime/os_freebsd2.go b/src/runtime/os_freebsd2.go
new file mode 100644 (file)
index 0000000..6947a05
--- /dev/null
@@ -0,0 +1,20 @@
+// 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)
+}
diff --git a/src/runtime/os_freebsd_amd64.go b/src/runtime/os_freebsd_amd64.go
new file mode 100644 (file)
index 0000000..dc0bb9f
--- /dev/null
@@ -0,0 +1,24 @@
+// 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)
+}
similarity index 65%
rename from src/runtime/sigaction_linux.go
rename to src/runtime/sigaction.go
index 4775f6412393efa1f0af7e5a924d2d663f02ec78..eb454f9327074d9024a942c94681299a1db6e9e5 100644 (file)
@@ -2,12 +2,12 @@
 // 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
index 78649c52a9fbf312547ab8bbaa5b28b7c8ac9125..d87f1bed16929ec0b9538cc04adc80ad224e95d4 100644 (file)
@@ -484,7 +484,10 @@ func raisebadsignal(sig uint32, c *sigctxt) {
        // 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
        }
 
index 94b2357c624b21dcad8d405ceb5bf77943280ad5..dba2f206dbfebb90a446b1bba0df4e34e0aa4ff2 100644 (file)
@@ -19,6 +19,7 @@ TEXT runtime·sys_umtx_op(SB),NOSPLIT,$-4
 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
@@ -211,11 +212,10 @@ TEXT runtime·nanotime(SB), NOSPLIT, $32
        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
index c2c71784dd610dce6a320eee22ce42d04d1b7483..4d3e88b482005a843c15a9dfda313b35d7fc39b0 100644 (file)
@@ -26,6 +26,7 @@ TEXT runtime·thr_new(SB),NOSPLIT,$0
        MOVL size+8(FP), SI
        MOVL $455, AX
        SYSCALL
+       MOVL    AX, ret+16(FP)
        RET
 
 TEXT runtime·thr_start(SB),NOSPLIT,$0
@@ -169,14 +170,27 @@ TEXT runtime·nanotime(SB), NOSPLIT, $32
        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
@@ -216,6 +230,82 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$72
        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
index d0b1e96a1acc5e2507c1605ccf3d82df782a04cc..1a76f1767f531078c7d5a07c229b11dbff81abbc 100644 (file)
@@ -59,6 +59,7 @@ TEXT runtime·thr_new(SB),NOSPLIT,$0
        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
@@ -207,14 +208,14 @@ TEXT runtime·nanotime(SB), NOSPLIT, $32
        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