
* 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
90 lines
2.3 KiB
Go
90 lines
2.3 KiB
Go
package native
|
|
|
|
/*
|
|
#include <sys/types.h>
|
|
#include <sys/ptrace.h>
|
|
*/
|
|
import "C"
|
|
|
|
import (
|
|
"fmt"
|
|
"unsafe"
|
|
|
|
"github.com/go-delve/delve/pkg/proc/amd64util"
|
|
)
|
|
|
|
var (
|
|
xsaveLen int
|
|
xsaveErr error
|
|
)
|
|
|
|
func ptraceGetXsaveLen(tid int) (int, error) {
|
|
var info C.struct_ptrace_xstate_info
|
|
ret, err := C.ptrace(C.PT_GETXSTATE_INFO, C.pid_t(tid), C.caddr_t(unsafe.Pointer(&info)), C.int(unsafe.Sizeof(info)))
|
|
if ret == 0 {
|
|
xsaveLen = int(info.xsave_len)
|
|
} else {
|
|
xsaveLen, xsaveErr = -1, err
|
|
return xsaveLen, fmt.Errorf("failed to get xstate info: %v", err)
|
|
}
|
|
return xsaveLen, nil
|
|
}
|
|
|
|
func ptraceXsaveLen(tid int) (int, error) {
|
|
if xsaveLen > 0 {
|
|
return xsaveLen, nil
|
|
}
|
|
if xsaveLen < 0 {
|
|
return xsaveLen, fmt.Errorf("failed to get xstate info: %v", xsaveErr)
|
|
}
|
|
return ptraceGetXsaveLen(tid)
|
|
}
|
|
|
|
// ptraceGetXsave gets the X86 XSAVE data for the given tid.
|
|
func ptraceGetXsave(tid int) ([]byte, error) {
|
|
len, err := ptraceXsaveLen(tid)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
xsaveBuf := make([]byte, len)
|
|
ret, err := C.ptrace(C.PT_GETXSTATE, C.pid_t(tid), C.caddr_t(unsafe.Pointer(&xsaveBuf[0])), C.int(len))
|
|
if ret != 0 {
|
|
return nil, fmt.Errorf("failed to get xstate: %v", err)
|
|
}
|
|
return xsaveBuf, nil
|
|
}
|
|
|
|
// ptraceSetXsave sets the X86 XSAVE data for the given tid.
|
|
func ptraceSetXsave(tid int, xsaveBuf []byte) error {
|
|
ret, err := C.ptrace(C.PT_SETXSTATE, C.pid_t(tid), C.caddr_t(unsafe.Pointer(&xsaveBuf[0])), C.int(len(xsaveBuf)))
|
|
if ret != 0 {
|
|
return fmt.Errorf("failed to set xstate: %v", err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func ptraceGetRegset(id int) (*amd64util.AMD64Xstate, error) {
|
|
var regset amd64util.AMD64Xstate
|
|
ret, err := C.ptrace(C.PT_GETFPREGS, C.pid_t(id), C.caddr_t(unsafe.Pointer(®set.AMD64PtraceFpRegs)), C.int(0))
|
|
if ret != 0 {
|
|
return nil, fmt.Errorf("failed to get FP registers: %v", err)
|
|
}
|
|
regset.Xsave, err = ptraceGetXsave(id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
err = amd64util.AMD64XstateRead(regset.Xsave, false, ®set)
|
|
return ®set, err
|
|
}
|
|
|
|
func ptraceSetRegset(id int, regset *amd64util.AMD64Xstate) error {
|
|
ret, err := C.ptrace(C.PT_SETFPREGS, C.pid_t(id), C.caddr_t(unsafe.Pointer(®set.AMD64PtraceFpRegs)), C.int(0))
|
|
if ret != 0 {
|
|
return fmt.Errorf("failed to set FP registers: %v", err)
|
|
}
|
|
if regset.Xsave != nil {
|
|
return ptraceSetXsave(id, regset.Xsave)
|
|
}
|
|
return nil
|
|
}
|