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 ability to change localhost when starting gdb #402

Closed
lagerholm opened this issue Feb 22, 2021 · 25 comments
Closed

Add ability to change localhost when starting gdb #402

lagerholm opened this issue Feb 22, 2021 · 25 comments

Comments

@lagerholm
Copy link

lagerholm commented Feb 22, 2021

Is there a way to change how to connect to the remote when starting gdb? To not always use localhost.
I can't find any setting for this. I thought that preLaunchCommands or overrideLaunchCommands would do it but it seems the three first commands are hardcoded. I found several references to target-select extended-remote localhost in debugadapter.js and extension.js. I tried changing these to the IP-adress I wanted and then I got it working as I wanted.

Reading symbols from 'xyz.elf'
Finished reading symbols
Please check OUTPUT tab (Adapter Output) for output from /mnt/c/Program Files (x86)/SEGGER/JLink/JLinkGDBServerCL.exe
Launching server: "/mnt/c/Program Files (x86)/SEGGER/JLink/JLinkGDBServerCL.exe" "-if" "swd" "-port" "50000" "-swoport" "50001" "-telnetport" "50002" "-device" "LPC1768" "-nolocalhostonly"
Launching GDB: "/gcc/gcc-arm-none-eabi-9-2019-q4-major/bin/arm-none-eabi-gdb" "-q" "--interpreter=mi2"
1-gdb-set target-async on
2-interpreter-exec console "source /home/user/.vscode-server/extensions/marus25.cortex-debug-0.3.12/support/gdbsupport.init"
3-target-select extended-remote localhost:50000

Some background information:
I am using WSL2 on windows 10 as my primary development environment where i use a cross-compiler in a docker container. Since I'm doing this all the paths in the elf file will be relative to the linux system. Since WSL2 doesn't support USB forwarding i want to run the gdbserver in Windows and gdb in Linux. Therefore I want to change localhost:port since localhost in Linux won't point to the localhost in Windows that gdbserver is listening to. VS code is run as a remote in WSL2 with VS code Server making it think that it is running in Linux. Therefore I can't run both gdbserver and gdb in Windows since then gdb mi2 interpreter will spit out paths in the form of //$wsl/some_path which doesn't make sense under Linux.

@Marus
Copy link
Owner

Marus commented Feb 23, 2021

Yes, we’re aware of certain limitations in regards to usage with a WSL2 setup, because of the inability to access USB. At the current time we recommend using the external server type and managing the launching of the GDB server yourself - with that server type you do provide the target to connect to.

@lagerholm
Copy link
Author

lagerholm commented Feb 23, 2021

It not really the GDB server that is the problem. It's the initialization of gdb. Specifically the call 3-target-select extended-remote localhost:50000 . This comes from line 36 of jlink.ts target-select extended-remote localhost:${gdbport}. It would be great if this was overridable in the same way launchCommands is with the setting overrideLaunchCommands in launch.json. Then my setup with WSL2 would work perfect. Then there are no practical limitations with WSL2 since you can run Windows CLI programs as if they where native in WSL2.

Edit: Just realized the titel was misleading. I had written gdb server by mistsake... I actually meant gdb.

@lagerholm lagerholm changed the title Add ability to change localhost when starting gdb server Add ability to change localhost when starting gdb Feb 23, 2021
@Marus
Copy link
Owner

Marus commented Feb 23, 2021

Yes - I understand where the issue is caused - and we are looking at adding some better support for running in a WSL2 setup (something I need to figure out how to setup so I have a testing environment) which would include determining the correct IP and stuff to connect on. I was trying to give you a work around for the time-being and that would be using something like the following:

{
   "name": "External GDB Server",
   "request": "launch",
   "type": "cortex-debug",
   "servertype": "external",
   "gdbTarget": "<IP:PORT Here>"
}

and manually launch your GDB server.

@lagerholm
Copy link
Author

Ah sorry for being so slow... Now i get it. Thanks! I will try it out.

It would be great if the gdbTarget could be made available for all server types to override the standard localhost:port.

@Marus
Copy link
Owner

Marus commented Feb 24, 2021

