gccgo: 运行时错误的调用堆栈,CallersFrames

bxpogfeg  于 4个月前  发布在  Go
关注(0)|答案(1)|浏览(36)

堆栈跟踪对于带有优化(尤其是中栈内联)的gccgo来说并不准确。

package main

import (
	"fmt"
	"runtime"
)

func main() {
	f()
}
func f() {
	g()
}

//go:noinline
func g() {
	for i := 0; i < 4; i++ {
		var pcs [1]uintptr
		runtime.Callers(i+1, pcs[:])
		f, _ := runtime.CallersFrames(pcs[:]).Next()
		fmt.Printf("%x %s %s:%d\n", f.PC, f.Function, f.File, f.Line)
	}
}

在gc下运行,我得到:

48683c main.g /usr/local/google/home/khr/gowork/tmp5.go:19
48678f main.f /usr/local/google/home/khr/gowork/tmp5.go:12
48675f main.main /usr/local/google/home/khr/gowork/tmp5.go:9
428846 runtime.main /usr/local/google/home/khr/go1.11/src/runtime/proc.go:201

在gccgo -O3下运行,我得到:

56261c5ebc19 main.g /usr/local/google/home/khr/gowork/tmp5.go:19
56261c5ebeb3 main.f /usr/local/google/home/khr/gowork/tmp5.go:12
56261c5ebeb3 main.f /usr/local/google/home/khr/gowork/tmp5.go:12
7f9974ede51c runtime_main ../../../src/libgo/runtime/proc.c:606

请注意第三行 - 那应该是 main.main ,而不是第二行的 main.f 的复制。
gccgo可以在不使用-O3的情况下工作。
在使用-O3时,发生了中栈内联,main.main 直接调用了 main.gmain.f 甚至不在二进制文件中。
提供 runtime.Callers 一个更大的缓冲区也没有帮助。
请注意,这段代码确实可以正常工作,只需调用一次 runtime.Callers 并使用 runtime.CallersFrames 迭代器:

package main

import (
	"fmt"
	"runtime"
)

func main() {
	f()
}
func f() {
	g()
}

//go:noinline
func g() {
	var pcs [10]uintptr
	n := runtime.Callers(1, pcs[:])
	iter := runtime.CallersFrames(pcs[:n])
	for {
		f, more := iter.Next()
		fmt.Printf("%x %s %s:%d\n", f.PC, f.Function, f.File, f.Line)
		if !more {
			break
		}
	}
}
55bb3972acd4 main.g /usr/local/google/home/khr/gowork/tmp6.go:18
55bb3972afc3 main.f /usr/local/google/home/khr/gowork/tmp6.go:12
55bb3972afc3 main.main /usr/local/google/home/khr/gowork/tmp6.go:9
7fa2706d451c runtime_main ../../../src/libgo/runtime/proc.c:606

@ianlancetaylor

enyaitl3

enyaitl31#

这并不令人惊讶。我能想到的让这个工作的方法是使用魔法PC值,比如你在cmd/compile中使用的内联标记NOPs。由于gccgo没有改变GCC后端,它没有这样的机会。我看不到任何理由去编写像你的第一个程序那样的代码,所以我不倾向于花时间尝试在gccgo中修复这个问题。

相关问题