Отладка с помощью GDB - 5. Остановка и продолжение исполнения

[Содержание]   [Назад]   [Пред]   [Вверх]   [След]   [Вперед]  


5. Остановка и продолжение исполнения

Основные цели применения отладчика--остановка вашей программы до ее завершения, или чтобы в случае нарушений в работе вашей программы вы могли выяснить их причину.

Внутри GDB ваша программа может остановиться по нескольким причинам, таким как сигнал, точка останова, или достижение новой строки после команды GDB, такой как step. Затем вы можете исследовать и изменять значения переменных, устанавливать новые точки останова и удалять старые, и затем продолжить выполнение. Обычно, выводимые GDB сообщения предоставляют достаточную информацию о состоянии вашей программы, но вы также можете запросить эту информацию явно в любое время.

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

5.1 Точки останова, точки наблюдения и точки перехвата

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

В конфигурациях HP-UX, SunOS 4.x, SVR4 и Alpha OSF/1, вы можете устанавливать точки останова в разделяемых библиотеках до запуска выполняемого файла. В системах HP-UX существует небольшое ограничение: вы должны подождать, пока программа не перестанет выполняться, для установки точек останова в подпрограммах из разделяемой библиотеки, которые не вызываются напрямую из программы (например, подпрограммах, являющихся аргументами вызова pthread_create).

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

Вы можете установить, что значения из вашей программы должны отображаться автоматически, когда GDB останавливается в точке останова. См. раздел 8.6 Автоматическое отображение.

Точка перехвата---это другая специализированная точка останова, которая останавливает вашу программу при возникновении события определенного типа, такого как выбрасывание исключения в Си++ или загрузка библиотеки. Также как с точками наблюдения, вы используете другую команду для установки точки перехвата, (см. раздел 5.1.3 Установка точек перехвата), но помимо этого, вы можете обращаться с ней так же, как с любой другой точкой останова. (Для остановки, когда ваша программа получает сигнал, используйте команду handle; смотрите раздел 5.3 Сигналы.)

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

Некоторые команды GDB допускают в качестве указания точек останова, на которые они действуют, их диапазоны. Диапазон точек останова--это или номер одной точки, например `5', или два таких номера, в порядке увеличения, разделенные дефисом, например `5-7'. Когда команде задается диапазон точек останова, она действует на все точки останова в этом диапазоне.

5.1.1 Установка точек останова

