github.com/tencent/goom@v1.0.1/internal/bytecode/stub/holder.go (about)

     1  // Package stub 负责管理桩函数内存管理
     2  package stub
     3  
     4  import (
     5  	"errors"
     6  	"reflect"
     7  	"sync/atomic"
     8  	"unsafe"
     9  
    10  	"github.com/tencent/goom/internal/bytecode"
    11  	"github.com/tencent/goom/internal/logger"
    12  )
    13  
    14  // placeHolderIns 占位实例
    15  var placeHolderIns *PlaceHolder
    16  
    17  // errSpaceOverflow 空间使用溢出错误
    18  var errSpaceOverflow = errors.New("placeholder space usage overflow")
    19  
    20  // PlaceHolder 占位对象
    21  type PlaceHolder struct {
    22  	// count hook 次数统计
    23  	count int
    24  	// off 当前占位函数使用的偏移量
    25  	off uintptr
    26  	// min 占位函数起始位置
    27  	min uintptr
    28  	// max 占位函数末尾位置
    29  	max uintptr
    30  }
    31  
    32  // Placeholder 汇编函数声明: 占位函数
    33  func Placeholder()
    34  
    35  func init() {
    36  	offset := reflect.ValueOf(Placeholder).Pointer()
    37  	// 兼容 go 1.17(1.17以上会对 assembler 函数进行 wrap, 需要找到其内部的调用)
    38  	innerOffset, err := bytecode.GetInnerFunc(64, offset)
    39  	if innerOffset > 0 && err == nil {
    40  		offset = innerOffset
    41  	}
    42  
    43  	size, err := bytecode.GetFuncSize(64, offset, false)
    44  	if err != nil {
    45  		logger.Error("GetFuncSize error", err)
    46  		size = 102400
    47  	}
    48  
    49  	placeHolderIns = &PlaceHolder{
    50  		count: 0,
    51  		off:   offset,
    52  		min:   offset,
    53  		max:   uintptr(size) + offset,
    54  	}
    55  	logger.Debugf("Placeholder pointer: %d %d\n", placeHolderIns.min, offset)
    56  }
    57  
    58  // acquireFromHolder enough executable space from holder
    59  // nolint
    60  func acquireFromHolder(len int) (uintptr, *[]byte, error) {
    61  	placeholder := atomic.LoadUintptr(&placeHolderIns.off)
    62  	if placeholder+uintptr(len) > placeHolderIns.max {
    63  		logger.Error("placeholder space usage overflow")
    64  		return 0, nil, errSpaceOverflow
    65  	}
    66  
    67  	// add up to off
    68  	newOffset := atomic.AddUintptr(&placeHolderIns.off, uintptr(len))
    69  	if newOffset > placeHolderIns.max {
    70  		logger.Error("placeholder space usage overflow", placeHolderIns.count, "hook functions")
    71  		return 0, nil, errSpaceOverflow
    72  	}
    73  
    74  	bytes := (*[]byte)(unsafe.Pointer(&reflect.SliceHeader{
    75  		Data: placeholder,
    76  		Len:  len,
    77  		Cap:  len,
    78  	}))
    79  	return placeholder, bytes, nil
    80  }