aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/traceback.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtime/traceback.go')
-rw-r--r--src/runtime/traceback.go95
1 files changed, 84 insertions, 11 deletions
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index 06df9385fd..0f392a50fd 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -627,18 +627,22 @@ func printcreatedby(gp *g) {
pc := gp.gopc
f := findfunc(pc)
if f.valid() && showframe(f, gp, false, false) && gp.goid != 1 {
- print("created by ", funcname(f), "\n")
- tracepc := pc // back up to CALL instruction for funcline.
- if pc > f.entry {
- tracepc -= sys.PCQuantum
- }
- file, line := funcline(f, tracepc)
- print("\t", file, ":", line)
- if pc > f.entry {
- print(" +", hex(pc-f.entry))
- }
- print("\n")
+ printcreatedby1(f, pc)
+ }
+}
+
+func printcreatedby1(f funcInfo, pc uintptr) {
+ print("created by ", funcname(f), "\n")
+ tracepc := pc // back up to CALL instruction for funcline.
+ if pc > f.entry {
+ tracepc -= sys.PCQuantum
}
+ file, line := funcline(f, tracepc)
+ print("\t", file, ":", line)
+ if pc > f.entry {
+ print(" +", hex(pc-f.entry))
+ }
+ print("\n")
}
func traceback(pc, sp, lr uintptr, gp *g) {
@@ -689,6 +693,71 @@ func traceback1(pc, sp, lr uintptr, gp *g, flags uint) {
print("...additional frames elided...\n")
}
printcreatedby(gp)
+
+ if gp.ancestors == nil {
+ return
+ }
+ for _, ancestor := range *gp.ancestors {
+ printAncestorTraceback(ancestor)
+ }
+}
+
+// printAncestorTraceback prints the traceback of the given ancestor.
+// TODO: Unify this with gentraceback and CallersFrames.
+func printAncestorTraceback(ancestor ancestorInfo) {
+ print("[originating from goroutine ", ancestor.goid, "]:\n")
+ elideWrapper := false
+ for fidx, pc := range ancestor.pcs {
+ f := findfunc(pc) // f previously validated
+ if showfuncinfo(f, fidx == 0, elideWrapper && fidx != 0) {
+ elideWrapper = printAncestorTracebackFuncInfo(f, pc)
+ }
+ }
+ if len(ancestor.pcs) == _TracebackMaxFrames {
+ print("...additional frames elided...\n")
+ }
+ // Show what created goroutine, except main goroutine (goid 1).
+ f := findfunc(ancestor.gopc)
+ if f.valid() && showfuncinfo(f, false, false) && ancestor.goid != 1 {
+ printcreatedby1(f, ancestor.gopc)
+ }
+}
+
+// printAncestorTraceback prints the given function info at a given pc
+// within an ancestor traceback. The precision of this info is reduced
+// due to only have access to the pcs at the time of the caller
+// goroutine being created.
+func printAncestorTracebackFuncInfo(f funcInfo, pc uintptr) bool {
+ tracepc := pc // back up to CALL instruction for funcline.
+ if pc > f.entry {
+ tracepc -= sys.PCQuantum
+ }
+ file, line := funcline(f, tracepc)
+ inldata := funcdata(f, _FUNCDATA_InlTree)
+ if inldata != nil {
+ inltree := (*[1 << 20]inlinedCall)(inldata)
+ ix := pcdatavalue(f, _PCDATA_InlTreeIndex, tracepc, nil)
+ for ix != -1 {
+ name := funcnameFromNameoff(f, inltree[ix].func_)
+ print(name, "(...)\n")
+ print("\t", file, ":", line, "\n")
+
+ file = funcfile(f, inltree[ix].file)
+ line = inltree[ix].line
+ ix = inltree[ix].parent
+ }
+ }
+ name := funcname(f)
+ if name == "runtime.gopanic" {
+ name = "panic"
+ }
+ print(name, "(...)\n")
+ print("\t", file, ":", line)
+ if pc > f.entry {
+ print(" +", hex(pc-f.entry))
+ }
+ print("\n")
+ return elideWrapperCalling(name)
}
func callers(skip int, pcbuf []uintptr) int {
@@ -711,6 +780,10 @@ func showframe(f funcInfo, gp *g, firstFrame, elideWrapper bool) bool {
if g.m.throwing > 0 && gp != nil && (gp == g.m.curg || gp == g.m.caughtsig.ptr()) {
return true
}
+ return showfuncinfo(f, firstFrame, elideWrapper)
+}
+
+func showfuncinfo(f funcInfo, firstFrame, elideWrapper bool) bool {
level, _, _ := gotraceback()
if level > 1 {
// Show all frames.