This is the mail archive of the mailing list for the Archer project.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

archer-pmuldoon-exception-rewind quick demo script

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/ -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/
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/
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:

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/
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/
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/
31 if (dummy > 0)
(gdb) s
33 }
(gdb) s
main () at ../archer/gdb/testsuite/gdb.cp/
77 exceptions.no_throw_function ();

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]