Techniques to Debug Scheme GIMP Plug-ins
About
This describes several techniques for debugging Scheme plugins for the GIMP app.
This document is specific to debugging plugins in the Scheme language. You can also use techniques (with modifications) to debug plugins written in other languages.
Overview of the techniques
The techniques are:
- view logs of the ScriptFu system
- harness your plugin with “print” statements
- use a debugger on the plugin process
- harness the ScriptFu code itself
The first are easier, but give less information.
Start the GIMP app from a console/terminal
You should start the GIMP app from a terminal, for most of the debugging techniques. Messages appear in the terminal.
This is the notation we use to show a command typed into a terminal. The “>” is the terminal’s prompt.
> gimp
Unfortunately, on Linux, any messages, from both the GIMP app and plugins, appear interleaved in the terminal. The GIMP app and plugins are separate processes, and write to the same stdout/stderr streams.
Alternatively, you can use the GIMP app’s Error Console dockable. See “Debugging ScriptFu Using gimp-message.”
To see a few more messages about what GIMP is doing:
> gimp --verbose --stack-trace-mode always
View Logs
By viewing logs, you can see what the GIMP app and ScriptFu system were doing at the time of some exception.
Set an environment variable before starting the GIMP app:
> export G_MESSAGES_DEBUG=scriptfu
> gimp
This “turns on” printing of messages for the DEBUG level of logging. This is for the logging domain “scriptfu”. (It also happens to be the name of an executable.) You can use “all” to mean all logging domains, which might mean messages from the GIMP app, and even GLib and Gtk.
The last logged message is usually most pertinent to any exception.
Logs are not easy to understand unless you are familiar with internals of ScriptFu.
The ScriptFu system uses the logging feature of GLib. There are calls to the g_logging function in the ScriptFu source code. The calls specify a log level of INFO, DEBUG, WARNING, or CRITICAL. You can see the log for the DEBUG level by setting environment variables as above. Messages of WARNING and CRITICAL appear anyway; environment variables don’t suppress them.
Harness your plugin
“Harnessing” is putting special code for debugging (or performance monitoring) in a program’s source. Sometimes you leave the special code in the source, or you remove it when you are done debugging.
You can sprinkle your code with calls to Scheme functions that print messages:
- display or displayln
- write
- gimp-message
The display and displayln functions write to stdin/stderr streams.
(display "here\n")
(displayln "here2")
(Since GIMP v3; in GIMP v2, they did not write to a terminal. displayln adds a newline character. The print function is not in ScriptFu.)
The write function writes to the currently opened port (a Scheme concept.) You can open a port to a file and log to the file, which might be easier to read. (No example given here.)
See “Debugging ScriptFu Using gimp-message.”
Use a debugger
This is about using a debugger tool such as gdb. You must start the GIMP app in a terminal since the gdb tool reads and writes to the terminal (it’s a command line program.)
See “Debugging Plugins”, which applies to plugins written in any language. This describes specifics for Scheme plugins.
When you use a debugger, you can inspect execution of all parts of a program:
- the ScriptFu interpreter
- the wrapped TinyScheme interpreter
- GIMP library libgimp
- GLib libraries
The gdb debugger is not a “Scheme debugger” so it will not examine the Scheme source. You examine the underlying C source code. So this technique is more useful when you suspect a bug in ScriptFu or GIMP.
Plugins runs as a process separate from the GIMP app. Using a debugger on a separate process can require “attaching” the debugger to the already running process.
The details vary by style of plugin:
- old-style, installed to /scripts
- new-style, independently interpreted, installed to /plug-ins
The debugging steps are:
- start a terminal
- set environment variables
- start the GIMP app
- invoke your plugin by choosing its menu item in the GIMP app
- in the terminal, respond to gdb prompts
Generally, when debugging a Scheme plugin you don’t set breakpoints. Because you can only set breakpoints on functions in the ScriptFu interpreter and not on Scheme functions.
Instead, generally you wait for a fatal condition and then get a backtrace.
Ensuring a fatal condition enters the debugger
Often, a buggy plugin script either crashes hard or yields a WARNING or CRITICAL.
You can set environment variables so that WARNINGS and CRITICALS from the ScriptFu system or GIMP are fatal, and so that the debugger then gives a prompt. At which time you enter “bt” to get a stack trace.
> export G_DEBUG=fatal-warnings
> export G_DEBUG=fatal-criticals
These affect the logging system of GLib (used by GIMP.) Choose one of the two. Fatal warnings also means fatal criticals, but not vice versa.
Configuring debug info
An executable can be built with debugging info aka symbols. The debugging symbols let a debugger give more informative traces, with source code files and line numbers.
Formerly, the debugging information was contained in an executable file. Now the debugger can download debug info separately. You can set environment variables to point to debug info on the net. Here is an example for Ubuntu (for common packaged libraries such as GLib):
export DEBUGINFOD_URLS="https://debuginfod.ubuntu.com"
Old-style scripts installed to /scripts
We recommend you not write new plugin scripts in this style.
You must debug the process extension-script-fu, which serves all old-style scripts. The name of the executable file is “script-fu”.
> export GIMP_PLUGIN_DEBUG=script-fu
> gimp --stack-trace-mode always
OR
> export GIMP_PLUGIN_DEBUG_WRAP=script-fu
> export GIMP_PLUGIN_DEBUG_WRAPPER="gdb --args"
> gimp
The GIMP app starts the process extension-script-fu when GIMP starts (to query all the scripts.) You might then need to respond to gdb prompts; enter “r” to mean run. The process extension-script-fu stays running, within the debugger. Later, when you choose a menu item for the plugin, the debugger will prompt again (on an exception or breakpoint.)
New-style scripts installed to /plug-ins
You must debug the process of the independently interpreted plugin. You must specify the name of the executable file, the text file that has a shebang (in the first line “#!…”)
export GIMP_PLUGIN_DEBUG_WRAPPER="gdb --args"
export GIMP_PLUGIN_DEBUG_WRAP=test-sphere-v3.scm
The GIMP app starts the plugin process when you choose its menu item in the GIMP app. Then you will see the debugger’s prompt in the terminal. You might enter “r” to mean run, or some other command of the debugger.
Since a plugin is executed more than once, for query and run phases, you might need to enter “r” twice. It depends on whether you have changed the source file and thus whether GIMP queries the plugin file again.
Harnessing ScriptFu or GIMP or TinyScheme itself
You might suspect a bug in ScriptFu or TinyScheme or GIMP. Then you might involve GIMP developers. Or you can build GIMP yourself, and harness its code.
The TinyScheme interpreter embedded in ScriptFu has a trace facility. In other words, built-in logging. But it is rarely used. It reveals the very deep, internal workings of the “S expression” virtual machine in the innermost interpreter. (It even seems broken, since the innermost interpreter has not been changed for a long time, and the trace feature not maintained.)