| // Copyright 2016 The Go Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style | 
 | // license that can be found in the LICENSE file. | 
 |  | 
 | // Traceback support for gccgo. | 
 | // The actual traceback code is written in C. | 
 |  | 
 | package runtime | 
 |  | 
 | import ( | 
 | 	"internal/bytealg" | 
 | 	"runtime/internal/sys" | 
 | 	"unsafe" | 
 | ) | 
 |  | 
 | func printcreatedby(gp *g) { | 
 | 	// Show what created goroutine, except main goroutine (goid 1). | 
 | 	pc := gp.gopc | 
 | 	tracepc := pc // back up to CALL instruction for funcfileline. | 
 | 	entry := funcentry(tracepc) | 
 | 	if entry != 0 && tracepc > entry { | 
 | 		tracepc -= sys.PCQuantum | 
 | 	} | 
 | 	function, file, line, _ := funcfileline(tracepc, -1, false) | 
 | 	if function != "" && showframe(function, gp, false) && gp.goid != 1 { | 
 | 		printcreatedby1(function, file, line, entry, pc) | 
 | 	} | 
 | } | 
 |  | 
 | func printcreatedby1(function, file string, line int, entry, pc uintptr) { | 
 | 	print("created by ", function, "\n") | 
 | 	print("\t", file, ":", line) | 
 | 	if entry != 0 && pc > entry { | 
 | 		print(" +", hex(pc-entry)) | 
 | 	} | 
 | 	print("\n") | 
 | } | 
 |  | 
 | // tracebackg is used to collect stack traces from other goroutines. | 
 | type tracebackg struct { | 
 | 	gp     *g | 
 | 	locbuf [_TracebackMaxFrames]location | 
 | 	c      int | 
 | } | 
 |  | 
 | // location is a location in the program, used for backtraces. | 
 | type location struct { | 
 | 	pc       uintptr | 
 | 	filename string | 
 | 	function string | 
 | 	lineno   int | 
 | } | 
 |  | 
 | //go:noescape | 
 | //extern runtime_callers | 
 | func c_callers(skip int32, locbuf *location, max int32, keepThunks bool) int32 | 
 |  | 
 | // callers returns a stack trace of the current goroutine. | 
 | // The gc version of callers takes []uintptr, but we take []location. | 
 | func callers(skip int, locbuf []location) int { | 
 | 	n := c_callers(int32(skip)+1, &locbuf[0], int32(len(locbuf)), false) | 
 | 	return int(n) | 
 | } | 
 |  | 
 | //go:noescape | 
 | //extern runtime_callersRaw | 
 | func c_callersRaw(pcs *uintptr, max int32) int32 | 
 |  | 
 | // callersRaw returns a raw (PCs only) stack trace of the current goroutine. | 
 | func callersRaw(pcbuf []uintptr) int { | 
 | 	n := c_callersRaw(&pcbuf[0], int32(len(pcbuf))) | 
 | 	return int(n) | 
 | } | 
 |  | 
 | // traceback prints a traceback of the current goroutine. | 
 | // This differs from the gc version, which is given pc, sp, lr and g and | 
 | // can print a traceback of any goroutine. | 
 | func traceback(skip int32) { | 
 | 	var locbuf [100]location | 
 | 	c := c_callers(skip+1, &locbuf[0], int32(len(locbuf)), false) | 
 | 	gp := getg() | 
 | 	printtrace(locbuf[:c], gp) | 
 | 	printcreatedby(gp) | 
 |  | 
 | 	if gp.ancestors == nil { | 
 | 		return | 
 | 	} | 
 | 	for _, ancestor := range *gp.ancestors { | 
 | 		printAncestorTraceback(ancestor) | 
 | 	} | 
 | } | 
 |  | 
 | // printAncestorTraceback prints the traceback of the given ancestor. | 
 | func printAncestorTraceback(ancestor ancestorInfo) { | 
 | 	print("[originating from goroutine ", ancestor.goid, "]:\n") | 
 | 	for fidx, pc := range ancestor.pcs { | 
 | 		function, file, line, _ := funcfileline(pc, -1, false) | 
 | 		if showfuncinfo(function, fidx == 0) { | 
 | 			printAncestorTracebackFuncInfo(function, file, line, pc) | 
 | 		} | 
 | 	} | 
 | 	if len(ancestor.pcs) == _TracebackMaxFrames { | 
 | 		print("...additional frames elided...\n") | 
 | 	} | 
 | 	// Show what created goroutine, except main goroutine (goid 1). | 
 | 	function, file, line, _ := funcfileline(ancestor.gopc, -1, false) | 
 | 	if function != "" && showfuncinfo(function, false) && ancestor.goid != 1 { | 
 | 		printcreatedby1(function, file, line, funcentry(ancestor.gopc), ancestor.gopc) | 
 | 	} | 
 | } | 
 |  | 
 | // printAncestorTraceback prints the given function info at a given pc | 
 | // within an ancestor traceback. The precision of this info is reduced | 
 | // due to only have access to the pcs at the time of the caller | 
 | // goroutine being created. | 
 | func printAncestorTracebackFuncInfo(name, file string, line int, pc uintptr) { | 
 | 	if name == "runtime.gopanic" { | 
 | 		name = "panic" | 
 | 	} | 
 | 	print(name, "(...)\n") | 
 | 	print("\t", file, ":", line) | 
 | 	entry := funcentry(pc) | 
 | 	if pc > entry { | 
 | 		print(" +", hex(pc-entry)) | 
 | 	} | 
 | 	print("\n") | 
 | } | 
 |  | 
 | // printtrace prints a traceback from locbuf. | 
 | func printtrace(locbuf []location, gp *g) { | 
 | 	nprint := 0 | 
 | 	for i := range locbuf { | 
 | 		if showframe(locbuf[i].function, gp, nprint == 0) { | 
 | 			name := locbuf[i].function | 
 | 			if name == "runtime.gopanic" { | 
 | 				name = "panic" | 
 | 			} | 
 | 			print(name, "\n\t", locbuf[i].filename, ":", locbuf[i].lineno, "\n") | 
 | 			nprint++ | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | // showframe returns whether to print a frame in a traceback. | 
 | // name is the function name. | 
 | func showframe(name string, gp *g, firstFrame bool) bool { | 
 | 	g := getg() | 
 | 	if g.m.throwing > 0 && gp != nil && (gp == g.m.curg || gp == g.m.caughtsig.ptr()) { | 
 | 		return true | 
 | 	} | 
 | 	return showfuncinfo(name, firstFrame) | 
 | } | 
 |  | 
 | func showfuncinfo(name string, firstFrame bool) bool { | 
 | 	// Gccgo can trace back through C functions called via cgo. | 
 | 	// We want to print those in the traceback. | 
 | 	// But unless GOTRACEBACK > 1 (checked below), still skip | 
 | 	// internal C functions and cgo-generated functions. | 
 | 	if name != "" && bytealg.IndexByteString(name, '.') < 0 && !hasPrefix(name, "__go_") && !hasPrefix(name, "_cgo_") { | 
 | 		return true | 
 | 	} | 
 |  | 
 | 	level, _, _ := gotraceback() | 
 | 	if level > 1 { | 
 | 		// Show all frames. | 
 | 		return true | 
 | 	} | 
 |  | 
 | 	if name == "" { | 
 | 		return false | 
 | 	} | 
 |  | 
 | 	// Special case: always show runtime.gopanic frame | 
 | 	// in the middle of a stack trace, so that we can | 
 | 	// see the boundary between ordinary code and | 
 | 	// panic-induced deferred code. | 
 | 	// See golang.org/issue/5832. | 
 | 	if name == "runtime.gopanic" && !firstFrame { | 
 | 		return true | 
 | 	} | 
 |  | 
 | 	return bytealg.IndexByteString(name, '.') >= 0 && (!hasPrefix(name, "runtime.") || isExportedRuntime(name)) | 
 | } | 
 |  | 
 | // isExportedRuntime reports whether name is an exported runtime function. | 
 | // It is only for runtime functions, so ASCII A-Z is fine. Here also check | 
 | // for mangled functions from runtime/<...>, which will be prefixed with | 
 | // "runtime_1". | 
 | func isExportedRuntime(name string) bool { | 
 | 	const n = len("runtime.") | 
 | 	if hasPrefix(name, "runtime_1") { | 
 | 		return true | 
 | 	} | 
 | 	return len(name) > n && name[:n] == "runtime." && 'A' <= name[n] && name[n] <= 'Z' | 
 | } | 
 |  | 
 | var gStatusStrings = [...]string{ | 
 | 	_Gidle:           "idle", | 
 | 	_Grunnable:       "runnable", | 
 | 	_Grunning:        "running", | 
 | 	_Gsyscall:        "syscall", | 
 | 	_Gwaiting:        "waiting", | 
 | 	_Gdead:           "dead", | 
 | 	_Gcopystack:      "copystack", | 
 | 	_Gexitingsyscall: "exiting syscall", | 
 | } | 
 |  | 
 | func goroutineheader(gp *g) { | 
 | 	gpstatus := readgstatus(gp) | 
 |  | 
 | 	isScan := gpstatus&_Gscan != 0 | 
 | 	gpstatus &^= _Gscan // drop the scan bit | 
 |  | 
 | 	// Basic string status | 
 | 	var status string | 
 | 	if 0 <= gpstatus && gpstatus < uint32(len(gStatusStrings)) { | 
 | 		status = gStatusStrings[gpstatus] | 
 | 	} else { | 
 | 		status = "???" | 
 | 	} | 
 |  | 
 | 	// Override. | 
 | 	if gpstatus == _Gwaiting && gp.waitreason != waitReasonZero { | 
 | 		status = gp.waitreason.String() | 
 | 	} | 
 |  | 
 | 	// approx time the G is blocked, in minutes | 
 | 	var waitfor int64 | 
 | 	if (gpstatus == _Gwaiting || gpstatus == _Gsyscall) && gp.waitsince != 0 { | 
 | 		waitfor = (nanotime() - gp.waitsince) / 60e9 | 
 | 	} | 
 | 	print("goroutine ", gp.goid, " [", status) | 
 | 	if isScan { | 
 | 		print(" (scan)") | 
 | 	} | 
 | 	if waitfor >= 1 { | 
 | 		print(", ", waitfor, " minutes") | 
 | 	} | 
 | 	if gp.lockedm != 0 { | 
 | 		print(", locked to thread") | 
 | 	} | 
 | 	print("]:\n") | 
 | } | 
 |  | 
 | // isSystemGoroutine reports whether the goroutine g must be omitted | 
 | // in stack dumps and deadlock detector. This is any goroutine that | 
 | // starts at a runtime.* entry point, except for runtime.main and | 
 | // sometimes runtime.runfinq. | 
 | // | 
 | // If fixed is true, any goroutine that can vary between user and | 
 | // system (that is, the finalizer goroutine) is considered a user | 
 | // goroutine. | 
 | func isSystemGoroutine(gp *g, fixed bool) bool { | 
 | 	if !gp.isSystemGoroutine { | 
 | 		return false | 
 | 	} | 
 | 	if fixed && gp.isFinalizerGoroutine { | 
 | 		// This goroutine can vary. In fixed mode, | 
 | 		// always consider it a user goroutine. | 
 | 		return false | 
 | 	} | 
 | 	return true | 
 | } | 
 |  | 
 | func tracebackothers(me *g) { | 
 | 	var tb tracebackg | 
 | 	tb.gp = me | 
 |  | 
 | 	// The getTraceback function will modify me's stack context. | 
 | 	// Preserve it in case we have been called via systemstack. | 
 | 	context := me.context | 
 | 	stackcontext := me.stackcontext | 
 |  | 
 | 	level, _, _ := gotraceback() | 
 |  | 
 | 	// Show the current goroutine first, if we haven't already. | 
 | 	g := getg() | 
 | 	gp := g.m.curg | 
 | 	if gp != nil && gp != me { | 
 | 		print("\n") | 
 | 		goroutineheader(gp) | 
 | 		gp.traceback = (uintptr)(noescape(unsafe.Pointer(&tb))) | 
 | 		getTraceback(me, gp) | 
 | 		printtrace(tb.locbuf[:tb.c], nil) | 
 | 		printcreatedby(gp) | 
 | 	} | 
 |  | 
 | 	lock(&allglock) | 
 | 	for _, gp := range allgs { | 
 | 		if gp == me || gp == g.m.curg || readgstatus(gp) == _Gdead || isSystemGoroutine(gp, false) && level < 2 { | 
 | 			continue | 
 | 		} | 
 | 		print("\n") | 
 | 		goroutineheader(gp) | 
 |  | 
 | 		// gccgo's only mechanism for doing a stack trace is | 
 | 		// _Unwind_Backtrace.  And that only works for the | 
 | 		// current thread, not for other random goroutines. | 
 | 		// So we need to switch context to the goroutine, get | 
 | 		// the backtrace, and then switch back. | 
 | 		// | 
 | 		// This means that if g is running or in a syscall, we | 
 | 		// can't reliably print a stack trace.  FIXME. | 
 |  | 
 | 		// Note: gp.m == g.m occurs when tracebackothers is | 
 | 		// called from a signal handler initiated during a | 
 | 		// systemstack call. The original G is still in the | 
 | 		// running state, and we want to print its stack. | 
 | 		if gp.m != g.m && readgstatus(gp)&^_Gscan == _Grunning { | 
 | 			print("\tgoroutine running on other thread; stack unavailable\n") | 
 | 			printcreatedby(gp) | 
 | 		} else if readgstatus(gp)&^_Gscan == _Gsyscall { | 
 | 			print("\tgoroutine in C code; stack unavailable\n") | 
 | 			printcreatedby(gp) | 
 | 		} else { | 
 | 			gp.traceback = (uintptr)(noescape(unsafe.Pointer(&tb))) | 
 | 			getTraceback(me, gp) | 
 | 			printtrace(tb.locbuf[:tb.c], nil) | 
 | 			printcreatedby(gp) | 
 | 		} | 
 | 	} | 
 | 	unlock(&allglock) | 
 |  | 
 | 	me.context = context | 
 | 	me.stackcontext = stackcontext | 
 | } |