Angus said:
The exception that is being raised in one of my applications I can
only catch by the unhlandled exception handler. But many functions
could have caused this exception. Just knowing I have an unhandled
excpetion doesn't help with debugging. I would ideally like to get
the line and file causing the exception? Is this possible? How can I
get more information so I can sned to log?
Well the most practical solution I see is to switch to Common Lisp
which has the ability to call the condition handlers in the dynamic
context of the condition.
AFAIK, in C++, you just lose.
What you could do, but of course it'll apply only to code of which you
may modify the sources, is to edit all the exception classes and all
the throw expressions to add __FILE__ and __LINE__ as parameter to the
exceptions.
Example: Two functions throwing an ERROR "exception" 1/10 of the time:
C/USER[14]> (defun f (n) (when (zerop (random 10)) (error "SIMPLE ERROR ~D" n)))
F
C/USER[15]> (defun g (n) (when (zerop (random 10)) (error "SIMPLE ERROR ~D" n)))
G
We call them with a dynamic handler:
C/USER[16]> (handler-bind ((error (lambda (condition) (invoke-debugger condition))))
(loop :for n :from 0 :do (f n) (g n)))
*** - SIMPLE ERROR 6
The following restarts are available:
ABORT :R1 Abort main loop
Ok, so which was it, F or G?
C/Break 1 USER[17]> :bt
<1/257> #<SYSTEM-FUNCTION EXT:SHOW-STACK> 3
<2/250> #<COMPILED-FUNCTION SYSTEM:

RINT-BACKTRACE>
<3/244> #<COMPILED-FUNCTION SYSTEM:

EBUG-BACKTRACE>
<4/235> #<SYSTEM-FUNCTION SYSTEM::READ-EVAL-PRINT> 2
<5/232> #<COMPILED-FUNCTION SYSTEM::BREAK-LOOP-2-3>
<6/228> #<SYSTEM-FUNCTION SYSTEM::SAME-ENV-AS> 2
<7/214> #<COMPILED-FUNCTION SYSTEM::BREAK-LOOP-2>
<8/212> #<SYSTEM-FUNCTION SYSTEM:

RIVER>
<9/172> #<COMPILED-FUNCTION SYSTEM::BREAK-LOOP>
<10/169> #<SYSTEM-FUNCTION INVOKE-DEBUGGER>
[168] EVAL frame for form (INVOKE-DEBUGGER CONDITION)
[153] APPLY frame for call

LAMBDA '#<SIMPLE-ERROR #x0003340A4D20>)
<11/149> #<FUNCTION :LAMBDA (CONDITION) (INVOKE-DEBUGGER CONDITION)> 1
<12/146> #<COMPILED-FUNCTION #:COMPILED-FORM-969>
<13/141> #<SYSTEM-FUNCTION SIGNAL> 1
<14/135> #<SYSTEM-FUNCTION ERROR> 2
[133] EVAL frame for form (ERROR "SIMPLE ERROR ~D" N)
<15/131> #<SPECIAL-OPERATOR WHEN>
[129] EVAL frame for form (WHEN (ZEROP (RANDOM 10)) (ERROR "SIMPLE ERROR ~D" N))
[114] APPLY frame for call (G '6)
Well this time it was G.
<16/110> #<FUNCTION G (N) (DECLARE (SYSTEM::IN-DEFUN G)) (BLOCK G (WHEN (ZEROP (RANDOM 10)) (ERROR "SIMPLE ERROR ~D" N)))> 1
[109] EVAL frame for form (G N)
<17/106> #<SPECIAL-OPERATOR PROGN>
[105] EVAL frame for form (PROGN (F N) (G N))
<18/93> #<SPECIAL-OPERATOR TAGBODY>
[92] EVAL frame for form (TAGBODY SYSTEM::BEGIN-LOOP (PROGN (F N) (G N)) (PSETQ N (+ N 1)) (GO SYSTEM::BEGIN-LOOP) SYSTEM::END-LOOP)
<19/85> #<SPECIAL-OPERATOR LET>
[83] EVAL frame for form (LET NIL (TAGBODY SYSTEM::BEGIN-LOOP (PROGN (F N) (G N)) (PSETQ N (+ N 1)) (GO SYSTEM::BEGIN-LOOP) SYSTEM::END-LOOP))
<20/74> #<SPECIAL-OPERATOR LET>
[72] EVAL frame for form (LET ((N 0)) (LET NIL (TAGBODY SYSTEM::BEGIN-LOOP (PROGN (F N) (G N)) (PSETQ N (+ N 1)) (GO SYSTEM::BEGIN-LOOP) SYSTEM::END-LOOP)))
[59] APPLY frame for call

LAMBDA)
<21/56> #<FUNCTION :LAMBDA NIL (PROGN (LOOP :FOR N :FROM 0

O (F N) (G N)))> 0
<22/50> #<COMPILED-FUNCTION #:COMPILED-FORM-969>
<23/51> #<SPECIAL-OPERATOR LOCALLY>
[50] EVAL frame for form (LOCALLY (DECLARE (COMPILE)) (SYSTEM::%HANDLER-BIND #:G10021 'ERROR #'(LAMBDA (CONDITION) (FUNCALL (FUNCALL #:G10020) CONDITION))))
<24/39> #<SPECIAL-OPERATOR LET>
[37] EVAL frame for form
(LET
((#1=#:G10020 #'(LAMBDA NIL (PROGN (LAMBDA (CONDITION) (INVOKE-DEBUGGER CONDITION)))))
(#2=#:G10021 #'(LAMBDA NIL (PROGN (LOOP :FOR N :FROM 0

O (F N) (G N))))))
(LOCALLY (DECLARE (COMPILE)) (SYSTEM::%HANDLER-BIND #2# 'ERROR #'(LAMBDA (CONDITION) (FUNCALL (FUNCALL #1#) CONDITION)))))
Printed 24 frames
C/Break 1 USER[17]>
Notice that since the handler is in the dynamic context of the
exception, it can _correct_ the problem, and return or "break" to a
sane situation so the processing may go on.