diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index bdaea8180f4..edffc11eec1 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -2aa95f1499cf931ef8e95c7958463829276a0f2c +7e94bac5676afc8188677c98ecb263c78c1a7f8d The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/libgo/go/runtime/crash_gccgo_test.go b/libgo/go/runtime/crash_gccgo_test.go new file mode 100644 index 00000000000..c216e542ce8 --- /dev/null +++ b/libgo/go/runtime/crash_gccgo_test.go @@ -0,0 +1,59 @@ +// 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 cgo,gccgo + +package runtime_test + +import ( + "bytes" + "fmt" + "internal/testenv" + "os" + "os/exec" + "strings" + "testing" +) + +func TestGccgoCrashTraceback(t *testing.T) { + t.Parallel() + got := runTestProg(t, "testprogcgo", "CrashTracebackGccgo") + ok := true + for i := 1; i <= 3; i++ { + if !strings.Contains(got, fmt.Sprintf("CFunction%d", i)) { + t.Errorf("missing C function CFunction%d", i) + ok = false + } + } + if !ok { + t.Log(got) + } +} + +func TestGccgoCrashTracebackNodebug(t *testing.T) { + testenv.MustHaveGoBuild(t) + if os.Getenv("CC") == "" { + t.Skip("no compiler in environment") + } + + cc := strings.Fields(os.Getenv("CC")) + cc = append(cc, "-x", "c++", "-") + out, _ := exec.Command(cc[0], cc[1:]...).CombinedOutput() + if bytes.Contains(out, []byte("error trying to exec 'cc1plus'")) { + t.Skip("no C++ compiler") + } + os.Setenv("CXX", os.Getenv("CC")) + + got := runTestProg(t, "testprogcxx", "CrashTracebackNodebug") + ok := true + for i := 1; i <= 3; i++ { + if !strings.Contains(got, fmt.Sprintf("cxxFunction%d", i)) { + t.Errorf("missing C++ function cxxFunction%d", i) + ok = false + } + } + if !ok { + t.Log(got) + } +} diff --git a/libgo/go/runtime/testdata/testprogcgo/traceback_gccgo.go b/libgo/go/runtime/testdata/testprogcgo/traceback_gccgo.go new file mode 100644 index 00000000000..83357fdd5d9 --- /dev/null +++ b/libgo/go/runtime/testdata/testprogcgo/traceback_gccgo.go @@ -0,0 +1,40 @@ +// 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 gccgo + +package main + +// This program will crash. +// We want the stack trace to include the C functions. + +/* +#cgo CFLAGS: -g -O0 + +#include + +char *p; + +static int CFunction3(void) { + *p = 0; + return 0; +} + +static int CFunction2(void) { + return CFunction3(); +} + +static int CFunction1(void) { + return CFunction2(); +} +*/ +import "C" + +func init() { + register("CrashTracebackGccgo", CrashTracebackGccgo) +} + +func CrashTracebackGccgo() { + C.CFunction1() +} diff --git a/libgo/go/runtime/testdata/testprogcxx/main.go b/libgo/go/runtime/testdata/testprogcxx/main.go new file mode 100644 index 00000000000..0ecab1079c6 --- /dev/null +++ b/libgo/go/runtime/testdata/testprogcxx/main.go @@ -0,0 +1,35 @@ +// 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. + +package main + +import "os" + +var cmds = map[string]func(){} + +func register(name string, f func()) { + if cmds[name] != nil { + panic("duplicate registration: " + name) + } + cmds[name] = f +} + +func registerInit(name string, f func()) { + if len(os.Args) >= 2 && os.Args[1] == name { + f() + } +} + +func main() { + if len(os.Args) < 2 { + println("usage: " + os.Args[0] + " name-of-test") + return + } + f := cmds[os.Args[1]] + if f == nil { + println("unknown function: " + os.Args[1]) + return + } + f() +} diff --git a/libgo/go/runtime/testdata/testprogcxx/traceback.cc b/libgo/go/runtime/testdata/testprogcxx/traceback.cc new file mode 100644 index 00000000000..d4bd26cf768 --- /dev/null +++ b/libgo/go/runtime/testdata/testprogcxx/traceback.cc @@ -0,0 +1,19 @@ +// 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. + +char *p; + +static int cxxFunction3() { + *p = 0; + return 0; +} + +static int cxxFunction2() { + return cxxFunction3(); +} + +extern "C" +int cxxFunction1() { + return cxxFunction2(); +} diff --git a/libgo/go/runtime/testdata/testprogcxx/traceback.go b/libgo/go/runtime/testdata/testprogcxx/traceback.go new file mode 100644 index 00000000000..0e40ca8ffbb --- /dev/null +++ b/libgo/go/runtime/testdata/testprogcxx/traceback.go @@ -0,0 +1,24 @@ +// 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. + +package main + +// This program will crash. +// We want the stack trace to include the C++ functions, +// even though we compile with -g0. + +/* +#cgo CXXFLAGS: -g0 -O0 + +extern int cxxFunction1(void); +*/ +import "C" + +func init() { + register("CrashTracebackNodebug", CrashTracebackNodebug) +} + +func CrashTracebackNodebug() { + C.cxxFunction1() +} diff --git a/libgo/runtime/go-callers.c b/libgo/runtime/go-callers.c index 2eaac682779..590315376e3 100644 --- a/libgo/runtime/go-callers.c +++ b/libgo/runtime/go-callers.c @@ -143,6 +143,20 @@ callback (void *data, uintptr_t pc, const char *filename, int lineno, return arg->index >= arg->max; } +/* Syminfo callback. */ + +static void +syminfo_fnname_callback (void *data, uintptr_t pc __attribute__ ((unused)), + const char *symname, + uintptr_t address __attribute__ ((unused)), + uintptr_t size __attribute__ ((unused))) +{ + Location* locptr = (Location*) data; + + if (symname != NULL) + locptr->function = runtime_gostringnocopy ((const byte *) symname); +} + /* Error callback. */ static void @@ -179,15 +193,17 @@ int32 runtime_callers (int32 skip, Location *locbuf, int32 m, bool keep_thunks) { struct callers_data data; + struct backtrace_state* state; + int32 i; data.locbuf = locbuf; data.skip = skip + 1; data.index = 0; data.max = m; data.keep_thunks = keep_thunks; + state = __go_get_backtrace_state (); runtime_xadd (&runtime_in_callers, 1); - backtrace_full (__go_get_backtrace_state (), 0, callback, error_callback, - &data); + backtrace_full (state, 0, callback, error_callback, &data); runtime_xadd (&runtime_in_callers, -1); /* For some reason GCC sometimes loses the name of a thunk function @@ -204,6 +220,18 @@ runtime_callers (int32 skip, Location *locbuf, int32 m, bool keep_thunks) --data.index; } + /* Try to use backtrace_syminfo to fill in any missing function + names. This can happen when tracing through an object which has + no debug info; backtrace_syminfo will look at the symbol table to + get the name. This should only happen when tracing through code + that is not written in Go and is not part of libgo. */ + for (i = 0; i < data.index; ++i) + { + if (locbuf[i].function.len == 0 && locbuf[i].pc != 0) + backtrace_syminfo (state, locbuf[i].pc, syminfo_fnname_callback, + error_callback, &locbuf[i]); + } + return data.index; } diff --git a/libgo/testsuite/gotest b/libgo/testsuite/gotest index f5c908adef8..f978042cccc 100755 --- a/libgo/testsuite/gotest +++ b/libgo/testsuite/gotest @@ -348,18 +348,18 @@ x) fi match=false ;; - $goos | $goarch | cgo | go1.[0-9]) + $goos | $goarch | cgo | gccgo | go1.[0-9]) match=true ;; - "!"$goos | "!"$goarch | "!cgo" | "!"go1.[0-9]) + "!"$goos | "!"$goarch | "!cgo" | "!gccgo" | "!"go1.[0-9]) ;; *,*) cmatch=true for ctag in `echo $tag | sed -e 's/,/ /g'`; do case $ctag in - $goos | $goarch | cgo | go1.[0-9]) + $goos | $goarch | cgo | gccgo | go1.[0-9]) ;; - "!"$goos | "!"$goarch | "!cgo" | "!"go1.[0-9]) + "!"$goos | "!"$goarch | "!cgo" | "!gccgo" | "!"go1.[0-9]) cmatch=false ;; "!"*)