gitlab.com/Raven-IO/raven-delve@v1.22.4/pkg/proc/amd64util/xsave.go (about) 1 package amd64util 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "fmt" 7 8 "gitlab.com/Raven-IO/raven-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 (xstate *AMD64Xstate) Decode() []proc.Register { 40 var regs []proc.Register 41 // x87 registers 42 regs = proc.AppendUint64Register(regs, "CW", uint64(xstate.Cwd)) 43 regs = proc.AppendUint64Register(regs, "SW", uint64(xstate.Swd)) 44 regs = proc.AppendUint64Register(regs, "TW", uint64(xstate.Ftw)) 45 regs = proc.AppendUint64Register(regs, "FOP", uint64(xstate.Fop)) 46 regs = proc.AppendUint64Register(regs, "FIP", xstate.Rip) 47 regs = proc.AppendUint64Register(regs, "FDP", xstate.Rdp) 48 49 for i := 0; i < len(xstate.StSpace); i += 4 { 50 var buf bytes.Buffer 51 binary.Write(&buf, binary.LittleEndian, uint64(xstate.StSpace[i+1])<<32|uint64(xstate.StSpace[i])) 52 binary.Write(&buf, binary.LittleEndian, uint16(xstate.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(xstate.Mxcsr)) 58 regs = proc.AppendUint64Register(regs, "MXCSR_MASK", uint64(xstate.MxcrMask)) 59 60 for i := 0; i < len(xstate.XmmSpace); i += 16 { 61 n := i / 16 62 regs = proc.AppendBytesRegister(regs, fmt.Sprintf("XMM%d", n), xstate.XmmSpace[i:i+16]) 63 if xstate.AvxState { 64 regs = proc.AppendBytesRegister(regs, fmt.Sprintf("YMM%d", n), xstate.YmmSpace[i:i+16]) 65 if xstate.Avx512State { 66 regs = proc.AppendBytesRegister(regs, fmt.Sprintf("ZMM%d", n), xstate.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, ®set.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 }