code-debug icon indicating copy to clipboard operation
code-debug copied to clipboard

Debugging using WSL

Open tabedzki opened this issue 6 years ago • 8 comments

Hi, I really like your extension and find it very useful for debugging on my Linux machine machines both locally and over SSH. This has been really useful. One setup I can't get this to work is on my local Windows machine where I want to debug a program built in WSL (Ubuntu 18.04 LTS).

I have tried this configuration

        {
            "type": "gdb",
            "request": "launch",
            "name": "Launch Program",
            "target": "./debug",  //name of the executable program
            "cwd": "${workspaceRoot}"
        },

where ${workspaceRoot} is the Windows path (C:\Users\tabedzki\AppData\Local\lxss\root\code\example) and I have also tried

        {
            "type": "gdb",
            "request": "launch",
            "name": "Launch Program",
            "target": "/root/code/example/debug", //name of the executable program
            "cwd": "${workspaceRoot}"
        },

as well as using the full windows path explicitly in the launch.json. Do you know the proper configuration in order to debug a program on WSL with this extension? For completeness, the Microsoft's debugger (the C/C++ extension) can debug the program using the following configuration:

        {
            "name": "C++ Launch",
            "type": "cppdbg",
            "request": "launch",
            "program": "/root/code/dmft-lc/debug",
            "args": [
                "-fThreading"
            ],
            "stopAtEntry": false,
            "cwd": "/root/code/dmft-lc",
            "environment": [],
            "externalConsole": true,
            "windows": {
                "MIMode": "gdb",
                "setupCommands": [
                    {
                        "text": "-enable-pretty-printing",
                        "description": "enable pretty printing",
                        "ignoreFailures": true
                    },
                    {
                        "text": "handle SIGPIPE nostop noprint pass",
                        "description": "ignore SIGPIPE",
                        "ignoreFailures": true
                    }
                ]
                // "setupCommands": [
                //     {
                //         "description": "Enable pretty-printing for gdb",
                //         "text": "-enable-pretty-printing",
                //         "ignoreFailures": true
                //     }
                // ]
            },
            "pipeTransport": {
                "pipeCwd": "",
                "pipeProgram": "c:\\windows\\sysnative\\bash.exe",
                "pipeArgs": [
                    "-c"
                ],
                "debuggerPath": "/usr/bin/gdb"
            },
            "sourceFileMap": {
                "/mnt/c/": "C:\\",
                "/root": "C:\\Users\\tabedzki\\AppData\\Local\\lxss/root",
            }
        },

tabedzki avatar Jan 16 '19 22:01 tabedzki

Here's more information about the piping mechanism that they use: https://github.com/Microsoft/vscode-cpptools/blob/master/Documentation/Debugger/gdb/Windows%20Subsystem%20for%20Linux.md

tabedzki avatar Jan 16 '19 22:01 tabedzki

I don't think you can make that work with my extension except if you would run like a gdbserver on your linux side and connect from the windows side via localhost to it (there is an example snippet for gdbserver)

I don't really know how WSL works and I have never used it so I can't really help you on that.

WebFreak001 avatar Jan 16 '19 22:01 WebFreak001

Ahh alright. Thanks anyway. I'll leave this open in case someone wants to tackle it.

tabedzki avatar Jan 16 '19 22:01 tabedzki

I got this scenario working in the IntelliJ D plugin but also failed for Visual Studio Code so far. I created 2 batch files and set them as dub /gdb in Intellij:

dubwsl.bat with content:

@ECHO OFF
wsl dub %*

and a file gdbwsl.bat with content:

@ECHO OFF
wsl gdb %*

The command wsl will execute the following command in the default linux system. All arguments are passed.

andre2007 avatar Aug 06 '19 19:08 andre2007

@WebFreak001 I think the scenario is working if sourceFileMap would be supported similiar like in the C/C++ extension.

My assumption is, the missing source file mapping is the reason why the breakpoint is not found and gdb exits normally:

