{"record":{"id":"896c34a4eb24c138","repo":"go-delve/delve","slug":"could-not-set-pc","errorCode":null,"errorMessage":"could not set pc","messagePattern":"could not set pc","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/proc/native/registers_darwin_amd64.go","lineNumber":122,"sourceCode":"\treturn 0\n}\n\n// TLS returns the value of the register\n// that contains the location of the thread\n// local storage segment.\nfunc (r *Regs) TLS() uint64 {\n\treturn r.gsBase\n}\n\nfunc (r *Regs) GAddr() (uint64, bool) {\n\treturn 0, false\n}\n\n// SetPC sets the RIP register to the value specified by `pc`.\nfunc (thread *nativeThread) setPC(pc uint64) error {\n\tkret := C.set_pc(thread.os.threadAct, C.uint64_t(pc))\n\tif kret != C.KERN_SUCCESS {\n\t\treturn fmt.Errorf(\"could not set pc\")\n\t}\n\treturn nil\n}\n\n// SetReg changes the value of the specified register.\nfunc (thread *nativeThread) SetReg(regNum uint64, reg *op.DwarfRegister) error {\n\tif regNum != regnum.AMD64_Rip {\n\t\treturn fmt.Errorf(\"changing register %d not implemented\", regNum)\n\t}\n\treturn thread.setPC(reg.Uint64Val)\n}\n\nfunc (r *Regs) Get(n int) (uint64, error) {\n\treg := x86asm.Reg(n)\n\tconst (\n\t\tmask8  = 0x000f\n\t\tmask16 = 0x00ff\n\t\tmask32 = 0xffff","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/go-delve/delve/blob/a23773e6c31361e43246bc43a424ee009679b174/pkg/proc/native/registers_darwin_amd64.go#L104-L140","documentation":"On darwin/amd64, nativeThread.setPC calls the Mach wrapper set_pc on the thread act; any kern_return other than KERN_SUCCESS is collapsed into the opaque message 'could not set pc'. The kernel refused to change the instruction pointer of the thread.","triggerScenarios":"Setting a new PC during step/restart (e.g. after a breakpoint hit, 'continue' from a breakpoint skipping, or reverse-step machinery) when the thread act is invalid — the thread/process terminated — or Mach privileges were lost.","commonSituations":"Race where the debuggee exits while delve is relocating the PC off a breakpoint; macOS hardening (SIP/hardened runtime) interfering with task-for-pid; stale thread act after exec.","solutions":["Check the process is still alive before attempting setPC; treat thread-death races as expected failures","Re-attach if task/port rights were invalidated (e.g. after the target execed)","Run delve with proper entitlements/permissions on macOS (SIP constraints, developer mode)","Log the kern_return code from set_pc to distinguish KERN_INVALID_ARGUMENT vs KERN_TERMINATED for accurate handling"],"exampleFix":"// before\nkret := C.set_pc(thread.os.threadAct, C.uint64_t(pc))\nif kret != C.KERN_SUCCESS {\n\treturn fmt.Errorf(\"could not set pc\")\n}\n// after\nkret := C.set_pc(thread.os.threadAct, C.uint64_t(pc))\nif kret != C.KERN_SUCCESS {\n\treturn fmt.Errorf(\"could not set pc to 0x%x: kern_return=%d\", pc, kret)\n}","handlingStrategy":"try-catch","validationCode":"// before setPC on darwin\nif !procAlive(dbp) || !isThreadAlive(dbp, thread.ID) {\n\treturn fmt.Errorf(\"thread gone; cannot set pc\")\n}","typeGuard":"func isSetPCErr(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), \"could not set pc\")\n}","tryCatchPattern":"err := thread.setPC(pc)\nif isSetPCErr(err) {\n\t// likely thread/process died mid-step; re-sync debugger state\n\tdbp.reattachOrDrop()\n\treturn err\n}","preventionTips":["Check process liveness before PC relocation after breakpoint hits","Expect exit races during step/restart and handle them as non-fatal","Run with macOS developer mode / proper entitlements to avoid Mach permission failures","Log kern_return values to diagnose Mach failures"],"tags":["darwin","mach","registers","setpc","thread-exited"],"backgroundTag":"mach-register-write-failed","analyzedSha":"a23773e6c31361e43246bc43a424ee009679b174","analyzedAt":"2026-08-31T15:12:45.221Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}