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

Add explicit documentation for configuring substitutePaths when using -trimpath #2609

Open
firelizzard18 opened this issue Jan 11, 2023 · 4 comments

Comments

@firelizzard18
Copy link
Contributor

Is your feature request related to a problem? Please describe.
It is not clear how to set up substitutePaths when debugging a binary built with -trimpath.

Describe the solution you'd like
A section in docs/debugging.md that shows an example of how to debug a binary built with -trimpath.

Describe alternatives you've considered
Stumbling around and googling until you find go-delve/delve#2754, then figuring it out on your own from there.

@gopherbot gopherbot added this to the Untriaged milestone Jan 11, 2023
@adonovan adonovan modified the milestones: Untriaged, v0.38.0 Jan 12, 2023
@hyangah
Copy link
Contributor

hyangah commented Feb 10, 2023

Today I observed another google user who wanted to debug a binary built with compiler's -trimpath option (note: it's not built with in module mode) and this issue came up.

Ideally, it would be nice if this substitutePaths config can be inferred or the support is implemented in source somehow, so users don't need to configure it most of time.

@hyangah hyangah modified the milestones: v0.38.0, vscode-go/later Feb 10, 2023
@gopherbot
Copy link
Collaborator

Change https://go.dev/cl/469916 mentions this issue: docs/debugging.md: add tips for debugging with -trimpath

@firelizzard18
Copy link
Contributor Author

@hyangah @suzmue Capitalization is another potential pitfall. The project I am working on has a dependency with a capitalized name in the path. With -trimpath the binary has paths such as github.com/AccumulateNetwork/jsonrpc2/v15@v15.0.0-20220517212445-953ad957e040/handler.go which needs to be resolved to /home/ME/go/pkg/mod/github.com/!accumulate!network/jsonrpc2/v15@v15.0.0-20220517212445-953ad957e040/handler.go. I have { "to": "", "from": "${env:HOME}/go/pkg/mod/" } as my last substitution rule, but that doesn't cover the capitalization case. Ultimately the conflict is that the go module system uses the !a substitution rule for filesystem paths, but does not apply that rule when synthesizing paths for -trimpath. Adding a substitution rule for each such case is not a burden to me (there aren't many), but I'd like to nominate this to be added to the "Can we intelligently map paths?" consideration list.

gopherbot pushed a commit that referenced this issue Mar 2, 2023
Updates #2609

Change-Id: I6fae938b428f834f8e55e2e8afd4d309db33d0a9
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/469916
Reviewed-by: Ethan Reesor <ethan.reesor@gmail.com>
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
Run-TryBot: Suzy Mueller <suzmue@golang.org>
TryBot-Result: kokoro <noreply+kokoro@google.com>
@suzmue suzmue removed their assignment Mar 15, 2023
@dlipovetsky
Copy link
Contributor

dlipovetsky commented Apr 2, 2023

[Update: The day after posting this comment, I saw fa820d4, which already covers everything I found. My comment is mostly redundant. Sorry!]

I've been investigating remotely debugging Go executables distributed in container images. I used https://github.com/kubernetes/sample-controller as an example.

I built it with go 1.20.1 and found the following:

  1. The target module

    /home/myuser/sample-controller/controller.go

    k8s.io/sample-controller/controller.go (with -trimpath)

  2. The go standard library

    /home/myuser/.local/go/1.20.1/src/fmt/errors.go

    fmt/errors.go (with -trimpath)

  3. Modules in the go mod cache

    /home/myuser/.local/go/pkg/mod/k8s.io/client-go@v0.26.3/listers/storage/v1beta1/csistoragecapacity.go

    k8s.io/client-go@v0.26.3/listers/storage/v1alpha1/csistoragecapacity.go (with -trimpath)

Based on this, I defined one substitution for my target module, one substitution for every module in the standard library, and one for the Go mod cache.

Working set of substitutions
"substitutePath": [
    // Our module, built with -trimpath
    {
        "from": "/home/myuser/sample-controller",
        "to": "k8s.io/sample-controller",
    },
    // Packages in GOROOT (standard library)
    {
        "from": "/home/myuser/.local/go/1.20.1/src/archive",
        "to": "archive"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/arena",
        "to": "arena"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/bufio",
        "to": "bufio"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/builtin",
        "to": "builtin"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/bytes",
        "to": "bytes"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/cmd",
        "to": "cmd"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/compress",
        "to": "compress"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/container",
        "to": "container"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/context",
        "to": "context"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/crypto",
        "to": "crypto"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/database",
        "to": "database"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/debug",
        "to": "debug"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/embed",
        "to": "embed"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/encoding",
        "to": "encoding"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/errors",
        "to": "errors"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/expvar",
        "to": "expvar"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/flag",
        "to": "flag"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/fmt",
        "to": "fmt"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/go",
        "to": "go"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/hash",
        "to": "hash"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/html",
        "to": "html"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/image",
        "to": "image"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/index",
        "to": "index"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/internal",
        "to": "internal"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/io",
        "to": "io"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/log",
        "to": "log"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/math",
        "to": "math"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/mime",
        "to": "mime"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/net",
        "to": "net"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/os",
        "to": "os"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/path",
        "to": "path"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/plugin",
        "to": "plugin"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/reflect",
        "to": "reflect"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/regexp",
        "to": "regexp"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/runtime",
        "to": "runtime"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/sort",
        "to": "sort"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/strconv",
        "to": "strconv"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/strings",
        "to": "strings"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/sync",
        "to": "sync"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/syscall",
        "to": "syscall"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/testdata",
        "to": "testdata"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/testing",
        "to": "testing"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/text",
        "to": "text"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/time",
        "to": "time"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/unicode",
        "to": "unicode"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/unsafe",
        "to": "unsafe"
    },
    {
        "from": "/home/myuser/.local/go/1.20.1/src/vendor",
        "to": "vendor"
    },
    // Modules in GOMODCACHE
    {
        "from": "/home/myuser/.local/go/pkg/mod",
        "to": "",
    },
]

Some observations

  1. The order of substitutions appears to matter. The Go mod cache substitution has an empty string to field. The empty string seems to match all paths, so for my other substitutions to take effect, I had to define the Go mod cache one last.

  2. I had to create a substitution for each standard library module, and that was inconvenient. If all standard library modules had a common prefix, I could use substitution.

  3. To create the right substitution for each standard library module, I had to know (a) the Go version used to built the executable, and (b) the path to the source code for that version. It would be nice to have (a) included in the source code path, e.g. 1.20.1/fmt/errors.go instead of fmt/errors.go.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants