diff --git a/pkg/proc/amd64util/xsave.go b/pkg/proc/amd64util/xsave.go new file mode 100644 index 0000000000000000000000000000000000000000..b90bb3e48b491006f19a26432bb196595cc73673 --- /dev/null +++ b/pkg/proc/amd64util/xsave.go @@ -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 +} diff --git a/pkg/proc/amd64util/xsave_amd64.go b/pkg/proc/amd64util/xsave_amd64.go new file mode 100644 index 0000000000000000000000000000000000000000..539914d9cf02de21efcd9d8dde665c5c10cacd63 --- /dev/null +++ b/pkg/proc/amd64util/xsave_amd64.go @@ -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 +} diff --git a/pkg/proc/amd64util/xsave_amd64.s b/pkg/proc/amd64util/xsave_amd64.s new file mode 100644 index 0000000000000000000000000000000000000000..130e374554a109ea51b0d1750bf1174e0f768a93 --- /dev/null +++ b/pkg/proc/amd64util/xsave_amd64.s @@ -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 diff --git a/pkg/proc/amd64util/xsave_other.go b/pkg/proc/amd64util/xsave_other.go new file mode 100644 index 0000000000000000000000000000000000000000..aa86dc5e02dc8374710ff28d4579df3ae44b06f3 --- /dev/null +++ b/pkg/proc/amd64util/xsave_other.go @@ -0,0 +1,7 @@ +//+build !amd64 + +package amd64util + +func AMD64XstateMaxSize() int { + return _XSTATE_MAX_KNOWN_SIZE +} diff --git a/pkg/proc/core/linux_core.go b/pkg/proc/core/linux_core.go index 6861451ac194fd583239ef60c9a1f322a210861b..5d758c65289a14b661b72d4d0f300f061850f539 100644 --- a/pkg/proc/core/linux_core.go +++ b/pkg/proc/core/linux_core.go @@ -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 diff --git a/pkg/proc/fbsdutil/regs.go b/pkg/proc/fbsdutil/regs.go index 94c130309418c3ff03eb817a85d4a88c0cbc1a47..aa29a61bdb4b921ff241957709bcfbe475cd49a3 100644 --- a/pkg/proc/fbsdutil/regs.go +++ b/pkg/proc/fbsdutil/regs.go @@ -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)) -} diff --git a/pkg/proc/linutil/regs_amd64_arch.go b/pkg/proc/linutil/regs_amd64_arch.go index f25dd5898662f33c8d0065cc7fd3e373ece46753..6ea4bbc997dc0efeeb5052b73d3d838fa3b46f48 100644 --- a/pkg/proc/linutil/regs_amd64_arch.go +++ b/pkg/proc/linutil/regs_amd64_arch.go @@ -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 -} diff --git a/pkg/proc/linutil/regs_i386_arch.go b/pkg/proc/linutil/regs_i386_arch.go index ed7d6bbea30604409c3c60aef3f8b38fdb4e684c..823505cb604e4740c5f28c1aa648d29d1c4f262c 100644 --- a/pkg/proc/linutil/regs_i386_arch.go +++ b/pkg/proc/linutil/regs_i386_arch.go @@ -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 -} diff --git a/pkg/proc/native/ptrace_freebsd.go b/pkg/proc/native/ptrace_freebsd.go index 1e3fc431e9138072fc18952bfd6b3938a0675136..f165e47db96f0d7a85470d5c3b08e359cf4d66fd 100644 --- a/pkg/proc/native/ptrace_freebsd.go +++ b/pkg/proc/native/ptrace_freebsd.go @@ -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 diff --git a/pkg/proc/native/ptrace_linux_386.go b/pkg/proc/native/ptrace_linux_386.go index f01e3562279db35b81ab5438cd21710710755858..a0a64e3091c029e7850639ebb95d876e7778724b 100644 --- a/pkg/proc/native/ptrace_linux_386.go +++ b/pkg/proc/native/ptrace_linux_386.go @@ -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 } diff --git a/pkg/proc/native/ptrace_linux_amd64.go b/pkg/proc/native/ptrace_linux_amd64.go index a56cf19d0126744e3b68df00e994c3dcc9678993..5f5c99d5055cf3cfc62d8f2a81319beebd3a523b 100644 --- a/pkg/proc/native/ptrace_linux_amd64.go +++ b/pkg/proc/native/ptrace_linux_amd64.go @@ -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 } diff --git a/pkg/proc/native/register_linux_386.go b/pkg/proc/native/register_linux_386.go index e3fb1916033b53c9cdfa77d98a8d76a7f34fb439..b09fa9a109e0dd41e3905c91d84c72cdf3556923 100644 --- a/pkg/proc/native/register_linux_386.go +++ b/pkg/proc/native/register_linux_386.go @@ -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) }) diff --git a/pkg/proc/native/registers_freebsd_amd64.go b/pkg/proc/native/registers_freebsd_amd64.go index 73ecc41563882a1070efa22e006f52eac0d07495..98e099121c334f5416cbe47b0a2f350e9a75d998 100644 --- a/pkg/proc/native/registers_freebsd_amd64.go +++ b/pkg/proc/native/registers_freebsd_amd64.go @@ -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()) diff --git a/pkg/proc/native/registers_linux_amd64.go b/pkg/proc/native/registers_linux_amd64.go index a16a08a35c2a8a41df182e1792840849b09243f6..c189de2bc8a201f8d222ae1b2a94d066d928b4fb 100644 --- a/pkg/proc/native/registers_linux_amd64.go +++ b/pkg/proc/native/registers_linux_amd64.go @@ -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 {