How to break when a specific exception type is thrown in GDB?

According to the documentation I can break on specific exception type by using conditional breakpoints. However the syntax for the condition isn't very clear to me:

condition bnum <expression>

Looking at the expression syntax I think this is the pattern I need:

{type} addr

However, I don't know what I should pass for the addr argument. I tried the following:

(gdb) catch throw
(gdb) condition 1 boost::bad_function_call *

But it doesn't work (gdb breaks on all exception types).

Can anyone help?


Update

I also tried @Adam's suggestion, but it results in an error message:
(gdb) catch throw boost::bad_function_call
Junk at end of arguments.

Without boost:: namespace:

(gdb) catch throw bad_function_call
Junk at end of arguments.


Workaround

Breaking in the constructor of bad_function_call works.

Solution 1:

EDIT

The documentation suggests that catch throw <exceptname> can be used to break whenever an exception of type <exceptname> is thrown; however, that doesn't seem to work in practice.

(gdb) help catch
Set catchpoints to catch events.
Raised signals may be caught:
        catch signal              - all signals
        catch signal <signame>    - a particular signal
Raised exceptions may be caught:
        catch throw               - all exceptions, when thrown
        catch throw <exceptname>  - a particular exception, when thrown
        catch catch               - all exceptions, when caught
        catch catch <exceptname>  - a particular exception, when caught
Thread or process events may be caught:
        catch thread_start        - any threads, just after creation
        catch thread_exit         - any threads, just before expiration
        catch thread_join         - any threads, just after joins
Process events may be caught:
        catch start               - any processes, just after creation
        catch exit                - any processes, just before expiration
        catch fork                - calls to fork()
        catch vfork               - calls to vfork()
        catch exec                - calls to exec()
Dynamically-linked library events may be caught:
        catch load                - loads of any library
        catch load <libname>      - loads of a particular library
        catch unload              - unloads of any library
        catch unload <libname>    - unloads of a particular library
The act of your program's execution stopping may also be caught:
        catch stop

C++ exceptions may be caught:
        catch throw               - all exceptions, when thrown
        catch catch               - all exceptions, when caught
Ada exceptions may be caught:
        catch exception           - all exceptions, when raised
        catch exception <name>    - a particular exception, when raised
        catch exception unhandled - all unhandled exceptions, when raised
        catch assert              - all failed assertions, when raised

Do "help set follow-fork-mode" for info on debugging your program
after a fork or vfork is caught.

Do "help breakpoints" for info on other commands dealing with breakpoints.

Solution 2:

When gdb command 'catch throw' fails, try this workaround :
(tested with Linux g++ 4.4.5/gdb 6.6)
1/ Add this code anywhere in the program to debug :

#include <stdexcept>
#include <exception>
#include <typeinfo>

struct __cxa_exception {
    std::type_info *inf;
};
struct __cxa_eh_globals {
    __cxa_exception *exc;
};
extern "C" __cxa_eh_globals* __cxa_get_globals();
const char* what_exc() {
    __cxa_eh_globals* eh = __cxa_get_globals();
    if (eh && eh->exc && eh->exc->inf)
        return eh->exc->inf->name();
    return NULL;
}

2/ In gdb you will then be able to filter exceptions with :

(gdb) break __cxa_begin_catch  
(gdb) cond N (what_exc()?strstr(what_exc(),"exception_name"):0!=0)  

where N is the breakpoint number, and exception_name is the name of exception for which we wish to break.

Solution 3:

From what I have understood from the question here, you want to break when a specific exception boost::bad_function_call is thrown in your application.

$> gdb /path/to/binary
(gdb) break boost::bad_function_call::bad_function_call()
(gdb) run --some-cli-options

So when the temporary object boost::bad_function_call is constructed in preparation for the throw; gdb will break out!

I have tested this and it does work. If you precisely know the way the exception object is being constructed then you can set breakpoint on the specific constructor, otherwise as shown in the example below, you can omit the arguments prototype list, and gdb will set break points on all different flavours of the constructor.

$ gdb /path/to/binary

(gdb) break boost::bad_function_call::bad_function_call
Breakpoint 1 at 0x850f7bf: boost::bad_function_call::bad_function_call. (4 locations)

(gdb) info breakpoints
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   <MULTIPLE>
1.1                         y     0x0850f7bf in boost::bad_function_call::bad_function_call() at /usr/include/boost/function/function_base.hpp:742
1.2                         y     0x0850fdd5 in boost::bad_function_call::bad_function_call(boost::bad_function_call const&) at /usr/include/boost/function/function_base.hpp:739
1.3                         y     0x0863b7d2 <boost::bad_function_call::bad_function_call()+4>
1.4                         y     0x086490ee <boost::bad_function_call::bad_function_call(boost::bad_function_call const&)+6>

Solution 4:

Another approach is to rely on the tinfo argument available when the catch point is triggered, which is a pointer to the object returned by typeid(type).

So say if I want to catch exception std::bad_alloc being thrown, I could just do:

> p &typeid(std::bad_alloc)
> $1 = (__cxxabiv1::__si_class_type_info *) 0x8c6db60 <typeinfo for std::bad_alloc>
> catch throw if tinfo == 0x8c6db60