aboutsummaryrefslogtreecommitdiffstats
path: root/library/go/x/xruntime/stacktrace.go
blob: 5c5e661188f22220c171768f3e4bc1c73850c00d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package xruntime

import (
	"runtime"
)

type StackTrace struct {
	frames []uintptr
	full   bool
}

func NewStackTrace16(skip int) *StackTrace {
	var pcs [16]uintptr
	return newStackTrace(skip+2, pcs[:])
}

func NewStackTrace32(skip int) *StackTrace {
	var pcs [32]uintptr
	return newStackTrace(skip+2, pcs[:])
}

func NewStackTrace64(skip int) *StackTrace {
	var pcs [64]uintptr
	return newStackTrace(skip+2, pcs[:])
}

func NewStackTrace128(skip int) *StackTrace {
	var pcs [128]uintptr
	return newStackTrace(skip+2, pcs[:])
}

func newStackTrace(skip int, pcs []uintptr) *StackTrace {
	n := runtime.Callers(skip+1, pcs)
	return &StackTrace{frames: pcs[:n], full: true}
}

func NewFrame(skip int) *StackTrace {
	var pcs [3]uintptr
	n := runtime.Callers(skip+1, pcs[:])
	return &StackTrace{frames: pcs[:n]}
}

func (st *StackTrace) Frames() []runtime.Frame {
	frames := runtime.CallersFrames(st.frames[:])
	if !st.full {
		if _, ok := frames.Next(); !ok {
			return nil
		}

		fr, ok := frames.Next()
		if !ok {
			return nil
		}

		return []runtime.Frame{fr}
	}

	var res []runtime.Frame
	for {
		frame, more := frames.Next()
		if !more {
			break
		}

		res = append(res, frame)
	}

	return res
}