Как сломать, когда конкретный тип исключения загружается в GDB?

В соответствии с документацией я могу разбить конкретный тип исключения, используя условные точки останова. Однако синтаксис этого условия мне не очень понятен:

condition bnum <expression>

Глядя на синтаксис выражения, я думаю, что это шаблон, который мне нужен:

{type} addr

Однако я не знаю, что мне нужно передать для аргумента addr. Я попробовал следующее:

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

Но он не работает (gdb разбивается на все типы исключений).

Может ли кто-нибудь помочь?

<ч/" >

Обновление

Я также попробовал @Adam предложение, но в результате появляется сообщение об ошибке:
(gdb) catch throw boost::bad_function_call
Junk at end of arguments.

Без boost:: пространства имен:

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

<ч/" >

Обход

Разрыв в конструкторе bad_function_call работает.

Ответ 1

ИЗМЕНИТЬ

Документация предполагает, что catch throw <exceptname> может использоваться для разбиения всякий раз, когда генерируется исключение типа <exceptname>; однако, похоже, что это не работает на практике.

(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 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.

Ответ 2

Когда команда gdb "catch throw" выходит из строя, попробуйте это обходное решение:
(протестирован с Linux g++ 4.4.5/gdb 6.6)
1/Добавьте этот код в любом месте программы для отладки:

#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/В gdb вы сможете фильтровать исключения с помощью:

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

где N - номер точки останова, а exception_name - это имя исключения, для которого мы хотим сломать.

Ответ 3

Из того, что я понял из вопроса здесь, вы хотите разбить, когда в вашем приложении выбрано конкретное исключение boost::bad_function_call.

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

Итак, когда временный объект boost::bad_function_call построен при подготовке к throw; gdb выйдет!

Я тестировал это, и он работает. Если вы точно знаете способ создания объекта исключения, вы можете установить точку останова на конкретном конструкторе, иначе, как показано в примере ниже, вы можете опустить список прототипов аргументов, а gdb будет устанавливать точки останова на всех разных вариантах конструктора.

$ 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>

Ответ 4

Как уже упоминалось, эта функциональность не работает на практике. Но в качестве обходного пути вы можете установить условие на catch throw. Когда выбрано исключение, мы приходим к функции __cxa_throw. Он имеет несколько параметров, указывающих на класс исключений, поэтому мы можем установить условие для одного из них. В примере gdb образца ниже, я ставлю условие на dest параметр __cxa_throw. Единственная проблема заключается в том, что значение dest (0x80486ec в этом случае) неизвестно заранее. Это может быть известно, например, при первом запуске gdb без условия на точке останова.

[[email protected] ~]#
[[email protected] ~]# gdb ./a.out
GNU gdb (GDB) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /root/a.out...done.
(gdb) catch throw
Catchpoint 1 (throw)
(gdb) condition 1 dest==0x80486ec
No symbol "dest" in current context.
(gdb) r
warning: failed to reevaluate condition for breakpoint 1: No symbol "dest" in current context.
warning: failed to reevaluate condition for breakpoint 1: No symbol "dest" in current context.
warning: failed to reevaluate condition for breakpoint 1: No symbol "dest" in current context.
Catchpoint 1 (exception thrown), __cxxabiv1::__cxa_throw (obj=0x804a080, tinfo=0x8049ca0, dest=0x80486ec <[email protected]>) at ../../../../gcc-4.4.3/libstdc++-v3/libsupc++/eh_throw.cc:68
68      ../../../../gcc-4.4.3/libstdc++-v3/libsupc++/eh_throw.cc: No such file or directory.
        in ../../../../gcc-4.4.3/libstdc++-v3/libsupc++/eh_throw.cc
(gdb) bt
#0  __cxxabiv1::__cxa_throw (obj=0x804a080, tinfo=0x8049ca0, dest=0x80486ec <[email protected]>) at ../../../../gcc-4.4.3/libstdc++-v3/libsupc++/eh_throw.cc:68
#1  0x08048940 in main () at test.cpp:14
(gdb) i b
Num     Type           Disp Enb Address    What
1       breakpoint     keep y   0x008d9ddb exception throw
        stop only if dest==0x80486ec
        breakpoint already hit 1 time
(gdb)

Обновление

Вы также должны загрузить информацию об отладке для libstdС++ для этого обходного пути.

Ответ 5

Другой подход состоит в том, чтобы полагаться на аргумент tinfo, доступный при запуске точки catch, который является указателем на объект, возвращаемый typeid(type).

Итак, скажите, хочу ли я исключить исключение std::bad_alloc, я мог бы просто сделать:

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

Ответ 6

Я думаю, что могу ответить на вопрос об установке условных перерывов. Я не буду отвечать на вопрос об исключениях, поскольку __raise_exception, похоже, не существует в g ​​++ 4.5.2 (?)

Предположим, что у вас есть следующий код (я использую void, чтобы получить что-то похожее на __raise_exception из документа gdb)

void foo(void* x) {

}

int main() {
    foo((void*)1);
    foo((void*)2);
}

чтобы разбить на foo (2), вы используете следующие команды

(gdb) break foo
Breakpoint 1 at 0x804851c: file q.cpp, line 20.
(gdb) condition 1 x == 2

Если вы используете

(gdb) r

вы увидите, что он останавливается при втором вызове foo, но не на первом

Я думаю, что они подразумевали в документах, так это то, что вы устанавливаете разрыв функции __raise_exception (очень зависимый от реализации)

 /* addr is where the exception identifier is stored
    id is the exception identifier.  */
    void __raise_exception (void **addr, void *id);

а затем установите условный разрыв по id, как описано выше (вам нужно как-то определить, что такое id для вашего типа исключения).

К сожалению

 (gdb) break __raise_exception

результаты с (g++ 4.5.2)

 Function "__raise_exception" not defined.