Отладка — Как я могу получить значение и тип текущего исключения в C ++, используя GDB?

GDB позволяет ловить исключения, когда они выбрасываются и когда их ловят. Но иногда строка, в которую выдается исключение, не имеет символов, или точка прерывания срабатывает во время обработки исключения. Как мне проверить значение текущего исключения?

28

Решение

обновленный


Вот некоторая информация из Руководства GDB

В настоящее время существуют некоторые ограничения в обработке исключений в C ++ (catch
кинь и лови лови) в gdb:

Если вы вызываете функцию в интерактивном режиме, GDB обычно возвращает управление
Вы, когда функция завершила выполнение. Если вызов поднимает
исключение, однако, вызов может обойти механизм, который возвращает
контролировать вас и заставить вашу программу либо прервать, либо просто
продолжать работать, пока не достигнет точки останова, ловит сигнал, что GDB
слушает или выходит. Это так, даже если вы установили
точка ловли для исключения; точки перехвата исключений отключены
в интерактивных звонках. Вы не можете вызвать исключение в интерактивном режиме.
Вы не можете установить обработчик исключений в интерактивном режиме. Иногда ловить
не лучший способ отладки обработки исключений: если вам нужно знать
именно там, где возникает исключение, лучше остановиться
вызывается обработчик исключений, так как таким образом вы можете видеть стек
до того, как происходит раскрутка. Если вы установите точку останова в
вместо обработчика исключений может быть нелегко выяснить, где
исключение было поднято.

Чтобы остановить непосредственно перед вызовом обработчика исключений, вам нужно
знание реализации. В случае GNU C ++, исключения
вызываются вызовом библиотечной функции с именем __raise_exception, которая
имеет следующий интерфейс ANSI C:

     /* addr is where the exception identifier is stored.
id is the exception identifier.  */
void __raise_exception (void **addr, void *id); To make the debugger catch all exceptions before any stack unwinding takes place,

установить точку останова на __raise_exception (см. Точки останова; Точки наблюдения;
и исключения).


Что сказал

Это зависит от кода и того, где вы находитесь в стеке. Если вы действительно поймали исключение, как в:

try { .... } catch (std::exception &e) {
//do stuff
}

Вы могли бы попробовать распечатать e.what()Или посмотрите на членов исключения. Если вы просто поймали это как (…), тогда я не уверен, что вы сможете собрать.

Еще одна вещь, которую вы можете сделать, это перехватить throw в gdb и перехватить catch, если вы действительно хотите следовать всему потоку.

gdb> catch catch
gdb> catch throw

Таким образом, вы получите точки останова прямо перед тем, как будут сгенерированы исключения, и когда они будут перехвачены, вы можете пройтись по стеку, чтобы получить больше информации о происходящем. Даже если вы находитесь в другой точке останова, вы сможете пройти вверх по стеку (используя вверх или вниз), чтобы получить кадр, в котором видимо исключение.

8

Другие решения

Более ранние ответы были правильными при написании (в 2013 году), но с тех пор gdb и libstdc ++ изменились.

В libstdc ++ теперь есть несколько хуков, которые позволяют gdb лучше взаимодействовать с системой исключений. В частности, теперь GDB предоставляет достаточно информации для предоставления $_exception удобная переменная для пользователя. Эта переменная содержит генерируемое исключение. Это действительно только в том месте, где происходит исключение; который вы можете остановить при использовании catch catch,

Увидеть страница из руководства для деталей.

6

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

Объяснил ответ:

иногда выбрасывается строка, исключающая символы

Если двоичный файл, который вы отлаживаете, не имеет отладочных символов, то двоичный файл, вероятно, будет удален, и вы вообще не сможете ничего узнать о типах / значениях чего-либо.

Как мне проверить значение текущего исключения?

Я думаю, что вы предполагаете, что исключением является языковая функция, которую может проверить gdb; на самом деле исключение в C ++ представляет собой сочетание возможностей C ++ как языка, libc ++ и ABI. И может даже быть больше чем одно активное текущее исключение.

Как указывает UpAndAdam, вы можете установить точку останова в блоке catch с помощью спецификатора типа, а затем проверить этот элемент, но я подозреваю, что ваша проблема в тех случаях, когда вы обнаружите «catch (…)». В этих случаях вы не сможете много узнать о текущем исключении, если не углубитесь в реализацию обработки исключений.

С очень коротким и неполным описанием мы могли бы сказать, что бросить исключение:

  1. Ваша программа вызовет libc ++, чтобы вызвать исключение
  2. libc ++ вызовет «unwind» в glibc, чтобы начать разматывание стека
  3. unwind будет вызывать «личностную функцию» из libc ++ для каждого кадра стека (в основном, каждый вызов функции в стеке)
  4. функция индивидуальности каким-то образом решит, может ли текущий кадр стека обработать или исключить это исключение
  5. если исключение может быть обработано, блок catch будет выполнен

Сейчас трудно говорить о деталях, потому что большая часть обработки исключений зависит от вашей цепочки инструментов (компилятор, платформа, архитектура, libc ++ и т. Д.), Но в большинстве случаев «catch (…)» даже не получит исходное исключение в качестве аргумента. В любом случае, чтобы как-то ответить на ваш вопрос: в gcc с libc ++ от gnu вы можете попробовать что-то вроде этого:

  1. Получите libc ++ с отладочными символами
  2. Установите точку останова в __gxx_personality_v0 (это называется личностной функцией). Эта функция будет вызвана, чтобы определить, имеет ли кадр стека (в основном, вызов функции) подходящий блок catch для обработки исключения
  3. В функции индивидуальности вы сможете найти указатель на _Unwind_Exception, который является оберткой для вашего реального исключения
  4. Получите информацию о типе для вашего исключения следующим образом:
    __cxa_exception * exception_header = (__cxa_exception *) (unwind_exception + 1) -1;
    std :: type_info * thrown_exception_type = exception_header-> exceptionType;
  5. Вы получите тип исключения, который затем сможете найти в остальной части RTTI, определенной для вашего кода.

В любом случае вам, вероятно, придется потратить немало времени, пытаясь понять, как обработка исключений реализована на вашей платформе. Если вы хотите прочитать немного больше об обработке исключений, в прошлом я потратил некоторое время на написание темы @ http://monoinfinito.wordpress.com/series/exception-handling-in-c/. Это не официальный источник, но в нем есть ссылки на спецификации каждой части, связанной с обработкой исключения.

3
По вопросам рекламы [email protected]