Как сломать, когда конкретный тип исключения загружается в 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.