Точки останова устанавливаются командой break (сокращенно b). Вспомогательная переменная отладчика `$bpnum' хранит номер последней установленной вами точки останова; смотрите раздел 8.9 Вспомогательные переменные, для обсуждения того, что вы можете делать со вспомогательными переменными.

Вы можете задавать место для установки новой точки останова несколькими способами.

break функция
Установить точку останова на входе в функцию функция. При использовании языков, допускающих перегрузку символов, таких как Си++, функция может ссылаться более чем на одно возможное место останова. См. раздел 5.1.8 Меню точки останова, для обсуждения такой ситуации.
break +смещение
break -смещение
Установить точку останова через несколько строк впереди или сзади от позиции, на которой выполнение остановилось в текущем выбранном кадре стека. (См. раздел 6.1 Кадры стека, для описания кадров стека.)
break номер-строки
Установить точку останова на строке номер-строки в текущем исходном файле. Текущий исходный файл--это файл, исходный текст которого отображался последним. Точка останова остановит вашу программу сразу перед выполнением какого-либо кода на этой строке.
break имя-файла:номер-строки
Установить точку останова на строке номер-строки в исходном файле имя-файла.
break имя-файла:функция
Установить точку останова на входе в функцию, находящуюся в файле имя-файла. Указание имени файла вместе с именем функции является излишним, за исключением ситуаций, когда несколько файлов содержат одинаково названные функции.
break *адрес
Установить точку останова по адресу адрес. Вы можете использовать это для установки точек останова в тех частях вашей программы, которые не имеют отладочной информации или исходных файлов.
break
При вызове без аргументов, break устанавливает точку останова на инструкции, которая должна быть выполнена следующей в выбранном кадре стека (см. раздел 6. Исследование стека). В любом выбранном кадре, кроме самого внутреннего, это останавливает вашу программу, как только управление возвращается в этот кадр. Это похоже на результат команды finish в кадре внутри выбранного кадра--за исключением того, что finish не оставляет активной точки останова. Если вы используете break без аргументов в самом внутреннем кадре, GDB останавливается, когда в следующий раз достигает текущего места; это может быть полезно внутри циклов. Обычно GDB игнорирует точки останова, когда он возобновляет выполнение, пока не будет выполнена хотя бы одна инструкция. Если бы он этого не делал, вы не могли бы продолжать выполнение после точки останова, не отключив сперва эту точку останова. Это правило применяется вне зависимости от того, существовала или нет точка останова, когда ваша программа остановилась.
break ... if усл
Установить точку останова с условием усл; каждый раз, когда достигается точка останова, происходит вычисление выражения усл, и остановка происходит только если эта величина не равна нулю--то есть, если усл истинно. `...' означает один из возможных аргументов, перечисленных выше (или отсутствие аргументов), описывающих место остановки. См. раздел 5.1.6 Условия останова, для большей информации об условных точках останова.
tbreak арг
Установить точку останова только до первой активизации. Аргументы арг такие же, как для команды break, и точка останова устанавливается аналогичным образом, но она автоматически уничтожается после того, как ваша программа первый раз на ней остановится. См. раздел 5.1.5 Отключение точек останова.
hbreak арг
Установить аппаратно-поддерживаемую точку останова. Аргументы арг такие же, как и для команды break, и точка останова устанавливается аналогичным образом, но она требует аппаратной поддержки и некоторые целевые платформы могут ее не иметь. Основной целью этого является отладка кода EPROM/ROM, так что вы можете установить точку останова на инструкции без изменения инструкции. Это может быть использовано с новой генерацией ловушек, предоставляемой SPARClite DSU и некоторыми машинами на базе x86. Эти платформы будут генерировать ловушки, когда программа обращается к некоторым данным или адресу инструкции, которые назначены регистрам отладки. Однако, регистры аппаратных точек останова могут хранить ограниченное число точек останова. Например, на DSU, только две точки останова могут быть установлены одновременно, и GDB будет отвергать эту команду, если используется больше. Удалите или отключите неиспользуемые аппаратные точки останова перед установкой новых (см. раздел 5.1.5 Отключение точек останова). См. раздел 5.1.6 Условия останова.
thbreak арг
Установить аппаратно-поддерживаемую точку останова, включенную только до первой активизации. Аргументы арг такие же, как и для команды hbreak, и точка останова устанавливается аналогичным образом. Однако, как в случае команды tbreak, точка останова автоматически уничтожается после того, как программа первый раз на ней остановится. Также, как и в случае команды hbreak, точка останова требует аппаратной поддержки и некоторые аппаратные платформы могут ее не иметь. См. раздел 5.1.5 Отключение точек останова. Смотрите также раздел 5.1.6 Условия останова.
rbreak рег-выр
Установить точки останова на всех функциях, удовлетворяющих регулярному выражению рег-выр. Эта команда устанавливает безусловные точки останова при всех совпадениях, выводя список всех установленных точек останова. После установки, они рассматриваются точно так же, как точки останова, установленные командой break. Вы можете удалять их, отключать, или делать их условными таким же способом, как любые другие точки останова. Регулярные выражения имеют стандартный синтаксис, используемый такими средствами, как `grep'. Заметьте, что это отличается от синтаксиса, используемого оболочками; так, например, foo* подходит для всех функций, которые включают fo, за которым следует любое число букв o. Существует неявное .* в начале и в конце введенного вами регулярного выражения, так что для нахождения только тех функций, которые начинаются на foo, используйте ^foo. При отладке программ, написанных на Си++, rbreak полезна для установки точек останова на перегруженных функциях, не являющихся членами никакого специального класса.
info breakpoints [n]
info break [n]
info watchpoints [n]
Вывести таблицу всех установленных и не удаленных точек останова, наблюдения и перехвата, со следующими колонками для каждой точки:
Номер точки останова
Тип
Точка останова, наблюдения или перехвата.
План
Помечена ли точка останова для отключения или удаления после активации.
Включена или отключена
Включенные точки останова помечаются как `y'. `n' отмечает отключенные точки.
Адрес
Адрес памяти, где расположена точка останова в вашей программе.
Где
Файл и номер строки, где расположена точка останова в исходном файле.
Если точка останова условная, info break показывает условие на строке, следующей за этой точкой; команды точки останова, если они есть, перечисляются после этого. info break с номером точки останова n в качестве аргумента отображает только эту точку. Вспомогательная переменная $_ и адрес по умолчанию для исследования для команды x устанавливаются равными адресу последней из перечисленных точек останова (см. раздел 8.5 Исследование памяти). info break отображает то число раз, которое точка останова была активирована. Это особенно полезно при использовании вместе с командой ignore. Вы можете игнорировать большое число активаций точки останова, посмотреть информацию о точке останова чтобы узнать, сколько раз она активировалась, и затем запустить заново, игнорируя на единицу меньше, чем это число. Это быстро приведет вас к последней активации этой точки останова.

GDB позволяет вам установить любое число точек останова в одном и том же месте вашей программы. В этом нет ничего глупого или бессмысленного. Когда точки останова являются условными, это даже полезно (см. раздел 5.1.6 Условия останова).

GDB сам иногда устанавливает точки останова в вашей программе для специальных целей, таких как правильная обработка longjmp (в программах на Си). Этим внутренним точкам останова присваиваются отрицательные номера, начиная с -1; `info breakpoints' не отображает их.

Вы можете увидеть эти точки останова с помощью служебной команды GDB `maint info breakpoints'.

