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

debug: automatically Infer Path Mapping for Remote Debugging #45

Closed
quoctruong opened this issue May 14, 2020 · 10 comments
Closed

debug: automatically Infer Path Mapping for Remote Debugging #45

quoctruong opened this issue May 14, 2020 · 10 comments
Labels
debug/legacy legacy debug adapter related issues - new issues won't be fixed Debug Issues related to the debugging functionality of the extension. FrozenDueToAge

Comments

@quoctruong
Copy link
Contributor

quoctruong commented May 14, 2020

Background

Existing Implementation

Currently, we are using 2 attributes in the launch configuration to configure path mapping: cwd and remotePath.

cwd - Workspace relative or absolute path to the working directory of the program being debugged. Default is the current workspace.
remotePath - Absolute path to the file being debugged on the remote machine in case of remote debugging.

Let’s say the local path is C:\Users\quoct\Github\project\hello-world and the remote path is /app/project/hello-world.

Processing and Storing the local and remote path

Using the path in cwd and remotePath, we detect the local path separator (LPS) and remote path separator (RPS) respectively.

With these separators, we attempt to find the longest common suffix between the 2 paths. For the example above, that would be project/hello-world.

We truncate the longest common suffix from the local and remote path and store them internally. For the example above, that would be C:\Users\quoct\Github and /app. If there are no common suffixes, we just trim the last path separator of the remote path. Let’s call these processed local root (PLR) and processed remote root (PRR) respectively.

Setting a breakpoint

This happens when the user sets a breakpoint in a file, for example: C:\Users\quoct\Github\project\hello-world\testing.go.

We use the remote path separator in the file name. So it will become C:/Users/quoct/Github/project/hello-world/testing.go. We then substitute the PLR (C:\Users\quoct\Github) with the PRR (/app). So now the breakpoint file will become /app/project/hello-world/testing.go. We call Delve to set a breakpoint in this file.

Breakpoint hit

This happens if a breakpoint is hit on the remote Delve instance. In this case, Delve will send us back the name of the file that contains the breakpoint and we will have to map this file to a file on the local machine. Let’s say the name of the file is /app/project/hello-world/testing.go.

If the path to convert starts with the PRR (/app), we then substitute the PRR with the PLR (C:\Users\quoct\Github) in the path. So it will become C:\Users\quoct\Github\project\hello-world\testing.go. There seems to be a BUG here where we are not taking into account different path separators for remote and local roots.

If it doesn’t start with the PRR, then we assume that it can be mapped to a file in the GOROOT directory. We do this by assuming that the remote file’s name starts with /app (which is another BUG?).

Problems

A lot of times users don’t know that they have to provide path mapping for the breakpoints to hit. Even if they do, they don’t provide the correct path mappings. So what happens is that the debugger appears to be running but no breakpoints are hit. This can cause a lot of confusion to the users.
Users currently cannot set breakpoints for packages in GOPATH. There is a proposal to add another field to map this. Even the experience for setting breakpoints for files in GOROOT is not great as we are blindly assuming that the GOROOT starts with /src.
The current implementation expects the paths to be absolute but they can be relative. There are PRs out there trying to address this by introducing more fields

Proposal

Instead of trying to add multiple fields to address the relative path mapping and GOPATH problems, we can fix these problems and reduce the user’s friction points by attempting to automatically infer the path mapping for the user.

Delve has an API to list all the files used by the program. So we can simply get the list of files on the remote machine and map it to the files on the local machine. These include files in the GOROOT and GOPATH on the remote machine as well so we can try to map them to the files in the local machine GOROOT and GOPATH.

Mapping local path to remote path

Since we get all the remote sources, we can retrieve all the remote source files that share the same file name with the local file. We can then do a suffix match to get the best matching remote path.
Mapping remote path to local path
This is more complicated because there are multiple places where we can try to find a match on the local machine.

However, we can use the ListPackagesBuildInfo to help us retrieve all the different Go packages used. Each package item returned comes with a Directory Path and an Import Path. Using Directory Path, we can determine if the remote path is in a particular package or not:

  • If the remote path is in a package, we can try to find whether the package exists on the local machine. We will be searching for it in 3 places:

    • The current user’s workspace folder.
    • The current user’s GOPATH.
    • The current user’s GOMOD folder (%GOMOD%/pkg/mod) if the package name contains pkg/mod.
  • If the remote path is not in any package, then we retrieve the name of the remote path and search for files with that name in the current workspace folder. We find the best matching one using a suffix match.

@polinasok @hyangah @stamblerre

@hyangah hyangah added the Debug Issues related to the debugging functionality of the extension. label May 15, 2020
@hyangah hyangah changed the title Automatically Infer Path Mapping for Remote Debugging debug: automatically Infer Path Mapping for Remote Debugging May 15, 2020
@gopherbot
Copy link
Collaborator

Change https://golang.org/cl/234020 mentions this issue: Add logic to infer remote path automatically

