archer-pmuldoon-exception-rewind quick demo script
Phil Muldoon
pmuldoon@redhat.com
Tue Jan 13 15:23:00 GMT 2009
Someone asked us to write up demo instructions for our own merged
branches at the last meeting. Here are mine with a bit of a narrative
for the features addressed in the
origin/archer-pmuldoon-exception-rewind branch.
* Build and set-up:
Check out the demo branch. Configure and build it. I built my GDB
out-of-tree, so for the purposes of this demo the base binary directory
is: "demo_obj".
When the GDB build is done, build the test inferior. It is already in
the source tree. Here is how I built it:
[pmuldoon@localhost demo_obj]$ g++ -g3 -O0
../archer/gdb/testsuite/gdb.cp/gdb2495.cc -o gdb2495
And start the freshly built GDB with the test inferior.
[pmuldoon@localhost demo_obj]$ ./gdb/gdb gdb2495
* Old behaviour:
To demonstrate the old non-patched behaviour first turn off the "unwind
on unhandled exception" flag.
(gdb) set unwind-on-terminating-exception off
Next break at main, and then run:
(gdb) b main
(gdb) r
Breakpoint 1, main () at ../archer/gdb/testsuite/gdb.cp/gdb2495.cc:76
76 exceptions.raise_signal (-1);
Now if we try to print a function that has a "throw" statement but no
in-frame handler, things go badly wrong:
(gdb) p exceptions.throw_function()
terminate called after throwing an instance of 'int'
Program received signal SIGABRT, Aborted.
0x000000378c632f05 in raise () from /lib64/libc.so.6
The program being debugged was signaled while in a function called from GDB.
GDB remains in the frame where the signal was received.
To change this behavior use "set unwindonsignal on".
Evaluation of the expression containing the function
(SimpleException::throw_function()) will be abandoned.
Let's try to step from where we were before we asked for that function
to be printed.
(gdb) s
Single stepping until exit from function raise,
which has no line number information.
Program terminated with signal SIGABRT, Aborted.
The program no longer exists.
That's not very nice! All I wanted GDB to do was print the output of the
function and things went badly wrong. As it is, the inferior has been
terminated and our abortive GDB debug session is at and end. If we look
at the contents of the function, it is perfectly normal and legal:
void throw_function ()
{
throw 1;
}
It threw an exception, but did not handle it. In the normal flow of
code this exception is handled in another frame. But in the confines of
the inferior function call and its dummy-frame, all opportunity to find
the matching exception-handler has been denied. The unwinder throws up
its proverbial hands and terminates the process. But this is not
"normal". Normally, and in this inferior's example, this code works
fine when it is run or stepped to completion. It is just the inferior
function call creating a bogus environment, that "fools" the unwinder
that results in its termination.
In my opinion - and probably many others - inferior function calls
should never result in the termination of the inferior. Legal or not,
horrible or not, the function call should safeguard the inferior. This
patch addresses one dimension of that.
* New "patched" behaviour:
In the case above, if the user had set "unwindonsignal" to "on", the bad
frame would have been "popped" and control restored to the point just
before the inferior function call. But "unwindonsignal" is set to "off"
by default. Setting this to "on" by default is not desirable. (This
thread here references why:
http://sourceware.org/ml/archer/2008-q3/msg00199.html)
So what this branch achieves is to detect the sequence where an
unhandled exception is about to terminate the application. This is gated
by the behaviour of the "unwind-on-terminating-exception" flag, which
defaults to on. When it detects this behaviour it prevents the
termination, pops the dummy-frame and restores control to the inferior.
Lets restart the application
(gdb) r
Breakpoint 1, main () at ../archer/gdb/testsuite/gdb.cp/gdb2495.cc:76
76 exceptions.raise_signal (-1);
Set the patched behaviour to "on"
(gdb) set unwind-on-terminating-exception on
And try printing the result from that function again.
(gdb) p exceptions.throw_function()
Breakpoint 0, 0x0000003793ac3d00 in std::terminate() () from
/usr/lib64/libstdc++.so.6
The program being debugged entered a std::terminate call which would
have terminated the program being debugged. GDB has restored the
context to what it was before the call.
To change this behaviour use "set unwind-on-terminating-exception off"
Evaluation of the expression containing the function
(SimpleException::throw_function()) will be abandoned.
This time we detected that the inferior function call was about to enter
the std::terminate call, prevented it and popped the frame. So we are
back at the point before we made the call and back to stepping as normal:
(gdb) s
SimpleException::raise_signal (this=0x6013e0, dummy=-1) at
../archer/gdb/testsuite/gdb.cp/gdb2495.cc:31
31 if (dummy > 0)
(gdb) s
33 }
(gdb) s
main () at ../archer/gdb/testsuite/gdb.cp/gdb2495.cc:77
77 exceptions.no_throw_function ();
More information about the Archer
mailing list