go-delve/delve · error

changing register %d not implemented

Error message

changing register %d not implemented

What it means

The arm64 SetReg implementation covers only a fixed subset of registers (GPRs and V0-V31 vector registers). Any register number falling through to the default case has no write path implemented, so the request is rejected.

Source

Thrown at pkg/proc/linutil/regs_arm64_arch.go:177

			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
}

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Restrict register writes to GPRs and V0-V31 on arm64
  2. Handle FPSR/FPCR writes through ptrace GETFPREGS/SETFPREGS at the native backend level if needed
  3. Verify the regnum constant is a valid ARM64 register for the intended set

Example fix

// before
thread.SetReg(regnum.ARM64_FPSR, reg) // not implemented
// after
if regnum.ARM64_V0 <= regNum && regNum <= regnum.ARM64_V0+31 {
    thread.SetReg(regNum, reg)
} else {
    return fmt.Errorf("cannot set register %d on arm64", regNum)
}
Defensive patterns

Strategy: validation

Validate before calling

supported := regNum <= regnum.ARM64_R30 || (regNum >= regnum.ARM64_V0 && regNum <= regnum.ARM64_V0+31)
if !supported {
    return fmt.Errorf("register %d not settable on arm64", regNum)
}

Type guard

func isSettableARM64(regNum uint64) bool {
    return regNum <= 30 || (regNum >= regnum.ARM64_V0 && regNum <= regnum.ARM64_V0+31)
}

Try / catch

if _, err := thread.SetReg(regNum, reg); err != nil {
    if strings.Contains(err.Error(), "not implemented") {
        return fmt.Errorf("arm64 register %d cannot be modified", regNum)
    }
    return err
}

Prevention

When it happens

Trigger: Calling SetReg on Linux/arm64 with a register number that is neither a handled general-purpose register nor within ARM64_V0..V0+31 (e.g. FPSR, FPCR, or a bogus/out-of-range regnum).

Common situations: Trying to modify arm64 floating-point status/control registers or system registers via the debugger; porting code that assumed x86-style full register writability.

Related errors


AI-assisted analysis of go-delve/delve@a23773e6c3 (2026-08-31). Data as JSON: /api/errors/dc50fb71ba6f5cc1. Report an issue: GitHub.