How to debug a plug-in

Writing Gimp plug-ins is very easy, due to the simple but powerful structure of the API (applications programming interface) provided by The Gimp to plug-in developers. However, some people have had problems when attempting to debug plug-ins. This short tutorial tries to explain just how to do that, using the very fine GDB (the GNU debugger).

Why is it not obvious how to debug plug-ins?

When writing `normal', stand-alone programs, you simply have to use the -g option with gcc (or whatever option your compiler uses to enable compilation with debugging information). Using GDB, a typical debug sequence may be started as follows:

$ gdb someprogram
GDB is free software and you are welcome to distribute copies of it
 under certain conditions; type "show copying" to see the conditions.
There is absolutely no warranty for GDB; type "show warranty" for details.
GDB 4.14 (i486-slackware-linux), Copyright 1995 Free Software Foundation, Inc...

You can then easily start to debug your program by using GDB's "run" command. If you want, you can set breakpoints and such before you run the program, set up signal handlers, etc.

However, plug-ins are somewhat different beasts. It is very easy to debug stand-alone programs, because you actually launch them from GDB (i.e. you know exactly when they begin execution and such). However, plug-ins get started by The Gimp, not by you. So how do you debug them?

The power of GDB

GDB is a very powerful debugger. Among many other things, it lets you debug processes which are already running, and that's just what we need for debugging our plug-ins.

Let's say your plug-in is called foobar. First of all, make sure you have compiled it using gcc's "-g" option, or whatever options your compiler needs to produce debugging information.

For now, let's assume that your plug-in uses a dialog box to let the user set its parameters before doing its work. This is good, because the plug-in does not do anything while the dialog box is running (i.e. it is only after you click the OK button that the plug-in actually starts its interesting work). So we'll use that `pause' time to fire up GDB and tell it to `attach' to our already-running plug-in.

Start the foobar plug-in using the normal Gimp menus. If all goes well up to the dialog box creation (we'll assume that for now; later I will explain how to debug this kind of problems), you'll be shown the dialog box, and the plug-in will happily sit idle until you click the OK button. Now we have to figure out which running process corresponds to our plug-in. That's what the "ps" command is for, and by looking at it we'll know the PID (process-ID) of our plug-in:

$ ps
   67 v01 SW    0:00 (bash)
  342 v01 SW    0:00 (startx)
  346 v01 SW    0:00 (xinit)
  349 v01 S     0:02 /usr/openwin/bin/olvwm
  355 v01 SW    0:00 (olwmslave)
  357 pp0 SW    0:00 (bash)
  367 pp0 S     0:00 xclock -geometry 66x66+539-0 -padding 2
  368 pp0 S     5:16 procmeter
  370 pp0 S     0:00 xload -geometry 239x66+290-0 -scale 3 -update 2 -hl red -nolabel -jumpscroll 1
  371 pp0 S     0:42 emacs
  374 pp1 S     0:00 -bash
  383 pp2 S     0:00 -bash
  392 pp3 SW    0:00 (bash)
  401 pp4 SW    0:00 (bash)
  410 pp5 S     0:00 (bash)
  419 pp6 SW    0:00 (bash)
  428 pp6 S     0:00 xmixer
  430 pp0 S     0:31 netscape -install -geometry 1014x738+0+0
  628 pp5 S     0:02 ./gimp
  629 pp5 S     0:00 /home/quartic/gimp/plug-ins/foobar -gimp 6 5
  631 pp2 R     0:00 ps

From this output, we see that the foobar process' PID is number 629. Don't worry about those weird command-line parameters; they are used solely by the Gimp's API to set up the communications stuff between the plug-in and the Gimp.

Let's fire up GDB. On an xterm or similar, switch to the directory where your plug-in's source and binary reside. Now fire up GDB:

$ gdb foobar
GDB is free software and you are welcome to distribute copies of it
 under certain conditions; type "show copying" to see the conditions.
There is absolutely no warranty for GDB; type "show warranty" for details.
GDB 4.14 (i486-slackware-linux), Copyright 1995 Free Software Foundation, Inc...

GDB has only loaded the debugging information from the plug-in's binary; it has not run the plug-in. Now we will use GDB's "attach" command to do just that, to attach to a running process. This is one of the beauties of Unix and GDB; you do not have to be the parent process of another process to be able to debug it. You just have to be its owner. The plug-in's PID was 629, so we will use the following command:

(gdb) attach 629
Attaching to program `/home/quartic/gimp/plug-ins/plasma', process 629
0x50016ead in channels ()
The stuff in the last line may vary. The following things have happened. GDB has temporarily become the parent process of our plug-in, so that we can control its execution. Also, the running process of the plug-in has been stopped.

You can now set a breakpoint in your plug-in's main `work' function or whatever. For example, if that function is called do_foobar(), you could use

(gdb) break do_foobar
Breakpoint 1 at 0x8000d96: file foobar.c, line 180.

Now we have to resume execution of the plug-in's process (remember, it was stopped by GDB). Use GDB's "cont" command for this.

(gdb) cont

Now return to your plug-in's dialog box, configure its parameters, and click the OK button. GDB will stop the program when it reaches the do_foobar() function, at the point where we set the breakpoint. GDB will look more or less like this:

Breakpoint 1, do_foobar (input=0x800a000, output=0x800c000, turb=0) at foobar.c:180
180             gimp_image_area(input, &ix1, &iy1, &ix2, &iy2);

After that, you can use GDB's usual commands for stepping through your program, setting watchpoints, breakpoints, etc. When it has finished execution (or if it has crashed), GDB will tell you. Note that you don't have to fire up GDB every time you want to re-run the plug-in; you just have to use the "attach" command again, to attach to the appropriate process. Remember that if the binary file has changed (say, because of a recompilation), you'll have to reload it.

Debugging plug-ins before the dialog box

The above stuff is all you need to know to start debugging plug-ins which invoke dialog boxes (and you get them right). However, some plug-ins do not have dialog boxes (so you don't have an implied pause before the plug-in starts its work), or you actually want to debug the dialog box's creation process or your widget callback functions.

There are several methods to accomplish this. The easiest one is to insert a getchar() in the main() function of your plug-in, before everything else runs. When you invoke the plug-in from the Gimp, you won't see anything. You have to switch to the xterm from where you started the Gimp, and press a key so that your plug-in will continue its execution.

You can use that `pause' time to find about your plug-in's PID, fire up gdb, attach to the process, set up breakpoints, and use the "cont" command to let it continue. After that, switch to the xterm from where you started the Gimp and do press a key to let your plug-in continue.

Another way is to insert a sleep() in main() with a pause long enough to let you do all the GDB stuff. There are many ways to insert pauses in the plug-in's execution, but perhaps the most flexible is the getchar() one. Experiment.

Some plug-in programming tips

Here are some tips for when you are starting to develop Gimp plug-ins. Many people get surprised by some of these little details, so you have to be careful. You'll save some hours of debugging time, as well.

Send comments, bug reports, and other stuff to That's Federico Mena Quintero.

This page last updated: 1996/07/21 12:30:14