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

Tom Tromey tromey at redhat.com
Wed Feb 20 13:28:06 PST 2013


>>>>> "Lubos" == Lubos Lunak <l.lunak at suse.cz> writes:

Tom> Is there something we could do to improve it?

Lubos>  I don't know how much control gdb over exception handling has,
Lubos> so I don't know :).

:-)

FWIW we have the same problem in reverse: the gdb group at Red Hat is,
among other things, tasked with improving the C++ debugging experience.
However, most of us don't actually debug C++ programs on a regular
basis.  We do know some issues, via bugzilla and other discussions, but
I feel sure we are also missing things.

Lubos>  What I was refering to was the problem that if a catch block
Lubos> catches an exception, it's often difficult to find out where it
Lubos> actually came from.  Using 'catch catch' doesn't show where it
Lubos> originated (unless I missed a non-obvious way). And if the
Lubos> exception propagated out of complex nesting of function calls,
Lubos> then 'catch throw' may trigger a number of times for exceptions
Lubos> that will be handled elsewhere.

Solving this in general looks tricky to me.  I am not really sure how to
do it, but I will think about it some more.

The basic issue is that if 'catch throw' triggers multiple times for the
same exception, then it seems that there must be code that catches the
exception and then throws it again:

  try { } catch (blah) { throw blah; }

As opposed to a true re-throw:

  try { } catch (blah) { throw; }

AFAIK re-throws are currently not caught, see
http://sourceware.org/bugzilla/show_bug.cgi?id=12824

I'm not sure whether it is possible to easily detect whether "throw x"
is throwing some object which has already been thrown.

Hopefully I'm misunderstanding the problem :)


Meanwhile, I did whip up a quick-and-dirty Python-based approach.  It
adds a new "track-throws" command.  This command installs a breakpoint
that records the point of the most recent "throw".  Then you can examine
the result with "info last-throw".

Here it is in action:

(gdb) source track_throw.py
(gdb) track-throws 
Breakpoint 1 at 0x400910
(gdb) catch catch
Catchpoint 2 (catch)
(gdb) run
[...]
Catchpoint 2 (exception caught), __cxxabiv1::__cxa_begin_catch (
    exc_obj_in=0x602070) at ../../../../libstdc++-v3/libsupc++/eh_catch.cc:41
41	{
(gdb) info last-throw 
Last exception thrown at file ../../../archer/gdb/testsuite/gdb.cp/nextoverthrow.cc, line 36


"track-throws" makes the breakpoint it installs user-visible so you can
disable the feature simply by deleting the breakpoint.

I'm curious to know if this is useful to you.

Tom


import gdb

last_sal = None

throw_bp = None

class ThrowTracker(gdb.Breakpoint):
    def __init__(self):
        gdb.Breakpoint.__init__(self, '__cxa_throw')

    def stop(self):
        global last_sal
        frame = gdb.newest_frame().older()
        last_sal = frame.find_sal()
        return False

class TrackThrows(gdb.Command):
    def __init__(self):
        gdb.Command.__init__(self, 'track-throws', gdb.COMMAND_BREAKPOINTS)

    def invoke(self, arg, from_tty):
        global throw_bp
        if throw_bp is None or not throw_bp.is_valid():
            # Still no good way to create a pending breakpoint from
            # Python.
            save = gdb.parameter('breakpoint pending')
            gdb.execute('set breakpoint pending on', to_string = True)
            throw_bp = ThrowTracker()
            if save is None:
                arg = 'auto'
            elif save:
                arg = 'on'
            else:
                arg = 'off'
            gdb.execute('set breakpoint pending %s' % arg, to_string = True)

class InfoThrow(gdb.Command):
    def __init__(self):
        gdb.Command.__init__(self, 'info last-throw', gdb.COMMAND_BREAKPOINTS)

    def invoke(self, arg, from_tty):
        global last_sal
        if last_sal is not None:
            filename = last_sal.symtab.filename
            line = last_sal.line
            print "Last exception thrown at file %s, line %d" % (filename, line)
        else:
            print "No previous exception seen"

TrackThrows()
InfoThrow()


More information about the LibreOffice mailing list