go-delve/delve · warning

can not write registers

Error message

can not write registers

What it means

After bounds checking, compositeMemory.WriteMemory inspects its pieces; if any piece is a register piece (op.RegPiece) and mem.regs.ChangeFunc is nil, there is no mechanism to write values back into CPU registers, so it returns 'can not write registers'. This protects against silently writing only the cached slice while the live value stays in a register.

Source

Thrown at pkg/proc/mem.go:195

func (mem *compositeMemory) ReadMemory(data []byte, addr uint64) (int, error) {
	addr -= mem.base
	if addr >= uint64(len(mem.data)) || addr+uint64(len(data)) > uint64(len(mem.data)) {
		return 0, errors.New("read out of bounds")
	}
	copy(data, mem.data[addr:addr+uint64(len(data))])
	return len(data), nil
}

func (mem *compositeMemory) WriteMemory(addr uint64, data []byte) (int, error) {
	addr -= mem.base
	if addr >= uint64(len(mem.data)) || addr+uint64(len(data)) > uint64(len(mem.data)) {
		return 0, errors.New("write out of bounds")
	}
	if mem.regs.ChangeFunc == nil {
		for _, piece := range mem.pieces {
			if piece.Kind == op.RegPiece {
				return 0, errors.New("can not write registers")
			}
		}
	}

	copy(mem.data[addr:], data)

	curAddr := uint64(0)
	donesz := 0
	for _, piece := range mem.pieces {
		if curAddr < (addr+uint64(len(data))) && addr < (curAddr+uint64(piece.Size)) {
			// changed memory interval overlaps current piece
			pieceMem := mem.data[curAddr : curAddr+uint64(piece.Size)]

			switch piece.Kind {
			case op.RegPiece:
				oldReg := mem.regs.Reg(piece.Val)
				newReg := op.DwarfRegisterFromBytes(pieceMem)
				err := mem.regs.ChangeFunc(piece.Val, oldReg.Overwrite(newReg))

View on GitHub (pinned to a23773e6c3)

Solutions

  1. Rebuild the target with -gcflags="all=-N -l" so the variable spills to a stack slot, then set it
  2. Set a different, memory-located variable or restructure code (copy the value to a stack variable) for debugging
  3. Avoid variable writes in core-dump sessions; instead, edit code or use live debugging with a backend supporting register writes

Example fix

// before
$ go build main.go   # i kept in a register
(dlv) set i = 10     // can not write registers
// after
$ go build -gcflags="all=-N -l" main.go
(dlv) set i = 10
Defensive patterns

Strategy: fallback

Validate before calling

// Detect register-backed variables before writing:
//   (dlv) print &i
// If the address is not a normal stack address (or the build is optimized
// or you are in a core dump), the write will hit registers and fail.

Try / catch

err := setVariable("i", "10")
if err != nil && strings.Contains(err.Error(), "can not write registers") {
    log.Printf("variable held in registers; rebuild with -gcflags='all=-N -l' to set it")
    return fallbackSkipWrite()
}

Prevention

When it happens

Trigger: Assigning to a variable whose value is (partially) held in CPU registers via compositeMemory when the register set has no ChangeFunc — e.g. the 'set' command on an argument or local variable kept in a register, common in optimized code and on architectures/backends without register-write support (e.g. core dump targets).

Common situations: Setting variables in optimized binaries where parameters are register-allocated; attempting writes while debugging a core dump (registers are read-only); backends lacking register modification support.

Related errors


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