{"record":{"id":"bb3852233b325b44","repo":"go-delve/delve","slug":"break-on-read-only-not-supported","errorCode":null,"errorMessage":"break on read only not supported","messagePattern":"break on read only not supported","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/proc/amd64util/debugregs.go","lineNumber":75,"sourceCode":"// SetBreakpoint sets hardware breakpoint at index 'idx' to the specified\n// address, read/write flags and size.\n// If the breakpoint is already in use but the parameters match it does\n// nothing.\nfunc (drs *DebugRegisters) SetBreakpoint(idx uint8, addr uint64, read, write bool, sz int) error {\n\tif int(idx) >= len(drs.pAddrs) {\n\t\treturn errors.New(\"hardware breakpoints exhausted\")\n\t}\n\tcuraddr, curread, curwrite, cursz := drs.breakpoint(idx)\n\tif curaddr != 0 {\n\t\tif (curaddr != addr) || (curread != read) || (curwrite != write) || (cursz != sz) {\n\t\t\treturn fmt.Errorf(\"hardware breakpoint %d already in use (address %#x)\", idx, curaddr)\n\t\t}\n\t\t// hardware breakpoint already set\n\t\treturn nil\n\t}\n\n\tif read && !write {\n\t\treturn errors.New(\"break on read only not supported\")\n\t}\n\n\t*(drs.pAddrs[idx]) = addr\n\tvar lenrw uint64\n\tif write {\n\t\tlenrw |= 0x1\n\t}\n\tif read {\n\t\tlenrw |= 0x2\n\t}\n\tswitch sz {\n\tcase 1:\n\t\t// already ok\n\tcase 2:\n\t\tlenrw |= 0x1 << 2\n\tcase 4:\n\t\tlenrw |= 0x3 << 2\n\tcase 8:","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/go-delve/delve/blob/a23773e6c31361e43246bc43a424ee009679b174/pkg/proc/amd64util/debugregs.go#L57-L93","documentation":"SetBreakpoint rejects watchpoints configured with read=true and write=false. The x86 debug register RW encoding supports execute, write-only, or read/write — a pure read-only watchpoint cannot be expressed, so Delve fails fast rather than silently widening the watchpoint to read/write.","triggerScenarios":"Calling SetBreakpoint(idx, addr, true /*read*/, false /*write*/, sz), e.g. asking for a data watchpoint that triggers only on memory reads.","commonSituations":"Users setting 'watch -r' style read-only watchpoints via the terminal or RPC and expecting x86 to support it; porting watchpoint code from debuggers whose backends emulate read-only watching.","solutions":["Request read+write (read=true, write=true) instead of read-only — x86 supports the combined mode","Use a write-only watchpoint if reads don't matter","Emulate read-only watching with software breakpoints on the code paths that read the variable","Reject read-only watchpoints in the client UI before sending them to the backend"],"exampleFix":"// before\nerr := drs.SetBreakpoint(0, addr, true, false, 8) // error\n// after\nerr := drs.SetBreakpoint(0, addr, true, true, 8) // read/write watchpoint, accepted","handlingStrategy":"validation","validationCode":"func validateWatchpoint(read, write bool) error {\n    if read && !write {\n        return errors.New(\"x86 supports execute, write, or read+write watchpoints only\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := drs.SetBreakpoint(idx, addr, read, write, sz); err != nil {\n    if strings.Contains(err.Error(), \"break on read only not supported\") {\n        // retry with read+write or surface unsupported-watchpoint to user\n    }\n}","preventionTips":["Never request read-only data watchpoints on x86 backends","Default watchpoint UIs to read/write when the user selects 'read'","Document the x86 DR7 RW-encoding limitation in client code"],"tags":["debugger","watchpoints","x86","hardware-limitation"],"backgroundTag":"read-only-watchpoint-unsupported","analyzedSha":"a23773e6c31361e43246bc43a424ee009679b174","analyzedAt":"2026-08-31T15:12:45.221Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}