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. 4 5// Traceback support for gccgo. 6// The actual traceback code is written in C. 7 8package runtime 9 10import ( 11 "internal/bytealg" 12 "runtime/internal/sys" 13 "unsafe" 14) 15 16func printcreatedby(gp *g) { 17 // Show what created goroutine, except main goroutine (goid 1). 18 pc := gp.gopc 19 tracepc := pc // back up to CALL instruction for funcfileline. 20 entry := funcentry(tracepc) 21 if entry != 0 && tracepc > entry { 22 tracepc -= sys.PCQuantum 23 } 24 function, file, line, _ := funcfileline(tracepc, -1, false) 25 if function != "" && showframe(function, gp, false) && gp.goid != 1 { 26 printcreatedby1(function, file, line, entry, pc) 27 } 28} 29 30func printcreatedby1(function, file string, line int, entry, pc uintptr) { 31 print("created by ", function, "\n") 32 print("\t", file, ":", line) 33 if entry != 0 && pc > entry { 34 print(" +", hex(pc-entry)) 35 } 36 print("\n") 37} 38 39// tracebackg is used to collect stack traces from other goroutines. 40type tracebackg struct { 41 gp *g 42 locbuf [_TracebackMaxFrames]location 43 c int 44} 45 46// location is a location in the program, used for backtraces. 47type location struct { 48 pc uintptr 49 filename string 50 function string 51 lineno int 52} 53 54//go:noescape 55//extern runtime_callers 56func c_callers(skip int32, locbuf *location, max int32, keepThunks bool) int32 57 58// callers returns a stack trace of the current goroutine. 59// The gc version of callers takes []uintptr, but we take []location. 60func callers(skip int, locbuf []location) int { 61 n := c_callers(int32(skip)+1, &locbuf[0], int32(len(locbuf)), false) 62 return int(n) 63} 64 65//go:noescape 66//extern runtime_callersRaw 67func c_callersRaw(pcs *uintptr, max int32) int32 68 69// callersRaw returns a raw (PCs only) stack trace of the current goroutine. 70func callersRaw(pcbuf []uintptr) int { 71 n := c_callersRaw(&pcbuf[0], int32(len(pcbuf))) 72 return int(n) 73} 74 75// traceback prints a traceback of the current goroutine. 76// This differs from the gc version, which is given pc, sp, lr and g and 77// can print a traceback of any goroutine. 78func traceback(skip int32) { 79 var locbuf [100]location 80 c := c_callers(skip+1, &locbuf[0], int32(len(locbuf)), false) 81 gp := getg() 82 printtrace(locbuf[:c], gp) 83 printcreatedby(gp) 84 85 if gp.ancestors == nil { 86 return 87 } 88 for _, ancestor := range *gp.ancestors { 89 printAncestorTraceback(ancestor) 90 } 91} 92 93// printAncestorTraceback prints the traceback of the given ancestor. 94func printAncestorTraceback(ancestor ancestorInfo) { 95 print("[originating from goroutine ", ancestor.goid, "]:\n") 96 for fidx, pc := range ancestor.pcs { 97 function, file, line, _ := funcfileline(pc, -1, false) 98 if showfuncinfo(function, fidx == 0) { 99 printAncestorTracebackFuncInfo(function, file, line, pc) 100 } 101 } 102 if len(ancestor.pcs) == _TracebackMaxFrames { 103 print("...additional frames elided...\n") 104 } 105 // Show what created goroutine, except main goroutine (goid 1). 106 function, file, line, _ := funcfileline(ancestor.gopc, -1, false) 107 if function != "" && showfuncinfo(function, false) && ancestor.goid != 1 { 108 printcreatedby1(function, file, line, funcentry(ancestor.gopc), ancestor.gopc) 109 } 110} 111 112// printAncestorTraceback prints the given function info at a given pc 113// within an ancestor traceback. The precision of this info is reduced 114// due to only have access to the pcs at the time of the caller 115// goroutine being created. 116func printAncestorTracebackFuncInfo(name, file string, line int, pc uintptr) { 117 if name == "runtime.gopanic" { 118 name = "panic" 119 } 120 print(name, "(...)\n") 121 print("\t", file, ":", line) 122 entry := funcentry(pc) 123 if pc > entry { 124 print(" +", hex(pc-entry)) 125 } 126 print("\n") 127} 128 129// printtrace prints a traceback from locbuf. 130func printtrace(locbuf []location, gp *g) { 131 nprint := 0 132 for i := range locbuf { 133 if showframe(locbuf[i].function, gp, nprint == 0) { 134 name := locbuf[i].function 135 if name == "runtime.gopanic" { 136 name = "panic" 137 } 138 print(name, "\n\t", locbuf[i].filename, ":", locbuf[i].lineno, "\n") 139 nprint++ 140 } 141 } 142} 143 144// showframe returns whether to print a frame in a traceback. 145// name is the function name. 146func showframe(name string, gp *g, firstFrame bool) bool { 147 g := getg() 148 if g.m.throwing > 0 && gp != nil && (gp == g.m.curg || gp == g.m.caughtsig.ptr()) { 149 return true 150 } 151 return showfuncinfo(name, firstFrame) 152} 153 154func showfuncinfo(name string, firstFrame bool) bool { 155 // Gccgo can trace back through C functions called via cgo. 156 // We want to print those in the traceback. 157 // But unless GOTRACEBACK > 1 (checked below), still skip 158 // internal C functions and cgo-generated functions. 159 if name != "" && bytealg.IndexByteString(name, '.') < 0 && !hasPrefix(name, "__go_") && !hasPrefix(name, "_cgo_") { 160 return true 161 } 162 163 level, _, _ := gotraceback() 164 if level > 1 { 165 // Show all frames. 166 return true 167 } 168 169 if name == "" { 170 return false 171 } 172 173 // Special case: always show runtime.gopanic frame 174 // in the middle of a stack trace, so that we can 175 // see the boundary between ordinary code and 176 // panic-induced deferred code. 177 // See golang.org/issue/5832. 178 if name == "runtime.gopanic" && !firstFrame { 179 return true 180 } 181 182 return bytealg.IndexByteString(name, '.') >= 0 && (!hasPrefix(name, "runtime.") || isExportedRuntime(name)) 183} 184 185// isExportedRuntime reports whether name is an exported runtime function. 186// It is only for runtime functions, so ASCII A-Z is fine. Here also check 187// for mangled functions from runtime/<...>, which will be prefixed with 188// "runtime_1". 189func isExportedRuntime(name string) bool { 190 const n = len("runtime.") 191 if hasPrefix(name, "runtime_1") { 192 return true 193 } 194 return len(name) > n && name[:n] == "runtime." && 'A' <= name[n] && name[n] <= 'Z' 195} 196 197var gStatusStrings = [...]string{ 198 _Gidle: "idle", 199 _Grunnable: "runnable", 200 _Grunning: "running", 201 _Gsyscall: "syscall", 202 _Gwaiting: "waiting", 203 _Gdead: "dead", 204 _Gcopystack: "copystack", 205 _Gexitingsyscall: "exiting syscall", 206} 207 208func goroutineheader(gp *g) { 209 gpstatus := readgstatus(gp) 210 211 isScan := gpstatus&_Gscan != 0 212 gpstatus &^= _Gscan // drop the scan bit 213 214 // Basic string status 215 var status string 216 if 0 <= gpstatus && gpstatus < uint32(len(gStatusStrings)) { 217 status = gStatusStrings[gpstatus] 218 } else { 219 status = "???" 220 } 221 222 // Override. 223 if gpstatus == _Gwaiting && gp.waitreason != waitReasonZero { 224 status = gp.waitreason.String() 225 } 226 227 // approx time the G is blocked, in minutes 228 var waitfor int64 229 if (gpstatus == _Gwaiting || gpstatus == _Gsyscall) && gp.waitsince != 0 { 230 waitfor = (nanotime() - gp.waitsince) / 60e9 231 } 232 print("goroutine ", gp.goid, " [", status) 233 if isScan { 234 print(" (scan)") 235 } 236 if waitfor >= 1 { 237 print(", ", waitfor, " minutes") 238 } 239 if gp.lockedm != 0 { 240 print(", locked to thread") 241 } 242 print("]:\n") 243} 244 245// isSystemGoroutine reports whether the goroutine g must be omitted 246// in stack dumps and deadlock detector. This is any goroutine that 247// starts at a runtime.* entry point, except for runtime.main and 248// sometimes runtime.runfinq. 249// 250// If fixed is true, any goroutine that can vary between user and 251// system (that is, the finalizer goroutine) is considered a user 252// goroutine. 253func isSystemGoroutine(gp *g, fixed bool) bool { 254 if !gp.isSystemGoroutine { 255 return false 256 } 257 if fixed && gp.isFinalizerGoroutine { 258 // This goroutine can vary. In fixed mode, 259 // always consider it a user goroutine. 260 return false 261 } 262 return true 263} 264 265func tracebackothers(me *g) { 266 var tb tracebackg 267 tb.gp = me 268 269 // The getTraceback function will modify me's stack context. 270 // Preserve it in case we have been called via systemstack. 271 context := me.context 272 stackcontext := me.stackcontext 273 274 level, _, _ := gotraceback() 275 276 // Show the current goroutine first, if we haven't already. 277 g := getg() 278 gp := g.m.curg 279 if gp != nil && gp != me { 280 print("\n") 281 goroutineheader(gp) 282 gp.traceback = (uintptr)(noescape(unsafe.Pointer(&tb))) 283 getTraceback(me, gp) 284 printtrace(tb.locbuf[:tb.c], nil) 285 printcreatedby(gp) 286 } 287 288 lock(&allglock) 289 for _, gp := range allgs { 290 if gp == me || gp == g.m.curg || readgstatus(gp) == _Gdead || isSystemGoroutine(gp, false) && level < 2 { 291 continue 292 } 293 print("\n") 294 goroutineheader(gp) 295 296 // gccgo's only mechanism for doing a stack trace is 297 // _Unwind_Backtrace. And that only works for the 298 // current thread, not for other random goroutines. 299 // So we need to switch context to the goroutine, get 300 // the backtrace, and then switch back. 301 // 302 // This means that if g is running or in a syscall, we 303 // can't reliably print a stack trace. FIXME. 304 305 // Note: gp.m == g.m occurs when tracebackothers is 306 // called from a signal handler initiated during a 307 // systemstack call. The original G is still in the 308 // running state, and we want to print its stack. 309 if gp.m != g.m && readgstatus(gp)&^_Gscan == _Grunning { 310 print("\tgoroutine running on other thread; stack unavailable\n") 311 printcreatedby(gp) 312 } else if readgstatus(gp)&^_Gscan == _Gsyscall { 313 print("\tgoroutine in C code; stack unavailable\n") 314 printcreatedby(gp) 315 } else { 316 gp.traceback = (uintptr)(noescape(unsafe.Pointer(&tb))) 317 getTraceback(me, gp) 318 printtrace(tb.locbuf[:tb.c], nil) 319 printcreatedby(gp) 320 } 321 } 322 unlock(&allglock) 323 324 me.context = context 325 me.stackcontext = stackcontext 326} 327