7.6.3 Using a Debugger (EDebug)

Another way is to use the ELisp Debugger, EDebug. This allows you to see the exact steps the DSL evaluator goes through in executing a traversal and the effects it has on the code, and can be helpful if you want to understand why a traversal isn’t doing what you think it should be doing, or even if you just want to understand how the DSL works! A good debugger isn’t just for debugging problems, it’s also an exploratory tool for quick feedback at the creative stage when you’re implementing new functionality. It can help you be more efficient at every stage of development.

To use it, first evaluate the relevant traversal evaluator (for instance, the symex-eval function) for debugging by placing point somewhere within it and then invoking M-x edebug-defun (a convenient keybinding for this, e.g., via a Hydra, is recommended). Now, if you execute a traversal (e.g., via the REPL as in the recipe above, or with a test expression in the Scratch buffer, or even just by invoking the relevant feature on source code while in Symex mode), it will put you in the debugger and allow you to step through the code. Handy commands for EDebug:

There are also lots of other features like setting and unsetting breakpoints (b and u), seeing a backtrace (d), evaluating expressions in the evaluation context (e), and lots more, making it an indispensible tool for ELisp debugging.

When you’re done debugging, you can remove the debugger hooks by just evaluating the debugged functions in the usual way (e.g. via M-x eval-defun or M-x eval-buffer).

Also see this series on ELisp debugging for more tips.