diff --git a/Documentation/usage/dlv_dap.md b/Documentation/usage/dlv_dap.md index fafb1e7d..e0d3a3c4 100644 --- a/Documentation/usage/dlv_dap.md +++ b/Documentation/usage/dlv_dap.md @@ -33,7 +33,7 @@ dlv dap [flags] ### Options ``` - --client-addr string host:port where the DAP client is waiting for the DAP server to dial in + --client-addr string Address where the DAP client is waiting for the DAP server to dial in. Prefix with 'unix:' to use a unix domain socket. -h, --help help for dap ``` diff --git a/cmd/dlv/cmds/commands.go b/cmd/dlv/cmds/commands.go index 95b294f0..8a3d0313 100644 --- a/cmd/dlv/cmds/commands.go +++ b/cmd/dlv/cmds/commands.go @@ -244,7 +244,7 @@ will exit when the debug session ends.`, Run: dapCmd, ValidArgsFunction: cobra.NoFileCompletions, } - dapCommand.Flags().StringVar(&dapClientAddr, "client-addr", "", "host:port where the DAP client is waiting for the DAP server to dial in") + dapCommand.Flags().StringVar(&dapClientAddr, "client-addr", "", "Address where the DAP client is waiting for the DAP server to dial in. Prefix with 'unix:' to use a unix domain socket.") must(dapCommand.RegisterFlagCompletionFunc("client-addr", cobra.NoFileCompletions)) // TODO(polina): support --tty when dlv dap allows to launch a program from command-line @@ -463,7 +463,8 @@ Some backends can be configured using environment variables: * DELVE_DEBUGSERVER_PATH specifies the path of the debugserver executable for the lldb backend * DELVE_RR_RECORD_FLAGS specifies additional flags used when calling 'rr record' * DELVE_RR_REPLAY_FLAGS specifies additional flags used when calling 'rr replay' -`}) +`, + }) rootCommand.AddCommand(&cobra.Command{ Use: "log", @@ -581,12 +582,7 @@ func dapCmd(cmd *cobra.Command, args []string) { } cfg.Listener = listener } else { // with a predetermined client. - var err error - conn, err = net.Dial("tcp", dapClientAddr) - if err != nil { - fmt.Fprintf(os.Stderr, "Failed to connect to the DAP client: %v\n", err) - return 1 - } + conn = netDial(dapClientAddr) } server := dap.NewServer(cfg) diff --git a/cmd/dlv/dlv_test.go b/cmd/dlv/dlv_test.go index c9fd2641..c3371de3 100644 --- a/cmd/dlv/dlv_test.go +++ b/cmd/dlv/dlv_test.go @@ -922,6 +922,53 @@ func TestDAPCmdWithClient(t *testing.T) { } } +// TestDAPCmdWithUnixClient tests dlv dap --client-addr can be started with unix domain socket and shut down. +func TestDAPCmdWithUnixClient(t *testing.T) { + tmpdir := os.TempDir() + if tmpdir == "" { + return + } + + listenPath := filepath.Join(tmpdir, "dap_test") + listener, err := net.Listen("unix", listenPath) + if err != nil { + t.Fatalf("cannot setup listener required for testing: %v", err) + } + defer listener.Close() + + dlvbin := getDlvBin(t) + + cmd := exec.Command(dlvbin, "dap", "--log-output=dap", "--log", "--client-addr=unix:"+listener.Addr().String()) + buf := &bytes.Buffer{} + cmd.Stdin = buf + cmd.Stdout = buf + assertNoError(cmd.Start(), t, "start dlv dap process with --client-addr flag") + + // Wait for the connection. + conn, err := listener.Accept() + if err != nil { + cmd.Process.Kill() // release the socket file + t.Fatalf("Failed to get connection: %v", err) + } + t.Log("dlv dap process dialed in successfully") + + client := daptest.NewClientFromConn(conn) + client.InitializeRequest() + client.ExpectInitializeResponse(t) + + // Close the connection. + if err := conn.Close(); err != nil { + cmd.Process.Kill() + t.Fatalf("Failed to get connection: %v", err) + } + + // Connection close should trigger dlv-reverse command's normal exit. + if err := cmd.Wait(); err != nil { + cmd.Process.Kill() + t.Fatalf("command failed: %v\n%s\n%v", err, buf.Bytes(), cmd.Process.Pid) + } +} + func TestTrace(t *testing.T) { dlvbin := getDlvBin(t)