pkg/proc/native,pkg/proc/amd64util: xsave decoding cleanup (#3840)
- move the cpuid querying code to pkg/proc/native/cpuid since pkg/proc/native is the only package entitled to calling it - add a type to describe the xstate_bv bitmap instead of using hardcoded constants everywhere - use xcr0 instead of xstate_bv for the offset heuristic like gdb does
This commit is contained in:
parent
f83958b923
commit
e0c80c8612
@ -18,6 +18,8 @@ type AMD64Xstate struct {
|
||||
YmmSpace [256]byte
|
||||
Avx512State bool // contains AVX512 state
|
||||
ZmmSpace [512]byte
|
||||
|
||||
zmmHi256offset int
|
||||
}
|
||||
|
||||
// AMD64PtraceFpRegs tracks user_fpregs_struct in /usr/include/x86_64-linux-gnu/sys/user.h
|
||||
@ -72,15 +74,24 @@ func (xstate *AMD64Xstate) Decode() []proc.Register {
|
||||
}
|
||||
|
||||
const (
|
||||
_XSTATE_MAX_KNOWN_SIZE = 2969
|
||||
|
||||
_XSAVE_XMM_REGION_START = 160
|
||||
_XSAVE_HEADER_START = 512
|
||||
_XSAVE_HEADER_LEN = 64
|
||||
_XSAVE_EXTENDED_REGION_START = 576
|
||||
_XSAVE_SSE_REGION_LEN = 416
|
||||
_I386_LINUX_XSAVE_XCR0_OFFSET = 464
|
||||
)
|
||||
|
||||
// xstate_bv is a type representing the xcr0 and xstate_bv bitmaps as
|
||||
// described in section 13.1 and 13.3 of the Intel® 64 and IA-32 Architectures
|
||||
// Software Developer’s Manual, Volume 1
|
||||
type xstate_bv uint64
|
||||
|
||||
func (s xstate_bv) hasAVX() bool { return s&(1<<2) != 0 }
|
||||
func (s xstate_bv) hasZMM_Hi256() bool { return s&(1<<6) != 0 }
|
||||
func (s xstate_bv) hasHi16_ZMM() bool { return s&(1<<7) != 0 } //lint:ignore U1000 future use
|
||||
func (s xstate_bv) hasPKRU() bool { return s&(1<<9) != 0 }
|
||||
|
||||
// AMD64XstateRead reads a byte array containing an XSAVE area into regset.
|
||||
// If readLegacy is true regset.PtraceFpRegs will be filled with the
|
||||
// contents of the legacy region of the XSAVE area.
|
||||
@ -97,17 +108,19 @@ func AMD64XstateRead(xstateargs []byte, readLegacy bool, regset *AMD64Xstate, xs
|
||||
return err
|
||||
}
|
||||
}
|
||||
xcr0 := xstate_bv(binary.LittleEndian.Uint64(xstateargs[_I386_LINUX_XSAVE_XCR0_OFFSET:][:8]))
|
||||
xsaveheader := xstateargs[_XSAVE_HEADER_START : _XSAVE_HEADER_START+_XSAVE_HEADER_LEN]
|
||||
xstate_bv := binary.LittleEndian.Uint64(xsaveheader[0:8])
|
||||
xstate_bv := xstate_bv(binary.LittleEndian.Uint64(xsaveheader[0:8]))
|
||||
xcomp_bv := binary.LittleEndian.Uint64(xsaveheader[8:16])
|
||||
|
||||
fmt.Printf("xcr0: %#x xstate_bv: %#x\n", xcr0, xstate_bv)
|
||||
|
||||
if xcomp_bv&(1<<63) != 0 {
|
||||
// compact format not supported
|
||||
return nil
|
||||
}
|
||||
|
||||
if xstate_bv&(1<<2) == 0 {
|
||||
// AVX state not present
|
||||
if !xstate_bv.hasAVX() {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -115,15 +128,14 @@ func AMD64XstateRead(xstateargs []byte, readLegacy bool, regset *AMD64Xstate, xs
|
||||
regset.AvxState = true
|
||||
copy(regset.YmmSpace[:], avxstate[:len(regset.YmmSpace)])
|
||||
|
||||
if xstate_bv&(1<<6) == 0 {
|
||||
// AVX512 state not present
|
||||
if !xstate_bv.hasZMM_Hi256() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if xstateZMMHi256Offset == 0 {
|
||||
// Guess ZMM_Hi256 component offset
|
||||
// ref: https://github.com/bminor/binutils-gdb/blob/df89bdf0baf106c3b0a9fae53e4e48607a7f3f87/gdb/i387-tdep.c#L916
|
||||
if xstate_bv&(1<<9) != 0 && len(xstateargs) == 2440 {
|
||||
if xcr0.hasPKRU() && len(xstateargs) == 2440 {
|
||||
// AMD CPUs supporting PKRU
|
||||
xstateZMMHi256Offset = 896
|
||||
} else {
|
||||
@ -132,11 +144,13 @@ func AMD64XstateRead(xstateargs []byte, readLegacy bool, regset *AMD64Xstate, xs
|
||||
}
|
||||
}
|
||||
|
||||
regset.zmmHi256offset = xstateZMMHi256Offset
|
||||
|
||||
avx512state := xstateargs[xstateZMMHi256Offset:]
|
||||
regset.Avx512State = true
|
||||
copy(regset.ZmmSpace[:], avx512state[:len(regset.ZmmSpace)])
|
||||
|
||||
// TODO(aarzilli): if xstate_bv&(1<<7) is set then xstateargs[1664:2688]
|
||||
// TODO(aarzilli): if xstate_bv.hasHi16_ZMM() is set then xstateargs[1664:2688]
|
||||
// contains ZMM16 through ZMM31, those aren't just the higher 256bits, it's
|
||||
// the full register so each is 64 bytes (512bits)
|
||||
|
||||
@ -192,7 +206,7 @@ func (xstate *AMD64Xstate) SetXmmRegister(n int, value []byte) error {
|
||||
// Copy bytes [32, 64) to Xsave area
|
||||
|
||||
zmmval := rest
|
||||
zmmpos := AMD64XstateZMMHi256Offset() + (n * 32)
|
||||
zmmpos := xstate.zmmHi256offset + (n * 32) //TODO: change this!!!
|
||||
if zmmpos >= len(xstate.Xsave) {
|
||||
return fmt.Errorf("could not set XMM%d: bytes 32..%d not in XSAVE area", n, 32+len(zmmval))
|
||||
}
|
||||
|
@ -1,12 +0,0 @@
|
||||
//go:build !amd64
|
||||
|
||||
package amd64util
|
||||
|
||||
func AMD64XstateMaxSize() int {
|
||||
return _XSTATE_MAX_KNOWN_SIZE
|
||||
}
|
||||
|
||||
func AMD64XstateZMMHi256Offset() int {
|
||||
// AVX-512 not supported
|
||||
return 0
|
||||
}
|
@ -1,14 +1,20 @@
|
||||
package amd64util
|
||||
//go:build amd64 || 386
|
||||
|
||||
package cpuid
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
const _XSTATE_MAX_KNOWN_SIZE = 2969
|
||||
|
||||
|
||||
var xstateMaxSize int
|
||||
var loadXstateMaxSizeOnce sync.Once
|
||||
|
||||
func cpuid(axIn, cxIn uint32) (axOut, bxOut, cxOut, dxOut uint32)
|
||||
|
||||
// AMD64XstateMaxSize returns the maximum size of the xstate area.
|
||||
func AMD64XstateMaxSize() int {
|
||||
loadXstateMaxSizeOnce.Do(func() {
|
||||
// See Intel 64 and IA-32 Architecture Software Developer's Manual, Vol. 1
|
@ -1,3 +1,5 @@
|
||||
//go:build amd64 || 386
|
||||
|
||||
TEXT ·cpuid(SB),$0-24
|
||||
MOVL axIn+0(FP), AX
|
||||
MOVL cxIn+4(FP), CX
|
||||
@ -7,3 +9,4 @@ TEXT ·cpuid(SB),$0-24
|
||||
MOVL CX, cxOut+16(FP)
|
||||
MOVL DX, dxOut+20(FP)
|
||||
RET
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/go-delve/delve/pkg/proc/amd64util"
|
||||
"github.com/go-delve/delve/pkg/proc/native/cpuid"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -73,7 +74,7 @@ func ptraceGetRegset(id int) (*amd64util.AMD64Xstate, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = amd64util.AMD64XstateRead(regset.Xsave, false, ®set, amd64util.AMD64XstateZMMHi256Offset())
|
||||
err = amd64util.AMD64XstateRead(regset.Xsave, false, ®set, cpuid.AMD64XstateZMMHi256Offset())
|
||||
return ®set, err
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
sys "golang.org/x/sys/unix"
|
||||
|
||||
"github.com/go-delve/delve/pkg/proc/amd64util"
|
||||
"github.com/go-delve/delve/pkg/proc/native/cpuid"
|
||||
)
|
||||
|
||||
// ptraceGetRegset returns floating point registers of the specified thread
|
||||
@ -22,7 +23,7 @@ func ptraceGetRegset(tid int) (regset amd64util.AMD64Xstate, err error) {
|
||||
err = nil
|
||||
}
|
||||
|
||||
xstateargs := make([]byte, amd64util.AMD64XstateMaxSize())
|
||||
xstateargs := make([]byte, cpuid.AMD64XstateMaxSize())
|
||||
iov := sys.Iovec{Base: &xstateargs[0], Len: uint32(len(xstateargs))}
|
||||
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETREGSET, uintptr(tid), _NT_X86_XSTATE, uintptr(unsafe.Pointer(&iov)), 0, 0)
|
||||
if err != syscall.Errno(0) {
|
||||
@ -38,7 +39,7 @@ func ptraceGetRegset(tid int) (regset amd64util.AMD64Xstate, err error) {
|
||||
}
|
||||
|
||||
regset.Xsave = xstateargs[:iov.Len]
|
||||
err = amd64util.AMD64XstateRead(regset.Xsave, false, ®set, amd64util.AMD64XstateZMMHi256Offset())
|
||||
err = amd64util.AMD64XstateRead(regset.Xsave, false, ®set, cpuid.AMD64XstateZMMHi256Offset())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
sys "golang.org/x/sys/unix"
|
||||
|
||||
"github.com/go-delve/delve/pkg/proc/amd64util"
|
||||
"github.com/go-delve/delve/pkg/proc/native/cpuid"
|
||||
)
|
||||
|
||||
// ptraceGetRegset returns floating point registers of the specified thread
|
||||
@ -21,7 +22,7 @@ func ptraceGetRegset(tid int) (regset amd64util.AMD64Xstate, err error) {
|
||||
err = nil
|
||||
}
|
||||
|
||||
xstateargs := make([]byte, amd64util.AMD64XstateMaxSize())
|
||||
xstateargs := make([]byte, cpuid.AMD64XstateMaxSize())
|
||||
iov := sys.Iovec{Base: &xstateargs[0], Len: uint64(len(xstateargs))}
|
||||
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETREGSET, uintptr(tid), _NT_X86_XSTATE, uintptr(unsafe.Pointer(&iov)), 0, 0)
|
||||
if err != syscall.Errno(0) {
|
||||
@ -37,6 +38,6 @@ func ptraceGetRegset(tid int) (regset amd64util.AMD64Xstate, err error) {
|
||||
}
|
||||
|
||||
regset.Xsave = xstateargs[:iov.Len]
|
||||
err = amd64util.AMD64XstateRead(regset.Xsave, false, ®set, amd64util.AMD64XstateZMMHi256Offset())
|
||||
err = amd64util.AMD64XstateRead(regset.Xsave, false, ®set, cpuid.AMD64XstateZMMHi256Offset())
|
||||
return
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user