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 := &regState{
    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(&reg))
   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  }