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