[vim/vim] runtime(termdebug): Allow remote debugging over tty (ssh, wsl, docker ...) (PR #18429)

15 views
Skip to first unread message

MiguelBarro

unread,
Sep 28, 2025, 3:17:15 PM (9 days ago) Sep 28
to vim/vim, Subscribed

The termdebug plugin doesn't work with gdbserver because is focus on tty. This plugin allows launching gdb connecting it via tty to the program windows.

This PR modifies it to allow using a remote tty device by launching the program window terminal remotely too. It automatically detects remoting if g:termdebug_config['command'] uses ssh or wsl (vim can access the sources directly on that case).

For other use cases (like docker) a g:termdebug_config['remote_windows'] allows customization.

This only works in prompt-buffer mode because termina-job mode (default) specifically creates a local tty window.

The PR provides g:termdebug_config['substitute_path'] entry to map remote to local files using the same strategy that gdb's substitute-path command.

Examples

ssh

In this case the netrw builtin plugin retrieves the sources automatically from the remote machine.

let g:termdebug_config = {}
let g:termdebug_config['use_prompt'] = v:true
let g:termdebug_config['command'] = ['ssh', 'hostname', 'gdb']
let g:termdebug_config['substitute_path'] = { '/': 'scp://hostname//' }

wsl

In this case the Windows OS will use special UNC paths for the linux filesystem and mounts for the windows drives.

let g:termdebug_config = {}
let g:termdebug_config['use_prompt'] = v:true
let g:termdebug_config['command'] = ['wsl', 'gdb']
let g:termdebug_config['substitute_path'] = {
    \ '/': '\\wsl.localhost\Ubuntu-22.04\',
    \ '/mnt/c/': 'C:/' }

Note: the UNC path can be queried using wslpath tool.


You can view, comment on, or merge this pull request online at:

  https://github.com/vim/vim/pull/18429

Commit Summary

File Changes

(4 files)

Patch Links:


Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18429@github.com>

MiguelBarro

unread,
Sep 29, 2025, 5:12:56 AM (8 days ago) Sep 29
to vim/vim, Push

@MiguelBarro pushed 1 commit.

  • 1f2435f Piggyback fix on gdb's job options. Must be reorder to work properly.


View it on GitHub or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18429/before/b7894ce2daac9af723c090b77563191cecfa43d6/after/1f2435fa68dbd530948d89d1c94e751abba08ce4@github.com>

MiguelBarro

unread,
Sep 29, 2025, 8:15:00 AM (8 days ago) Sep 29
to vim/vim, Push

@MiguelBarro pushed 1 commit.

  • 05d1cee Piggyback fix on gdb's job options. Must be reorder to work properly.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18429/before/1f2435fa68dbd530948d89d1c94e751abba08ce4/after/05d1cee33498022d7c6e181280d69d8c4793afff@github.com>

MiguelBarro

unread,
Sep 29, 2025, 8:51:38 AM (8 days ago) Sep 29
to vim/vim, Push

@MiguelBarro pushed 5 commits.

  • 01951c0 Update breakpoint management.
  • 760dca0 Update debugee terminal set up
  • be568b2 Update documentation
  • 10be77f Update testing
  • 944ef0a Piggyback fix on gdb's job options. Must be reorder to work properly.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18429/before/05d1cee33498022d7c6e181280d69d8c4793afff/after/944ef0af3db416539416012c3db714d8666be8fe@github.com>

MiguelBarro

unread,
Oct 1, 2025, 2:14:23 PM (6 days ago) Oct 1
to vim/vim, Push

@MiguelBarro pushed 1 commit.

  • d1b2c37 Improve program window using socat

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18429/before/944ef0af3db416539416012c3db714d8666be8fe/after/d1b2c37c694f4a6e192648cf877763d1122f1345@github.com>

Copilot

unread,
Oct 1, 2025, 3:48:33 PM (6 days ago) Oct 1
to vim/vim, Subscribed

@Copilot commented on this pull request.

Pull Request Overview

This PR adds remote debugging capabilities to the termdebug plugin, enabling gdb debugging over remote connections like ssh, wsl, and docker. It automatically detects remote contexts and provides path substitution for mapping remote files to local ones.

Key Changes

  • Added remote terminal window support for launching program windows on remote systems
  • Implemented path substitution mechanism to map remote file paths to local paths
  • Added automatic detection for ssh and wsl commands with customizable remote window configuration

Reviewed Changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 1 comment.

File Description
src/testdir/test_plugin_termdebug.vim Added comprehensive test for remote debugging functionality with path substitution
runtime/doc/terminal.txt Added documentation for remote debugging features including configuration examples
runtime/doc/tags Added new documentation tags for remote debugging help references

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.


In runtime/doc/terminal.txt:

> +- Use Windows' `UNC` paths to access `WSL2` sources: >
+    let g:termdebug_config['command'] = ['wsl', 'gdb']
+    let g:termdebug_config['substitute_path'] = {
+	\ '/': '\\wsl.localhost\Ubuntu-22.04\',
+	\ '/mnt/c/': 'C:/' }
+< Note: that several mappings are required: one for each drive unit
+  and one for the linux filesystem (queried via `wslpath`).
+
+The plugin "program window" is linked to `gdb` using `pty slave devices`.
+Those must be local to the `gdb` instance, thus remote debugging only works
+on `prompt mode` (see |termdebug_use_prompt|).
+In this mode any `ssh` or `wsl` command would be detected and a similar command
+used to launch a remote `tty` terminal session and connect it to `gdb`.
+
+						*termdebug-remote-window*
+In order to use another remote terminal clients, set "remote_window" entry

Grammar error: 'clients' should be 'client' since it refers to a single client.

⬇️ Suggested change
-In order to use another remote terminal clients, set "remote_window" entry
+In order to use another remote terminal client, set "remote_window" entry


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18429/review/3290849247@github.com>

MiguelBarro

unread,
Oct 1, 2025, 4:00:19 PM (6 days ago) Oct 1
to vim/vim, Subscribed

@MiguelBarro commented on this pull request.


In runtime/doc/terminal.txt:

> +- Use Windows' `UNC` paths to access `WSL2` sources: >
+    let g:termdebug_config['command'] = ['wsl', 'gdb']
+    let g:termdebug_config['substitute_path'] = {
+	\ '/': '\\wsl.localhost\Ubuntu-22.04\',
+	\ '/mnt/c/': 'C:/' }
+< Note: that several mappings are required: one for each drive unit
+  and one for the linux filesystem (queried via `wslpath`).
+
+The plugin "program window" is linked to `gdb` using `pty slave devices`.
+Those must be local to the `gdb` instance, thus remote debugging only works
+on `prompt mode` (see |termdebug_use_prompt|).
+In this mode any `ssh` or `wsl` command would be detected and a similar command
+used to launch a remote `tty` terminal session and connect it to `gdb`.
+
+						*termdebug-remote-window*
+In order to use another remote terminal clients, set "remote_window" entry

If I were referencing a single client, e.g. telnet, no extra option would be required. I would have included extra builtin management (like with ssh or wsl) 🤣.


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18429/review/3290886927@github.com>

Christian Brabandt

unread,
Oct 1, 2025, 4:02:58 PM (6 days ago) Oct 1
to vim/vim, Subscribed

@chrisbra commented on this pull request.


In runtime/doc/terminal.txt:

> @@ -1634,6 +1635,48 @@ interrupt the running program.  But after using the MI command
 "continue" being used for the `:Continue` command, instead of using the
 communication channel.
 
+Remote Debugging ~
+							*termdebug-remote*
+One of the main issues of remote debugging is the access to the debuggee's
+source files. The plugin can profit from system and vim's networking
+capabilities to workaround this.
+						*termdebug-substitute-path*
+Use the `g:termdebug_config['substitute_path']` entry to map remote to local
+files using the same strategy that gdb's `substitute-path` command.
⬇️ Suggested change
-files using the same strategy that gdb's `substitute-path` command.
+files using the same strategy that gdb's `substitute-path` command uses.

In runtime/doc/terminal.txt:

> @@ -1634,6 +1635,48 @@ interrupt the running program.  But after using the MI command
 "continue" being used for the `:Continue` command, instead of using the
 communication channel.
 
+Remote Debugging ~
+							*termdebug-remote*
+One of the main issues of remote debugging is the access to the debuggee's
+source files. The plugin can profit from system and vim's networking
+capabilities to workaround this.
+						*termdebug-substitute-path*
+Use the `g:termdebug_config['substitute_path']` entry to map remote to local
+files using the same strategy that gdb's `substitute-path` command.
+For example:
+- Use |netrw| to access files remoting via ssh: >
+    let g:termdebug_config['command'] = ['ssh', 'hostname', 'gdb']
+    let g:termdebug_config['substitute_path'] = { '/': 'scp://hostname//' }
+< Note: that first is specified the remote machine root path and later
⬇️ Suggested change
-< Note: that first is specified the remote machine root path and later
+< Note: that the key specifies the remote machine root path and the value

In runtime/doc/terminal.txt:

> +						*termdebug-substitute-path*
+Use the `g:termdebug_config['substitute_path']` entry to map remote to local
+files using the same strategy that gdb's `substitute-path` command.
+For example:
+- Use |netrw| to access files remoting via ssh: >
+    let g:termdebug_config['command'] = ['ssh', 'hostname', 'gdb']
+    let g:termdebug_config['substitute_path'] = { '/': 'scp://hostname//' }
+< Note: that first is specified the remote machine root path and later
+  the local one.
+- Use Windows' `UNC` paths to access `WSL2` sources: >
+    let g:termdebug_config['command'] = ['wsl', 'gdb']
+    let g:termdebug_config['substitute_path'] = {
+	\ '/': '\\wsl.localhost\Ubuntu-22.04\',
+	\ '/mnt/c/': 'C:/' }
+< Note: that several mappings are required: one for each drive unit
+  and one for the linux filesystem (queried via `wslpath`).

Do we always need to specify g:termdebug_config['command'] and also g:termdebug_config['substitute_path'] ?

Can you please also give an example. Something along the lines of:

Assuming you want to debug a program on a remote server using ssh, you would need to run the following command: >
ssh user@hostname gdb args /opt/command

This needs to be translated into a command your local Vim can run: >
gdb args scp://user@hostname//opt/command

In runtime/doc/terminal.txt:

> +- Use Windows' `UNC` paths to access `WSL2` sources: >
+    let g:termdebug_config['command'] = ['wsl', 'gdb']
+    let g:termdebug_config['substitute_path'] = {
+	\ '/': '\\wsl.localhost\Ubuntu-22.04\',
+	\ '/mnt/c/': 'C:/' }
+< Note: that several mappings are required: one for each drive unit
+  and one for the linux filesystem (queried via `wslpath`).
+
+The plugin "program window" is linked to `gdb` using `pty slave devices`.
+Those must be local to the `gdb` instance, thus remote debugging only works
+on `prompt mode` (see |termdebug_use_prompt|).
+In this mode any `ssh` or `wsl` command would be detected and a similar command
+used to launch a remote `tty` terminal session and connect it to `gdb`.
+
+						*termdebug-remote-window*
+In order to use another remote terminal clients, set "remote_window" entry
⬇️ Suggested change
-In order to use another remote terminal clients, set "remote_window" entry
+In order to use another remote terminal client, set "remote_window" entry

In runtime/pack/dist/opt/termdebug/plugin/termdebug.vim:

> +  # Check if the user provided a command to launch the program window
+  var term_cmd = null_list
+  if exists('g:termdebug_config') && has_key(g:termdebug_config, 'remote_window')
+    term_cmd = g:termdebug_config['remote_window']
+    term_cmd = type(term_cmd) == v:t_list ? copy(term_cmd) : [term_cmd]
+  else
+    # Check if it is a remote gdb, the program terminal should be started
+    # on the remote machine.
+    const remote_pattern = '^\(ssh\|wsl\)'
+    if gdb_cmd[0] =~? remote_pattern
+      var gdb_pos = indexof(gdb_cmd, $'v:val =~? "^{GetCommand()[-1]}"')
+      if gdb_pos > 0
+        # strip debugger call
+        term_cmd = gdb_cmd[0 : gdb_pos - 1]
+        # create a devoted tty slave device and link to stdin/stdout
+        term_cmd += ['socat', '-d', '-d', '-', 'PTY,raw,echo=0']

that socat is required should be documented or even better checked


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18429/review/3290850922@github.com>

MiguelBarro

unread,
Oct 2, 2025, 5:08:40 PM (5 days ago) Oct 2
to vim/vim, Push

@MiguelBarro pushed 1 commit.

  • d2deb63 Addressing reviewer's comments

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18429/before/d1b2c37c694f4a6e192648cf877763d1122f1345/after/d2deb63426b2493180e606573dcd95db26ff8bb7@github.com>

MiguelBarro

unread,
Oct 2, 2025, 5:12:25 PM (5 days ago) Oct 2
to vim/vim, Subscribed

@MiguelBarro commented on this pull request.


In runtime/pack/dist/opt/termdebug/plugin/termdebug.vim:

> +  # Check if the user provided a command to launch the program window
+  var term_cmd = null_list
+  if exists('g:termdebug_config') && has_key(g:termdebug_config, 'remote_window')
+    term_cmd = g:termdebug_config['remote_window']
+    term_cmd = type(term_cmd) == v:t_list ? copy(term_cmd) : [term_cmd]
+  else
+    # Check if it is a remote gdb, the program terminal should be started
+    # on the remote machine.
+    const remote_pattern = '^\(ssh\|wsl\)'
+    if gdb_cmd[0] =~? remote_pattern
+      var gdb_pos = indexof(gdb_cmd, $'v:val =~? "^{GetCommand()[-1]}"')
+      if gdb_pos > 0
+        # strip debugger call
+        term_cmd = gdb_cmd[0 : gdb_pos - 1]
+        # create a devoted tty slave device and link to stdin/stdout
+        term_cmd += ['socat', '-d', '-d', '-', 'PTY,raw,echo=0']

Let's check. I was afraid it might introduce a roundtrip that could slow down startup, but that doesn't seem to be the case.


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18429/review/3296413000@github.com>

MiguelBarro

unread,
Oct 2, 2025, 5:13:32 PM (5 days ago) Oct 2
to vim/vim, Subscribed

@MiguelBarro commented on this pull request.


In runtime/doc/terminal.txt:

> +						*termdebug-substitute-path*
+Use the `g:termdebug_config['substitute_path']` entry to map remote to local
+files using the same strategy that gdb's `substitute-path` command.
+For example:
+- Use |netrw| to access files remoting via ssh: >
+    let g:termdebug_config['command'] = ['ssh', 'hostname', 'gdb']
+    let g:termdebug_config['substitute_path'] = { '/': 'scp://hostname//' }
+< Note: that first is specified the remote machine root path and later
+  the local one.
+- Use Windows' `UNC` paths to access `WSL2` sources: >
+    let g:termdebug_config['command'] = ['wsl', 'gdb']
+    let g:termdebug_config['substitute_path'] = {
+	\ '/': '\\wsl.localhost\Ubuntu-22.04\',
+	\ '/mnt/c/': 'C:/' }
+< Note: that several mappings are required: one for each drive unit
+  and one for the linux filesystem (queried via `wslpath`).

I have reproduced the session example as a remote session.


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18429/review/3296415681@github.com>

MiguelBarro

unread,
Oct 6, 2025, 10:32:02 AM (yesterday) Oct 6
to vim/vim, Push

@MiguelBarro pushed 4 commits.

  • 22d00ff Refactor to reuse tty management code
  • 822aad2 Extend remoting to terminal mode
  • 568bd85 Update docs. Remote debugging works on terminal and prompt mode crossplatform.
  • 8b2d986 Extend remoting testing to terminal mode

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18429/before/d2deb63426b2493180e606573dcd95db26ff8bb7/after/8b2d986f2759cc3177bf617a7a05c12ccb79e7e3@github.com>

MiguelBarro

unread,
Oct 6, 2025, 11:08:51 AM (24 hours ago) Oct 6
to vim/vim, Push

@MiguelBarro pushed 1 commit.

  • 9a0f103 Extend remoting testing to terminal mode

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18429/before/8b2d986f2759cc3177bf617a7a05c12ccb79e7e3/after/9a0f1031ccd3129aa96f50519461cf9dc9899064@github.com>

MiguelBarro

unread,
Oct 6, 2025, 12:19:04 PM (23 hours ago) Oct 6
to vim/vim, Push

@MiguelBarro pushed 3 commits.

  • 4b6dc87 Extend remoting to terminal mode
  • 7d06c44 Update docs. Remote debugging works on:
  • aec2676 Extend remoting testing to terminal mode

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18429/before/9a0f1031ccd3129aa96f50519461cf9dc9899064/after/aec2676399521b97033182ab9603f23669626da8@github.com>

MiguelBarro

unread,
Oct 6, 2025, 12:28:42 PM (22 hours ago) Oct 6
to vim/vim, Push

@MiguelBarro pushed 1 commit.

  • 73e0bae Extend remoting testing to terminal mode

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18429/before/aec2676399521b97033182ab9603f23669626da8/after/73e0baeccfc4ac41670d21e76f7729a5275bc116@github.com>

MiguelBarro

unread,
Oct 6, 2025, 9:04:26 PM (14 hours ago) Oct 6
to vim/vim, Push

@MiguelBarro pushed 3 commits.

  • ecb91ba Extend remoting to terminal mode:
  • 3ed12e9 Update docs. Remote debugging works on:
  • 35cc7cc Extend remoting testing to terminal mode

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18429/before/73e0baeccfc4ac41670d21e76f7729a5275bc116/after/35cc7cc18a60addd30c0a2caa0c9f01ee52d8e2e@github.com>

MiguelBarro

unread,
Oct 6, 2025, 9:51:51 PM (13 hours ago) Oct 6
to vim/vim, Push

@MiguelBarro pushed 1 commit.

  • 630abb9 Only extend virtual buffer for remoting (socat)

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18429/before/35cc7cc18a60addd30c0a2caa0c9f01ee52d8e2e/after/630abb9ca6c40ca61e13159c056375e59ab11cdd@github.com>

Reply all
Reply to author
Forward
0 new messages