mirror of
https://github.com/go-delve/delve.git
synced 2025-10-29 01:27:16 +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).
|
||||
|
||||
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 + debug (builds and launches, like 'dlv debug')
|
||||
- launch + test (builds and tests, like 'dlv test')
|
||||
- launch + replay (replays an rr trace, like 'dlv replay')
|
||||
- launch + core (replays a core dump file, like 'dlv core')
|
||||
- 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).
|
||||
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.
|
||||
|
||||
@ -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).
|
||||
|
||||
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 + debug (builds and launches, like 'dlv debug')
|
||||
- launch + test (builds and tests, like 'dlv test')
|
||||
- launch + replay (replays an rr trace, like 'dlv replay')
|
||||
- launch + core (replays a core dump file, like 'dlv core')
|
||||
- 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).
|
||||
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.`,
|
||||
|
||||
@ -864,8 +864,8 @@ func (s *Server) onLaunchRequest(request *dap.LaunchRequest) {
|
||||
|
||||
var cmd string
|
||||
var out []byte
|
||||
// Log debug binary build
|
||||
s.log.Debugf("building binary '%s' from '%s' with flags '%v'", debugbinary, program, buildFlags)
|
||||
wd, _ := os.Getwd()
|
||||
s.log.Debugf("building program '%s' in '%s' with flags '%v'", program, wd, buildFlags)
|
||||
switch mode {
|
||||
case "debug":
|
||||
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.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 {
|
||||
s.mu.Lock()
|
||||
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.
|
||||
// Note that he rest of the test sequence assumes that
|
||||
// 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
|
||||
// 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) {
|
||||
client.InitializeRequest()
|
||||
client.ExpectInitializeResponseAndCapabilities(t)
|
||||
@ -3994,8 +3995,10 @@ func runDebugSessionWithBPs(t *testing.T, client *daptest.Client, cmd string, cm
|
||||
panic("expected launch or attach command")
|
||||
}
|
||||
|
||||
client.SetBreakpointsRequest(source, breakpoints)
|
||||
client.ExpectSetBreakpointsResponse(t)
|
||||
if source != "" {
|
||||
client.SetBreakpointsRequest(source, breakpoints)
|
||||
client.ExpectSetBreakpointsResponse(t)
|
||||
}
|
||||
|
||||
// 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
|
||||
// sequences for a program that does not stop on entry
|
||||
// while specifying unique launch criteria via parameters.
|
||||
func runDebugSession(t *testing.T, client *daptest.Client, cmd string, cmdRequest func(), source string) {
|
||||
runDebugSessionWithBPs(t, client, cmd, cmdRequest, source, nil, nil)
|
||||
func runDebugSession(t *testing.T, client *daptest.Client, cmd string, cmdRequest func()) {
|
||||
runDebugSessionWithBPs(t, client, cmd, cmdRequest, "", nil, nil)
|
||||
}
|
||||
|
||||
func TestLaunchDebugRequest(t *testing.T) {
|
||||
@ -4061,7 +4064,7 @@ func TestLaunchDebugRequest(t *testing.T) {
|
||||
runDebugSession(t, client, "launch", func() {
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{
|
||||
"mode": "debug", "program": fixture.Source, "output": tmpBin})
|
||||
}, fixture.Source)
|
||||
})
|
||||
})
|
||||
// Wait for the test to finish to capture all stderr
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
@ -4098,13 +4101,13 @@ func TestLaunchRequestDefaults(t *testing.T) {
|
||||
runDebugSession(t, client, "launch", func() {
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{
|
||||
"mode": "" /*"debug" by default*/, "program": fixture.Source, "output": "__mybin"})
|
||||
}, fixture.Source)
|
||||
})
|
||||
})
|
||||
runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
|
||||
runDebugSession(t, client, "launch", func() {
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{
|
||||
/*"mode":"debug" by default*/ "program": fixture.Source, "output": "__mybin"})
|
||||
}, fixture.Source)
|
||||
})
|
||||
})
|
||||
runTest(t, "increment", func(client *daptest.Client, fixture protest.Fixture) {
|
||||
runDebugSession(t, client, "launch", func() {
|
||||
@ -4112,7 +4115,7 @@ func TestLaunchRequestDefaults(t *testing.T) {
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{
|
||||
"mode": "debug", "program": fixture.Source})
|
||||
// writes to default output dir __debug_bin
|
||||
}, fixture.Source)
|
||||
})
|
||||
})
|
||||
|
||||
// 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() {
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{
|
||||
"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) {
|
||||
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() {
|
||||
// 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()
|
||||
testdir, _ := filepath.Abs(filepath.Join(fixtures, "buildtest"))
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{
|
||||
"mode": "test", "program": testdir, "output": "__mytestdir"})
|
||||
}, fixture.Source)
|
||||
"mode": "exec", "program": symlink})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestLaunchTestRequest(t *testing.T) {
|
||||
client := startDapServer(t)
|
||||
defer client.Close() // will trigger Stop()
|
||||
runDebugSession(t, client, "launch", func() {
|
||||
fixtures := protest.FindFixturesDir()
|
||||
testdir, _ := filepath.Abs(filepath.Join(fixtures, "buildtest"))
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{
|
||||
"mode": "test", "program": testdir, "output": "__mytestdir"})
|
||||
})
|
||||
}
|
||||
|
||||
@ -4242,7 +4277,7 @@ func TestLaunchRequestWithArgs(t *testing.T) {
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{
|
||||
"mode": "exec", "program": fixture.Path,
|
||||
"args": []string{"test", "pass flag"}})
|
||||
}, fixture.Source)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@ -4258,7 +4293,7 @@ func TestLaunchRequestWithBuildFlags(t *testing.T) {
|
||||
client.LaunchRequestWithArgs(map[string]interface{}{
|
||||
"mode": "debug", "program": fixture.Source, "output": "__mybin",
|
||||
"buildFlags": "-ldflags '-X main.Hello=World'"})
|
||||
}, fixture.Source)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user