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 }