maint info breakpoints
Используя тот же формат, что и `info breakpoints', отобразить как точки останова, установленные вами явно, так и те, которые GDB использует для внутренних целей. Внутренние точки останова показываются с отрицательными номерами. Колонка типа определяет, какого типа точка останова показана:
breakpoint
Обычная, явно установленная точка останова.
watchpoint
Обычная, явно установленная точка наблюдения.
longjmp
Внутренняя точка останова, используемая для корректной обработки пошагового выполнения вызовов longjmp.
longjmp resume
Внутренняя точка останова на цели longjmp.
until
Временная внутренняя точка останова, используемая командой GDB until.
finish
Временная внутренняя точка останова, используемая командой GDB finish.
shlib events
События в разделяемых библиотеках.

5.1.2 Установка точек наблюдения

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

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

В некоторых системах, таких как HP-UX, Linux и некоторых других платформах, базирующихся на x86, GDB включает поддержку для аппаратных точек наблюдения, которые не замедляют выполнение вашей программы.

watch выраж
Устанавливает точку наблюдения за выражением. GDB остановит программу, когда выраж сохраняется программой и его величина изменяется.
rwatch выраж
Устанавливает точку наблюдения, которая остановит программу, когда наблюдаемое выраж считывается программой.
awatch выраж
Устанавливает точку наблюдения, которая остановит программу, когда выраж либо считывается, либо сохраняется программой.
info watchpoints
Эта команда печатает список точек наблюдения, останова и перехвата; это то же самое, что и info break.

Когда это возможно, GDB устанавливает аппаратную точку наблюдения. Аппаратные точки наблюдения выполняются очень быстро, и отладчик сообщает об изменении величины точно в месте инструкции, где это изменение произошло. Если GDB не может установить аппаратную точку наблюдения, он устанавливает программную точку наблюдения, которая выполняется намного медленнее и сообщает об изменении величины на следующем операторе, а не инструкции, после появления изменения.

Когда вы даете команду watch, GDB сообщает

Hardware watchpoint номер: выраж

если ему удалось установить аппаратную точку наблюдения.

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

Expression cannot be implemented with read/access
watchpoint.(6)

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

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

Hardware watchpoint номер: Could not insert watchpoint(7)

Если это происходит, удалите или отключите некоторые точки наблюдения.

SPARClite DSU будет генерировать ловушки, когда программа обращается к некоторым данным или адресу инструкции, которые отведены для отладочных регистров. Для адресов данных, DSU упрощает команду watch. Однако, аппаратные регистры точек останова могут принять только две точки наблюдения за данными, и обе точки наблюдения должны быть одного типа. Например, вы можете установить две точки наблюдения с помощью команды watch, две с помощью команды rwatch, или две с помощью команды awatch, но вы не можете установить одну точку наблюдения с помощью одной команды, а другую с помощью другой. GDB не примет команду, если вы попытаетесь смешать различные точки наблюдения. Удалите или отключите неиспользуемые точки наблюдения перед установкой новых.

Если вы вызываете функцию интерактивно, используя print или call, все установленные вами точки наблюдения будут неактивными, до тех пор пока GDB не достигнет точки останова другого типа, или пока вызов не завершится.

GDB автоматически удаляет точки наблюдения, которые наблюдают за локальными переменными, или за выражениями, которые используют такие переменные, когда они выходят из области видимости, то есть когда выполнение покидает блок, в котором эти переменные были определены. В частности, когда отлаживаемая программа завершается, все локальные переменные выходят из области видимости, и таким образом остаются установленными только те точки наблюдения, которые наблюдают за глобальными переменными. Если вы снова запустите программу, вы должны будете заново установить все такие точки наблюдения. Одним из способов сделать это будет установить точку останова на входе в функцию main, и, когда программа остановится, установить все точки наблюдения.

Предупреждение: В многонитевых программах точки наблюдения являются лишь частично полезными. С текущей реализацией точек наблюдения, GDB может наблюдать только за величиной выражения в одной нити. Если вы уверены, что выражение может измениться только вследствие действий внутри текущей нити (и если вы также уверены, что никакая другая нить не может стать текущей), то вы можете использовать точки наблюдения как обычно. Однако, GDB может не заметить, когда действия в не текущей нити изменяют выражение.

Предупреждение для HP-UX: В многонитевых программах, программные точки наблюдения являются лишь частично полезными. Если GDB создает программную точку наблюдения, она может наблюдать только за величиной выражения в одной нити. Если вы уверены, что выражение может измениться только вследствие действий внутри текущей нити (и если вы также уверены, что никакая другая нить не может стать текущей), то вы можете использовать программные точки наблюдения как обычно. Однако, GDB может не заметить, когда действия в не текущей нити изменяют выражение. (Аппаратные же точки наблюдения напротив, наблюдают за выражением во всех нитях.)

5.1.3 Установка точек перехвата

Вы можете использовать точки перехвата, чтобы вызвать остановку отладчика в ответ на определенные типы событий в программе, такие как исключения в Си++ или загрузка разделяемой библиотеки. Для установки точки перехвата используйте команду catch.

catch событие
Остановиться, когда происходит событие. Событие может быть одним из:
throw
Выбрасывание исключения Си++.
catch
Перехват исключения Си++.
exec
Вызов exec. В настоящее время это доступно только на HP-UX.
fork
Вызов fork. В настоящее время это доступно только на HP-UX.
vfork
Вызов vfork. В настоящее время это доступно только на HP-UX.
load
load имя-библ
Динамическая загрузка любой разделяемой библиотеки, или загрузка библиотеки имя-библ. В настоящее время это доступно только на HP-UX.
unload
unload имя-библ
Выгрузка любой динамически загруженной разделяемой библиотеки, или выгрузка библиотеки имя-библ. В настоящее время это доступно только на HP-UX.
tcatch событие
Установить точку перехвата, которая включена только до первой активации. Точка перехвата автоматически уничтожается после того, как событие перехвачено первый раз.

Используйте команду info break для получения списка текущих точек перехвата.

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

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

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

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

    /* addr -- где хранится идентификатор исключения.
       id -- идентификатор исключения.  */
    void __raise_exception (void **addr, void *id);

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

С помощью условных точек останова (см. раздел 5.1.6 Условия останова), зависящих от величины id, вы можете остановить вашу программу, когда возбуждается определенное исключение. Вы можете использовать несколько условных точек останова, чтобы остановить программу, когда возбуждается любое из нескольких исключений.

5.1.4 Удаление точек останова

Часто бывает необходимо уничтожить точку останова, наблюдения или перехвата, когда она сделала свое дело и вы больше не хотите останавливать там свою программу. Это называется уничтожением точки останова. Точка останова, которая была уничтожена, более не существует; она забыта.

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

Не обязательно удалять точку останова, чтобы продолжить выполнение после нее. GDB автоматически игнорирует точки останова на первой инструкции, которая должна быть выполнена, когда вы продолжаете исполнение без изменения адреса выполнения.

clear
Удаляет любые точки останова, установленные на следующей инструкции, которая должна быть выполнена в выбранном кадре стека (см. раздел 6.3 Выбор кадра). Когда выбран самый внутренний кадр, это хороший способ удалить ту точку останова, на которой ваша программа только что остановилась.
clear функция
clear имя-файла:функция
Удалить любые точки останова, установленные на входе в функцию.
clear номер-строки
clear имя-файла:номер-строки
Удалить все точки останова, установленные на или внутри кода на указанной строке.
delete [breakpoints] [диапазон...]
Удалить точки останова, наблюдения или перехвата из диапазона, указанного в качестве аргумента. Если аргумент не задан, удалить все точки останова (GDB запрашивает подтверждение, если у вас не установлено set confirm off). Вы можете сократить это команду как d.

5.1.5 Отключение точек останова

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

Вы отключаете и включаете точки останова, наблюдения и перехвата командами enable и disable, возможно указывая один или более номеров точек останова в качестве аргументов. Используйте info break или info watch для распечатки списка точек останова, наблюдения и перехвата, если вы не знаете какие номера использовать.

Точка останова, наблюдения или перехвата может находиться в одном из четырех состояний:

  • Включена. Точка останова останавливает вашу программу. Точка останова, установленная командой break, изначально находится в таком состоянии.
  • Отключена. Точка останова не оказывает воздействия на вашу программу.
  • Включена до первого срабатывания. Точка останова останавливает вашу программу, но потом становится отключенной.
  • Включена для удаления. Точка останова останавливает вашу программу, но сразу после этого она удаляется навсегда. Точка останова, установленная командой tbreak, изначально находится в этом состоянии.

Вы можете использовать следующие команды для включения или отключения точек останова, наблюдения и перехвата:

disable [breakpoints] [диапазон...]
Отключить указанные точки останова, или все точки останова, если ни одна не перечислена. Отключенная точка останова не оказывает никакого действия, но она не забывается. Все параметры, такие как счетчик игнорирований, условия и команды запоминаются, на случай, если точка останова позже будет снова включена. Вы можете сокращать disable как dis.
enable [breakpoints] [диапазон...]
Включает указанные (или все определенные) точки останова. Они снова становятся значимыми для остановки вашей программы.
enable [breakpoints] once диапазон...
Временно включить указанные точки останова. GDB отключает любую из этих точек останова немедленно после срабатывания.
enable [breakpoints] delete диапазон...
Включить указанные точки останова до первого срабатывания, затем уничтожить. GDB удаляет любую из этих точек останова, как только ваша программа останавливается на ней.

Кроме точек останова, установленных командой tbreak (см. раздел 5.1.1 Установка точек останова), установленные вами точки останова изначально включены; следовательно, они становятся отключенными или включенными только когда вы используете одну из вышеперечисленных команд. (Команда until может устанавливать и удалять свою собственную точку останова, но она не изменяет состояние ваших других точек останова; см. раздел 5.2 Продолжение и выполнение по шагам.)

5.1.6 Условия останова

Простейшая точка останова останавливает вашу программу каждый раз, когда управление достигает заданного места. Вы можете также указать условие для точки останова. Условие является просто булевым выражением в вашем языке программирования (см. раздел 8.1 Выражения). Точка останова с условием вычисляет выражение каждый раз, когда ваша программа достигает ее, и ваша программа остановится только в том случае, если условие истинно.

Это противоположно использованию утверждений для проверки правильности программы; в этом случае, вы хотите остановиться, когда утверждение нарушается--то есть, когда условие ложно. В Си, если вы хотите проверить утверждение, выраженное условием assert, вы должны установить условие `! assert' на соответствующей точке останова.

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

