// run -gcflags=-l=4 // Copyright 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package main import ( "fmt" "runtime" ) var skip int var npcs int var pcs = make([]uintptr, 32) func f() { g() } func g() { h() } func h() { npcs = runtime.Callers(skip, pcs) } func testCallers(skp int) (frames []string) { skip = skp f() for i := 0; i < npcs; i++ { fn := runtime.FuncForPC(pcs[i] - 1) frames = append(frames, fn.Name()) if fn.Name() == "main.main" { break } } return } func testCallersFrames(skp int) (frames []string) { skip = skp f() callers := pcs[:npcs] ci := runtime.CallersFrames(callers) for { frame, more := ci.Next() frames = append(frames, frame.Function) if !more || frame.Function == "main.main" { break } } return } var expectedFrames [][]string = [][]string{ 0: {"runtime.Callers", "main.h", "main.g", "main.f", "main.testCallers", "main.main"}, 1: {"main.h", "main.g", "main.f", "main.testCallers", "main.main"}, 2: {"main.g", "main.f", "main.testCallers", "main.main"}, 3: {"main.f", "main.testCallers", "main.main"}, 4: {"main.testCallers", "main.main"}, 5: {"main.main"}, } var allFrames = []string{"runtime.Callers", "main.h", "main.g", "main.f", "main.testCallersFrames", "main.main"} func same(xs, ys []string) bool { if len(xs) != len(ys) { return false } for i := range xs { if xs[i] != ys[i] { return false } } return true } func main() { for i := 0; i <= 5; i++ { frames := testCallers(i) expected := expectedFrames[i] if !same(frames, expected) { fmt.Printf("testCallers(%d):\n got %v\n want %v\n", i, frames, expected) } frames = testCallersFrames(i) expected = allFrames[i:] if !same(frames, expected) { fmt.Printf("testCallersFrames(%d):\n got %v\n want %v\n", i, frames, expected) } } }