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