mirror of
https://github.com/golang/go
synced 2024-11-12 04:00:23 -07:00
69c2c56453
Work involved in getting a stack trace is divided between runtime.Callers and runtime.CallersFrames. Before this CL, runtime.Callers returns a pc per runtime frame. runtime.CallersFrames is responsible for expanding a runtime frame into potentially multiple user frames. After this CL, runtime.Callers returns a pc per user frame. runtime.CallersFrames just maps those to user frame info. Entries in the result of runtime.Callers are now pcs of the calls (or of the inline marks), not of the instruction just after the call. Fixes #29007 Fixes #28640 Update #26320 Change-Id: I1c9567596ff73dc73271311005097a9188c3406f Reviewed-on: https://go-review.googlesource.com/c/152537 Run-TryBot: Keith Randall <khr@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: David Chase <drchase@google.com>
96 lines
2.0 KiB
Go
96 lines
2.0 KiB
Go
// 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])
|
|
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.testCallers", "main.testCallers", "main.testCallers", "main.testCallers", "main.main"},
|
|
1: {"main.testCallers", "main.testCallers", "main.testCallers", "main.testCallers", "main.main"},
|
|
2: {"main.testCallers", "main.testCallers", "main.testCallers", "main.main"},
|
|
3: {"main.testCallers", "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)
|
|
}
|
|
}
|
|
}
|