Основные цели применения отладчика---остановка вашей программы до ее завершения, или чтобы в случае нарушений в работе вашей программы вы могли выяснить их причину.
Внутри GDB ваша программа может остановиться по нескольким
причинам, таким как сигнал, точка останова, или достижение новой строки
после команды GDB, такой как step
. Затем вы можете
исследовать и изменять значения переменных, устанавливать новые точки
останова и удалять старые, и затем продолжить выполнение. Обычно,
выводимые GDB сообщения предоставляют достаточную информацию о
состоянии вашей программы, но вы также можете запросить эту информацию
явно в любое время.
info program
Точка останова останавливает вашу программу всякий раз, когда ее
выполнение достигает определенной точки. Для каждой точки останова вы
можете добавлять условия для лучшего управления условиями остановки.
Вы можете устанавливать точки останова командой
break
и ее вариантами (see section Установка точек останова), чтобы задать место, где должна остановиться
ваша программа, по номеру строки, имени функции или точному адресу.
В конфигурациях HP-UX, SunOS 4.x, SVR4 и Alpha OSF/1, вы можете устанавливать
точки останова в разделяемых библиотеках до запуска выполняемого файла.
В системах HP-UX существует небольшое ограничение: вы должны подождать,
пока программа не перестанет выполняться, для установки точек
останова в подпрограммах из разделяемой библиотеки, которые не
вызываются напрямую из программы (например, подпрограммах, являющихся
аргументами вызова pthread_create
).
Точка наблюдения---это специальная точка останова, которая останавливает вашу программу при изменении значения выражения. Вы должны использовать другую команду для установки точки наблюдения (see section Установка точек наблюдения), но помимо этого, вы можете обращаться с ней так же, как с любой другой точкой останова: вы включаете, отключаете и удаляете точки останова и точки наблюдения при помощи одних и тех же команд.
Вы можете установить, что значения из вашей программы должны отображаться автоматически, когда GDB останавливается в точке останова. See section Автоматическое отображение.
Точка перехвата---это другая специализированная точка останова,
которая останавливает вашу программу при возникновении события
определенного типа, такого как выбрасывание исключения в Си++ или
загрузка библиотеки. Также как с точками наблюдения, вы используете
другую команду для установки точки перехвата, (see section Установка точек перехвата), но помимо этого, вы можете
обращаться с ней так же, как с любой другой точкой останова. (Для
остановки, когда ваша программа получает сигнал, используйте команду
handle
; смотрите section Сигналы.)
Когда вы создаете точку останова, наблюдения или перехвата, GDB присваивает ей номер; эти номера являются последовательными целыми числами, начинающимися с единицы. Во многих командах для управления различными возможностями точек останова, вы используете эти номера для указания, какую точку останова вы хотите изменить. Каждая точка останова может быть включена или отключена; если точка останова отключена, она не оказывает никакого влияния на вашу программу, пока вы снова не включите ее.
Некоторые команды GDB допускают в качестве указания точек останова, на которые они действуют, их диапазоны. Диапазон точек останова---это или номер одной точки, например `5', или два таких номера, в порядке увеличения, разделенные дефисом, например `5-7'. Когда команде задается диапазон точек останова, она действует на все точки останова в этом диапазоне.
Точки останова устанавливаются командой break
(сокращенно
b
). Вспомогательная переменная отладчика `$bpnum' хранит
номер последней установленной вами точки останова; смотрите
section Вспомогательные переменные, для
обсуждения того, что вы можете делать со вспомогательными переменными.
Вы можете задавать место для установки новой точки останова несколькими способами.
break функция
break +смещение
break -смещение
break номер-строки
break имя-файла:номер-строки
break имя-файла:функция
break *адрес
break
break
устанавливает точку останова на
инструкции, которая должна быть выполнена следующей в выбранном кадре
стека (see section Исследование стека). В любом выбранном кадре,
кроме самого внутреннего, это останавливает вашу программу, как только
управление возвращается в этот кадр. Это похоже на результат команды
finish
в кадре внутри выбранного кадра---за исключением того, что
finish
не оставляет активной точки останова. Если вы используете
break
без аргументов в самом внутреннем кадре, GDB
останавливается, когда в следующий раз достигает текущего места; это
может быть полезно внутри циклов.
Обычно GDB игнорирует точки останова, когда он возобновляет
выполнение, пока не будет выполнена хотя бы одна
инструкция. Если бы он этого не делал, вы не могли бы продолжать
выполнение после точки останова, не отключив сперва эту точку останова.
Это правило применяется вне зависимости от того, существовала или нет
точка останова, когда ваша программа остановилась.
break ... if усл
tbreak арг
break
, и точка останова
устанавливается аналогичным образом, но она автоматически уничтожается
после того, как ваша программа первый раз на ней остановится.
See section Отключение точек останова.
hbreak арг
break
, и точка
останова устанавливается аналогичным образом, но она требует аппаратной
поддержки и некоторые целевые платформы могут ее не иметь. Основной
целью этого является отладка кода EPROM/ROM, так что вы можете установить точку
останова на инструкции без изменения инструкции. Это может быть
использовано с новой генерацией ловушек, предоставляемой SPARClite DSU и
некоторыми машинами на базе x86. Эти платформы будут генерировать
ловушки, когда программа обращается к некоторым данным или адресу
инструкции, которые назначены регистрам отладки. Однако, регистры
аппаратных точек останова могут хранить ограниченное число точек
останова. Например, на DSU, только две точки останова могут быть
установлены одновременно, и GDB будет отвергать эту команду,
если используется больше. Удалите или отключите неиспользуемые
аппаратные точки останова перед установкой новых (see section Отключение точек останова). See section Условия останова.
thbreak арг
hbreak
, и точка останова устанавливается
аналогичным образом. Однако, как в случае команды tbreak
, точка
останова автоматически уничтожается после того, как программа первый раз
на ней остановится. Также, как и в случае команды hbreak
,
точка останова требует аппаратной поддержки и некоторые аппаратные
платформы могут ее не иметь. See section Отключение точек останова. Смотрите также section Условия останова.
rbreak рег-выр
break
. Вы можете удалять их, отключать,
или делать их условными таким же способом, как любые другие точки
останова.
Регулярные выражения имеют стандартный синтаксис, используемый такими
средствами, как `grep'. Заметьте, что это отличается от
синтаксиса, используемого оболочками; так, например, foo*
подходит для всех функций, которые включают fo
, за которым
следует любое число букв o
. Существует неявное .*
в
начале и в конце введенного вами регулярного выражения, так что для
нахождения только тех функций, которые начинаются на foo
,
используйте ^foo
.
При отладке программ, написанных на Си++, rbreak
полезна для
установки точек останова на перегруженных функциях, не являющихся
членами никакого специального класса.
info breakpoints [n]
info break [n]
info watchpoints [n]
info break
показывает условие на
строке, следующей за этой точкой; команды точки останова, если они есть,
перечисляются после этого.
info break
с номером точки останова n в качестве аргумента
отображает только эту точку. Вспомогательная переменная $_
и
адрес по умолчанию для исследования для команды x
устанавливаются
равными адресу последней из перечисленных точек останова (see section Исследование памяти).
info break
отображает то число раз, которое точка останова была
активирована. Это особенно полезно при использовании вместе с командой
ignore
. Вы можете игнорировать большое число активаций точки
останова, посмотреть информацию о точке останова чтобы узнать, сколько
раз она активировалась, и затем запустить заново, игнорируя на единицу
меньше, чем это число. Это быстро приведет вас к последней активации
этой точки останова.
GDB позволяет вам установить любое число точек останова в одном и том же месте вашей программы. В этом нет ничего глупого или бессмысленного. Когда точки останова являются условными, это даже полезно (see section Условия останова).
GDB сам иногда устанавливает точки останова в вашей программе
для специальных целей, таких как правильная обработка longjmp
(в
программах на Си). Этим внутренним точкам останова присваиваются
отрицательные номера, начиная с -1
; `info breakpoints' не
отображает их.
Вы можете увидеть эти точки останова с помощью служебной команды GDB `maint info breakpoints'.
maint info breakpoints
breakpoint
watchpoint
longjmp
longjmp
.
longjmp resume
longjmp
.
until
until
.
finish
finish
.
shlib events
Вы можете использовать точку наблюдения для остановки выполнения, как только изменится значение какого-либо выражения, не предсказывая конкретное место, где это может произойти.
В зависимости от вашей системы, точки наблюдения могут быть реализованы программно или аппаратно. GDB осуществляет программную реализацию точек наблюдения путем пошагового выполнения вашей программы и проверки значения переменной на каждом шаге, что в сотни раз медленнее нормального выполнения. (Но тем не менее это может стоить того, найти ошибку в программе, когда вы не представляете, в какой ее части она находится, может быть очень нелегко.)
В некоторых системах, таких как HP-UX, Linux и некоторых других платформах, базирующихся на x86, GDB включает поддержку для аппаратных точек наблюдения, которые не замедляют выполнение вашей программы.
watch выраж
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 может не заметить, когда действия в не текущей нити изменяют выражение. (Аппаратные же точки наблюдения напротив, наблюдают за выражением во всех нитях.)
Вы можете использовать точки перехвата, чтобы вызвать остановку
отладчика в ответ на определенные типы событий в программе, такие как
исключения в Си++ или загрузка разделяемой библиотеки. Для установки
точки перехвата используйте команду catch
.
catch событие
throw
catch
exec
exec
. В настоящее время это доступно только на HP-UX.
fork
fork
. В настоящее время это доступно только на HP-UX.
vfork
vfork
. В настоящее время это доступно только на HP-UX.
load
load имя-библ
unload
unload имя-библ
tcatch событие
Используйте команду info break
для получения списка текущих точек
перехвата.
В настоящее время, в GDB существуют некоторые ограничения на
обработку исключений Си++ (catch throw
и catch catch
):
Иногда catch
не является лучшим способом отладки обработки
исключений: если вам необходимо точно знать, где исключение возбуждено,
то лучше остановиться до того, как вызван обработчик исключения,
так как в этом случае вы можете увидеть стек до того, как произойдет
какое-либо развертывание.
Если вместо этого вы установите точку останова в обработчике исключений,
то может быть нелегко определить, где исключение было возбуждено.
Для остановки сразу перед вызовом обработчика исключений, вам необходимы
некоторые знания о реализации. В случае GNU Си++, исключения
возбуждаются путем вызова библиотечной функции __raise_exception
,
которая имеет следующий интерфейс ANSI Си:
/* addr -- где хранится идентификатор исключения.
id -- идентификатор исключения. */
void __raise_exception (void **addr, void *id);
Для того, чтобы отладчик перехватывал все исключения до того, как
произойтет развертывание стека, установите точку останова на
__raise_exception
(see section Точки останова, точки наблюдения и точки перехвата).
С помощью условных точек останова (see section Условия останова), зависящих от величины id, вы можете остановить вашу программу, когда возбуждается определенное исключение. Вы можете использовать несколько условных точек останова, чтобы остановить программу, когда возбуждается любое из нескольких исключений.
Часто бывает необходимо уничтожить точку останова, наблюдения или перехвата, когда она сделала свое дело и вы больше не хотите останавливать там свою программу. Это называется уничтожением точки останова. Точка останова, которая была уничтожена, более не существует; она забыта.
С помощью команды clear
вы можете удалять точки останова в
соответствии с тем, где они находятся в вашей программе. С помощью
команды delete
вы можете удалять отдельные точки останова,
наблюдения или перехвата, указывая их номера.
Не обязательно удалять точку останова, чтобы продолжить выполнение после нее. GDB автоматически игнорирует точки останова на первой инструкции, которая должна быть выполнена, когда вы продолжаете исполнение без изменения адреса выполнения.
clear
clear функция
clear имя-файла:функция
clear номер-строки
clear имя-файла:номер-строки
delete [breakpoints] [диапазон...]
set confirm off
). Вы можете сократить это команду
как d
.
Вместо того, чтобы удалять точку останова, наблюдения или перехвата, вам может быть удобнее отключить ее. Это делает точку останова бездействующей, как если бы она была удалена, но информация о ней запоминается, так что вы можете позже включить ее снова.
Вы отключаете и включаете точки останова, наблюдения и перехвата
командами enable
и disable
, возможно указывая один или
более номеров точек останова в качестве аргументов. Используйте
info break
или info watch
для распечатки списка точек
останова, наблюдения и перехвата, если вы не знаете какие номера
использовать.
Точка останова, наблюдения или перехвата может находиться в одном из четырех состояний:
break
, изначально находится в таком состоянии.
tbreak
, изначально находится в этом состоянии.
Вы можете использовать следующие команды для включения или отключения точек останова, наблюдения и перехвата:
disable [breakpoints] [диапазон...]
disable
как dis
.
enable [breakpoints] [диапазон...]
enable [breakpoints] once диапазон...
enable [breakpoints] delete диапазон...
Кроме точек останова, установленных командой tbreak
(see section Установка точек останова),
установленные вами точки останова изначально включены; следовательно,
они становятся отключенными или включенными только когда вы используете
одну из вышеперечисленных команд. (Команда until
может
устанавливать и удалять свою собственную точку останова, но она не
изменяет состояние ваших других точек останова; см. section Продолжение и выполнение по шагам.)
Простейшая точка останова останавливает вашу программу каждый раз, когда управление достигает заданного места. Вы можете также указать условие для точки останова. Условие является просто булевым выражением в вашем языке программирования (see section Выражения). Точка останова с условием вычисляет выражение каждый раз, когда ваша программа достигает ее, и ваша программа остановится только в том случае, если условие истинно.
Это противоположно использованию утверждений для проверки правильности программы; в этом случае, вы хотите остановиться, когда утверждение нарушается---то есть, когда условие ложно. В Си, если вы хотите проверить утверждение, выраженное условием assert, вы должны установить условие `! assert' на соответствующей точке останова.
Условия также допускаются для точек наблюдения; вам они могут не понадобиться, так как точка наблюдения так или иначе контролирует значение выражения---но может оказаться проще, скажем, просто установить точку наблюдения на имя переменной и указать условие, проверяющее, является ли новое значение тем, которое нас интересует.
Условия останова могут иметь побочные эффекты, и даже могут вызывать функции в вашей программе. Это может быть полезным, например, для активации функций, которые запоминают продвижение выполнения вашей программы, или для использования ваших собственных функций печати для форматирования специальных структур данных. Результаты полностью предсказуемы, если нет другой включенной точки останова по тому же адресу. (В этом случае, GDB может сначала увидеть другую точку останова и остановить вашу программу программу без проверки условия первой точки останова.) Заметьте, что команды точек останова обычно более удобны и гибки, чем условия останова, для выполнения побочных эффектов, когда достигается точка останова (see section Команды точки останова).
Условия останова могут быть заданы в момент установки точки останова,
используя `if' в аргументах команды break
. See section Установка точек останова. Они могут быть также
изменены в любой момент с помощью команды condition
.
Вы также можете использовать ключевое слово if
с командой
watch
. Команда catch
не распознает ключевое слово
if
; condition
является единственным способом наложить
дальнейшие условия на точку перехвата.
condition номер выражение
condition
, GDB немедленно проверяет
выражение на синтаксическую корректность и для определения, что
символы в нем имеют объекты ссылки в контексте вашей точки останова.
Если выражение использует символы, не существующие в контексте
точки останова, GDB выведет сообщение об ошибке:
No symbol "foo" in current context.(8)
Однако, GDB в действительности не вычисляет выражение в
момент подачи команды condition
(или команды, устанавливающей
точку останова с условием, такой как break if ...
).
See section Выражения.
condition номер
Специальным случаем условия для точки останова является остановка только когда точка останова была достигнута определенное число раз. Это настолько полезно, что существует специальный способ сделать это, используя счетчик игнорирования точки останова. Каждая точка останова имеет счетчик игнорирования, являющийся целым числом. Как правило, счетчик игнорирования равен нулю, и, следовательно, не производит никакого действия. Но если ваша программа достигает точки останова, чей счетчик игнорирования положителен, тогда вместо того чтобы остановиться, она лишь уменьшит его на единицу и продолжит выполнение. В результате, если величина счетчика игнорирования равна n, точка останова не остановит программу следующие n раз, когда программа его достигнет.
ignore номер значение
continue
для возобновления выполнения вашей
программы от точки останова, вы можете установить счетчик игнорирований
непосредственно как аргумент к continue
, а не использовать
ignore
. See section Продолжение и выполнение по шагам.
Если точка останова имеет положительный счетчик игнорирований и условие,
то условие не проверяется. Как только счетчик игнорирований достигнет
нуля, GDB возобновит проверку условия.
Вы можете достигнуть эффекта счетчика игнорирований с помощью такого
условия, как `$foo-- <= 0', используя вспомогательную
переменную отладчика, которая уменьшается каждый раз.
See section Вспомогательные переменные.
Счетчики игнорирований можно использовать с точками останова, точками наблюдения и точками перехвата.
Вы можете подать любой точке останова (наблюдения или перехвата) ряд команд, которые будут выполняться при остановке вашей программы на этой точке останова. Например, вы можете захотеть вывести значения определенных выражений, или включить другие точки останова.
commands [номер]
... список-команд ...
end
end
.
Чтобы удалить все команды от точки останова, введите commands
и
немедленно за этим end
, то есть задайте пустой список команд.
Без аргумента номер, commands
относится к последней
установленной точке останова, наблюдения или перехвата (но не к
последней встреченной).
Нажатие RET, как средство повторения последней команды GDB, отключено внутри списка-команд.
Вы можете использовать команды для точки останова, чтобы снова запустить
вашу программу на выполнение. Просто используйте команду continue
, или
step
, или любую другую команду, возобновляющую выполнение.
После команды, возобновляющей выполнение, любые другие команды в списке
игнорируются. Так сделано потому, что каждый раз, когда вы
возобновляете выполнение (даже просто с помощью next
или
step
), вы можете встретить другую точку останова---которая может
иметь свой собственный список команд, что приведет к неоднозначности,
какой из списков выполнять.
Если в качестве первой команды в списке команд вы укажете silent
,
обычное сообщение об остановке на точке останова не будет выводиться.
Это может быть желательно для точек останова, которые должны вывести
определенное сообщение, и затем продолжить выполнение. Если никакая из
оставшихся команд ничего не выводит, вы не увидите никакого знака о том,
что точка останова была достигнута. silent
имеет смысл только в
начале списка команд точки останова.
Команды echo
, output
и printf
позволяют вам
более точно контролировать выводимый текст, и часто полезны в "тихих"
точках останова. See section Команды для управляемого вывода.
Например, вот как вы можете использовать команды точки останова для
вывода величины 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
Некоторые языки программирования (особенно Си++) допускают, чтобы одно и
то же имя функции было определено несколько раз, для применения в
различных контекстах. Это называется перегрузкой. Когда имя
функции перегружается, `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)
В некоторых операционных системах точки останова не могут быть
использованы в программе, если какой-либо другой процесс выполняет эту
программу. В этом случае, попытка выполнить или продолжить выполнение
программы с точкой останова приводит тому, что GDB печатает
сообщение об ошибке:
Cannot insert breakpoints.
The same program may be running in another process.(9)
Когда это происходит, у вас есть три варианта дальнейших действий:
exec-file
для указания, что GDB
должен выполнять вашу программу под этим именем. Затем запустите вашу
программу снова.
Аналогичное сообщение может выводиться, если вы запрашиваете слишком
много активных аппаратно-поддерживаемых точек останова и наблюдения:
Stopped; cannot insert breakpoints.
You may have requested too many hardware breakpoints and watchpoints.(10)
Это сообщение выводится, когда вы пытаетесь возобновить выполнение программы, так как только тогда GDB знает точно, сколько аппаратных точек останова и наблюдения ему нужно установить.
Когда это сообщение выводится, вам необходимо отключить или удалить некоторые аппаратно-поддерживаемые точки останова и наблюдения, и затем продолжить.
Продолжение означает возобновление выполнения программы до ее
нормального завершения. Напротив, пошаговое выполнение означает
выполнение еще одного "шага" вашей программы, где "шаг" быть либо
одной строкой исходного кода, либо одной машинной инструкцией (в
зависимости от того, какую именно команду вы используете). И в
случае продолжения, и в случае выполнения по шагам, ваша программа
может остановиться и раньше, вследствие точки останова или сигнала.
(Если она останавливается по сигналу, вы можете использовать
handle
, или `signal 0' для возобновления выполнения.
See section Сигналы.)
continue [счетчик-игнор]
c [счетчик-игнор]
fg [счетчик-игнор]
ignore
(see section Условия останова).
Аргумент счетчик-игнор имеет смысл только если ваша программа
остановилась в точке останова. В остальных случаях, аргумент к
continue
игнорируется.
Синонимы c
и fg
(от foregroung, так как отлаживаемая
программа считается фоновой), предоставляются исключительно для
удобства, и имеют в точности тот же смысл, что и continue
.
Чтобы возобновить выполнение с другого места, вы можете использовать
return
(see section Возврат из функции) чтобы вернуться
назад к вызывающей функции; или jump
(see section Продолжение исполнения с другого адреса) для перехода к произвольному месту в
вашей программе.
Типичная техника для использования пошагового выполнения заключается в установке точки останова (see section Точки останова, точки наблюдения и точки перехвата) на начале функции или раздела вашей программы, где предположительно находится ошибка, выполнении вашей программы до остановки на этой точке останова, и затем пошаговом выполнении подозреваемого участка, с исследованием интересуемых переменных, пока вы не увидите, что случилась ошибка.
step
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
(see section Возврат из функции).
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
(see section Установка точек останова). Эта форма команды использует точки останова, и,
следовательно, является более быстрой, чем until
без аргумента.
stepi
stepi арг
si
step
.
nexti
nexti арг
ni
next
.
Сигнал---это асинхронное событие, которое может произойти в программе.
Операционная система определяет возможные типы сигналов и дает каждому
типу имя и номер. В Unix, например, SIGINT
---это сигнал, получаемый
программой, когда вы вводите знак прерывания (часто C-c);
SIGSEGV
---сигнал, получаемый программой при ссылке на область
памяти, отличную от всех используемых областей; SIGALRM
появляется
при срабатывании интервального таймера (возникает только, если ваша
программа запросила временной сигнал).
Некоторые сигналы, такие как SIGALRM
, являются обычной частью
функционирования вашей программы. Другие, такие как SIGSEGV
,
обозначают ошибки; эти сигналы являются фатальными (они немедленно
убивают вашу программу), если программа не определила заранее другой
способ их обработки. SIGINT
не указывает на ошибку в вашей
программе, но обычно является фатальным, так что он может выполнять
функцию прерывания: убить программу.
GDB способен обнаружить любое появление сигнала в вашей программе. Вы можете заранее сообщить GDB, что делать для каждого типа сигнала.
Обычно, GDB установлен так, чтобы игнорировать неошибочные сигналы,
такие как SIGALRM
(чтобы не мешать их действию при исполнении вашей
программы), но немедленно останавливать вашу программу всякий раз, когда
возникает сигнал об ошибке. Вы можете изменить эти установки командой
handle
.
info signals
info handle
info handle
является синонимом для info signals
.
handle сигнал ключевые-слова...
Ключевые слова, допускаемые командой handle
, могут быть
сокращены. Вот их полные имена:
nostop
stop
print
.
print
noprint
nostop
.
pass
nopass
Когда сигнал останавливает вашу программу, он невидим для нее,
пока вы не продолжите выполнение. Затем ваша программа видит
сигнал, если в данный момент на рассматриваемый сигнал
распространяется действие команды pass
. Другими словами, после
того, как GDB сообщит о сигнале, вы можете использовать команду
handle
c pass
или nopass
, чтобы
указать, должна ли ваша программа увидеть этот сигнал при продолжении.
Вы также можете использовать команду signal
для того, чтобы
помешать вашей программе увидеть сигнал или, наоборот, заставить ее
заметить обычно игнорируемый сигнал, или чтобы подать ей произвольный
сигнал в любое время. Например, если ваша программа остановилась
вследствие какой-либо ошибки обращения к памяти, вы можете сохранить
правильные значения в ошибочные переменные и продолжить выполнение, в
надежде посмотреть на дальнейшее выполнение, но ваша программа вероятно
немедленно остановилась бы из-за фатального сигнала, как только она бы
его заметила. Чтобы помешать этому, вы можете продолжить выполнение с
`signal 0'. See section Подача сигнала вашей программе.
Когда ваша программа имеет несколько нитей выполнения (see section Отладка программ с несколькими нитями), вы можете выбрать, установить точки останова либо во всех, либо в каких-то отдельных нитях.
break ном-строки thread номер-нити
break ном-строки thread номер-нити if ...
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
Go to the first, previous, next, last section, table of contents.