Debugging C/C++ Programs Remotely Using Visual Studio Code and gdbserver
If you’re like me and prefer using a GUI to a command line for setting breakpoints, stepping through code, and inspecting values as your program runs, here is how you can set up VSCode and gdbserver to edit and debug your code locally while running it on a remote server.
Background: I’m working on an assignment for CSC469 at the University of Toronto, and it will only compile and run on the university’s teaching lab machines. My goal was to be able to edit and debug locally in a familiar editor while compiling and running on the remote teaching lab machines.
Note: I’m using macOS Sierra locally, with the remote machine running Ubuntu 14.04, but this guide should work with any Unix system. (Sorry, Windows users).
Note: Commands to be run on the remote machine are prefixed with
remote$ and local commands are prefixed with
1. Install gdbserver on the remote machine
Installation varies by system. On Debian/Ubuntu, you can do:
remote$ apt-get install gdbserver
Since students are not allowed to install software via apt on the U of T machines, I used Linuxbrew to install it to my user folder:
remote$ brew install gdbserver
2. Install gdb on your local machine
On macOS Sierra, I used Homebrew to install gdb:
local$ brew install gdb --with-all-targets
--with-all-targets option is important; without it, you won’t be able to debug on a remote machine with a different OS or architecture than your local machine.
3. Test gdb
At this point, you should be able to run gdbserver on the remote machine and connect to it from your local gdb CLI. I’ll use the
-L option of ssh to forward local port 9091 connections to the remote port 9091:
local$ ssh -L9091:localhost:9091 user@remote
remote$ cd ./myproject/ && make
remote$ gdbserver :9091 ./myprogram
(Port 9091 is arbitrary; use any port number you like)
Leave that command running in a terminal window; it will wait until gdb connects before running
In another terminal window on your local machine, run gdb:
GNU gdb (GDB) 7.12
Copyright (C) 2016 Free Software Foundation, Inc.
For help, type "help".
Type "apropos word" to search for commands related to "word".
Then connect to the gdbserver instance:
(gdb) target remote localhost:9091
Remote debugging using localhost:9091
To verify things are working, you can run various gdb commands like
info sources , or set a breakpoint with
break . Use
continue to run
4. codesign gdb
VSCode prevents you from running gdb unless it’s signed; follow these steps to ensure it’s signed.
5. Synchronize local and remote file systems
You may have noticed that, for basic functionality, the gdb CLI on your local machine doesn’t need to be provided any information about the program or its source code except for the host and port on which gdbserver is running. But there are two big reasons why you’ll want to keep your local and remote project directories in sync:
- Viewing source code in the gdb CLI (i.e.
- The VSCode C/C++ extension requires you to provide the path to the compiled executable to launch gdb. (The
"program"field in launch.json).
I opted to use sshfs since it required the least server-side setup, but you could use NFS, rsync, or other alternatives.
Using sshfs, mount the remote project folder locally:
local$ mkdir ./myproject
local$ sshfs user@remote:myproject ./myproject
Note: on macOS, you can later unmount the directory with
umount ./myproject. On Linux, use
fusermount -u ./myproject.
6. Configure Visual Studio Code
Open your newly-mounted project
./myproject/ in VSCode, then open
.vscode/launch.json or create it if it doesn’t exist:
"name": "C++ Launch",
This configuration will make it so clicking “C++ Launch” will run gdb similar to:
local$ gdb ./myprogram
(gdb) target remote localhost:9091
7. Write a script to compile your program and launch gdbserver
Ideally, you’d want to be able to run a single command or click a single button to compile & debug your program.
Instead I wrote a quick-and-dirty shell script
# Kill gdbserver if it's running
ssh user@remote killall gdbserver &> /dev/null
# Compile myprogram and launch gdbserver, listening on port 9091
"zsh -l -c 'cd myproject && make && gdbserver :9091 ./myprogram'"
8. Start debugging
Here is your new workflow:
- Edit some code.
./prepare_remote_debug.shin a terminal window. Your program’s output will appear here.
- Set some breakpoints.
- Run “C++ Launch”.
- Step through your code in VSCode’s debugger.
That’s it! I hope this helps someone, and let me know if it can be simplified even further.