[1/7] Preprocessor cleanup
[official-gcc.git] / libgo / go / runtime / traceback_gccgo.go
blob7347cea71b22ea0597797957eca00d0910229237
1 // Copyright 2016 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // Traceback support for gccgo.
6 // The actual traceback code is written in C.
8 package runtime
10 import (
11 "runtime/internal/sys"
12 "unsafe"
15 func printcreatedby(gp *g) {
16 // Show what created goroutine, except main goroutine (goid 1).
17 pc := gp.gopc
18 tracepc := pc // back up to CALL instruction for funcfileline.
19 entry := funcentry(tracepc)
20 if entry != 0 && tracepc > entry {
21 tracepc -= sys.PCQuantum
23 function, file, line := funcfileline(tracepc, -1)
24 if function != "" && showframe(function, gp) && gp.goid != 1 {
25 print("created by ", function, "\n")
26 print("\t", file, ":", line)
27 if entry != 0 && pc > entry {
28 print(" +", hex(pc-entry))
30 print("\n")
34 // tracebackg is used to collect stack traces from other goroutines.
35 type tracebackg struct {
36 gp *g
37 locbuf [_TracebackMaxFrames]location
38 c int
41 // location is a location in the program, used for backtraces.
42 type location struct {
43 pc uintptr
44 filename string
45 function string
46 lineno int
49 //go:noescape
50 //extern runtime_callers
51 func c_callers(skip int32, locbuf *location, max int32, keepThunks bool) int32
53 // callers returns a stack trace of the current goroutine.
54 // The gc version of callers takes []uintptr, but we take []location.
55 func callers(skip int, locbuf []location) int {
56 n := c_callers(int32(skip)+1, &locbuf[0], int32(len(locbuf)), false)
57 return int(n)
60 // traceback prints a traceback of the current goroutine.
61 // This differs from the gc version, which is given pc, sp, lr and g and
62 // can print a traceback of any goroutine.
63 func traceback(skip int32) {
64 var locbuf [100]location
65 c := c_callers(skip+1, &locbuf[0], int32(len(locbuf)), false)
66 printtrace(locbuf[:c], getg())
67 printcreatedby(getg())
70 // printtrace prints a traceback from locbuf.
71 func printtrace(locbuf []location, gp *g) {
72 for i := range locbuf {
73 if showframe(locbuf[i].function, gp) {
74 name := locbuf[i].function
75 if name == "runtime.gopanic" {
76 name = "panic"
78 print(name, "\n\t", locbuf[i].filename, ":", locbuf[i].lineno, "\n")
83 // showframe returns whether to print a frame in a traceback.
84 // name is the function name.
85 func showframe(name string, gp *g) bool {
86 g := getg()
87 if g.m.throwing > 0 && gp != nil && (gp == g.m.curg || gp == g.m.caughtsig.ptr()) {
88 return true
91 // Gccgo can trace back through C functions called via cgo.
92 // We want to print those in the traceback.
93 // But unless GOTRACEBACK > 1 (checked below), still skip
94 // internal C functions and cgo-generated functions.
95 if name != "" && !contains(name, ".") && !hasprefix(name, "__go_") && !hasprefix(name, "_cgo_") {
96 return true
99 level, _, _ := gotraceback()
101 // Special case: always show runtime.gopanic frame, so that we can
102 // see where a panic started in the middle of a stack trace.
103 // See golang.org/issue/5832.
104 // __go_panic is the current gccgo name.
105 if name == "runtime.gopanic" || name == "__go_panic" {
106 return true
109 return level > 1 || contains(name, ".") && (!hasprefix(name, "runtime.") || isExportedRuntime(name))
112 // isExportedRuntime reports whether name is an exported runtime function.
113 // It is only for runtime functions, so ASCII A-Z is fine. Here also check
114 // for mangled functions from runtime/<...>, which will be prefixed with
115 // "runtime..z2f".
116 func isExportedRuntime(name string) bool {
117 const n = len("runtime.")
118 if hasprefix(name, "runtime..z2f") {
119 return true
121 return len(name) > n && name[:n] == "runtime." && 'A' <= name[n] && name[n] <= 'Z'
124 var gStatusStrings = [...]string{
125 _Gidle: "idle",
126 _Grunnable: "runnable",
127 _Grunning: "running",
128 _Gsyscall: "syscall",
129 _Gwaiting: "waiting",
130 _Gdead: "dead",
131 _Gcopystack: "copystack",
134 func goroutineheader(gp *g) {
135 gpstatus := readgstatus(gp)
137 isScan := gpstatus&_Gscan != 0
138 gpstatus &^= _Gscan // drop the scan bit
140 // Basic string status
141 var status string
142 if 0 <= gpstatus && gpstatus < uint32(len(gStatusStrings)) {
143 status = gStatusStrings[gpstatus]
144 } else {
145 status = "???"
148 // Override.
149 if gpstatus == _Gwaiting && gp.waitreason != waitReasonZero {
150 status = gp.waitreason.String()
153 // approx time the G is blocked, in minutes
154 var waitfor int64
155 if (gpstatus == _Gwaiting || gpstatus == _Gsyscall) && gp.waitsince != 0 {
156 waitfor = (nanotime() - gp.waitsince) / 60e9
158 print("goroutine ", gp.goid, " [", status)
159 if isScan {
160 print(" (scan)")
162 if waitfor >= 1 {
163 print(", ", waitfor, " minutes")
165 if gp.lockedm != 0 {
166 print(", locked to thread")
168 print("]:\n")
171 // isSystemGoroutine reports whether the goroutine g must be omitted in
172 // stack dumps and deadlock detector.
173 func isSystemGoroutine(gp *g) bool {
174 return gp.isSystemGoroutine
177 func tracebackothers(me *g) {
178 var tb tracebackg
179 tb.gp = me
181 // The getTraceback function will modify me's stack context.
182 // Preserve it in case we have been called via systemstack.
183 context := me.context
184 stackcontext := me.stackcontext
186 level, _, _ := gotraceback()
188 // Show the current goroutine first, if we haven't already.
189 g := getg()
190 gp := g.m.curg
191 if gp != nil && gp != me {
192 print("\n")
193 goroutineheader(gp)
194 gp.traceback = (uintptr)(noescape(unsafe.Pointer(&tb)))
195 getTraceback(me, gp)
196 printtrace(tb.locbuf[:tb.c], nil)
197 printcreatedby(gp)
200 lock(&allglock)
201 for _, gp := range allgs {
202 if gp == me || gp == g.m.curg || readgstatus(gp) == _Gdead || isSystemGoroutine(gp) && level < 2 {
203 continue
205 print("\n")
206 goroutineheader(gp)
208 // gccgo's only mechanism for doing a stack trace is
209 // _Unwind_Backtrace. And that only works for the
210 // current thread, not for other random goroutines.
211 // So we need to switch context to the goroutine, get
212 // the backtrace, and then switch back.
214 // This means that if g is running or in a syscall, we
215 // can't reliably print a stack trace. FIXME.
217 // Note: gp.m == g.m occurs when tracebackothers is
218 // called from a signal handler initiated during a
219 // systemstack call. The original G is still in the
220 // running state, and we want to print its stack.
221 if gp.m != g.m && readgstatus(gp)&^_Gscan == _Grunning {
222 print("\tgoroutine running on other thread; stack unavailable\n")
223 printcreatedby(gp)
224 } else if readgstatus(gp)&^_Gscan == _Gsyscall {
225 print("\tgoroutine in C code; stack unavailable\n")
226 printcreatedby(gp)
227 } else {
228 gp.traceback = (uintptr)(noescape(unsafe.Pointer(&tb)))
229 getTraceback(me, gp)
230 printtrace(tb.locbuf[:tb.c], nil)
231 printcreatedby(gp)
234 unlock(&allglock)
236 me.context = context
237 me.stackcontext = stackcontext