Skip to content

How to add a new debugger

rocky edited this page Dec 4, 2017 · 43 revisions

Here are the steps to add a new debugger.

Table of Contents

Do I have the prerequisites?

If you want realgud to track source location when the debugger is paused for input, it needs to know:

  1. when the program is stopped for input
  2. the source code location is it is stopped at

Other information that his helpful includes:

  • when a breakpoint is added, removed, changed
  • what a backtrace looks like

realgud uses regular expressions to parse output strings to pick out information. These regular expressions are defined in an initialization file called init.el; this is located below a directory with the debugger name. For example, for the lldb debugger under the github project realgud-lldb, the initialization file with the regular expression definitions is realgud-lldb/lldb/init.el.

Continuing to use lldb as an example debugger, when that debugger is stopped for input, its prompt starts on a new line. It's prompt looks like

(lldb)

Other debuggers however can vary the prompt a bit more. For the bash debugger prompts can look similar to one of the lines below:

bashdb<(1)>
bashdb<10>
bashdb<<2>>

Somewhere before that prompt, you should see a line that describes where the program is stopped. That usually includes a file name and a line number. There might also be a column number. I supposed a byte offset from the beginning of the file will do as well. For bashdb, this might take the form of something like:

(/etc/init.d/apparmor:35):

Clone a similar realgud-related code

We are going to use as a template the realgud-lldb code, and the new debugger I am going add is one for maxima.

To clone the code: git clone git://github.com/realgud/realgud-lldb.git realgud-maxima.

Make sure realgud and forked code works

See install instructions to see that it works. You don't actually have to install the code to develop from it, but you should make sure that it works. realgud uses a couple of other packages; so those emacs packages have to be installed.

But realgud does not have to be installed per se. I generally run the code directly from the development directory.

Modify Debugger Files

  • Under the directory you cloned, e.g. realgud-lldb, will be a directory with the suffix, e.g. lldb. Change that to your new name, e.g. maxima.
  • There will also be a elisp file with the .el suffix the same name as the directory. e.g. realgud-lldb.el Change that as well.
  • There may be some tests in the tests directory that have the old debugger name in them. Change those files as well.

For concreteness, in the example below I will use the Maxima debugger maxima copied from lldb debugger lldb:

$ OLD_NAME=lldb
$ NEW_NAME=maxima
$ git clone git://github.com/realgud/realgud-${OLD_NAME}.git realgud-$NEW_NAME
$ cd realgud-$NEW_NAME
$ git mv $OLD_NAME $NEW_NAME
$ git mv realgud-${OLD_NAME}.el realgud-${NEW_NAME}.el
$ git mv ${NEW_NAME}/${OLD_NAME}.el $NEW_NAME/${NEW_NAME}.el
$ git mv test/test-regexp-${OLD_NAME}.el test/test-regexp-${NEW_NAME}.el

Above I copied from lldb, but if there is another debugger that is similar to your new one, you might want to use that one instead. If not but there is another supported debugger for the same programming language, that might also be a good starting point. If there's not a debugger for the same programming language but a similar programming language, I'd suggest using that. For example, C and C++ are similar. As a last resort, debuggers for dynamic interpreted languages like Perl, Python, Ruby, POSIX shell (bash, zsh, ksh), or JavaScript work very differently from static compiled languages like C, C++, Go, or Java. If your debugger is for the former camp, start out with realgud-lldb. If it is in the latter camp, start out with realgud-pry.

Since we are copying from lldb, and that debugs C programs, you will find in test/lldb some C files. You will want to change those examples.

Note: Every file in the debugger you should be able to eval inside Emacs and it will pull in other files that it needs.

Separate Programming Language from Debugger?

If there are several debuggers for a programming language you might want to split out programming language things from debugger-specific things. This is done in realgud/realgud/lang.

Modify contents of the Elisp files

In the example above, the new debugger I was using is maxima and I copied from the lldb debugger project. So let's continue with that.

In the files just copied, Change all occurrences of 'lldb' to 'maxima' (inside GNU Emacs of course).

Special Customizations to Pay Attention To

The file init.el has regular expressions that are specific to debugger output. When a "comint" process sees one of these strings, some action may trigger. For example, when it sees a source location, it my cause that source to appear in another Emacs window. Therefore, by far this is the most important file to pay attention to. There is a special section for file init.el below.

In core.el there is a -parse-cmd-args function that is used to build a command line to invoke the debugger. What's tricky here is that we have to separate options that might be for the debugger from those that might be for the program. And we need to pick out the script name.

