github.com/Rookout/GoSDK@v0.1.48/pkg/services/instrumentation/module/pcsp_generator_arm64.go (about) 1 //go:build arm64 2 // +build arm64 3 4 package module 5 6 import ( 7 "github.com/Rookout/GoSDK/pkg/rookoutErrors" 8 "strconv" 9 "strings" 10 "unsafe" 11 12 "github.com/Rookout/GoSDK/pkg/logger" 13 "github.com/Rookout/GoSDK/pkg/services/disassembler" 14 "golang.org/x/arch/arm64/arm64asm" 15 ) 16 17 type baseInstruction = arm64asm.Inst 18 19 type regState struct { 20 regToValue map[arm64asm.Reg]int 21 skipUntilPC uintptr 22 } 23 24 func newRegState() *regState { 25 r := ®State{ 26 regToValue: make(map[arm64asm.Reg]int), 27 } 28 r.regToValue[arm64asm.SP] = 0 29 return r 30 } 31 32 func (r *regState) getStackSize() int { 33 sp, _ := r.getRegValue(arm64asm.SP) 34 35 return -sp 36 } 37 38 func (r *regState) getRegValue(reg arm64asm.Reg) (int, bool) { 39 val, ok := r.regToValue[reg] 40 return val, ok 41 } 42 43 func (r *regState) setRegValue(reg arm64asm.Reg, value int) { 44 r.regToValue[reg] = value 45 } 46 47 48 const extShiftLDL = 9 49 50 51 type RegExtshiftAmount struct { 52 reg arm64asm.Reg 53 extShift uint8 54 amount uint8 55 show_zero bool 56 } 57 58 59 type MemImmediate struct { 60 Base arm64asm.RegSP 61 Mode uint8 62 imm int32 63 } 64 65 66 type ImmShift struct { 67 imm uint16 68 shift uint8 69 } 70 71 func getImmValue(immString string) int64 { 72 immString = immString[1:] 73 base := 10 74 if strings.HasPrefix(immString, "0x") { 75 base = 16 76 immString = immString[2:] 77 } 78 immNum, _ := strconv.ParseInt(immString, base, 64) 79 return immNum 80 } 81 82 func tryGetReg(reg interface{}) (arm64asm.Reg, bool) { 83 if r, ok := reg.(arm64asm.Reg); ok { 84 return r, true 85 } 86 if r, ok := reg.(arm64asm.RegSP); ok { 87 return (arm64asm.Reg(r)), true 88 } 89 return 0, false 90 } 91 92 93 94 95 96 97 98 func (r *regState) updateAddrIndexInstruction(i *disassembler.Instruction) { 99 var destArg arm64asm.Arg 100 if i.Op == arm64asm.STP || i.Op == arm64asm.LDP { 101 destArg = i.Args[2] 102 } else { 103 destArg = i.Args[1] 104 } 105 106 memArg, ok := destArg.(arm64asm.MemImmediate) 107 108 if !ok || (memArg.Mode != arm64asm.AddrPreIndex && memArg.Mode != arm64asm.AddrPostIndex) { 109 return 110 } 111 112 113 val, ok := r.getRegValue(arm64asm.Reg(memArg.Base)) 114 if !ok { 115 116 return 117 } 118 119 120 mem := (*MemImmediate)(unsafe.Pointer(&memArg)) 121 122 123 val = val + int(mem.imm) 124 r.setRegValue(arm64asm.Reg(mem.Base), val) 125 } 126 127 128 129 130 131 132 133 func (r *regState) updateAddSubInstruction(i *disassembler.Instruction) { 134 destReg, ok := tryGetReg(i.Args[0]) 135 if !ok { 136 logger.Logger().Warningf("Got unexpected dest reg in add/sub: %v [%T], instruction = %v", i.Args[0], i.Args[0], i) 137 return 138 } 139 140 sourceReg, ok := tryGetReg(i.Args[1]) 141 if !ok { 142 logger.Logger().Warningf("Got unexpected source reg in add/sub: %v [%T], instruction = %v", i.Args[1], i.Args[1], i) 143 return 144 } 145 146 147 if imm, ok := i.Args[2].(arm64asm.ImmShift); ok { 148 immNum := getImmValue(imm.String()) 149 150 val, ok := r.getRegValue(sourceReg) 151 if !ok { 152 153 return 154 } 155 156 if i.Op == arm64asm.SUB { 157 r.setRegValue(destReg, val-int(immNum)) 158 } else { 159 r.setRegValue(destReg, val+int(immNum)) 160 } 161 } 162 163 164 if reg, ok := i.Args[2].(arm64asm.RegExtshiftAmount); ok { 165 166 newReg := *(*RegExtshiftAmount)(unsafe.Pointer(®)) 167 168 169 sourceVal2, ok := r.getRegValue(newReg.reg) 170 if !ok { 171 172 return 173 } 174 175 176 if newReg.extShift == extShiftLDL { 177 sourceVal2 = sourceVal2 << newReg.amount 178 } else if newReg.extShift != 0 { 179 return 180 } 181 182 sourceVal1, ok := r.getRegValue(sourceReg) 183 if !ok { 184 185 return 186 } 187 188 if i.Op == arm64asm.SUB { 189 r.setRegValue(destReg, sourceVal1-sourceVal2) 190 } else { 191 r.setRegValue(destReg, sourceVal1+sourceVal2) 192 } 193 } 194 } 195 196 197 198 199 200 func (r *regState) updateMovInstruction(i *disassembler.Instruction) { 201 destReg, ok := tryGetReg(i.Args[0]) 202 if !ok { 203 logger.Logger().Warningf("Got unexpected dest reg in mov: %v [%T], instruction = %v", i.Args[0], i.Args[0], i) 204 return 205 } 206 207 208 if sourceReg, ok := tryGetReg(i.Args[1]); ok { 209 val, ok := r.getRegValue(sourceReg) 210 if !ok { 211 212 return 213 } 214 r.setRegValue(destReg, val) 215 } 216 217 218 if sourceImm, ok := i.Args[1].(arm64asm.Imm64); ok { 219 sourceNum := getImmValue(sourceImm.String()) 220 r.setRegValue(destReg, int(sourceNum)) 221 } 222 223 224 if sourceImm, ok := i.Args[1].(arm64asm.Imm); ok { 225 sourceNum := getImmValue(sourceImm.String()) 226 r.setRegValue(destReg, int(sourceNum)) 227 } 228 } 229 230 func (r *regState) update(i *disassembler.Instruction) { 231 232 switch i.Op { 233 case arm64asm.STR, arm64asm.STP, arm64asm.LDR, arm64asm.LDP: 234 r.updateAddrIndexInstruction(i) 235 236 case arm64asm.ADD, arm64asm.SUB: 237 r.updateAddSubInstruction(i) 238 239 case arm64asm.MOV: 240 r.updateMovInstruction(i) 241 } 242 } 243 244 func read(startPC uintptr, endPC uintptr) ([]*disassembler.Instruction, rookoutErrors.RookoutError) { 245 246 instructions, err := disassembler.Decode(startPC, endPC, true) 247 if err != nil { 248 return nil, err 249 } 250 251 var skipUntil uintptr 252 var prevInst *disassembler.Instruction 253 var notSkipped []*disassembler.Instruction 254 for _, inst := range instructions { 255 if skipUntil > inst.Offset { 256 continue 257 } 258 259 260 if prevInst != nil && prevInst.Op == arm64asm.B && inst.Op == arm64asm.NOP { 261 262 263 264 if pcrel, ok := prevInst.Args[0].(arm64asm.PCRel); ok { 265 skipUntil = prevInst.Offset + uintptr(pcrel) 266 } 267 } 268 269 notSkipped = append(notSkipped, inst) 270 prevInst = inst 271 } 272 273 return notSkipped, nil 274 } 275 276 func instructionSizeBytes(pc uintptr) (uintptr, rookoutErrors.RookoutError) { 277 return 4, nil 278 }