proc: use CPUID to determine maximum size of XSAVE area (#2256)
the maximum size of the Xsave area was previously hardcoded but the CPUID instruction can be used to determine its maximum size.
This commit is contained in:
parent
7ac317a7e8
commit
24ec1754b2
131
pkg/proc/amd64util/xsave.go
Normal file
131
pkg/proc/amd64util/xsave.go
Normal file
@ -0,0 +1,131 @@
|
||||
package amd64util
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-delve/delve/pkg/proc"
|
||||
)
|
||||
|
||||
// AMD64Xstate represents amd64 XSAVE area. See Section 13.1 (and
|
||||
// following) of Intel® 64 and IA-32 Architectures Software Developer’s
|
||||
// Manual, Volume 1: Basic Architecture.
|
||||
type AMD64Xstate struct {
|
||||
AMD64PtraceFpRegs
|
||||
Xsave []byte // raw xsave area
|
||||
AvxState bool // contains AVX state
|
||||
YmmSpace [256]byte
|
||||
Avx512State bool // contains AVX512 state
|
||||
ZmmSpace [512]byte
|
||||
}
|
||||
|
||||
// AMD64PtraceFpRegs tracks user_fpregs_struct in /usr/include/x86_64-linux-gnu/sys/user.h
|
||||
type AMD64PtraceFpRegs struct {
|
||||
Cwd uint16
|
||||
Swd uint16
|
||||
Ftw uint16
|
||||
Fop uint16
|
||||
Rip uint64
|
||||
Rdp uint64
|
||||
Mxcsr uint32
|
||||
MxcrMask uint32
|
||||
StSpace [32]uint32
|
||||
XmmSpace [256]byte
|
||||
Padding [24]uint32
|
||||
}
|
||||
|
||||
// Decode decodes an XSAVE area to a list of name/value pairs of registers.
|
||||
func (xsave *AMD64Xstate) Decode() []proc.Register {
|
||||
var regs []proc.Register
|
||||
// x87 registers
|
||||
regs = proc.AppendUint64Register(regs, "CW", uint64(xsave.Cwd))
|
||||
regs = proc.AppendUint64Register(regs, "SW", uint64(xsave.Swd))
|
||||
regs = proc.AppendUint64Register(regs, "TW", uint64(xsave.Ftw))
|
||||
regs = proc.AppendUint64Register(regs, "FOP", uint64(xsave.Fop))
|
||||
regs = proc.AppendUint64Register(regs, "FIP", xsave.Rip)
|
||||
regs = proc.AppendUint64Register(regs, "FDP", xsave.Rdp)
|
||||
|
||||
for i := 0; i < len(xsave.StSpace); i += 4 {
|
||||
var buf bytes.Buffer
|
||||
binary.Write(&buf, binary.LittleEndian, uint64(xsave.StSpace[i+1])<<32|uint64(xsave.StSpace[i]))
|
||||
binary.Write(&buf, binary.LittleEndian, uint16(xsave.StSpace[i+2]))
|
||||
regs = proc.AppendBytesRegister(regs, fmt.Sprintf("ST(%d)", i/4), buf.Bytes())
|
||||
}
|
||||
|
||||
// SSE registers
|
||||
regs = proc.AppendUint64Register(regs, "MXCSR", uint64(xsave.Mxcsr))
|
||||
regs = proc.AppendUint64Register(regs, "MXCSR_MASK", uint64(xsave.MxcrMask))
|
||||
|
||||
for i := 0; i < len(xsave.XmmSpace); i += 16 {
|
||||
n := i / 16
|
||||
regs = proc.AppendBytesRegister(regs, fmt.Sprintf("XMM%d", n), xsave.XmmSpace[i:i+16])
|
||||
if xsave.AvxState {
|
||||
regs = proc.AppendBytesRegister(regs, fmt.Sprintf("YMM%d", n), xsave.YmmSpace[i:i+16])
|
||||
if xsave.Avx512State {
|
||||
regs = proc.AppendBytesRegister(regs, fmt.Sprintf("ZMM%d", n), xsave.ZmmSpace[n*32:(n+1)*32])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return regs
|
||||
}
|
||||
|
||||
const (
|
||||
_XSTATE_MAX_KNOWN_SIZE = 2969
|
||||
|
||||
_XSAVE_HEADER_START = 512
|
||||
_XSAVE_HEADER_LEN = 64
|
||||
_XSAVE_EXTENDED_REGION_START = 576
|
||||
_XSAVE_SSE_REGION_LEN = 416
|
||||
_XSAVE_AVX512_ZMM_REGION_START = 1152
|
||||
)
|
||||
|
||||
// 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.
|
||||
// See Section 13.1 (and following) of Intel® 64 and IA-32 Architectures
|
||||
// Software Developer’s Manual, Volume 1: Basic Architecture.
|
||||
func AMD64XstateRead(xstateargs []byte, readLegacy bool, regset *AMD64Xstate) error {
|
||||
if _XSAVE_HEADER_START+_XSAVE_HEADER_LEN >= len(xstateargs) {
|
||||
return nil
|
||||
}
|
||||
if readLegacy {
|
||||
rdr := bytes.NewReader(xstateargs[:_XSAVE_HEADER_START])
|
||||
if err := binary.Read(rdr, binary.LittleEndian, ®set.AMD64PtraceFpRegs); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
xsaveheader := xstateargs[_XSAVE_HEADER_START : _XSAVE_HEADER_START+_XSAVE_HEADER_LEN]
|
||||
xstate_bv := binary.LittleEndian.Uint64(xsaveheader[0:8])
|
||||
xcomp_bv := binary.LittleEndian.Uint64(xsaveheader[8:16])
|
||||
|
||||
if xcomp_bv&(1<<63) != 0 {
|
||||
// compact format not supported
|
||||
return nil
|
||||
}
|
||||
|
||||
if xstate_bv&(1<<2) == 0 {
|
||||
// AVX state not present
|
||||
return nil
|
||||
}
|
||||
|
||||
avxstate := xstateargs[_XSAVE_EXTENDED_REGION_START:]
|
||||
regset.AvxState = true
|
||||
copy(regset.YmmSpace[:], avxstate[:len(regset.YmmSpace)])
|
||||
|
||||
if xstate_bv&(1<<6) == 0 {
|
||||
// AVX512 state not present
|
||||
return nil
|
||||
}
|
||||
|
||||
avx512state := xstateargs[_XSAVE_AVX512_ZMM_REGION_START:]
|
||||
regset.Avx512State = true
|
||||
copy(regset.ZmmSpace[:], avx512state[:len(regset.ZmmSpace)])
|
||||
|
||||
// TODO(aarzilli): if xstate_bv&(1<<7) 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)
|
||||
|
||||
return nil
|
||||
}
|
30
pkg/proc/amd64util/xsave_amd64.go
Normal file
30
pkg/proc/amd64util/xsave_amd64.go
Normal file
@ -0,0 +1,30 @@
|
||||
package amd64util
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
var xstateMaxSize int
|
||||
var loadXstateMaxSizeOnce sync.Once
|
||||
|
||||
func cpuid(axIn, cxIn uint32) (axOut, bxOut, cxOut, dxOut uint32)
|
||||
|
||||
func AMD64XstateMaxSize() int {
|
||||
loadXstateMaxSizeOnce.Do(func() {
|
||||
// See Intel 64 and IA-32 Architecture Software Developer's Manual, Vol. 1
|
||||
// chapter 13.2 and Vol. 2A CPUID instruction for a description of all the
|
||||
// magic constants.
|
||||
|
||||
_, _, cx, _ := cpuid(0x01, 0x00)
|
||||
|
||||
if cx&(1<<26) == 0 { // Vol. 2A, Table 3-10, XSAVE enabled bit check
|
||||
// XSAVE not supported by this processor
|
||||
xstateMaxSize = _XSTATE_MAX_KNOWN_SIZE
|
||||
return
|
||||
}
|
||||
|
||||
_, _, cx, _ = cpuid(0x0d, 0x00) // processor extended state enumeration main leaf
|
||||
xstateMaxSize = int(cx)
|
||||
})
|
||||
return xstateMaxSize
|
||||
}
|
9
pkg/proc/amd64util/xsave_amd64.s
Normal file
9
pkg/proc/amd64util/xsave_amd64.s
Normal file
@ -0,0 +1,9 @@
|
||||
TEXT ·cpuid(SB),$0-24
|
||||
MOVL axIn+0(FP), AX
|
||||
MOVL cxIn+4(FP), CX
|
||||
CPUID
|
||||
MOVL AX, axOut+8(FP)
|
||||
MOVL BX, bxOut+12(FP)
|
||||
MOVL CX, cxOut+16(FP)
|
||||
MOVL DX, dxOut+20(FP)
|
||||
RET
|
7
pkg/proc/amd64util/xsave_other.go
Normal file
7
pkg/proc/amd64util/xsave_other.go
Normal file
@ -0,0 +1,7 @@
|
||||
//+build !amd64
|
||||
|
||||
package amd64util
|
||||
|
||||
func AMD64XstateMaxSize() int {
|
||||
return _XSTATE_MAX_KNOWN_SIZE
|
||||
}
|
@ -10,6 +10,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/go-delve/delve/pkg/proc"
|
||||
"github.com/go-delve/delve/pkg/proc/amd64util"
|
||||
"github.com/go-delve/delve/pkg/proc/linutil"
|
||||
)
|
||||
|
||||
@ -73,7 +74,7 @@ func linuxThreadsFromNotes(p *process, notes []*note, machineType elf.Machine) p
|
||||
case _NT_X86_XSTATE:
|
||||
if machineType == _EM_X86_64 {
|
||||
if lastThreadAMD != nil {
|
||||
lastThreadAMD.regs.Fpregs = note.Desc.(*linutil.AMD64Xstate).Decode()
|
||||
lastThreadAMD.regs.Fpregs = note.Desc.(*amd64util.AMD64Xstate).Decode()
|
||||
}
|
||||
}
|
||||
case elf.NT_PRPSINFO:
|
||||
@ -279,8 +280,8 @@ func readNote(r io.ReadSeeker, machineType elf.Machine) (*note, error) {
|
||||
note.Desc = data
|
||||
case _NT_X86_XSTATE:
|
||||
if machineType == _EM_X86_64 {
|
||||
var fpregs linutil.AMD64Xstate
|
||||
if err := linutil.AMD64XstateRead(desc, true, &fpregs); err != nil {
|
||||
var fpregs amd64util.AMD64Xstate
|
||||
if err := amd64util.AMD64XstateRead(desc, true, &fpregs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
note.Desc = &fpregs
|
||||
|
@ -4,7 +4,7 @@ import (
|
||||
"golang.org/x/arch/x86/x86asm"
|
||||
|
||||
"github.com/go-delve/delve/pkg/proc"
|
||||
"github.com/go-delve/delve/pkg/proc/linutil"
|
||||
"github.com/go-delve/delve/pkg/proc/amd64util"
|
||||
)
|
||||
|
||||
// AMD64Registers implements the proc.Registers interface for the native/freebsd
|
||||
@ -12,7 +12,7 @@ import (
|
||||
type AMD64Registers struct {
|
||||
Regs *AMD64PtraceRegs
|
||||
Fpregs []proc.Register
|
||||
Fpregset *AMD64Xstate
|
||||
Fpregset *amd64util.AMD64Xstate
|
||||
Fsbase uint64
|
||||
|
||||
loadFpRegs func(*AMD64Registers) error
|
||||
@ -323,7 +323,7 @@ func (r *AMD64Registers) Copy() (proc.Registers, error) {
|
||||
}
|
||||
var rr AMD64Registers
|
||||
rr.Regs = &AMD64PtraceRegs{}
|
||||
rr.Fpregset = &AMD64Xstate{}
|
||||
rr.Fpregset = &amd64util.AMD64Xstate{}
|
||||
*(rr.Regs) = *(r.Regs)
|
||||
if r.Fpregset != nil {
|
||||
*(rr.Fpregset) = *(r.Fpregset)
|
||||
@ -334,13 +334,3 @@ func (r *AMD64Registers) Copy() (proc.Registers, error) {
|
||||
}
|
||||
return &rr, nil
|
||||
}
|
||||
|
||||
type AMD64Xstate linutil.AMD64Xstate
|
||||
|
||||
func AMD64XstateRead(xstateargs []byte, readLegacy bool, regset *AMD64Xstate) error {
|
||||
return linutil.AMD64XstateRead(xstateargs, readLegacy, (*linutil.AMD64Xstate)(regset))
|
||||
}
|
||||
|
||||
func (xsave *AMD64Xstate) Decode() (regs []proc.Register) {
|
||||
return (*linutil.AMD64Xstate).Decode((*linutil.AMD64Xstate)(xsave))
|
||||
}
|
||||
|
@ -1,13 +1,10 @@
|
||||
package linutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"golang.org/x/arch/x86/x86asm"
|
||||
|
||||
"github.com/go-delve/delve/pkg/proc"
|
||||
"github.com/go-delve/delve/pkg/proc/amd64util"
|
||||
)
|
||||
|
||||
// AMD64Registers implements the proc.Registers interface for the native/linux
|
||||
@ -15,7 +12,7 @@ import (
|
||||
type AMD64Registers struct {
|
||||
Regs *AMD64PtraceRegs
|
||||
Fpregs []proc.Register
|
||||
Fpregset *AMD64Xstate
|
||||
Fpregset *amd64util.AMD64Xstate
|
||||
|
||||
loadFpRegs func(*AMD64Registers) error
|
||||
}
|
||||
@ -299,7 +296,7 @@ func (r *AMD64Registers) Copy() (proc.Registers, error) {
|
||||
}
|
||||
var rr AMD64Registers
|
||||
rr.Regs = &AMD64PtraceRegs{}
|
||||
rr.Fpregset = &AMD64Xstate{}
|
||||
rr.Fpregset = &amd64util.AMD64Xstate{}
|
||||
*(rr.Regs) = *(r.Regs)
|
||||
if r.Fpregset != nil {
|
||||
*(rr.Fpregset) = *(r.Fpregset)
|
||||
@ -310,122 +307,3 @@ func (r *AMD64Registers) Copy() (proc.Registers, error) {
|
||||
}
|
||||
return &rr, nil
|
||||
}
|
||||
|
||||
// AMD64PtraceFpRegs tracks user_fpregs_struct in /usr/include/x86_64-linux-gnu/sys/user.h
|
||||
type AMD64PtraceFpRegs struct {
|
||||
Cwd uint16
|
||||
Swd uint16
|
||||
Ftw uint16
|
||||
Fop uint16
|
||||
Rip uint64
|
||||
Rdp uint64
|
||||
Mxcsr uint32
|
||||
MxcrMask uint32
|
||||
StSpace [32]uint32
|
||||
XmmSpace [256]byte
|
||||
Padding [24]uint32
|
||||
}
|
||||
|
||||
// AMD64Xstate represents amd64 XSAVE area. See Section 13.1 (and
|
||||
// following) of Intel® 64 and IA-32 Architectures Software Developer’s
|
||||
// Manual, Volume 1: Basic Architecture.
|
||||
type AMD64Xstate struct {
|
||||
AMD64PtraceFpRegs
|
||||
Xsave []byte // raw xsave area
|
||||
AvxState bool // contains AVX state
|
||||
YmmSpace [256]byte
|
||||
Avx512State bool // contains AVX512 state
|
||||
ZmmSpace [512]byte
|
||||
}
|
||||
|
||||
// Decode decodes an XSAVE area to a list of name/value pairs of registers.
|
||||
func (xsave *AMD64Xstate) Decode() (regs []proc.Register) {
|
||||
// x87 registers
|
||||
regs = proc.AppendUint64Register(regs, "CW", uint64(xsave.Cwd))
|
||||
regs = proc.AppendUint64Register(regs, "SW", uint64(xsave.Swd))
|
||||
regs = proc.AppendUint64Register(regs, "TW", uint64(xsave.Ftw))
|
||||
regs = proc.AppendUint64Register(regs, "FOP", uint64(xsave.Fop))
|
||||
regs = proc.AppendUint64Register(regs, "FIP", xsave.Rip)
|
||||
regs = proc.AppendUint64Register(regs, "FDP", xsave.Rdp)
|
||||
|
||||
for i := 0; i < len(xsave.StSpace); i += 4 {
|
||||
var buf bytes.Buffer
|
||||
binary.Write(&buf, binary.LittleEndian, uint64(xsave.StSpace[i+1])<<32|uint64(xsave.StSpace[i]))
|
||||
binary.Write(&buf, binary.LittleEndian, uint16(xsave.StSpace[i+2]))
|
||||
regs = proc.AppendBytesRegister(regs, fmt.Sprintf("ST(%d)", i/4), buf.Bytes())
|
||||
}
|
||||
|
||||
// SSE registers
|
||||
regs = proc.AppendUint64Register(regs, "MXCSR", uint64(xsave.Mxcsr))
|
||||
regs = proc.AppendUint64Register(regs, "MXCSR_MASK", uint64(xsave.MxcrMask))
|
||||
|
||||
for i := 0; i < len(xsave.XmmSpace); i += 16 {
|
||||
n := i / 16
|
||||
regs = proc.AppendBytesRegister(regs, fmt.Sprintf("XMM%d", n), xsave.XmmSpace[i:i+16])
|
||||
if xsave.AvxState {
|
||||
regs = proc.AppendBytesRegister(regs, fmt.Sprintf("YMM%d", n), xsave.YmmSpace[i:i+16])
|
||||
if xsave.Avx512State {
|
||||
regs = proc.AppendBytesRegister(regs, fmt.Sprintf("ZMM%d", n), xsave.ZmmSpace[n*32:(n+1)*32])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
const (
|
||||
_XSAVE_HEADER_START = 512
|
||||
_XSAVE_HEADER_LEN = 64
|
||||
_XSAVE_EXTENDED_REGION_START = 576
|
||||
_XSAVE_SSE_REGION_LEN = 416
|
||||
_XSAVE_AVX512_ZMM_REGION_START = 1152
|
||||
)
|
||||
|
||||
// LinuxX86XstateRead 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.
|
||||
// See Section 13.1 (and following) of Intel® 64 and IA-32 Architectures
|
||||
// Software Developer’s Manual, Volume 1: Basic Architecture.
|
||||
func AMD64XstateRead(xstateargs []byte, readLegacy bool, regset *AMD64Xstate) error {
|
||||
if _XSAVE_HEADER_START+_XSAVE_HEADER_LEN >= len(xstateargs) {
|
||||
return nil
|
||||
}
|
||||
if readLegacy {
|
||||
rdr := bytes.NewReader(xstateargs[:_XSAVE_HEADER_START])
|
||||
if err := binary.Read(rdr, binary.LittleEndian, ®set.AMD64PtraceFpRegs); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
xsaveheader := xstateargs[_XSAVE_HEADER_START : _XSAVE_HEADER_START+_XSAVE_HEADER_LEN]
|
||||
xstate_bv := binary.LittleEndian.Uint64(xsaveheader[0:8])
|
||||
xcomp_bv := binary.LittleEndian.Uint64(xsaveheader[8:16])
|
||||
|
||||
if xcomp_bv&(1<<63) != 0 {
|
||||
// compact format not supported
|
||||
return nil
|
||||
}
|
||||
|
||||
if xstate_bv&(1<<2) == 0 {
|
||||
// AVX state not present
|
||||
return nil
|
||||
}
|
||||
|
||||
avxstate := xstateargs[_XSAVE_EXTENDED_REGION_START:]
|
||||
regset.AvxState = true
|
||||
copy(regset.YmmSpace[:], avxstate[:len(regset.YmmSpace)])
|
||||
|
||||
if xstate_bv&(1<<6) == 0 {
|
||||
// AVX512 state not present
|
||||
return nil
|
||||
}
|
||||
|
||||
avx512state := xstateargs[_XSAVE_AVX512_ZMM_REGION_START:]
|
||||
regset.Avx512State = true
|
||||
copy(regset.ZmmSpace[:], avx512state[:len(regset.ZmmSpace)])
|
||||
|
||||
// TODO(aarzilli): if xstate_bv&(1<<7) 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)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -1,11 +1,10 @@
|
||||
package linutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"github.com/go-delve/delve/pkg/proc"
|
||||
"golang.org/x/arch/x86/x86asm"
|
||||
|
||||
"github.com/go-delve/delve/pkg/proc"
|
||||
"github.com/go-delve/delve/pkg/proc/amd64util"
|
||||
)
|
||||
|
||||
// I386Registers implements the proc.Registers interface for the native/linux
|
||||
@ -13,7 +12,7 @@ import (
|
||||
type I386Registers struct {
|
||||
Regs *I386PtraceRegs
|
||||
Fpregs []proc.Register
|
||||
Fpregset *I386Xstate
|
||||
Fpregset *amd64util.AMD64Xstate
|
||||
Tls uint64
|
||||
|
||||
loadFpRegs func(*I386Registers) error
|
||||
@ -199,7 +198,7 @@ func (r *I386Registers) Copy() (proc.Registers, error) {
|
||||
}
|
||||
var rr I386Registers
|
||||
rr.Regs = &I386PtraceRegs{}
|
||||
rr.Fpregset = &I386Xstate{}
|
||||
rr.Fpregset = &amd64util.AMD64Xstate{}
|
||||
*(rr.Regs) = *(r.Regs)
|
||||
if r.Fpregset != nil {
|
||||
*(rr.Fpregset) = *(r.Fpregset)
|
||||
@ -210,95 +209,3 @@ func (r *I386Registers) Copy() (proc.Registers, error) {
|
||||
}
|
||||
return &rr, nil
|
||||
}
|
||||
|
||||
// I386PtraceFpRegs tracks user_fpregs_struct in /usr/include/x86_64-linux-gnu/sys/user.h
|
||||
type I386PtraceFpRegs struct {
|
||||
Cwd uint16
|
||||
Swd uint16
|
||||
Ftw uint16
|
||||
Fop uint16
|
||||
Rip uint64
|
||||
Rdp uint64
|
||||
Mxcsr uint32
|
||||
MxcrMask uint32
|
||||
StSpace [32]uint32
|
||||
XmmSpace [256]byte
|
||||
Padding [24]uint32
|
||||
}
|
||||
|
||||
// I386Xstate represents amd64 XSAVE area. See Section 13.1 (and
|
||||
// following) of Intel® 64 and IA-32 Architectures Software Developer’s
|
||||
// Manual, Volume 1: Basic Architecture.
|
||||
type I386Xstate struct {
|
||||
I386PtraceFpRegs
|
||||
Xsave []byte // raw xsave area
|
||||
AvxState bool // contains AVX state
|
||||
YmmSpace [256]byte
|
||||
}
|
||||
|
||||
// Decode decodes an XSAVE area to a list of name/value pairs of registers.
|
||||
func (xsave *I386Xstate) Decode() (regs []proc.Register) {
|
||||
// x87 registers
|
||||
regs = proc.AppendUint64Register(regs, "CW", uint64(xsave.Cwd))
|
||||
regs = proc.AppendUint64Register(regs, "SW", uint64(xsave.Swd))
|
||||
regs = proc.AppendUint64Register(regs, "TW", uint64(xsave.Ftw))
|
||||
regs = proc.AppendUint64Register(regs, "FOP", uint64(xsave.Fop))
|
||||
regs = proc.AppendUint64Register(regs, "FIP", uint64(xsave.Rip))
|
||||
regs = proc.AppendUint64Register(regs, "FDP", uint64(xsave.Rdp))
|
||||
|
||||
for i := 0; i < len(xsave.StSpace); i += 4 {
|
||||
var buf bytes.Buffer
|
||||
binary.Write(&buf, binary.LittleEndian, uint64(xsave.StSpace[i+1])<<32|uint64(xsave.StSpace[i]))
|
||||
binary.Write(&buf, binary.LittleEndian, uint16(xsave.StSpace[i+2]))
|
||||
regs = proc.AppendBytesRegister(regs, fmt.Sprintf("ST(%d)", i/4), buf.Bytes())
|
||||
}
|
||||
|
||||
// SSE registers
|
||||
regs = proc.AppendUint64Register(regs, "MXCSR", uint64(xsave.Mxcsr))
|
||||
regs = proc.AppendUint64Register(regs, "MXCSR_MASK", uint64(xsave.MxcrMask))
|
||||
|
||||
for i := 0; i < len(xsave.XmmSpace); i += 16 {
|
||||
regs = proc.AppendBytesRegister(regs, fmt.Sprintf("XMM%d", i/16), xsave.XmmSpace[i:i+16])
|
||||
if xsave.AvxState {
|
||||
regs = proc.AppendBytesRegister(regs, fmt.Sprintf("YMM%d", i/16), xsave.YmmSpace[i:i+16])
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// LinuxX86XstateRead 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.
|
||||
// See Section 13.1 (and following) of Intel® 64 and IA-32 Architectures
|
||||
// Software Developer’s Manual, Volume 1: Basic Architecture.
|
||||
func I386XstateRead(xstateargs []byte, readLegacy bool, regset *I386Xstate) error {
|
||||
if _XSAVE_HEADER_START+_XSAVE_HEADER_LEN >= len(xstateargs) {
|
||||
return nil
|
||||
}
|
||||
if readLegacy {
|
||||
rdr := bytes.NewReader(xstateargs[:_XSAVE_HEADER_START])
|
||||
if err := binary.Read(rdr, binary.LittleEndian, ®set.I386PtraceFpRegs); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
xsaveheader := xstateargs[_XSAVE_HEADER_START : _XSAVE_HEADER_START+_XSAVE_HEADER_LEN]
|
||||
xstate_bv := binary.LittleEndian.Uint64(xsaveheader[0:8])
|
||||
xcomp_bv := binary.LittleEndian.Uint64(xsaveheader[8:16])
|
||||
|
||||
if xcomp_bv&(1<<63) != 0 {
|
||||
// compact format not supported
|
||||
return nil
|
||||
}
|
||||
|
||||
if xstate_bv&(1<<2) == 0 {
|
||||
// AVX state not present
|
||||
return nil
|
||||
}
|
||||
|
||||
avxstate := xstateargs[_XSAVE_EXTENDED_REGION_START:]
|
||||
regset.AvxState = true
|
||||
copy(regset.YmmSpace[:], avxstate[:len(regset.YmmSpace)])
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
|
||||
sys "golang.org/x/sys/unix"
|
||||
|
||||
"github.com/go-delve/delve/pkg/proc/fbsdutil"
|
||||
"github.com/go-delve/delve/pkg/proc/amd64util"
|
||||
)
|
||||
|
||||
// ptraceAttach executes the sys.PtraceAttach call.
|
||||
@ -54,7 +54,7 @@ func ptraceGetLwpInfo(wpid int) (info sys.PtraceLwpInfoStruct, err error) {
|
||||
return info, err
|
||||
}
|
||||
|
||||
func ptraceGetRegset(id int) (regset fbsdutil.AMD64Xstate, err error) {
|
||||
func ptraceGetRegset(id int) (regset amd64util.AMD64Xstate, err error) {
|
||||
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETFPREGS, uintptr(id), uintptr(unsafe.Pointer(®set.AMD64PtraceFpRegs)), 0, 0, 0)
|
||||
if err == syscall.Errno(0) || err == syscall.ENODEV {
|
||||
var xsave_len C.size_t
|
||||
@ -62,7 +62,7 @@ func ptraceGetRegset(id int) (regset fbsdutil.AMD64Xstate, err error) {
|
||||
defer C.free(unsafe.Pointer(xsave))
|
||||
if xsave != nil {
|
||||
xsave_sl := C.GoBytes(unsafe.Pointer(xsave), C.int(xsave_len))
|
||||
err = fbsdutil.AMD64XstateRead(xsave_sl, false, ®set)
|
||||
err = amd64util.AMD64XstateRead(xsave_sl, false, ®set)
|
||||
}
|
||||
}
|
||||
return
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
|
||||
sys "golang.org/x/sys/unix"
|
||||
|
||||
"github.com/go-delve/delve/pkg/proc/linutil"
|
||||
"github.com/go-delve/delve/pkg/proc/amd64util"
|
||||
)
|
||||
|
||||
// ptraceGetRegset returns floating point registers of the specified thread
|
||||
@ -17,15 +17,15 @@ import (
|
||||
// See i386_linux_fetch_inferior_registers in gdb/i386-linux-nat.c.html
|
||||
// and i386_supply_xsave in gdb/i386-tdep.c.html
|
||||
// and Section 13.1 (and following) of Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 1: Basic Architecture
|
||||
func ptraceGetRegset(tid int) (regset linutil.I386Xstate, err error) {
|
||||
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETFPREGS, uintptr(tid), uintptr(0), uintptr(unsafe.Pointer(®set.I386PtraceFpRegs)), 0, 0)
|
||||
func ptraceGetRegset(tid int) (regset amd64util.AMD64Xstate, err error) {
|
||||
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETFPREGS, uintptr(tid), uintptr(0), uintptr(unsafe.Pointer(®set.AMD64PtraceFpRegs)), 0, 0)
|
||||
if err == syscall.Errno(0) || err == syscall.ENODEV {
|
||||
// ignore ENODEV, it just means this CPU doesn't have X87 registers (??)
|
||||
err = nil
|
||||
}
|
||||
|
||||
var xstateargs [_X86_XSTATE_MAX_SIZE]byte
|
||||
iov := sys.Iovec{Base: &xstateargs[0], Len: _X86_XSTATE_MAX_SIZE}
|
||||
xstateargs := make([]byte, amd64util.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) {
|
||||
if err == syscall.ENODEV || err == syscall.EIO {
|
||||
@ -39,7 +39,7 @@ func ptraceGetRegset(tid int) (regset linutil.I386Xstate, err error) {
|
||||
}
|
||||
|
||||
regset.Xsave = xstateargs[:iov.Len]
|
||||
err = linutil.I386XstateRead(regset.Xsave, false, ®set)
|
||||
err = amd64util.AMD64XstateRead(regset.Xsave, false, ®set)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
|
||||
sys "golang.org/x/sys/unix"
|
||||
|
||||
"github.com/go-delve/delve/pkg/proc/linutil"
|
||||
"github.com/go-delve/delve/pkg/proc/amd64util"
|
||||
)
|
||||
|
||||
// ptraceGetRegset returns floating point registers of the specified thread
|
||||
@ -14,15 +14,15 @@ import (
|
||||
// See amd64_linux_fetch_inferior_registers in gdb/amd64-linux-nat.c.html
|
||||
// and amd64_supply_xsave in gdb/amd64-tdep.c.html
|
||||
// and Section 13.1 (and following) of Intel® 64 and IA-32 Architectures Software Developer’s Manual, Volume 1: Basic Architecture
|
||||
func ptraceGetRegset(tid int) (regset linutil.AMD64Xstate, err error) {
|
||||
func ptraceGetRegset(tid int) (regset amd64util.AMD64Xstate, err error) {
|
||||
_, _, err = syscall.Syscall6(syscall.SYS_PTRACE, sys.PTRACE_GETFPREGS, uintptr(tid), uintptr(0), uintptr(unsafe.Pointer(®set.AMD64PtraceFpRegs)), 0, 0)
|
||||
if err == syscall.Errno(0) || err == syscall.ENODEV {
|
||||
// ignore ENODEV, it just means this CPU doesn't have X87 registers (??)
|
||||
err = nil
|
||||
}
|
||||
|
||||
var xstateargs [_X86_XSTATE_MAX_SIZE]byte
|
||||
iov := sys.Iovec{Base: &xstateargs[0], Len: _X86_XSTATE_MAX_SIZE}
|
||||
xstateargs := make([]byte, amd64util.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) {
|
||||
if err == syscall.ENODEV || err == syscall.EIO {
|
||||
@ -36,6 +36,6 @@ func ptraceGetRegset(tid int) (regset linutil.AMD64Xstate, err error) {
|
||||
}
|
||||
|
||||
regset.Xsave = xstateargs[:iov.Len]
|
||||
err = linutil.AMD64XstateRead(regset.Xsave, false, ®set)
|
||||
err = amd64util.AMD64XstateRead(regset.Xsave, false, ®set)
|
||||
return
|
||||
}
|
||||
|
@ -69,15 +69,7 @@ func registers(thread *nativeThread) (proc.Registers, error) {
|
||||
return r, nil
|
||||
}
|
||||
|
||||
const (
|
||||
_X86_XSTATE_MAX_SIZE = 2688
|
||||
_NT_X86_XSTATE = 0x202
|
||||
|
||||
_XSAVE_HEADER_START = 512
|
||||
_XSAVE_HEADER_LEN = 64
|
||||
_XSAVE_EXTENDED_REGION_START = 576
|
||||
_XSAVE_SSE_REGION_LEN = 416
|
||||
)
|
||||
const _NT_X86_XSTATE = 0x202
|
||||
|
||||
func (thread *nativeThread) fpRegisters() (regs []proc.Register, fpregs linutil.I386Xstate, err error) {
|
||||
thread.dbp.execPtraceFunc(func() { fpregs, err = ptraceGetRegset(thread.ID) })
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
sys "golang.org/x/sys/unix"
|
||||
|
||||
"github.com/go-delve/delve/pkg/proc"
|
||||
"github.com/go-delve/delve/pkg/proc/amd64util"
|
||||
"github.com/go-delve/delve/pkg/proc/fbsdutil"
|
||||
)
|
||||
|
||||
@ -61,7 +62,7 @@ func registers(thread *nativeThread) (proc.Registers, error) {
|
||||
return nil, err
|
||||
}
|
||||
r := fbsdutil.NewAMD64Registers(®s, uint64(fsbase), func(r *fbsdutil.AMD64Registers) error {
|
||||
var fpregset fbsdutil.AMD64Xstate
|
||||
var fpregset amd64util.AMD64Xstate
|
||||
var floatLoadError error
|
||||
r.Fpregs, fpregset, floatLoadError = thread.fpRegisters()
|
||||
r.Fpregset = &fpregset
|
||||
@ -70,17 +71,9 @@ func registers(thread *nativeThread) (proc.Registers, error) {
|
||||
return r, nil
|
||||
}
|
||||
|
||||
const (
|
||||
_X86_XSTATE_MAX_SIZE = 2696
|
||||
_NT_X86_XSTATE = 0x202
|
||||
const _NT_X86_XSTATE = 0x202
|
||||
|
||||
_XSAVE_HEADER_START = 512
|
||||
_XSAVE_HEADER_LEN = 64
|
||||
_XSAVE_EXTENDED_REGION_START = 576
|
||||
_XSAVE_SSE_REGION_LEN = 416
|
||||
)
|
||||
|
||||
func (thread *nativeThread) fpRegisters() (regs []proc.Register, fpregs fbsdutil.AMD64Xstate, err error) {
|
||||
func (thread *nativeThread) fpRegisters() (regs []proc.Register, fpregs amd64util.AMD64Xstate, err error) {
|
||||
thread.dbp.execPtraceFunc(func() { fpregs, err = ptraceGetRegset(thread.ID) })
|
||||
if err != nil {
|
||||
err = fmt.Errorf("could not get floating point registers: %v", err.Error())
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
sys "golang.org/x/sys/unix"
|
||||
|
||||
"github.com/go-delve/delve/pkg/proc"
|
||||
"github.com/go-delve/delve/pkg/proc/amd64util"
|
||||
"github.com/go-delve/delve/pkg/proc/linutil"
|
||||
)
|
||||
|
||||
@ -56,7 +57,7 @@ func registers(thread *nativeThread) (proc.Registers, error) {
|
||||
return nil, err
|
||||
}
|
||||
r := linutil.NewAMD64Registers(®s, func(r *linutil.AMD64Registers) error {
|
||||
var fpregset linutil.AMD64Xstate
|
||||
var fpregset amd64util.AMD64Xstate
|
||||
var floatLoadError error
|
||||
r.Fpregs, fpregset, floatLoadError = thread.fpRegisters()
|
||||
r.Fpregset = &fpregset
|
||||
@ -65,17 +66,9 @@ func registers(thread *nativeThread) (proc.Registers, error) {
|
||||
return r, nil
|
||||
}
|
||||
|
||||
const (
|
||||
_X86_XSTATE_MAX_SIZE = 2696
|
||||
_NT_X86_XSTATE = 0x202
|
||||
const _NT_X86_XSTATE = 0x202
|
||||
|
||||
_XSAVE_HEADER_START = 512
|
||||
_XSAVE_HEADER_LEN = 64
|
||||
_XSAVE_EXTENDED_REGION_START = 576
|
||||
_XSAVE_SSE_REGION_LEN = 416
|
||||
)
|
||||
|
||||
func (thread *nativeThread) fpRegisters() (regs []proc.Register, fpregs linutil.AMD64Xstate, err error) {
|
||||
func (thread *nativeThread) fpRegisters() (regs []proc.Register, fpregs amd64util.AMD64Xstate, err error) {
|
||||
thread.dbp.execPtraceFunc(func() { fpregs, err = ptraceGetRegset(thread.ID) })
|
||||
regs = fpregs.Decode()
|
||||
if err != nil {
|
||||
|
Loading…
Reference in New Issue
Block a user