Description
Description:
When using the dlv-dap
server for remote debugging in debug mode, there appears to be an inconsistency between what the VSCode Go extension expects and what the server actually does.
Observed Behavior
-
The VSCode extension expects the
"program"
attribute in the launch configuration to point to a valid local directory or Go file. It checks this usinglstatSync
. -
In a remote debugging scenario (e.g., debugging inside a Docker container), the local path might be:
/local/path/to/project/cmd/service
and the
"substitutePath"
mapping is set up to map this local path to the remote path (e.g.,/remote/app
). -
However, when launching in
"debug"
mode, the extension passes the local path (without applying the substitution) to thedlv
server. The server then issues a build command similar to:go build -o /remote/app/__debug_binXYZ -gcflags all=-N -l /local/path/to/project/cmd/service
Since
/local/path/to/project/cmd/service
does not exist on the remote system, the build fails with an error (e.g.,ENOENT: no such file or directory
). -
In contrast, when using
"mode": "exec"
, no build is performed, and the path is used directly, so the remote path works as expected.
Relevant Code Snippets
From the VSCode extension (parseDebugProgramArgSync
):
try {
const pstats = lstatSync(program);
if (pstats.isDirectory()) {
return { program, dirname: program, programIsDirectory: true };
}
const ext = path.extname(program);
if (ext === '.go') {
return { program, dirname: path.dirname(program), programIsDirectory: false };
}
} catch (e) {
console.log(`parseDebugProgramArgSync failed: ${e}`);
}
throw new Error(
`The program attribute '${program}' must be a valid directory or .go file in debug/test/auto modes.`
);
🔹 Problem: This enforces that "program"
must be a local file, but in remote debugging, the path is only valid remotely.
From the dlv-dap
server (simplified handling of program
in debug mode):
switch args.Mode {
case "debug":
cmd, out, err = gobuild.GoBuildCombinedOutput(args.Output, []string{args.Program}, args.BuildFlags.value)
// ...
}
🔹 Problem: args.Program
is passed directly into the build command without applying "substitutePath"
.
Inconsistency
The VSCode extension (client) enforces a local path, while the dlv server uses the raw "program"
path for building.
- This causes an issue in remote debugging, where the path only exists on the remote system.
- The
"substitutePath"
mapping is applied for source code conversion (e.g., for breakpoints), but not when running the build command.
Suggested Fix
For "debug"
mode, the dlv server should apply the "substitutePath"
mapping to the "program"
value before calling the build command.
For example, with the following launch configuration:
"program": "/local/path/to/project/cmd/service",
"substitutePath": [
{ "from": "/local/path/to/project", "to": "/remote/app" }
]
The program
path should be transformed before passing it to the build command.
Suggested Change in dlv-dap
(Go Code)
Modify dlv-dap
to apply "substitutePath"
before using args.Program
:
func applySubstitutions(path string, mappings []SubstitutePathRule) string {
for _, rule := range mappings {
if strings.HasPrefix(path, rule.From) {
return strings.Replace(path, rule.From, rule.To, 1)
}
}
return path
}
switch args.Mode {
case "debug":
args.Program = applySubstitutions(args.Program, args.SubstitutePath)
cmd, out, err = gobuild.GoBuildCombinedOutput(args.Output, []string{args.Program}, args.BuildFlags.value)
// ...
}
🔹 Why? This ensures that if "program"
is a local path, it is correctly replaced with the remote path before execution.
Additional Context
- In
"exec"
mode, no build is performed, so the issue does not occur. - The current VSCode extension enforces that
"program"
must exist locally, which contradicts howdlv-dap
is handling remote builds. - This fix aligns
"debug"
mode behavior with"exec"
mode, making remote debugging work as expected.
Activity