Условия останова могут иметь побочные эффекты, и даже могут вызывать функции в вашей программе. Это может быть полезным, например, для активации функций, которые запоминают продвижение выполнения вашей программы, или для использования ваших собственных функций печати для форматирования специальных структур данных. Результаты полностью предсказуемы, если нет другой включенной точки останова по тому же адресу. (В этом случае, GDB может сначала увидеть другую точку останова и остановить вашу программу программу без проверки условия первой точки останова.) Заметьте, что команды точек останова обычно более удобны и гибки, чем условия останова, для выполнения побочных эффектов, когда достигается точка останова (см. раздел 5.1.7 Команды точки останова).

Условия останова могут быть заданы в момент установки точки останова, используя `if' в аргументах команды break. См. раздел 5.1.1 Установка точек останова. Они могут быть также изменены в любой момент с помощью команды condition.

Вы также можете использовать ключевое слово if с командой watch. Команда catch не распознает ключевое слово if; condition является единственным способом наложить дальнейшие условия на точку перехвата.

condition номер выражение
Задайте выражение как условие остановки для точки останова, наблюдения или перехвата с номером номер. После того, как вы установили условие, данная точка останова остановит вашу программу только если значение выражения будет истинным (ненулевым, в Си). Когда вы используете condition, GDB немедленно проверяет выражение на синтаксическую корректность и для определения, что символы в нем имеют объекты ссылки в контексте вашей точки останова. Если выражение использует символы, не существующие в контексте точки останова, GDB выведет сообщение об ошибке:
No symbol "foo" in current context.(8)
Однако, GDB в действительности не вычисляет выражение в момент подачи команды condition (или команды, устанавливающей точку останова с условием, такой как break if ...). См. раздел 8.1 Выражения.
condition номер
Снимает условие с точки останова с номером номер. Она становится обычной безусловной точкой останова.

Специальным случаем условия для точки останова является остановка только когда точка останова была достигнута определенное число раз. Это настолько полезно, что существует специальный способ сделать это, используя счетчик игнорирования точки останова. Каждая точка останова имеет счетчик игнорирования, являющийся целым числом. Как правило, счетчик игнорирования равен нулю, и, следовательно, не производит никакого действия. Но если ваша программа достигает точки останова, чей счетчик игнорирования положителен, тогда вместо того чтобы остановиться, она лишь уменьшит его на единицу и продолжит выполнение. В результате, если величина счетчика игнорирования равна n, точка останова не остановит программу следующие n раз, когда программа его достигнет.

ignore номер значение
Устанавливает счетчик игнорирований точки останова с номером номер в значение. Следующие значение раз, когда точка останова будет достигнута, выполнение вашей программы не будет остановлено; кроме как уменьшить счетчик игнорирований, GDB не производит никаких действий. Чтобы точка останова сработала при следующем достижении, установите счетчик в ноль. Когда вы используете continue для возобновления выполнения вашей программы от точки останова, вы можете установить счетчик игнорирований непосредственно как аргумент к continue, а не использовать ignore. См. раздел 5.2 Продолжение и выполнение по шагам. Если точка останова имеет положительный счетчик игнорирований и условие, то условие не проверяется. Как только счетчик игнорирований достигнет нуля, GDB возобновит проверку условия. Вы можете достигнуть эффекта счетчика игнорирований с помощью такого условия, как `$foo-- <= 0', используя вспомогательную переменную отладчика, которая уменьшается каждый раз. См. раздел 8.9 Вспомогательные переменные.

