emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH]: Re: Early backtrace.


From: Alan Mackenzie
Subject: [PATCH]: Re: Early backtrace.
Date: Sun, 30 Jan 2022 11:07:32 +0000

Hello, everybody.

On Tue, Jan 11, 2022 at 09:47:34 -0500, Stefan Monnier wrote:
> >> I have a similar hack here for the same reason ;-)
> >> So a +1 from me (tho I'd recommend using the `debugger-` namespace
> >> rather than `early-`).

> > Thanks!  Maybe `debug-early' and `backtrace-early' would do for the two
> > functions?  There isn't really a debugger- prefix that early in the
> > bootstrap.

> Namespace prefixes don't need to be created before we use them.
> The point is just that `debugger-` is already used by definitions (in
> `debug.el`) so we can reuse that space instead of messing up pristine
> real estate.

OK, I've called it debug-early.

> > No, inside signal_or_quit, Vdebugger gets bound to Qdebug, so as to
> > bypass the setting made in ERT.  Also it is filtered out by checking for
> > not being in dump or bootstrap.  Instead, we should check Ffboundp
> > (Qdebug) || Ffboundp (Qdebug_early).  Not difficult to do.

> Oh, god, I didn't know (or forgot) about that horror.
> We should throw it out: your code should make it obsolete.
> E.g. we can take your new code as the default value of `debugger` and
> only replace it with `#'debugger` when an interactive frame
> is available.

debug-early.el installs itself as the debugger when it loads.  I've made
debug-early the dump routine used in batch mode.

I now have a patch ready.  It permits a Lisp backtrace to be created
early in the bootstrapping process.

It also fixes a bug in signal_or_quit (eval.c) where previously there
was:

      specbind (Vdebugger, Qdebug);

, which had the effect of binding the contents of Vdebugger (namely
Qdebug) to itself.  Correct would have been:

      specbind (Qdebugger, Qdebug);

, binding the symbol Qdebugger to Qdebug.

The patch loads lisp/emacs-lisp/debug-early.el as the first loaded by
loadup.el, and creates debug-early.el.

Are there any objections to me committing this to master?



diff --git a/lisp/loadup.el b/lisp/loadup.el
index 1be73a2090..81172c584d 100644
--- a/lisp/loadup.el
+++ b/lisp/loadup.el
@@ -128,6 +128,7 @@
 (set-buffer "*scratch*")
 (setq buffer-undo-list t)
 
+(load "emacs-lisp/debug-early")
 (load "emacs-lisp/byte-run")
 (load "emacs-lisp/backquote")
 (load "subr")
diff --git a/src/eval.c b/src/eval.c
index 6a8c759c1d..034f8bf6e4 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1893,18 +1893,19 @@ signal_or_quit (Lisp_Object error_symbol, Lisp_Object 
data, bool keyboard_quit)
     }
 
   /* If we're in batch mode, print a backtrace unconditionally to help
-     with debugging.  Make sure to use `debug' unconditionally to not
-     interfere with ERT or other packages that install custom
-     debuggers.  Don't try to call the debugger while dumping or
-     bootstrapping, it wouldn't work anyway.  */
+     with debugging.  Make sure to use `debug-early' unconditionally
+     to not interfere with ERT or other packages that install custom
+     debuggers.  */
   if (!debugger_called && !NILP (error_symbol)
       && (NILP (clause) || EQ (h->tag_or_ch, Qerror))
       && noninteractive && backtrace_on_error_noninteractive
-      && !will_dump_p () && !will_bootstrap_p ()
-      && NILP (Vinhibit_debugger))
+      && NILP (Vinhibit_debugger)
+      && !NILP (Ffboundp (Qdebug_early)))
     {
+      max_ensure_room (&max_lisp_eval_depth, lisp_eval_depth, 100);
+      max_ensure_room (&max_specpdl_size, SPECPDL_INDEX (), 200);
       ptrdiff_t count = SPECPDL_INDEX ();
-      specbind (Vdebugger, Qdebug);
+      specbind (Qdebugger, Qdebug_early);
       call_debugger (list2 (Qerror, Fcons (error_symbol, data)));
       unbind_to (count, Qnil);
     }
@@ -4421,6 +4422,7 @@ syms_of_eval (void)
   DEFSYM (Qclosure, "closure");
   DEFSYM (QCdocumentation, ":documentation");
   DEFSYM (Qdebug, "debug");
+  DEFSYM (Qdebug_early, "debug-early");
 
   DEFVAR_LISP ("inhibit-debugger", Vinhibit_debugger,
               doc: /* Non-nil means never enter the debugger.
@@ -4467,6 +4469,7 @@ syms_of_eval (void)
               doc: /* Non-nil means display call stack frames as lists. */);
   debugger_stack_frame_as_list = 0;
 
+  DEFSYM (Qdebugger, "debugger");
   DEFVAR_LISP ("debugger", Vdebugger,
               doc: /* Function to call to invoke debugger.
 If due to frame exit, args are `exit' and the value being returned;


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;;; debug-early.el --- Dump a Lisp backtrace without frills  -*- 
lexical-binding: t; -*-

;; Copyright (C) 2022 Free Software Foundation, Inc.

;; Author: Alan Mackenzie <acm@muc.de>
;; Maintainer: emacs-devel@gnu.org
;; Keywords: internal, backtrace, bootstrap.
;; Package: emacs

;; This file is part of GNU Emacs.

;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.

;;; Commentary:

;; This file dumps a backtrace on stderr when an error is thrown.
;; It has no dependencies on any Lisp libraries and is thus suitable
;; for generating backtraces in the early parts of bootstrapping.  It
;; is also good for generating backtraces in batch mode in general.

(defalias 'debug-early-backtrace
  #'(lambda ()
  "Print a trace of Lisp function calls currently active.
The output stream used is the value of `standard-output'.

This is a simplified version of the standard `backtrace'
function, intended for use in debugging the early parts
of the build process."
  (princ "\n")
  (mapbacktrace
   #'(lambda (evald func args _flags)
       (let ((args args))
         (if evald
             (progn
               (princ "  ")
               (prin1 func)
               (princ " (")
               (while args
                 (prin1 (car args))
                 (setq args (cdr args))
                 (if args
                     (princ " ")))
               (princ ")\n"))
           (while args
             (princ "  ")
             (prin1 (car args))
             (princ "\n")
             (setq args (cdr args)))))))))

(defalias 'debug-early
  #'(lambda (&rest args)
  "Print a trace of Lisp function calls currently active.
The output stream used is the value of `standard-output'.

There should be two ARGS, the symbol `error' and a cons of
the error symbol and its data.

This is a simplified version of `debug', intended for use
in debugging the early parts of the build process."
  (princ "\nError: ")
  (prin1 (car (car (cdr args))))        ; The error symbol.
  (princ " ")
  (prin1 (cdr (car (cdr args))))        ; The error data.
  (debug-early-backtrace)))

(setq debugger #'debug-early)

;;; debug-early.el ends here.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

>         Stefan

-- 
Alan Mackenzie (Nuremberg, Germany).



reply via email to

[Prev in Thread] Current Thread [Next in Thread]