1 | // Copyright 2018 The Go Authors. All rights reserved.
|
---|
2 | // Use of this source code is governed by a BSD-style
|
---|
3 | // license that can be found in the LICENSE file.
|
---|
4 |
|
---|
5 | package xerrors
|
---|
6 |
|
---|
7 | import (
|
---|
8 | "runtime"
|
---|
9 | )
|
---|
10 |
|
---|
11 | // A Frame contains part of a call stack.
|
---|
12 | type Frame struct {
|
---|
13 | // Make room for three PCs: the one we were asked for, what it called,
|
---|
14 | // and possibly a PC for skipPleaseUseCallersFrames. See:
|
---|
15 | // https://go.googlesource.com/go/+/032678e0fb/src/runtime/extern.go#169
|
---|
16 | frames [3]uintptr
|
---|
17 | }
|
---|
18 |
|
---|
19 | // Caller returns a Frame that describes a frame on the caller's stack.
|
---|
20 | // The argument skip is the number of frames to skip over.
|
---|
21 | // Caller(0) returns the frame for the caller of Caller.
|
---|
22 | func Caller(skip int) Frame {
|
---|
23 | var s Frame
|
---|
24 | runtime.Callers(skip+1, s.frames[:])
|
---|
25 | return s
|
---|
26 | }
|
---|
27 |
|
---|
28 | // location reports the file, line, and function of a frame.
|
---|
29 | //
|
---|
30 | // The returned function may be "" even if file and line are not.
|
---|
31 | func (f Frame) location() (function, file string, line int) {
|
---|
32 | frames := runtime.CallersFrames(f.frames[:])
|
---|
33 | if _, ok := frames.Next(); !ok {
|
---|
34 | return "", "", 0
|
---|
35 | }
|
---|
36 | fr, ok := frames.Next()
|
---|
37 | if !ok {
|
---|
38 | return "", "", 0
|
---|
39 | }
|
---|
40 | return fr.Function, fr.File, fr.Line
|
---|
41 | }
|
---|
42 |
|
---|
43 | // Format prints the stack as error detail.
|
---|
44 | // It should be called from an error's Format implementation
|
---|
45 | // after printing any other error detail.
|
---|
46 | func (f Frame) Format(p Printer) {
|
---|
47 | if p.Detail() {
|
---|
48 | function, file, line := f.location()
|
---|
49 | if function != "" {
|
---|
50 | p.Printf("%s\n ", function)
|
---|
51 | }
|
---|
52 | if file != "" {
|
---|
53 | p.Printf("%s:%d\n", file, line)
|
---|
54 | }
|
---|
55 | }
|
---|
56 | }
|
---|