mirror of https://github.com/beego/bee.git
349 lines
9.9 KiB
Go
349 lines
9.9 KiB
Go
|
package proc
|
|||
|
|
|||
|
import (
|
|||
|
"bytes"
|
|||
|
"encoding/binary"
|
|||
|
"errors"
|
|||
|
"fmt"
|
|||
|
"math"
|
|||
|
"os"
|
|||
|
"strings"
|
|||
|
)
|
|||
|
|
|||
|
// Registers is an interface for a generic register type. The
|
|||
|
// interface encapsulates the generic values / actions
|
|||
|
// we need independent of arch. The concrete register types
|
|||
|
// will be different depending on OS/Arch.
|
|||
|
type Registers interface {
|
|||
|
PC() uint64
|
|||
|
SP() uint64
|
|||
|
BP() uint64
|
|||
|
CX() uint64
|
|||
|
TLS() uint64
|
|||
|
// GAddr returns the address of the G variable if it is known, 0 and false otherwise
|
|||
|
GAddr() (uint64, bool)
|
|||
|
Get(int) (uint64, error)
|
|||
|
Slice() []Register
|
|||
|
// Copy returns a copy of the registers that is guaranteed not to change
|
|||
|
// when the registers of the associated thread change.
|
|||
|
Copy() Registers
|
|||
|
}
|
|||
|
|
|||
|
// Register represents a CPU register.
|
|||
|
type Register struct {
|
|||
|
Name string
|
|||
|
Bytes []byte
|
|||
|
Value string
|
|||
|
}
|
|||
|
|
|||
|
// AppendWordReg appends a word (16 bit) register to regs.
|
|||
|
func AppendWordReg(regs []Register, name string, value uint16) []Register {
|
|||
|
var buf bytes.Buffer
|
|||
|
binary.Write(&buf, binary.LittleEndian, value)
|
|||
|
return append(regs, Register{name, buf.Bytes(), fmt.Sprintf("%#04x", value)})
|
|||
|
}
|
|||
|
|
|||
|
// AppendDwordReg appends a double word (32 bit) register to regs.
|
|||
|
func AppendDwordReg(regs []Register, name string, value uint32) []Register {
|
|||
|
var buf bytes.Buffer
|
|||
|
binary.Write(&buf, binary.LittleEndian, value)
|
|||
|
return append(regs, Register{name, buf.Bytes(), fmt.Sprintf("%#08x", value)})
|
|||
|
}
|
|||
|
|
|||
|
// AppendQwordReg appends a quad word (64 bit) register to regs.
|
|||
|
func AppendQwordReg(regs []Register, name string, value uint64) []Register {
|
|||
|
var buf bytes.Buffer
|
|||
|
binary.Write(&buf, binary.LittleEndian, value)
|
|||
|
return append(regs, Register{name, buf.Bytes(), fmt.Sprintf("%#016x", value)})
|
|||
|
}
|
|||
|
|
|||
|
func appendFlagReg(regs []Register, name string, value uint64, descr flagRegisterDescr, size int) []Register {
|
|||
|
var buf bytes.Buffer
|
|||
|
binary.Write(&buf, binary.LittleEndian, value)
|
|||
|
return append(regs, Register{name, buf.Bytes()[:size], descr.Describe(value, size)})
|
|||
|
}
|
|||
|
|
|||
|
// AppendEflagReg appends EFLAG register to regs.
|
|||
|
func AppendEflagReg(regs []Register, name string, value uint64) []Register {
|
|||
|
return appendFlagReg(regs, name, value, eflagsDescription, 64)
|
|||
|
}
|
|||
|
|
|||
|
// AppendMxcsrReg appends MXCSR register to regs.
|
|||
|
func AppendMxcsrReg(regs []Register, name string, value uint64) []Register {
|
|||
|
return appendFlagReg(regs, name, value, mxcsrDescription, 32)
|
|||
|
}
|
|||
|
|
|||
|
// AppendX87Reg appends a 80 bit float register to regs.
|
|||
|
func AppendX87Reg(regs []Register, index int, exponent uint16, mantissa uint64) []Register {
|
|||
|
var f float64
|
|||
|
fset := false
|
|||
|
|
|||
|
const (
|
|||
|
_SIGNBIT = 1 << 15
|
|||
|
_EXP_BIAS = (1 << 14) - 1 // 2^(n-1) - 1 = 16383
|
|||
|
_SPECIALEXP = (1 << 15) - 1 // all bits set
|
|||
|
_HIGHBIT = 1 << 63
|
|||
|
_QUIETBIT = 1 << 62
|
|||
|
)
|
|||
|
|
|||
|
sign := 1.0
|
|||
|
if exponent&_SIGNBIT != 0 {
|
|||
|
sign = -1.0
|
|||
|
}
|
|||
|
exponent &= ^uint16(_SIGNBIT)
|
|||
|
|
|||
|
NaN := math.NaN()
|
|||
|
Inf := math.Inf(+1)
|
|||
|
|
|||
|
switch exponent {
|
|||
|
case 0:
|
|||
|
switch {
|
|||
|
case mantissa == 0:
|
|||
|
f = sign * 0.0
|
|||
|
fset = true
|
|||
|
case mantissa&_HIGHBIT != 0:
|
|||
|
f = NaN
|
|||
|
fset = true
|
|||
|
}
|
|||
|
case _SPECIALEXP:
|
|||
|
switch {
|
|||
|
case mantissa&_HIGHBIT == 0:
|
|||
|
f = sign * Inf
|
|||
|
fset = true
|
|||
|
default:
|
|||
|
f = NaN // signaling NaN
|
|||
|
fset = true
|
|||
|
}
|
|||
|
default:
|
|||
|
if mantissa&_HIGHBIT == 0 {
|
|||
|
f = NaN
|
|||
|
fset = true
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if !fset {
|
|||
|
significand := float64(mantissa) / (1 << 63)
|
|||
|
f = sign * math.Ldexp(significand, int(exponent-_EXP_BIAS))
|
|||
|
}
|
|||
|
|
|||
|
var buf bytes.Buffer
|
|||
|
binary.Write(&buf, binary.LittleEndian, exponent)
|
|||
|
binary.Write(&buf, binary.LittleEndian, mantissa)
|
|||
|
|
|||
|
return append(regs, Register{fmt.Sprintf("ST(%d)", index), buf.Bytes(), fmt.Sprintf("%#04x%016x\t%g", exponent, mantissa, f)})
|
|||
|
}
|
|||
|
|
|||
|
// AppendSSEReg appends a 256 bit SSE register to regs.
|
|||
|
func AppendSSEReg(regs []Register, name string, xmm []byte) []Register {
|
|||
|
buf := bytes.NewReader(xmm)
|
|||
|
|
|||
|
var out bytes.Buffer
|
|||
|
var vi [16]uint8
|
|||
|
for i := range vi {
|
|||
|
binary.Read(buf, binary.LittleEndian, &vi[i])
|
|||
|
}
|
|||
|
|
|||
|
fmt.Fprintf(&out, "0x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8], vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0])
|
|||
|
|
|||
|
fmt.Fprintf(&out, "\tv2_int={ %02x%02x%02x%02x%02x%02x%02x%02x %02x%02x%02x%02x%02x%02x%02x%02x }", vi[7], vi[6], vi[5], vi[4], vi[3], vi[2], vi[1], vi[0], vi[15], vi[14], vi[13], vi[12], vi[11], vi[10], vi[9], vi[8])
|
|||
|
|
|||
|
fmt.Fprintf(&out, "\tv4_int={ %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x }", vi[3], vi[2], vi[1], vi[0], vi[7], vi[6], vi[5], vi[4], vi[11], vi[10], vi[9], vi[8], vi[15], vi[14], vi[13], vi[12])
|
|||
|
|
|||
|
fmt.Fprintf(&out, "\tv8_int={ %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x %02x%02x }", vi[1], vi[0], vi[3], vi[2], vi[5], vi[4], vi[7], vi[6], vi[9], vi[8], vi[11], vi[10], vi[13], vi[12], vi[15], vi[14])
|
|||
|
|
|||
|
fmt.Fprintf(&out, "\tv16_int={ %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x }", vi[0], vi[1], vi[2], vi[3], vi[4], vi[5], vi[6], vi[7], vi[8], vi[9], vi[10], vi[11], vi[12], vi[13], vi[14], vi[15])
|
|||
|
|
|||
|
buf.Seek(0, os.SEEK_SET)
|
|||
|
var v2 [2]float64
|
|||
|
for i := range v2 {
|
|||
|
binary.Read(buf, binary.LittleEndian, &v2[i])
|
|||
|
}
|
|||
|
fmt.Fprintf(&out, "\tv2_float={ %g %g }", v2[0], v2[1])
|
|||
|
|
|||
|
buf.Seek(0, os.SEEK_SET)
|
|||
|
var v4 [4]float32
|
|||
|
for i := range v4 {
|
|||
|
binary.Read(buf, binary.LittleEndian, &v4[i])
|
|||
|
}
|
|||
|
fmt.Fprintf(&out, "\tv4_float={ %g %g %g %g }", v4[0], v4[1], v4[2], v4[3])
|
|||
|
|
|||
|
return append(regs, Register{name, xmm, out.String()})
|
|||
|
}
|
|||
|
|
|||
|
// ErrUnknownRegister is returned when the value of an unknown
|
|||
|
// register is requested.
|
|||
|
var ErrUnknownRegister = errors.New("unknown register")
|
|||
|
|
|||
|
type flagRegisterDescr []flagDescr
|
|||
|
type flagDescr struct {
|
|||
|
name string
|
|||
|
mask uint64
|
|||
|
}
|
|||
|
|
|||
|
var mxcsrDescription flagRegisterDescr = []flagDescr{
|
|||
|
{"FZ", 1 << 15},
|
|||
|
{"RZ/RN", 1<<14 | 1<<13},
|
|||
|
{"PM", 1 << 12},
|
|||
|
{"UM", 1 << 11},
|
|||
|
{"OM", 1 << 10},
|
|||
|
{"ZM", 1 << 9},
|
|||
|
{"DM", 1 << 8},
|
|||
|
{"IM", 1 << 7},
|
|||
|
{"DAZ", 1 << 6},
|
|||
|
{"PE", 1 << 5},
|
|||
|
{"UE", 1 << 4},
|
|||
|
{"OE", 1 << 3},
|
|||
|
{"ZE", 1 << 2},
|
|||
|
{"DE", 1 << 1},
|
|||
|
{"IE", 1 << 0},
|
|||
|
}
|
|||
|
|
|||
|
var eflagsDescription flagRegisterDescr = []flagDescr{
|
|||
|
{"CF", 1 << 0},
|
|||
|
{"", 1 << 1},
|
|||
|
{"PF", 1 << 2},
|
|||
|
{"AF", 1 << 4},
|
|||
|
{"ZF", 1 << 6},
|
|||
|
{"SF", 1 << 7},
|
|||
|
{"TF", 1 << 8},
|
|||
|
{"IF", 1 << 9},
|
|||
|
{"DF", 1 << 10},
|
|||
|
{"OF", 1 << 11},
|
|||
|
{"IOPL", 1<<12 | 1<<13},
|
|||
|
{"NT", 1 << 14},
|
|||
|
{"RF", 1 << 16},
|
|||
|
{"VM", 1 << 17},
|
|||
|
{"AC", 1 << 18},
|
|||
|
{"VIF", 1 << 19},
|
|||
|
{"VIP", 1 << 20},
|
|||
|
{"ID", 1 << 21},
|
|||
|
}
|
|||
|
|
|||
|
func (descr flagRegisterDescr) Mask() uint64 {
|
|||
|
var r uint64
|
|||
|
for _, f := range descr {
|
|||
|
r = r | f.mask
|
|||
|
}
|
|||
|
return r
|
|||
|
}
|
|||
|
|
|||
|
func (descr flagRegisterDescr) Describe(reg uint64, bitsize int) string {
|
|||
|
var r []string
|
|||
|
for _, f := range descr {
|
|||
|
if f.name == "" {
|
|||
|
continue
|
|||
|
}
|
|||
|
// rbm is f.mask with only the right-most bit set:
|
|||
|
// 0001 1100 -> 0000 0100
|
|||
|
rbm := f.mask & -f.mask
|
|||
|
if rbm == f.mask {
|
|||
|
if reg&f.mask != 0 {
|
|||
|
r = append(r, f.name)
|
|||
|
}
|
|||
|
} else {
|
|||
|
x := (reg & f.mask) >> uint64(math.Log2(float64(rbm)))
|
|||
|
r = append(r, fmt.Sprintf("%s=%x", f.name, x))
|
|||
|
}
|
|||
|
}
|
|||
|
if reg & ^descr.Mask() != 0 {
|
|||
|
r = append(r, fmt.Sprintf("unknown_flags=%x", reg&^descr.Mask()))
|
|||
|
}
|
|||
|
return fmt.Sprintf("%#0*x\t[%s]", bitsize/4, reg, strings.Join(r, " "))
|
|||
|
}
|
|||
|
|
|||
|
// PtraceFpRegs tracks user_fpregs_struct in /usr/include/x86_64-linux-gnu/sys/user.h
|
|||
|
type PtraceFpRegs 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
|
|||
|
}
|
|||
|
|
|||
|
// LinuxX86Xstate 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 LinuxX86Xstate struct {
|
|||
|
PtraceFpRegs
|
|||
|
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 *LinuxX86Xstate) Decode() (regs []Register) {
|
|||
|
// x87 registers
|
|||
|
regs = AppendWordReg(regs, "CW", xsave.Cwd)
|
|||
|
regs = AppendWordReg(regs, "SW", xsave.Swd)
|
|||
|
regs = AppendWordReg(regs, "TW", xsave.Ftw)
|
|||
|
regs = AppendWordReg(regs, "FOP", xsave.Fop)
|
|||
|
regs = AppendQwordReg(regs, "FIP", xsave.Rip)
|
|||
|
regs = AppendQwordReg(regs, "FDP", xsave.Rdp)
|
|||
|
|
|||
|
for i := 0; i < len(xsave.StSpace); i += 4 {
|
|||
|
regs = AppendX87Reg(regs, i/4, uint16(xsave.StSpace[i+2]), uint64(xsave.StSpace[i+1])<<32|uint64(xsave.StSpace[i]))
|
|||
|
}
|
|||
|
|
|||
|
// SSE registers
|
|||
|
regs = AppendMxcsrReg(regs, "MXCSR", uint64(xsave.Mxcsr))
|
|||
|
regs = AppendDwordReg(regs, "MXCSR_MASK", xsave.MxcrMask)
|
|||
|
|
|||
|
for i := 0; i < len(xsave.XmmSpace); i += 16 {
|
|||
|
regs = AppendSSEReg(regs, fmt.Sprintf("XMM%d", i/16), xsave.XmmSpace[i:i+16])
|
|||
|
if xsave.AvxState {
|
|||
|
regs = AppendSSEReg(regs, fmt.Sprintf("YMM%d", i/16), xsave.YmmSpace[i:i+16])
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
const (
|
|||
|
_XSAVE_HEADER_START = 512
|
|||
|
_XSAVE_HEADER_LEN = 64
|
|||
|
_XSAVE_EXTENDED_REGION_START = 576
|
|||
|
_XSAVE_SSE_REGION_LEN = 416
|
|||
|
)
|
|||
|
|
|||
|
// 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 LinuxX86XstateRead(xstateargs []byte, readLegacy bool, regset *LinuxX86Xstate) 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.PtraceFpRegs); 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
|
|||
|
}
|