emacs-gdb icon indicating copy to clipboard operation
emacs-gdb copied to clipboard

GDB graphical interface for GNU Emacs

  • GDB Graphical Interface for GNU Emacs This package provides a graphical interface to the GDB debugger. It is intended to be fast and intuitive.

[[file:assets/screenshot.png]]

It was made as a drop-in replacement for the builtin package [[https://www.gnu.org/software/emacs/manual/html_node/emacs/GDB-Graphical-Interface.html][gdb-mi]] (check [[#why-rewrite][this question]] for the reason behind rewriting the entire package from scratch).

** Features

  • Fast :: Instead of parsing the GDB/MI output in Elisp, I've created a [[https://www.gnu.org/software/emacs/manual/html_node/elisp/Dynamic-Modules.html][dynamic module]] in C, which makes it run fast like a bullet!

  • Easy to use :: The keybindings, which were inspired by Visual Studio and Qt Creator, were chosen to be easy to memorize and to provide the best interaction possible without much putting much strain on your fingers.

  • Does what you meant :: Each command tries its best to infer what you meant when you run them.

  • Organized :: You can change which buffer is displayed in each window, and even pop buffers to their own separate frames!

  • Simultaneous sessions :: You can debug multiple programs at the same time, with different GDB sessions; each session creates its own frame.

  • Debug remotely :: You may debug programs remotely over TRAMP!

*** List of special buffers

  • Threads

  • Stack frames

  • Breakpoints

  • Automatic variables

  • Watchers

  • Registers

  • Disassembly (of the selected stack frame)

  • Inferior I/O

  • GDB command shell (please read [[#gdb-commands][this question]] before going crazy!) ** Interested? Here's the quick-start guide! *** Dependencies

  • GCC or Clang to compile the dynamic module

    • The module is /automatically/ compiled as soon as possible
  • GDB (surprise, surprise) is needed to debug programs; I've only tested version 8.2, but will probably work on older ones

  • Emacs package Hydra is needed for the buffer switcher

*** Package installation This package intentionally uses the name ~gdb-mi~ in order to shadow the builtin package, as it could be confusing to have two packages with the same purpose installed.

The easiest way to install it is by using [[https://framagit.org/steckerhalter/quelpa][Quelpa]], which builds the packages for you from any source you want.

In order to install, give Quelpa the following package recipe: #+BEGIN_SRC emacs-lisp '(gdb-mi :fetcher git :url "https://github.com/weirdNox/emacs-gdb.git" :files (".el" ".c" "*.h" "Makefile")) #+END_SRC

It is highly recommended that you delete the autoloaded definitions from the builtin package in order to prevent confusion: #+BEGIN_SRC emacs-lisp (fmakunbound 'gdb) (fmakunbound 'gdb-enable-debug) #+END_SRC

Here is an example configuration using ~use-package~: #+BEGIN_SRC emacs-lisp (use-package gdb-mi :quelpa (gdb-mi :fetcher git :url "https://github.com/weirdNox/emacs-gdb.git" :files (".el" ".c" "*.h" "Makefile")) :init (fmakunbound 'gdb) (fmakunbound 'gdb-enable-debug)) #+END_SRC

You may also do everything manually or use another package manager that supports Git repos. Example for ~straight.el~: #+BEGIN_SRC emacs-lisp (use-package gdb-mi :straight (:host github :repo "weirdNox/emacs-gdb" :files (".el" ".c" "*.h" "Makefile")) :init (fmakunbound 'gdb) (fmakunbound 'gdb-enable-debug)) #+END_SRC

*** Smash those bugs! After the installation is complete, you may start a debugging session.

If you want to debug an executable, run ~gdb-executable~. You may also use this command to change the executable being debugged.

If you want another type of target, you may try running ~gdb-create-session~ and then inserting the commands manually in the shell buffer. I've not tested this, so I don't know how well it works.

** Default keybindings The main way to interact with this package is by using the global minor mode ~gdb-keys-mode~, which enables the usual keybindings you expect in a debugger, inspired by Visual Studio and Qt Creator:

| Keybinding | Description | |--------------------------------------+-------------------------------------------------------------------| | @@html:@@ F5 @@html:@@ | Run or continue | | @@html:@@ C-F5 @@html:@@ | (Re)Start and break at main | | @@html:@@ S-F5 @@html:@@ | Kill inferior | | @@html:@@ F6 @@html:@@ | Stop | | @@html:@@ F8 @@html:@@ | Create watcher | | @@html:@@ C-F8 @@html:@@ | Evaluate expression once | | @@html:@@ F9 @@html:@@ | Create or delete breakpoint | | @@html:@@ F10 @@html:@@ | Step over (instruction wise with @@html:@@M-@@html:@@) | | @@html:@@ C-F10 @@html:@@ | Run [[https://sourceware.org/gdb/onlinedocs/gdb/Continuing-and-Stepping.html#index-until][until]] cursor | | @@html:@@ F11 @@html:@@ | Step into (instruction wise with @@html:@@M-@@html:@@) | | @@html:@@ C-F11 @@html:@@ | [[https://sourceware.org/gdb/onlinedocs/gdb/Continuing-and-Stepping.html#index-advance-location][Advance]] to cursor | | @@html:@@ S-F11 @@html:@@ | Step out | | @@html:@@ F12 @@html:@@ | Switch buffer or pop to frame |

Nevertheless, even without the global minor mode, every buffer has some keybindings associated with it:

*** Threads buffer | Keybinding | Description | |------------------------------------+-----------------| | @@html:@@ SPC @@html:@@ | Select thread | | @@html:@@ c @@html:@@ | Continue thread | | @@html:@@ s @@html:@@ | Stop thread |

*** Stack frames buffer | Keybinding | Description | |------------------------------------+-----------------| | @@html:@@ SPC @@html:@@ | Select frame | | @@html:@@ c @@html:@@ | Continue thread |

*** Breakpoints buffer | Keybinding | Description | |------------------------------------------------------------------------------------------------------------+---------------------------| | @@html:@@ d @@html:@@ or @@html:@@ ⌫ @@html:@@ or @@html:@@ DEL @@html:@@ | Delete breakpoint | | @@html:@@ SPC @@html:@@ | Enable/disable breakpoint |

*** Automatic variables buffer | Keybinding | Description | |------------------------------------+-------------------------------------------------------------------------------------| | @@html:@@ SPC @@html:@@ | Create watcher (prompt with @@html:@@ Shift @@html:@@) | | @@html:@@ RET @@html:@@ | Create watcher and select window (prompt with @@html:@@ Shift @@html:@@) |

*** Watchers buffer | Keybinding | Description | |--------------------------------------------------------------------------+------------------------------| | @@html:@@ a @@html:@@ | Add new expression | | @@html:@@ RET @@html:@@ | Assign to expression | | @@html:@@ e @@html:@@ | Edit expression under cursor | | @@html:@@ f @@html:@@ | Change format | | @@html:@@ d @@html:@@ | Duplicate | | @@html:@@ h @@html:@@ | Toggle frame holding | | @@html:@@ t @@html:@@ | Toggle access specifiers | | @@html:@@ SPC @@html:@@ or @@html:@@ TAB @@html:@@ | Toggle children | | @@html:@@ ⌫ @@html:@@ or @@html:@@ DEL @@html:@@ | Delete watcher |

*** Registers buffer | Keybinding | Description | |------------------------------------+-------------------------------------------------------------------------------------| | @@html:@@ f @@html:@@ | Change format | | @@html:@@ SPC @@html:@@ | Create watcher (prompt with @@html:@@ Shift @@html:@@) | | @@html:@@ RET @@html:@@ | Create watcher and select window (prompt with @@html:@@ Shift @@html:@@) |

*** Disassembly buffer | Keybinding | Description | |----------------------------------+---------------| | @@html:@@ f @@html:@@ | Change format | | @@html:@@ F @@html:@@ | Change flavor |

** FAQ *** Why rewrite the already existing package that comes with Emacs? @@html:@@ :PROPERTIES: :CUSTOM_ID: why-rewrite :END: There are many things that led to my decision of rewriting ~gdb-mi~:

  • When I wanted to use it, I ended up having to modify and rewrite many functions in order to have predictable functionality

  • In some cases, the parsing would be so slow that I could not use it at all (when disassembling a big function and then stepping, for example)

  • It felt weird that it changed all my windows instead of opening in a new frame

  • Other reasons I've forgotten

  • I like C, Elisp, and a good challenge: I couldn't find a package that used dynamic modules and it seemed like the perfect chance to do something I would use, as I couldn't find a debugger for Linux that I could say I liked.

*** Why use this interface instead of [insert Linux graphical debugger here]? Well, if you use Emacs, both this and the builtin package are great because you never need to leave the environment you use the rest of the day.

If you don't use Emacs (but are willing to try it) and you can't find a good graphical debugger for Linux, this could be it!

If you are already happy with what you have, then there isn't much to see here. ☺

*** May I send custom GDB commands?@@html:@@ :PROPERTIES: :CUSTOM_ID: gdb-commands :END: You may send any GDB command you want.

/However/, keep in mind that if:

  • the command does not use the background form (eg. ~continue&~), it will block GDB until it finishes what it is doing, so you won't be able to interact with it! If you want to interrupt it, run ~comint-interrupt-subjob~ in the command shell buffer (bound to @@html:@@ C-c C-c @@html:@@).

  • the command does not cause GDB to notify the interface of the changes it made, the interface may become out of sync and start giving errors

** Other information

  • This package uses the library [[https://github.com/brasko/gdbwire][GDBWIRE]] for parsing the GDB/MI output.
  • The original Emacs GDB interface was my main inspiration, so thanks Nick Roberts!