mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 10:47:27 +08:00 
			
		
		
		
	 5452c30fac
			
		
	
	5452c30fac
	
	
	
		
			
			The ebpf implementations uses cgo, but only to access some C struct definitions. Instead of using cgo simply duplicate the defintion of those two structs in Go and add a test to check that the duplicate definitions remain synchronized. Fixes #2827
		
			
				
	
	
		
			182 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			182 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package proc
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 
 | |
| 	"github.com/go-delve/delve/pkg/dwarf/op"
 | |
| )
 | |
| 
 | |
| // AsmInstruction represents one assembly instruction.
 | |
| type AsmInstruction struct {
 | |
| 	Loc        Location
 | |
| 	DestLoc    *Location
 | |
| 	Bytes      []byte
 | |
| 	Breakpoint bool
 | |
| 	AtPC       bool
 | |
| 
 | |
| 	Size int
 | |
| 	Kind AsmInstructionKind
 | |
| 
 | |
| 	Inst archInst
 | |
| }
 | |
| 
 | |
| type AsmInstructionKind uint8
 | |
| 
 | |
| const (
 | |
| 	OtherInstruction AsmInstructionKind = iota
 | |
| 	CallInstruction
 | |
| 	RetInstruction
 | |
| 	JmpInstruction
 | |
| 	HardBreakInstruction
 | |
| )
 | |
| 
 | |
| // IsCall is true if instr is a call instruction.
 | |
| func (instr *AsmInstruction) IsCall() bool {
 | |
| 	return instr.Kind == CallInstruction
 | |
| }
 | |
| 
 | |
| // IsRet is true if instr is a return instruction.
 | |
| func (instr *AsmInstruction) IsRet() bool {
 | |
| 	return instr.Kind == RetInstruction
 | |
| }
 | |
| 
 | |
| // IsJmp is true if instr is an unconditional jump instruction.
 | |
| func (instr *AsmInstruction) IsJmp() bool {
 | |
| 	return instr.Kind == JmpInstruction
 | |
| }
 | |
| 
 | |
| // IsHardBreak is true if instr is a hardcoded breakpoint instruction.
 | |
| func (instr *AsmInstruction) IsHardBreak() bool {
 | |
| 	return instr.Kind == HardBreakInstruction
 | |
| }
 | |
| 
 | |
| type archInst interface {
 | |
| 	Text(flavour AssemblyFlavour, pc uint64, symLookup func(uint64) (string, uint64)) string
 | |
| 	OpcodeEquals(op uint64) bool
 | |
| }
 | |
| 
 | |
| // AssemblyFlavour is the assembly syntax to display.
 | |
| type AssemblyFlavour int
 | |
| 
 | |
| const (
 | |
| 	// GNUFlavour will display GNU assembly syntax.
 | |
| 	GNUFlavour AssemblyFlavour = iota
 | |
| 	// IntelFlavour will display Intel assembly syntax.
 | |
| 	IntelFlavour
 | |
| 	// GoFlavour will display Go assembly syntax.
 | |
| 	GoFlavour
 | |
| )
 | |
| 
 | |
| type opcodeSeq []uint64
 | |
| 
 | |
| // firstPCAfterPrologueDisassembly returns the address of the first
 | |
| // instruction after the prologue for function fn by disassembling fn and
 | |
| // matching the instructions against known split-stack prologue patterns.
 | |
| // If sameline is set firstPCAfterPrologueDisassembly will always return an
 | |
| // address associated with the same line as fn.Entry
 | |
