Marus / cortex-debug

Visual Studio Code extension for enhancing debug capabilities for Cortex-M Microcontrollers
MIT License
984 stars 238 forks source link

WSL2 support for in Cortex-Debug. Discussion and Strategy #467

Open haneefdm opened 3 years ago

haneefdm commented 3 years ago

WSL2 is next on my list. I am trying to set up a Windows machine (my previous WSL2 seems like it got corrupted). I would like people to subscribe to this Issue and comment and help test it. There are several issues and workarounds already related to this and I would like to consolidate the discussion here.

First, comments are welcome on how it should work.

mpekurin commented 1 year ago

@sullivanmj

To achieve all of this, I was hoping to find a way to use both the serverPath and gdbTarget debug attributes, but it seems that gdbTarget is only used when the servertype is external, in which case, the serverPath is not used. This is an understandable behavior given the context of normal GDB client/server connections, but it prevents the approach I'm describing from being used.

That's what preLaunchTask is used for, to bypass that behavior and basically do what the serverPath should do. So maybe a simpler alternative to your solution would be just adding a support of using both serverPath and gdbTarget. Then a config like this should do the trick:

{
  "type": "cortex-debug",
  "name": "Launch",
  "request": "launch",
  "servertype": "theServerOfYourChoice",
  "serverPath": "/mnt/c/path/to/theServerOfYourChoice.exe",
  "serverArgs": ["--port", "61234"],
  "gdbTarget": "${env:HOSTNAME}.mshome.net:61234"
}

Additionally, if this is (or will be) required, the extension can check if serverPath is an .exe to understand where the server is run.

Is there a better way of achieving what I've described above with the existing functionality of cortex-debug, or should I open a PR?

Without using USB-IP or tasks most likely no.

romancardenas commented 11 months ago

Hi, folks!

I'm setting WSL2 with Cortex-Debug for a course and I was wondering what is the approach you recommend at this point. Should I...?

I'm not expert in VSCode plugins nor WSL, but I can try to open a PR with this change

GitMensch commented 11 months ago

I'm no export in anything of those but would suggest to connect to WSL2 first (with either the SSH or WSL2 extensions; either from https://github.com/jeanp413 or, if you prefer non-free "in preview" extensions with telemetry the matching one from Microsoft) and fully debug there, with the possible need to expose your board to WSL first.

haneefdm commented 11 months ago

I am getting reports that WSL2 with USB-IP works very well. In this case, you would install OpenOCD/Jlink/whatever right on the Linux side and use the Linux versions.

But, make sure that your USB is working first by using various command-line tools (lsusb). You may run into firewall issues but there are workarounds for those too. Let Google be your friend. Make sure you can launch the gdb-server (OpenOCD, JLink, etc.) from the command-line first and that it recognizes your adapter/probe.

romancardenas commented 11 months ago

It does work pretty well! The only issue is that students need to handle the USB attachment etc., which might be a bit confusing for them.

So far I'll use the usbipd approach. If I have time I'll try to do a PR with the required changes to skip all this process and leave openOCD run on Windows while GDB is on WSL.

haneefdm commented 11 months ago

@romancardenas About making the PR, you also have to handle allocating/finding the TCP ports if you are running on the Windows side. I think running the server on the Linux side is still a better option. We want things like SWO, RTT, etc. to also work. Some instructions for your students may be beneficial.

szszoke commented 11 months ago

I managed to work around the problem of J-Link software not being able to resolve the IP address host.docker.internal. I needed this to be able to connect to a J-Link remote server that was running on the same host as my Dev Container. Hard-coding an IP like 172.17.0.1 did not work because different host platforms have different IP addresses. This method was tested on a Linux host and on a Windows host running WSL2.

In order for this to work, you need to run docker with the following argument: --add-host=host.docker.internal:host-gateway. This argument is technically redundant on Windows and Mac, but it is needed on Linux. You can do this by adding the following todevcontainer.json:

{
  "runArgs": ["--add-host=host.docker.internal:host-gateway"]
}

This will ensure that you have host.docker.internal entry in /etc/hosts which points to the IP of your host that is running the Dev Container.

The second step is to resolve this hostname to an IP so that we can pass it to JLinkGDBServer.

This can be done with the following command:

$ getent hosts host.docker.internal
172.17.0.1      host.docker.internal

We can further clean this command up with the help of awk:

$ getent hosts host.docker.internal | awk '{ print $1 }'
172.17.0.1

Great, now we have the IP address and it is not hard-coded. Unfortunately there is obvious way to provide this IP to the debug configuration without hard-coding it so we need a different solution.

I noticed that there is a serverpath parameter which allows us to provide a custom path for JLinkGDBServer. This is what allowed me to finally make things working. I created a shell script with the following content:

#!/bin/sh

REMOTE_JLINK_IP=`getent hosts host.docker.internal | awk '{ print $1 }'`

JLinkGDBServer -select ip=$REMOTE_JLINK_IP "$@"

What this will do is to get the IP address behind the host.docker.internal entry in /etc/hosts and store it in REMOTE_JLINK_IP. I then just invoke JLinkGDBServer, pass the IP via -select ip=$REMOTE_JLINK_IP and pass any other arguments that were passed to the script via "$@".