Customize file init.el

Most of init.el are regular expressions for matching output. The regular expressions are stored in a buffer-local variable called realgud-xxx-pat-hash where xxx is the name of the debugger. For example, for lldb, the variable name is realgud-lldb-pat-hash.

One can (and should!) start with a minimal number of definitions in this hash. Later, add more. The two most critical are:

  • loc — a regular expression that describes a location in the source code you are
  • prompt — regular expression that describes a command prompt

There is another import hash table called realgud-xxx-command-hash. This has a mapping of standard realgud debugger commands to the specific debugger commands

For a list of key/command names that could go in that command-hash, see realgud-cmd:default-hash defined in realgud/common/send.el. In general we use the gdb name as the standard name. For example, for the "step in" debugger concept we use "step", for the "step over" debugger concept we use "next".

Also see the comments in an existing init.el file for more hash keys and what they control.

An interactive way that I use to test regular expressions is to go in the *scratch* buffer and use the string-match function. For example to test the maxima prompt, I would evaluate:

(string-match "^(dbm:[0-9]+) " "(dbm:1) ")

But having put in the mental effort to come up with these kinds of example, one should capture this in a test that gets run regularly.

There is usually a test program just for the regular expressions. This is done in directory tests. For debugger maxima this file would be called realgud-maxima/test/test-regexp-maxima.el.

The simple test framework test-simple allows you to evaluate the buffer inside to run the buffer as well as run it in a batch emacs. And you can evaluate pieces via eval-last-expression inside the file as well as inside Emacs's **scratch** buffer. I sometimes use the scratch buffer to set up variables.

Customize file core.el

There are a few ways in which a debugger can get called, and largely this module has to accommodate those ways.

Sometimes, the debugger is separate from the programming language it debugs, such as in gdb, and sometimes it integral to the programming language system and is simply a flag, such as in remake.

Often there is a filename-like parameter in the invocation that serves as the thing you want to debug, but sometimes especially in remote debugging, there is no name. The filename parameter, realgud uses in naming of the buffer process when applicable.

These issues come into play in customizing the functions realgud:xxx-parse-args and realgud:xxx-suggest-invocation. (The xxx is replaced with the debugger name you are working on.)

The suggest-invocation routine's job is to suggest a command that will have a debugger invoked. When there is a filename-like object that needs to be specified, it then has the task of finding a reasonable name to suggest. That name can come from files that look debuggable, i.e. are in a particular programming language suitable for the debugger. Or it can come from buffers that you are editing. In the case that there is no specific file object to debug, the suggest-invocation routine should know this, and just suggest the name of the system. For example, for "maxima" the suggested invocation is simple "maxima " with a space at the end to make it easy for a user to add her own additional options.

Somewhat related is the parse-args routine. Its job is to take a command invocation and categorize the parts of it:

  • the program to invoke and its command arguments, which may include a debug flag. Is the program name a reasonable name for this kind of debugger? For example, for "gdb" the name should have "gdb" in the invocation.
  • the program that is getting debugged and its command arguments, if relevant
  • any flags which might affect realgud, e.g. is this a remote debug session, or are needed additional annotation switches allowed by say gdb given?

configure and Makefile

In Makefile.am your debugger subdirectory should already be listed in SUBDIRS Makefile variable as a result of changing file content above. You might want to double check though:

Here is an example for maxima:

SUBDIRS = maxima

Recreate a configure script using the autoreconf command, and then gen a newly-generated Makefile created for your new debugger directory. There is however a shell script called autogen.sh that does this for you:

$ $SHELL ./autogen.sh
autoreconf: Entering directory `.'
...
Running configure with --enable-maintainer-mode
...
config.status: creating test/Makefile

Test

Some may say that this step is out of order and that you should have writing the tests in conjunction with or even before you were modifying the code.

Either way, writing tests can save you time and hassle. And this is just as true in working with GNU Emacs Lisp as it would be in any other programming language.

Furthermore, that for the most part you can just cut and paste existing tests that I have written for some other debugger.

Share back!

Having made changes, at some point you'll probably want push that back to github or git. If github, create a new project. Then run

$ PROJECT='your project' # e.g. git@github.com:realgud/realgud-maxima.git
$ git remote set-url origin $PROJECT
$ git push -u origin master

After everything works, if you have a github account please send back merge request. Maybe you'll just have better tests than the existing ones. That's cool too!

For a new debugger, Melpa packaging may need adjusting for the new files. See melpa/recipes/realgud . Finally the wiki entry Debuggers Supported will need updating for the new debugger.