Подтвердить что ты не робот

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

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

4b9b3361

Ответ 1

Обновление


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

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

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

Чтобы остановить работу перед вызовом обработчика исключений, вам нужно знания об осуществлении. В случае gnu С++ исключения возникают путем вызова библиотечной функции с именем __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() или посмотреть на членов исключения. Если вы просто поймали его как (...), тогда я не уверен, что вы сможете собрать.

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

gdb> catch catch  
gdb> catch throw

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

Ответ 2

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

Объясненный ответ:

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

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

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

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

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

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

  • Ваша программа вызовет libС++ для создания исключения
  • libС++ вызовет "разматывать" в glibc, чтобы запустить раскрутку стека
  • unwind вызовет функцию "личность" из libС++ для каждого фрейма стека (каждый вызов функции в стеке в основном)
  • функция личности каким-то образом решит, может ли текущий стек стека обрабатывать или исключать этот исключение
  • если исключение можно обработать, блок catch будет выполнен

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

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

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

Ответ 3

Эти ответы были правильными при написании, но с тех пор были изменены gdb и libstdС++.

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

Подробнее см. страницу из руководства.