The issue with it is that port and stuff are not necessarily consistent from run to run (it usually is - but isn't guaranteed to be) - so makes it hard to include. We are looking at adding support for the WSL2 environment where it would actually determine the appropriate IP/port and use that automatically - but need to do a bit more research into how to get that to work reliably. For now this is the work-around - not ideal as some features (like SWO) don't work and it doesn't manage launching the GDB server and stuff itself - but better than nothing.

@lagerholm
Copy link
Author

Thanks for clarification! Sure the IP adress would have to be fetched again for every run since it could be changed even if it's unlikely. And it would be nice not to have to configure it.

I would gladly help out with testing when you come to that stage since I use this every day.

@haneefdm
Copy link
Collaborator

In WSL2, can't you use a hostname instead of IPv4 address?

microsoft/WSL#5780 (comment)
microsoft/WSL#4305 (comment)

@haneefdm
Copy link
Collaborator

Btw, if you use the "external" server method, you can launch the external server in persistent mode and just leave it running.

@nosajthenitram
Copy link

Given the limitations of WSL2 specified above, is there anything wrong with the following patch? It allows for more control over the the gdb target. I've replicated the code across all of the debug interfaces, though only have only tested jlink at this time.

Which port is inconsistent? The GDB server port? Is this for a specific debug interface that it changes?

     public initCommands(): string[] {
-        const gdbport = this.ports[createPortName(this.args.targetProcessor)];
+        if (this.args.gdbTarget) {
+            return [
+                `target-select extended-remote ${this.args.gdbTarget}`
+            ];
+        }
+        else {
+            const gdbport = this.ports[createPortName(this.args.targetProcessor)];

-        return [
-            `target-select extended-remote localhost:${gdbport}`
-        ];
+            return [
+                `target-select extended-remote localhost:${gdbport}`
+            ];
+        }
     }

@haneefdm
Copy link
Collaborator

The way code above works, we do a bunch of work to find available ports on the localhost and then we don't use them and use something else specified by gdbTarget. Cortex-Debug goes the extra mile to avoids port conflicts. You can have multiple Cortex-Debugs running at the same time with different ports (selected automatically) or someone else using those ports. Then there are multi-processor issues. If you specify the gdbTarget, what about the SWO port?

The gdbTarget is intended to be used specifically when the servertype is external and all our assumptions will still hold true.

I agree, we need to find a better way for the WSL. I can't find a good solution right now.

@lagerholm
Copy link
Author

Could this be an option to find the IP to the Windows host?
https://stackoverflow.com/a/65634105/5784039 (the first option with ${hostname}.local)

I tried it with the IP that the ${hostname}.local resolves to and it worked. Couldn't use ${hostname}.local directly in the obfuscated code though. Then it didn't resolve it so I'm guessing you need some more steps in the code.

@haneefdm
Copy link
Collaborator

haneefdm commented May 21, 2021

@lagerholm This sounds promising. Can you help me with the scene though? Following will give me a better problem statement and then may lead to solutions.

  1. Where is VSCode running? WSL or Windows. This means Cortex-Debug and Gdb and the gdb-server (JLinkGdbServer, openocd, pyocd, etc.) will also be running here. If WSL, implies these are all Linux executables/installations as well.
  2. Where was the code compiled? WSL or Windows? The elf file contains pathnames used to compile/link it. Hopefully the answer is WSL/Linux
  3. How can one detect if a program is running in WSL? What does uname, uname -a, and uname -r return? Hopefully still Linux?
    • See this thread.
    • See also thread
    • Hopefully, javascript (Node.js) also gives the same answers as uname
  4. Same thing with cat /proc/version. Is there any signature to indicate its Linux is under WSL1/2
  5. What is the IP address of the WSL env.?
  6. What is the IP address of the Windows host?
  7. What does ping localhost do? Does it show the WSL address or the Windows host?
  • Some people said ping was not working at all or partially working.

Note that every program I mentioned above expects localhost and 127.0.0.1 to be resolved properly.

It might sound very simple (and frustrating to you all) but not from my perspective. I have seen users do all kinds of things. Like compiling in WSL but running the debugger in Windows and many combinations thereof and wonder why things don't work. If we can provide a flow that works for most people, then we made progress.

I am thinking of not worrying about WSL1 at all. WSL2 and WSL1 are totally different beasts. I see people still using WSL1 and that baffles me.

@lagerholm
Copy link
Author

I'm going to try to describe how I think it works (in my setup) and answer your questions. (When I write WSL below i mean WSL2).

  1. When using VSCode (VSC) and WSL, VSC on Windows 10 will connect to an VSC server that is running on WSL (Linux env). See this for a picture of how it work. This means that VSC (and it's plugins) will run as if it where on Linux. The big problem is that WSL2 doesn't have support for forwarding USB traffic to the Linux instance running is WSL. This means you cannot connect your USB debugger to WSL2 and have it be accessible from Linux inside WSL. So the gdbserver cannot be run in Linux. Luckily from the WSL environment you have full access to running programs in Windows and that way the gdb-server can be run there hence the connection problems. So everything except the gdb-server is in WSL/Linux.
  2. The code is compiled on the VSC server so it's on WSL/Linux. In a docker container.

anton@xyz:~$ uname
Linux
anton@xyz:~$ uname -a
Linux xyz 5.4.72-microsoft-standard-WSL2 #⁠1 SMP Wed Oct 28 23:40:43 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
anton@xyz:~$ uname -r
5.4.72-microsoft-standard-WSL2

  1. Seem like it's quite easy to determine.

anton@xyz:~$ cat /proc/version
Linux version 5.4.72-microsoft-standard-WSL2 (oe-user@oe-host) (gcc version 8.2.0 (GCC)) #⁠1 SMP Wed Oct 28 23:40:43 UTC 2020

I'm not a JS developer so I don't know how to test that. If you could provide a method to test it then I could try that on my machine.

  1. 172.31.191.195
  2. 192.168.67.193 ($(hostname).local gives IP xyz.mshome.net (172.31.176.1))

In my opinion this is the workflow that should be used today. It's the one that came easiest when I started using it. I haven't made any strange/hacky changes to the configuration (except modifying cortex-debug to connect to another IP for the gdb-server :) ). I can think that there where a lot of strange things going on before when WSL and VSC was more immature. Now they both seem pretty stable.

I think it's wise to forget all about WSL1. It should be declared dead. I can't see any reason for anyone to use it. Except maybe if you are on a company PC with an old Windows version.

Please let me know if there is anything else you need to know.

@haneefdm
Copy link
Collaborator

Thanks, @lagerholm.

I created a javascript (Node) script that you can run. I will do the same when my Windows machine is resuscitated. If others an also run this script and report back, that would be helpful

Btw, uname and proc version was not returning the strings you are seeing for other people. Depends on the Windows build and any updates you may have installed. In fact, there was no hint of 'microsoft' in there 6-12 months ago. Lot of complaints and looks like MS did acknowledge that. This is why it has been so frustrating for idiot developers like me. In fact, WSL2 looked like a fresh install of native Ubuntu

You will need to install Node and have it in your path. Try node --version. Probably already installed since you are using VSCode but not in your path. For platforms other than Win/Mac, you can get it here https://nodejs.org/en/download/package-manager/ and for Win/Mac, it is here https://nodejs.org/en/download/

Here is the script to run. Save it to a file info.js and do node info.js

const os = require('os');

console.log('Platform: ' + os.platform());
console.log('Type    : ' + os.type());
console.log('Release : ' + os.release());
console.log('Hostname: ' + os.hostname());

// Older versions of Node does not have this
if (os.version) {
    console.log('Version : ' + os.version());
} else {
    console.log('Version : Unknown');
}    

console.log('Network Interfaces:');
console.log(os.networkInterfaces());

@nosajthenitram
Copy link

Platform: linux
Type    : Linux
Release : 4.19.104-microsoft-standard
Hostname: MachineName
Version : #1 SMP Wed Feb 19 06:37:35 UTC 2020
Network Interfaces:
{
  lo: [
    {
      address: '127.0.0.1',
      netmask: '255.0.0.0',
      family: 'IPv4',
      mac: '00:00:00:00:00:00',
      internal: true,
      cidr: '127.0.0.1/8'
    },
    {
      address: '::1',
      netmask: 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
      family: 'IPv6',
      mac: '00:00:00:00:00:00',
      internal: true,
      cidr: '::1/128',
      scopeid: 0
    }
  ],
  eth0: [
    {
      address: '172.31.158.181',
      netmask: '255.255.240.0',
      family: 'IPv4',
      mac: '00:15:5d:5c:f1:85',
      internal: false,
      cidr: '172.31.158.181/20'
    },
    {
      address: 'fe80::215:5dff:fe5c:f185',
      netmask: 'ffff:ffff:ffff:ffff::',
      family: 'IPv6',
      mac: '00:15:5d:5c:f1:85',
      internal: false,
      cidr: 'fe80::215:5dff:fe5c:f185/64',
      scopeid: 4
    }
  ]
}

@haneefdm
Copy link
Collaborator

Thanks. Is this right? Hostname: MachineName. I have a friend who named his cat cat.

So, the loopback/localhost addresses do not resolve to the WSL machine even though it is listed as such. It resolves to the host instead? That is crazy.

In this case, '172.31.158.181' seems to be your local IP address and it was different before '172.31.191.195'. Was this the IP you wanted to set with gdbTarget?

@nosajthenitram
Copy link

MachineName was an edit as my machine name was a bit doxxable.

Localhost is in the hosts file as 127.0.0.1 in the WSL instance, which will always resolve to the local instance of 127.0.0.1. What is necessary is being able to get to the Windows localhost, which Windows also knows as 127.0.01, because that's where JlinkGDBServer is hosting the GDB instance. In order to access the GDB server from WSL, I need to explicitly call out my Windows IP address, which is a 192.168.1.x. The 172.x.x.x is a WSL instantiated IP address.

@haneefdm
Copy link
Collaborator

Okay, you can't run the JlinkGDBServer on your WSL side? SEGGER does offer Linux versions right? I USB/udev-rules a problem then?

In this case, the GDB-server is truly external to the WSL (and VSCode and Cortex-Debug)

@haneefdm
Copy link
Collaborator

Ah, you answered that question in your earlier comment. Sorry.

@RisinT96
Copy link

RisinT96 commented May 21, 2021

I mentioned this previously, on a different issue thread, but if you're working with a j-link, you can:

  • run a j-link remote server on your windows machine.
  • Run the j-link gdb server inside WSL, give it the windows host IP as an argument.
  • make sure the j-link remote server is not blocked in the windows firewall

Voila everything works from inside WSL.

Tested and works for me.

Edit:
Found my comment here.

Edit 2:
You can even automate the IP assignment by assigning the host IP to an environment variable:

export WSL_HOST=$(tail -1 /etc/resolv.conf | cut -d' ' -f2)

Credit: https://gist.github.com/ThYpHo0n/349f1f6473e207b866f65aca4728da3e#file-zshrc-L8

And setting the IP conf in launch.json to {env:WSL_HOST}.

@haneefdm
Copy link
Collaborator

Next thought:

During normal processing, we do a port scan to see what ports are available. We need several and some consecutively. We keep searching until we find a set we can use. But this was done on the localhost.

But suddenly we are connecting to another localhost where these same ports may not be free and will cause failures and collisions.

A simple way to demonstrating this is to try to run two instances of Cortex-Debug. There are other ways this can fail.

If we can do a port scan (by creating a server on it) on the Windows side, then we are golden. I see a security problem here where Windows Firewall may not allow us to do that. But there maybe other ways

I have to try this for myself.

@haneefdm
Copy link
Collaborator

Thanks, @RisinT96 Yup, I saw that documented on the SEGGER website a while ago as well.

But, hopefully we can find a solution for all gdb servers and document a flow

@RisinT96
Copy link

Yes, of course this is just j-link specific, and hopefully you can work out a solution that works for all gdb servers :)

I think the fact that WSL allows running programs on the host from within WSL can be "abused" to do the port scan on windows.

@haneefdm
Copy link
Collaborator

Yea @RisinT96 , I know, the thought of doing this makes me shudder. I feel bad about doing such a port-scan and MS may plug that hole anytime

@haneefdm
Copy link
Collaborator

I am closing this as USB ports work better with WSL2 and for JLink, there are other options like using their server software

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

5 participants