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  }