github.com/Rookout/GoSDK@v0.1.48/pkg/services/instrumentation/binary_info/arch_amd64.go (about) 1 // The MIT License (MIT) 2 3 // Copyright (c) 2014 Derek Parker 4 5 // Permission is hereby granted, free of charge, to any person obtaining a copy of 6 // this software and associated documentation files (the "Software"), to deal in 7 // the Software without restriction, including without limitation the rights to 8 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 // the Software, and to permit persons to whom the Software is furnished to do so, 10 // subject to the following conditions: 11 12 // The above copyright notice and this permission notice shall be included in all 13 // copies or substantial portions of the Software. 14 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22 //go:build amd64 23 // +build amd64 24 25 package binary_info 26 27 import ( 28 "bytes" 29 "encoding/binary" 30 "fmt" 31 "io" 32 "math" 33 "strings" 34 35 "github.com/Rookout/GoSDK/pkg/services/collection/registers" 36 "github.com/Rookout/GoSDK/pkg/services/instrumentation/dwarf/frame" 37 "github.com/Rookout/GoSDK/pkg/services/instrumentation/dwarf/op" 38 ) 39 40 const ( 41 DwarfIPRegNum uint64 = 16 42 DwarfSPRegNum uint64 = 7 43 DwarfBPRegNum uint64 = 6 44 ) 45 46 func FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *BinaryInfo) *frame.FrameContext { 47 if fctxt == nil || (bi.sigreturnfn != nil && pc >= bi.sigreturnfn.Entry && pc < bi.sigreturnfn.End) { 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 return &frame.FrameContext{ 67 RetAddrReg: DwarfIPRegNum, 68 Regs: map[uint64]frame.DWRule{ 69 DwarfIPRegNum: { 70 Rule: frame.RuleOffset, 71 Offset: int64(-bi.PointerSize), 72 }, 73 DwarfBPRegNum: { 74 Rule: frame.RuleOffset, 75 Offset: int64(-2 * bi.PointerSize), 76 }, 77 DwarfSPRegNum: { 78 Rule: frame.RuleValOffset, 79 Offset: 0, 80 }, 81 }, 82 CFA: frame.DWRule{ 83 Rule: frame.RuleCFA, 84 Reg: DwarfBPRegNum, 85 Offset: int64(2 * bi.PointerSize), 86 }, 87 } 88 } 89 90 if bi.crosscall2fn != nil && pc >= bi.crosscall2fn.Entry && pc < bi.crosscall2fn.End { 91 rule := fctxt.CFA 92 if rule.Offset == crosscall2SPOffsetBad { 93 rule.Offset += crosscall2SPOffset 94 } 95 fctxt.CFA = rule 96 } 97 98 99 100 101 102 if fctxt.Regs[DwarfBPRegNum].Rule == frame.RuleUndefined { 103 fctxt.Regs[DwarfBPRegNum] = frame.DWRule{ 104 Rule: frame.RuleFramePointer, 105 Reg: DwarfBPRegNum, 106 Offset: 0, 107 } 108 } 109 110 return fctxt 111 } 112 113 114 115 116 117 118 func RegSize(regnum uint64) int { 119 120 if regnum > DwarfIPRegNum && regnum <= 32 { 121 return 16 122 } 123 124 if regnum >= 33 && regnum <= 40 { 125 return 10 126 } 127 return 8 128 } 129 130 131 132 133 134 135 var amd64DwarfToName = map[int]string{ 136 0: "Rax", 137 1: "Rdx", 138 2: "Rcx", 139 3: "Rbx", 140 4: "Rsi", 141 5: "Rdi", 142 6: "Rbp", 143 7: "Rsp", 144 8: "R8", 145 9: "R9", 146 10: "R10", 147 11: "R11", 148 12: "R12", 149 13: "R13", 150 14: "R14", 151 15: "R15", 152 16: "Rip", 153 17: "XMM0", 154 18: "XMM1", 155 19: "XMM2", 156 20: "XMM3", 157 21: "XMM4", 158 22: "XMM5", 159 23: "XMM6", 160 24: "XMM7", 161 25: "XMM8", 162 26: "XMM9", 163 27: "XMM10", 164 28: "XMM11", 165 29: "XMM12", 166 30: "XMM13", 167 31: "XMM14", 168 32: "XMM15", 169 33: "ST(0)", 170 34: "ST(1)", 171 35: "ST(2)", 172 36: "ST(3)", 173 37: "ST(4)", 174 38: "ST(5)", 175 39: "ST(6)", 176 40: "ST(7)", 177 49: "Rflags", 178 50: "Es", 179 51: "Cs", 180 52: "Ss", 181 53: "Ds", 182 54: "Fs", 183 55: "Gs", 184 58: "Fs_base", 185 59: "Gs_base", 186 64: "MXCSR", 187 65: "CW", 188 66: "SW", 189 } 190 191 var amd64NameToDwarf = func() map[string]int { 192 r := make(map[string]int) 193 for regNum, regName := range amd64DwarfToName { 194 r[strings.ToLower(regName)] = regNum 195 } 196 r["eflags"] = 49 197 r["st0"] = 33 198 r["st1"] = 34 199 r["st2"] = 35 200 r["st3"] = 36 201 r["st4"] = 37 202 r["st5"] = 38 203 r["st6"] = 39 204 r["st7"] = 40 205 return r 206 }() 207 208 func maxAmd64DwarfRegister() int { 209 max := int(DwarfIPRegNum) 210 for i := range amd64DwarfToName { 211 if i > max { 212 max = i 213 } 214 } 215 return max 216 } 217 218 func RegistersToDwarfRegisters(staticBase uint64, regs registers.Registers) op.DwarfRegisters { 219 dregs := initDwarfRegistersFromSlice(maxAmd64DwarfRegister(), regs, amd64NameToDwarf) 220 dr := op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, DwarfIPRegNum, DwarfSPRegNum, DwarfBPRegNum, 0) 221 dr.SetLoadMoreCallback(loadMoreDwarfRegistersFromSliceFunc(dr, regs, amd64NameToDwarf)) 222 return *dr 223 } 224 225 func initDwarfRegistersFromSlice(maxRegs int, regs registers.Registers, nameToDwarf map[string]int) []*op.DwarfRegister { 226 dregs := make([]*op.DwarfRegister, maxRegs+1) 227 regslice, _ := regs.Slice(false) 228 for _, reg := range regslice { 229 if dwarfReg, ok := nameToDwarf[strings.ToLower(reg.Name)]; ok { 230 dregs[dwarfReg] = reg.Reg 231 } 232 } 233 return dregs 234 } 235 236 func loadMoreDwarfRegistersFromSliceFunc(dr *op.DwarfRegisters, regs registers.Registers, nameToDwarf map[string]int) func() { 237 return func() { 238 regslice, err := regs.Slice(true) 239 dr.FloatLoadError = err 240 for _, reg := range regslice { 241 name := strings.ToLower(reg.Name) 242 if dwarfReg, ok := nameToDwarf[name]; ok { 243 dr.AddReg(uint64(dwarfReg), reg.Reg) 244 } else if reg.Reg.Bytes != nil && (strings.HasPrefix(name, "ymm") || strings.HasPrefix(name, "zmm")) { 245 xmmIdx, ok := nameToDwarf["x"+name[1:]] 246 if !ok { 247 continue 248 } 249 xmmReg := dr.Reg(uint64(xmmIdx)) 250 if xmmReg == nil || xmmReg.Bytes == nil { 251 continue 252 } 253 nb := make([]byte, 0, len(xmmReg.Bytes)+len(reg.Reg.Bytes)) 254 nb = append(nb, xmmReg.Bytes...) 255 nb = append(nb, reg.Reg.Bytes...) 256 xmmReg.Bytes = nb 257 } 258 } 259 } 260 } 261 262 func AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters { 263 dregs := make([]*op.DwarfRegister, DwarfIPRegNum+1) 264 dregs[DwarfIPRegNum] = op.DwarfRegisterFromUint64(pc) 265 dregs[DwarfSPRegNum] = op.DwarfRegisterFromUint64(sp) 266 dregs[DwarfBPRegNum] = op.DwarfRegisterFromUint64(bp) 267 268 return *op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, DwarfIPRegNum, DwarfSPRegNum, DwarfBPRegNum, 0) 269 } 270 271 func formatSSEReg(name string, reg []byte) string { 272 out := new(bytes.Buffer) 273 formatSSERegInternal(reg, out) 274 if len(reg) < 32 { 275 return out.String() 276 } 277 278 fmt.Fprintf(out, "\n\t[%sh] ", "Y"+name[1:]) 279 formatSSERegInternal(reg[16:], out) 280 281 if len(reg) < 64 { 282 return out.String() 283 } 284 285 fmt.Fprintf(out, "\n\t[%shl] ", "Z"+name[1:]) 286 formatSSERegInternal(reg[32:], out) 287 fmt.Fprintf(out, "\n\t[%shh] ", "Z"+name[1:]) 288 formatSSERegInternal(reg[48:], out) 289 290 return out.String() 291 } 292 293 func formatSSERegInternal(xmm []byte, out *bytes.Buffer) { 294 buf := bytes.NewReader(xmm) 295 296 var vi [16]uint8 297 for i := range vi { 298 binary.Read(buf, binary.LittleEndian, &vi[i]) 299 } 300 301 fmt.Fprintf(out, "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8], vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0]) 302 303 fmt.Fprintf(out, "\tv2_int={ %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x%02x%02x%02x%02x }", vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0], vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8]) 304 305 fmt.Fprintf(out, "\tv4_int={ %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x }", vi[3], vi[2], vi[1], vi[0], vi[7], vi[6], vi[5], vi[4], vi[11], vi[10], vi[9], vi[8], vi[15], vi[14], vi[13], vi[12]) 306 307 fmt.Fprintf(out, "\tv8_int={ %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x }", vi[1], vi[0], vi[3], vi[2], vi[5], vi[4], vi[7], vi[6], vi[9], vi[8], vi[11], vi[10], vi[13], vi[12], vi[15], vi[14]) 308 309 fmt.Fprintf(out, "\tv16_int={ %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x }", vi[0], vi[1], vi[2], vi[3], vi[4], vi[5], vi[6], vi[7], vi[8], vi[9], vi[10], vi[11], vi[12], vi[13], vi[14], vi[15]) 310 311 buf.Seek(0, io.SeekStart) 312 var v2 [2]float64 313 for i := range v2 { 314 binary.Read(buf, binary.LittleEndian, &v2[i]) 315 } 316 fmt.Fprintf(out, "\tv2_float={ %g %g }", v2[0], v2[1]) 317 318 buf.Seek(0, io.SeekStart) 319 var v4 [4]float32 320 for i := range v4 { 321 binary.Read(buf, binary.LittleEndian, &v4[i]) 322 } 323 fmt.Fprintf(out, "\tv4_float={ %g %g %g %g }", v4[0], v4[1], v4[2], v4[3]) 324 } 325 326 func formatX87Reg(b []byte) string { 327 if len(b) < 10 { 328 return fmt.Sprintf("%#x", b) 329 } 330 mantissa := binary.LittleEndian.Uint64(b[:8]) 331 exponent := uint16(binary.LittleEndian.Uint16(b[8:])) 332 333 var f float64 334 fset := false 335 336 const ( 337 _SIGNBIT = 1 << 15 338 _EXP_BIAS = (1 << 14) - 1 339 _SPECIALEXP = (1 << 15) - 1 340 _HIGHBIT = 1 << 63 341 _QUIETBIT = 1 << 62 342 ) 343 344 sign := 1.0 345 if exponent&_SIGNBIT != 0 { 346 sign = -1.0 347 } 348 exponent &= ^uint16(_SIGNBIT) 349 350 NaN := math.NaN() 351 Inf := math.Inf(+1) 352 353 switch exponent { 354 case 0: 355 switch { 356 case mantissa == 0: 357 f = sign * 0.0 358 fset = true 359 case mantissa&_HIGHBIT != 0: 360 f = NaN 361 fset = true 362 } 363 case _SPECIALEXP: 364 switch { 365 case mantissa&_HIGHBIT == 0: 366 f = sign * Inf 367 fset = true 368 default: 369 f = NaN 370 fset = true 371 } 372 default: 373 if mantissa&_HIGHBIT == 0 { 374 f = NaN 375 fset = true 376 } 377 } 378 379 if !fset { 380 significand := float64(mantissa) / (1 << 63) 381 f = sign * math.Ldexp(significand, int(exponent-_EXP_BIAS)) 382 } 383 384 var buf bytes.Buffer 385 binary.Write(&buf, binary.LittleEndian, exponent) 386 binary.Write(&buf, binary.LittleEndian, mantissa) 387 388 return fmt.Sprintf("%#04x%016x\t%g", exponent, mantissa, f) 389 }