mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 02:36:18 +08:00 
			
		
		
		
	 9c5777e762
			
		
	
	9c5777e762
	
	
	
		
			
			* pkg/proc: convert freebsd ptrace code to cgo There is little point in having cgo call a custom C function, when the same can be done directly from cgo (with less code and effort). Split the amd64 specific code into ptrace_freebsd_amd64.go. Also avoid mixing C.ptrace() with syscall.SYS_PTRACE. This will make further changes easier - no functional change intended. * pkg/proc: check return values of ptrace calls on freebsd The return values of the PT_GETNUMLWPS and PT_GETLWPLIST ptrace calls were previously unchecked. While these should not fail, panic instead of using -1 with slice allocation/handling. * pkg/proc: return *amd64util.AMD64Xstate from freebsd ptraceGetRegset Return a pointer to a struct, rather than a struct - this simplifies the code in both the caller and the ptraceGetRegset function, while also avoiding struct copying. * pkg/proc: fix floating point register setting on freebsd The original code could never work - PT_SETREGS on freebsd does not take an iovec, nor does it set FP registers. Furthermore, the xsave bytes were not stored in the amd64util.AMD64Xstate struct. Updates #3001 * pkg/proc: re-enable function call injection on freebsd Floating point registers can now be set and restored correctly. This is a partial revert of 51090f003bace1f8cc37b8480ffdb6f6cc91fa5a. Fixes #3001 * pkg/proc: deduplicate register setting code on freebsd
		
			
				
	
	
		
			253 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			253 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package fbsdutil
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 
 | |
| 	"github.com/go-delve/delve/pkg/dwarf/op"
 | |
| 	"github.com/go-delve/delve/pkg/dwarf/regnum"
 | |
| 	"github.com/go-delve/delve/pkg/proc"
 | |
| 	"github.com/go-delve/delve/pkg/proc/amd64util"
 | |
| )
 | |
| 
 | |
| // AMD64Registers implements the proc.Registers interface for the native/freebsd
 | |
| // backend and core/freebsd backends, on AMD64.
 | |
| type AMD64Registers struct {
 | |
| 	Regs     *AMD64PtraceRegs
 | |
| 	Fpregs   []proc.Register
 | |
| 	Fpregset *amd64util.AMD64Xstate
 | |
| 	Fsbase   uint64
 | |
| 
 | |
| 	loadFpRegs func(*AMD64Registers) error
 | |
| }
 | |
| 
 | |
| func NewAMD64Registers(regs *AMD64PtraceRegs, fsbase uint64, loadFpRegs func(*AMD64Registers) error) *AMD64Registers {
 | |
| 	return &AMD64Registers{Regs: regs, Fsbase: fsbase, loadFpRegs: loadFpRegs}
 | |
| }
 | |
| 
 | |
| // AMD64PtraceRegs is the struct used by the freebsd kernel to return the
 | |
| // general purpose registers for AMD64 CPUs.
 | |
| // source: sys/x86/include/reg.h
 | |
| type AMD64PtraceRegs struct {
 | |
| 	R15    int64
 | |
| 	R14    int64
 | |
| 	R13    int64
 | |
| 	R12    int64
 | |
| 	R11    int64
 | |
| 	R10    int64
 | |
| 	R9     int64
 | |
| 	R8     int64
 | |
| 	Rdi    int64
 | |
| 	Rsi    int64
 | |
| 	Rbp    int64
 | |
| 	Rbx    int64
 | |
| 	Rdx    int64
 | |
| 	Rcx    int64
 | |
| 	Rax    int64
 | |
| 	Trapno uint32
 | |
| 	Fs     uint16
 | |
| 	Gs     uint16
 | |
| 	Err    uint32
 | |
| 	Es     uint16
 | |
| 	Ds     uint16
 | |
| 	Rip    int64
 | |
| 	Cs     int64
 | |
| 	Rflags int64
 | |
| 	Rsp    int64
 | |
| 	Ss     int64
 | |
| }
 | |
| 
 | |
| // Slice returns the registers as a list of (name, value) pairs.
 | |
