1
0
mirror of https://github.com/golang/go synced 2024-11-07 14:56:16 -07:00

runtime: move cgo traceback into unwinder

Currently, gentraceback's loop ends with a call to tracebackCgoContext
to process cgo frames. This requires spreading various parts of the
printing and pcbuf logic across these two functions.

Clean this up by moving cgo unwinding into unwinder and then lifting
the printing and pcbuf logic from tracebackCgoContext into
gentraceback along with the other printing and pcbuf logic.

Updates #54466.

Change-Id: Ic71afaa5ae110c0ea5be9409e267e4284e36a8c9
Reviewed-on: https://go-review.googlesource.com/c/go/+/468299
Reviewed-by: Michael Pratt <mpratt@google.com>
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
Austin Clements 2023-02-14 11:50:30 -05:00
parent c9b2da3f28
commit 9872428a71

View File

@ -569,6 +569,28 @@ func (u *unwinder) symPC() uintptr {
return u.frame.pc return u.frame.pc
} }
// cgoCallers populates pcBuf with the cgo callers of the current frame using
// the registered cgo unwinder. It returns the number of PCs written to pcBuf.
// If the current frame is not a cgo frame or if there's no registered cgo
// unwinder, it returns 0.
func (u *unwinder) cgoCallers(pcBuf []uintptr) int {
if cgoTraceback == nil || u.frame.fn.funcID != funcID_cgocallback || u.cgoCtxt < 0 {
// We don't have a cgo unwinder (typical case), or we do but we're not
// in a cgo frame or we're out of cgo context.
return 0
}
ctxt := u.g.ptr().cgoCtxt[u.cgoCtxt]
u.cgoCtxt--
cgoContextPCs(ctxt, pcBuf)
for i, pc := range pcBuf {
if pc == 0 {
return i
}
}
return len(pcBuf)
}
// Generic traceback. Handles runtime stack prints (pcbuf == nil), // Generic traceback. Handles runtime stack prints (pcbuf == nil),
// and the runtime.Callers function (pcbuf != nil). // and the runtime.Callers function (pcbuf != nil).
// A little clunky to merge these, but avoids // A little clunky to merge these, but avoids
@ -605,10 +627,13 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
nprint := 0 nprint := 0
n := 0 n := 0
var cgoBuf [32]uintptr
for ; n < max && u.valid(); u.next() { for ; n < max && u.valid(); u.next() {
frame := &u.frame frame := &u.frame
f := frame.fn f := frame.fn
cgoN := u.cgoCallers(cgoBuf[:])
if pcbuf != nil { if pcbuf != nil {
// TODO: Why does cache escape? (Same below) // TODO: Why does cache escape? (Same below)
for iu, uf := newInlineUnwinder(f, u.symPC(), noEscapePtr(&u.cache)); uf.valid(); uf = iu.next(uf) { for iu, uf := newInlineUnwinder(f, u.symPC(), noEscapePtr(&u.cache)); uf.valid(); uf = iu.next(uf) {
@ -626,6 +651,13 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
} }
u.calleeFuncID = sf.funcID u.calleeFuncID = sf.funcID
} }
// Add cgo frames
if skip == 0 { // skip only applies to Go frames
for i := 0; i < cgoN && n < max; i++ {
(*[1 << 20]uintptr)(unsafe.Pointer(pcbuf))[n] = cgoBuf[i]
n++
}
}
n-- // offset n++ below n-- // offset n++ below
} }
@ -669,18 +701,31 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
nprint++ nprint++
} }
} }
} // Print cgo frames.
n++ if cgoN > 0 {
var arg cgoSymbolizerArg
if f.funcID == funcID_cgocallback && u.cgoCtxt >= 0 { anySymbolized := false
ctxt := gp.cgoCtxt[u.cgoCtxt] for _, pc := range cgoBuf[:cgoN] {
u.cgoCtxt-- if n >= max {
break
// skip only applies to Go frames. }
if skip == 0 { if cgoSymbolizer == nil {
n = tracebackCgoContext(pcbuf, printing, ctxt, n, max) print("non-Go function at pc=", hex(pc), "\n")
} else {
c := printOneCgoTraceback(pc, max-n, &arg)
n += c - 1 // +1 a few lines down
anySymbolized = true
}
nprint++
}
if anySymbolized {
// Free symbolization state.
arg.pc = 0
callCgoSymbolizer(&arg)
}
} }
} }
n++
} }
if printing { if printing {
@ -791,39 +836,6 @@ printloop:
} }
} }
// tracebackCgoContext handles tracing back a cgo context value, from
// the context argument to setCgoTraceback, for the gentraceback
// function. It returns the new value of n.
func tracebackCgoContext(pcbuf *uintptr, printing bool, ctxt uintptr, n, max int) int {
var cgoPCs [32]uintptr
cgoContextPCs(ctxt, cgoPCs[:])
var arg cgoSymbolizerArg
anySymbolized := false
for _, pc := range cgoPCs {
if pc == 0 || n >= max {
break
}
if pcbuf != nil {
(*[1 << 20]uintptr)(unsafe.Pointer(pcbuf))[n] = pc
}
if printing {
if cgoSymbolizer == nil {
print("non-Go function at pc=", hex(pc), "\n")
} else {
c := printOneCgoTraceback(pc, max-n, &arg)
n += c - 1 // +1 a few lines down
anySymbolized = true
}
}
n++
}
if anySymbolized {
arg.pc = 0
callCgoSymbolizer(&arg)
}
return n
}
func printcreatedby(gp *g) { func printcreatedby(gp *g) {
// Show what created goroutine, except main goroutine (goid 1). // Show what created goroutine, except main goroutine (goid 1).
pc := gp.gopc pc := gp.gopc