Thread overview | |||||||
---|---|---|---|---|---|---|---|
|
October 27, 2013 proposal(+working code): catch block callback before stack unwinds to allow attaching debugger | ||||
---|---|---|---|---|
| ||||
Attachments:
| currently, there's no way to execute some function attached to a specific 'catch block' right before unwinding the stack, after a thrown exception/error. The only thing we can do is set a custom Runtime.traceHandler, but this cannot depend on the catch block (and doing so for every catch block would hurt performance) This prevents attaching a debugger right before stack unwinding at the root of the program in the following scenario: ---- void fun(){ try{...}catch{...} // code that may throw and is usually caught in normal setting // occasionally some unusual exceptions/errors won't be caught } void call_debugger(){ //raise signal so we can attach a debugger } void main(){ try{ fun(); } catch(Throwable t){ // we want to call call_debugger after an uncaught exception lands here but before stack unwinds, because most information is lost after stack unwinds // the other catch blocks should be unaffected, in particular call_debugger should only be called before landing on this specific catch block } } ---- I've modified rt/deh2.d to allow it, it works great, but my implementation is hacky, and I'd like to poke the newsgroup for a better design: class ThrowableSpecialUnwinding : Throwable {...} void main(){ try{...} catch(ThrowableSpecialUnwinding t){ //callbackBeforeUnwinding is called right before unwinding stack and entering this block // it doesn't affect other catch blocks nor assumes anything about the caught exception which could be any Throwable. // I've cheated here so casting back auto real_t=cast(Throwable)cast(void*)t; } } extern(C) void callbackBeforeUnwinding(Throwable t){ call_debugger; //this could be calling a function pointer modifyable at runtime } The hacky part is here: in rt/deh2.d, I changed: if (_d_isbaseof(ci, pcb.type) ) to : bool isSpecial = pcb.type== ThrowableSpecialUnwinding.classinfo && _d_isbaseof(ci, Throwable.classinfo); if(isSpecial) callbackBeforeUnwinding(cast(Throwable) *h); if (_d_isbaseof(ci, pcb.type) || isSpecial) {/*will stack unwind here*/} |
October 27, 2013 Re: proposal(+working code): catch block callback before stack unwinds to allow attaching debugger | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timothee Cour | On Sunday, 27 October 2013 at 13:09:21 UTC, Timothee Cour wrote:
> The hacky part is here:
> in rt/deh2.d, I changed:
Haven't looked at the proposal in any detail yet, but keep in mind that rt.deh2 is only used by DMD. GDC and LDC use GCC's libunwind for exception handling on most platforms.
If the semantics of a feature are reasonable, it's probably possible to implement it on top of libunwind as well, but it's definitely something to keep in mind.
David
|
October 27, 2013 Re: proposal(+working code): catch block callback before stack unwinds to allow attaching debugger | ||||
---|---|---|---|---|
| ||||
Posted in reply to David Nadlinger Attachments:
| ideal syntax would be something along those lines: try{...} catch(SomeThrowableType e, &callback_before_unwinding){...} with callback_before_unwinding of type 'void function(Throwable t)' The semantics of which is: if 'e' is about to be caught in this particular catch block, call callback_before_unwinding(e) _before_ unwinding stack and entering catch block. Advantages are: * it allows one to, for example, attach a debugger before stack unwinds and entering this catch block * the debugger is only attached at that point, hence not making the regular program slower * it doesn't affect other catch blocks nor does it affect how exceptions/errors are thrown * it could even allow one to make speed up exception handling, by computing backtrace _only_ inside this callback_before_unwinding, so that usual exceptions (std.conv conversions etc) can be caught without any backtrace inside the main program while unusual unintended exceptions would be caught at the root and show proper stack trace. This saves a lot of time when debugging issues, at _zero_ cost in performance. Does libunwind allow that? Otherwise could it be adapted to do that? On Sun, Oct 27, 2013 at 6:27 AM, David Nadlinger <code@klickverbot.at>wrote: > On Sunday, 27 October 2013 at 13:09:21 UTC, Timothee Cour wrote: > >> The hacky part is here: >> in rt/deh2.d, I changed: >> > > Haven't looked at the proposal in any detail yet, but keep in mind that rt.deh2 is only used by DMD. GDC and LDC use GCC's libunwind for exception handling on most platforms. > > If the semantics of a feature are reasonable, it's probably possible to implement it on top of libunwind as well, but it's definitely something to keep in mind. > > David > |
October 28, 2013 Re: proposal(+working code): catch block callback before stack unwinds to allow attaching debugger | ||||
---|---|---|---|---|
| ||||
On 27 October 2013 23:43, Timothee Cour <thelastmammoth@gmail.com> wrote: > ideal syntax would be something along those lines: > > try{...} > catch(SomeThrowableType e, &callback_before_unwinding){...} > with callback_before_unwinding of type 'void function(Throwable t)' > > The semantics of which is: > if 'e' is about to be caught in this particular catch block, call > callback_before_unwinding(e) _before_ unwinding stack and entering catch > block. > > Advantages are: > * it allows one to, for example, attach a debugger before stack unwinds and > entering this catch block > * the debugger is only attached at that point, hence not making the regular > program slower > * it doesn't affect other catch blocks nor does it affect how > exceptions/errors are thrown > * it could even allow one to make speed up exception handling, by computing > backtrace _only_ inside this callback_before_unwinding, so that usual > exceptions (std.conv conversions etc) can be caught without any backtrace > inside the main program while unusual unintended exceptions would be caught > at the root and show proper stack trace. > > This saves a lot of time when debugging issues, at _zero_ cost in performance. > > Does libunwind allow that? Otherwise could it be adapted to do that? > GDB has 'catch throw' and 'catch catch' as convenient C++ breakpoint placeholders in the debugger. Can certainly implement them for D too. http://www.delorie.com/gnu/docs/gdb/gdb_31.html -- Iain Buclaw *(p < e ? p++ : p) = (c & 0x0f) + '0'; |
October 28, 2013 Re: proposal(+working code): catch block callback before stack unwinds to allow attaching debugger | ||||
---|---|---|---|---|
| ||||
Attachments:
| On Mon, Oct 28, 2013 at 12:08 AM, Iain Buclaw <ibuclaw@ubuntu.com> wrote: > On 27 October 2013 23:43, Timothee Cour <thelastmammoth@gmail.com> wrote: > > ideal syntax would be something along those lines: > > > > try{...} > > catch(SomeThrowableType e, &callback_before_unwinding){...} > > with callback_before_unwinding of type 'void function(Throwable t)' > > > > The semantics of which is: > > if 'e' is about to be caught in this particular catch block, call > > callback_before_unwinding(e) _before_ unwinding stack and entering catch > > block. > > > > Advantages are: > > * it allows one to, for example, attach a debugger before stack unwinds > and > > entering this catch block > > * the debugger is only attached at that point, hence not making the > regular > > program slower > > * it doesn't affect other catch blocks nor does it affect how > > exceptions/errors are thrown > > * it could even allow one to make speed up exception handling, by > computing > > backtrace _only_ inside this callback_before_unwinding, so that usual exceptions (std.conv conversions etc) can be caught without any backtrace inside the main program while unusual unintended exceptions would be > caught > > at the root and show proper stack trace. > > > > This saves a lot of time when debugging issues, at _zero_ cost in performance. > > > > Does libunwind allow that? Otherwise could it be adapted to do that? > > > > GDB has 'catch throw' and 'catch catch' as convenient C++ breakpoint placeholders in the debugger. Can certainly implement them for D too. > > http://www.delorie.com/gnu/docs/gdb/gdb_31.html > > I'm worried about that from performance standpoint: * that implies running the normal program execution while attached to a debugger, which would be slower * catch throw will stop at every thrown exception as opposed to the ones that are caught at a certain 'root' point. In what I suggested (and implemented for dmd), it has 0 performance penalty and only triggers when a thrown exception is caught in a particular location; debugger isn't attached during normal program execution. > -- > Iain Buclaw > > *(p < e ? p++ : p) = (c & 0x0f) + '0'; > |
Copyright © 1999-2021 by the D Language Foundation