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

     1  package bytecode
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/hex"
     6  
     7  	"github.com/tencent/goom/internal/arch/arm64asm"
     8  	"github.com/tencent/goom/internal/bytecode/memory"
     9  	"github.com/tencent/goom/internal/logger"
    10  )
    11  
    12  // defaultLength 默认指令长度
    13  const defaultLength = 4
    14  
    15  // funcPrologue 函数的开头指纹,用于不同OS获取不同的默认值
    16  var funcPrologue = armFuncPrologue64
    17  
    18  const (
    19  	// CallInsName call 指令名称
    20  	CallInsName = "B"
    21  	// CallInsName1 call 指令名称
    22  	CallInsName1 = "BL"
    23  )
    24  
    25  // GetFuncSize get func binary size
    26  // not absolutely safe
    27  func GetFuncSize(_ int, start uintptr, minimal bool) (length int, err error) {
    28  	funcSizeReadLock.Lock()
    29  	defer funcSizeReadLock.Unlock()
    30  
    31  	defer func() {
    32  		funcSizeCache[start] = length
    33  	}()
    34  
    35  	if l, ok := funcSizeCache[start]; ok {
    36  		return l, nil
    37  	}
    38  
    39  	prologueLen := len(funcPrologue)
    40  	code := memory.RawRead(start, 16) // instruction takes at most 16 bytes
    41  
    42  	int0Found := false
    43  	curLen := 0
    44  	for {
    45  		inst, err := arm64asm.Decode(code)
    46  		if err != nil {
    47  			return curLen, nil
    48  		}
    49  
    50  		if inst.Op == 0 && code[0] == 0x00 {
    51  			// 0x00 -> int0, trap to debugger, padding to function end
    52  			if minimal {
    53  				return curLen, nil
    54  			}
    55  			int0Found = true
    56  		} else if int0Found {
    57  			return curLen, nil
    58  		}
    59  
    60  		curLen += defaultLength
    61  		code = memory.RawRead(start+uintptr(curLen), 16) // instruction takes at most 16 bytes
    62  
    63  		if bytes.Equal(funcPrologue, code[:prologueLen]) {
    64  			return curLen, nil
    65  		}
    66  	}
    67  }
    68  
    69  // PrintInstf 调试内存指令替换,对原指令、替换之后的指令进行输出对比
    70  func PrintInstf(title string, from uintptr, copyOrigin []byte, level int) {
    71  	if logger.LogLevel < level {
    72  		return
    73  	}
    74  	logger.Important(title)
    75  
    76  	startAddr := (uint64)(from)
    77  	for pos := 0; pos < len(copyOrigin); {
    78  		// read 16 bytes at most each time
    79  		endPos := pos + 16
    80  		if endPos > len(copyOrigin) {
    81  			endPos = len(copyOrigin)
    82  		}
    83  
    84  		code := copyOrigin[pos:endPos]
    85  		ins, err := arm64asm.Decode(code)
    86  		if err != nil {
    87  			logger.Importantf("[0] 0x%x: inst decode error:%s", startAddr+(uint64)(pos), err)
    88  			pos = pos + 4
    89  			continue
    90  		}
    91  
    92  		if ins.Op == 0 {
    93  			if code[0] == 0x00 {
    94  				pos = pos + 1
    95  			} else {
    96  				pos = pos + 4
    97  			}
    98  			continue
    99  		}
   100  
   101  		logger.Importantf("[%d] 0x%x:\t%s\t\t%-30s\t\t%s", 4,
   102  			startAddr+(uint64)(pos), ins.Op, ins.String(), hex.EncodeToString(code[:4]))
   103  
   104  		pos = pos + 4
   105  	}
   106  }
   107  
   108  // GetInnerFunc Get the first real func location from wrapper
   109  // not absolutely safe
   110  func GetInnerFunc(mode int, start uintptr) (uintptr, error) {
   111  	prologueLen := len(funcPrologue)
   112  	code := memory.RawRead(start, 16) // instruction takes at most 16 bytes
   113  
   114  	int0Found := false
   115  	curLen := 0
   116  	for {
   117  		inst, err := arm64asm.Decode(code)
   118  		if err != nil {
   119  			return 0, err
   120  		}
   121  
   122  		if inst.Op == 0 && code[0] == 0x00 {
   123  			int0Found = true
   124  		} else if int0Found {
   125  			return 0, nil
   126  		}
   127  
   128  		if inst.Op.String() == CallInsName || inst.Op.String() == CallInsName1 {
   129  			rAddr, ok := (inst.Args[0]).(arm64asm.PCRel)
   130  			if ok {
   131  				if rAddr >= 0 {
   132  					return start + uintptr(curLen) + uintptr(rAddr), nil
   133  				}
   134  				if curLen+int(rAddr) < 0 {
   135  					return start + uintptr(curLen) - uintptr(-rAddr), nil
   136  				}
   137  			}
   138  		}
   139  
   140  		curLen += defaultLength
   141  		code = memory.RawRead(start+uintptr(curLen), 16) // instruction takes at most 16 bytes
   142  
   143  		if bytes.Equal(funcPrologue, code[:prologueLen]) {
   144  			return 0, nil
   145  		}
   146  		if curLen > 4096 {
   147  			return 0, nil
   148  		}
   149  	}
   150  }