github.com/undoio/delve@v1.9.0/pkg/proc/x86_disasm.go (about) 1 package proc 2 3 import ( 4 "github.com/undoio/delve/pkg/dwarf/op" 5 6 "golang.org/x/arch/x86/x86asm" 7 ) 8 9 type x86Inst x86asm.Inst 10 11 // AsmDecode decodes the assembly instruction starting at mem[0:] into asmInst. 12 // It assumes that the Loc and AtPC fields of asmInst have already been filled. 13 func x86AsmDecode(asmInst *AsmInstruction, mem []byte, regs *op.DwarfRegisters, memrw MemoryReadWriter, bi *BinaryInfo, bit int) error { 14 inst, err := x86asm.Decode(mem, bit) 15 if err != nil { 16 asmInst.Inst = (*x86Inst)(nil) 17 asmInst.Size = 1 18 asmInst.Bytes = mem[:asmInst.Size] 19 return err 20 } 21 22 asmInst.Size = inst.Len 23 asmInst.Bytes = mem[:asmInst.Size] 24 patchPCRelX86(asmInst.Loc.PC, &inst) 25 asmInst.Inst = (*x86Inst)(&inst) 26 asmInst.Kind = OtherInstruction 27 28 switch inst.Op { 29 case x86asm.JMP, x86asm.LJMP: 30 asmInst.Kind = JmpInstruction 31 case x86asm.CALL, x86asm.LCALL: 32 asmInst.Kind = CallInstruction 33 case x86asm.RET, x86asm.LRET: 34 asmInst.Kind = RetInstruction 35 case x86asm.INT: 36 asmInst.Kind = HardBreakInstruction 37 } 38 39 asmInst.DestLoc = resolveCallArgX86(&inst, asmInst.Loc.PC, asmInst.AtPC, regs, memrw, bi) 40 return nil 41 } 42 43 // converts PC relative arguments to absolute addresses 44 func patchPCRelX86(pc uint64, inst *x86asm.Inst) { 45 for i := range inst.Args { 46 rel, isrel := inst.Args[i].(x86asm.Rel) 47 if isrel { 48 inst.Args[i] = x86asm.Imm(int64(pc) + int64(rel) + int64(inst.Len)) 49 } 50 } 51 } 52 53 func (inst *x86Inst) Text(flavour AssemblyFlavour, pc uint64, symLookup func(uint64) (string, uint64)) string { 54 if inst == nil { 55 return "?" 56 } 57 58 var text string 59 60 switch flavour { 61 case GNUFlavour: 62 text = x86asm.GNUSyntax(x86asm.Inst(*inst), pc, symLookup) 63 case GoFlavour: 64 text = x86asm.GoSyntax(x86asm.Inst(*inst), pc, symLookup) 65 case IntelFlavour: 66 fallthrough 67 default: 68 text = x86asm.IntelSyntax(x86asm.Inst(*inst), pc, symLookup) 69 } 70 71 return text 72 } 73 74 func (inst *x86Inst) OpcodeEquals(op uint64) bool { 75 if inst == nil { 76 return false 77 } 78 return uint64(inst.Op) == op 79 } 80 81 func resolveCallArgX86(inst *x86asm.Inst, instAddr uint64, currentGoroutine bool, regs *op.DwarfRegisters, mem MemoryReadWriter, bininfo *BinaryInfo) *Location { 82 switch inst.Op { 83 case x86asm.CALL, x86asm.LCALL, x86asm.JMP, x86asm.LJMP: 84 // ok 85 default: 86 return nil 87 } 88 89 var pc uint64 90 var err error 91 92 switch arg := inst.Args[0].(type) { 93 case x86asm.Imm: 94 pc = uint64(arg) 95 case x86asm.Reg: 96 if !currentGoroutine || regs == nil { 97 return nil 98 } 99 pc, err = bininfo.Arch.getAsmRegister(regs, int(arg)) 100 if err != nil { 101 return nil 102 } 103 case x86asm.Mem: 104 if !currentGoroutine || regs == nil { 105 return nil 106 } 107 if arg.Segment != 0 { 108 return nil 109 } 110 base, err1 := bininfo.Arch.getAsmRegister(regs, int(arg.Base)) 111 index, err2 := bininfo.Arch.getAsmRegister(regs, int(arg.Index)) 112 if err1 != nil || err2 != nil { 113 return nil 114 } 115 addr := uint64(int64(base) + int64(index*uint64(arg.Scale)) + arg.Disp) 116 pc, err = readUintRaw(mem, addr, int64(inst.MemBytes)) 117 if err != nil { 118 return nil 119 } 120 default: 121 return nil 122 } 123 124 file, line, fn := bininfo.PCToLine(pc) 125 if fn == nil { 126 return &Location{PC: pc} 127 } 128 return &Location{PC: pc, File: file, Line: line, Fn: fn} 129 }