1-gdb-set target-async on
2-environment-directory "C:\\D\\projects\\sample1"
3-file-exec-and-symbols "/mnt/c/D/projects/sample1/sample1"
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"thread-group-added","output":[["id","i1"]]}]}
GDB -> App: {"token":1,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[]}}
GDB -> App: {"outOfBandRecord":[{"isStream":true,"type":"log","content":"Warning: /mnt/c/D/projects/sample1/C:\\D\\projects\\sample1: No such file or directory.\n"}]}
Warning: /mnt/c/D/projects/sample1/C:\D\projects\sample1: No such file or directory.
GDB -> App: {"token":2,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[["source-path","/mnt/c/D/projects/sample1/C:\\D\\projects\\sample1:$cdir:$cwd"]]}}
GDB -> App: {"token":3,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[]}}
4-break-delete
GDB -> App: {"token":4,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[]}}
5-break-insert -f "c:\\D\\projects\\sample1\\source\\app.d:5"
GDB -> App: {"outOfBandRecord":[{"isStream":true,"type":"log","content":"No source file named c.\n"}]}
No source file named c.
GDB -> App: {"token":5,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[["bkpt",[["number","1"],["type","breakpoint"],["disp","keep"],["enabled","y"],["addr","<PENDING>"],["pending","c:\\D\\projects\\sample1\\source\\app.d:5"],["times","0"],["original-location","c:\\D\\projects\\sample1\\source\\app.d:5"]]]]}}
6-thread-info
GDB -> App: {"token":6,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[["threads",[]]]}}
Running executable
7-exec-run
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"thread-group-started","output":[["id","i1"],["pid","44"]]}]}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"thread-created","output":[["id","1"],["group-id","i1"]]}]}
8-thread-info
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"library-loaded","output":[["id","/lib64/ld-linux-x86-64.so.2"],["target-name","/lib64/ld-linux-x86-64.so.2"],["host-name","/lib64/ld-linux-x86-64.so.2"],["symbols-loaded","0"],["thread-group","i1"],["ranges",[[["from","0x00007fffff400f10"],["to","0x00007fffff41fb20"]]]]]}]}
GDB -> App: {"token":7,"outOfBandRecord":[],"resultRecords":{"resultClass":"running","results":[]}}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"exec","asyncClass":"running","output":[["thread-id","all"]]}]}
GDB -> App: {"token":8,"outOfBandRecord":[],"resultRecords":{"resultClass":"done","results":[["threads",[[["id","1"],["target-id","process 44"],["name","sample1"],["state","running"],["core","0"]]]],["current-thread-id","1"]]}}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"library-loaded","output":[["id","/lib/x86_64-linux-gnu/libpthread.so.0"],["target-name","/lib/x86_64-linux-gnu/libpthread.so.0"],["host-name","/lib/x86_64-linux-gnu/libpthread.so.0"],["symbols-loaded","0"],["thread-group","i1"],["ranges",[[["from","0x00007fffff1e5bb0"],["to","0x00007fffff1f40f1"]]]]]}]}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"library-loaded","output":[["id","/lib/x86_64-linux-gnu/libm.so.6"],["target-name","/lib/x86_64-linux-gnu/libm.so.6"],["host-name","/lib/x86_64-linux-gnu/libm.so.6"],["symbols-loaded","0"],["thread-group","i1"],["ranges",[[["from","0x00007ffffee4ba80"],["to","0x00007ffffef0a2f5"]]]]]}]}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"library-loaded","output":[["id","/lib/x86_64-linux-gnu/librt.so.1"],["target-name","/lib/x86_64-linux-gnu/librt.so.1"],["host-name","/lib/x86_64-linux-gnu/librt.so.1"],["symbols-loaded","0"],["thread-group","i1"],["ranges",[[["from","0x00007ffffec32200"],["to","0x00007ffffec3570c"]]]]]}]}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"library-loaded","output":[["id","/lib/x86_64-linux-gnu/libdl.so.2"],["target-name","/lib/x86_64-linux-gnu/libdl.so.2"],["host-name","/lib/x86_64-linux-gnu/libdl.so.2"],["symbols-loaded","0"],["thread-group","i1"],["ranges",[[["from","0x00007ffffea20e50"],["to","0x00007ffffea21bde"]]]]]}]}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"library-loaded","output":[["id","/lib/x86_64-linux-gnu/libgcc_s.so.1"],["target-name","/lib/x86_64-linux-gnu/libgcc_s.so.1"],["host-name","/lib/x86_64-linux-gnu/libgcc_s.so.1"],["symbols-loaded","0"],["thread-group","i1"],["ranges",[[["from","0x00007ffffe802b30"],["to","0x00007ffffe812ced"]]]]]}]}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"library-loaded","output":[["id","/lib/x86_64-linux-gnu/libc.so.6"],["target-name","/lib/x86_64-linux-gnu/libc.so.6"],["host-name","/lib/x86_64-linux-gnu/libc.so.6"],["symbols-loaded","0"],["thread-group","i1"],["ranges",[[["from","0x00007ffffe4212d0"],["to","0x00007ffffe599c3c"]]]]]}]}
GDB -> App: {"outOfBandRecord":[{"isStream":true,"type":"console","content":"[Thread debugging using libthread_db enabled]\n"}]}
[Thread debugging using libthread_db enabled]
GDB -> App: {"outOfBandRecord":[{"isStream":true,"type":"console","content":"Using host libthread_db library \"/lib/x86_64-linux-gnu/libthread_db.so.1\".\n"}]}
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Edit source/app.d to start your project.
GDB -> App: {"outOfBandRecord":[{"isStream":true,"type":"console","content":"[Inferior 1 (process 44) exited normally]\n"}]}
[Inferior 1 (process 44) exited normally]
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"thread-exited","output":[["id","1"],["group-id","i1"]]}]}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"notify","asyncClass":"thread-group-exited","output":[["id","i1"],["exit-code","0"]]}]}
GDB -> App: {"outOfBandRecord":[{"isStream":false,"type":"exec","asyncClass":"stopped","output":[["reason","exited-normally"]]}]}
-gdb-exit
GDB -> App: {"outOfBandRecord":[],"resultRecords":{"resultClass":"exit","results":[]}}

