fix(debug): target the traced thread and keep the kill from ever blocking

The Go runtime can migrate the debuggee's target-mode goroutine off the
process leader before PTRACE_TRACEME, which left the trace relation on a
thread the session never addressed: its stops starved the waits on the
leader, and a kill sequence that resumed nothing and then blocked in
Wait4 hung the whole package.  The debuggee now reports the traced thread
in the launch handshake and parks with a thread-directed stop, every
ptrace request and wait addresses that thread, a SIGURG arriving on a
single-step resumes it as a single-step again instead of letting the
tracee run uncontrolled, a resume rejected with ESRCH lifts a group-stop
with SIGCONT and retries once, and Kill resumes, kills and reaps through
non-blocking waits so it returns for a tracee in any state.

Assisted-by: GLM 5.3
This commit is contained in:
petrbalvin committed 2026-10-07 13:46:18 +02:00
1 parent 409c8b348d
commit b5d6f1b46a
14 files changed
+265 -80

No files matched your search

+5 -2
View File
@@ -99,11 +99,14 @@ func runTarget(asmPath, funcName, argsFile, tmpDir string) error {
if _, _, errno := syscall.Syscall(syscall.SYS_PTRACE, uintptr(syscall.PTRACE_TRACEME), 0, 0); errno != 0 {
return fmt.Errorf("debug target: PTRACE_TRACEME: %v", errno)
}
// The tracer must address the thread that called PTRACE_TRACEME, which
// is not necessarily the process leader: report it before readiness.
os.WriteFile(tmpDir+"/tracetid", []byte(fmt.Sprintf("%d", syscall.Gettid())), 0o644)
os.WriteFile(tmpDir+"/ready", []byte("ok"), 0o644)
syscall.Kill(syscall.Getpid(), syscall.SIGSTOP)
parkSelf()
os.WriteFile(tmpDir+"/entry", []byte("ok"), 0o644)
syscall.Kill(syscall.Getpid(), syscall.SIGSTOP)
parkSelf()
fnAddr := codeBase + uintptr(fl.Offset)
stackArgs := make([]byte, fl.Args)