github.com/undoio/delve@v1.9.0/pkg/proc/amd64util/xsave.go (about)

     1  package amd64util
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"fmt"
     7  
     8  	"github.com/undoio/delve/pkg/proc"
     9  )
    10  
    11  // AMD64Xstate represents amd64 XSAVE area. See Section 13.1 (and
    12  // following) of Intel® 64 and IA-32 Architectures Software Developer’s
    13  // Manual, Volume 1: Basic Architecture.
    14  type AMD64Xstate struct {
    15  	AMD64PtraceFpRegs
    16  	Xsave       []byte // raw xsave area
    17  	AvxState    bool   // contains AVX state
    18  	YmmSpace    [256]byte
    19  	Avx512State bool // contains AVX512 state
    20  	ZmmSpace    [512]byte
    21  }
    22  
    23  // AMD64PtraceFpRegs tracks user_fpregs_struct in /usr/include/x86_64-linux-gnu/sys/user.h
    24  type AMD64PtraceFpRegs struct {
    25  	Cwd      uint16
    26  	Swd      uint16
    27  	Ftw      uint16
    28  	Fop      uint16
    29  	Rip      uint64
    30  	Rdp      uint64
    31  	Mxcsr    uint32
    32  	MxcrMask uint32
    33  	StSpace  [32]uint32
    34  	XmmSpace [256]byte
    35  	Padding  [24]uint32
    36  }
    37  
    38  // Decode decodes an XSAVE area to a list of name/value pairs of registers.
    39  func (xsave *AMD64Xstate) Decode() []proc.Register {
    40  	var regs []proc.Register
    41  	// x87 registers
    42  	regs = proc.AppendUint64Register(regs, "CW", uint64(xsave.Cwd))
    43  	regs = proc.AppendUint64Register(regs, "SW", uint64(xsave.Swd))
    44  	regs = proc.AppendUint64Register(regs, "TW", uint64(xsave.Ftw))
    45  	regs = proc.AppendUint64Register(regs, "FOP", uint64(xsave.Fop))
    46  	regs = proc.AppendUint64Register(regs, "FIP", xsave.Rip)
    47  	regs = proc.AppendUint64Register(regs, "FDP", xsave.Rdp)
    48  
    49  	for i := 0; i < len(xsave.StSpace); i += 4 {
    50  		var buf bytes.Buffer
    51  		binary.Write(&buf, binary.LittleEndian, uint64(xsave.StSpace[i+1])<<32|uint64(xsave.StSpace[i]))
    52  		binary.Write(&buf, binary.LittleEndian, uint16(xsave.StSpace[i+2]))
    53  		regs = proc.AppendBytesRegister(regs, fmt.Sprintf("ST(%d)", i/4), buf.Bytes())
    54  	}
    55  
    56  	// SSE registers
    57  	regs = proc.AppendUint64Register(regs, "MXCSR", uint64(xsave.Mxcsr))
    58  	regs = proc.AppendUint64Register(regs, "MXCSR_MASK", uint64(xsave.MxcrMask))
    59  
    60  	for i := 0; i < len(xsave.XmmSpace); i += 16 {
    61  		n := i / 16
    62  		regs = proc.AppendBytesRegister(regs, fmt.Sprintf("XMM%d", n), xsave.XmmSpace[i:i+16])
    63  		if xsave.AvxState {
    64  			regs = proc.AppendBytesRegister(regs, fmt.Sprintf("YMM%d", n), xsave.YmmSpace[i:i+16])
    65  			if xsave.Avx512State {
    66  				regs = proc.AppendBytesRegister(regs, fmt.Sprintf("ZMM%d", n), xsave.ZmmSpace[n*32:(n+1)*32])
    67  			}
    68  		}
    69  	}
    70  
    71  	return regs
    72  }
    73  
    74  const (
    75  	_XSTATE_MAX_KNOWN_SIZE = 2969
    76  
    77  	_XSAVE_XMM_REGION_START        = 160
    78  	_XSAVE_HEADER_START            = 512
    79  	_XSAVE_HEADER_LEN              = 64
    80  	_XSAVE_EXTENDED_REGION_START   = 576
    81  	_XSAVE_SSE_REGION_LEN          = 416
    82  	_XSAVE_AVX512_ZMM_REGION_START = 1152
    83  )
    84  
    85  // AMD64XstateRead reads a byte array containing an XSAVE area into regset.
    86  // If readLegacy is true regset.PtraceFpRegs will be filled with the
    87  // contents of the legacy region of the XSAVE area.
    88  // See Section 13.1 (and following) of Intel® 64 and IA-32 Architectures
    89  // Software Developer’s Manual, Volume 1: Basic Architecture.
    90  func AMD64XstateRead(xstateargs []byte, readLegacy bool, regset *AMD64Xstate) error {
    91  	if _XSAVE_HEADER_START+_XSAVE_HEADER_LEN >= len(xstateargs) {
    92  		return nil
    93  	}
    94  	if readLegacy {
    95  		rdr := bytes.NewReader(xstateargs[:_XSAVE_HEADER_START])
    96  		if err := binary.Read(rdr, binary.LittleEndian, &regset.AMD64PtraceFpRegs); err != nil {
    97  			return err
    98  		}
    99  	}
   100  	xsaveheader := xstateargs[_XSAVE_HEADER_START : _XSAVE_HEADER_START+_XSAVE_HEADER_LEN]
   101  	xstate_bv := binary.LittleEndian.Uint64(xsaveheader[0:8])
   102  	xcomp_bv := binary.LittleEndian.Uint64(xsaveheader[8:16])
   103  
   104  	if xcomp_bv&(1<<63) != 0 {
   105  		// compact format not supported
   106  		return nil
   107  	}
   108  
   109  	if xstate_bv&(1<<2) == 0 {
   110  		// AVX state not present
   111  		return nil
   112  	}
   113  
   114  	avxstate := xstateargs[_XSAVE_EXTENDED_REGION_START:]
   115  	regset.AvxState = true
   116  	copy(regset.YmmSpace[:], avxstate[:len(regset.YmmSpace)])
   117  
   118  	if xstate_bv&(1<<6) == 0 {
   119  		// AVX512 state not present
   120  		return nil
   121  	}
   122  
   123  	avx512state := xstateargs[_XSAVE_AVX512_ZMM_REGION_START:]
   124  	regset.Avx512State = true
   125  	copy(regset.ZmmSpace[:], avx512state[:len(regset.ZmmSpace)])
   126  
   127  	// TODO(aarzilli): if xstate_bv&(1<<7) is set then xstateargs[1664:2688]
   128  	// contains ZMM16 through ZMM31, those aren't just the higher 256bits, it's
   129  	// the full register so each is 64 bytes (512bits)
   130  
   131  	return nil
   132  }
   133  
   134  func (xstate *AMD64Xstate) SetXmmRegister(n int, value []byte) error {
   135  	if n >= 16 {
   136  		return fmt.Errorf("setting register XMM%d not supported", n)
   137  	}
   138  	if len(value) > 64 {
   139  		return fmt.Errorf("value of register XMM%d too large (%d bytes)", n, len(value))
   140  	}
   141  
   142  	// Copy least significant 16 bytes to Xsave area
   143  
   144  	xmmval := value
   145  	if len(xmmval) > 16 {
   146  		xmmval = xmmval[:16]
   147  	}
   148  	rest := value[len(xmmval):]
   149  
   150  	xmmpos := _XSAVE_XMM_REGION_START + (n * 16)
   151  	if xmmpos >= len(xstate.Xsave) {
   152  		return fmt.Errorf("could not set XMM%d: not in XSAVE area", n)
   153  	}
   154  
   155  	copy(xstate.Xsave[xmmpos:], xmmval)
   156  
   157  	if len(rest) == 0 {
   158  		return nil
   159  	}
   160  
   161  	// Copy bytes [16, 32) to Xsave area
   162  
   163  	ymmval := rest
   164  	if len(ymmval) > 16 {
   165  		ymmval = ymmval[:16]
   166  	}
   167  	rest = rest[len(ymmval):]
   168  
   169  	ymmpos := _XSAVE_EXTENDED_REGION_START + (n * 16)
   170  	if ymmpos >= len(xstate.Xsave) {
   171  		return fmt.Errorf("could not set XMM%d: bytes 16..%d not in XSAVE area", n, 16+len(ymmval))
   172  	}
   173  
   174  	copy(xstate.Xsave[ymmpos:], ymmval)
   175  
   176  	if len(rest) == 0 {
   177  		return nil
   178  	}
   179  
   180  	// Copy bytes [32, 64) to Xsave area
   181  
   182  	zmmval := rest
   183  	zmmpos := _XSAVE_AVX512_ZMM_REGION_START + (n * 32)
   184  	if zmmpos >= len(xstate.Xsave) {
   185  		return fmt.Errorf("could not set XMM%d: bytes 32..%d not in XSAVE area", n, 32+len(zmmval))
   186  	}
   187  
   188  	copy(xstate.Xsave[zmmpos:], zmmval)
   189  	return nil
   190  }