{"record":{"id":"a9cda590082ed43f","repo":"go-delve/delve","slug":"could-not-get-registers","errorCode":null,"errorMessage":"could not get registers","messagePattern":"could not get registers","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/proc/native/registers_darwin_amd64.go","lineNumber":297,"sourceCode":"\tcase x86asm.R12:\n\t\treturn r.r12, nil\n\tcase x86asm.R13:\n\t\treturn r.r13, nil\n\tcase x86asm.R14:\n\t\treturn r.r14, nil\n\tcase x86asm.R15:\n\t\treturn r.r15, nil\n\t}\n\n\treturn 0, proc.ErrUnknownRegister\n}\n\nfunc registers(thread *nativeThread) (proc.Registers, error) {\n\tvar state C.x86_thread_state64_t\n\tvar identity C.thread_identifier_info_data_t\n\tkret := C.get_registers(C.mach_port_name_t(thread.os.threadAct), &state)\n\tif kret != C.KERN_SUCCESS {\n\t\treturn nil, fmt.Errorf(\"could not get registers\")\n\t}\n\tkret = C.get_identity(C.mach_port_name_t(thread.os.threadAct), &identity)\n\tif kret != C.KERN_SUCCESS {\n\t\treturn nil, fmt.Errorf(\"could not get thread identity information\")\n\t}\n\t/*\n\t\tthread_identifier_info::thread_handle contains the base of the\n\t\tthread-specific data area, which on x86 and x86_64 is the thread’s base\n\t\taddress of the %gs segment. 10.9.2 xnu-2422.90.20/osfmk/kern/thread.c\n\t\tthread_info_internal() gets the value from\n\t\tmachine_thread::cthread_self, which is the same value used to set the\n\t\t%gs base in xnu-2422.90.20/osfmk/i386/pcb_native.c\n\t\tact_machine_switch_pcb().\n\t\t--\n\t\tcomment copied from chromium's crashpad\n\t\thttps://chromium.googlesource.com/crashpad/crashpad/+/master/snapshot/mac/process_reader.cc\n\t*/\n\tregs := &Regs{","sourceCodeStart":279,"sourceCodeEnd":315,"githubUrl":"https://github.com/go-delve/delve/blob/a23773e6c31361e43246bc43a424ee009679b174/pkg/proc/native/registers_darwin_amd64.go#L279-L315","documentation":"registers() on darwin/amd64 reads GPRs with the Mach call get_registers(thread_act, x86_thread_state64_t). Any kern_return other than KERN_SUCCESS produces the opaque 'could not get registers' error. Typically the thread act is no longer valid or the task port lost rights.","triggerScenarios":"Listing/reading registers for a thread that terminated between thread enumeration and the Mach call, after the target execed (stale acts), or when task-for-pid/thread privileges were denied by macOS hardening.","commonSituations":"Debuggee exit racing a 'goroutines'/'registers' command; attaching to protected processes under SIP/hardened runtime; stale thread cache after fork/exec.","solutions":["Refresh the thread list and skip/evict threads whose act is invalid (KERN_TERMINATED)","Ensure delve can access the task port (same user/root, and not blocked by SIP/hardened runtime restrictions)","Re-attach to the process if its task port rights were revoked (e.g. after exec)","Surface the kern_return value in the error to distinguish thread-dead from permission problems"],"exampleFix":"// before\nkret := C.get_registers(C.mach_port_name_t(thread.os.threadAct), &state)\nif kret != C.KERN_SUCCESS {\n\treturn nil, fmt.Errorf(\"could not get registers\")\n}\n// after\nkret := C.get_registers(C.mach_port_name_t(thread.os.threadAct), &state)\nif kret != C.KERN_SUCCESS {\n\treturn nil, fmt.Errorf(\"could not get registers for thread %d: kern_return=%d\", thread.ID, kret)\n}","handlingStrategy":"retry","validationCode":"// before reading registers on darwin\nif !isThreadAlive(dbp, thread.ID) {\n\treturn nil, fmt.Errorf(\"thread %d no longer valid\", thread.ID)\n}","typeGuard":"func isGetRegsErr(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), \"could not get registers\")\n}","tryCatchPattern":"regs, err := registers(thread)\nif isGetRegsErr(err) {\n\t// refresh thread list once, then retry\n\tdbp.refreshThreads()\n\tregs, err = registers(thread)\n}\nreturn regs, err","preventionTips":["Evict threads whose Mach act returns KERN_TERMINATED and refresh the thread cache","Handle exec/fork by re-attaching instead of reusing old thread acts","Verify macOS permissions (SIP, task-for-pid) when failures are consistent rather than transient"],"tags":["darwin","mach","registers","thread-exited","permissions"],"backgroundTag":"mach-register-read-failed","analyzedSha":"a23773e6c31361e43246bc43a424ee009679b174","analyzedAt":"2026-08-31T15:12:45.221Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}