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