github.com/tencent/goom@v1.0.1/internal/bytecode/func_amd64.go (about) 1 package bytecode 2 3 import ( 4 "bytes" 5 "encoding/hex" 6 "strings" 7 8 "github.com/tencent/goom/internal/arch/x86asm" 9 "github.com/tencent/goom/internal/bytecode/memory" 10 "github.com/tencent/goom/internal/logger" 11 ) 12 13 // defaultInsLen 默认一次解析指令的长度 14 const defaultInsLen = 16 15 16 // funcPrologue 函数的开头指纹,用于不同 OS 获取不同的默认值 17 var funcPrologue = defaultFuncPrologue64 18 19 // CallInsName call 指令名称 20 const CallInsName = "CALL" 21 22 // GetFuncSize get func binary size 23 // not absolutely safe 24 func GetFuncSize(mode int, start uintptr, minimal bool) (length int, err error) { 25 funcSizeReadLock.Lock() 26 defer func() { 27 funcSizeCache[start] = length 28 funcSizeReadLock.Unlock() 29 }() 30 31 if l, ok := funcSizeCache[start]; ok { 32 return l, nil 33 } 34 35 prologueLen := len(funcPrologue) 36 code := memory.RawRead(start, defaultInsLen) 37 38 var ( 39 int3Found = false 40 curLen = 0 41 ) 42 for { 43 inst, err := x86asm.Decode(code, mode) 44 if err != nil || (inst.Opcode == 0 && inst.Len == 1 && inst.Prefix[0] == x86asm.Prefix(code[0])) { 45 return curLen, nil 46 } 47 48 if inst.Len == 1 && code[0] == 0xcc { 49 // 0xcc -> int3, trap to debugger, padding to function end 50 if minimal { 51 return curLen, nil 52 } 53 int3Found = true 54 } else if int3Found { 55 return curLen, nil 56 } 57 58 curLen = curLen + inst.Len 59 code = memory.RawRead(start+uintptr(curLen), defaultInsLen) 60 if bytes.Equal(funcPrologue, code[:prologueLen]) { 61 return curLen, nil 62 } 63 } 64 } 65 66 // PrintInstf 调试内存指令替换,对原指令、替换之后的指令进行输出对比 67 func PrintInstf(title string, from uintptr, copyOrigin []byte, level int) { 68 if logger.LogLevel < level { 69 return 70 } 71 logger.Important(title) 72 73 startAddr := (uint64)(from) 74 for pos := 0; pos < len(copyOrigin); { 75 to := pos + defaultInsLen 76 if to > len(copyOrigin) { 77 to = len(copyOrigin) 78 } 79 80 code := copyOrigin[pos:to] 81 ins, err := x86asm.Decode(code, 64) 82 83 if err != nil { 84 logger.Importantf("[0] 0x%x: inst decode error:%s", startAddr+(uint64)(pos), err) 85 if ins.Len == 0 { 86 pos = pos + 1 87 } else { 88 pos = pos + ins.Len 89 } 90 continue 91 } 92 93 if ins.Opcode == 0 { 94 if ins.Len == 0 { 95 pos = pos + 1 96 } else { 97 pos = pos + ins.Len 98 } 99 continue 100 } 101 102 if ins.PCRelOff <= 0 { 103 logger.Importantf("[%d] 0x%x:\t%s\t\t%-30s\t\t%s", ins.Len, 104 startAddr+(uint64)(pos), ins.Op, ins.String(), hex.EncodeToString(code[:ins.Len])) 105 pos = pos + ins.Len 106 continue 107 } 108 109 offset := pos + ins.PCRelOff 110 relativeAddr := DecodeAddress(copyOrigin[offset:offset+ins.PCRel], ins.PCRel) 111 if !isRelativeAdd(ins) && relativeAddr > 0 { 112 relativeAddr = -relativeAddr 113 } 114 115 logger.Importantf("[%d] 0x%x:\t%s\t\t%-30s\t\t%s\t\tabs:0x%x", ins.Len, 116 startAddr+(uint64)(pos), ins.Op, ins.String(), hex.EncodeToString(code[:ins.Len]), 117 from+uintptr(pos)+uintptr(relativeAddr)+uintptr(ins.Len)) 118 119 pos = pos + ins.Len 120 } 121 } 122 123 func isRelativeAdd(ins x86asm.Inst) bool { 124 isAdd := true 125 for i := 0; i < len(ins.Args); i++ { 126 arg := ins.Args[i] 127 if arg == nil { 128 break 129 } 130 addrArgs := arg.String() 131 if strings.HasPrefix(addrArgs, ".-") || strings.Contains(addrArgs, "RIP-") { 132 isAdd = false 133 } 134 } 135 return isAdd 136 } 137 138 // GetInnerFunc Get the first real func location from wrapper 139 // not absolutely safe 140 func GetInnerFunc(mode int, start uintptr) (uintptr, error) { 141 prologueLen := len(funcPrologue) 142 code := memory.RawRead(start, defaultInsLen) 143 144 var ( 145 int3Found = false 146 curLen = 0 147 ) 148 for { 149 inst, err := x86asm.Decode(code, mode) 150 if err != nil || (inst.Opcode == 0 && inst.Len == 1 && inst.Prefix[0] == x86asm.Prefix(code[0])) { 151 return 0, nil 152 } 153 154 if inst.Len == 1 && code[0] == 0xcc { 155 int3Found = true 156 } else if int3Found { 157 return 0, nil 158 } 159 160 if inst.Op.String() == CallInsName { 161 relativeAddr := DecodeRelativeAddr(&inst, code, inst.PCRelOff) 162 if relativeAddr >= 0 { 163 return start + uintptr(curLen) + uintptr(relativeAddr) + uintptr(inst.Len), nil 164 } 165 if curLen+int(relativeAddr) < 0 { 166 return start + uintptr(curLen) - uintptr(-relativeAddr) + uintptr(inst.Len), nil 167 } 168 } 169 170 curLen = curLen + inst.Len 171 code = memory.RawRead(start+uintptr(curLen), defaultInsLen) 172 if bytes.Equal(funcPrologue, code[:prologueLen]) { 173 return 0, nil 174 } 175 } 176 }