1// Copyright 2014 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
5package runtime
6
7import (
8	_ "unsafe" // for go:linkname
9)
10
11// Frames may be used to get function/file/line information for a
12// slice of PC values returned by Callers.
13type Frames struct {
14	// callers is a slice of PCs that have not yet been expanded to frames.
15	callers []uintptr
16
17	// The last PC we saw.
18	last uintptr
19
20	// The number of times we've seen last.
21	lastCount int
22}
23
24// Frame is the information returned by Frames for each call frame.
25type Frame struct {
26	// PC is the program counter for the location in this frame.
27	// For a frame that calls another frame, this will be the
28	// program counter of a call instruction. Because of inlining,
29	// multiple frames may have the same PC value, but different
30	// symbolic information.
31	PC uintptr
32
33	// Func is the Func value of this call frame. This may be nil
34	// for non-Go code or fully inlined functions.
35	Func *Func
36
37	// Function is the package path-qualified function name of
38	// this call frame. If non-empty, this string uniquely
39	// identifies a single function in the program.
40	// This may be the empty string if not known.
41	// If Func is not nil then Function == Func.Name().
42	Function string
43
44	// File and Line are the file name and line number of the
45	// location in this frame. For non-leaf frames, this will be
46	// the location of a call. These may be the empty string and
47	// zero, respectively, if not known.
48	File string
49	Line int
50
51	// Entry point program counter for the function; may be zero
52	// if not known. If Func is not nil then Entry ==
53	// Func.Entry().
54	Entry uintptr
55}
56
57// CallersFrames takes a slice of PC values returned by Callers and
58// prepares to return function/file/line information.
59// Do not change the slice until you are done with the Frames.
60func CallersFrames(callers []uintptr) *Frames {
61	return &Frames{callers: callers}
62}
63
64// Next returns frame information for the next caller.
65// If more is false, there are no more callers (the Frame value is valid).
66func (ci *Frames) Next() (frame Frame, more bool) {
67	if len(ci.callers) == 0 {
68		return Frame{}, false
69	}
70
71	pc := ci.callers[0]
72	ci.callers = ci.callers[1:]
73
74	i := 0
75	if pc == ci.last {
76		ci.lastCount++
77		i = ci.lastCount
78	} else {
79		ci.last = pc
80		ci.lastCount = 0
81	}
82	more = len(ci.callers) > 0
83
84	// Subtract 1 from PC to undo the 1 we added in callback in
85	// go-callers.c.
86	function, file, line, _ := funcfileline(pc-1, int32(i), more)
87	if function == "" && file == "" {
88		return Frame{}, more
89	}
90
91	// Demangle function name if needed.
92	function = demangleSymbol(function)
93
94	// Create entry.
95	entry := funcentry(pc - 1)
96	f := &Func{name: function, entry: entry}
97
98	xpc := pc
99	if xpc > entry {
100		xpc--
101	}
102
103	frame = Frame{
104		PC:       xpc,
105		Func:     f,
106		Function: function,
107		File:     file,
108		Line:     line,
109		Entry:    entry,
110	}
111
112	return frame, more
113}
114
115//go:noescape
116// pcInlineCallers is written in C.
117func pcInlineCallers(pc uintptr, locbuf *location, max int32) int32
118
119// runtime_expandFinalInlineFrame expands the final pc in stk to include all
120// "callers" if pc is inline.
121//
122//go:linkname runtime_expandFinalInlineFrame runtime..z2fpprof.runtime_expandFinalInlineFrame
123func runtime_expandFinalInlineFrame(stk []uintptr) []uintptr {
124	if len(stk) == 0 {
125		return stk
126	}
127	pc := stk[len(stk)-1]
128	tracepc := pc - 1
129
130	var locbuf [_TracebackMaxFrames]location
131	n := pcInlineCallers(tracepc, &locbuf[0], int32(len(locbuf)))
132
133	// Returning the same PC several times causes Frame.Next to do
134	// the right thing.
135	for i := int32(1); i < n; i++ {
136		stk = append(stk, pc)
137	}
138
139	return stk
140}
141
142// NOTE: Func does not expose the actual unexported fields, because we return *Func
143// values to users, and we want to keep them from being able to overwrite the data
144// with (say) *f = Func{}.
145// All code operating on a *Func must call raw() to get the *_func
146// or funcInfo() to get the funcInfo instead.
147
148// A Func represents a Go function in the running binary.
149type Func struct {
150	name  string
151	entry uintptr
152}
153
154// FuncForPC returns a *Func describing the function that contains the
155// given program counter address, or else nil.
156//
157// If pc represents multiple functions because of inlining, it returns
158// the a *Func describing the innermost function, but with an entry
159// of the outermost function.
160func FuncForPC(pc uintptr) *Func {
161	name, _, _, _ := funcfileline(pc, -1, false)
162	if name == "" {
163		return nil
164	}
165	entry := funcentry(pc)
166	return &Func{name: name, entry: entry}
167}
168
169// Name returns the name of the function.
170func (f *Func) Name() string {
171	if f == nil {
172		return ""
173	}
174	return f.name
175}
176
177// Entry returns the entry address of the function.
178func (f *Func) Entry() uintptr {
179	if f == nil {
180		return 0
181	}
182	return f.entry
183}
184
185// FileLine returns the file name and line number of the
186// source code corresponding to the program counter pc.
187// The result will not be accurate if pc is not a program
188// counter within f.
189func (f *Func) FileLine(pc uintptr) (file string, line int) {
190	_, file, line, _ = funcfileline(pc, -1, false)
191	return file, line
192}
193
194func hexval(b byte) uint {
195	if b >= '0' && b <= '9' {
196		return uint(b - '0')
197	}
198	if b >= 'a' && b <= 'f' {
199		return uint(b-'a') + 10
200	}
201	return 0
202}
203
204func hexDigitsToRune(digits []byte, ndig int) rune {
205	result := uint(0)
206	for i := 0; i < ndig; i++ {
207		result <<= uint(4)
208		result |= hexval(digits[i])
209	}
210	return rune(result)
211}
212
213// Perform an in-place decoding on the input byte slice. This looks
214// for "..z<hex 2 >", "..u<hex x 4>" and "..U<hex x 8>" and overwrites
215// with the encoded bytes corresponding to the unicode in question.
216// Return value is the number of bytes taken by the result.
217
218func decodeIdentifier(bsl []byte) int {
219	j := 0
220	for i := 0; i < len(bsl); i++ {
221		b := bsl[i]
222
223		if i+1 < len(bsl) && bsl[i] == '.' && bsl[i+1] == '.' {
224			if i+4 < len(bsl) && bsl[i+2] == 'z' {
225				digits := bsl[i+3:]
226				r := hexDigitsToRune(digits, 2)
227				nc := encoderune(bsl[j:], r)
228				j += nc
229				i += 4
230				continue
231			} else if i+6 < len(bsl) && bsl[i+2] == 'u' {
232				digits := bsl[i+3:]
233				r := hexDigitsToRune(digits, 4)
234				nc := encoderune(bsl[j:], r)
235				j += nc
236				i += 6
237				continue
238			} else if i+10 < len(bsl) && bsl[i+2] == 'U' {
239				digits := bsl[i+3:]
240				r := hexDigitsToRune(digits, 8)
241				nc := encoderune(bsl[j:], r)
242				j += nc
243				i += 10
244				continue
245			}
246		}
247		bsl[j] = b
248		j += 1
249	}
250	return j
251}
252
253// Demangle a function symbol. Applies the reverse of go_encode_id()
254// as used in the compiler.
255
256func demangleSymbol(s string) string {
257	bsl := []byte(s)
258	nchars := decodeIdentifier(bsl)
259	bsl = bsl[:nchars]
260	return string(bsl)
261}
262
263// implemented in go-caller.c
264func funcfileline(uintptr, int32, bool) (string, string, int, int)
265func funcentry(uintptr) uintptr
266