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