github.com/Rookout/GoSDK@v0.1.48/pkg/services/instrumentation/binary_info/arch_arm64.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 arm64
    23  // +build arm64
    24  
    25  package binary_info
    26  
    27  import (
    28  	"bytes"
    29  	"encoding/binary"
    30  	"fmt"
    31  	"strings"
    32  
    33  	"github.com/Rookout/GoSDK/pkg/services/collection/registers"
    34  	"github.com/Rookout/GoSDK/pkg/services/instrumentation/dwarf/frame"
    35  	"github.com/Rookout/GoSDK/pkg/services/instrumentation/dwarf/op"
    36  )
    37  
    38  var arm64BreakInstruction = []byte{0x0, 0x0, 0x20, 0xd4}
    39  
    40  const (
    41  	DwarfPCRegNum                uint64 = 32
    42  	DwarfSPRegNum                uint64 = 31
    43  	DwarfLRRegNum                uint64 = 30
    44  	DwarfBPRegNum                uint64 = 29
    45  	DwarfV0RegNum                uint64 = 64
    46  	_ARM64_MaxRegNum                    = DwarfV0RegNum + 31
    47  	crosscall2SPOffsetNonWindows        = 0x58
    48  )
    49  
    50  func FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *BinaryInfo) *frame.FrameContext {
    51  	if fctxt == nil || (bi.sigreturnfn != nil && pc >= bi.sigreturnfn.Entry && pc < bi.sigreturnfn.End) {
    52  		
    53  		
    54  		
    55  		
    56  		
    57  
    58  		
    59  		
    60  		
    61  		
    62  		
    63  		
    64  		
    65  		
    66  		
    67  		
    68  		
    69  
    70  		return &frame.FrameContext{
    71  			RetAddrReg: DwarfPCRegNum,
    72  			Regs: map[uint64]frame.DWRule{
    73  				DwarfPCRegNum: frame.DWRule{
    74  					Rule:   frame.RuleOffset,
    75  					Offset: int64(-bi.PointerSize),
    76  				},
    77  				DwarfBPRegNum: frame.DWRule{
    78  					Rule:   frame.RuleOffset,
    79  					Offset: int64(-2 * bi.PointerSize),
    80  				},
    81  				DwarfSPRegNum: frame.DWRule{
    82  					Rule:   frame.RuleValOffset,
    83  					Offset: 0,
    84  				},
    85  			},
    86  			CFA: frame.DWRule{
    87  				Rule:   frame.RuleCFA,
    88  				Reg:    DwarfBPRegNum,
    89  				Offset: int64(2 * bi.PointerSize),
    90  			},
    91  		}
    92  	}
    93  
    94  	if bi.crosscall2fn != nil && pc >= bi.crosscall2fn.Entry && pc < bi.crosscall2fn.End {
    95  		rule := fctxt.CFA
    96  		if rule.Offset == crosscall2SPOffsetBad {
    97  			rule.Offset += crosscall2SPOffsetNonWindows
    98  		}
    99  		fctxt.CFA = rule
   100  	}
   101  
   102  	
   103  	
   104  	
   105  	
   106  	if fctxt.Regs[DwarfBPRegNum].Rule == frame.RuleUndefined {
   107  		fctxt.Regs[DwarfBPRegNum] = frame.DWRule{
   108  			Rule:   frame.RuleFramePointer,
   109  			Reg:    DwarfBPRegNum,
   110  			Offset: 0,
   111  		}
   112  	}
   113  	if fctxt.Regs[DwarfLRRegNum].Rule == frame.RuleUndefined {
   114  		fctxt.Regs[DwarfLRRegNum] = frame.DWRule{
   115  			Rule:   frame.RuleFramePointer,
   116  			Reg:    DwarfLRRegNum,
   117  			Offset: 0,
   118  		}
   119  	}
   120  
   121  	return fctxt
   122  }
   123  
   124  const arm64cgocallSPOffsetSaveSlot = 0x8
   125  const prevG0schedSPOffsetSaveSlot = 0x10
   126  
   127  func RegSize(regnum uint64) int {
   128  	
   129  	if regnum >= 64 && regnum <= 95 {
   130  		return 16
   131  	}
   132  
   133  	return 8 
   134  }
   135  
   136  func ARM64ToName(num uint64) string {
   137  	switch {
   138  	case num <= 30:
   139  		return fmt.Sprintf("X%d", num)
   140  	case num == DwarfSPRegNum:
   141  		return "SP"
   142  	case num == DwarfPCRegNum:
   143  		return "PC"
   144  	case num >= DwarfV0RegNum && num <= 95:
   145  		return fmt.Sprintf("V%d", num-64)
   146  	default:
   147  		return fmt.Sprintf("unknown%d", num)
   148  	}
   149  }
   150  
   151  var NameToDwarf = func() map[string]int {
   152  	r := make(map[string]int)
   153  	for i := 0; i <= 32; i++ {
   154  		r[fmt.Sprintf("x%d", i)] = i
   155  	}
   156  	r["fp"] = 29
   157  	r["lr"] = int(DwarfLRRegNum)
   158  	r["sp"] = 31
   159  	r["pc"] = int(DwarfPCRegNum)
   160  	for i := 0; i <= 31; i++ {
   161  		r[fmt.Sprintf("v%d", i)] = i + 64
   162  	}
   163  	return r
   164  }()
   165  
   166  func RegistersToDwarfRegisters(staticBase uint64, regs registers.Registers) op.DwarfRegisters {
   167  	dregs := initDwarfRegistersFromSlice(int(_ARM64_MaxRegNum), regs, NameToDwarf)
   168  	dr := op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, DwarfPCRegNum, DwarfSPRegNum, DwarfBPRegNum, DwarfLRRegNum)
   169  	dr.SetLoadMoreCallback(loadMoreDwarfRegistersFromSliceFunc(dr, regs, NameToDwarf))
   170  	return *dr
   171  }
   172  
   173  func loadMoreDwarfRegistersFromSliceFunc(dr *op.DwarfRegisters, regs registers.Registers, nameToDwarf map[string]int) func() {
   174  	return func() {
   175  		regslice, err := regs.Slice(true)
   176  		dr.FloatLoadError = err
   177  		for _, reg := range regslice {
   178  			name := strings.ToLower(reg.Name)
   179  			if dwarfReg, ok := nameToDwarf[name]; ok {
   180  				dr.AddReg(uint64(dwarfReg), reg.Reg)
   181  			} else if reg.Reg.Bytes != nil && (strings.HasPrefix(name, "ymm") || strings.HasPrefix(name, "zmm")) {
   182  				xmmIdx, ok := nameToDwarf["x"+name[1:]]
   183  				if !ok {
   184  					continue
   185  				}
   186  				xmmReg := dr.Reg(uint64(xmmIdx))
   187  				if xmmReg == nil || xmmReg.Bytes == nil {
   188  					continue
   189  				}
   190  				nb := make([]byte, 0, len(xmmReg.Bytes)+len(reg.Reg.Bytes))
   191  				nb = append(nb, xmmReg.Bytes...)
   192  				nb = append(nb, reg.Reg.Bytes...)
   193  				xmmReg.Bytes = nb
   194  			}
   195  		}
   196  	}
   197  }
   198  
   199  func arm64AddrAndStackRegsToDwarfRegisters(staticBase, pc, sp, bp, lr uint64) op.DwarfRegisters {
   200  	dregs := make([]*op.DwarfRegister, DwarfPCRegNum+1)
   201  	dregs[DwarfPCRegNum] = op.DwarfRegisterFromUint64(pc)
   202  	dregs[DwarfSPRegNum] = op.DwarfRegisterFromUint64(sp)
   203  	dregs[DwarfBPRegNum] = op.DwarfRegisterFromUint64(bp)
   204  	dregs[DwarfLRRegNum] = op.DwarfRegisterFromUint64(lr)
   205  
   206  	return *op.NewDwarfRegisters(staticBase, dregs, binary.LittleEndian, DwarfPCRegNum, DwarfSPRegNum, DwarfBPRegNum, DwarfLRRegNum)
   207  }
   208  
   209  func initDwarfRegistersFromSlice(maxRegs int, regs registers.Registers, nameToDwarf map[string]int) []*op.DwarfRegister {
   210  	dregs := make([]*op.DwarfRegister, maxRegs+1)
   211  	regslice, _ := regs.Slice(false)
   212  	for _, reg := range regslice {
   213  		if dwarfReg, ok := nameToDwarf[strings.ToLower(reg.Name)]; ok {
   214  			dregs[dwarfReg] = reg.Reg
   215  		}
   216  	}
   217  	return dregs
   218  }
   219  
   220  func arm64DwarfRegisterToString(i int, reg *op.DwarfRegister) (name string, floatingPoint bool, repr string) {
   221  	name = ARM64ToName(uint64(i))
   222  
   223  	if reg == nil {
   224  		return name, false, ""
   225  	}
   226  
   227  	if reg.Bytes != nil && name[0] == 'V' {
   228  		buf := bytes.NewReader(reg.Bytes)
   229  
   230  		var out bytes.Buffer
   231  		var vi [16]uint8
   232  		for i := range vi {
   233  			_ = binary.Read(buf, binary.LittleEndian, &vi[i])
   234  		}
   235  		
   236  		fmt.Fprintf(&out, " {\n\tD = {u = {0x%02x%02x%02x%02x%02x%02x%02x%02x,", vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0])
   237  		fmt.Fprintf(&out, " 0x%02x%02x%02x%02x%02x%02x%02x%02x},", vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8])
   238  		fmt.Fprintf(&out, " s = {0x%02x%02x%02x%02x%02x%02x%02x%02x,", vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0])
   239  		fmt.Fprintf(&out, " 0x%02x%02x%02x%02x%02x%02x%02x%02x}},", vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8])
   240  
   241  		
   242  		fmt.Fprintf(&out, " \n\tS = {u = {0x%02x%02x%02x%02x,0x%02x%02x%02x%02x,", vi[3], vi[2], vi[1], vi[0], vi[7], vi[6], vi[5], vi[4])
   243  		fmt.Fprintf(&out, " 0x%02x%02x%02x%02x,0x%02x%02x%02x%02x},", vi[11], vi[10], vi[9], vi[8], vi[15], vi[14], vi[13], vi[12])
   244  		fmt.Fprintf(&out, " s = {0x%02x%02x%02x%02x,0x%02x%02x%02x%02x,", vi[3], vi[2], vi[1], vi[0], vi[7], vi[6], vi[5], vi[4])
   245  		fmt.Fprintf(&out, " 0x%02x%02x%02x%02x,0x%02x%02x%02x%02x}},", vi[11], vi[10], vi[9], vi[8], vi[15], vi[14], vi[13], vi[12])
   246  
   247  		
   248  		fmt.Fprintf(&out, " \n\tH = {u = {0x%02x%02x,0x%02x%02x,0x%02x%02x,0x%02x%02x,", vi[1], vi[0], vi[3], vi[2], vi[5], vi[4], vi[7], vi[6])
   249  		fmt.Fprintf(&out, " 0x%02x%02x,0x%02x%02x,0x%02x%02x,0x%02x%02x},", vi[9], vi[8], vi[11], vi[10], vi[13], vi[12], vi[15], vi[14])
   250  		fmt.Fprintf(&out, " s = {0x%02x%02x,0x%02x%02x,0x%02x%02x,0x%02x%02x,", vi[1], vi[0], vi[3], vi[2], vi[5], vi[4], vi[7], vi[6])
   251  		fmt.Fprintf(&out, " 0x%02x%02x,0x%02x%02x,0x%02x%02x,0x%02x%02x}},", vi[9], vi[8], vi[11], vi[10], vi[13], vi[12], vi[15], vi[14])
   252  
   253  		
   254  		fmt.Fprintf(&out, " \n\tB = {u = {0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,", vi[0], vi[1], vi[2], vi[3], vi[4], vi[5], vi[6], vi[7])
   255  		fmt.Fprintf(&out, " 0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x},", vi[8], vi[9], vi[10], vi[11], vi[12], vi[13], vi[14], vi[15])
   256  		fmt.Fprintf(&out, " s = {0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,", vi[0], vi[1], vi[2], vi[3], vi[4], vi[5], vi[6], vi[7])
   257  		fmt.Fprintf(&out, " 0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x}}", vi[8], vi[9], vi[10], vi[11], vi[12], vi[13], vi[14], vi[15])
   258  
   259  		
   260  		fmt.Fprintf(&out, " \n\tQ = {u = {0x%02x%02x%02x%02x%02x%02x%02x%02x", vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8])
   261  		fmt.Fprintf(&out, "%02x%02x%02x%02x%02x%02x%02x%02x},", vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0])
   262  		fmt.Fprintf(&out, " s = {0x%02x%02x%02x%02x%02x%02x%02x%02x", vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8])
   263  		fmt.Fprintf(&out, "%02x%02x%02x%02x%02x%02x%02x%02x}}\n\t}", vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0])
   264  		return name, true, out.String()
   265  	} else if reg.Bytes == nil || (reg.Bytes != nil && len(reg.Bytes) < 16) {
   266  		return name, false, fmt.Sprintf("%#016x", reg.Uint64Val)
   267  	}
   268  	return name, false, fmt.Sprintf("%#x", reg.Bytes)
   269  }