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.
5 // Traceback support for gccgo.
6 // The actual traceback code is written in C.
11 "runtime/internal/sys"
15 func printcreatedby(gp
*g
) {
16 // Show what created goroutine, except main goroutine (goid 1).
18 tracepc
:= pc
// back up to CALL instruction for funcfileline.
19 entry
:= funcentry(tracepc
)
20 if entry
!= 0 && tracepc
> entry
{
21 tracepc
-= sys
.PCQuantum
23 function
, file
, line
:= funcfileline(tracepc
, -1)
24 if function
!= "" && showframe(function
, gp
) && gp
.goid
!= 1 {
25 print("created by ", function
, "\n")
26 print("\t", file
, ":", line
)
27 if entry
!= 0 && pc
> entry
{
28 print(" +", hex(pc
-entry
))
34 // tracebackg is used to collect stack traces from other goroutines.
35 type tracebackg
struct {
37 locbuf
[_TracebackMaxFrames
]location
41 // location is a location in the program, used for backtraces.
42 type location
struct {
50 //extern runtime_callers
51 func c_callers(skip
int32, locbuf
*location
, max
int32, keepThunks
bool) int32
53 // callers returns a stack trace of the current goroutine.
54 // The gc version of callers takes []uintptr, but we take []location.
55 func callers(skip
int, locbuf
[]location
) int {
56 n
:= c_callers(int32(skip
)+1, &locbuf
[0], int32(len(locbuf
)), false)
60 // traceback prints a traceback of the current goroutine.
61 // This differs from the gc version, which is given pc, sp, lr and g and
62 // can print a traceback of any goroutine.
63 func traceback(skip
int32) {
64 var locbuf
[100]location
65 c
:= c_callers(skip
+1, &locbuf
[0], int32(len(locbuf
)), false)
66 printtrace(locbuf
[:c
], getg())
67 printcreatedby(getg())
70 // printtrace prints a traceback from locbuf.
71 func printtrace(locbuf
[]location
, gp
*g
) {
72 for i
:= range locbuf
{
73 if showframe(locbuf
[i
].function
, gp
) {
74 name
:= locbuf
[i
].function
75 if name
== "runtime.gopanic" {
78 print(name
, "\n\t", locbuf
[i
].filename
, ":", locbuf
[i
].lineno
, "\n")
83 // showframe returns whether to print a frame in a traceback.
84 // name is the function name.
85 func showframe(name
string, gp
*g
) bool {
87 if g
.m
.throwing
> 0 && gp
!= nil && (gp
== g
.m
.curg || gp
== g
.m
.caughtsig
.ptr()) {
91 // Gccgo can trace back through C functions called via cgo.
92 // We want to print those in the traceback.
93 // But unless GOTRACEBACK > 1 (checked below), still skip
94 // internal C functions and cgo-generated functions.
95 if name
!= "" && !contains(name
, ".") && !hasprefix(name
, "__go_") && !hasprefix(name
, "_cgo_") {
99 level
, _
, _
:= gotraceback()
101 // Special case: always show runtime.gopanic frame, so that we can
102 // see where a panic started in the middle of a stack trace.
103 // See golang.org/issue/5832.
104 // __go_panic is the current gccgo name.
105 if name
== "runtime.gopanic" || name
== "__go_panic" {
109 return level
> 1 ||
contains(name
, ".") && (!hasprefix(name
, "runtime.") ||
isExportedRuntime(name
))
112 // isExportedRuntime reports whether name is an exported runtime function.
113 // It is only for runtime functions, so ASCII A-Z is fine. Here also check
114 // for mangled functions from runtime/<...>, which will be prefixed with
116 func isExportedRuntime(name
string) bool {
117 const n
= len("runtime.")
118 if hasprefix(name
, "runtime..z2f") {
121 return len(name
) > n
&& name
[:n
] == "runtime." && 'A' <= name
[n
] && name
[n
] <= 'Z'
124 var gStatusStrings
= [...]string{
126 _Grunnable
: "runnable",
127 _Grunning
: "running",
128 _Gsyscall
: "syscall",
129 _Gwaiting
: "waiting",
131 _Gcopystack
: "copystack",
134 func goroutineheader(gp
*g
) {
135 gpstatus
:= readgstatus(gp
)
137 isScan
:= gpstatus
&_Gscan
!= 0
138 gpstatus
&^= _Gscan
// drop the scan bit
140 // Basic string status
142 if 0 <= gpstatus
&& gpstatus
< uint32(len(gStatusStrings
)) {
143 status
= gStatusStrings
[gpstatus
]
149 if gpstatus
== _Gwaiting
&& gp
.waitreason
!= waitReasonZero
{
150 status
= gp
.waitreason
.String()
153 // approx time the G is blocked, in minutes
155 if (gpstatus
== _Gwaiting || gpstatus
== _Gsyscall
) && gp
.waitsince
!= 0 {
156 waitfor
= (nanotime() - gp
.waitsince
) / 60e9
158 print("goroutine ", gp
.goid
, " [", status
)
163 print(", ", waitfor
, " minutes")
166 print(", locked to thread")
171 // isSystemGoroutine reports whether the goroutine g must be omitted in
172 // stack dumps and deadlock detector.
173 func isSystemGoroutine(gp
*g
) bool {
174 return gp
.isSystemGoroutine
177 func tracebackothers(me
*g
) {
181 // The getTraceback function will modify me's stack context.
182 // Preserve it in case we have been called via systemstack.
183 context
:= me
.context
184 stackcontext
:= me
.stackcontext
186 level
, _
, _
:= gotraceback()
188 // Show the current goroutine first, if we haven't already.
191 if gp
!= nil && gp
!= me
{
194 gp
.traceback
= (uintptr)(noescape(unsafe
.Pointer(&tb
)))
196 printtrace(tb
.locbuf
[:tb
.c
], nil)
201 for _
, gp
:= range allgs
{
202 if gp
== me || gp
== g
.m
.curg ||
readgstatus(gp
) == _Gdead ||
isSystemGoroutine(gp
) && level
< 2 {
208 // gccgo's only mechanism for doing a stack trace is
209 // _Unwind_Backtrace. And that only works for the
210 // current thread, not for other random goroutines.
211 // So we need to switch context to the goroutine, get
212 // the backtrace, and then switch back.
214 // This means that if g is running or in a syscall, we
215 // can't reliably print a stack trace. FIXME.
217 // Note: gp.m == g.m occurs when tracebackothers is
218 // called from a signal handler initiated during a
219 // systemstack call. The original G is still in the
220 // running state, and we want to print its stack.
221 if gp
.m
!= g
.m
&& readgstatus(gp
)&^_Gscan
== _Grunning
{
222 print("\tgoroutine running on other thread; stack unavailable\n")
224 } else if readgstatus(gp
)&^_Gscan
== _Gsyscall
{
225 print("\tgoroutine in C code; stack unavailable\n")
228 gp
.traceback
= (uintptr)(noescape(unsafe
.Pointer(&tb
)))
230 printtrace(tb
.locbuf
[:tb
.c
], nil)
237 me
.stackcontext
= stackcontext