Skip to content

Commit 9872428

Browse files
committed
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 <[email protected]> Run-TryBot: Austin Clements <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent c9b2da3 commit 9872428

File tree

1 file changed

+55
-43
lines changed

1 file changed

+55
-43
lines changed

src/runtime/traceback.go

Lines changed: 55 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,28 @@ func (u *unwinder) symPC() uintptr {
569569
return u.frame.pc
570570
}
571571

572+
// cgoCallers populates pcBuf with the cgo callers of the current frame using
573+
// the registered cgo unwinder. It returns the number of PCs written to pcBuf.
574+
// If the current frame is not a cgo frame or if there's no registered cgo
575+
// unwinder, it returns 0.
576+
func (u *unwinder) cgoCallers(pcBuf []uintptr) int {
577+
if cgoTraceback == nil || u.frame.fn.funcID != funcID_cgocallback || u.cgoCtxt < 0 {
578+
// We don't have a cgo unwinder (typical case), or we do but we're not
579+
// in a cgo frame or we're out of cgo context.
580+
return 0
581+
}
582+
583+
ctxt := u.g.ptr().cgoCtxt[u.cgoCtxt]
584+
u.cgoCtxt--
585+
cgoContextPCs(ctxt, pcBuf)
586+
for i, pc := range pcBuf {
587+
if pc == 0 {
588+
return i
589+
}
590+
}
591+
return len(pcBuf)
592+
}
593+
572594
// Generic traceback. Handles runtime stack prints (pcbuf == nil),
573595
// and the runtime.Callers function (pcbuf != nil).
574596
// 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
605627

606628
nprint := 0
607629
n := 0
630+
var cgoBuf [32]uintptr
608631
for ; n < max && u.valid(); u.next() {
609632
frame := &u.frame
610633
f := frame.fn
611634

635+
cgoN := u.cgoCallers(cgoBuf[:])
636+
612637
if pcbuf != nil {
613638
// TODO: Why does cache escape? (Same below)
614639
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
626651
}
627652
u.calleeFuncID = sf.funcID
628653
}
654+
// Add cgo frames
655+
if skip == 0 { // skip only applies to Go frames
656+
for i := 0; i < cgoN && n < max; i++ {
657+
(*[1 << 20]uintptr)(unsafe.Pointer(pcbuf))[n] = cgoBuf[i]
658+
n++
659+
}
660+
}
629661
n-- // offset n++ below
630662
}
631663

@@ -669,18 +701,31 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
669701
nprint++
670702
}
671703
}
672-
}
673-
n++
674-
675-
if f.funcID == funcID_cgocallback && u.cgoCtxt >= 0 {
676-
ctxt := gp.cgoCtxt[u.cgoCtxt]
677-
u.cgoCtxt--
678-
679-
// skip only applies to Go frames.
680-
if skip == 0 {
681-
n = tracebackCgoContext(pcbuf, printing, ctxt, n, max)
704+
// Print cgo frames.
705+
if cgoN > 0 {
706+
var arg cgoSymbolizerArg
707+
anySymbolized := false
708+
for _, pc := range cgoBuf[:cgoN] {
709+
if n >= max {
710+
break
711+
}
712+
if cgoSymbolizer == nil {
713+
print("non-Go function at pc=", hex(pc), "\n")
714+
} else {
715+
c := printOneCgoTraceback(pc, max-n, &arg)
716+
n += c - 1 // +1 a few lines down
717+
anySymbolized = true
718+
}
719+
nprint++
720+
}
721+
if anySymbolized {
722+
// Free symbolization state.
723+
arg.pc = 0
724+
callCgoSymbolizer(&arg)
725+
}
682726
}
683727
}
728+
n++
684729
}
685730

686731
if printing {
@@ -791,39 +836,6 @@ printloop:
791836
}
792837
}
793838

794-
// tracebackCgoContext handles tracing back a cgo context value, from
795-
// the context argument to setCgoTraceback, for the gentraceback
796-
// function. It returns the new value of n.
797-
func tracebackCgoContext(pcbuf *uintptr, printing bool, ctxt uintptr, n, max int) int {
798-
var cgoPCs [32]uintptr
799-
cgoContextPCs(ctxt, cgoPCs[:])
800-
var arg cgoSymbolizerArg
801-
anySymbolized := false
802-
for _, pc := range cgoPCs {
803-
if pc == 0 || n >= max {
804-
break
805-
}
806-
if pcbuf != nil {
807-
(*[1 << 20]uintptr)(unsafe.Pointer(pcbuf))[n] = pc
808-
}
809-
if printing {
810-
if cgoSymbolizer == nil {
811-
print("non-Go function at pc=", hex(pc), "\n")
812-
} else {
813-
c := printOneCgoTraceback(pc, max-n, &arg)
814-
n += c - 1 // +1 a few lines down
815-
anySymbolized = true
816-
}
817-
}
818-
n++
819-
}
820-
if anySymbolized {
821-
arg.pc = 0
822-
callCgoSymbolizer(&arg)
823-
}
824-
return n
825-
}
826-
827839
func printcreatedby(gp *g) {
828840
// Show what created goroutine, except main goroutine (goid 1).
829841
pc := gp.gopc

0 commit comments

Comments
 (0)