@@ -90,11 +90,31 @@ if [[ "${DEBUG_DELVE}" == 1 ]]; then
9090 # binary, so we can just build the debug binary here without having to worry
9191 # about/use the makefile.
9292 ./scripts/build_go.sh " ${build_flags[@]} "
93- # Use go run to ensure Delve is built with current Go version.
9493 # Go 1.25+ uses DWARFv5 which requires Delve built with Go 1.25+.
9594 # GOTOOLCHAIN is set to force building Delve with the current Go version.
95+ # We use go install (not go run) so $dlv_pid is the actual dlv process.
96+ # Using go run is an intermediary that orphans dlv.
9697 current_toolchain=" go$( go env GOVERSION | sed ' s/^go//' ) "
97- runcmd=(env " GOTOOLCHAIN=${current_toolchain} " go run github.com/go-delve/delve/cmd/dlv@latest exec --headless --continue --listen 127.0.0.1:12345 --accept-multiclient " $CODER_DELVE_DEBUG_BIN " --)
98+ GOBIN=" ${PROJECT_ROOT} /build/.bin" GOTOOLCHAIN=" ${current_toolchain} " go install github.com/go-delve/delve/cmd/dlv@latest
99+ dlv_bin=" build/.bin/dlv"
100+ # The dlv exec mode does not allow the coder binary to shut down
101+ # gracefully but attach mode does. So we run the coder binary
102+ # directly, then attach dlv. The trap forwards signals to the
103+ # debuggee. For proper signal propagation to work, we have to
104+ # capture them here and can't exec either program.
105+ " ${runcmd[@]} " --global-config " ${CODER_DEV_DIR} " " $@ " &
106+ debuggee_pid=$!
107+ " $dlv_bin " attach $debuggee_pid --headless --continue --listen 127.0.0.1:12345 --accept-multiclient &
108+ dlv_pid=$!
109+ trap ' kill -INT $dlv_pid 2>/dev/null; wait $dlv_pid 2>/dev/null; kill -INT $debuggee_pid 2>/dev/null' INT TERM HUP
110+ # First wait is interrupted when the trap fires, second
111+ # wait blocks until the debuggee finishes shutting down.
112+ wait $debuggee_pid
113+ wait $debuggee_pid
114+ ret=$?
115+ kill -INT $dlv_pid 2> /dev/null
116+ wait $dlv_pid 2> /dev/null
117+ exit $ret
98118fi
99119
100120exec " ${runcmd[@]} " --global-config " ${CODER_DEV_DIR} " " $@ "
0 commit comments