github.com/team-ide/go-dialect@v1.9.20/vitess/vterrors/stack.go (about) 1 /* 2 Copyright 2019 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package vterrors 18 19 /* This file is copied from https://github.com/pkg/errors/blob/v0.8.0/stack.go */ 20 21 import ( 22 "fmt" 23 "io" 24 "path" 25 "runtime" 26 "strings" 27 ) 28 29 // Frame represents a program counter inside a stack frame. 30 type Frame uintptr 31 32 // pc returns the program counter for this frame; 33 // multiple frames may have the same PC value. 34 func (f Frame) pc() uintptr { return uintptr(f) - 1 } 35 36 // file returns the full path to the file that contains the 37 // function for this Frame's pc. 38 func (f Frame) file() string { 39 fn := runtime.FuncForPC(f.pc()) 40 if fn == nil { 41 return "unknown" 42 } 43 file, _ := fn.FileLine(f.pc()) 44 return file 45 } 46 47 // line returns the line number of source code of the 48 // function for this Frame's pc. 49 func (f Frame) line() int { 50 fn := runtime.FuncForPC(f.pc()) 51 if fn == nil { 52 return 0 53 } 54 _, line := fn.FileLine(f.pc()) 55 return line 56 } 57 58 // Format formats the frame according to the fmt.Formatter interface. 59 // 60 // %s source file 61 // %d source line 62 // %n function name 63 // %v equivalent to %s:%d 64 // 65 // Format accepts flags that alter the printing of some verbs, as follows: 66 // 67 // %+s path of source file relative to the compile time GOPATH 68 // %+v equivalent to %+s:%d 69 func (f Frame) Format(s fmt.State, verb rune) { 70 switch verb { 71 case 's': 72 switch { 73 case s.Flag('+'): 74 pc := f.pc() 75 fn := runtime.FuncForPC(pc) 76 if fn == nil { 77 io.WriteString(s, "unknown") 78 } else { 79 file, _ := fn.FileLine(pc) 80 fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file) 81 } 82 default: 83 io.WriteString(s, path.Base(f.file())) 84 } 85 case 'd': 86 fmt.Fprintf(s, "%d", f.line()) 87 case 'n': 88 name := runtime.FuncForPC(f.pc()).Name() 89 io.WriteString(s, funcname(name)) 90 case 'v': 91 f.Format(s, 's') 92 io.WriteString(s, ":") 93 f.Format(s, 'd') 94 } 95 } 96 97 // StackTrace is stack of Frames from innermost (newest) to outermost (oldest). 98 type StackTrace []Frame 99 100 // Format format the stacktrace according to the fmt.Formatter interface. 101 // 102 // %s source file 103 // %d source line 104 // %n function name 105 // %v equivalent to %s:%d 106 // 107 // Format accepts flags that alter the printing of some verbs, as follows: 108 // 109 // %+s path of source file relative to the compile time GOPATH 110 // %+v equivalent to %+s:%d 111 func (st StackTrace) Format(s fmt.State, verb rune) { 112 switch verb { 113 case 'v': 114 115 if s.Flag('#') { 116 fmt.Fprintf(s, "%#v", []Frame(st)) 117 } else { 118 for _, f := range st { 119 fmt.Fprintf(s, "\n%v", f) 120 } 121 } 122 123 case 's': 124 fmt.Fprintf(s, "%s", []Frame(st)) 125 } 126 } 127 128 // stack represents a stack of program counters. 129 type stack []uintptr 130 131 func (s *stack) Format(st fmt.State, verb rune) { 132 switch verb { 133 case 'v': 134 for _, pc := range *s { 135 f := Frame(pc) 136 fmt.Fprintf(st, "\n%+v", f) 137 } 138 } 139 } 140 141 func (s *stack) StackTrace() StackTrace { 142 f := make([]Frame, len(*s)) 143 for i := 0; i < len(f); i++ { 144 f[i] = Frame((*s)[i]) 145 } 146 return f 147 } 148 149 func callers() *stack { 150 const depth = 32 151 var pcs [depth]uintptr 152 n := runtime.Callers(3, pcs[:]) 153 var st stack = pcs[0:n] 154 return &st 155 } 156 157 // funcname removes the path prefix component of a function's name reported by func.Name(). 158 func funcname(name string) string { 159 i := strings.LastIndex(name, "/") 160 name = name[i+1:] 161 i = strings.Index(name, ".") 162 return name[i+1:] 163 }