Debugging Elisp is sometimes tricky. Some time ago I had an issue with a variant of
show-paren-mode. The issue looked like a complete hang of Emacs, when even
C-g didn’t help. How to debug that?
Of course, I could instrument a few functions for Edebug (which I eventually did anyway). However, a situation when Emacs repeatedly hangs is at least annoying. Of course, one can start a separate Emacs process (and that’s also what I did) and kill it when needed, but it is good to know that that wasn’t the only possibility.
It is not a very well-known thing, but sending Emacs a SIGUSR2 signal is a stronger way than
C-g to tell Emacs to stop whatever it is doing. As the manual says (see
(info "(emacs) Checklist")):
If you cannot get Emacs to respond to ‘C-g’ (e.g., because ‘inhibit-quit’ is set), then you can try sending the signal specified by ‘debug-on-event’ (default SIGUSR2) from outside Emacs to cause it to enter the debugger.
It turned out that my function looking for the matching delimiter was waaay to slow, and in case of a mismatch took more than 10 seconds to complete. So it wasn’t a hang after all – but
C-g apparently didn’t help, since the function was being called after
It also turned out that after feeding Emacs the SIGUSR2 signal,
C-g started to “work”, i.e., it did stop after the apparent hang. Why was that so?
Apparently, sending SIGUSR2 to Emacs somehow triggered the change of
debug-on-quit to t. With that turned on,
C-g moved the point away from the place where my code repeatedly tried to find the (nonexistent) matching delimiter to the
*Backtrace* buffer, and Emacs started responding normally.
Investigating this further, one can find out more debugging knobs. The function
toggle-debug-on-quit toggles the behavior I described above. Its cousin
toggle-debug-on-error is very useful when something triggers an error and you don’t know what it is (which happens quite often). It shows a
*Backtrace* buffer whenever there is an error, and you can see exactly what called what and with what arguments. Way more useful than
Edebug in some cases.
But wait, there’s more! If you do
M-x apropos-variable RET debug-on
RET, you’ll see quite a few potentially useful things. (And
apropos-command RET debug-on RET is left as an exercise to the reader!)
One of them I didn’t know about is
debug-on-message. You can set it to a regex, and any call to
message with the message matching it will trigger the display of
*Backtrace*. This might be especially handy in case of something displaying a message which you have no idea where it comes from. (I had such a problem, with a mysterious “Mark set” being displayed in the echo area. If only I knew about this variable then… Happily, I managed to solve that problem in a bit different way – but that’s another story!) The last thing worth mentioning in this department is the
--debug-init command-line switch. If you have some error on Emacs startup and you don’t know why, this is the simplest way to find its cause. (Another one, more involved, but also potentially useful and extremely cool, is to use Artur Malabarba’s Emacs Bug Hunter. Check it out!)