I wonder if there a world record for the longest description of a one
line patch. I'll describe the problem....
For most systems GCC uses the exception handling strategy documented
here: http://www.codesourcery.com/public/cxx-abi/
This strategy tries to find an exception handler firstly "in frame";
if none is found, it unwinds the stack until it finds a handler that
can handle the exception. If it cannot find an exception handler
anywhere in the stack, it calls std::terminate. This checks to see if
there is a custom "default handler" and if found, executes that. If it
cannot find a custom "default handler", or when a custom handler
returns, std::abort is called and the process exits subsequent to
being delivered a SIGABRT. That is a gross simplication of the
sequence, but that is the basic strategy. In the normal execution of a
process, this is sane and correct - if there is no handler for an
exception anywhere in the stack, there is little else than can be
done. However in the artifically constructed environment of the
debugger controlling the inferior, it can become problematic in some
situations. Inferior function calls are one of the situations where
this becomes problematic.
In GDB inferior function calls are very common. For example:
(gdb) print foo()
Will print the result (return value) of that function. To do that GDB
must create an inferior function call that executes the function in a
dummy frame. This isolated and dummy frame is problematic as it cannot
be unwound (moving up the stack) beyond the dummy frame.
If an exception is generated by foo() when the function is being
executed in the inferior function call, and it does not happen to have
an in-frame exception handler, the whole inferior is (wrongly)
terminated. This is because any out-of-frame exception handler that
usually handles exceptions in function foo() and are normally "up" in
the stack will not be considered. The inferior is terminated as
detailed above, has to be restarted, and brought back to state by the
(probably frustrated) user. This is wrong in my opinion. It is
perfectly legal to have a function handler out-of-frame, and in normal
execution it would be found and handled; but the artificial
environment constructed around the frame for the purpose of the
inferior function call "fools" the unwinder and terminates the inferior.
There is a flag in GDB named: "unwindonsignal" that is currently set
to "off". This flag tells the inferior function call code that *if* a
signal is delivered to the inferior during an inferior function call,
to unwind the stack to the state before the dummy frame was completed.
This restores the state of the inferior as if the inferior function
call (for all intents and purposes,) did not happen. This does not fix
the exception issue - out-of-frame exception handlers are still not
found when a dummy frame is created. But it does fix the worst
complications and does not terminate the inferior.
I propose via this patch that we set the flag to "on" as default. It
can always be turned off if the user desires it. Defaulting to "on"
will improve the C++ user experience. A longer term approach would be
as Daniel suggested: a command to restore the frame and clears the
signal "after the fact" if the user wants to do so. This is longer
term, but equally valid. Another alternative would be to leave
"unwindonsignal" off, create an internal breakpoint in
std::terminate, and if that "triggers" unwind (perhaps with a flag
"unwindonterminate" gating the feature).
Regards
Phil
2008-09-17 Phil Muldoon <pmuldoon@redhat.com>
* infcall.c: Set unwind_on_signal_p to 1
by default.