andre2007 avatar Aug 07 '19 14:08 andre2007

While I think that this is something that should be included in the program, the functionality I was seeking has been replicated through MSFT plugins for VSCode now. Do you want to keep this open or are you ok with me closing this?

tabedzki avatar May 17 '21 23:05 tabedzki

you should keep it open while it's not in here, people with similar issues will find this so they can know to use the MSFT plugins for this use-case instead or attempt to fix it.

WebFreak001 avatar May 18 '21 14:05 WebFreak001

@tabedzki - What do you mean with MSFT plugins? Are those free or proprietary plugins?

@andre2007 - The sourceFileMap part is tracked in #298 and would definitely be useful (to not say "mandatory") for debugging via ssh, currently you can map 1 directory via cwd and ssh.cwd.

Working with WSL2 (you really should update from WSL1 if you are still on this as it is much too slow) is in general quite similar to working with any remote machine, the main differences:

  • for the gdbserver approach you need a gdb executable that supports the elf files - gdb-multiarch from MSYS2 is perfectly fine for this (and ARM and ...)
  • if you go with the gdbserver approach you'll always have the symbol files (and sources if they reside on the wsl instance) on the "client" (= Windows) via the wsl mapping \\wsl$\Distro\path)
  • if you go with the SSH approach you'll always have the source files on the "host" (= wsl instance via the wsl mapping /mnt/x/path), so a substitutePath will provide the sources directly to GDB
  • to get the WSL instance' IP from Windows wsl hostname -I, to get the Windows IP from wsl echo $(cat /etc/resolv.conf | grep nameserver | awk '{print $2}')
  • you can forward X11 from WSL quite fine with VcXsrv, you may want to do it directly via exporting DISPLAY instead of routing it through GDB (not sure if/what difference that makes)

Side note: "of course" you have to have ssh installed enabled on the server (wsl instance, for example with sudo apt install openssh-server && sudo service ssh start, after doing this check from a command prompt if ssh %wslip% does work and answer the connect question).

GitMensch avatar Nov 09 '21 16:11 GitMensch

The most useful thing nowadays for debugging on WSL is to just use a remote workspace, I can highly suggest to use https://github.com/jeanp413/open-remote-ssh (you need to open and find the ssh port as noted above) or use the specialized extension https://github.com/jeanp413/open-remote-wsl which gives a similar user-experience to the proprietary ones from M$.

Using a "relative up to date" Windows will remove the need to explicit export DISPLAY or start an own X-Server for both options above. It just runs when not tinkering with it (so just leave the X11 parts out of the debug configuration).

As the referenced issues are also closed and there's really nothing to do here: -> closing.

GitMensch avatar Feb 07 '24 09:02 GitMensch