4

Here's a common debugging scenario: I am investigating a failure and for whatever reason I cannot instrument the relevant code with edebug. I can, however, in most cases get a backtrace via toggle-debug-on-error, or debug-on-entry. In the backtrace, I can jump to code along the call stack, but how does one get the values or arguments or variables? Here's an simple example:

(define-error 'test-signal
  "Test signal" 'error)

(setq myvar 42)
(defun foo (arg)
  (signal 'test-signal '(1 2 3)))

(provide 'foo)

Now Imagine I have debug-on-error turned on, and do M-x eval (foo 123).

Once I'm in the debugger, what commands do I need to issue to see that the value of arg is 123 and of myvar is 42? debugger-eval-expression always seems to return "Symbol's value as variable is void".

Drew
  • 75,699
  • 9
  • 109
  • 225

1 Answers1

6

The backtrace looks like this:

  signal(test-signal (1 2 3))
  foo(123)
  (progn (foo 123))
  eval((progn (foo 123)) t)
  elisp--eval-last-sexp(t)
  eval-last-sexp(t)
  eval-print-last-sexp(nil)
  funcall-interactively(eval-print-last-sexp nil)
  call-interactively(eval-print-last-sexp nil nil)
  command-execute(eval-print-last-sexp)

For myvar, you can place the cursor on any line of the bactrace, type e and enter myvar in the minibuffer. The value is printed in the echo area. That is because myvar is global.

You can see directly that the argument of foo was 123. You can also use e to eval arg, but that will only work when you are inside the function foo, i.e. when you've selected the stack frame where signal is called. You select the stack frame by placing your cursor on that line. In any other stack frame, higher up the stack, the symbol arg is not bound to a value, so if you try to eval it you get "Symbol's value as variable is void".

The Emacs Lisp manual contains a chapter on debugging, with a section on the Lisp Debugger. The e command, along with many others, is described in the section Debugger commands. The chapter also contains information about other debuggers (like Edebug).

NickD
  • 27,023
  • 3
  • 23
  • 42
  • Ah, it wasn't entirely clear that just having the cursor on the relevant stack trace line places you in the correct context. Also not obvious is that while you can examine the code for `foo` by going to `foo`'s line and pressing RET, you need to go one line up in the backtrace to be able to eval the arguments you see. – Leo Alekseyev Jun 17 '20 at 23:41
  • Well, the link to the code can be unreliable (e.g. if you redefine a function). Also, think of the argument bindings as an implicit `(let ((arg 123)) )` around the body of the function. The stack frame where the function call appears is that of the caller of the function. The argument bindings "belong" to the stack frame of the execution of the function body (including the implicit `let` that binds the arguments). – NickD Jun 18 '20 at 03:31