]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: show panics in traceback
authorAustin Clements <austin@google.com>
Fri, 12 Feb 2016 15:33:51 +0000 (10:33 -0500)
committerRuss Cox <rsc@golang.org>
Tue, 16 Feb 2016 16:58:43 +0000 (16:58 +0000)
We used to include panic calls in tracebacks; however, when
runtime.panic was renamed to runtime.gopanic in the conversion of the
runtime to Go, we missed the special case in showframe that includes
panic calls even though they're in package runtime.

Fix the function name check in showframe (and, while we're here, fix
the other check for "runtime.panic" in runtime/pprof). Since the
"runtime.gopanic" name doesn't match what users call panic and hence
isn't very user-friendly, make traceback rewrite it to just "panic".

Updates #5832, #13857. Fixes #14315.

Change-Id: I8059621b41ec043e63d5cfb4cbee479f47f64973
Reviewed-on: https://go-review.googlesource.com/19492
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Russ Cox <rsc@golang.org>
src/runtime/crash_test.go
src/runtime/pprof/pprof.go
src/runtime/testdata/testprog/deadlock.go
src/runtime/traceback.go

index b622eb4526a8d63bbb5d846d9f0451a713636c13..5f0e77b0dc33590536cefd39264eb5255eeaa09d 100644 (file)
@@ -317,3 +317,22 @@ func TestNetpollDeadlock(t *testing.T) {
                t.Fatalf("output does not start with %q:\n%s", want, output)
        }
 }
+
+func TestPanicTraceback(t *testing.T) {
+       output := runTestProg(t, "testprog", "PanicTraceback")
+       want := "panic: hello"
+       if !strings.HasPrefix(output, want) {
+               t.Fatalf("output does not start with %q:\n%s", want, output)
+       }
+
+       // Check functions in the traceback.
+       fns := []string{"panic", "main.pt1.func1", "panic", "main.pt2.func1", "panic", "main.pt2", "main.pt1"}
+       for _, fn := range fns {
+               re := regexp.MustCompile(`(?m)^` + regexp.QuoteMeta(fn) + `\(.*\n`)
+               idx := re.FindStringIndex(output)
+               if idx == nil {
+                       t.Fatalf("expected %q function in traceback:\n%s", fn, output)
+               }
+               output = output[idx[1]:]
+       }
+}
index 7d677cb64e6c23e856d8d1f0bd9346e4ad3eeb4c..e09a33d5d9f8242f538a880257c1239daf992cba 100644 (file)
@@ -346,7 +346,7 @@ func printStackRecord(w io.Writer, stk []uintptr, allFrames bool) {
                        name := f.Name()
                        // Hide runtime.goexit and any runtime functions at the beginning.
                        // This is useful mainly for allocation traces.
-                       wasPanic = name == "runtime.panic"
+                       wasPanic = name == "runtime.gopanic"
                        if name == "runtime.goexit" || !show && strings.HasPrefix(name, "runtime.") {
                                continue
                        }
index 7f0a0cd1e03cac355c67b37ecbc1c1ebc837a8cc..73fbf6224dfc54fdbb66b19579d079c43d5ec9fd 100644 (file)
@@ -29,7 +29,7 @@ func init() {
        register("GoexitInPanic", GoexitInPanic)
        register("PanicAfterGoexit", PanicAfterGoexit)
        register("RecoveredPanicAfterGoexit", RecoveredPanicAfterGoexit)
-
+       register("PanicTraceback", PanicTraceback)
 }
 
 func SimpleDeadlock() {
@@ -171,3 +171,21 @@ func RecoveredPanicAfterGoexit() {
        }()
        runtime.Goexit()
 }
+
+func PanicTraceback() {
+       pt1()
+}
+
+func pt1() {
+       defer func() {
+               panic("panic pt1")
+       }()
+       pt2()
+}
+
+func pt2() {
+       defer func() {
+               panic("panic pt2")
+       }()
+       panic("hello")
+}
index 6559cd7ba3c0a0bf2fb58923024a6553582852c1..b4bfe716272929c8620704b19b890797a2005c31 100644 (file)
@@ -380,7 +380,11 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
                                if (n > 0 || flags&_TraceTrap == 0) && frame.pc > f.entry && !waspanic {
                                        tracepc--
                                }
-                               print(funcname(f), "(")
+                               name := funcname(f)
+                               if name == "runtime.gopanic" {
+                                       name = "panic"
+                               }
+                               print(name, "(")
                                argp := (*[100]uintptr)(unsafe.Pointer(frame.argp))
                                for i := uintptr(0); i < frame.arglen/sys.PtrSize; i++ {
                                        if i >= 10 {
@@ -617,10 +621,10 @@ func showframe(f *_func, gp *g) bool {
        level, _, _ := gotraceback()
        name := funcname(f)
 
-       // Special case: always show runtime.panic frame, so that we can
+       // Special case: always show runtime.gopanic frame, so that we can
        // see where a panic started in the middle of a stack trace.
        // See golang.org/issue/5832.
-       if name == "runtime.panic" {
+       if name == "runtime.gopanic" {
                return true
        }