github.com/undoio/delve@v1.9.0/pkg/proc/arm64_disasm.go (about)

     1  // TODO: disassembler support should be compiled in unconditionally,
     2  // instead of being decided by the build-target architecture, and be
     3  // part of the Arch object instead.
     4  
     5  package proc
     6  
     7  import (
     8  	"github.com/undoio/delve/pkg/dwarf/op"
     9  	"github.com/undoio/delve/pkg/dwarf/regnum"
    10  
    11  	"golang.org/x/arch/arm64/arm64asm"
    12  )
    13  
    14  func arm64AsmDecode(asmInst *AsmInstruction, mem []byte, regs *op.DwarfRegisters, memrw MemoryReadWriter, bi *BinaryInfo) error {
    15  	asmInst.Size = 4
    16  	asmInst.Bytes = mem[:asmInst.Size]
    17  
    18  	inst, err := arm64asm.Decode(mem)
    19  	if err != nil {
    20  		asmInst.Inst = (*arm64ArchInst)(nil)
    21  		return err
    22  	}
    23  
    24  	asmInst.Inst = (*arm64ArchInst)(&inst)
    25  	asmInst.Kind = OtherInstruction
    26  
    27  	switch inst.Op {
    28  	case arm64asm.BL, arm64asm.BLR:
    29  		asmInst.Kind = CallInstruction
    30  	case arm64asm.RET, arm64asm.ERET:
    31  		asmInst.Kind = RetInstruction
    32  	case arm64asm.B, arm64asm.BR:
    33  		asmInst.Kind = JmpInstruction
    34  	case arm64asm.BRK:
    35  		asmInst.Kind = HardBreakInstruction
    36  	}
    37  
    38  	asmInst.DestLoc = resolveCallArgARM64(&inst, asmInst.Loc.PC, asmInst.AtPC, regs, memrw, bi)
    39  
    40  	return nil
    41  }
    42  
    43  func resolveCallArgARM64(inst *arm64asm.Inst, instAddr uint64, currentGoroutine bool, regs *op.DwarfRegisters, mem MemoryReadWriter, bininfo *BinaryInfo) *Location {
    44  	switch inst.Op {
    45  	case arm64asm.BL, arm64asm.BLR, arm64asm.B, arm64asm.BR:
    46  		//ok
    47  	default:
    48  		return nil
    49  	}
    50  
    51  	var pc uint64
    52  	var err error
    53  
    54  	switch arg := inst.Args[0].(type) {
    55  	case arm64asm.Imm:
    56  		pc = uint64(arg.Imm)
    57  	case arm64asm.Reg:
    58  		if !currentGoroutine || regs == nil {
    59  			return nil
    60  		}
    61  		pc, err = bininfo.Arch.getAsmRegister(regs, int(arg))
    62  		if err != nil {
    63  			return nil
    64  		}
    65  	case arm64asm.PCRel:
    66  		pc = uint64(instAddr) + uint64(arg)
    67  	default:
    68  		return nil
    69  	}
    70  
    71  	file, line, fn := bininfo.PCToLine(pc)
    72  	if fn == nil {
    73  		return &Location{PC: pc}
    74  	}
    75  	return &Location{PC: pc, File: file, Line: line, Fn: fn}
    76  }
    77  
    78  // Possible stacksplit prologues are inserted by stacksplit in
    79  // $GOROOT/src/cmd/internal/obj/arm64/obj7.go.
    80  var prologuesARM64 []opcodeSeq
    81  
    82  func init() {
    83  	var tinyStacksplit = opcodeSeq{uint64(arm64asm.MOV), uint64(arm64asm.CMP), uint64(arm64asm.B)}
    84  	var smallStacksplit = opcodeSeq{uint64(arm64asm.SUB), uint64(arm64asm.CMP), uint64(arm64asm.B)}
    85  	var bigStacksplit = opcodeSeq{uint64(arm64asm.CMP), uint64(arm64asm.B), uint64(arm64asm.ADD), uint64(arm64asm.SUB), uint64(arm64asm.MOV), uint64(arm64asm.CMP), uint64(arm64asm.B)}
    86  	var unixGetG = opcodeSeq{uint64(arm64asm.LDR)}
    87  
    88  	prologuesARM64 = make([]opcodeSeq, 0, 3)
    89  	for _, getG := range []opcodeSeq{unixGetG} {
    90  		for _, stacksplit := range []opcodeSeq{tinyStacksplit, smallStacksplit, bigStacksplit} {
    91  			prologue := make(opcodeSeq, 0, len(getG)+len(stacksplit))
    92  			prologue = append(prologue, getG...)
    93  			prologue = append(prologue, stacksplit...)
    94  			prologuesARM64 = append(prologuesARM64, prologue)
    95  		}
    96  	}
    97  }
    98  
    99  type arm64ArchInst arm64asm.Inst
   100  
   101  func (inst *arm64ArchInst) Text(flavour AssemblyFlavour, pc uint64, symLookup func(uint64) (string, uint64)) string {
   102  	if inst == nil {
   103  		return "?"
   104  	}
   105  
   106  	var text string
   107  
   108  	switch flavour {
   109  	case GNUFlavour:
   110  		text = arm64asm.GNUSyntax(arm64asm.Inst(*inst))
   111  	default:
   112  		text = arm64asm.GoSyntax(arm64asm.Inst(*inst), pc, symLookup, nil)
   113  	}
   114  
   115  	return text
   116  }
   117  
   118  func (inst *arm64ArchInst) OpcodeEquals(op uint64) bool {
   119  	if inst == nil {
   120  		return false
   121  	}
   122  	return uint64(inst.Op) == op
   123  }
   124  
   125  var arm64AsmRegisters = func() map[int]asmRegister {
   126  	r := make(map[int]asmRegister)
   127  	for i := arm64asm.X0; i <= arm64asm.X30; i++ {
   128  		r[int(i)] = asmRegister{regnum.ARM64_X0 + uint64(i-arm64asm.X0), 0, 0}
   129  	}
   130  	return r
   131  }()