4134d28a599c49a7c69fbc02c388c87d63ceaa6b
[platform/upstream/gcc.git] / libgo / go / runtime / traceback_gccgo.go
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
8 package runtime
9
10 import (
11         "runtime/internal/sys"
12         "unsafe"
13 )
14
15 func 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
29 func 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.
39 type 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.
46 type location struct {
47         pc       uintptr
48         filename string
49         function string
50         lineno   int
51 }
52
53 //go:noescape
54 //extern runtime_callers
55 func 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.
59 func 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
66 func c_callersRaw(pcs *uintptr, max int32) int32
67
68 // callersRaw returns a raw (PCs only) stack trace of the current goroutine.
69 func 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.
77 func 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.
93 func 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)
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)
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.
115 func 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.
129 func 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.
145 func 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
153 func 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".
188 func 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
196 var 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
207 func 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.
252 func 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
264 func 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 }