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 }