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 }()