Счетчики игнорирований можно использовать с точками останова, точками наблюдения и точками перехвата.

5.1.7 Команды точки останова

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

commands [номер]
... список-команд ...
end
Определяет список команд для точки останова с номером номер. Сами команды указываются в следующих строках. Для завершения списка команд, введите строку, содержащую только end. Чтобы удалить все команды от точки останова, введите commands и немедленно за этим end, то есть задайте пустой список команд. Без аргумента номер, commands относится к последней установленной точке останова, наблюдения или перехвата (но не к последней встреченной).

Нажатие RET, как средство повторения последней команды GDB, отключено внутри списка-команд.

Вы можете использовать команды для точки останова, чтобы снова запустить вашу программу на выполнение. Просто используйте команду continue, или step, или любую другую команду, возобновляющую выполнение.

После команды, возобновляющей выполнение, любые другие команды в списке игнорируются. Так сделано потому, что каждый раз, когда вы возобновляете выполнение (даже просто с помощью next или step), вы можете встретить другую точку останова--которая может иметь свой собственный список команд, что приведет к неоднозначности, какой из списков выполнять.

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

Команды echo, output и printf позволяют вам более точно контролировать выводимый текст, и часто полезны в "тихих" точках останова. См. раздел 16.4 Команды для управляемого вывода.