I saved this script in my .devcontainer directory as remote-gdb-server.sh and then updated my debug configuration to use it by adding "serverpath": "./.devcontainer/remote-gdb-server.sh".

Don't forget to run chmod +x remote-gdb-server.sh.

This exact pattern can also be used in a Makefile:

REMOTE_JLINK_IP := $(shell getent hosts host.docker.internal | awk '{ print $$1 }')

One word of caution however is that $ needs to be escaped, which becomes $$.

haneefdm commented 11 months ago

I wish someone volunteers to document what works in our Wiki. We could have sections for WSL, docker, etc. I can start a Wiki Page if you want but I am not good for the content. You all know way more than me.

szszoke commented 11 months ago

I can start a Wiki Page if you want but I am not good for the content.

If you start a Wiki page, I could contribute my previous comment as an article about using J-Link from a Docker container.

haneefdm commented 11 months ago

https://github.com/Marus/cortex-debug/wiki/Working-with-WSL2-or-Docker

Feel free to re-organize the page. I just started something. Maybe we want two separate pages, we can decide later.

Long time ago, I was playing with Codespaces and here was my Docker configuration

https://github.com/haneefdm/psoc6hello/tree/master/.devcontainer

Of course not everything I have is applicable to all.

szszoke commented 11 months ago

I think my comment would fit in better with the things in J Link Specific Configuration, since it is highly specific to that programmer and the software that comes with it.

haneefdm commented 11 months ago

Make sections and sub-sections as you please. I would expect some setup differences for various gdb-servers.

And, edit which ever page you like.

szszoke commented 10 months ago

I think I will be using my setup for a bit to iron out some kinks. Until then, if somebody needs help, hopefully they see my previous comment.

rhempel commented 10 months ago

I have had some success with the following scenario:

It works, but single stepping is painful, and I'm not sure I like the requirement to mess with USB-IP so I will check some of the comments above and rather start st-util on the host machine and connect to the gdb-server running on the host from the container where gdb is running.

Is anyone interested in my progress on this?

jnz86 commented 10 months ago

Is anyone interested in my progress on this?

I'm following. I'd be more interested had I not given up and just switched to linux desktop for at LEAST until this is all solved for Windows, which may be never.

rhempel commented 10 months ago

I have a potential solution here:

https://github.com/rhempel/docker-devcontainers/tree/main/adaptabuild-example

The difference from my original scenario is that now we run stlink-util on the Windows host, and get the correct IP address into the container /etc/hosts file using this line in the devcontainer,json file:

// This line is the key to accessing the GDB server on the host machine
// when running Docker on a Windows machine.
//
// See .vscode/launch.json for details

  "runArgs": [
    "--add-host=host.gdb.gateway:host-gateway",
  ],

In .vscode/launch.json the key is:

      "gdbTarget": "host.gdb.gateway:4242",

Note, the container is based on Ubuntu 22.04 and pulls in everything needed to build a simple application, plus Shpinx for docs and gcov. The launch.json file assumes a project called adaptabuild-example which you can build in ~/projects.

Note: you might need to change ownership on ~/projects to adaptabuild:adaptabuild to allow cloning there.

The adaptabuild-example project is here:

https://github.com/rhempel/adaptabuild-example

I'm still busy getting it polished and writing a tutorial, but please let me know if this works for you :-)

CaptainKAZ commented 7 months ago

https://devblogs.microsoft.com/commandline/windows-subsystem-for-linux-september-2023-update/ It seems that we can use new "mirror" networking mode for connecting gdb server running on windows and gdb client on wsl2? I tried but openocd claims that it fails to bind tcl port.

openocd.exe -c "gdb_port 50000" -c "tcl_port 50001" -c "telnet_port 50002" -s /home/neo/Robocon2024-Embedded-BoardC -f /home/neo/.vscode-server/extensions/marus25.cortex-debug-1.12.1/support/openocd-helpers.tcl -f openocd.cfg -c "CDRTOSConfigure auto" -c CDLiveWatchSetup
xPack Open On-Chip Debugger 0.12.0+dev-01312-g18281b0c4-dirty (2023-09-04-22:32)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
CDLiveWatchSetup
Info : auto-selecting first available session transport "hla_swd". To override use 'transport select <transport>'.
Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
/home/neo/.vscode-server/extensions/marus25.cortex-debug-1.12.1/support/openocd-helpers.tcl: stm32f4x.cpu configure -rtos auto
/home/neo/.vscode-server/extensions/marus25.cortex-debug-1.12.1/support/openocd-helpers.tcl: Info: Setting gdb-max-connections for target 'stm32f4x.cpu' to 2
Error: couldn't bind tcl to socket on port 50001: No error
xpz24 commented 5 months ago

I believe wsl, cortex debug and openocd works well together now, at least for nucleo32 boards over usb. I tried it on a Windows 11, WSL2, ubuntu 23.10, 6.2.x kernel, usbipd nightly version. Before that I updated the ST-Link firmware to the latest version. https://steelph0enix.github.io/posts/vscode-cubemx-setup/ this guide helped a lot.