| func firstPCAfterPrologueDisassembly(p Process, fn *Function, sameline bool) (uint64, error) {
 | |
| 	mem := p.Memory()
 | |
| 	breakpoints := p.Breakpoints()
 | |
| 	bi := p.BinInfo()
 | |
| 	text, err := disassemble(mem, nil, breakpoints, bi, fn.Entry, fn.End, false)
 | |
| 	if err != nil {
 | |
| 		return fn.Entry, err
 | |
| 	}
 | |
| 
 | |
| 	if len(text) <= 0 {
 | |
| 		return fn.Entry, nil
 | |
| 	}
 | |
| 
 | |
| 	for _, prologue := range p.BinInfo().Arch.prologues {
 | |
| 		if len(prologue) >= len(text) {
 | |
| 			continue
 | |
| 		}
 | |
| 		if checkPrologue(text, prologue) {
 | |
| 			r := &text[len(prologue)]
 | |
| 			if sameline {
 | |
| 				if r.Loc.Line != text[0].Loc.Line {
 | |
| 					return fn.Entry, nil
 | |
| 				}
 | |
| 			}
 | |
| 			return r.Loc.PC, nil
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return fn.Entry, nil
 | |
| }
 | |
| 
 | |
| func checkPrologue(s []AsmInstruction, prologuePattern opcodeSeq) bool {
 | |
| 	line := s[0].Loc.Line
 | |
| 	for i, op := range prologuePattern {
 | |
| 		if !s[i].Inst.OpcodeEquals(op) || s[i].Loc.Line != line {
 | |
| 			return false
 | |
| 		}
 | |
| 	}
 | |
| 	return true
 | |
| }
 | |
| 
 | |
| // Disassemble disassembles target memory between startAddr and endAddr, marking
 | |
| // the current instruction being executed in goroutine g.
 | |
| // If currentGoroutine is set and thread is stopped at a CALL instruction Disassemble
 | |
| // will evaluate the argument of the CALL instruction using the thread's registers.
 | |
| // Be aware that the Bytes field of each returned instruction is a slice of a larger array of size startAddr - endAddr.
 | |
| func Disassemble(mem MemoryReadWriter, regs Registers, breakpoints *BreakpointMap, bi *BinaryInfo, startAddr, endAddr uint64) ([]AsmInstruction, error) {
 | |
| 	if startAddr > endAddr {
 | |
| 		return nil, fmt.Errorf("start address(%x) should be less than end address(%x)", startAddr, endAddr)
 | |
| 	}
 | |
| 	return disassemble(mem, regs, breakpoints, bi, startAddr, endAddr, false)
 | |
| }
 | |
| 
 | |
| func disassemble(memrw MemoryReadWriter, regs Registers, breakpoints *BreakpointMap, bi *BinaryInfo, startAddr, endAddr uint64, singleInstr bool) ([]AsmInstruction, error) {
 | |
| 	var dregs *op.DwarfRegisters
 | |
| 	if regs != nil {
 | |
| 		dregs = bi.Arch.RegistersToDwarfRegisters(0, regs)
 | |
| 	}
 | |
| 
 | |
| 	mem := make([]byte, int(endAddr-startAddr))
 | |
| 	_, err := memrw.ReadMemory(mem, startAddr)
 | |
| 	if err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 
 | |
| 	r := make([]AsmInstruction, 0, len(mem)/int(bi.Arch.MaxInstructionLength()))
 | |
| 	pc := startAddr
 | |
| 
 | |
| 	var curpc uint64
 | |
| 	if regs != nil {
 | |
| 		curpc = regs.PC()
 | |
| 	}
 | |
| 
 | |
| 	for len(mem) > 0 {
 | |
| 		bp, atbp := breakpoints.M[pc]
 | |
| 		if atbp {
 | |
| 			copy(mem, bp.OriginalData)
 | |
| 		}
 | |
| 
 | |
| 		file, line, fn := bi.PCToLine(pc)
 | |
| 
 | |
| 		var inst AsmInstruction
 | |
| 		inst.Loc = Location{PC: pc, File: file, Line: line, Fn: fn}
 | |
| 		inst.Breakpoint = atbp
 | |
| 		inst.AtPC = (regs != nil) && (curpc == pc)
 | |
| 
 | |
| 		bi.Arch.asmDecode(&inst, mem, dregs, memrw, bi)
 | |
| 
 | |
| 		r = append(r, inst)
 | |
| 
 | |
| 		pc += uint64(inst.Size)
 | |
| 		mem = mem[inst.Size:]
 | |
| 
 | |
| 		if singleInstr {
 | |
| 			break
 | |
| 		}
 | |
| 	}
 | |
| 	return r, nil
 | |
| }
 | |
| 
 | |
| // Text will return the assembly instructions in human readable format according to
 | |
| // the flavour specified.
 | |
| func (inst *AsmInstruction) Text(flavour AssemblyFlavour, bi *BinaryInfo) string {
 | |
| 	return inst.Inst.Text(flavour, inst.Loc.PC, bi.symLookup)
 | |
| }
 |