首页 > 解决方案 > 为什么 Frame 的值表示 pc 函数中的程序计数器 + 1

问题描述

在研究 pkg/errors 时我很困惑。在文件stack.go中,我们可以看到关于结构体的注释Frame如下:

// Frame represents a program counter inside a stack frame.
// For historical reasons if Frame is interpreted as a uintptr
// its value represents the program counter + 1.
type Frame uintptr

// pc returns the program counter for this frame;
// multiple frames may have the same PC value.
func (f Frame) pc() uintptr { return uintptr(f) - 1 }

谁能告诉我为什么 pc 函数得到uintptr(f) - 1作为程序计数器的值。我写了一些关于pc的代码来测试,我可以得到正确的答案,尽管重写pc函数如下:

type Frame uintptr

func (f Frame) pc() uintptr { return uintptr(f) }

func (f Frame) line() int {
    fn := runtime.FuncForPC(f.pc())
    if fn == nil {
        return 0
    }
    _, line := fn.FileLine(f.pc())
    return line
}

func main() {

    var pc, _, line, _ = runtime.Caller(0)
    fmt.Printf("pc:%v, line:%v\n", pc, line)

    fmt.Println("-------------")

    frame := Frame(pc)
    line = frame.line()
    fmt.Printf("Frame:%v, line:%v\n", uintptr(frame), line)
}

代码的结果是:

pc:4779003, line:23
-------------
Frame:4779003, line:23

标签: gostackruntimeframeprogram-counter

解决方案


https://github.com/golang/go/blob/897b3da2e079b9b940b309747305a5379fffa6ec/src/runtime/traceback.go#L339

// Normally, pc is a return address. In that case, we want to look up
// file/line information using pc-1, because that is the pc of the
// call instruction (more precisely, the last byte of the call instruction).
// Callers expect the pc buffer to contain return addresses and do the
// same -1 themselves, so we keep pc unchanged.
// When the pc is from a signal (e.g. profiler or segv) then we want
// to look up file/line information using pc, and we store pc+1 in the
// pc buffer so callers can unconditionally subtract 1 before looking up.
// See issue 34123.

推荐阅读