Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconsistent handling of program path with substitutePath in debug mode when using dlv-dap #3915

Open
slava-nikulin opened this issue Feb 8, 2025 · 0 comments

Comments

@slava-nikulin
Copy link

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 using lstatSync.

  • 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 the dlv 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 how dlv-dap is handling remote builds.
  • This fix aligns "debug" mode behavior with "exec" mode, making remote debugging work as expected.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant