proc: use CPUID to determine ZMM_Hi256 region offset (#3831)
The offset of state component i can be found via CPUID.(EAX=0DH,ECX=i):EBX. The ZMM_Hi256 is state component 6, so we use CPUID to enumerate the offset instead of hardcoding. For core dumps, we guess the ZMM_Hi256 offset based on xcr0 and the length of xsave region. The logic comes from binutils-gdb. Fixes #3827.
This commit is contained in:
parent
423644e288
commit
bef326c6a5
@ -79,7 +79,6 @@ const (
|
||||
_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.
|
||||
@ -87,7 +86,8 @@ const (
|
||||
// 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 xstateZMMHi256Offset is zero, it will be guessed.
|
||||
func AMD64XstateRead(xstateargs []byte, readLegacy bool, regset *AMD64Xstate, xstateZMMHi256Offset int) error {
|
||||
if _XSAVE_HEADER_START+_XSAVE_HEADER_LEN >= len(xstateargs) {
|
||||
return nil
|
||||
}
|
||||
@ -120,7 +120,19 @@ func AMD64XstateRead(xstateargs []byte, readLegacy bool, regset *AMD64Xstate) er
|
||||
return nil
|
||||
}
|
||||
|
||||
avx512state := xstateargs[_XSAVE_AVX512_ZMM_REGION_START:]
|
||||
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 {
|
||||
// AMD CPUs supporting PKRU
|
||||
xstateZMMHi256Offset = 896
|
||||
} else {
|
||||
// Intel CPUs supporting AVX512
|
||||
xstateZMMHi256Offset = 1152
|
||||
}
|
||||
}
|
||||
|
||||
avx512state := xstateargs[xstateZMMHi256Offset:]
|
||||
regset.Avx512State = true
|
||||
copy(regset.ZmmSpace[:], avx512state[:len(regset.ZmmSpace)])
|
||||
|
||||
@ -180,7 +192,7 @@ func (xstate *AMD64Xstate) SetXmmRegister(n int, value []byte) error {
|
||||
// Copy bytes [32, 64) to Xsave area
|
||||
|
||||
zmmval := rest
|
||||
zmmpos := _XSAVE_AVX512_ZMM_REGION_START + (n * 32)
|
||||
zmmpos := AMD64XstateZMMHi256Offset() + (n * 32)
|
||||
if zmmpos >= len(xstate.Xsave) {
|
||||
return fmt.Errorf("could not set XMM%d: bytes 32..%d not in XSAVE area", n, 32+len(zmmval))
|
||||
}
|
||||
|
@ -28,3 +28,28 @@ func AMD64XstateMaxSize() int {
|
||||
})
|
||||
return xstateMaxSize
|
||||
}
|
||||
|
||||
var xstateZMMHi256Offset int
|
||||
var loadXstateZMMHi256OffsetOnce sync.Once
|
||||
|
||||
// AMD64XstateZMMHi256Offset probes ZMM_Hi256 offset of the current CPU. Beware
|
||||
// that core dumps may be generated from a different CPU.
|
||||
func AMD64XstateZMMHi256Offset() int {
|
||||
loadXstateZMMHi256OffsetOnce.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
|
||||
xstateZMMHi256Offset = 0
|
||||
return
|
||||
}
|
||||
|
||||
_, bx, _, _ := cpuid(0x0d, 0x06) // ZMM_Hi256 is component #6
|
||||
xstateZMMHi256Offset = int(bx)
|
||||
})
|
||||
return xstateZMMHi256Offset
|
||||
}
|
||||
|
@ -5,3 +5,8 @@ package amd64util
|
||||
func AMD64XstateMaxSize() int {
|
||||
return _XSTATE_MAX_KNOWN_SIZE
|
||||
}
|
||||
|
||||
func AMD64XstateZMMHi256Offset() int {
|
||||
// AVX-512 not supported
|
||||
return 0
|
||||
}
|
||||
|
@ -338,7 +338,7 @@ func readNote(r io.ReadSeeker, machineType elf.Machine) (*note, error) {
|
||||
case _NT_X86_XSTATE:
|
||||
if machineType == _EM_X86_64 {
|
||||
var fpregs amd64util.AMD64Xstate
|
||||
if err := amd64util.AMD64XstateRead(desc, true, &fpregs); err != nil {
|
||||
if err := amd64util.AMD64XstateRead(desc, true, &fpregs, 0); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
note.Desc = &fpregs
|
||||
|
@ -73,7 +73,7 @@ func ptraceGetRegset(id int) (*amd64util.AMD64Xstate, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = amd64util.AMD64XstateRead(regset.Xsave, false, ®set)
|
||||
err = amd64util.AMD64XstateRead(regset.Xsave, false, ®set, amd64util.AMD64XstateZMMHi256Offset())
|
||||
return ®set, err
|
||||
}
|
||||
|
||||
|
@ -38,7 +38,7 @@ func ptraceGetRegset(tid int) (regset amd64util.AMD64Xstate, err error) {
|
||||
}
|
||||
|
||||
regset.Xsave = xstateargs[:iov.Len]
|
||||
err = amd64util.AMD64XstateRead(regset.Xsave, false, ®set)
|
||||
err = amd64util.AMD64XstateRead(regset.Xsave, false, ®set, amd64util.AMD64XstateZMMHi256Offset())
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -37,6 +37,6 @@ func ptraceGetRegset(tid int) (regset amd64util.AMD64Xstate, err error) {
|
||||
}
|
||||
|
||||
regset.Xsave = xstateargs[:iov.Len]
|
||||
err = amd64util.AMD64XstateRead(regset.Xsave, false, ®set)
|
||||
err = amd64util.AMD64XstateRead(regset.Xsave, false, ®set, amd64util.AMD64XstateZMMHi256Offset())
|
||||
return
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user