github.com/vedadiyan/sqlparser@v1.0.0/pkg/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  }