[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
How can I rethrow an error after recording a backtrace?
From: |
Clément Pit--Claudel |
Subject: |
How can I rethrow an error after recording a backtrace? |
Date: |
Thu, 4 Aug 2016 22:12:22 -0400 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.2.0 |
Hey emacs-devel,
The Emacs server doesn't print backtraces, so I'm trying to get these
backtraces myself and return them to the server. After some exploration, I
found about the debugger variable, and realized that I could actually force
code to break into the debugger regardless of handlers using debug-on-signal.
So far so good. Then I wrote the following "debugger"
(defun my-handle-error (&rest args)
(let (;; Prevent recursive error catching
(debugger #'debug)
(debug-on-quit nil)
(debug-on-error nil)
(debug-on-signal nil))
(pcase args
(`(exit ,retv) retv)
(`(error ,error-args)
(setq saved-backtrace (with-output-to-string (backtrace)))
(signal (car error-args) (cdr error-args))))))
And then I called my code as follows:
(let* (;; Make sure that we'll intercept all errors
(debug-on-quit t)
(debug-on-error t)
(debug-on-signal t)
(debug-ignored-errors nil)
;; Make sure debugger has room to execute
(max-specpdl-size (+ 50 max-specpdl-size))
(max-lisp-eval-depth (+ 50 max-lisp-eval-depth))
;; Register ourselves as the debugger
(debugger #'my-handle-error))
(my code here))
This was in part inspired by similar code in allout-widgets.el (although I
think that code never worked, since it calls signal with a non-list second
argument).
When running on an emacs server, though, this code doesn't work. That is, it
works fine the first time, but not on further invocations; so I stepped through
the code in GDB, and I understood that the issue was here:
if (
/* Don't try to run the debugger with interrupts blocked.
The editing loop would return anyway. */
! input_blocked_p ()
&& NILP (Vinhibit_debugger)
/* Does user want to enter debugger for this kind of error? */
&& (EQ (sig, Qquit)
? debug_on_quit
: wants_debugger (Vdebug_on_error, conditions))
&& ! skip_debugger (conditions, combined_data)
/* RMS: What's this for? */
&& when_entered_debugger < num_nonmacro_input_events)
{
call_debugger (list2 (Qerror, combined_data));
return 1;
}
(in maybe_call_debugger). The first time around the debugger is called, but not
the second time, because the `when_entered_debugger <
num_nonmacro_input_events` is false (on the first round it evaluates to -1 < 0,
and on the second one to 0 < 0). This reason for this clause was explained when
this code was written back in 1991:
/* The value of num_nonmacro_input_events as of the last time we
started to enter the debugger. If we decide to enter the debugger
again when this is still equal to num_nonmacro_input_events, then we
know that the debugger itself has an error, and we should just
signal the error instead of entering an infinite loop of debugger
invocations. */
static EMACS_INT when_entered_debugger;
The problem is that I'm running this code using emacsclient --eval '(error
"abc")', and so the num_nonmacro_input_events value never increases. I "fixed"
it this way:
(defun my-handle-error (&rest args)
(let (;; Prevent recursive error catching
(debugger #'debug)
(debug-on-quit nil)
(debug-on-error nil)
(debug-on-signal nil))
;; HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK ;;
(setq num-nonmacro-input-events (1+ num-nonmacro-input-events))
;; HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK ;;
(pcase args
(`(exit ,retv) retv)
(`(error ,error-args)
(setq saved-backtrace (with-output-to-string (backtrace)))
(signal (car error-args) (cdr error-args))))))
Is this going to have horrible consequences? If it is, could someone more
experienced point me to how I am supposed to capture a backtrace and then
rethrow an error? I can provide a full example if anyone wants to experiment
and finds this description incomplete.
Cheers,
Clément.
signature.asc
Description: OpenPGP digital signature
- How can I rethrow an error after recording a backtrace?,
Clément Pit--Claudel <=
- Re: How can I rethrow an error after recording a backtrace?, Clément Pit--Claudel, 2016/08/04
- Re: How can I rethrow an error after recording a backtrace?, Eli Zaretskii, 2016/08/05
- Message not available
- Re: How can I rethrow an error after recording a backtrace?, Eli Zaretskii, 2016/08/05
- Re: How can I rethrow an error after recording a backtrace?, Clément Pit--Claudel, 2016/08/05
- Re: How can I rethrow an error after recording a backtrace?, Eli Zaretskii, 2016/08/06
- Re: How can I rethrow an error after recording a backtrace?, Clément Pit--Claudel, 2016/08/06
- Re: How can I rethrow an error after recording a backtrace?, Eli Zaretskii, 2016/08/06
- Re: How can I rethrow an error after recording a backtrace?, Clément Pit--Claudel, 2016/08/06
- Re: How can I rethrow an error after recording a backtrace?, Eli Zaretskii, 2016/08/06
Re: How can I rethrow an error after recording a backtrace?, Stefan Monnier, 2016/08/05