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)
 | |
| 	}
 | |
| }
 |