diff options
author | Michael Munday <mike.munday@ibm.com> | 2019-03-28 12:51:30 -0400 |
---|---|---|
committer | Michael Munday <mike.munday@ibm.com> | 2019-04-15 13:17:28 +0000 |
commit | aafe257390cc9048e8b5df898fabd79a9e0d4c39 (patch) | |
tree | 2c0636b4b1ab59eb4b00a1f185515ce22ee2ff5a /src/runtime/runtime-gdb_test.go | |
parent | 0bd101cecc5458a8463b8d672bf1745c3cbb7c02 (diff) | |
download | go-aafe257390cc9048e8b5df898fabd79a9e0d4c39.tar.gz go-aafe257390cc9048e8b5df898fabd79a9e0d4c39.zip |
cmd/link, runtime: mark goexit as the top of the call stack
This CL adds a new attribute, TOPFRAME, which can be used to mark
functions that should be treated as being at the top of the call
stack. The function `runtime.goexit` has been marked this way on
architectures that use a link register.
This will stop programs that use DWARF to unwind the call stack
from unwinding past `runtime.goexit` on architectures that use a
link register. For example, it eliminates "corrupt stack?"
warnings when generating a backtrace that hits `runtime.goexit`
in GDB on s390x.
Similar code should be added for non-link-register architectures
(i.e. amd64, 386). They mark the top of the call stack slightly
differently to link register architectures so I haven't added
that code (they need to mark "rip" as undefined).
Fixes #24385.
Change-Id: I15b4c69ac75b491daa0acf0d981cb80eb06488de
Reviewed-on: https://go-review.googlesource.com/c/go/+/169726
Run-TryBot: Michael Munday <mike.munday@ibm.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Diffstat (limited to 'src/runtime/runtime-gdb_test.go')
-rw-r--r-- | src/runtime/runtime-gdb_test.go | 22 |
1 files changed, 22 insertions, 0 deletions
diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go index d47c7c2262..8117a5c979 100644 --- a/src/runtime/runtime-gdb_test.go +++ b/src/runtime/runtime-gdb_test.go @@ -82,6 +82,22 @@ func checkGdbPython(t *testing.T) { } } +// checkCleanBacktrace checks that the given backtrace is well formed and does +// not contain any error messages from GDB. +func checkCleanBacktrace(t *testing.T, backtrace string) { + backtrace = strings.TrimSpace(backtrace) + lines := strings.Split(backtrace, "\n") + if len(lines) == 0 { + t.Fatalf("empty backtrace") + } + for i, l := range lines { + if !strings.HasPrefix(l, fmt.Sprintf("#%v ", i)) { + t.Fatalf("malformed backtrace at line %v: %v", i, l) + } + } + // TODO(mundaym): check for unknown frames (e.g. "??"). +} + const helloSource = ` import "fmt" import "runtime" @@ -272,6 +288,11 @@ func testGdbPython(t *testing.T, cgo bool) { t.Fatalf("info locals failed: %s", bl) } + // Check that the backtraces are well formed. + checkCleanBacktrace(t, blocks["goroutine 1 bt"]) + checkCleanBacktrace(t, blocks["goroutine 2 bt"]) + checkCleanBacktrace(t, blocks["goroutine 1 bt at the end"]) + btGoroutine1Re := regexp.MustCompile(`(?m)^#0\s+(0x[0-9a-f]+\s+in\s+)?main\.main.+at`) if bl := blocks["goroutine 1 bt"]; !btGoroutine1Re.MatchString(bl) { t.Fatalf("goroutine 1 bt failed: %s", bl) @@ -281,6 +302,7 @@ func testGdbPython(t *testing.T, cgo bool) { if bl := blocks["goroutine 2 bt"]; !btGoroutine2Re.MatchString(bl) { t.Fatalf("goroutine 2 bt failed: %s", bl) } + btGoroutine1AtTheEndRe := regexp.MustCompile(`(?m)^#0\s+(0x[0-9a-f]+\s+in\s+)?main\.main.+at`) if bl := blocks["goroutine 1 bt at the end"]; !btGoroutine1AtTheEndRe.MatchString(bl) { t.Fatalf("goroutine 1 bt at the end failed: %s", bl) |