I used the openocd, customised version by STMicroelectronics, the one in ubuntu repos would work? STMCubeMX (linux version, with latest JRE, most likely unnecessary, the bundled JRE would be ok I think) to generate the code. stm32-for-vscode by dingen automated most of the stuff in the guide. I used the svd file from STM website. Programing and flashing works well, Debugging also works well I say, can see the variables, peripherals, registers and memory.

All possible from wsl side, only windows program I had to install was usbipd.

AaronFontaine-DojoFive commented 5 months ago

@xpz24, I think that much of the discussion here has been concerned with how to bridge out of WSL for the debugger. A lot of that has focused on getting the gdb server launched on the Windows side and then getting a WSL-side gdb client connected to it. I now think the better approach is, as you say, to use usbipd. There is now even a GUI for managing this. Golioth has a good article about it.

rhempel commented 3 months ago

I have tried both scenarios, and unless I am missing something, running the gdb-server over usbipd is al least an order of magnitude slower than gdb-server running on the host and connecting over a socket.

Plus, running gdb-server on the host and using a socket works on Windows/Linux and MacOS if there is a gdb-server for your debugger hardware on MacOS

BenSchoelerSonos commented 2 weeks ago

I have a potential solution here:

https://github.com/rhempel/docker-devcontainers/tree/main/adaptabuild-example

The difference from my original scenario is that now we run stlink-util on the Windows host, and get the correct IP address into the container /etc/hosts file using this line in the devcontainer,json file:

// This line is the key to accessing the GDB server on the host machine
// when running Docker on a Windows machine.
//
// See .vscode/launch.json for details

  "runArgs": [
    "--add-host=host.gdb.gateway:host-gateway",
  ],

In .vscode/launch.json the key is:

      "gdbTarget": "host.gdb.gateway:4242",

Note, the container is based on Ubuntu 22.04 and pulls in everything needed to build a simple application, plus Shpinx for docs and gcov. The launch.json file assumes a project called adaptabuild-example which you can build in ~/projects.

Note: you might need to change ownership on ~/projects to adaptabuild:adaptabuild to allow cloning there.

The adaptabuild-example project is here:

https://github.com/rhempel/adaptabuild-example

I'm still busy getting it polished and writing a tutorial, but please let me know if this works for you :-)

Hi @rhempel, did you happen to write a tutorial for this method? Very interested :)

rhempel commented 2 weeks ago

Well, sort of ...

EDIT: SEE THIS REPO INSTEAD FOR INSTRUCTIONS:

https://github.com/rhempel/adaptabuild-example

The main repository for getting started is here: https://github.com/rhempel/docker-devcontainers

That contains a folder for building a Docker base image for embedded development (it's about 2.2 GB and takes 5 minutes or so with typical dev PC and 50 mbps internet. It works on Windows and Linux and so far one M1 Mac :-)

https://github.com/rhempel/docker-devcontainers/tree/main/docker-base-images

The README.md file covers some background and has instructions for kicking of the build of the Docker image. I highly recommend we stick with the 22.04 variant due to some issues building rpi2040 with the gcc 13 compiler - something about TLS initialization.

Next, you want to build the actual devcontainer - thats in the adaptabuild-example-22.04 folder here:

https://github.com/rhempel/docker-devcontainers/tree/main/adaptabuild-example-22.04

Make sure the Docker daemon is running before going to the next step

Just rightclick and open with VSCode, and VSCode will see the .devcontainer folder and try to build and start a shiny new container. Note that it will also create a Docker Volume called adaptabuild-volume and it will mount (not copy) your local user's .ssh file to the container root - that makes git work transparently :-) It will also automagically pull in all the VSCode extensions needed for embedded ARM work.

If you get that far - congratulations - you will be presented with two shell terminals in VSCode. Now what?

Navigate to ~/projects and:

git clone https://github.com/rhempel/adaptabuild-example cd adaptabuild-example git submodule update --init

That should pull in the latest example of my adaptabuild example code and framework.

Let me know if I messed up the URLs (again) I think I have everything set to https:

Clcik on Terminal/RunTask and choose "Build All" - that should build all the targets curently supported

You're almost there! On your host machine (WIndows/Mac/Linux) you will run st-util in a terminal - that will look for your ST-Link compatible dev board and set up a GDB server waiting on port 4242

Now click on Launch in VSCode - you should see options for a couple of ST and nrf and rpi boards - clicking the launch for the board you have should start the debugger - connect to the STlink over a network socket - and bingo - you are done.

For anyone interested in testing this, I would be more than happy to support your questions and can arrange a Zoom call to help. I am interested in feedback for this setup - it sounds complex but it can get a new developer up and running in under 30 minutes, and I am very intetrested in collecting user feedback so that I can improve it.

I won't give private contact info here but you can find me on LinkedIn - unfortunately there are two Ralph Hempel users, I'm the one that matches my avatar here and exLEGO :-)

rhempel commented 1 week ago

Sorry for the long post above - here is a ( hopefully ) better summary:

https://github.com/rhempel/adaptabuild-example

I would be happy to get feedback - let me know in the comments and we can set up a 30 minute screen share.