| func (r *AMD64Registers) Slice(floatingPoint bool) ([]proc.Register, error) {
 | |
| 	var regs64 = []struct {
 | |
| 		k string
 | |
| 		v int64
 | |
| 	}{
 | |
| 		{"R15", r.Regs.R15},
 | |
| 		{"R14", r.Regs.R14},
 | |
| 		{"R13", r.Regs.R13},
 | |
| 		{"R12", r.Regs.R12},
 | |
| 		{"R11", r.Regs.R11},
 | |
| 		{"R10", r.Regs.R10},
 | |
| 		{"R9", r.Regs.R9},
 | |
| 		{"R8", r.Regs.R8},
 | |
| 		{"Rdi", r.Regs.Rdi},
 | |
| 		{"Rsi", r.Regs.Rsi},
 | |
| 		{"Rbp", r.Regs.Rbp},
 | |
| 		{"Rbx", r.Regs.Rbx},
 | |
| 		{"Rdx", r.Regs.Rdx},
 | |
| 		{"Rcx", r.Regs.Rcx},
 | |
| 		{"Rax", r.Regs.Rax},
 | |
| 		{"Rip", r.Regs.Rip},
 | |
| 		{"Cs", r.Regs.Cs},
 | |
| 		{"Rflags", r.Regs.Rflags},
 | |
| 		{"Rsp", r.Regs.Rsp},
 | |
| 		{"Ss", r.Regs.Ss},
 | |
| 	}
 | |
| 	var regs32 = []struct {
 | |
| 		k string
 | |
| 		v uint32
 | |
| 	}{
 | |
| 		{"Trapno", r.Regs.Trapno},
 | |
| 		{"Err", r.Regs.Err},
 | |
| 	}
 | |
| 	var regs16 = []struct {
 | |
| 		k string
 | |
| 		v uint16
 | |
| 	}{
 | |
| 		{"Fs", r.Regs.Fs},
 | |
| 		{"Gs", r.Regs.Gs},
 | |
| 		{"Es", r.Regs.Es},
 | |
| 		{"Ds", r.Regs.Ds},
 | |
| 	}
 | |
| 	out := make([]proc.Register, 0,
 | |
| 		len(regs64)+
 | |
| 			len(regs32)+
 | |
| 			len(regs16)+
 | |
| 			1+ // for Rflags
 | |
| 			len(r.Fpregs))
 | |
| 	for _, reg := range regs64 {
 | |
| 		// FreeBSD defines the registers as signed, but Linux defines
 | |
| 		// them as unsigned.  Of course, a register doesn't really have
 | |
| 		// a concept of signedness.  Cast to what Delve expects.
 | |
| 		out = proc.AppendUint64Register(out, reg.k, uint64(reg.v))
 | |
| 	}
 | |
| 	for _, reg := range regs32 {
 | |
| 		out = proc.AppendUint64Register(out, reg.k, uint64(reg.v))
 | |
| 	}
 | |
| 	for _, reg := range regs16 {
 | |
| 		out = proc.AppendUint64Register(out, reg.k, uint64(reg.v))
 | |
| 	}
 | |
| 	// x86 called this register "Eflags".  amd64 extended it and renamed it
 | |
| 	// "Rflags", but Linux still uses the old name.
 | |
| 	out = proc.AppendUint64Register(out, "Rflags", uint64(r.Regs.Rflags))
 | |
| 	var floatLoadError error
 | |
| 	if floatingPoint {
 | |
| 		if r.loadFpRegs != nil {
 | |
| 			floatLoadError = r.loadFpRegs(r)
 | |
| 			r.loadFpRegs = nil
 | |
| 		}
 | |
| 		out = append(out, r.Fpregs...)
 | |
| 	}
 | |
| 	return out, floatLoadError
 | |
| }
 | |
| 
 | |
| // PC returns the value of RIP register.
 | |
| func (r *AMD64Registers) PC() uint64 {
 | |
| 	return uint64(r.Regs.Rip)
 | |
| }
 | |
| 
 | |
| // SP returns the value of RSP register.
 | |
| func (r *AMD64Registers) SP() uint64 {
 | |
| 	return uint64(r.Regs.Rsp)
 | |
| }
 | |
| 
 | |
| func (r *AMD64Registers) BP() uint64 {
 | |
| 	return uint64(r.Regs.Rbp)
 | |
| }
 | |
| 
 | |
| func (r *AMD64Registers) LR() uint64 {
 | |
| 	return 0
 | |
| }
 | |
| 
 | |
| // TLS returns the address of the thread local storage memory segment.
 | |
| func (r *AMD64Registers) TLS() uint64 {
 | |
| 	return r.Fsbase
 | |
| }
 | |
| 
 | |
| // GAddr returns the address of the G variable if it is known, 0 and false
 | |
| // otherwise.
 | |
| func (r *AMD64Registers) GAddr() (uint64, bool) {
 | |
| 	return 0, false
 | |
| }
 | |
