How to use gdb
==============
:toc:
Cyril Brulebois <kibi@debian.org>


Foreword
--------

One should note that X is responsible for VT switching, meaning
switching between an X session and console terminals. In other words,
`Ctrl+Alt+Fn` is handled by X. If X is stopped, for example because
it’s running under `gdb`, one can no longer switch to another
VT. That’s why we’re recommending using a second machine to debug
X. Nevertheless, here are some instructions to attempt debugging X
with a single machine.

One-machine approach
~~~~~~~~~~~~~~~~~~~~

This is a _post-mortem_ approach. The idea is to run X with the
`-core` option. Once it dies, a core file (`/etc/X11/core`) is
generated, and can be loaded from `gdb`.

Follow these steps:

 1. Getting a core file.
 2. Loading a core file.
 3. Displaying/saving a backtrace.

Two-machine approach
~~~~~~~~~~~~~~~~~~~~

You pay the “need a second machine” price, but that buys you
interactivity. Just log into the first machine from the second one,
using `ssh`.

Follow these steps:

 1. Attaching/Starting X from gdb.
 2. Displaying/saving a backtrace.

Needed packages
~~~~~~~~~~~~~~~

Obviously, `gdb` is needed; `xserver-xorg-core-dbg` contains the
debugging symbols for the server itself. Other needed packages can be
determined by looking at the backtrace. **FIXME: More info about
that.**


<<<
Actual gdb work
---------------

Getting a core file
~~~~~~~~~~~~~~~~~~~

 * Using `gdm3`: The idea is to tweak the daemon’s
   `LocalXserverCommand` setting, adding the `-core` option. As of
   `gdm3 2.30`, the defaults can be found in
   `/usr/share/gdm/gdm.schemas`. Sample `/etc/gdm3/daemon.conf`
   excerpt:

----
[daemon]
LocalXserverCommand=/usr/bin/Xorg -br -verbose -audit 0 -novtswitch -core
----

 * Using `kdm`: One should look for the `ServerArgsLocal` variable in
   the `/etc/kde4/kdm/kdmrc` file, and add `-core` there. Example:

----
ServerArgsLocal=-br -nolisten tcp -core
----

 * Using `xdm`: It’s sufficient to add `-core` to the command
   configured through `/etc/X11/xdm/Xservers`, for example:

----
:0 local /usr/bin/X :0 vt7 -nolisten tcp -core
----

Loading a core file
~~~~~~~~~~~~~~~~~~~

That’s trivial, one just needs to pass both the core file and the path
to the binary:

----
# gdb -c /etc/X11/core /usr/bin/Xorg
----

Now `gdb` is ready to display backtraces.

Attaching X from gdb
~~~~~~~~~~~~~~~~~~~~

The way of starting X doesn’t really matter, as `gdb` makes it
possible to attach a running process. If there’s a single X instance
running, that will do the job:

----
# gdb attach $(pidof X)
[---GDB starts---]
(gdb) handle SIGPIPE nostop
(gdb) cont
----

If there are several instances, one can use `ps aux` to determine the
PID of the appropriate instance (2nd column → `$pid`), and then attach
it:

----
# gdb attach $pid
[---GDB starts---]
(gdb) handle SIGPIPE nostop
(gdb) cont
----

Starting X from gdb
~~~~~~~~~~~~~~~~~~~

In case X crashes at start-up, one can start X from `gdb` in the
following way. In this example, the only parameter is the display, but
more parameters can be added.

----
# gdb --args Xorg :0
[---GDB starts---]
(gdb) handle SIGPIPE nostop
(gdb) run
----

What is SIGPIPE?
~~~~~~~~~~~~~~~~

`SIGPIPE` is a signal that can reach the X server quite easily,
especially when performing a VT switch, or refreshing large parts of
the screen. That’s why we ask `gdb` not to stop when such a signal is
caught, thanks to the `handle SIGPIPE nostop` command.

How to display a backtrace?
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Once X is crashed, for example because it received a `SIGSEGV`
(segmentation fault, usually because of a NULL pointer dereference),
or a `SIGBUS`, one gets back to the `gdb` prompt. One can then request
a backtrace (`bt`) or a full backtrace (`bt full`). The latter is what
developers are usually interested in, because variable values are also
available.

----
(gdb) bt
(gdb) bt full
----

How to save a backtrace?
~~~~~~~~~~~~~~~~~~~~~~~~

To save a recording of the gdb session to a file (`gdb.txt` by
default):

----
(gdb) set logging on
----

To save in a different file, use this instead:

----
(gdb) set logging file my-file.txt
(gdb) set logging on
----

Once logging is enabled, you can request a (full) backtrace using the
previous commands.