Например, вот как вы можете использовать команды точки останова для вывода величины x на входе в foo, когда x положительна.

break foo if x>0
commands
silent
printf "x is %d\n",x
cont
end

Одним из применений команд точки останова является компенсация одной ошибки, так, чтобы вы могли искать другую. Поместите точку останова сразу после строки кода, содержащей ошибку, задайте ей условие для определения случая, в котором было сделано что-то ошибочное, и определите команды для присвоения правильных значений тем переменным, для которых это требуется. Закончите командой continue, чтобы ваше программа не останавливалась, а начните с команды silent, чтобы не было никакого вывода. Вот пример:

break 403
commands
silent
set x = y + 4
cont
end

5.1.8 Меню точки останова

Некоторые языки программирования (особенно Си++) допускают, чтобы одно и то же имя функции было определено несколько раз, для применения в различных контекстах. Это называется перегрузкой. Когда имя функции перегружается, `break функция' не достаточно, чтобы указать GDB, где вы хотите установить точку останова. Если вы столкнулись с этой проблемой, вы можете использовать что-то типа `break функция(типы)' для указания, какую конкретную версию функции вы имеете в виду. В противном случае, GDB предлагает вам выбор из пронумерованных вариантов для различных возможных точек останова, и ждет вашего выбора с приглашением `>'. Первыми двумя вариантами всегда являются `[0] cancel' и `[1] all'. Ввод 1 устанавливает точку останова на каждом определении функции, и ввод 0 прерывает команду break без установки новых точек останова.

Например, следующая выдержка из сеанса иллюстрирует попытку установить точку останова на перегруженном символе String::after. Мы выбрали три конкретных определения имени функции:

(gdb) b String::after
[0] cancel
[1] all
[2] file:String.cc; line number:867
[3] file:String.cc; line number:860
[4] file:String.cc; line number:875
[5] file:String.cc; line number:853
[6] file:String.cc; line number:846
[7] file:String.cc; line number:735
> 2 4 6
Breakpoint 1 at 0xb26c: file String.cc, line 867.
Breakpoint 2 at 0xb344: file String.cc, line 875.
Breakpoint 3 at 0xafcc: file String.cc, line 846.
Multiple breakpoints were set.
Use the "delete" command to delete unwanted
 breakpoints.
(gdb)

5.1.9 "Не удается поместить точки останова"

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

Cannot insert breakpoints.
The same program may be running in another process.(9)

Когда это происходит, у вас есть три варианта дальнейших действий:

  1. Удалить или отключить точки останова, и затем продолжить.
  2. Приостановить GDB и скопировать файл, содержащий вашу программу, под другим иненем. Возобновить работу GDB и использовать команду exec-file для указания, что GDB должен выполнять вашу программу под этим именем. Затем запустите вашу программу снова.
  3. Скомпоновать заново вашу программу так, чтобы сегмент текста был неразделяемым, используя ключ компоновщика `-N'. Ограничения операционной системы могут не распространяться на неразделяемые выполняемые файлы.

Аналогичное сообщение может выводиться, если вы запрашиваете слишком много активных аппаратно-поддерживаемых точек останова и наблюдения:

Stopped; cannot insert breakpoints.
You may have requested too many hardware breakpoints and watchpoints.(10)

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

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

5.2 Продолжение и выполнение по шагам

Продолжение означает возобновление выполнения программы до ее нормального завершения. Напротив, пошаговое выполнение означает выполнение еще одного "шага" вашей программы, где "шаг" быть либо одной строкой исходного кода, либо одной машинной инструкцией (в зависимости от того, какую именно команду вы используете). И в случае продолжения, и в случае выполнения по шагам, ваша программа может остановиться и раньше, вследствие точки останова или сигнала. (Если она останавливается по сигналу, вы можете использовать handle, или `signal 0' для возобновления выполнения. См. раздел 5.3 Сигналы.)

continue [счетчик-игнор]
c [счетчик-игнор]
fg [счетчик-игнор]
Возобновить выполнение программы, с того адреса, где ваша программа остановилась последний раз; все точки останова, установленные по этому адресу, пропускаются. Необязательный аргумент счетчик-игнор позволяет вам задать количество последующих игнорирований точки останова в этом месте; его действие совпадает с действием ignore (см. раздел 5.1.6 Условия останова). Аргумент счетчик-игнор имеет смысл только если ваша программа остановилась в точке останова. В остальных случаях, аргумент к continue игнорируется. Синонимы c и fg (от foregroung, так как отлаживаемая программа считается фоновой), предоставляются исключительно для удобства, и имеют в точности тот же смысл, что и continue.

Чтобы возобновить выполнение с другого места, вы можете использовать return (см. раздел 11.4 Возврат из функции) чтобы вернуться назад к вызывающей функции; или jump (см. раздел 11.2 Продолжение исполнения с другого адреса) для перехода к произвольному месту в вашей программе.

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

