summaryrefslogtreecommitdiff
path: root/libgo/go/runtime/traceback_gccgo.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/runtime/traceback_gccgo.go')
-rw-r--r--libgo/go/runtime/traceback_gccgo.go228
1 files changed, 228 insertions, 0 deletions
diff --git a/libgo/go/runtime/traceback_gccgo.go b/libgo/go/runtime/traceback_gccgo.go
new file mode 100644
index 0000000000..611aba91a4
--- /dev/null
+++ b/libgo/go/runtime/traceback_gccgo.go
@@ -0,0 +1,228 @@
+// Copyright 2016 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.
+
+// Traceback support for gccgo.
+// The actual traceback code is written in C.
+
+package runtime
+
+import (
+ "runtime/internal/sys"
+ _ "unsafe" // for go:linkname
+)
+
+// For gccgo, use go:linkname to rename compiler-called functions to
+// themselves, so that the compiler will export them.
+// These are temporary for C runtime code to call.
+//go:linkname traceback runtime.traceback
+//go:linkname printtrace runtime.printtrace
+//go:linkname goroutineheader runtime.goroutineheader
+//go:linkname printcreatedby runtime.printcreatedby
+
+func printcreatedby(gp *g) {
+ // Show what created goroutine, except main goroutine (goid 1).
+ pc := gp.gopc
+ tracepc := pc // back up to CALL instruction for funcfileline.
+ entry := funcentry(tracepc)
+ if entry != 0 && tracepc > entry {
+ tracepc -= sys.PCQuantum
+ }
+ function, file, line := funcfileline(tracepc, -1)
+ if function != "" && showframe(function, gp) && gp.goid != 1 {
+ print("created by ", function, "\n")
+ print("\t", file, ":", line)
+ if entry != 0 && pc > entry {
+ print(" +", hex(pc-entry))
+ }
+ print("\n")
+ }
+}
+
+// tracebackg is used to collect stack traces from other goroutines.
+type tracebackg struct {
+ gp *g
+ locbuf [_TracebackMaxFrames]location
+ c int
+}
+
+// location is a location in the program, used for backtraces.
+type location struct {
+ pc uintptr
+ filename string
+ function string
+ lineno int
+}
+
+//extern runtime_callers
+func c_callers(skip int32, locbuf *location, max int32, keepThunks bool) int32
+
+// callers returns a stack trace of the current goroutine.
+// The gc version of callers takes []uintptr, but we take []location.
+func callers(skip int, locbuf []location) int {
+ n := c_callers(int32(skip), &locbuf[0], int32(len(locbuf)), false)
+ return int(n)
+}
+
+// traceback prints a traceback of the current goroutine.
+// This differs from the gc version, which is given pc, sp, lr and g and
+// can print a traceback of any goroutine.
+func traceback(skip int32) {
+ var locbuf [100]location
+ c := c_callers(skip+1, &locbuf[0], int32(len(locbuf)), false)
+ printtrace(locbuf[:c], getg())
+}
+
+// printtrace prints a traceback from locbuf.
+func printtrace(locbuf []location, gp *g) {
+ for i := range locbuf {
+ if showframe(locbuf[i].function, gp) {
+ print(locbuf[i].function, "\n\t", locbuf[i].filename, ":", locbuf[i].lineno, "\n")
+ }
+ }
+}
+
+// showframe returns whether to print a frame in a traceback.
+// name is the function name.
+func showframe(name string, gp *g) bool {
+ g := getg()
+ if g.m.throwing > 0 && gp != nil && (gp == g.m.curg || gp == g.m.caughtsig.ptr()) {
+ return true
+ }
+
+ // Gccgo can trace back through C functions called via cgo.
+ // We want to print those in the traceback.
+ // But unless GOTRACEBACK > 1 (checked below), still skip
+ // internal C functions and cgo-generated functions.
+ if !contains(name, ".") && !hasprefix(name, "__go_") && !hasprefix(name, "_cgo_") {
+ return true
+ }
+
+ level, _, _ := gotraceback()
+
+ // 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.
+ // __go_panic is the current gccgo name.
+ if name == "runtime.gopanic" || name == "__go_panic" {
+ return true
+ }
+
+ return level > 1 || contains(name, ".") && (!hasprefix(name, "runtime.") || isExportedRuntime(name))
+}
+
+// isExportedRuntime reports whether name is an exported runtime function.
+// It is only for runtime functions, so ASCII A-Z is fine.
+func isExportedRuntime(name string) bool {
+ const n = len("runtime.")
+ return len(name) > n && name[:n] == "runtime." && 'A' <= name[n] && name[n] <= 'Z'
+}
+
+var gStatusStrings = [...]string{
+ _Gidle: "idle",
+ _Grunnable: "runnable",
+ _Grunning: "running",
+ _Gsyscall: "syscall",
+ _Gwaiting: "waiting",
+ _Gdead: "dead",
+ _Gcopystack: "copystack",
+}
+
+func goroutineheader(gp *g) {
+ gpstatus := readgstatus(gp)
+
+ isScan := gpstatus&_Gscan != 0
+ gpstatus &^= _Gscan // drop the scan bit
+
+ // Basic string status
+ var status string
+ if 0 <= gpstatus && gpstatus < uint32(len(gStatusStrings)) {
+ status = gStatusStrings[gpstatus]
+ } else {
+ status = "???"
+ }
+
+ // Override.
+ if gpstatus == _Gwaiting && gp.waitreason != "" {
+ status = gp.waitreason
+ }
+
+ // approx time the G is blocked, in minutes
+ var waitfor int64
+ if (gpstatus == _Gwaiting || gpstatus == _Gsyscall) && gp.waitsince != 0 {
+ waitfor = (nanotime() - gp.waitsince) / 60e9
+ }
+ print("goroutine ", gp.goid, " [", status)
+ if isScan {
+ print(" (scan)")
+ }
+ if waitfor >= 1 {
+ print(", ", waitfor, " minutes")
+ }
+ if gp.lockedm != nil {
+ print(", locked to thread")
+ }
+ print("]:\n")
+}
+
+// isSystemGoroutine reports whether the goroutine g must be omitted in
+// stack dumps and deadlock detector.
+func isSystemGoroutine(gp *g) bool {
+ // FIXME.
+ return false
+}
+
+func tracebackothers(me *g) {
+ var tb tracebackg
+ tb.gp = me
+
+ level, _, _ := gotraceback()
+
+ // Show the current goroutine first, if we haven't already.
+ g := getg()
+ gp := g.m.curg
+ if gp != nil && gp != me {
+ print("\n")
+ goroutineheader(gp)
+ gp.traceback = &tb
+ getTraceback(me, gp)
+ printtrace(tb.locbuf[:tb.c], nil)
+ printcreatedby(gp)
+ }
+
+ lock(&allglock)
+ for _, gp := range allgs {
+ if gp == me || gp == g.m.curg || readgstatus(gp) == _Gdead || isSystemGoroutine(gp) && level < 2 {
+ continue
+ }
+ print("\n")
+ goroutineheader(gp)
+
+ // gccgo's only mechanism for doing a stack trace is
+ // _Unwind_Backtrace. And that only works for the
+ // current thread, not for other random goroutines.
+ // So we need to switch context to the goroutine, get
+ // the backtrace, and then switch back.
+ //
+ // This means that if g is running or in a syscall, we
+ // can't reliably print a stack trace. FIXME.
+
+ // Note: gp.m == g.m occurs when tracebackothers is
+ // called from a signal handler initiated during a
+ // systemstack call. The original G is still in the
+ // running state, and we want to print its stack.
+ if gp.m != g.m && readgstatus(gp)&^_Gscan == _Grunning {
+ print("\tgoroutine running on other thread; stack unavailable\n")
+ printcreatedby(gp)
+ } else if readgstatus(gp)&^_Gscan == _Gsyscall {
+ print("\tgoroutine in C code; stack unavailable\n")
+ printcreatedby(gp)
+ } else {
+ gp.traceback = &tb
+ getTraceback(me, gp)
+ printtrace(tb.locbuf[:tb.c], nil)
+ printcreatedby(gp)
+ }
+ }
+ unlock(&allglock)
+}