mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 02:36:18 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			132 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			132 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // TODO: disassembler support should be compiled in unconditionally,
 | |
| // instead of being decided by the build-target architecture, and be
 | |
| // part of the Arch object instead.
 | |
| 
 | |
| package proc
 | |
| 
 | |
| import (
 | |
| 	"github.com/go-delve/delve/pkg/dwarf/op"
 | |
| 	"github.com/go-delve/delve/pkg/dwarf/regnum"
 | |
| 
 | |
| 	"golang.org/x/arch/arm64/arm64asm"
 | |
| )
 | |
| 
 | |
| func arm64AsmDecode(asmInst *AsmInstruction, mem []byte, regs *op.DwarfRegisters, memrw MemoryReadWriter, bi *BinaryInfo) error {
 | |
| 	asmInst.Size = 4
 | |
| 	asmInst.Bytes = mem[:asmInst.Size]
 | |
| 
 | |
| 	inst, err := arm64asm.Decode(mem)
 | |
| 	if err != nil {
 | |
| 		asmInst.Inst = (*arm64ArchInst)(nil)
 | |
| 		return err
 | |
| 	}
 | |
| 
 | |
| 	asmInst.Inst = (*arm64ArchInst)(&inst)
 | |
| 	asmInst.Kind = OtherInstruction
 | |
| 
 | |
| 	switch inst.Op {
 | |
| 	case arm64asm.BL, arm64asm.BLR:
 | |
| 		asmInst.Kind = CallInstruction
 | |
| 	case arm64asm.RET, arm64asm.ERET:
 | |
| 		asmInst.Kind = RetInstruction
 | |
| 	case arm64asm.B, arm64asm.BR:
 | |
| 		asmInst.Kind = JmpInstruction
 | |
| 	case arm64asm.BRK:
 | |
| 		asmInst.Kind = HardBreakInstruction
 | |
| 	}
 | |
| 
 | |
| 	asmInst.DestLoc = resolveCallArgARM64(&inst, asmInst.Loc.PC, asmInst.AtPC, regs, memrw, bi)
 | |
| 
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func resolveCallArgARM64(inst *arm64asm.Inst, instAddr uint64, currentGoroutine bool, regs *op.DwarfRegisters, mem MemoryReadWriter, bininfo *BinaryInfo) *Location {
 | |
| 	switch inst.Op {
 | |
| 	case arm64asm.BL, arm64asm.BLR, arm64asm.B, arm64asm.BR:
 | |
| 		// ok
 | |
| 	default:
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	var pc uint64
 | |
| 	var err error
 | |
| 
 | |
| 	switch arg := inst.Args[0].(type) {
 | |
| 	case arm64asm.Imm:
 | |
| 		pc = uint64(arg.Imm)
 | |
| 	case arm64asm.Reg:
 | |
| 		if !currentGoroutine || regs == nil {
 | |
| 			return nil
 | |
| 		}
 | |
| 		pc, err = bininfo.Arch.getAsmRegister(regs, int(arg))
 | |
| 		if err != nil {
 | |
| 			return nil
 | |
| 		}
 | |
| 	case arm64asm.PCRel:
 | |
| 		pc = uint64(instAddr) + uint64(arg)
 | |
| 	default:
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	file, line, fn := bininfo.PCToLine(pc)
 | |
| 	if fn == nil {
 | |
| 		return &Location{PC: pc}
 | |
| 	}
 | |
| 	return &Location{PC: pc, File: file, Line: line, Fn: fn}
 | |
| }
 | |
| 
 | |
| // Possible stacksplit prologues are inserted by stacksplit in
 | |
| // $GOROOT/src/cmd/internal/obj/arm64/obj7.go.
 | |
| var prologuesARM64 []opcodeSeq
 | |
| 
 | |
| func init() {
 | |
| 	var tinyStacksplit = opcodeSeq{uint64(arm64asm.MOV), uint64(arm64asm.CMP), uint64(arm64asm.B)}
 | |
| 	var smallStacksplit = opcodeSeq{uint64(arm64asm.SUB), uint64(arm64asm.CMP), uint64(arm64asm.B)}
 | |
| 	var bigStacksplit = opcodeSeq{uint64(arm64asm.CMP), uint64(arm64asm.B), uint64(arm64asm.ADD), uint64(arm64asm.SUB), uint64(arm64asm.MOV), uint64(arm64asm.CMP), uint64(arm64asm.B)}
 | |
| 	var unixGetG = opcodeSeq{uint64(arm64asm.LDR)}
 | |
| 
 | |
| 	prologuesARM64 = make([]opcodeSeq, 0, 3)
 | |
| 	for _, getG := range []opcodeSeq{unixGetG} {
 | |
| 		for _, stacksplit := range []opcodeSeq{tinyStacksplit, smallStacksplit, bigStacksplit} {
 | |
| 			prologue := make(opcodeSeq, 0, len(getG)+len(stacksplit))
 | |
| 			prologue = append(prologue, getG...)
 | |
| 			prologue = append(prologue, stacksplit...)
 | |
| 			prologuesARM64 = append(prologuesARM64, prologue)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| type arm64ArchInst arm64asm.Inst
 | |
| 
 | |
| func (inst *arm64ArchInst) Text(flavour AssemblyFlavour, pc uint64, symLookup func(uint64) (string, uint64)) string {
 | |
| 	if inst == nil {
 | |
| 		return "?"
 | |
| 	}
 | |
| 
 | |
| 	var text string
 | |
| 
 | |
| 	switch flavour {
 | |
| 	case GNUFlavour:
 | |
| 		text = arm64asm.GNUSyntax(arm64asm.Inst(*inst))
 | |
| 	default:
 | |
| 		text = arm64asm.GoSyntax(arm64asm.Inst(*inst), pc, symLookup, nil)
 | |
| 	}
 | |
| 
 | |
| 	return text
 | |
| }
 | |
| 
 | |
| func (inst *arm64ArchInst) OpcodeEquals(op uint64) bool {
 | |
| 	if inst == nil {
 | |
| 		return false
 | |
| 	}
 | |
| 	return uint64(inst.Op) == op
 | |
| }
 | |
| 
 | |
| var arm64AsmRegisters = func() map[int]asmRegister {
 | |
| 	r := make(map[int]asmRegister)
 | |
| 	for i := arm64asm.X0; i <= arm64asm.X30; i++ {
 | |
| 		r[int(i)] = asmRegister{regnum.ARM64_X0 + uint64(i-arm64asm.X0), 0, 0}
 | |
| 	}
 | |
| 	return r
 | |
| }()
 | 
