delve/pkg/proc/linutil/regs_arm64_arch.go

201 lines
4.9 KiB
Go

package linutil
import (
"fmt"
"github.com/go-delve/delve/pkg/dwarf/op"
"github.com/go-delve/delve/pkg/dwarf/regnum"
"github.com/go-delve/delve/pkg/proc"
)
// ARM64Registers is a wrapper for sys.PtraceRegs.
type ARM64Registers struct {
Regs *ARM64PtraceRegs // general-purpose registers
iscgo bool
tpidr_el0 uint64
Fpregs []proc.Register // Formatted floating point registers
Fpregset []byte // holding all floating point register values
loadFpRegs func(*ARM64Registers) error
}
func NewARM64Registers(regs *ARM64PtraceRegs, iscgo bool, tpidr_el0 uint64, loadFpRegs func(*ARM64Registers) error) *ARM64Registers {
return &ARM64Registers{Regs: regs, iscgo: iscgo, tpidr_el0: tpidr_el0, loadFpRegs: loadFpRegs}
}
// ARM64PtraceRegs is the struct used by the linux kernel to return the
// general purpose registers for ARM64 CPUs.
// copy from sys/unix/ztypes_linux_arm64.go:735
type ARM64PtraceRegs struct {
Regs [31]uint64
Sp uint64
Pc uint64
Pstate uint64
}
// Slice returns the registers as a list of (name, value) pairs.
func (r *ARM64Registers) Slice(floatingPoint bool) ([]proc.Register, error) {
var regs64 = []struct {
k string
v uint64
}{
{"X0", r.Regs.Regs[0]},
{"X1", r.Regs.Regs[1]},
{"X2", r.Regs.Regs[2]},
{"X3", r.Regs.Regs[3]},
{"X4", r.Regs.Regs[4]},
{"X5", r.Regs.Regs[5]},
{"X6", r.Regs.Regs[6]},
{"X7", r.Regs.Regs[7]},
{"X8", r.Regs.Regs[8]},
{"X9", r.Regs.Regs[9]},
{"X10", r.Regs.Regs[10]},
{"X11", r.Regs.Regs[11]},
{"X12", r.Regs.Regs[12]},
{"X13", r.Regs.Regs[13]},
{"X14", r.Regs.Regs[14]},
{"X15", r.Regs.Regs[15]},
{"X16", r.Regs.Regs[16]},
{"X17", r.Regs.Regs[17]},
{"X18", r.Regs.Regs[18]},
{"X19", r.Regs.Regs[19]},
{"X20", r.Regs.Regs[20]},
{"X21", r.Regs.Regs[21]},
{"X22", r.Regs.Regs[22]},
{"X23", r.Regs.Regs[23]},
{"X24", r.Regs.Regs[24]},
{"X25", r.Regs.Regs[25]},
{"X26", r.Regs.Regs[26]},
{"X27", r.Regs.Regs[27]},
{"X28", r.Regs.Regs[28]},
{"X29", r.Regs.Regs[29]},
{"X30", r.Regs.Regs[30]},
{"SP", r.Regs.Sp},
{"PC", r.Regs.Pc},
{"PSTATE", r.Regs.Pstate},
}
out := make([]proc.Register, 0, len(regs64)+len(r.Fpregs))
for _, reg := range regs64 {
out = proc.AppendUint64Register(out, reg.k, reg.v)
}
var floatLoadError error
if floatingPoint {
if r.loadFpRegs != nil {
floatLoadError = r.loadFpRegs(r)
r.loadFpRegs = nil
}
out = append(out, r.Fpregs...)
}
return out, floatLoadError
}
// PC returns the value of RIP register.
func (r *ARM64Registers) PC() uint64 {
return r.Regs.Pc
}
// SP returns the value of RSP register.
func (r *ARM64Registers) SP() uint64 {
return r.Regs.Sp
}
func (r *ARM64Registers) BP() uint64 {
return r.Regs.Regs[29]
}
// TLS returns the address of the thread local storage memory segment.
func (r *ARM64Registers) TLS() uint64 {
if !r.iscgo {
return 0
}
return r.tpidr_el0
}
// GAddr returns the address of the G variable if it is known, 0 and false
// otherwise.
func (r *ARM64Registers) GAddr() (uint64, bool) {
return r.Regs.Regs[28], !r.iscgo
}
// LR returns the link register.
func (r *ARM64Registers) LR() uint64 {
return r.Regs.Regs[30]
}
// Copy returns a copy of these registers that is guaranteed not to change.
func (r *ARM64Registers) Copy() (proc.Registers, error) {
if r.loadFpRegs != nil {
err := r.loadFpRegs(r)
r.loadFpRegs = nil
if err != nil {
return nil, err
}
}
var rr ARM64Registers
rr.Regs = &ARM64PtraceRegs{}
*(rr.Regs) = *(r.Regs)
if r.Fpregs != nil {
rr.Fpregs = make([]proc.Register, len(r.Fpregs))
copy(rr.Fpregs, r.Fpregs)
}
if r.Fpregset != nil {
rr.Fpregset = make([]byte, len(r.Fpregset))
copy(rr.Fpregset, r.Fpregset)
}
return &rr, nil
}
func (r *ARM64Registers) SetReg(regNum uint64, reg *op.DwarfRegister) (fpchanged bool, err error) {
switch regNum {
case regnum.ARM64_PC:
r.Regs.Pc = reg.Uint64Val
return false, nil
case regnum.ARM64_SP:
r.Regs.Sp = reg.Uint64Val
return false, nil
default:
switch {
case regNum >= regnum.ARM64_X0 && regNum <= regnum.ARM64_X0+30:
r.Regs.Regs[regNum-regnum.ARM64_X0] = reg.Uint64Val
return false, nil
case regNum >= regnum.ARM64_V0 && regNum <= regnum.ARM64_V0+30:
if r.loadFpRegs != nil {
err := r.loadFpRegs(r)
r.loadFpRegs = nil
if err != nil {
return false, err
}
}
i := regNum - regnum.ARM64_V0
reg.FillBytes()
copy(r.Fpregset[16*i:], reg.Bytes)
return true, nil
default:
return false, fmt.Errorf("changing register %d not implemented", regNum)
}
}
}
type ARM64PtraceFpRegs struct {
Vregs []byte
Fpsr uint32
Fpcr uint32
}
const _ARM_FP_REGS_LENGTH = 512
func (fpregs *ARM64PtraceFpRegs) Decode() (regs []proc.Register) {
for i := 0; i < len(fpregs.Vregs); i += 16 {
regs = proc.AppendBytesRegister(regs, fmt.Sprintf("V%d", i/16), fpregs.Vregs[i:i+16])
}
return
}
func (fpregs *ARM64PtraceFpRegs) Byte() []byte {
fpregs.Vregs = make([]byte, _ARM_FP_REGS_LENGTH)
return fpregs.Vregs[:]
}