github.com/nikandfor/loc@v0.5.1/unsafe.go (about)

     1  package loc
     2  
     3  import (
     4  	"reflect"
     5  	"runtime"
     6  	"sync"
     7  	"unsafe"
     8  )
     9  
    10  type (
    11  	nfl struct {
    12  		name string
    13  		file string
    14  		line int
    15  	}
    16  )
    17  
    18  var (
    19  	locmu sync.Mutex
    20  	locc  = map[PC]nfl{}
    21  )
    22  
    23  //go:noescape
    24  //go:linkname callers runtime.callers
    25  func callers(skip int, pc []PC) int
    26  
    27  //go:noescape
    28  //go:linkname caller1 runtime.callers
    29  func caller1(skip int, pc *PC, len, cap int) int //nolint:predeclared
    30  
    31  //go:linkname callersFrames runtime.CallersFrames
    32  func callersFrames(pcs PCs) *runtime.Frames
    33  
    34  // NameFileLine returns function name, file and line number for location.
    35  //
    36  // This works only in the same binary where location was captured.
    37  //
    38  // This functions is a little bit modified version of runtime.(*Frames).Next().
    39  func (l PC) NameFileLine() (name, file string, line int) {
    40  	if l == 0 {
    41  		return
    42  	}
    43  
    44  	locmu.Lock()
    45  	c, ok := locc[l]
    46  	locmu.Unlock()
    47  	if ok {
    48  		return c.name, c.file, c.line
    49  	}
    50  
    51  	name, file, line = l.nameFileLine()
    52  
    53  	if file != "" {
    54  		file = cropFilename(file, name)
    55  	}
    56  
    57  	locmu.Lock()
    58  	locc[l] = nfl{
    59  		name: name,
    60  		file: file,
    61  		line: line,
    62  	}
    63  	locmu.Unlock()
    64  
    65  	return
    66  }
    67  
    68  // SetCache sets name, file and line for the PC.
    69  // It allows to work with PC in another binary the same as in original.
    70  func SetCache(l PC, name, file string, line int) {
    71  	locmu.Lock()
    72  	if name == "" && file == "" && line == 0 {
    73  		delete(locc, l)
    74  	} else {
    75  		locc[l] = nfl{
    76  			name: name,
    77  			file: file,
    78  			line: line,
    79  		}
    80  	}
    81  	locmu.Unlock()
    82  }
    83  
    84  func SetCacheBytes(l PC, name, file []byte, line int) {
    85  	locmu.Lock()
    86  	if name == nil && file == nil && line == 0 {
    87  		delete(locc, l)
    88  	} else {
    89  		x := locc[l]
    90  
    91  		if x.line != line || x.name != string(name) || x.file != string(file) {
    92  			locc[l] = nfl{
    93  				name: string(name),
    94  				file: string(file),
    95  				line: line,
    96  			}
    97  		}
    98  	}
    99  	locmu.Unlock()
   100  }
   101  
   102  func Cached(l PC) (ok bool) {
   103  	locmu.Lock()
   104  	_, ok = locc[l]
   105  	locmu.Unlock()
   106  	return
   107  }
   108  
   109  func noescapeSlize(b *byte, l int) []byte {
   110  	return *(*[]byte)(unsafe.Pointer(&reflect.SliceHeader{ //nolint:govet
   111  		Data: uintptr(unsafe.Pointer(b)),
   112  		Len:  0,
   113  		Cap:  l,
   114  	}))
   115  }