| 
 | |
| // Copy returns a copy of these registers that is guaranteed not to change.
 | |
| func (r *AMD64Registers) Copy() (proc.Registers, error) {
 | |
| 	if r.loadFpRegs != nil {
 | |
| 		err := r.loadFpRegs(r)
 | |
| 		r.loadFpRegs = nil
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 	}
 | |
| 	var rr AMD64Registers
 | |
| 	rr.Regs = &AMD64PtraceRegs{}
 | |
| 	rr.Fpregset = &amd64util.AMD64Xstate{}
 | |
| 	*(rr.Regs) = *(r.Regs)
 | |
| 	if r.Fpregset != nil {
 | |
| 		*(rr.Fpregset) = *(r.Fpregset)
 | |
| 	}
 | |
| 	if r.Fpregs != nil {
 | |
| 		rr.Fpregs = make([]proc.Register, len(r.Fpregs))
 | |
| 		copy(rr.Fpregs, r.Fpregs)
 | |
| 	}
 | |
| 	return &rr, nil
 | |
| }
 | |
| 
 | |
| func (r *AMD64Registers) SetReg(regNum uint64, reg *op.DwarfRegister) (bool, error) {
 | |
| 	var p *int64
 | |
| 	switch regNum {
 | |
| 	case regnum.AMD64_Rax:
 | |
| 		p = &r.Regs.Rax
 | |
| 	case regnum.AMD64_Rbx:
 | |
| 		p = &r.Regs.Rbx
 | |
| 	case regnum.AMD64_Rcx:
 | |
| 		p = &r.Regs.Rcx
 | |
| 	case regnum.AMD64_Rdx:
 | |
| 		p = &r.Regs.Rdx
 | |
| 	case regnum.AMD64_Rsi:
 | |
| 		p = &r.Regs.Rsi
 | |
| 	case regnum.AMD64_Rdi:
 | |
| 		p = &r.Regs.Rdi
 | |
| 	case regnum.AMD64_Rbp:
 | |
| 		p = &r.Regs.Rbp
 | |
| 	case regnum.AMD64_Rsp:
 | |
| 		p = &r.Regs.Rsp
 | |
| 	case regnum.AMD64_R8:
 | |
| 		p = &r.Regs.R8
 | |
| 	case regnum.AMD64_R9:
 | |
| 		p = &r.Regs.R9
 | |
| 	case regnum.AMD64_R10:
 | |
| 		p = &r.Regs.R10
 | |
| 	case regnum.AMD64_R11:
 | |
| 		p = &r.Regs.R11
 | |
| 	case regnum.AMD64_R12:
 | |
| 		p = &r.Regs.R12
 | |
| 	case regnum.AMD64_R13:
 | |
| 		p = &r.Regs.R13
 | |
| 	case regnum.AMD64_R14:
 | |
| 		p = &r.Regs.R14
 | |
| 	case regnum.AMD64_R15:
 | |
| 		p = &r.Regs.R15
 | |
| 	case regnum.AMD64_Rip:
 | |
| 		p = &r.Regs.Rip
 | |
| 	case regnum.AMD64_Rflags:
 | |
| 		p = &r.Regs.Rflags
 | |
| 	}
 | |
| 
 | |
| 	if p != nil {
 | |
| 		if reg.Bytes != nil && len(reg.Bytes) != 8 {
 | |
| 			return false, fmt.Errorf("wrong number of bytes for register %s (%d)", regnum.AMD64ToName(regNum), len(reg.Bytes))
 | |
| 		}
 | |
| 		*p = int64(reg.Uint64Val)
 | |
| 		return false, nil
 | |
| 	}
 | |
| 
 | |
| 	if r.loadFpRegs != nil {
 | |
| 		if err := r.loadFpRegs(r); err != nil {
 | |
| 			return false, err
 | |
| 		}
 | |
| 		r.loadFpRegs = nil
 | |
| 	}
 | |
| 
 | |
| 	if regNum < regnum.AMD64_XMM0 || regNum > regnum.AMD64_XMM0+15 {
 | |
| 		return false, fmt.Errorf("can not set %s", regnum.AMD64ToName(regNum))
 | |
| 	}
 | |
| 
 | |
| 	reg.FillBytes()
 | |
| 
 | |
| 	if err := r.Fpregset.SetXmmRegister(int(regNum-regnum.AMD64_XMM0), reg.Bytes); err != nil {
 | |
| 		return false, err
 | |
| 	}
 | |
| 	return true, nil
 | |
| }
 |