gopherbot pushed a commit that referenced this issue May 20, 2020
Delve has an [API](https://godoc.org/github.com/go-delve/delve/service/rpc2#ListSourcesOut) to list all the files used by the program. So we can simply get the list of files on the remote machine and map it to the files on the local machine. These include files in the `GOROOT` and `GOPATH` on the remote machine as well so we can try to map them to the files in the local machine `GOROOT` and `GOPATH`.

## Mapping local path to remote path
Since we get all the remote sources, we can retrieve all the remote source files that share the same file name with the local file. We can then do a suffix match to get the best matching remote path.
Mapping remote path to local path
This is more complicated because there are multiple places where we can try to find a match on the local machine.

However, we can use the [`ListPackagesBuildInfo`](https://godoc.org/github.com/go-delve/delve/service/rpc2#ListPackagesBuildInfoOut) to help us retrieve all the different Go packages used. Each package item returned comes with a Directory Path and an Import Path. Using Directory Path, we can determine if the remote path is in a particular package or not:

- If the remote path is in a package, we can try to find whether the package exists on the local machine. We will be searching for it in 3 places:
    - The current user’s workspace folder.
    - The current user’s `GOPATH`.
    - The current user’s `GOMOD` folder (`%GOMOD%/pkg/mod`) if the package name contains `pkg/mod`.

- If the remote path is not in any package, then we retrieve the name of the remote path and search for files with that name in the current workspace folder. We find the best matching one using a suffix match.

Updates #45.

Change-Id: I619c45ea4f79036db944d271169665e72dcffab8
GitHub-Last-Rev: 0383036
GitHub-Pull-Request: #44
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/234020
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
@sbalabanov
Copy link

Does running ListPackagesBuildInfo involve discovering go packages, and thus running 'go list' on remote side? If so, getting this information can be pretty expensive.

In loaded IDE, we can know folders paths from opened project metadata, along with GOPATH and GOROOT. In 99.(9)% of the cases this is enough to match the remote file with the local one.

One concern that I have is that getting a list of all source paths from remote may be expensive.

@gopherbot
Copy link
Collaborator

Change https://golang.org/cl/236017 mentions this issue: src/debugAdapter/goDebug: add extra check for remote path inference

gopherbot pushed a commit that referenced this issue Jun 2, 2020
Add check for remote path inference to make sure that this will only get called for remote debugging case.

Updates #45
Updates #107

Change-Id: I7c4c2154013d8631c0b294b124b05eaddf1991f7
GitHub-Last-Rev: 552c403
GitHub-Pull-Request: #147
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/236017
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
@hyangah
Copy link
Contributor

hyangah commented Jun 25, 2020

BTW, is it possible for users to offer a delve configuration with explicit path mapping info currently?

@polinasok
Copy link
Contributor

polinasok commented Jun 25, 2020

Yes, for now, but there is talk of taking out that option once this one is stable. The problem is that a single path option can only point to either user's source code or 3rd party library in a different directory, but not both.

@hyangah
Copy link
Contributor

hyangah commented Jun 25, 2020

@polinasok Maybe my question was not specific. I am asking if users can supply config.yml that supports multiple path substitution.

@koxu1996
Copy link

This is side comment that might help someone. Documentation regarding path mapping is not explaining clearly how to set it up and how it works. I had to investigate code and that allowed me to understand two things:

  • remotePath keyword is misleading, because it's path to sources during executable build. Even if you move sources, then you must provide original one (I think they are compiled in), so for me name like originalBuildPath would be more clear.
  • local path setup - this is actually path obtained from cwd, but I would prefer setting something like localPath explicitly.

@shaunco
Copy link

shaunco commented Sep 5, 2020

@koxu1996 - Thank you! I spent far too long trying to get breakpoints to work during a remote debug session between vscode on windows and delv in an ubuntu docker. Setting remotePath to the go workspace directory the binary was built from (even though it had no relation to the windows machine) and then setting cwd to ${workspaceFolder}, and everything worked.

It would be awesome if the vscode-go extension could just try remapping whatever paths are in the binary on the remote machine to the currently opened ${workspaceFolder}, as it seems like the most likely case.

https://github.com/golang/vscode-go/blob/master/docs/debugging.md#remote-debugging is also out of date and still mentions using program instead of cwd, among other things.

@gopherbot
Copy link
Collaborator

Change https://golang.org/cl/253741 mentions this issue: docs/debugging.md: update remote debugging documentation

gopherbot pushed a commit that referenced this issue Sep 15, 2020
Fix the remote debugging documentation to have the current configuration
settings.

Fixes #164
Updates #45

Change-Id: I4df7b080d2e26275218ccbdf3d79d3b82c44bd8c
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/253741
Trust: Suzy Mueller <suzmue@golang.org>
Reviewed-by: Polina Sokolova <polina@google.com>
Reviewed-by: Quoc Truong <quoct@google.com>
@hyangah
Copy link
Contributor

hyangah commented Feb 14, 2021

We updated the section for remote debugging. Please review and if you find it's still unclear and needs improvement, please file a new issue or submit your PRs.

@hyangah hyangah closed this as completed Feb 14, 2021
@polinasok polinasok added the debug/legacy legacy debug adapter related issues - new issues won't be fixed label Jul 16, 2021
@golang golang locked and limited conversation to collaborators Jul 16, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
debug/legacy legacy debug adapter related issues - new issues won't be fixed Debug Issues related to the debugging functionality of the extension. FrozenDueToAge
Projects
None yet
Development

No branches or pull requests

7 participants