* capturing backtraces
@ 2014-08-24 20:43 Nic Ferrier
2014-08-24 21:14 ` Nic Ferrier
0 siblings, 1 reply; 6+ messages in thread
From: Nic Ferrier @ 2014-08-24 20:43 UTC (permalink / raw)
To: emacs-devel
I want to capture the backtrace that was current at the time of an error
into a list, string or buffer.
Something like:
(condition-case err
(thing-that-causes-errors)
(error (setq saved-backtrace
(way-to-get-backtrace-from-error err))))
Where the function way-to-get-backtrace-from-error represents a function
that can get the backtrace from an error.
Anyone have a clue how I can do that?
I asked this question before and Stefan referred me to
macroexp--backtrace
(http://lists.gnu.org/archive/html/emacs-devel/2014-05/msg00268.html)
which uses backtrace-frame. That function doesn't seem to be able to get
the backtrace from the point of the error though:
(defun nic-error ()
(let ((x 1))
(error "MEH")))
(condition-case err
(nic-error)
(error (backtrace-frame 1)))
=> (nil condition-case err (nic-error) (error (backtrace-frame 1)))
that's not what I want at all, as you can see it grabs the current
backtrace of the currently executing stack.
We must be able to do this though because the debugger does it to
display the backtrace that happened to cause an error when we have
debug-on-error turned on.
Anyone?
Nic
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: capturing backtraces
2014-08-24 20:43 capturing backtraces Nic Ferrier
@ 2014-08-24 21:14 ` Nic Ferrier
2014-08-25 2:43 ` Samuel Bronson
2014-08-25 14:57 ` Stefan Monnier
0 siblings, 2 replies; 6+ messages in thread
From: Nic Ferrier @ 2014-08-24 21:14 UTC (permalink / raw)
To: emacs-devel
Nic Ferrier <nferrier@ferrier.me.uk> writes:
> (condition-case err
> (thing-that-causes-errors)
> (error (setq saved-backtrace
> (way-to-get-backtrace-from-error err))))
>
> Where the function way-to-get-backtrace-from-error represents a function
> that can get the backtrace from an error.
Aha. Something like this works:
(defun nic-error ()
(let ((x 1))
(error "MEH")))
(defvar nic-args nil)
(flet ((debug (&rest args)
(setq nic-args args)))
(condition-case err
(nic-error)
((debug error) "blah")))
It seems a bit odd having to specify the debugger to capture the
backtrace.
I guess I could make a new condition-case like macro that did this
routinely.
Wouldn't it be better to just grab the backtrace whenever an error
occurs and put it in a global or push it on to a global list?
Nic
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: capturing backtraces
2014-08-24 21:14 ` Nic Ferrier
@ 2014-08-25 2:43 ` Samuel Bronson
2014-08-25 14:57 ` Stefan Monnier
1 sibling, 0 replies; 6+ messages in thread
From: Samuel Bronson @ 2014-08-25 2:43 UTC (permalink / raw)
To: Nic Ferrier; +Cc: emacs-devel
> Wouldn't it be better to just grab the backtrace whenever an error
> occurs and put it in a global or push it on to a global list?
Yes. Yes it would.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: capturing backtraces
2014-08-24 21:14 ` Nic Ferrier
2014-08-25 2:43 ` Samuel Bronson
@ 2014-08-25 14:57 ` Stefan Monnier
2014-08-25 16:27 ` Nic Ferrier
1 sibling, 1 reply; 6+ messages in thread
From: Stefan Monnier @ 2014-08-25 14:57 UTC (permalink / raw)
To: Nic Ferrier; +Cc: emacs-devel
> (flet ((debug (&rest args)
> (setq nic-args args)))
Better bind the `debugger' variable.
> Wouldn't it be better to just grab the backtrace whenever an error
> occurs and put it in a global or push it on to a global list?
Depends what you mean by better: the normal representation of the
backtrace is transient (embedded in the C stack), so that would require
converting it to an Elisp list upon every call to Fsignal.
IOW, you'd have to pay for it all the time, even tho it's very rarely
used (as a percentage of the number of times Fsignal is called).
But we could probably arrange for something less hackish than rebinding
`debug'. Maybe a new debugger-extra-data-function which would be called
by Fsignal and whose return value would be added data to the condition
that's being signaled (so you'd receive it in the `err' variable of your
condition-case).
Stefan
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: capturing backtraces
2014-08-25 14:57 ` Stefan Monnier
@ 2014-08-25 16:27 ` Nic Ferrier
2014-08-25 20:13 ` Nic Ferrier
0 siblings, 1 reply; 6+ messages in thread
From: Nic Ferrier @ 2014-08-25 16:27 UTC (permalink / raw)
To: Stefan Monnier; +Cc: emacs-devel
Stefan Monnier <monnier@IRO.UMontreal.CA> writes:
> > (flet ((debug (&rest args)
> > (setq nic-args args)))
>
> Better bind the `debugger' variable.
>
>> Wouldn't it be better to just grab the backtrace whenever an error
>> occurs and put it in a global or push it on to a global list?
>
> Depends what you mean by better: the normal representation of the
> backtrace is transient (embedded in the C stack), so that would require
> converting it to an Elisp list upon every call to Fsignal.
>
> IOW, you'd have to pay for it all the time, even tho it's very rarely
> used (as a percentage of the number of times Fsignal is called).
>
> But we could probably arrange for something less hackish than rebinding
> `debug'. Maybe a new debugger-extra-data-function which would be called
> by Fsignal and whose return value would be added data to the condition
> that's being signaled (so you'd receive it in the `err' variable of your
> condition-case).
We could just have a variable to decide whether the signal should do
that or not.
A bit like binding the debugger variable, but not quite so extreme.
I will probably setq the debugger variable for now, to achieve what I
want.
But I think I still have to arrange for the condition-cases to have the
debug symbol, which means I have to write the code in a particular way
just for this reason.
Nic
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: capturing backtraces
2014-08-25 16:27 ` Nic Ferrier
@ 2014-08-25 20:13 ` Nic Ferrier
0 siblings, 0 replies; 6+ messages in thread
From: Nic Ferrier @ 2014-08-25 20:13 UTC (permalink / raw)
To: Stefan Monnier; +Cc: emacs-devel
Oh well.
I wrote this:
(defmacro try (form &rest body)
"Try FORM and eval BODY if it fails.
Within BODY `backtrace' will return the backtrace including the
stack which caused the problem. This can be used for actually
debugging the problem."
(declare (indent 1))
(let ((ret-var (make-symbol "ret-var")))
`(let* (,ret-var
(debug-on-error t)
(debugger
(lambda (&rest args)
(setq ,ret-var (progn ,@body)))))
(condition-case err
(setq ,ret-var (progn ,form))
((debug error)))
,ret-var)))
To be used like this:
(try
(something-that-causes-an-error)
(handle-the-error
possibly-doing
(with-output-to-string (backtrace))))
It's not perfect because the backtrace you get like that includes the
stuff after the debugger enters. It's slightly odd behaviour. If I
understand it correctly the debugger is entered directly from the
error. So the debugger appears to be a continuance (I don't mean a
Scheme continuation) of the stack which caused the error.
I wonder if I can repeatedly do this, if errors need to be properly
"quit" somehow.
I'll give it a go in marmalade, that's quite a stressful environment for
this sort of thing.
Nic
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2014-08-25 20:13 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-08-24 20:43 capturing backtraces Nic Ferrier
2014-08-24 21:14 ` Nic Ferrier
2014-08-25 2:43 ` Samuel Bronson
2014-08-25 14:57 ` Stefan Monnier
2014-08-25 16:27 ` Nic Ferrier
2014-08-25 20:13 ` Nic Ferrier
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).