gdb-mi is a package by Nick Roberts which makes Emacs use GDB/MI interface to talk with the GNU Debugger. gdb-mi is currently in Emacs trunk, replacing the old gdb-ui package in GNU Emacs.

GSoC 2009

«Emacs GDB/MI migration» is one of two Emacs-related projects which were accepted for GoogleSummerOfCode 2009 program.

The goal of this project is to migrate the GDB graphical interface in Emacs to completely use GDB’s Machine Interface (GDB/MI). This will make GDB support in Emacs more robust and will allow using of GDB features available only with MI.

The development is carried out by Dmitry Dzhus under mentorship of Nick Roberts.

See this package stats at Ohloh!

What's new?

This section provides an overview of new user-visible features implemented during Google Summer of Code. This draft serves as a base for updated section of the Emacs manual (see «GDB Graphical Interface»).

Note that the development version of GDB 7.0 is needed for this package to work (-thread-info command, non-stop debugging support).

Stateless debugging

With MI, the notion of «current thread» is not so important as it provides means to query information for any thread without actually selecting it. This means that much more current thread selection logic may be implemented in the frontend without relying on the internal state of the debugger.

It’s now possible to observe information for several threads simultaneously (in addition to buffers which show information for currently selected thread). Select threads buffer by clicking «Threads» button or using gdb-display-threads-buffer command. Now you can ask Emacs to show information for thread under point using these keybindings, either using the current frame or creating a new one:


(Typing C-h m in threads list buffer will also give you this list.)

When you create a buffer showing information about some specific thread, it becomes «bound» to that thread and keeps showing actual information while you debug your program.

Non-stop debugging

All-stop debugging
When one thread stops (hitting a breakpoint or recieving a signal), all threads stop.
Non-stop debugging
When one thread stops, the rest continue running.

Non-stop debugging is much less intrusive.

To activate non-stop mode, set gdb-non-stop-setting customization variables to t. Note that changing this while debugging a program has no effect.

By default, when a thread stops in non-stop mode, Emacs automatically switches to that thread.

It may be undesirable to let Emacs switch current thread when you already have some other stopped thread selected. Set gdb-switch-when-another-stopped to nil to prevent this.

Emacs can decide whether or not to switch to stopped thread depending on the reason which caused the stop. Customize gdb-switch-reasons to select stop reasons which make Emacs switch thread.

gdb-stopped-hooks hook variable allows you to execute your functions whenever some thread stops. For example:

(defun my-gdb-stopped-hook (record)
  (with-current-buffer (get-buffer-create "*debug-stop-log*")
     (format "%s stopped in %s (%s)\n"
             (gdb-get-field record 'thread-id)
             (gdb-get-field record 'frame 'func)
             (gdb-get-field record 'reason)))))

(add-to-list 'gdb-stopped-hooks #'my-gdb-stopped-hook)

In non-stop mode, you can switch between different modes for GUD execution control commands.

When gdb-gud-control-all-threads is t (that’s default), interruption & continuation commands apply to all threads, so you can halt or continue all your threads with one command (gud-stop-subjob and gud-cont, respectively). Go button is shown on the toolbar when at least one thread is stopped, whereas Stop button is shown when at least one thread is running.
Nil gdb-gud-control-all-threads value means that only current thread is stopped/continued. Go/Stop buttons on the GUD toolbar are shown depending on the state of current thread.

Stepping commands always apply to current thread.

Fine thread control

In non-stop mode, you can interrupt/continue your threads without selecting them. Hitting i in threads list buffer interrupts thread under point, c continues it, s steps through. More commands may be added in the future.

Note that when you interrupt a thread, it stops with «Signal received» reason. If that reason is included in your gdb-switch-reasons (it is by default), Emacs will switch to that thread.

Given that you can create bound buffers for any thread, this allows you to observe state of many threads in the same time.

See the annotated screenshot showing how Emacs works with non-stop GDB:

You can customize what fields are included in stack frames list and threads list by changing options in gdb-buffers customization group.

Development plan

The following has been done for gdb-mi.el during Summer of Code 2009.

Implemented buffers for:

  1. Threads
  2. Disassembly
  3. Program memory sections

Major goals:

  1. Made it possible watch information for several threads simultaneously
  2. Added non-stop debugging support

Internals (you don’t want to read this):

  1. Got closer to MVC (gdb-buf-publisher provides a cleaner way to ask buffers to update; we maintain gdb-breakpoints-list and gdb-threads-list; we’re still tied to «one buffer — one handler» model)
  2. Most of code now uses JSON parser instead of regular expressions to parse MI responses.
  3. Handle all MI async records

Related public discussions

Force gdb-mi not to set windows as dedicated

gdb-mi.el sets all its windows to be dedicated by default which means that if one tries to switch-buffer in one of gdb-mi.el’s dedicated windows the buffer will appear in a different window instead. This can be rather annoying, so here’s a quick fix using advice to override gdb-mi.el’s window dedication.

;; Force gdb-mi to not dedicate any windows
(advice-add 'gdb-display-buffer
	    :around (lambda (orig-fun &rest r)
		      (let ((window (apply orig-fun r)))
			(set-window-dedicated-p window nil)

(advice-add 'gdb-set-window-buffer
	    :around (lambda (orig-fun name &optional ignore-dedicated window)
		      (funcall orig-fun name ignore-dedicated window)
		      (set-window-dedicated-p window nil)))