Skip to content

Commit c9b2da3

Browse files
committed
runtime: simplify traceback PC back-up logic
Updates #54466. Change-Id: If070cf3f484e3e02b8e586bff466e0018b1a1845 Reviewed-on: https://go-review.googlesource.com/c/go/+/468298 Run-TryBot: Austin Clements <[email protected]> Reviewed-by: Michael Pratt <[email protected]> TryBot-Result: Gopher Robot <[email protected]>
1 parent 2d99109 commit c9b2da3

File tree

1 file changed

+31
-18
lines changed

1 file changed

+31
-18
lines changed

src/runtime/traceback.go

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ const (
4545
// unwindTrap indicates that the initial PC and SP are from a trap, not a
4646
// return PC from a call.
4747
//
48+
// The unwindTrap flag is updated during unwinding. If set, frame.pc is the
49+
// address of a faulting instruction instead of the return address of a
50+
// call. It also means the liveness at pc may not be known.
51+
//
4852
// TODO: Distinguish frame.continpc, which is really the stack map PC, from
4953
// the actual continuation PC, which is computed differently depending on
5054
// this flag and a few other things.
@@ -461,6 +465,11 @@ func (u *unwinder) next() {
461465
}
462466

463467
injectedCall := f.funcID == funcID_sigpanic || f.funcID == funcID_asyncPreempt || f.funcID == funcID_debugCallV2
468+
if injectedCall {
469+
u.flags |= unwindTrap
470+
} else {
471+
u.flags &^= unwindTrap
472+
}
464473

465474
// Unwind to next frame.
466475
u.calleeFuncID = f.funcID
@@ -541,6 +550,25 @@ func (u *unwinder) finishInternal() {
541550
}
542551
}
543552

553+
// symPC returns the PC that should be used for symbolizing the current frame.
554+
// Specifically, this is the PC of the last instruction executed in this frame.
555+
//
556+
// If this frame did a normal call, then frame.pc is a return PC, so this will
557+
// return frame.pc-1, which points into the CALL instruction. If the frame was
558+
// interrupted by a signal (e.g., profiler, segv, etc) then frame.pc is for the
559+
// trapped instruction, so this returns frame.pc. See issue #34123. Finally,
560+
// frame.pc can be at function entry when the frame is initialized without
561+
// actually running code, like in runtime.mstart, in which case this returns
562+
// frame.pc because that's the best we can do.
563+
func (u *unwinder) symPC() uintptr {
564+
if u.flags&unwindTrap == 0 && u.frame.pc > u.frame.fn.entry() {
565+
// Regular call.
566+
return u.frame.pc - 1
567+
}
568+
// Trapping instruction or we're at the function entry point.
569+
return u.frame.pc
570+
}
571+
544572
// Generic traceback. Handles runtime stack prints (pcbuf == nil),
545573
// and the runtime.Callers function (pcbuf != nil).
546574
// A little clunky to merge these, but avoids
@@ -581,24 +609,9 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
581609
frame := &u.frame
582610
f := frame.fn
583611

584-
// Backup to the CALL instruction to read inlining info
585-
//
586-
// Normally, pc is a return address. In that case, we want to look up
587-
// file/line information using pc-1, because that is the pc of the
588-
// call instruction (more precisely, the last byte of the call instruction).
589-
// When the pc is from a signal (e.g. profiler or segv) then pc is for
590-
// the trapped instruction, not a return address, so we use pc unchanged.
591-
// See issue 34123.
592-
// The pc can be at function entry when the frame is initialized without
593-
// actually running code, like runtime.mstart.
594-
callPC := frame.pc
595-
if (n > 0 || flags&_TraceTrap == 0) && frame.pc > f.entry() && u.calleeFuncID != funcID_sigpanic {
596-
callPC--
597-
}
598-
599612
if pcbuf != nil {
600613
// TODO: Why does cache escape? (Same below)
601-
for iu, uf := newInlineUnwinder(f, callPC, noEscapePtr(&u.cache)); uf.valid(); uf = iu.next(uf) {
614+
for iu, uf := newInlineUnwinder(f, u.symPC(), noEscapePtr(&u.cache)); uf.valid(); uf = iu.next(uf) {
602615
sf := iu.srcFunc(uf)
603616
if sf.funcID == funcID_wrapper && elideWrapperCalling(u.calleeFuncID) {
604617
// ignore wrappers
@@ -623,7 +636,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
623636
// any frames. And don't elide wrappers that
624637
// called panic rather than the wrapped
625638
// function. Otherwise, leave them out.
626-
for iu, uf := newInlineUnwinder(f, callPC, noEscapePtr(&u.cache)); uf.valid(); uf = iu.next(uf) {
639+
for iu, uf := newInlineUnwinder(f, u.symPC(), noEscapePtr(&u.cache)); uf.valid(); uf = iu.next(uf) {
627640
sf := iu.srcFunc(uf)
628641
if (flags&_TraceRuntimeFrames) != 0 || showframe(sf, gp, nprint == 0, u.calleeFuncID) {
629642
name := sf.name()
@@ -640,7 +653,7 @@ func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max in
640653
print("...")
641654
} else {
642655
argp := unsafe.Pointer(frame.argp)
643-
printArgs(f, argp, callPC)
656+
printArgs(f, argp, u.symPC())
644657
}
645658
print(")\n")
646659
print("\t", file, ":", line)

0 commit comments

Comments
 (0)