mirror of
				https://github.com/go-delve/delve.git
				synced 2025-10-31 18:57:18 +08:00 
			
		
		
		
	service/dap: clarify handling of relative program path (#2653)
* service/dap: add test verifying handling of relative program path * Add exec test, log build dir and document in --help Co-authored-by: Polina Sokolova <polinasok@users.noreply.github.com>
This commit is contained in:
		| @ -7,13 +7,15 @@ | |||||||
| [EXPERIMENTAL] Starts a headless TCP server communicating via Debug Adaptor Protocol (DAP). | [EXPERIMENTAL] Starts a headless TCP server communicating via Debug Adaptor Protocol (DAP). | ||||||
|  |  | ||||||
| The server is always headless and requires a DAP client like vscode to connect and request a binary | The server is always headless and requires a DAP client like vscode to connect and request a binary | ||||||
| to be launched or process to be attached to. The following modes are supported: | to be launched or process to be attached to. The following modes can be specified via client's launch config: | ||||||
| - launch + exec (executes precompiled binary, like 'dlv exec') | - launch + exec (executes precompiled binary, like 'dlv exec') | ||||||
| - launch + debug (builds and launches, like 'dlv debug') | - launch + debug (builds and launches, like 'dlv debug') | ||||||
| - launch + test (builds and tests, like 'dlv test') | - launch + test (builds and tests, like 'dlv test') | ||||||
| - launch + replay (replays an rr trace, like 'dlv replay') | - launch + replay (replays an rr trace, like 'dlv replay') | ||||||
| - launch + core (replays a core dump file, like 'dlv core') | - launch + core (replays a core dump file, like 'dlv core') | ||||||
| - attach + local (attaches to a running process, like 'dlv attach') | - attach + local (attaches to a running process, like 'dlv attach') | ||||||
|  | Program and output binary paths will be interpreted relative to dlv's working directory. | ||||||
|  |  | ||||||
| The server does not yet accept multiple client connections (--accept-multiclient). | The server does not yet accept multiple client connections (--accept-multiclient). | ||||||
| While --continue is not supported, stopOnEntry launch/attach attribute can be used to control if | While --continue is not supported, stopOnEntry launch/attach attribute can be used to control if | ||||||
| execution is resumed at the start of the debug session. | execution is resumed at the start of the debug session. | ||||||
|  | |||||||
| @ -180,13 +180,15 @@ option to let the process continue or kill it. | |||||||
| 		Long: `[EXPERIMENTAL] Starts a headless TCP server communicating via Debug Adaptor Protocol (DAP). | 		Long: `[EXPERIMENTAL] Starts a headless TCP server communicating via Debug Adaptor Protocol (DAP). | ||||||
|  |  | ||||||
| The server is always headless and requires a DAP client like vscode to connect and request a binary | The server is always headless and requires a DAP client like vscode to connect and request a binary | ||||||
| to be launched or process to be attached to. The following modes are supported: | to be launched or process to be attached to. The following modes can be specified via client's launch config: | ||||||
| - launch + exec (executes precompiled binary, like 'dlv exec') | - launch + exec (executes precompiled binary, like 'dlv exec') | ||||||
| - launch + debug (builds and launches, like 'dlv debug') | - launch + debug (builds and launches, like 'dlv debug') | ||||||
| - launch + test (builds and tests, like 'dlv test') | - launch + test (builds and tests, like 'dlv test') | ||||||
| - launch + replay (replays an rr trace, like 'dlv replay') | - launch + replay (replays an rr trace, like 'dlv replay') | ||||||
| - launch + core (replays a core dump file, like 'dlv core') | - launch + core (replays a core dump file, like 'dlv core') | ||||||
| - attach + local (attaches to a running process, like 'dlv attach') | - attach + local (attaches to a running process, like 'dlv attach') | ||||||
|  | Program and output binary paths will be interpreted relative to dlv's working directory. | ||||||
|  |  | ||||||
| The server does not yet accept multiple client connections (--accept-multiclient). | The server does not yet accept multiple client connections (--accept-multiclient). | ||||||
| While --continue is not supported, stopOnEntry launch/attach attribute can be used to control if | While --continue is not supported, stopOnEntry launch/attach attribute can be used to control if | ||||||
| execution is resumed at the start of the debug session.`, | execution is resumed at the start of the debug session.`, | ||||||
|  | |||||||
| @ -864,8 +864,8 @@ func (s *Server) onLaunchRequest(request *dap.LaunchRequest) { | |||||||
|  |  | ||||||
| 		var cmd string | 		var cmd string | ||||||
| 		var out []byte | 		var out []byte | ||||||
| 		// Log debug binary build | 		wd, _ := os.Getwd() | ||||||
| 		s.log.Debugf("building binary '%s' from '%s' with flags '%v'", debugbinary, program, buildFlags) | 		s.log.Debugf("building program '%s' in '%s' with flags '%v'", program, wd, buildFlags) | ||||||
| 		switch mode { | 		switch mode { | ||||||
| 		case "debug": | 		case "debug": | ||||||
| 			cmd, out, err = gobuild.GoBuildCombinedOutput(debugbinary, []string{program}, buildFlags) | 			cmd, out, err = gobuild.GoBuildCombinedOutput(debugbinary, []string{program}, buildFlags) | ||||||
| @ -936,7 +936,7 @@ func (s *Server) onLaunchRequest(request *dap.LaunchRequest) { | |||||||
| 		s.config.Debugger.WorkingDir = wdParsed | 		s.config.Debugger.WorkingDir = wdParsed | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	s.log.Debugf("running program in %s\n", s.config.Debugger.WorkingDir) | 	s.log.Debugf("running binary '%s' in '%s'", program, s.config.Debugger.WorkingDir) | ||||||
| 	if noDebug, ok := request.Arguments["noDebug"].(bool); ok && noDebug { | 	if noDebug, ok := request.Arguments["noDebug"].(bool); ok && noDebug { | ||||||
| 		s.mu.Lock() | 		s.mu.Lock() | ||||||
| 		cmd, err := s.newNoDebugProcess(program, targetArgs, s.config.Debugger.WorkingDir) | 		cmd, err := s.newNoDebugProcess(program, targetArgs, s.config.Debugger.WorkingDir) | ||||||
|  | |||||||
| @ -3978,8 +3978,9 @@ type onBreakpoint struct { | |||||||
| //                     so the test author has full control of its arguments. | //                     so the test author has full control of its arguments. | ||||||
| //                     Note that he rest of the test sequence assumes that | //                     Note that he rest of the test sequence assumes that | ||||||
| //                     stopOnEntry is false. | //                     stopOnEntry is false. | ||||||
|  | //     source        - source file path, needed to set breakpoints, "" if none to be set. | ||||||
| //     breakpoints   - list of lines, where breakpoints are to be set | //     breakpoints   - list of lines, where breakpoints are to be set | ||||||
| //     onBreakpoints - list of test sequences to execute at each of the set breakpoints. | //     onBPs         - list of test sequences to execute at each of the set breakpoints. | ||||||
| func runDebugSessionWithBPs(t *testing.T, client *daptest.Client, cmd string, cmdRequest func(), source string, breakpoints []int, onBPs []onBreakpoint) { | func runDebugSessionWithBPs(t *testing.T, client *daptest.Client, cmd string, cmdRequest func(), source string, breakpoints []int, onBPs []onBreakpoint) { | ||||||
| 	client.InitializeRequest() | 	client.InitializeRequest() | ||||||
| 	client.ExpectInitializeResponseAndCapabilities(t) | 	client.ExpectInitializeResponseAndCapabilities(t) | ||||||
| @ -3994,8 +3995,10 @@ func runDebugSessionWithBPs(t *testing.T, client *daptest.Client, cmd string, cm | |||||||
| 		panic("expected launch or attach command") | 		panic("expected launch or attach command") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	if source != "" { | ||||||
| 		client.SetBreakpointsRequest(source, breakpoints) | 		client.SetBreakpointsRequest(source, breakpoints) | ||||||
| 		client.ExpectSetBreakpointsResponse(t) | 		client.ExpectSetBreakpointsResponse(t) | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	// Skip no-op setExceptionBreakpoints | 	// Skip no-op setExceptionBreakpoints | ||||||
|  |  | ||||||
| @ -4045,8 +4048,8 @@ func runDebugSessionWithBPs(t *testing.T, client *daptest.Client, cmd string, cm | |||||||
| // runDebugSession is a helper for executing the standard init and shutdown | // runDebugSession is a helper for executing the standard init and shutdown | ||||||
| // sequences for a program that does not stop on entry | // sequences for a program that does not stop on entry | ||||||
| // while specifying unique launch criteria via parameters. | // while specifying unique launch criteria via parameters. | ||||||
| func runDebugSession(t *testing.T, client *daptest.Client, cmd string, cmdRequest func(), source string) { | func runDebugSession(t *testing.T, client *daptest.Client, cmd string, cmdRequest func()) { | ||||||
| 	runDebugSessionWithBPs(t, client, cmd, cmdRequest, source, nil, nil) | 	runDebugSessionWithBPs(t, client, cmd, cmdRequest, "", nil, nil) | ||||||
| } | } | ||||||
|  |  | ||||||
| func TestLaunchDebugRequest(t *testing.T) { | func TestLaunchDebugRequest(t *testing.T) { | ||||||
| @ -4061,7 +4064,7 @@ func TestLaunchDebugRequest(t *testing.T) { | |||||||
| 		runDebugSession(t, client, "launch", func() { | 		runDebugSession(t, client, "launch", func() { | ||||||
| 			client.LaunchRequestWithArgs(map[string]interface{}{ | 			client.LaunchRequestWithArgs(map[string]interface{}{ | ||||||
| 				"mode": "debug", "program": fixture.Source, "output": tmpBin}) | 				"mode": "debug", "program": fixture.Source, "output": tmpBin}) | ||||||
| 		}, fixture.Source) | 		}) | ||||||
| 	}) | 	}) | ||||||
| 	// Wait for the test to finish to capture all stderr | 	// Wait for the test to finish to capture all stderr | ||||||
| 	time.Sleep(100 * time.Millisecond) | 	time.Sleep(100 * time.Millisecond) | ||||||
| @ -4098,13 +4101,13 @@ func TestLaunchRequestDefaults(t *testing.T) { | |||||||
| 		runDebugSession(t, client, "launch", func() { | 		runDebugSession(t, client, "launch", func() { | ||||||
| 			client.LaunchRequestWithArgs(map[string]interface{}{ | 			client.LaunchRequestWithArgs(map[string]interface{}{ | ||||||
| 				"mode": "" /*"debug" by default*/, "program": fixture.Source, "output": "__mybin"}) | 				"mode": "" /*"debug" by default*/, "program": fixture.Source, "output": "__mybin"}) | ||||||
| 		}, fixture.Source) | 		}) | ||||||
| 	}) | 	}) | ||||||
| 	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) { | 	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) { | ||||||
| 		runDebugSession(t, client, "launch", func() { | 		runDebugSession(t, client, "launch", func() { | ||||||
| 			client.LaunchRequestWithArgs(map[string]interface{}{ | 			client.LaunchRequestWithArgs(map[string]interface{}{ | ||||||
| 				/*"mode":"debug" by default*/ "program": fixture.Source, "output": "__mybin"}) | 				/*"mode":"debug" by default*/ "program": fixture.Source, "output": "__mybin"}) | ||||||
| 		}, fixture.Source) | 		}) | ||||||
| 	}) | 	}) | ||||||
| 	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) { | 	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) { | ||||||
| 		runDebugSession(t, client, "launch", func() { | 		runDebugSession(t, client, "launch", func() { | ||||||
| @ -4112,7 +4115,7 @@ func TestLaunchRequestDefaults(t *testing.T) { | |||||||
| 			client.LaunchRequestWithArgs(map[string]interface{}{ | 			client.LaunchRequestWithArgs(map[string]interface{}{ | ||||||
| 				"mode": "debug", "program": fixture.Source}) | 				"mode": "debug", "program": fixture.Source}) | ||||||
| 			// writes to default output dir __debug_bin | 			// writes to default output dir __debug_bin | ||||||
| 		}, fixture.Source) | 		}) | ||||||
| 	}) | 	}) | ||||||
|  |  | ||||||
| 	// if noDebug is not a bool, behave as if it is the default value (false). | 	// if noDebug is not a bool, behave as if it is the default value (false). | ||||||
| @ -4120,7 +4123,7 @@ func TestLaunchRequestDefaults(t *testing.T) { | |||||||
| 		runDebugSession(t, client, "launch", func() { | 		runDebugSession(t, client, "launch", func() { | ||||||
| 			client.LaunchRequestWithArgs(map[string]interface{}{ | 			client.LaunchRequestWithArgs(map[string]interface{}{ | ||||||
| 				"mode": "debug", "program": fixture.Source, "noDebug": "true"}) | 				"mode": "debug", "program": fixture.Source, "noDebug": "true"}) | ||||||
| 		}, fixture.Source) | 		}) | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -4219,16 +4222,48 @@ func TestNoDebug_AcceptNoRequestsButDisconnect(t *testing.T) { | |||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|  |  | ||||||
| func TestLaunchTestRequest(t *testing.T) { | func TestLaunchRequestWithRelativeBuildPath(t *testing.T) { | ||||||
| 	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) { | 	client := startDapServer(t) | ||||||
|  | 	defer client.Close() // will trigger Stop() | ||||||
|  |  | ||||||
|  | 	fixdir := protest.FindFixturesDir() | ||||||
|  | 	if filepath.IsAbs(fixdir) { | ||||||
|  | 		t.Fatal("this test requires relative program path") | ||||||
|  | 	} | ||||||
|  | 	program := filepath.Join(protest.FindFixturesDir(), "buildtest") | ||||||
|  |  | ||||||
|  | 	// Use different working dir for target than dlv. | ||||||
|  | 	// Program path will be interpreted relative to dlv's. | ||||||
|  | 	dlvwd, _ := os.Getwd() | ||||||
|  | 	runDebugSession(t, client, "launch", func() { | ||||||
|  | 		client.LaunchRequestWithArgs(map[string]interface{}{ | ||||||
|  | 			"mode": "debug", "program": program, "cwd": filepath.Dir(dlvwd)}) | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestLaunchRequestWithRelativeExecPath(t *testing.T) { | ||||||
|  | 	runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) { | ||||||
|  | 		symlink := "./__thisexe" | ||||||
|  | 		err := os.Symlink(fixture.Path, symlink) | ||||||
|  | 		defer os.Remove(symlink) | ||||||
|  | 		if err != nil { | ||||||
|  | 			t.Fatal("unable to create relative symlink:", err) | ||||||
|  | 		} | ||||||
|  | 		runDebugSession(t, client, "launch", func() { | ||||||
|  | 			client.LaunchRequestWithArgs(map[string]interface{}{ | ||||||
|  | 				"mode": "exec", "program": symlink}) | ||||||
|  | 		}) | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func TestLaunchTestRequest(t *testing.T) { | ||||||
|  | 	client := startDapServer(t) | ||||||
|  | 	defer client.Close() // will trigger Stop() | ||||||
| 	runDebugSession(t, client, "launch", func() { | 	runDebugSession(t, client, "launch", func() { | ||||||
| 			// We reuse the harness that builds, but ignore the built binary, |  | ||||||
| 			// only relying on the source to be built in response to LaunchRequest. |  | ||||||
| 		fixtures := protest.FindFixturesDir() | 		fixtures := protest.FindFixturesDir() | ||||||
| 		testdir, _ := filepath.Abs(filepath.Join(fixtures, "buildtest")) | 		testdir, _ := filepath.Abs(filepath.Join(fixtures, "buildtest")) | ||||||
| 		client.LaunchRequestWithArgs(map[string]interface{}{ | 		client.LaunchRequestWithArgs(map[string]interface{}{ | ||||||
| 			"mode": "test", "program": testdir, "output": "__mytestdir"}) | 			"mode": "test", "program": testdir, "output": "__mytestdir"}) | ||||||
| 		}, fixture.Source) |  | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -4242,7 +4277,7 @@ func TestLaunchRequestWithArgs(t *testing.T) { | |||||||
| 			client.LaunchRequestWithArgs(map[string]interface{}{ | 			client.LaunchRequestWithArgs(map[string]interface{}{ | ||||||
| 				"mode": "exec", "program": fixture.Path, | 				"mode": "exec", "program": fixture.Path, | ||||||
| 				"args": []string{"test", "pass flag"}}) | 				"args": []string{"test", "pass flag"}}) | ||||||
| 		}, fixture.Source) | 		}) | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -4258,7 +4293,7 @@ func TestLaunchRequestWithBuildFlags(t *testing.T) { | |||||||
| 			client.LaunchRequestWithArgs(map[string]interface{}{ | 			client.LaunchRequestWithArgs(map[string]interface{}{ | ||||||
| 				"mode": "debug", "program": fixture.Source, "output": "__mybin", | 				"mode": "debug", "program": fixture.Source, "output": "__mybin", | ||||||
| 				"buildFlags": "-ldflags '-X main.Hello=World'"}) | 				"buildFlags": "-ldflags '-X main.Hello=World'"}) | ||||||
| 		}, fixture.Source) | 		}) | ||||||
| 	}) | 	}) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 polinasok
					polinasok