Emacs provides a wrapper for various debuggers including GDB called the Grand Unified Debugger (GUD). I’ve tried it in the past but always run into lots of minor annoyances with the UI so I just use command line GDB instead. But recently I’ve being trying to adopt a more “Emacs native” workflow, including using EShell instead of a separate terminal window for Bash, Magit instead of command line git, ERC for IRC, etc. So let’s see if we can fix these GUD problems…

Basic configuration

(setq gdb-many-windows t
      gdb-use-separate-io-buffer t)

The default mode of GUD just creates a single window with the the normal GDB terminal. This doesn’t seem to offer much over running GDB directly. The “many windows” mode splits the screen into six separate windows showing the current source file, locals/registers, output, etc.

Source file opens in the wrong window

By default if you jump to a source file from e.g. the stack trace window it will open on top of the command input window (labeled “2” below) rather than the source file window “1”.

This seems to be “normal” behaviour, and there are loads of threads on Stack Overflow complaining about it but with no conclusive solution. E.g. see here or here.

The problem here is that GUD makes all the popup windows “dedicated” except for the command window. When you jump to a file it opens in the first non-dedicated window, which sort-of makes sense. The function that sets up the windows is called gdb-setup-windows so we can use Emacs’ “advice” system to hook this function and run some extra code afterwards to make the command window dedicated:

(advice-add 'gdb-setup-windows :after
            (lambda () (set-window-dedicated-p (selected-window) t)))

This works because gdb-setup-windows always leaves the command window selected when it finishes.

Quitting messes up the window configuration

How do you quit anyway? I think the correct way is just to run quit in the command window. But no matter how you quit GUD always messes up whatever window configuration you had before you opened it.

We can fix that by saving the window layout when we run M-x gdb by storing the layout into a register in gud-mode-hook. The gud-sentinal function runs when some event occurs on the inferior gdb process. We can hook that to restore the window state when the process exits.

(defconst gud-window-register 123456)
 
(defun gud-quit ()
  (interactive)
  (gud-basic-call "quit"))
 
(add-hook 'gud-mode-hook
          (lambda ()
            (gud-tooltip-mode)
            (window-configuration-to-register gud-window-register)
            (local-set-key (kbd "C-q") 'gud-quit)))
 
(advice-add 'gud-sentinel :after
            (lambda (proc msg)
              (when (memq (process-status proc) '(signal exit))
                (jump-to-register gud-window-register)
                (bury-buffer))))

I’ve bound C-q to gud-quit which send the quit command to GDB to save typing.