step
Продолжить выполнение вашей программы, пока управление не достигнет другой строки исходного текста, затем остановить ее и возвратить управление GDB. Эту команду можно сокращать до s.

Предупреждение: Если вы используете команду step, когда управление находится внутри функции, которая была скомпилирована без отладочной информации, выполнение продолжается, пока управление не достигнет функции, которая имеет ее. Аналогично, пошаговое выполнение не будет заходить в функцию, скомпилированную без отладочной информации. Для пошагового выполнения таких функций используйте команду stepi, описанную ниже.

Команда step останавливается только на первой инструкции строки исходного текста. Это предотвращает множественные остановки, которые в противном случае могут возникнуть в операторе switch, цикле for, и так далее. step продолжает останавливаться, если функция, имеющая отладочную информацию, вызывается внутри строки. Другими словами, step заходит внутрь функций, вызываемых в данной строке. Также, команда step входит в функцию только если для нее существует информация о номерах строк. Иначе она действует как команда next. Это позволяет избежать проблем, появляющихся при использовании cc -gl на машинах MIPS. Раньше step заходила в подпрограмму, если существовала хоть какая-нибудь отладочная информация о подпрограмме.
step число
Продолжает выполнение как по команде step, но делает это число раз. Если достигается точка останова, или приходит сигнал, не связанный с пошаговым выполнением, до выполнения числа шагов, пошаговое выполнение сразу останавливается.
next [число]
Продолжает выполнение до следующей строки исходного текста в текущем (внутреннем) кадре стека. Это аналогично step, но вызовы функций, которые появляются внутри строки кода, выполняются без остановки. Выполнение останавливается, когда управление достигает другой строки кода в исходном уровне стека, который выполнялся, когда вы дали команду next. Эта команда сокращается как n. Аргумент число является счетчиком повторений, как для step. Команда next останавливается только на первой инструкции исходной строки. Это предотвращает множественные остановки, которые иначе могут возникнуть в операторах switch, циклах for, и так далее.
finish
Продолжить выполнение до возврата из функции в выбранном кадре стека. Напечатать возвращенное значение (если таковое существует). Сравните это с командой return (см. раздел 11.4 Возврат из функции).
until
u
Продолжить выполнение до достижения строки исходного текста, следующей за текущей, в текущем кадре стека. Эта команда используется для избежания выполнения цикла по шагам больше одного раза. Она похожа на команду next, за исключением того, что когда until встречает переход, она автоматически продолжает выполнение, пока счетчик выполнения программы не станет больше, чем адрес перехода. Это означает, что когда вы достигаете конца цикла после его выполнения по шагам, until продолжает выполнение вашей программы, пока она не выйдет из цикла. Напротив, команда next в конце цикла просто переходит назад в начало цикла, что заставляет вас выполнять по шагам следующую итерацию. until всегда останавливает вашу программу, если она пытается выйти из текущего кадра стека. until может привести к несколько неожиданным результатам, если порядок машинных кодов не совпадает с порядком строк исходного текста. Например, в следующем отрывке сеанса отладки, команда f (frame) показывает, что выполнение остановилось на строке 206; хотя, когда мы используем until, мы переходим к строке 195:
(gdb) f
#0  main (argc=4, argv=0xf7fffae8) at m4.c:206
206                 expand_input();
(gdb) until
195             for ( ; argc > 0; NEXTARG) {
Это произошло потому, что для эффектвности выполнения компилятор сгенерировал код для проверки окончания цикла в конце, а не в начале цикла--даже если проверка в цикле for Си написана до тела цикла. Кажется, что команда until переместилась назад к началу цикла, когда двигалась к этому выражению; однако, в действительности она не переходила к более раннему оператору--в терминах фактического машинного кода. until без аргументов работает посредством пошагового выполнения отдельных инструкций, и, следовательно, является более медленной, чем until с аргументом.
until положение
u положение
Продолжить выполнение вашей программы, пока либо указанное место не будет достигнуто, либо не произойдет возврат из текущего кадра стека. положение может быть любой из доступных форм аргумента для break (см. раздел 5.1.1 Установка точек останова). Эта форма команды использует точки останова, и, следовательно, является более быстрой, чем until без аргумента.
stepi
stepi арг
si
Выполнить одну машинную инструкцию, затем остановиться и вернуться в отладчик. При пошаговом выполнении машинных инструкций, часто бывает полезным сделать `display/i $pc'. Это велит GDB автоматически отображать инструкцию, которая будет выполняться следующей, каждый раз, когда ваша программа останавливается. См. раздел 8.6 Автоматическое отображение. Аргумент является счетчиком повторений, как для step.
nexti
nexti арг
ni
Выполнить одну машинную инструкцию, но если это вызов функции, продолжать до возврата из нее. Аргумент является счетчиком повторений, как для next.

5.3 Сигналы

Сигнал--это асинхронное событие, которое может произойти в программе. Операционная система определяет возможные типы сигналов и дает каждому типу имя и номер. В Unix, например, SIGINT---это сигнал, получаемый программой, когда вы вводите знак прерывания (часто C-c); SIGSEGV---сигнал, получаемый программой при ссылке на область памяти, отличную от всех используемых областей; SIGALRM появляется при срабатывании интервального таймера (возникает только, если ваша программа запросила временной сигнал).

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

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

Обычно, GDB установлен так, чтобы игнорировать неошибочные сигналы, такие как SIGALRM (чтобы не мешать их действию при исполнении вашей программы), но немедленно останавливать вашу программу всякий раз, когда возникает сигнал об ошибке. Вы можете изменить эти установки командой handle.

info signals
info handle
Напечатать таблицу всех типов сигналов и описания, как GDB будет обрабатывать каждый из них. Вы можете использовать эту команду, чтобы посмотреть номера всех определенных типов сигналов. info handle является синонимом для info signals.
handle сигнал ключевые-слова...
Изменить способ, которым GDB обрабатывает сигнал. сигнал может быть номером сигнала или его именем (с `SIG' или без него в начале). Ключевые-слова определяют, какие сделать изменения.

Ключевые слова, допускаемые командой handle, могут быть сокращены. Вот их полные имена:

nostop
GDB не должен останавливать вашу программу при получении этого сигнала. Все же он может вывести сообщение, уведомляющее о получении сигнала.
stop
GDB должен остановить вашу программу при получении этого сигнала. Это также подразумевает ключевое слово print.
print
GDB должен вывести сообщение при возникновении данного сигнала.
noprint
GDB вообще не должен замечать возникновение сигнала. Это также подразумевает ключевое слово nostop.
pass
GDB должен позволить вашей программе увидеть этот сигнал; ваша программа может обработать сигнал, или же она может завершиться, если сигнал фатальный и не обработан.
nopass
GDB не должен позволять вашей программе видеть этот сигнал.

Когда сигнал останавливает вашу программу, он невидим для нее, пока вы не продолжите выполнение. Затем ваша программа видит сигнал, если в данный момент на рассматриваемый сигнал распространяется действие команды pass. Другими словами, после того, как GDB сообщит о сигнале, вы можете использовать команду handle c pass или nopass, чтобы указать, должна ли ваша программа увидеть этот сигнал при продолжении.

Вы также можете использовать команду signal для того, чтобы помешать вашей программе увидеть сигнал или, наоборот, заставить ее заметить обычно игнорируемый сигнал, или чтобы подать ей произвольный сигнал в любое время. Например, если ваша программа остановилась вследствие какой-либо ошибки обращения к памяти, вы можете сохранить правильные значения в ошибочные переменные и продолжить выполнение, в надежде посмотреть на дальнейшее выполнение, но ваша программа вероятно немедленно остановилась бы из-за фатального сигнала, как только она бы его заметила. Чтобы помешать этому, вы можете продолжить выполнение с `signal 0'. См. раздел 11.3 Подача сигнала вашей программе.

5.4 Остановка и запуск многонитевых программ

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

break ном-строки thread номер-нити
break ном-строки thread номер-нити if ...
ном-строки определяет строки исходного текста; существует несколько способов их задания, но результат всегда один и тот же--указать строку исходного текста. Используйте классификатор `thread номер-нити' с командой точки останова, чтобы указать GDB, что вы хотите остановить программу, только когда определенная нить достигнет этой точки. номер-нити---это один из числовых идентификаторов нити, присвоенный GDB, показываемый в первой колонке при выводе `info threads'. Если при установке точки останова вы не укажете `thread номер-нити', точка останова будет действовать для всех нитей вашей программы. Вы также можете использовать классификатор thread для условных точек останова; в этом случае, поместите `thread номер-нити' перед условием точки останова, вот так:
(gdb) break frik.c:13 thread 28 if bartab > lim

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

Наоборот, когда вы снова запускаете программу, все нити начинают выполняться. Это верно даже при пошаговом выполнении такими командами, как step или next.

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

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

В некоторых операционных системах вы можете заблокировать планировщик заданий и тем самым позволить выполняться только одной нити.

set scheduler-locking режим
Устанавливает режим блокировки планировщика заданий. Если он установлен в off, то блокировки нет и любая нить может выполняться в любое время. Если этот режим установлен в on, то только текущая нить может выполняться, когда выполнение продолжается. Режим step производит оптимизацию для пошагового выполнения. Он не дает другим нитям "захватывать приглашение" путем приоритетного прерывания обслуживания текущей нити во время пошагового выполнения. Другие нити едва ли получат возможность начать выполнение, когда вы выполняете очередной шаг. С большей вероятностью они начнут выполняться, когда вы выполняете команду next на вызове функции, и им не что не помешает выполняться, когда вы используете такие команды, как `continue', `until' или `finish'. Однако, если другие нити не достигнут точки останова в течение отведенного ему для выполнения времени, они никогда не перехватят приглашение GDB у отлаживаемой вами нити.
show scheduler-locking
Отобразить текущий режим блокировки.


[Содержание]   [Назад]   [Пред]   [Вверх]   [След]   [Вперед]