Gdb support for exceptions (Re: using backtrace() in exception throwing?)

Tom Tromey tromey at redhat.com
Wed Feb 27 13:28:54 PST 2013


>>>>> "Tom" == Tom Tromey <tromey at redhat.com> writes:

Tom> The various low-level exception-related functions, like __cxa_throw,
Tom> treat the exception object as a "void *".  However, the value of this
Tom> seems to change depending on the "throw" point.  It's clear that this
Tom> can't always be the argument to throw, due to scalar and object throws.
Tom> So I wonder what exactly it refers to.  I'll have to dig a bit deeper to
Tom> see how all this code really works.
[...]
Tom> It seems like it would be nice if gdb exposed some kind of convenience
Tom> variable so that "catch catch" and "catch throw" could be conditional on
Tom> the thrown object without needing the libstdc++ debuginfo.
[...]
Tom> This may require some libstdc++ change, perhaps a probe point.

I did some more digging here and wrote a few patches.

When throwing an exception, the compiler arranges to allocate an
internal exception object with enough extra space for the exception
passed to "throw".  Then it copy-constructs from the thrown object into
this space and it records the object's type_info into the internal
exception object.

I added some SDT probes to libstdc++ to expose this information more
nicely (there's really no good way to do it in all cases right now, even
with debuginfo installed, as a couple of the probes are mid-function).

So now I can:

(gdb) catch throw
Catchpoint 1 (throw)
(gdb) r
Starting program: /home/tromey/Space/SecondArcher/build/gdb/testsuite/gdb.cp/exception 
[... loads of gunk ...]
Catchpoint 1 (exception thrown), __cxxabiv1::__cxa_throw (obj=0x601090, 
    tinfo=0x600e60 <typeinfo for int@@CXXABI_1.3>, dest=0x0)
    at ../../../../gcc/libstdc++-v3/libsupc++/eh_throw.cc:63
63	  PROBE2 (throw, obj, tinfo);
(gdb) p $_exception
$1 = 13

Note that the exception variable automatically has the right type:

(gdb) up
#1  0x0000000000400873 in foo (i=20)
    at ../../../archer/gdb/testsuite/gdb.cp/exception.cc:28
28	    throw (int) 13;

So, cool.

The bad news is, since this requires a libstdc++ patch, even once I get
everything tidied up and approved and committed, it is going to be a
while before you can use it, unless you're willing to build your own gcc
and gdb.

Tom> If we had the convenience variable mentioned above, and if LibreOffice
Tom> has a relatively simple "exception identity" measure (e.g., if you only
Tom> throw pointers, you can just compare them with ==), then it could
Tom> perhaps be done by: break at the losing catch, make a conditional "catch
Tom> throw", then re-run.

This does turn out to be a tricky bit.
gdb generally mimics the source language, so things like:

    cond 5 $_exception == 23

... will fail if some exception thrown is not actually comparable to 23.

I'm investigating some options here.  Maybe a more-magical "==="
operator, or maybe a Python convenience function like:

    cond 5 $_dwim_equals ($_exception, 23)


I also implemented a way to filter exception catches by name:

    catch catch [REGEXP]
    catch throw [REGEXP]
    catch rethrow [REGEXP]

That will help the above problem a bit, you can do:

    catch catch int if $_exception == 23


I think all this should help with the problems that started this thread.

Insight, advice, ideas -- send them my way.

thanks,
Tom


More information about the LibreOffice mailing list