package linutil import ( "golang.org/x/arch/x86/x86asm" "github.com/go-delve/delve/pkg/proc" "github.com/go-delve/delve/pkg/proc/amd64util" ) // I386Registers implements the proc.Registers interface for the native/linux // backend and core/linux backends, on I386. type I386Registers struct { Regs *I386PtraceRegs Fpregs []proc.Register Fpregset *amd64util.AMD64Xstate Tls uint64 loadFpRegs func(*I386Registers) error } func NewI386Registers(regs *I386PtraceRegs, loadFpRegs func(*I386Registers) error) *I386Registers { return &I386Registers{Regs: regs, Fpregs: nil, Fpregset: nil, Tls: 0, loadFpRegs: loadFpRegs} } // I386PtraceRegs is the struct used by the linux kernel to return the // general purpose registers for I386 CPUs. type I386PtraceRegs struct { Ebx int32 Ecx int32 Edx int32 Esi int32 Edi int32 Ebp int32 Eax int32 Xds int32 Xes int32 Xfs int32 Xgs int32 Orig_eax int32 Eip int32 Xcs int32 Eflags int32 Esp int32 Xss int32 } // Slice returns the registers as a list of (name, value) pairs. func (r *I386Registers) Slice(floatingPoint bool) ([]proc.Register, error) { var regs = []struct { k string v int32 }{ {"Ebx", r.Regs.Ebx}, {"Ecx", r.Regs.Ecx}, {"Edx", r.Regs.Edx}, {"Esi", r.Regs.Esi}, {"Edi", r.Regs.Edi}, {"Ebp", r.Regs.Ebp}, {"Eax", r.Regs.Eax}, {"Xds", r.Regs.Xds}, {"Xes", r.Regs.Xes}, {"Xfs", r.Regs.Xfs}, {"Xgs", r.Regs.Xgs}, {"Orig_eax", r.Regs.Orig_eax}, {"Eip", r.Regs.Eip}, {"Xcs", r.Regs.Xcs}, {"Eflags", r.Regs.Eflags}, {"Esp", r.Regs.Esp}, {"Xss", r.Regs.Xss}, } out := make([]proc.Register, 0, len(regs)+len(r.Fpregs)) for _, reg := range regs { out = proc.AppendUint64Register(out, reg.k, uint64(uint32(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 EIP register. func (r *I386Registers) PC() uint64 { return uint64(uint32(r.Regs.Eip)) } // SP returns the value of ESP register. func (r *I386Registers) SP() uint64 { return uint64(uint32(r.Regs.Esp)) } func (r *I386Registers) BP() uint64 { return uint64(uint32(r.Regs.Ebp)) } // CX returns the value of ECX register. func (r *I386Registers) CX() uint64 { return uint64(uint32(r.Regs.Ecx)) } // TLS returns the address of the thread local storage memory segment. func (r I386Registers) TLS() uint64 { return r.Tls } // GAddr returns the address of the G variable if it is known, 0 and false // otherwise. func (r *I386Registers) GAddr() (uint64, bool) { return 0, false } // Get returns the value of the n-th register (in x86asm order). func (r *I386Registers) Get(n int) (uint64, error) { reg := x86asm.Reg(n) const ( mask8 = 0x000000ff mask16 = 0x0000ffff ) switch reg { // 8-bit case x86asm.AL: return uint64(r.Regs.Eax) & mask8, nil case x86asm.CL: return uint64(r.Regs.Ecx) & mask8, nil case x86asm.DL: return uint64(r.Regs.Edx) & mask8, nil case x86asm.BL: return uint64(r.Regs.Ebx) & mask8, nil case x86asm.AH: return (uint64(r.Regs.Eax) >> 8) & mask8, nil case x86asm.CH: return (uint64(r.Regs.Ecx) >> 8) & mask8, nil case x86asm.DH: return (uint64(r.Regs.Edx) >> 8) & mask8, nil case x86asm.BH: return (uint64(r.Regs.Ebx) >> 8) & mask8, nil case x86asm.SPB: return uint64(r.Regs.Esp) & mask8, nil case x86asm.BPB: return uint64(r.Regs.Ebp) & mask8, nil case x86asm.SIB: return uint64(r.Regs.Esi) & mask8, nil case x86asm.DIB: return uint64(r.Regs.Edi) & mask8, nil // 16-bit case x86asm.AX: return uint64(r.Regs.Eax) & mask16, nil case x86asm.CX: return uint64(r.Regs.Ecx) & mask16, nil case x86asm.DX: return uint64(r.Regs.Edx) & mask16, nil case x86asm.BX: return uint64(r.Regs.Ebx) & mask16, nil case x86asm.SP: return uint64(r.Regs.Esp) & mask16, nil case x86asm.BP: return uint64(r.Regs.Ebp) & mask16, nil case x86asm.SI: return uint64(r.Regs.Esi) & mask16, nil case x86asm.DI: return uint64(r.Regs.Edi) & mask16, nil // 32-bit case x86asm.EAX: return uint64(uint32(r.Regs.Eax)), nil case x86asm.ECX: return uint64(uint32(r.Regs.Ecx)), nil case x86asm.EDX: return uint64(uint32(r.Regs.Edx)), nil case x86asm.EBX: return uint64(uint32(r.Regs.Ebx)), nil case x86asm.ESP: return uint64(uint32(r.Regs.Esp)), nil case x86asm.EBP: return uint64(uint32(r.Regs.Ebp)), nil case x86asm.ESI: return uint64(uint32(r.Regs.Esi)), nil case x86asm.EDI: return uint64(uint32(r.Regs.Edi)), nil } return 0, proc.ErrUnknownRegister } // Copy returns a copy of these registers that is guaranteed not to change. func (r *I386Registers) Copy() (proc.Registers, error) { if r.loadFpRegs != nil { err := r.loadFpRegs(r) r.loadFpRegs = nil if err != nil { return nil, err } } var rr I386Registers rr.Regs = &I386PtraceRegs{} rr.Fpregset = &amd64util.AMD64Xstate{} *(rr.Regs) = *(r.Regs) if r.Fpregset != nil { *(rr.Fpregset) = *(r.Fpregset) } if r.Fpregs != nil { rr.Fpregs = make([]proc.Register, len(r.Fpregs)) copy(rr.Fpregs, r.Fpregs) } return &rr, nil }