Function: debug

debug is an autoloaded, interactive and byte-compiled function defined in debug.el.gz.

Signature

(debug &rest ARGS)

Documentation

Enter debugger. c (debugger-continue) returns from the debugger.

In interactive sessions, this switches to a backtrace buffer and shows the Lisp backtrace of function calls there. In batch mode (more accurately, when noninteractive is non-nil), it shows the Lisp backtrace on the standard error stream (unless backtrace-on-error-noninteractive is nil), and then kills Emacs, causing it to exit with a negative exit code.

Arguments are mainly for use when this is called from the internals of the evaluator.

You may call with no args, or you may pass nil as the first arg and any other args you like. In that case, the list of args after the first will be printed into the backtrace buffer.

If inhibit-redisplay is non-nil when this function is called, the debugger will not be entered.

View in manual

Probably introduced at or before Emacs version 1.2.

Key Bindings

Source Code

;; Defined in /usr/src/emacs/lisp/emacs-lisp/debug.el.gz
;;;###autoload
(defun debug (&rest args)
  "Enter debugger.  \\<debugger-mode-map>`\\[debugger-continue]' returns from the debugger.

In interactive sessions, this switches to a backtrace buffer and shows
the Lisp backtrace of function calls there.  In batch mode (more accurately,
when `noninteractive' is non-nil), it shows the Lisp backtrace on the
standard error stream (unless `backtrace-on-error-noninteractive' is nil),
and then kills Emacs, causing it to exit with a negative exit code.

Arguments are mainly for use when this is called from the internals
of the evaluator.

You may call with no args, or you may pass nil as the first arg and
any other args you like.  In that case, the list of args after the
first will be printed into the backtrace buffer.

If `inhibit-redisplay' is non-nil when this function is called,
the debugger will not be entered."
  (interactive)
  (if (or inhibit-redisplay
          (debugger--duplicate-p args))
      ;; Don't really try to enter debugger within an eval from redisplay
      ;; or if we already popper into the debugger for this error,
      ;; which can happen when we have several nested `handler-bind's that
      ;; want to invoke the debugger.
      debugger-value
    (setq debugger--last-error nil)
    (let ((non-interactive-frame
           (or noninteractive           ;FIXME: Presumably redundant.
               ;; If we're in the initial-frame (where `message' just
               ;; outputs to stdout) so there's no tty or GUI frame to
               ;; display the backtrace and interact with it: just dump a
               ;; backtrace to stdout.  This happens for example while
               ;; handling an error in code from early-init.el with
               ;; --debug-init.
               (and (eq t (framep (selected-frame)))
                    (equal "initial_terminal" (terminal-name)))))
          ;; Don't let `inhibit-message' get in our way (especially important if
          ;; `non-interactive-frame' evaluated to a non-nil value.
          (inhibit-message nil)
          ;; We may be entering the debugger from a context that has
          ;; let-bound `inhibit-read-only', which means that all
          ;; buffers would be read/write while the debugger is running.
          (inhibit-read-only nil))
      (unless non-interactive-frame
        (message "Entering debugger..."))
      (let (debugger-value
	    (debugger-previous-state
             (if (get-buffer "*Backtrace*")
                 (with-current-buffer "*Backtrace*"
                   (debugger--save-buffer-state))))
            (debugger-args args)
	    (debugger-buffer (get-buffer-create "*Backtrace*"))
	    (debugger-old-buffer (current-buffer))
	    (debugger-window nil)
	    (debugger-step-after-exit nil)
            (debugger-will-be-back nil)
	    ;; Don't keep reading from an executing kbd macro!
	    (executing-kbd-macro nil)
	    ;; Save the outer values of these vars for the `e' command
	    ;; before we replace the values.
	    (debugger-outer-match-data (match-data))
	    (debugger-with-timeout-suspend (with-timeout-suspend)))
        ;; Set this instead of binding it, so that `q'
        ;; will not restore it.
        (setq overriding-terminal-local-map nil)
        ;; Don't let these magic variables affect the debugger itself.
        (let ((last-command nil) this-command track-mouse
	      (inhibit-trace t)
	      unread-command-events
	      unread-post-input-method-events
	      last-input-event last-command-event last-nonmenu-event
	      last-event-frame
	      overriding-local-map
	      (load-read-function #'read)
	      ;; If we are inside a minibuffer, allow nesting
	      ;; so that we don't get an error from the `e' command.
	      (enable-recursive-minibuffers
	       (or enable-recursive-minibuffers (> (minibuffer-depth) 0)))
	      (standard-input t) (standard-output t)
	      inhibit-redisplay
	      (cursor-in-echo-area nil)
	      (window-configuration (current-window-configuration)))
	  (unwind-protect
	      (save-excursion
                (when (eq (car debugger-args) 'debug)
		  (let ((base (debugger--backtrace-base)))
		    (backtrace-debug 1 t base) ;FIXME!
		    ;; Place an extra debug-on-exit for macro's.
		    (when (eq 'lambda (car-safe (cadr (backtrace-frame 1 base))))
		      (backtrace-debug 2 t base))))
                (set-buffer debugger-buffer)
                (unless (derived-mode-p 'debugger-mode)
                  (debugger-mode))
                (debugger-setup-buffer debugger-args)
                (if non-interactive-frame
		    ;; If the backtrace is long, save the beginning
		    ;; and the end, but discard the middle.
                    (let ((inhibit-read-only t))
		      (when (> (count-lines (point-min) (point-max))
			       debugger-batch-max-lines)
                        (goto-char (point-min))
                        (forward-line (/ debugger-batch-max-lines 2))
                        (let ((middlestart (point)))
                          (goto-char (point-max))
                          (forward-line (- (/ debugger-batch-max-lines 2)))
                          (delete-region middlestart (point)))
                        (insert "...\n"))
		      (message "%s" (buffer-string)))
                  (pop-to-buffer
                   debugger-buffer
                   `((display-buffer-reuse-window
		      display-buffer-in-previous-window
		      display-buffer-below-selected)
		     . ((window-min-height . 10)
                        (window-height . fit-window-to-buffer)
                        ,@(when (and (window-live-p debugger-previous-window)
				     (frame-visible-p
				      (window-frame debugger-previous-window)))
                            `((previous-window . ,debugger-previous-window))))))
                  (setq debugger-window (selected-window))
		  (when debugger-jumping-flag
		    ;; Try to restore previous height of debugger
		    ;; window.
		    (condition-case nil
                        (window-resize
                         debugger-window
                         (- debugger-previous-window-height
			    (window-total-height debugger-window)))
		      (error nil))
		    (setq debugger-previous-window debugger-window))
                  (message "")
                  (let ((standard-output nil)
                        (buffer-read-only t))
		    (message "")
		    ;; Make sure we unbind buffer-read-only in the right buffer.
		    (save-excursion
		      (recursive-edit)))))
	    (when (and (window-live-p debugger-window)
		       (eq (window-buffer debugger-window) debugger-buffer))
	      ;; Record height of debugger window.
	      (setq debugger-previous-window-height
		    (window-total-height debugger-window)))
	    (if debugger-will-be-back
                ;; Restore previous window configuration (Bug#12623).
                (set-window-configuration window-configuration)
	      (when (and (window-live-p debugger-window)
                         (eq (window-buffer debugger-window) debugger-buffer))
                (progn
		  ;; Unshow debugger-buffer.
		  (quit-restore-window debugger-window debugger-bury-or-kill)
		  ;; Restore current buffer (Bug#12502).
		  (set-buffer debugger-old-buffer)))
              ;; Forget debugger window, it won't be back (Bug#17882).
              (setq debugger-previous-window nil))
            ;; Restore previous state of debugger-buffer in case we
            ;; were in a recursive invocation of the debugger,
            ;; otherwise just exit (after changing the mode, since we
            ;; can't interact with the buffer in the same way).
	    (when (buffer-live-p debugger-buffer)
	      (with-current-buffer debugger-buffer
                (if debugger-previous-state
                    (debugger--restore-buffer-state debugger-previous-state)
                  (backtrace-mode))))
	    (with-timeout-unsuspend debugger-with-timeout-suspend)
	    (set-match-data debugger-outer-match-data)))
	(when (eq 'error (car-safe debugger-args))
	  ;; Remember the error we just debugged, to avoid re-entering
          ;; the debugger if some higher-up `handler-bind' invokes us
          ;; again, oblivious that the error was already debugged from
          ;; a more deeply nested `handler-bind'.
	  (setq debugger--last-error (nth 1 debugger-args)))
        (setq debug-on-next-call debugger-step-after-exit)
        debugger-value))))