go-delve/delve · error

changing register %d not implemented

Error message

changing register %d not implemented

What it means

The riscv64 SetReg implementation covers integer registers and the F0-F31 floating-point registers; any other register number hits the default branch and is rejected as not implemented.

Source

Thrown at pkg/proc/linutil/regs_riscv64_arch.go:356

	}

	switch {
	case regNum >= regnum.RISCV64_F0 && regNum <= regnum.RISCV64_F31:
		if r.loadFpRegs != nil {
			err := r.loadFpRegs(r)
			r.loadFpRegs = nil
			if err != nil {
				return false, err
			}
		}

		i := regNum - regnum.RISCV64_F0
		reg.FillBytes()
		copy(r.Fpregset[8*i:], reg.Bytes)
		return true, nil

	default:
		return false, fmt.Errorf("changing register %d not implemented", regNum)
	}
}

// RISCV64PtraceFpRegs is refer to the definition of struct __riscv_d_ext_state in the kernel ptrace.h
type RISCV64PtraceFpRegs struct {
	Fregs []byte
	Fcsr  uint32
}

const _RISCV64_FPREGSET_LENGTH = (32 * 8)

func (fpregs *RISCV64PtraceFpRegs) Decode() (regs []proc.Register) {
	for i := 0; i < len(fpregs.Fregs); i += 8 {
		name := fmt.Sprintf("F%d", (i / 8))
		value := fpregs.Fregs[i : i+8]
		regs = proc.AppendBytesRegister(regs, name, value)
	}

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Only write GPRs and F0-F31 via SetReg on riscv64
  2. Handle FCSR writes through the native backend's ptrace register sets if needed
  3. Check regnum ranges in the caller before invoking SetReg

Example fix

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

Strategy: validation

Validate before calling

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

Type guard

func isSettableRISCV64(regNum uint64) bool {
    return isGPR(regNum) || (regNum >= regnum.RISCV64_F0 && regNum <= regnum.RISCV64_F0+31)
}

Try / catch

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

Prevention

When it happens

Trigger: Calling SetReg on Linux/riscv64 with a register number outside the implemented GPR set and outside RISCV64_F0..F0+31 (e.g. FCSR, CSR registers).

Common situations: Attempting to write riscv64 control/status registers via the debugger; register constants from another ISA leaking into the riscv64 path.

Related errors


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