github.com/cnboonhan/delve@v0.0.0-20230908061759-363f2388c2fb/pkg/proc/winutil/regs_arm64_arch.go (about)

     1  package winutil
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"fmt"
     7  	"unsafe"
     8  
     9  	"github.com/go-delve/delve/pkg/dwarf/op"
    10  	"github.com/go-delve/delve/pkg/dwarf/regnum"
    11  	"github.com/go-delve/delve/pkg/proc"
    12  )
    13  
    14  const (
    15  	ARM64_MAX_BREAKPOINTS = 8
    16  	ARM64_MAX_WATCHPOINTS = 2
    17  )
    18  
    19  // neon128 tracks the neon128 windows struct.
    20  type neon128 struct {
    21  	Low  uint64
    22  	High int64
    23  }
    24  
    25  // ARM64Registers represents CPU registers on an ARM64 processor.
    26  type ARM64Registers struct {
    27  	iscgo          bool
    28  	Regs           [31]uint64
    29  	Sp             uint64
    30  	Pc             uint64
    31  	FloatRegisters [32]neon128
    32  	Fpcr           uint32
    33  	Fpsr           uint32
    34  	Bcr            [ARM64_MAX_BREAKPOINTS]uint32
    35  	Bvr            [ARM64_MAX_BREAKPOINTS]uint64
    36  	Wcr            [ARM64_MAX_WATCHPOINTS]uint32
    37  	Wvr            [ARM64_MAX_WATCHPOINTS]uint64
    38  	Context        *ARM64CONTEXT
    39  }
    40  
    41  // NewARM64Registers creates a new ARM64Registers struct from a CONTEXT.
    42  func NewARM64Registers(context *ARM64CONTEXT, iscgo bool) *ARM64Registers {
    43  	regs := &ARM64Registers{
    44  		iscgo:          iscgo,
    45  		Regs:           context.Regs,
    46  		Sp:             context.Sp,
    47  		Pc:             context.Pc,
    48  		FloatRegisters: context.FloatRegisters,
    49  		Fpcr:           context.Fpcr,
    50  		Fpsr:           context.Fpsr,
    51  		Bcr:            context.Bcr,
    52  		Bvr:            context.Bvr,
    53  		Wcr:            context.Wcr,
    54  		Wvr:            context.Wvr,
    55  		Context:        context,
    56  	}
    57  
    58  	return regs
    59  }
    60  
    61  // Slice returns the registers as a list of (name, value) pairs.
    62  func (r *ARM64Registers) Slice(floatingPoint bool) ([]proc.Register, error) {
    63  	out := make([]proc.Register, 0, len(r.Regs)+len(r.FloatRegisters)+2)
    64  	for i, v := range r.Regs {
    65  		out = proc.AppendUint64Register(out, fmt.Sprintf("X%d", i), v)
    66  	}
    67  	out = proc.AppendUint64Register(out, "SP", r.Sp)
    68  	out = proc.AppendUint64Register(out, "PC", r.Pc)
    69  	if floatingPoint {
    70  		for i := range r.FloatRegisters {
    71  			var buf bytes.Buffer
    72  			binary.Write(&buf, binary.LittleEndian, r.FloatRegisters[i].Low)
    73  			binary.Write(&buf, binary.LittleEndian, r.FloatRegisters[i].High)
    74  			out = proc.AppendBytesRegister(out, fmt.Sprintf("V%d", i), buf.Bytes())
    75  		}
    76  		out = proc.AppendUint64Register(out, "Fpcr", uint64(r.Fpcr))
    77  		out = proc.AppendUint64Register(out, "Fpsr", uint64(r.Fpsr))
    78  	}
    79  	return out, nil
    80  }
    81  
    82  // PC returns the value of RIP register.
    83  func (r *ARM64Registers) PC() uint64 {
    84  	return r.Pc
    85  }
    86  
    87  // SP returns the value of RSP register.
    88  func (r *ARM64Registers) SP() uint64 {
    89  	return r.Sp
    90  }
    91  
    92  func (r *ARM64Registers) BP() uint64 {
    93  	return r.Regs[29]
    94  }
    95  
    96  // TLS returns the address of the thread local storage memory segment.
    97  func (r *ARM64Registers) TLS() uint64 {
    98  	if !r.iscgo {
    99  		return 0
   100  	}
   101  	return r.Regs[18]
   102  }
   103  
   104  // GAddr returns the address of the G variable if it is known, 0 and false
   105  // otherwise.
   106  func (r *ARM64Registers) GAddr() (uint64, bool) {
   107  	return r.Regs[28], !r.iscgo
   108  }
   109  
   110  // LR returns the link register.
   111  func (r *ARM64Registers) LR() uint64 {
   112  	return r.Regs[30]
   113  }
   114  
   115  // Copy returns a copy of these registers that is guaranteed not to change.
   116  func (r *ARM64Registers) Copy() (proc.Registers, error) {
   117  	rr := *r
   118  	rr.Context = NewARM64CONTEXT()
   119  	*(rr.Context) = *(r.Context)
   120  	return &rr, nil
   121  }
   122  
   123  // ARM64CONTEXT tracks the _ARM64_NT_CONTEXT of windows.
   124  type ARM64CONTEXT struct {
   125  	ContextFlags   uint32
   126  	Cpsr           uint32
   127  	Regs           [31]uint64
   128  	Sp             uint64
   129  	Pc             uint64
   130  	FloatRegisters [32]neon128
   131  	Fpcr           uint32
   132  	Fpsr           uint32
   133  	Bcr            [ARM64_MAX_BREAKPOINTS]uint32
   134  	Bvr            [ARM64_MAX_BREAKPOINTS]uint64
   135  	Wcr            [ARM64_MAX_WATCHPOINTS]uint32
   136  	Wvr            [ARM64_MAX_WATCHPOINTS]uint64
   137  }
   138  
   139  // NewARM64CONTEXT allocates Windows CONTEXT structure aligned to 16 bytes.
   140  func NewARM64CONTEXT() *ARM64CONTEXT {
   141  	var c *ARM64CONTEXT
   142  	buf := make([]byte, unsafe.Sizeof(*c)+15)
   143  	return (*ARM64CONTEXT)(unsafe.Pointer((uintptr(unsafe.Pointer(&buf[15]))) &^ 15))
   144  }
   145  
   146  func (ctx *ARM64CONTEXT) SetFlags(flags uint32) {
   147  	ctx.ContextFlags = flags
   148  }
   149  
   150  func (ctx *ARM64CONTEXT) SetPC(pc uint64) {
   151  	ctx.Pc = pc
   152  }
   153  
   154  func (ctx *ARM64CONTEXT) SetTrap(trap bool) {
   155  	const v = 0x200000
   156  	if trap {
   157  		ctx.Cpsr |= v
   158  	} else {
   159  		ctx.Cpsr &= ^uint32(v)
   160  	}
   161  }
   162  
   163  func (ctx *ARM64CONTEXT) SetReg(regNum uint64, reg *op.DwarfRegister) error {
   164  	switch regNum {
   165  	case regnum.ARM64_PC:
   166  		ctx.Pc = reg.Uint64Val
   167  		return nil
   168  	case regnum.ARM64_SP:
   169  		ctx.Sp = reg.Uint64Val
   170  		return nil
   171  	default:
   172  		switch {
   173  		case regNum >= regnum.ARM64_X0 && regNum <= regnum.ARM64_X0+30:
   174  			ctx.Regs[regNum-regnum.ARM64_X0] = reg.Uint64Val
   175  			return nil
   176  
   177  		case regNum >= regnum.ARM64_V0 && regNum <= regnum.ARM64_V0+30:
   178  			i := regNum - regnum.ARM64_V0
   179  			ctx.FloatRegisters[i].Low = reg.Uint64Val
   180  			ctx.FloatRegisters[i].High = 0
   181  			return nil
   182  		default:
   183  			return fmt.Errorf("changing register %d not implemented", regNum)
   184  		}
   185  	}
   186  }