{"record":{"id":"de19e0a907b40a35","repo":"go-delve/delve","slug":"could-not-restore-pc-v","errorCode":null,"errorMessage":"could not restore PC: %v","messagePattern":"could not restore PC: (.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/proc/fncall.go","lineNumber":866,"sourceCode":"\t\tif err != nil {\n\t\t\tfncall.err = fmt.Errorf(\"could not get precheck error reason: %v\", err)\n\t\t\tbreak\n\t\t}\n\t\terrvar.Name = \"err\"\n\t\tfncall.err = fmt.Errorf(\"%v\", constant.StringVal(errvar.Value))\n\n\tcase debugCallRegCompleteCall: // 0\n\t\tp.fncallForG[callScope.g.ID].startThreadID = 0\n\n\tcase debugCallRegRestoreRegisters: // 16\n\t\t// runtime requests that we restore the registers (all except pc and sp),\n\t\t// this is also the last step of the function call protocol.\n\t\tpc, sp := regs.PC(), regs.SP()\n\t\tif err := thread.RestoreRegisters(fncall.savedRegs); err != nil {\n\t\t\tfncall.err = fmt.Errorf(\"could not restore registers: %v\", err)\n\t\t}\n\t\tif err := setPC(thread, pc); err != nil {\n\t\t\tfncall.err = fmt.Errorf(\"could not restore PC: %v\", err)\n\t\t}\n\t\tif err := setSP(thread, sp); err != nil {\n\t\t\tfncall.err = fmt.Errorf(\"could not restore SP: %v\", err)\n\t\t}\n\t\tfncallLog(\"stepping thread %d\", thread.ThreadID())\n\t\tif err := stepInstructionOut(callScope.callCtx.grp, p, thread, fncall.debugCallName, fncall.debugCallName); err != nil {\n\t\t\tfncall.err = fmt.Errorf(\"could not step out of %s: %v\", fncall.debugCallName, err)\n\t\t}\n\t\tif bi.Arch.Name == \"amd64\" {\n\t\t\t// The tail of debugCallV2 corrupts the state of RFLAGS, we must restore\n\t\t\t// it one extra time after stepping out of it.\n\t\t\t// See https://github.com/go-delve/delve/issues/2985 and\n\t\t\t// TestCallInjectionFlagCorruption\n\t\t\trflags := bi.Arch.RegistersToDwarfRegisters(0, fncall.savedRegs).Uint64Val(regnum.AMD64_Rflags)\n\t\t\terr := thread.SetReg(regnum.AMD64_Rflags, op.DwarfRegisterFromUint64(rflags))\n\t\t\tif err != nil {\n\t\t\t\tfncall.err = fmt.Errorf(\"could not restore RFLAGS register: %v\", err)\n\t\t\t}","sourceCodeStart":848,"sourceCodeEnd":884,"githubUrl":"https://github.com/go-delve/delve/blob/a23773e6c31361e43246bc43a424ee009679b174/pkg/proc/fncall.go#L848-L884","documentation":"After restoring registers, Delve must also restore the saved program counter so execution continues where the injected call left off. This error occurs when setPC fails on the thread, indicating the instruction pointer could not be written back.","triggerScenarios":"funcCallStep in debugCallRegRestoreRegisters calls setPC(thread, pc) and the underlying SetPC/SetReg write fails (dead thread, ptrace error, invalid PC value).","commonSituations":"Target process terminated during the call; hardware/architecture restrictions on writing PC; gdbserial target that disconnected.","solutions":["Verify the debuggee is alive; restart the session if it died","Retry the call injection after re-attaching","Use a native backend session if the failure is backend-specific","Report a bug with backend, OS and architecture if it reproduces consistently"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Confirm the thread is live before call injection:\n// state, err := p.ProcessState(); ensure thread ID still exists in p.ThreadList()","typeGuard":null,"tryCatchPattern":"err := dbg.CallFunction(scope, fn, args)\nif err != nil && strings.Contains(err.Error(), \"could not restore PC\") {\n\t// restart session; PC could not be written back\n}\n","preventionTips":["Verify the target stays alive during injected calls","Re-attach after any backend communication error","Prefer native backend for reliable register writes","Restart the session on PC-restore failure instead of continuing"],"tags":["go","fncall","registers","pc"],"backgroundTag":"register-restore-failed","analyzedSha":"a23773e6c31361e43246bc43a424ee009679b174","analyzedAt":"2026-08-31T15:12:45.221Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}