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.
11 "runtime/internal/sys"
15 func printcreatedby(gp *g) {
16 // Show what created goroutine, except main goroutine (goid 1).
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, false) && gp.goid != 1 {
25 printcreatedby1(function, file, line, entry, pc)
29 func printcreatedby1(function, file string, line int, entry, pc uintptr) {
30 print("created by ", function, "\n")
31 print("\t", file, ":", line)
32 if entry != 0 && pc > entry {
33 print(" +", hex(pc-entry))
38 // tracebackg is used to collect stack traces from other goroutines.
39 type tracebackg struct {
41 locbuf [_TracebackMaxFrames]location
45 // location is a location in the program, used for backtraces.
46 type location struct {
54 //extern runtime_callers
55 func c_callers(skip int32, locbuf *location, max int32, keepThunks bool) int32
57 // callers returns a stack trace of the current goroutine.
58 // The gc version of callers takes []uintptr, but we take []location.
59 func callers(skip int, locbuf []location) int {
60 n := c_callers(int32(skip)+1, &locbuf[0], int32(len(locbuf)), false)
65 //extern runtime_callersRaw
66 func c_callersRaw(pcs *uintptr, max int32) int32
68 // callersRaw returns a raw (PCs only) stack trace of the current goroutine.
69 func callersRaw(pcbuf []uintptr) int {
70 n := c_callersRaw(&pcbuf[0], int32(len(pcbuf)))
74 // traceback prints a traceback of the current goroutine.
75 // This differs from the gc version, which is given pc, sp, lr and g and
76 // can print a traceback of any goroutine.
77 func traceback(skip int32) {
78 var locbuf [100]location
79 c := c_callers(skip+1, &locbuf[0], int32(len(locbuf)), false)
81 printtrace(locbuf[:c], gp)
84 if gp.ancestors == nil {
87 for _, ancestor := range *gp.ancestors {
88 printAncestorTraceback(ancestor)
92 // printAncestorTraceback prints the traceback of the given ancestor.
93 func printAncestorTraceback(ancestor ancestorInfo) {
94 print("[originating from goroutine ", ancestor.goid, "]:\n")
95 for fidx, pc := range ancestor.pcs {
96 function, file, line, _ := funcfileline(pc, -1)
97 if showfuncinfo(function, fidx == 0) {
98 printAncestorTracebackFuncInfo(function, file, line, pc)
101 if len(ancestor.pcs) == _TracebackMaxFrames {
102 print("...additional frames elided...\n")
104 // Show what created goroutine, except main goroutine (goid 1).
105 function, file, line, _ := funcfileline(ancestor.gopc, -1)
106 if function != "" && showfuncinfo(function, false) && ancestor.goid != 1 {
107 printcreatedby1(function, file, line, funcentry(ancestor.gopc), ancestor.gopc)
111 // printAncestorTraceback prints the given function info at a given pc
112 // within an ancestor traceback. The precision of this info is reduced
113 // due to only have access to the pcs at the time of the caller
114 // goroutine being created.
115 func printAncestorTracebackFuncInfo(name, file string, line int, pc uintptr) {
116 if name == "runtime.gopanic" {
119 print(name, "(...)\n")
120 print("\t", file, ":", line)
121 entry := funcentry(pc)
123 print(" +", hex(pc-entry))
128 // printtrace prints a traceback from locbuf.
129 func printtrace(locbuf []location, gp *g) {
131 for i := range locbuf {
132 if showframe(locbuf[i].function, gp, nprint == 0) {
133 name := locbuf[i].function
134 if name == "runtime.gopanic" {
137 print(name, "\n\t", locbuf[i].filename, ":", locbuf[i].lineno, "\n")
143 // showframe returns whether to print a frame in a traceback.
144 // name is the function name.
145 func showframe(name string, gp *g, firstFrame bool) bool {
147 if g.m.throwing > 0 && gp != nil && (gp == g.m.curg || gp == g.m.caughtsig.ptr()) {
150 return showfuncinfo(name, firstFrame)
153 func showfuncinfo(name string, firstFrame bool) bool {
154 // Gccgo can trace back through C functions called via cgo.
155 // We want to print those in the traceback.
156 // But unless GOTRACEBACK > 1 (checked below), still skip
157 // internal C functions and cgo-generated functions.
158 if name != "" && !contains(name, ".") && !hasPrefix(name, "__go_") && !hasPrefix(name, "_cgo_") {
162 level, _, _ := gotraceback()
172 // Special case: always show runtime.gopanic frame
173 // in the middle of a stack trace, so that we can
174 // see the boundary between ordinary code and
175 // panic-induced deferred code.
176 // See golang.org/issue/5832.
177 if name == "runtime.gopanic" && !firstFrame {
181 return contains(name, ".") && (!hasPrefix(name, "runtime.") || isExportedRuntime(name))
184 // isExportedRuntime reports whether name is an exported runtime function.
185 // It is only for runtime functions, so ASCII A-Z is fine. Here also check
186 // for mangled functions from runtime/<...>, which will be prefixed with
188 func isExportedRuntime(name string) bool {
189 const n = len("runtime.")
190 if hasPrefix(name, "runtime..z2f") {
193 return len(name) > n && name[:n] == "runtime." && 'A' <= name[n] && name[n] <= 'Z'
196 var gStatusStrings = [...]string{
198 _Grunnable: "runnable",
199 _Grunning: "running",
200 _Gsyscall: "syscall",
201 _Gwaiting: "waiting",
203 _Gcopystack: "copystack",
204 _Gexitingsyscall: "exiting syscall",
207 func goroutineheader(gp *g) {
208 gpstatus := readgstatus(gp)
210 isScan := gpstatus&_Gscan != 0
211 gpstatus &^= _Gscan // drop the scan bit
213 // Basic string status
215 if 0 <= gpstatus && gpstatus < uint32(len(gStatusStrings)) {
216 status = gStatusStrings[gpstatus]
222 if gpstatus == _Gwaiting && gp.waitreason != waitReasonZero {
223 status = gp.waitreason.String()
226 // approx time the G is blocked, in minutes
228 if (gpstatus == _Gwaiting || gpstatus == _Gsyscall) && gp.waitsince != 0 {
229 waitfor = (nanotime() - gp.waitsince) / 60e9
231 print("goroutine ", gp.goid, " [", status)
236 print(", ", waitfor, " minutes")
239 print(", locked to thread")
244 // isSystemGoroutine reports whether the goroutine g must be omitted
245 // in stack dumps and deadlock detector. This is any goroutine that
246 // starts at a runtime.* entry point, except for runtime.main and
247 // sometimes runtime.runfinq.
249 // If fixed is true, any goroutine that can vary between user and
250 // system (that is, the finalizer goroutine) is considered a user
252 func isSystemGoroutine(gp *g, fixed bool) bool {
253 if !gp.isSystemGoroutine {
256 if fixed && gp.isFinalizerGoroutine {
257 // This goroutine can vary. In fixed mode,
258 // always consider it a user goroutine.
264 func tracebackothers(me *g) {
268 // The getTraceback function will modify me's stack context.
269 // Preserve it in case we have been called via systemstack.
270 context := me.context
271 stackcontext := me.stackcontext
273 level, _, _ := gotraceback()
275 // Show the current goroutine first, if we haven't already.
278 if gp != nil && gp != me {
281 gp.traceback = (uintptr)(noescape(unsafe.Pointer(&tb)))
283 printtrace(tb.locbuf[:tb.c], nil)
288 for _, gp := range allgs {
289 if gp == me || gp == g.m.curg || readgstatus(gp) == _Gdead || isSystemGoroutine(gp, false) && level < 2 {
295 // gccgo's only mechanism for doing a stack trace is
296 // _Unwind_Backtrace. And that only works for the
297 // current thread, not for other random goroutines.
298 // So we need to switch context to the goroutine, get
299 // the backtrace, and then switch back.
301 // This means that if g is running or in a syscall, we
302 // can't reliably print a stack trace. FIXME.
304 // Note: gp.m == g.m occurs when tracebackothers is
305 // called from a signal handler initiated during a
306 // systemstack call. The original G is still in the
307 // running state, and we want to print its stack.
308 if gp.m != g.m && readgstatus(gp)&^_Gscan == _Grunning {
309 print("\tgoroutine running on other thread; stack unavailable\n")
311 } else if readgstatus(gp)&^_Gscan == _Gsyscall {
312 print("\tgoroutine in C code; stack unavailable\n")
315 gp.traceback = (uintptr)(noescape(unsafe.Pointer(&tb)))
317 printtrace(tb.locbuf[:tb.c], nil)
324 me.stackcontext = stackcontext