53 lines
1.2 KiB
Go
53 lines
1.2 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"path"
|
|
"runtime"
|
|
"strings"
|
|
)
|
|
|
|
var stack string
|
|
|
|
func f() {
|
|
pc := make([]uintptr, 6)
|
|
pc = pc[:runtime.Callers(1, pc)]
|
|
for _, f := range pc {
|
|
Func := runtime.FuncForPC(f)
|
|
name := Func.Name()
|
|
if strings.Contains(name, "$") || strings.Contains(name, ".func") {
|
|
name = "func" // anon funcs vary across toolchains
|
|
}
|
|
file, line := Func.FileLine(0)
|
|
stack += fmt.Sprintf("%s at %s:%d\n", name, path.Base(file), line)
|
|
}
|
|
}
|
|
|
|
func g() { f() }
|
|
func h() { g() }
|
|
func i() { func() { h() }() }
|
|
|
|
// Hack: the 'func' and the call to Caller are on the same line,
|
|
// to paper over differences between toolchains.
|
|
// (The interpreter's location info isn't yet complete.)
|
|
func runtimeCaller0() (uintptr, string, int, bool) { return runtime.Caller(0) }
|
|
|
|
func main() {
|
|
i()
|
|
if stack != `main.f at callstack.go:12
|
|
main.g at callstack.go:26
|
|
main.h at callstack.go:27
|
|
func at callstack.go:28
|
|
main.i at callstack.go:28
|
|
main.main at callstack.go:35
|
|
` {
|
|
panic("unexpected stack: " + stack)
|
|
}
|
|
|
|
pc, file, line, _ := runtimeCaller0()
|
|
got := fmt.Sprintf("%s @ %s:%d", runtime.FuncForPC(pc).Name(), path.Base(file), line)
|
|
if got != "main.runtimeCaller0 @ callstack.go:33" {
|
|
panic("runtime.Caller: " + got)
|
|
}
|
|
}
|