Using gdb and gdbserver

The gdb debugging tool is widely used by developers to introspect the execution environment of an application, revealing both its code and data state at any point.

As snaps are run within a confined environment, running gdb directly against a snap executable would introspect both the snap environment and the application itself, making the identification of any issues specific to the snap application much more difficult.

For this reason, the snap daemon embeds gdb within its own framework, allowing developers to call it directly against an installed snap with the run argument:

$ sudo snap run --gdb <snapname>

When GDB is instantiated in this way, it behaves just as it would were it called against the same executable outside of the snap environment.

:information_source: For general advice on fixing potential issues in running snaps, see Debugging snaps. Guidance on using GDB is outside the scope of our documentation, but a good place to start is the Sample GDB Session in the official documentation.

Using gdbserver

In addition to the gdb command (see above), the snap daemon also includes gdbserver. This is often a better way of working with gdb because it combines gdb functionality with the convenience of alternative frontends, remote access, and the ability to run applications as a normal user.

To run gdbserver, issue the following command for your own snap:

$ snap run --experimental-gdbserver <snapname>
Welcome to "snap run --gdbserver".
You are right before your application is run.
Please open a different terminal and run:

gdb -ex="target remote :43041" -ex=continue -ex="signal SIGCONT"
(gdb) continue

or use your favorite gdb frontend and connect to :43041

Use --experimental-gdbserver=":<my-port>" to request a specific port and to keep the port from changing with each run, such as --experimental-gdbserver=":43041".

You can now access the GDB session from your favourite frontend, or from gdb itself, running outside of the snap:

$ gdb -ex="target remote :43041"
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04) 9.2

To debug a snap remotely, first ensure any firewalls are set to permit the relevant ports (or are disabled) and precede the port argument with the IP address of the system running the snap:

$ gdb -ex="target remote"

After connecting to the session, you will need to issue several cont (continue) commands before reaching the exec() of the application. At which point, the original gdbserver session will output the following:

Welcome to `snap run --gdb`.
You are right before your application is execed():
- set any options you may need
- (optionally) set a breakpoint in 'main'
- use 'cont' to start

From the above point, you can debug your application normally.

Debug symbols

The majority of snaps do not ship with binaries that include debug symbols, and this means GDB can’t typically link to the original source to allow further analysis.

One solution is to build your own snaps with debug symbols enabled, and install them locally with the --devmode argument.

For example, to debug a typical C-based project using the CMake plugin, add set(CMAKE_BUILD_TYPE Debug) to its CMakeLists.txt and rebuild the snap.

After installing the snap and running GDB, the symbols will be located and the source code can be referenced, as shown below:

$ snap install test-gdb_0.1_amd64.snap --devmode
test-gdb 0.1 installed
$ snap run --gdb test-gdb.test-gdb
You are right before your application is execed():
- set any options you may need
- use 'cont' to start
(gdb) dir test-gdb/src/
Source directories searched: test-gdb/src:$cdir:$cwd
(gdb) list
1       #include <stdio.h>
3       int main (int argc, char *argv[])
4       {
5         printf ("GDB from a snap is working\n");
7         return 0;
8       }
(gdb) cont
GDB from a snap is working
[Inferior 1 (process 153259) exited normally]
(gdb) quit

See Collecting debug symbols for the forum discussion related to how snaps might bundle debug symbols.

Last updated 1 year, 11 months ago.