runtime: scan register backing store on ia64
[official-gcc.git] / libgo / go / runtime / crash_unix_test.go
blob584a6c742323d2453399ec690a98e1dff53d3d8c
1 // Copyright 2012 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.
5 // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
7 package runtime_test
9 import (
10 "bytes"
11 "internal/testenv"
12 "io"
13 "io/ioutil"
14 "os"
15 "os/exec"
16 "path/filepath"
17 "runtime"
18 "strings"
19 "syscall"
20 "testing"
23 // sigquit is the signal to send to kill a hanging testdata program.
24 // Send SIGQUIT to get a stack trace.
25 var sigquit = syscall.SIGQUIT
27 func init() {
28 if runtime.Sigisblocked(int(syscall.SIGQUIT)) {
29 // We can't use SIGQUIT to kill subprocesses because
30 // it's blocked. Use SIGKILL instead. See issue
31 // #19196 for an example of when this happens.
32 sigquit = syscall.SIGKILL
36 func TestCrashDumpsAllThreads(t *testing.T) {
37 switch runtime.GOOS {
38 case "darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
39 default:
40 t.Skipf("skipping; not supported on %v", runtime.GOOS)
43 if runtime.Sigisblocked(int(syscall.SIGQUIT)) {
44 t.Skip("skipping; SIGQUIT is blocked, see golang.org/issue/19196")
47 // We don't use executeTest because we need to kill the
48 // program while it is running.
50 testenv.MustHaveGoBuild(t)
52 checkStaleRuntime(t)
54 t.Parallel()
56 dir, err := ioutil.TempDir("", "go-build")
57 if err != nil {
58 t.Fatalf("failed to create temp directory: %v", err)
60 defer os.RemoveAll(dir)
62 if err := ioutil.WriteFile(filepath.Join(dir, "main.go"), []byte(crashDumpsAllThreadsSource), 0666); err != nil {
63 t.Fatalf("failed to create Go file: %v", err)
66 cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", "a.exe")
67 cmd.Dir = dir
68 out, err := testenv.CleanCmdEnv(cmd).CombinedOutput()
69 if err != nil {
70 t.Fatalf("building source: %v\n%s", err, out)
73 cmd = exec.Command(filepath.Join(dir, "a.exe"))
74 cmd = testenv.CleanCmdEnv(cmd)
75 cmd.Env = append(cmd.Env, "GOTRACEBACK=crash")
77 // Set GOGC=off. Because of golang.org/issue/10958, the tight
78 // loops in the test program are not preemptible. If GC kicks
79 // in, it may lock up and prevent main from saying it's ready.
80 newEnv := []string{}
81 for _, s := range cmd.Env {
82 if !strings.HasPrefix(s, "GOGC=") {
83 newEnv = append(newEnv, s)
86 cmd.Env = append(newEnv, "GOGC=off")
88 var outbuf bytes.Buffer
89 cmd.Stdout = &outbuf
90 cmd.Stderr = &outbuf
92 rp, wp, err := os.Pipe()
93 if err != nil {
94 t.Fatal(err)
96 cmd.ExtraFiles = []*os.File{wp}
98 if err := cmd.Start(); err != nil {
99 t.Fatalf("starting program: %v", err)
102 if err := wp.Close(); err != nil {
103 t.Logf("closing write pipe: %v", err)
105 if _, err := rp.Read(make([]byte, 1)); err != nil {
106 t.Fatalf("reading from pipe: %v", err)
109 if err := cmd.Process.Signal(syscall.SIGQUIT); err != nil {
110 t.Fatalf("signal: %v", err)
113 // No point in checking the error return from Wait--we expect
114 // it to fail.
115 cmd.Wait()
117 // We want to see a stack trace for each thread.
118 // Before https://golang.org/cl/2811 running threads would say
119 // "goroutine running on other thread; stack unavailable".
120 out = outbuf.Bytes()
121 n := bytes.Count(out, []byte("main.loop"))
122 if n != 4 {
123 t.Errorf("found %d instances of main.loop; expected 4", n)
124 t.Logf("%s", out)
128 const crashDumpsAllThreadsSource = `
129 package main
131 import (
132 "fmt"
133 "os"
134 "runtime"
135 "time"
138 func main() {
139 const count = 4
140 runtime.GOMAXPROCS(count + 1)
142 chans := make([]chan bool, count)
143 for i := range chans {
144 chans[i] = make(chan bool)
145 go loop(i, chans[i])
148 // Wait for all the goroutines to start executing.
149 for _, c := range chans {
153 time.Sleep(time.Millisecond)
155 // Tell our parent that all the goroutines are executing.
156 if _, err := os.NewFile(3, "pipe").WriteString("x"); err != nil {
157 fmt.Fprintf(os.Stderr, "write to pipe failed: %v\n", err)
158 os.Exit(2)
161 select {}
164 func loop(i int, c chan bool) {
165 close(c)
166 for {
167 for j := 0; j < 0x7fffffff; j++ {
173 func TestPanicSystemstack(t *testing.T) {
174 // Test that GOTRACEBACK=crash prints both the system and user
175 // stack of other threads.
177 // The GOTRACEBACK=crash handler takes 0.1 seconds even if
178 // it's not writing a core file and potentially much longer if
179 // it is. Skip in short mode.
180 if testing.Short() {
181 t.Skip("Skipping in short mode (GOTRACEBACK=crash is slow)")
184 if runtime.Sigisblocked(int(syscall.SIGQUIT)) {
185 t.Skip("skipping; SIGQUIT is blocked, see golang.org/issue/19196")
188 t.Parallel()
189 cmd := exec.Command(os.Args[0], "testPanicSystemstackInternal")
190 cmd = testenv.CleanCmdEnv(cmd)
191 cmd.Env = append(cmd.Env, "GOTRACEBACK=crash")
192 pr, pw, err := os.Pipe()
193 if err != nil {
194 t.Fatal("creating pipe: ", err)
196 cmd.Stderr = pw
197 if err := cmd.Start(); err != nil {
198 t.Fatal("starting command: ", err)
200 defer cmd.Process.Wait()
201 defer cmd.Process.Kill()
202 if err := pw.Close(); err != nil {
203 t.Log("closing write pipe: ", err)
205 defer pr.Close()
207 // Wait for "x\nx\n" to indicate readiness.
208 buf := make([]byte, 4)
209 _, err = io.ReadFull(pr, buf)
210 if err != nil || string(buf) != "x\nx\n" {
211 t.Fatal("subprocess failed; output:\n", string(buf))
214 // Send SIGQUIT.
215 if err := cmd.Process.Signal(syscall.SIGQUIT); err != nil {
216 t.Fatal("signaling subprocess: ", err)
219 // Get traceback.
220 tb, err := ioutil.ReadAll(pr)
221 if err != nil {
222 t.Fatal("reading traceback from pipe: ", err)
225 // Traceback should have two testPanicSystemstackInternal's
226 // and two blockOnSystemStackInternal's.
227 if bytes.Count(tb, []byte("testPanicSystemstackInternal")) != 2 {
228 t.Fatal("traceback missing user stack:\n", string(tb))
229 } else if bytes.Count(tb, []byte("blockOnSystemStackInternal")) != 2 {
230 t.Fatal("traceback missing system stack:\n", string(tb))
234 func init() {
235 if len(os.Args) >= 2 && os.Args[1] == "testPanicSystemstackInternal" {
236 // Get two threads running on the system stack with
237 // something recognizable in the stack trace.
238 runtime.GOMAXPROCS(2)
239 go testPanicSystemstackInternal()
240 testPanicSystemstackInternal()
244 func testPanicSystemstackInternal() {
245 runtime.BlockOnSystemStack()
246 os.Exit(1) // Should be unreachable.
249 func TestSignalExitStatus(t *testing.T) {
250 testenv.MustHaveGoBuild(t)
251 exe, err := buildTestProg(t, "testprog")
252 if err != nil {
253 t.Fatal(err)
255 err = testenv.CleanCmdEnv(exec.Command(exe, "SignalExitStatus")).Run()
256 if err == nil {
257 t.Error("test program succeeded unexpectedly")
258 } else if ee, ok := err.(*exec.ExitError); !ok {
259 t.Errorf("error (%v) has type %T; expected exec.ExitError", err, err)
260 } else if ws, ok := ee.Sys().(syscall.WaitStatus); !ok {
261 t.Errorf("error.Sys (%v) has type %T; expected syscall.WaitStatus", ee.Sys(), ee.Sys())
262 } else if !ws.Signaled() || ws.Signal() != syscall.SIGTERM {
263 t.Errorf("got %v; expected SIGTERM", ee)
267 func TestSignalIgnoreSIGTRAP(t *testing.T) {
268 output := runTestProg(t, "testprognet", "SignalIgnoreSIGTRAP")
269 want := "OK\n"
270 if output != want {
271 t.Fatalf("want %s, got %s\n", want, output)
275 func TestSignalDuringExec(t *testing.T) {
276 switch runtime.GOOS {
277 case "darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd":
278 default:
279 t.Skipf("skipping test on %s", runtime.GOOS)
281 output := runTestProg(t, "testprognet", "SignalDuringExec")
282 want := "OK\n"
283 if output != want {
284 t.Fatalf("want %s, got %s\n", want, output)