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  }