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 "runtime/internal/sys" 12 "unsafe" 13) 14 15func 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 22 } 23 function, file, line, _ := funcfileline(tracepc, -1, false) 24 if function != "" && showframe(function, gp, false) && gp.goid != 1 { 25 printcreatedby1(function, file, line, entry, pc) 26 } 27} 28 29func 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)) 34 } 35 print("\n") 36} 37 38// tracebackg is used to collect stack traces from other goroutines. 39type tracebackg struct { 40 gp *g 41 locbuf [_TracebackMaxFrames]location 42 c int 43} 44 45// location is a location in the program, used for backtraces. 46type location struct { 47 pc uintptr 48 filename string 49 function string 50 lineno int 51} 52 53//go:noescape 54//extern runtime_callers 55func c_callers(skip int32, locbuf *location, max int32, keepThunks bool) int32 56 57// callers returns a stack trace of the current goroutine. 58// The gc version of callers takes []uintptr, but we take []location. 59func callers(skip int, locbuf []location) int { 60 n := c_callers(int32(skip)+1, &locbuf[0], int32(len(locbuf)), false) 61 return int(n) 62} 63 64//go:noescape 65//extern runtime_callersRaw 66func c_callersRaw(pcs *uintptr, max int32) int32 67 68// callersRaw returns a raw (PCs only) stack trace of the current goroutine. 69func callersRaw(pcbuf []uintptr) int { 70 n := c_callersRaw(&pcbuf[0], int32(len(pcbuf))) 71 return int(n) 72} 73 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. 77func traceback(skip int32) { 78 var locbuf [100]location 79 c := c_callers(skip+1, &locbuf[0], int32(len(locbuf)), false) 80 gp := getg() 81 printtrace(locbuf[:c], gp) 82 printcreatedby(gp) 83 84 if gp.ancestors == nil { 85 return 86 } 87 for _, ancestor := range *gp.ancestors { 88 printAncestorTraceback(ancestor) 89 } 90} 91 92// printAncestorTraceback prints the traceback of the given ancestor. 93func 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, false) 97 if showfuncinfo(function, fidx == 0) { 98 printAncestorTracebackFuncInfo(function, file, line, pc) 99 } 100 } 101 if len(ancestor.pcs) == _TracebackMaxFrames { 102 print("...additional frames elided...\n") 103 } 104 // Show what created goroutine, except main goroutine (goid 1). 105 function, file, line, _ := funcfileline(ancestor.gopc, -1, false) 106 if function != "" && showfuncinfo(function, false) && ancestor.goid != 1 { 107 printcreatedby1(function, file, line, funcentry(ancestor.gopc), ancestor.gopc) 108 } 109} 110 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. 115func printAncestorTracebackFuncInfo(name, file string, line int, pc uintptr) { 116 if name == "runtime.gopanic" { 117 name = "panic" 118 } 119 print(name, "(...)\n") 120 print("\t", file, ":", line) 121 entry := funcentry(pc) 122 if pc > entry { 123 print(" +", hex(pc-entry)) 124 } 125 print("\n") 126} 127 128// printtrace prints a traceback from locbuf. 129func printtrace(locbuf []location, gp *g) { 130 nprint := 0 131 for i := range locbuf { 132 if showframe(locbuf[i].function, gp, nprint == 0) { 133 name := locbuf[i].function 134 if name == "runtime.gopanic" { 135 name = "panic" 136 } 137 print(name, "\n\t", locbuf[i].filename, ":", locbuf[i].lineno, "\n") 138 nprint++ 139 } 140 } 141} 142 143// showframe returns whether to print a frame in a traceback. 144// name is the function name. 145func showframe(name string, gp *g, firstFrame bool) bool { 146 g := getg() 147 if g.m.throwing > 0 && gp != nil && (gp == g.m.curg || gp == g.m.caughtsig.ptr()) { 148 return true 149 } 150 return showfuncinfo(name, firstFrame) 151} 152 153func 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_") { 159 return true 160 } 161 162 level, _, _ := gotraceback() 163 if level > 1 { 164 // Show all frames. 165 return true 166 } 167 168 if name == "" { 169 return false 170 } 171 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 { 178 return true 179 } 180 181 return contains(name, ".") && (!hasPrefix(name, "runtime.") || isExportedRuntime(name)) 182} 183 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 187// "runtime..z2f". 188func isExportedRuntime(name string) bool { 189 const n = len("runtime.") 190 if hasPrefix(name, "runtime..z2f") { 191 return true 192 } 193 return len(name) > n && name[:n] == "runtime." && 'A' <= name[n] && name[n] <= 'Z' 194} 195 196var gStatusStrings = [...]string{ 197 _Gidle: "idle", 198 _Grunnable: "runnable", 199 _Grunning: "running", 200 _Gsyscall: "syscall", 201 _Gwaiting: "waiting", 202 _Gdead: "dead", 203 _Gcopystack: "copystack", 204 _Gexitingsyscall: "exiting syscall", 205} 206 207func goroutineheader(gp *g) { 208 gpstatus := readgstatus(gp) 209 210 isScan := gpstatus&_Gscan != 0 211 gpstatus &^= _Gscan // drop the scan bit 212 213 // Basic string status 214 var status string 215 if 0 <= gpstatus && gpstatus < uint32(len(gStatusStrings)) { 216 status = gStatusStrings[gpstatus] 217 } else { 218 status = "???" 219 } 220 221 // Override. 222 if gpstatus == _Gwaiting && gp.waitreason != waitReasonZero { 223 status = gp.waitreason.String() 224 } 225 226 // approx time the G is blocked, in minutes 227 var waitfor int64 228 if (gpstatus == _Gwaiting || gpstatus == _Gsyscall) && gp.waitsince != 0 { 229 waitfor = (nanotime() - gp.waitsince) / 60e9 230 } 231 print("goroutine ", gp.goid, " [", status) 232 if isScan { 233 print(" (scan)") 234 } 235 if waitfor >= 1 { 236 print(", ", waitfor, " minutes") 237 } 238 if gp.lockedm != 0 { 239 print(", locked to thread") 240 } 241 print("]:\n") 242} 243 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. 248// 249// If fixed is true, any goroutine that can vary between user and 250// system (that is, the finalizer goroutine) is considered a user 251// goroutine. 252func isSystemGoroutine(gp *g, fixed bool) bool { 253 if !gp.isSystemGoroutine { 254 return false 255 } 256 if fixed && gp.isFinalizerGoroutine { 257 // This goroutine can vary. In fixed mode, 258 // always consider it a user goroutine. 259 return false 260 } 261 return true 262} 263 264func tracebackothers(me *g) { 265 var tb tracebackg 266 tb.gp = me 267 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 272 273 level, _, _ := gotraceback() 274 275 // Show the current goroutine first, if we haven't already. 276 g := getg() 277 gp := g.m.curg 278 if gp != nil && gp != me { 279 print("\n") 280 goroutineheader(gp) 281 gp.traceback = (uintptr)(noescape(unsafe.Pointer(&tb))) 282 getTraceback(me, gp) 283 printtrace(tb.locbuf[:tb.c], nil) 284 printcreatedby(gp) 285 } 286 287 lock(&allglock) 288 for _, gp := range allgs { 289 if gp == me || gp == g.m.curg || readgstatus(gp) == _Gdead || isSystemGoroutine(gp, false) && level < 2 { 290 continue 291 } 292 print("\n") 293 goroutineheader(gp) 294 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. 300 // 301 // This means that if g is running or in a syscall, we 302 // can't reliably print a stack trace. FIXME. 303 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") 310 printcreatedby(gp) 311 } else if readgstatus(gp)&^_Gscan == _Gsyscall { 312 print("\tgoroutine in C code; stack unavailable\n") 313 printcreatedby(gp) 314 } else { 315 gp.traceback = (uintptr)(noescape(unsafe.Pointer(&tb))) 316 getTraceback(me, gp) 317 printtrace(tb.locbuf[:tb.c], nil) 318 printcreatedby(gp) 319 } 320 } 321 unlock(&allglock) 322 323 me.context = context 324 me.stackcontext = stackcontext 325} 326