«Ричард Столмен, Роланд Пеш, Стан Шебс и другие. (Присылайте сообщения об ошибках и комментарии к GDB по адресу bug-gdb Отладка с помощью GDB TEXinfo 1999-10-01.07 Copyright c 1988-2000 Free Software ...»
Временно включить указанные точки останова. GDB отключает любую из этих точек останова немедленно после срабатывания.
enable [breakpoints] delete диапазон...
Включить указанные точки останова до первого срабатывания, затем уничтожить. GDB удаляет любую из этих точек останова, как только ваша программа останавливается на ней.
Кроме точек останова, установленных командой tbreak (см. Раздел 5.1.1 [Установка точек останова], с. 32), установленные вами точки останова изначально включены; следовательно, они становятся отключенными или включенными только когда вы используете одну из вышеперечисленных команд. (Команда until может устанавливать и удалять свою собственную точку останова, но она не изменяет состояние ваших других точек останова; см. Раздел 5.2 [Продолжение и выполнение по шагам], с. 44.) 5.1.6 Условия останова Простейшая точка останова останавливает вашу программу каждый раз, когда управление достигает заданного места. Вы можете также указать условие для точки останова.
Условие является просто булевым выражением в вашем языке программирования (см. Раздел 8.1 [Выражения], с. 61). Точка останова с условием вычисляет выражение каждый раз, когда ваша программа достигает ее, и ваша программа остановится только в том случае, если условие истинно.
Это противоположно использованию утверждений для проверки правильности программы; в этом случае, вы хотите остановиться, когда утверждение нарушается—то есть, когда условие ложно. В Си, если вы хотите проверить утверждение, выраженное условием assert, вы должны установить условие ‘! assert’ на соответствующей точке останова.
Условия также допускаются для точек наблюдения; вам они могут не понадобиться, так как точка наблюдения так или иначе контролирует значение выражения—но может оказаться проще, скажем, просто установить точку наблюдения на имя переменной и указать условие, проверяющее, является ли новое значение тем, которое нас интересует.
Условия останова могут иметь побочные эффекты, и даже могут вызывать функции в вашей программе. Это может быть полезным, например, для активации функций, которые запоминают продвижение выполнения вашей программы, или для использования ваших собственных функций печати для форматирования специальных структур данных.
Результаты полностью предсказуемы, если нет другой включенной точки останова по тому же адресу. (В этом случае, GDB может сначала увидеть другую точку останова и остановить вашу программу программу без проверки условия первой точки останова.) Заметьте, что команды точек останова обычно более удобны и гибки, чем условия останова, для выполнения побочных эффектов, когда достигается точка останова (см. Раздел 5.1. [Команды точки останова], с. 41).
Условия останова могут быть заданы в момент установки точки останова, используя ‘if’ в аргументах команды break. См. Раздел 5.1.1 [Установка точек останова], с. 32. Они могут быть также изменены в любой момент с помощью команды condition.
Вы также можете использовать ключевое слово if с командой watch. Команда catch не распознает ключевое слово if; condition является единственным способом наложить дальнейшие условия на точку перехвата.
condition номер выражение Задайте выражение как условие остановки для точки останова, наблюдения или перехвата с номером номер. После того, как вы установили условие, данная точка останова остановит вашу программу только если значение выражения будет истинным (ненулевым, в Си). Когда вы используете condition, GDB немедленно проверяет выражение на синтаксическую корректность и для определения, что символы в нем имеют объекты ссылки в контексте вашей точки останова. Если выражение использует символы, не существующие в контексте точки останова, GDB выведет сообщение об ошибке:
Однако, GDB в действительности не вычисляет выражение в момент подачи команды condition (или команды, устанавливающей точку останова с условием, такой как break if...). См. Раздел 8.1 [Выражения], с. 61.
condition номер Снимает условие с точки останова с номером номер. Она становится обычной безусловной точкой останова.
Специальным случаем условия для точки останова является остановка только когда точка останова была достигнута определенное число раз. Это настолько полезно, что существует специальный способ сделать это, используя счетчик игнорирования точки останова.
Каждая точка останова имеет счетчик игнорирования, являющийся целым числом. Как правило, счетчик игнорирования равен нулю, и, следовательно, не производит никакого действия. Но если ваша программа достигает точки останова, чей счетчик игнорирования положителен, тогда вместо того чтобы остановиться, она лишь уменьшит его на единицу и продолжит выполнение. В результате, если величина счетчика игнорирования равна n, точка останова не остановит программу следующие n раз, когда программа его достигнет.
ignore номер значение Устанавливает счетчик игнорирований точки останова с номером номер в значение. Следующие значение раз, когда точка останова будет достигнута, выполнение вашей программы не будет остановлено; кроме как уменьшить счетчик игнорирований, GDB не производит никаких действий.
Чтобы точка останова сработала при следующем достижении, установите счетчик в ноль.
Когда вы используете continue для возобновления выполнения вашей программы от точки останова, вы можете установить счетчик игнорирований непосредственно как аргумент к continue, а не использовать ignore. См. Раздел 5. [Продолжение и выполнение по шагам], с. 44.
Если точка останова имеет положительный счетчик игнорирований и условие, то условие не проверяется. Как только счетчик игнорирований достигнет нуля, GDB возобновит проверку условия.
Вы можете достигнуть эффекта счетчика игнорирований с помощью такого printf "x is %d\n",x Одним из применений команд точки останова является компенсация одной ошибки, так, чтобы вы могли искать другую. Поместите точку останова сразу после строки кода, содержащей ошибку, задайте ей условие для определения случая, в котором было сделано что-то ошибочное, и определите команды для присвоения правильных значений тем переменным, для которых это требуется. Закончите командой continue, чтобы ваше программа не останавливалась, а начните с команды silent, чтобы не было никакого вывода. Вот пример:
5.1.8 Меню точки останова Некоторые языки программирования (особенно Си++) допускают, чтобы одно и то же имя функции было определено несколько раз, для применения в различных контекстах. Это называется перегрузкой. Когда имя функции перегружается, ‘break функция’ не достаточно, чтобы указать GDB, где вы хотите установить точку останова. Если вы столкнулись с этой проблемой, вы можете использовать что-то типа ‘break функция(типы)’ для указания, какую конкретную версию функции вы имеете в виду. В противном случае, GDB предлагает вам выбор из пронумерованных вариантов для различных возможных точек останова, и ждет вашего выбора с приглашением ‘>’. Первыми двумя вариантами всегда являются ‘[0] cancel’ и ‘[1] all’. Ввод 1 устанавливает точку останова на каждом определении функции, и ввод 0 прерывает команду break без установки новых точек останова.
Например, следующая выдержка из сеанса иллюстрирует попытку установить точку останова на перегруженном символе String::after. Мы выбрали три конкретных определения имени функции:
(gdb) b String::after [2] file:String.cc; line number: [3] file:String.cc; line number: [4] file:String.cc; line number: [5] file:String.cc; line number: [6] file:String.cc; line number: [7] file:String.cc; line number: 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.
5.1.9 “Не удается поместить точки останова” В некоторых операционных системах точки останова не могут быть использованы в программе, если какой-либо другой процесс выполняет эту программу. В этом случае, попытка выполнить или продолжить выполнение программы с точкой останова приводит тому, что GDB печатает сообщение об ошибке:
Cannot insert breakpoints.
The same program may be running in another process. Когда это происходит, у вас есть три варианта дальнейших действий:
1. Удалить или отключить точки останова, и затем продолжить.
2. Приостановить GDB и скопировать файл, содержащий вашу программу, под другим иненем. Возобновить работу GDB и использовать команду exec-file для указания, что GDB должен выполнять вашу программу под этим именем. Затем запустите вашу программу снова.
3. Скомпоновать заново вашу программу так, чтобы сегмент текста был неразделяемым, используя ключ компоновщика ‘-N’. Ограничения операционной системы могут не распространяться на неразделяемые выполняемые файлы.
Аналогичное сообщение может выводиться, если вы запрашиваете слишком много активных аппаратно-поддерживаемых точек останова и наблюдения:
Stopped; cannot insert breakpoints.
Не удается поместить точки останова. Эта программа может выполняться в другом процессе. (Прим. переводчика) You may have requested too many hardware breakpoints and watchpoints. Это сообщение выводится, когда вы пытаетесь возобновить выполнение программы, так как только тогда GDB знает точно, сколько аппаратных точек останова и наблюдения ему нужно установить.
Когда это сообщение выводится, вам необходимо отключить или удалить некоторые аппаратно-поддерживаемые точки останова и наблюдения, и затем продолжить.
5.2 Продолжение и выполнение по шагам Продолжение означает возобновление выполнения программы до ее нормального завершения. Напротив, пошаговое выполнение означает выполнение еще одного “шага” вашей программы, где “шаг” быть либо одной строкой исходного кода, либо одной машинной инструкцией (в зависимости от того, какую именно команду вы используете). И в случае продолжения, и в случае выполнения по шагам, ваша программа может остановиться и раньше, вследствие точки останова или сигнала. (Если она останавливается по сигналу, вы можете использовать handle, или ‘signal 0’ для возобновления выполнения. См.
Раздел 5.3 [Сигналы], с. 46.) continue [счетчик-игнор] c [счетчик-игнор] fg [счетчик-игнор] Возобновить выполнение программы, с того адреса, где ваша программа остановилась последний раз; все точки останова, установленные по этому адресу, пропускаются. Необязательный аргумент счетчик-игнор позволяет вам задать количество последующих игнорирований точки останова в этом месте; его действие совпадает с действием ignore (см. Раздел 5.1.6 [Условия останова], с. 40).
Аргумент счетчик-игнор имеет смысл только если ваша программа остановилась в точке останова. В остальных случаях, аргумент к continue игнорируется.
Синонимы c и fg (от foregroung, так как отлаживаемая программа считается фоновой), предоставляются исключительно для удобства, и имеют в точности Чтобы возобновить выполнение с другого места, вы можете использовать return (см.
Раздел 11.4 [Возврат из функции], с. 103) чтобы вернуться назад к вызывающей функции; или jump (см. Раздел 11.2 [Продолжение с другого адреса], с. 102) для перехода к произвольному месту в вашей программе.
Типичная техника для использования пошагового выполнения заключается в установке точки останова (см. Раздел 5.1 [Точки останова], с. 31) на начале функции или раздела вашей программы, где предположительно находится ошибка, выполнении вашей программы до остановки на этой точке останова, и затем пошаговом выполнении подозреваемого участка, с исследованием интересуемых переменных, пока вы не увидите, что случилась ошибка.
Продолжить выполнение вашей программы, пока управление не достигнет друstep гой строки исходного текста, затем остановить ее и возвратить управление Предупреждение: Если вы используете команду step, когда управление находится внутри функции, которая была скомпилирована без Остановлено; не удается поместить точки останова. Вы могли запросить слишком много аппаратноподдерживаемых точек останова и наблюдения. (Прим. переводчика) отладочной информации, выполнение продолжается, пока управление не достигнет функции, которая имеет ее. Аналогично, пошаговое выполнение не будет заходить в функцию, скомпилированную без отладочной информации. Для пошагового выполнения таких функций используйте команду stepi, описанную ниже.
Команда step останавливается только на первой инструкции строки исходного текста. Это предотвращает множественные остановки, которые в противном случае могут возникнуть в операторе switch, цикле for, и так далее. step продолжает останавливаться, если функция, имеющая отладочную информацию, вызывается внутри строки. Другими словами, step заходит внутрь функций, Также, команда step входит в функцию только если для нее существует информация о номерах строк. Иначе она действует как команда next. Это позволяет избежать проблем, появляющихся при использовании cc -gl на машинах MIPS.
Раньше step заходила в подпрограмму, если существовала хоть какая-нибудь отладочная информация о подпрограмме.
step число Продолжает выполнение как по команде step, но делает это число раз. Если достигается точка останова, или приходит сигнал, не связанный с пошаговым выполнением, до выполнения числа шагов, пошаговое выполнение сразу останавливается.
next [число] Продолжает выполнение до следующей строки исходного текста в текущем (внутреннем) кадре стека. Это аналогично step, но вызовы функций, которые появляются внутри строки кода, выполняются без остановки. Выполнение останавливается, когда управление достигает другой строки кода в исходном уровне стека, который выполнялся, когда вы дали команду next. Эта команда Аргумент число является счетчиком повторений, как для step.
Команда next останавливается только на первой инструкции исходной строки.
Это предотвращает множественные остановки, которые иначе могут возникнуть в операторах switch, циклах for, и так далее.
Продолжить выполнение до возврата из функции в выбранном кадре стека.
finish Напечатать возвращенное значение (если таковое существует).
Сравните это с командой return (см. Раздел 11.4 [Возврат из функции], с. 103).
until Продолжить выполнение до достижения строки исходного текста, следующей за текущей, в текущем кадре стека. Эта команда используется для избежания выполнения цикла по шагам больше одного раза. Она похожа на команду next, за исключением того, что когда until встречает переход, она автоматически продолжает выполнение, пока счетчик выполнения программы не станет Это означает, что когда вы достигаете конца цикла после его выполнения по шагам, until продолжает выполнение вашей программы, пока она не выйдет из цикла. Напротив, команда next в конце цикла просто переходит назад в начало цикла, что заставляет вас выполнять по шагам следующую итерацию.
until всегда останавливает вашу программу, если она пытается выйти из текущего кадра стека.
until может привести к несколько неожиданным результатам, если порядок машинных кодов не совпадает с порядком строк исходного текста. Например, в следующем отрывке сеанса отладки, команда f (frame) показывает, что выполнение остановилось на строке 206; хотя, когда мы используем until, мы #0 main (argc=4, argv=0xf7fffae8) at m4.c: Это произошло потому, что для эффектвности выполнения компилятор сгенерировал код для проверки окончания цикла в конце, а не в начале цикла—даже если проверка в цикле for Си написана до тела цикла. Кажется, что команда until переместилась назад к началу цикла, когда двигалась к этому выражению; однако, в действительности она не переходила к более раннему оператору—в терминах фактического машинного кода.
until без аргументов работает посредством пошагового выполнения отдельных инструкций, и, следовательно, является более медленной, чем until с аргументом.
until положение u положение Продолжить выполнение вашей программы, пока либо указанное место не будет достигнуто, либо не произойдет возврат из текущего кадра стека. положение может быть любой из доступных форм аргумента для break (см. Раздел 5.1.1 [Установка точек останова], с. 32). Эта форма команды использует точки останова, и, следовательно, является более быстрой, чем until без аргумента.
stepi stepi арг Выполнить одну машинную инструкцию, затем остановиться и вернуться в При пошаговом выполнении машинных инструкций, часто бывает полезным сделать ‘display/i $pc’. Это велит GDB автоматически отображать инструкцию, которая будет выполняться следующей, каждый раз, когда ваша программа останавливается. См. Раздел 8.6 [Автоматическое отображение], с. 66.
Аргумент является счетчиком повторений, как для 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, могут быть сокращены. Вот их полные имена:
GDB не должен останавливать вашу программу при получении этого сигнала.
nostop Все же он может вывести сообщение, уведомляющее о получении сигнала.
GDB должен остановить вашу программу при получении этого сигнала. Это stop также подразумевает ключевое слово print.
GDB должен вывести сообщение при возникновении данного сигнала.
print GDB вообще не должен замечать возникновение сигнала. Это также подразуnoprint мевает ключевое слово nostop.
GDB должен позволить вашей программе увидеть этот сигнал; ваша програмpass ма может обработать сигнал, или же она может завершиться, если сигнал GDB не должен позволять вашей программе видеть этот сигнал.
nopass Когда сигнал останавливает вашу программу, он невидим для нее, пока вы не продолжите выполнение. Затем ваша программа видит сигнал, если в данный момент на рассматриваемый сигнал распространяется действие команды pass. Другими словами, после того, как GDB сообщит о сигнале, вы можете использовать команду handle c pass или nopass, чтобы указать, должна ли ваша программа увидеть этот сигнал при продолжении.
Вы также можете использовать команду signal для того, чтобы помешать вашей программе увидеть сигнал или, наоборот, заставить ее заметить обычно игнорируемый сигнал, или чтобы подать ей произвольный сигнал в любое время. Например, если ваша программа остановилась вследствие какой-либо ошибки обращения к памяти, вы можете сохранить правильные значения в ошибочные переменные и продолжить выполнение, в надежде посмотреть на дальнейшее выполнение, но ваша программа вероятно немедленно остановилась бы из-за фатального сигнала, как только она бы его заметила. Чтобы помешать этому, вы можете продолжить выполнение с ‘signal 0’. См. Раздел 11.3 [Подача сигнала вашей программе], с. 103.
5.4 Остановка и запуск многонитевых программ Когда ваша программа имеет несколько нитей выполнения (см. Раздел 4.9 [Отладка многонитевых программ], с. 26), вы можете выбрать, установить точки останова либо во всех, либо в каких-то отдельных нитях.
break ном-строки thread номер-нити break ном-строки thread номер-нити if...
ном-строки определяет строки исходного текста; существует несколько способов их задания, но результат всегда один и тот же—указать строку исходного Используйте классификатор ‘thread номер-нити’ с командой точки останова, чтобы указать GDB, что вы хотите остановить программу, только когда определенная нить достигнет этой точки. номер-нити—это один из числовых идентификаторов нити, присвоенный GDB, показываемый в первой колонке при Если при установке точки останова вы не укажете ‘thread номер-нити’, точка останова будет действовать для всех нитей вашей программы.
Вы также можете использовать классификатор thread для условных точек останова; в этом случае, поместите ‘thread номер-нити’ перед условием точки останова, вот так:
При любой остановке вашей программы под управлением GDB, прекращается выполнение всех нитей, а не только текущей. Это позволяет вам исследовать полное состояние программы, включая переключение между нитями, не опасаясь, что это может изменить что-либо в дальнейшем.
Наоборот, когда вы снова запускаете программу, все нити начинают выполняться. Это верно даже при пошаговом выполнении такими командами, как step или next.
В частности, GDB не может пошагово выполнять все нити параллельно. Так как планированием выполнения нити занимается операционная система отлаживаемой цели (не контролируемая GDB), то пока в текущей нити выполняется один шаг, в других может выполниться несколько. Более того, когда выполнение программы останавливается, другие потоки вообще могут остановиться в середине операторов, а не на границе между ними.
Вы даже можете обнаружить, что после продолжения исполнения или после пошагового выполнения ваша программа остановилась в другой нити. Это случается всякий раз, когда другая нить достигает точки останова, получает сигнал или в ней возникает исключительная ситуация, прежде чем первая нить завершает выполнение того, что вы запросили.
В некоторых операционных системах вы можете заблокировать планировщик заданий и тем самым позволить выполняться только одной нити.
set scheduler-locking режим Устанавливает режим блокировки планировщика заданий. Если он установлен в off, то блокировки нет и любая нить может выполняться в любое время. Если этот режим установлен в on, то только текущая нить может выполняться, когда выполнение продолжается. Режим step производит оптимизацию для пошагового выполнения. Он не дает другим нитям “захватывать приглашение” путем приоритетного прерывания обслуживания текущей нити во время пошагового выполнения. Другие нити едва ли получат возможность начать выполнение, когда вы выполняете очередной шаг. С большей вероятностью они начнут выполняться, когда вы выполняете команду next на вызове функции, и им не что не помешает выполняться, когда вы используете такие команды, как ‘continue’, ‘until’ или ‘finish’. Однако, если другие нити не достигнут точки останова в течение отведенного ему для выполнения времени, они никогда не перехватят приглашение GDB у отлаживаемой вами нити.
show scheduler-locking Отобразить текущий режим блокировки.
50 Отладка с помощью GDB 6 Исследование стека Когда ваша программа остановилась, первое, что вам нужно знать—где она остановилась и как она туда попала.
Каждый раз, когда ваша программа производит вызов функции, о нем создается определенная информация. Она включает положение вызова в вашей программе, параметры вызова и локальные переменные вызываемой функции. Информация сохраняется в блоке данных, называемом кадром стека. Кадры стека размещаются в области памяти, называемой стеком вызовов.
Команды GDB для исследования стека позволяют вам увидеть всю эту информацию при остановке вашей программы.
Один из кадров стека является выбранным GDB, и многие команды GDB неявно относятся к нему. В частности, когда вы запрашиваете у GDB значение переменной вашей программы, это значение находится в выбранном кадре. Для выбора интересующего вас кадра существуют специальные команды GDB. См. Раздел 6.3 [Выбор кадра], с. 52.
Когда ваша программа останавливается, GDB автоматически выбирает текущий выполняющийся кадр и выдает его краткое описание, аналогично команде frame (см. Раздел 6.4 [Информация о кадре стека], с. 53).
6.1 Кадры стека Cтек вызовов разделен на непрерывные участки, называемые кадрами стека, или кадрами для краткости; каждый кадр является данными, связанными с одним вызовом одной функции. Кадр содержит аргументы, переданные функции, ее локальные переменные и адрес, с которого она выполняется.
Когда ваша программа стартует, стек содержит только один кадр—для функции main.
Он называется начальным или внешним кадром. Каждый раз при вызове функции создается новый кадр. При каждом выходе из функции, кадр этого вызова функции уничтожается. Если функция является рекурсивной, для нее может существовать множество кадров.
Кадр для функции, исполняемой в данный момент, называется внутренним кадром. Это кадр, созданный самым последним из всех существующих кадров стека.
Внутри вашей программы кадры стека идентифицируются своим адресом. Кадр стека состоит из множества байт, каждый из которых имеет свой собственный адрес; каждый тип компьютеров имеет свой способ для выбора одного байта, чей адрес служит адресом кадра. Обычно, пока выполнение происходит в данном кадре, этот адрес содержится в регистре, называемом регистром указателя кадра.
GDB присваивает номера всем существующим кадрам стека, начиная с нуля для внутреннего кадра, единицу—вызвавшему его кадру, и так далее. В действительности, эти номера не существуют в вашей программе; они назначаются GDB, чтобы предоставить вам способ различать кадры стека в командах GDB.
Некоторые компиляторы позволяют компилировать функции так, чтобы они выполнялись без создания кадров стека. (Например, ключ gcc ‘-fomit-frame-pointer’ создает функции без кадра.) Это иногда делается с часто используемыми библиотечными функциями, чтобы сохранить время, требуемое для установки кадра. GDB имеет ограниченные возможности для обработки таких функциональных вызовов. Если вызов внутренней функции происходит без создания кадра стека, GDB, тем не менее, описывает его так, как если бы он имел отдельный кадр, который имеет, как обычно, номер 0, позволяя корректно трассировать цепочку функциональных вызовов. Однако, GDB не имеет средств для работы с функциями без кадра в другом месте стека.
frame арг Команда frame позволяет вам перемещаться от одного кадра стека к другому, и распечатывать выбранный вами кадр. Арг может быть либо адресом кадра, либо его номером. Без аргумента, frame выводит текущий кадр стека.
select-frame Команда select-frame позволяет вам перемещаться от одного кадра стека к другому без его распечатки. Это “тихая” версия frame.
6.2 Цепочки вызовов Цепочка вызовов предоставляет собой информацию о том, как ваша программа оказалась там, где она есть. Она отображает по одной строке для каждого кадра, начиная с текущего выполняющегося кадра (кадра 0), за которым следует кадр, из которого он был вызван (кадр 1), и далее вверх по стеку.
backtrace Вывести цепочку вызовов всего стека: по одной строке на кадр, для всех кадров Вы можете прервать цепочку вызовов в любое время, введя знак системного прерывания, обычно C-c.
backtrace n bt n То же самое, но выводятся только n внутренних кадров.
backtrace -n То же самое, но выводятся только n внешних кадров.
bt -n where и info stack (сокращенно info s)—дополнительные синонимы для backtrace.
Каждая строка в цепочке вызовов показывает номер кадра и имя функции. Счетчик команд также показывается, если только вы не используете set print address off. Цепочка вызовов также показывает имя исходного файла, номер строки и аргументы функции. Значение счетчика команд опускается, если он указывает на начало кода для данной строки.
Ниже приведен пример цепочки вызовов. Она была получена командой ‘bt 3’, так что она показывает три внутренних кадра.
#0 m4_traceon (obs=0x24eb0, argc=1, argv=0x2b8c8) #1 0x6e38 in expand_macro (sym=0x2b600) at macro.c: #2 0x6840 in expand_token (obs=0x0, t=177664, td=0xf7fffb08) (More stack frames follow...) Информация о нулевом кадре не начинается со значения счетчика команд, что указывает на то, что ваша программа остановилась в начале кода для строки 993 файла builtin.c.
6.3 Выбор кадра Большинство команд для исследования стека и других данных в вашей программе применяются выбранному в данный момент кадру. Здесь приведены команды для выбора кадра стека; все они завершаются выводом краткого описания выбранного кадра стека.
frame n fn Выбрать кадр номер n. Напоминаем, что нулевой кадр—это внутренний (исполняемый в данный момент) кадр, первый кадр—тот, из которого вызван нулевой, и так далее. Кадр с наибольшим номером—это кадр для функции frame адрес f адрес Выбрать кадр, расположенный по адресу адрес. В основном это полезно, если формирование цепочки кадров стека было нарушено из-за ошибки, сделавшей невозможным для GDB правильное присвоение номеров всем кадрам. Кроме того, это может быть полезным, когда у вашей программы есть несколько стеков и происходит переключение от одного к другому.
В архитектуре SPARC, команде frame для выбора произвольного кадра необходимо указать два адреса: указатель кадра и указатель вершины стека.
В архитектурах MIPS и Alpha требуется два адреса: указатель вершины стека В архитектуре 29k требуется три адреса: указатель вершины стека регистров, указатель команд и указатель вершины стека памяти.
up n Переместиться вверх по стеку на n кадров. Для положительных значений n, это перемещение происходит по направлению к внешнему кадру, к кадрам с большими номерами, к кадрам, которые существуют дольше. По умолчанию n down n Передвинуться вниз по стеку на n кадров. Для положительных значений n, это продвижение происходит по направлению к внутреннему кадру, к кадру с меньшим номером, к кадрам, которые были созданы позже. По умолчанию, значение n принимается равным единице. Вы можете сокращать down как do.
Все эти команды заканчиваются выводом двух строк, описывающих кадр. Первая строка показывает номер кадра, имя функции, аргументы, имя исходного файла и номер выполняемой строки в этом кадре. Вторая строка показывает содержимое этой строки исходного текста.
Например:
#1 0x22f0 in main (argc=1, argv=0xf7fffbf4, env=0xf7fffbfc) После такого вывода, команда list без аргументов выводит десять строк, расположенных вокруг точки выполнения в кадре. См. Раздел 7.1 [Вывод строк исходного текста], с. 55.
up-silently n down-silently n Эти две команды являются вариантами up и down соответственно, отличаясь от них тем, что делают свою работу “тихо”, не отображая новый кадр. Они предназначены для использования в основном в командных сценариях GDB, где вывод может быть ненужным и отвлекающим.
6.4 Информация о кадре стека Существуют несколько других команд для вывода информации о выбранном кадре стека.
frame При использовании без аргументов, эта команда не выбирает новый кадр, а выводит краткое описание текущего выбранного кадра стека. Эту команду можно сокращать как f. С аргументом, эта команда используется для выбора кадра стека. См. Раздел 6.3 [Выбор кадра стека], с. 52.
info frame Эта команда выводит подробное описание выбранного кадра стека, включаюinfo f • адрес следующего вниз по стеку кадра (вызываемого из данного) • адрес следующего вверх по стеку кадра (того, из которого был вызван • язык, на котором написан исходный код, соответствующий этому кадру • адрес локальных переменных кадра • сохраненный в кадре счетчик команд (адрес выполнения в кадре, вызвавшем данный) • регистры, которые были сохранены в кадре Подробное описание полезно, если из-за какой-либо ошибки формат стека не соответствует обычным соглашениям.
info frame адрес info f адрес Вывести подробное описание кадра стека, расположенного по адресу адрес, не выбирая этот кадр. Выбранный кадр этой командой не изменяется. Она требует параметр адрес того же типа, что и команда frame (для некоторых архитектур не один, а несколько). См. Раздел 6.3 [Выбор кадра стека], с. 52.
info args Вывести аргументы выбранного кадра, каждый на отдельной строке.
info locals Вывести локальные переменные выбранного кадра, каждую на отдельной строке. Выводятся все переменные (объявленные как статические или как автоматические), доступные в точке выполнения выбранного кадра стека.
info catch Выводит список всех обработчиков исключительных ситуаций, являющихся активными в текущей точке выполнения текущего кадра стека. Чтобы увидеть другие обработчики исключительных ситуаций, перейдите в соответствующую секцию (используя команды up, down или frame); затем наберите info catch.
См. Раздел 5.1.3 [Установка точек перехвата], с. 37.
7 Исследование исходных файлов GDB может выводить части исходных текстов вашей программы, так как отладочная информация, записанная в ней, сообщает GDB, какие исходные файлы использовались при создании программы. Когда ваша программа останавливается, GDB сам выводит строку, на которой она остановилась. Аналогично, когда вы выбираете кадр стека (см. Раздел 6. [Выбор кадра стека], с. 52), GDB выводит строку, на которой остановилось выполнение в этом кадре. Вы можете выводить другие части исходных файлов с помощью явных команд.
Если вы используете GDB через интерфейс к gnu Emacs, вы можете предпочесть воспользоваться средствами Emacs для просмотра исходных текстов; смотрите Глава 17 [Использование GDB под управлением gnu Emacs], с. 161.
7.1 Вывод строк исходного текста Чтобы вывести строки файла с исходным текстом, используйте команду list (сокращенно l). По умолчанию выводятся десять строк. Существует несколько способов определения того, какую часть файла вы хотите вывести.
Здесь представлены наиболее употребительные формы команды list:
list номер-строки Вывести строки, расположенные вокруг строки с номером номер-строки в текущем исходном файле.
list функция Вывести строки, расположенные вокруг начала функции функция.
Вывести еще определенное количество строк. Если последние выведенные строlist ки выводились с помощью команды list, то выводятся строки, следующие за последними выведенными; если, однако, последней выведенной строкой была одиночная строка, выведенная как часть отображения кадра стека (см. Глава [Исследование стека], с. 51), то выводятся строки, расположенные вокруг нее.
Вывести строки, расположенные непосредственно перед последними выведенlist - По умолчанию, для любой из этих форм команды list GDB выводит десять строк исходного текста. Вы можете изменить это командой set listsize:
set listsize число Установить количество выводимых командой list строк в число (если аргумент команды list не задает явно какое-нибудь другое число).
show listsize Отобразить количество строк, выводимых по команде list.
Повторение команды list нажатием RET отбрасывает аргумент, так что это эквивалентно вводу просто list. Это полезнее, чем вывод тех же самых строк снова. Исключение сделано для параметра ‘-’; этот параметр сохраняется при повторе команды, так что каждое повторение приводит к перемещению вверх по исходному файлу.
Обычно команда list ожидает от вас ноль, один или два указателя строк. Указатели строк определяют строки исходного текста; существует несколько способов их задания, но результат всегда заключается в задании строки исходного текста. Вот полное описание возможных параметров команды list:
list указ-стр Вывести строки, расположенные вокруг строки, определяемой указ-стр.
list перв,посл Вывести строки с перв до посл. Оба параметра являются указателями строк.
list,посл Вывести строки, расположенные перед посл.
list перв, Вывести строки, расположенные сразу за последними выведенными.
list + Вывести строки, расположенные непосредственно перед последними выведенlist - list Ниже перечислены способы указания одиночной строки исходного текста—все виды указателей строк.
номер Определяет строку с номером номер из текущего исходного файла. Если в качестве параметров к команде list задано два указателя строк, это относится к тому же исходному файлу, что и первый указатель строки.
+смещение Указывает на строку, смещенную вперед на смещение строк относительно последней выведенной строки. Когда используется в качестве второго указателя строки для команды list, имеющей два указателя, задает строку, смещенную на смещение строк вниз относительно строки, определенной первым указателем.
-смещение Указывает на строку, расположенную на смещение строк раньше последней имя-файла:номер Задает строку номер из исходного файла имя-файла.
функция Определяет строку, с которой начинается тело функции функция. Например, в Си это строка с открывающейся фигурной скобкой.
имя-файла:функция Определяет строку с открывающейся фигурной скобкой, с которой начинается тело функции функция в файле имя-файла. Имя файла необходимо лишь для того, чтобы избежать неоднозначности, когда в различных исходных файлах есть одинаково названные функции.
Определяет строку, соответствующую адресу адрес программы. адрес может *адрес 7.2 Поиск в исходных файлах Существуют две команды для поиска по регулярному выражению в текущем исходном файле.
forward-search рег-выраж search рег-выраж Команда ‘forward-search рег-выраж’ проверяет на соответствие регулярному выражению рег-выраж каждую строку, начиная со строки, следующей за последней выведенной. Найденная строка выводится. Вы можете использовать синоним ‘search рег-выраж’ или сокращать имя команды как fo.
reverse-search рег-выраж Команда ‘reverse-search рег-выраж’, двигаясь назад, проверяет на соответствие регулярному выражению рег-выраж каждую строку, начиная с предшествующей последней выведенной. Найденная строка выводится. Вы можете сокращать эту команду как rev.
7.3 Определение каталогов с исходными файлами Исполняемые программы иногда не сохраняют имена каталогов, в которых находились исходные файлы, из которых они скомпилированы, а хранят лишь имена файлов. Даже если они их сохранили, каталоги могли быть перемещены в период между компиляцией и сеансом отладки. У GDB есть список каталогов для поиска исходных файлов; он называется путь для исходных файлов. Каждый раз, когда GDB требуется исходный файл, он перебирает по порядку все каталоги из этого списка, пока не находит файл с требуемым именем. Заметьте, что пути поиска исполняемых файлов для этой цели не используются, как не используется и текущий рабочий каталог, если только он не присутствует в пути для исходных файлов.
Если GDB не может найти исходный файл, используя путь для исходных файлов, а в объектном файле программы указан какой-либо каталог, GDB просматривает также и его. В последнюю очередь, если путь для исходных файлов пуст и запись о каталоге компиляции отсутствует, GDB просматривает текущий каталог.
При переустановке или переупорядочивании пути для исходных файлов, GDB очищает любую запомненную им информацию о том, где исходные файлы были найдены и о расположении строк в них.
Когда вы вызываете GDB, путь для исходных файлов содержит только ‘cdir’ и ‘cwd’, в этом порядке. Для добавления других каталогов, используйте команду directory.
directory имя-каталога...
dir имя-каталога...
Добавить каталог имя-каталога в начало пути для исходных файлов. Этой команде могут быть заданы несколько имен, разделенные ‘:’ (‘;’ в MS-DOS и MS-Windows, где ‘:’ обычно является частью абсолютного имени файла) или пробелом. Вы можете указать каталог, который уже содержится в пути для исходных файлов; это переместит его в начало, так что GDB будет просматривать его раньше.
Вы можете использовать строку ‘$cdir’ для ссылки на каталог компиляции (если информация о нем сохранена), и ‘$cwd’ для ссылки на текущий рабочий каталог. ‘$cwd’ не есть то же самое, что ‘.’. Первая отслеживает текущий рабочий каталог, который может меняться во время вашего сеанса работы с GDB, тогда как вторая сразу преобразовывается в текущий каталог в момент его добавления в путь для исходных файлов.
directory Очистить путь для файлов с исходными текстами. Эта команда требует подтверждения.
show directories Вывести путь поиска исходных файлов: показать, какие каталоги он содержит.
Если ваш путь для исходных файлов перемешан с уже неиспользуемыми каталогами, GDB может иногда вызвать недоумение, найдя неправильный вариант исходного файла.
Вы можете исправить ситуацию следующим образом:
1. Использовать directory без параметров, чтобы очистить путь поиска исходных файлов.
2. Использовать directory с подходящими аргументами, чтобы переустановить каталоги, которые вы хотите видеть в пути для исходных файлов. Вы можете добавить все каталоги одной командой.
7.4 Исходный текст и машинный код Вы можете использовать команду info line, чтобы отобразить cтроки исходного текста в программные адреса (и наоборот), и команду disassemble, чтобы вывести диапазон адресов в виде машинных инструкций. При запуске в режиме gnu Emacs, команда info line выводит стрелку, указывающую на заданную строку. Также info line выводит адреса как в символьной форме, так и в шестнадцатеричной.
info line указ-стр Выводит начальный и конечный адреса скомпилированного кода, соответствующего строке исходного текста указ-стр. Вы можете определить строки исходного текста любым способом, воспринимаемым командой list (см. Раздел 7. [Вывод строк исходного текста], с. 55).
Например, мы можем использовать info line для определения положения объектного кода первой строки функции m4_changequote:
(gdb) info line m4_changequote Line 895 of "builtin.c" starts at pc 0x634c and ends at 0x6350.
Мы также можем запросить (используя *адрес как форму задания указ-стр), какая строка исходного текста соответствует определенному адресу:
(gdb) info line *0x63ff Line 926 of "builtin.c" starts at pc 0x63e4 and ends at 0x6404.
После info line, адрес, используемый по умолчанию для команды x, меняется на начальный адрес строки, так что ‘x/i’ достаточно для начала исследования машинного кода (см. Раздел 8.5 [Исследование памяти], с. 65). Этот адрес также сохраняется как значение вспомогательной переменной $_ (см. Раздел 8.9 [Вспомогательные переменные], с. 73).
disassemble Эта специализированная команда служит для дампа диапазона памяти в виде машинных инструкций. Диапазоном памяти по умолчанию является функция, в которой находится счетчик программы в выбранном кадре. Одиночным параметром этой команды является значение счетчика программы; GDB выводит дамп функции, которой принадлежит указанный адрес. Два параметра определяют диапазон адресов для дампа (первый включается, второй исключается).
Следующий пример показывает результат дисассемблирования диапазона адресов кода HP PA-RISC 2.0:
(gdb) disas 0x32c4 0x32e Dump of assembler code from 0x32c4 to 0x32e4:
0x32c8 : ldw 0x22c(sr0,r1),r 0x32cc : ldil 0x3000,r 0x32d0 : ble 0x3f8(sr4,r31) 0x32d8 : addil -0x800,dp 0x32dc : ldo 0x588(r1),r 0x32e0 : ldil 0x3000,r End of assembler dump.
Некоторые архитектуры имеют несколько широко используемых наборов мнемоник инструкций или другой синтаксис.
set disassembly-flavor набор-инструкций Выбрать набор инструкций для использования при дисассемблировании программы командами disassemble и x/i.
В настоящее время, эта команда определена только для Intel x86. Вы можете установить набор-инструкций в intel или att. По умолчанию установлено att, диалект AT&T используется по умолчанию ассемблерами Unix на архитектурах, базирующихся на x86.
60 Отладка с помощью GDB 8 Исследование данных Для исследования данных в вашей программе обычно используется команда print (сокращенно p) или ее синоним inspect. Она вычисляет и выводит значение выражения, записанного на том же языке, что и ваша программа (см. Глава 9 [Использование GDB с различными языками], с. 77).
print выраж print /f выраж выраж является выражением (на исходном языке). По умолчанию, значение выраж выводится в формате, соответствующем его типу данных; вы можете выбрать другой формат, указав ‘/f ’, где f—буква, определяющая формат;
смотрите Раздел 8.4 [Форматы вывода], с. 64.
print Если вы опустите выраж, GDB отображает последнее значение снова (из исprint /f тории значений; см. Раздел 8.8 [История значений], с. 72). Это предоставляет вам удобный способ изучить то же самое значение в другом формате.
Команда x позволяет исследовать данные на более низком уровне. Она исследует данные в памяти по указанному адресу и выводит их в указанном формате. См. Раздел 8. [Исследование памяти], с. 65.
Если вас интересует информация о типах или о том, как объявлены поля структуры или класса, используйте команду ptype выраж вместо print. См. Глава 10 [Исследование таблицы символов], с. 97.
8.1 Выражения print и многие другие команды GDB допускают в качестве параметра выражение и вычисляют его значение. В выражении GDB допустимо использование любого типа констант, переменных или операторов, определенных в используемом вами языке программирования, включая условные выражения, вызовы функций, приведение типов и строковые постоянные. К сожалению, исключением являются символы, определенные командами препроцессора #define.
GDB поддерживает константы-массивы в выражениях, введенных пользователем. Синтаксис следующий: {элемент, элемент... }. Например, вы можете использовать команду print {1, 2, 3}, чтобы создать в памяти массив, который будет доступен в программе так же, как выделенный функцией malloc.
По причине широкого распространения Си, большинство выражений в примерах этого руководства написаны на Си. См. Глава 9 [Использование GDB с различными языками], с. 77, для информации об использовании выражений в других языках.
В этом разделе мы обсуждаем операторы, которые вы можете использовать в выражениях GDB независимо от используемого вами языка программирования.
Приведения типов поддерживается во всех языках, а не только в Си, так как бывает очень полезно преобразовать число в указатель, чтобы исследовать структуру, расположенную по этому адресу в памяти.
GDB поддерживает эти операторы, в дополнении к следующим, являющимися общими для языков программирования:
‘@’ является бинарным оператором, позволяющим рассматривать области памяти как массивы. См. Раздел 8.3 [Исскуственные массивы], с. 63, для дополнительной информации.
‘::’ позволяет вам указывать переменную в терминах файла или функции, где она определена. См. Раздел 8.2 [Переменные программы], с. 62.
{тип} адрес Ссылается на объект типа тип, хранящийся в памяти по адресу адрес. Адрес может быть любым выражением, значением которого является целое число или указатель (но вокруг бинарных операторов, также как и вокруг оператора приведения типа, требуются скобки). Эта конструкция допустима, независимо от того, какого типа данные предположительно расположены по адресу.
8.2 Переменные программы Чаще всего в качестве выражения используется имя переменной вашей программы.
Переменные в выражениях трактуются в контексте выбранного кадра стека (см. Раздел 6.3 [Выбор кадра стека], с. 52); они могут быть либо • глобальными (или статическими) либо • видимыми из точки выполнения в данном кадре, в соответствии с правилами определения области видимости языка программирования.
Это означает, что в функции вы можете исследовать и использовать переменную a всякий раз, когда ваша программа выполняется в пределах функции foo, но вы можете использовать или исследовать переменную b только тогда, когда ваша программа выполняется внутри блока, в котором она объявлена.
Есть исключение: вы можете ссылаться на переменную или функцию, областью видимости которой является единственный исходный файл, даже если точка текущего выполнения в нем не находится. Допускается существование нескольких переменных или функций с одинаковым именем (в различных исходных файлах). Если это так, обращение к этому имени приводит к непредсказуемым результатам. Если хотите, вы можете указать статическую переменную в конкретной функции или в файле, используя двойное двоеточие:
файл::переменная функция::переменная Здесь файл или функция—название контекста для статической переменной. В первом случае вы можете использовать кавычки, чтобы GDB рассматривал имя файла как одно слово; например, чтобы вывести глобальное значение переменной x, определенной в ‘f2.c’:
(gdb) p ’f2.c’::x Такое использование ‘::’ крайне редко конфликтует с похожим использованием той же записи в Си++. GDB также поддерживает использование оператора определения области видимости Си++ в выражениях.
Предупреждение: В некоторых случаях, в определенной точке функции (сразу после входа в новую область видимости, и непосредственно перед выходом из нее) может показаться, что локальная переменная имеет неверное значение.
Вы можете столкнуться с этой проблемой при пошаговом выполнении по одной машинной инструкции. Она возникает из-за того, что на большинстве машин процедура установки кадра стека (включая определения локальных переменных) занимает более одной инструкции; если вы производите пошаговое выполнение по одной машинной инструкции, может показаться, что переменная имеет неверное значение, пока кадр стека не будет полностью построен. При выходе, для уничтожения кадра стека обычно также требуется более одной инструкции; после начала пошагового выполнения этой группы инструкций, определения локальных переменных могут пропасть.
Это также может случиться, когда компилятор делает значительную оптимизацию.
Чтобы быть уверенным, что вы всегда видите точные значения, отключите всю оптимизацию при компиляции.
Другой возможный эффект оптимизации компилятора заключается в уничтожении неиспользуемых переменных, или в присвоении переменных регистрам (а не адресам памяти).
В зависимости от поддержки таких ситуаций, предоставляемой форматом отладочной информации, который использует компилятор, GDB может не вывести значения таких локальных переменных. Если это происходит, GDB выведет сообщение, подобное этому:
No symbol "foo" in current context.
Для решения таких проблем, либо перекомпилируйте программу без оптимизации, или используйте другой формат отладочной информации, если компилятор поддерживает несколько таких форматов. Например GCC, компилятор gnu Си/Си++, обычно поддерживает ключ ‘-gstabs’. ‘-gstabs’ создает отладочную информацию в формате, являющимся развитием таких форматов, как COFF. У вас может быть возможность использовать DWARF-2 (‘-gdwarf-2’), который тоже является эффективной формой представления отладочной информации. Смотрите раздел “Опции для отладки вашей программы или gnu CC” в Использование gnu CC, для дополнительной информации.
8.3 Искусственные массивы Часто бывает полезным вывести несколько объектов одного типа, расположенных в памяти последовательно; часть массива или динамический массив, для которого в программе существует только указатель.
Вы можете это сделать, обращаясь к непрерывному участку памяти как к искусственному массиву, используя бинарный оператор ‘@’. Левым операндом для ‘@’ должен быть первый элемент желаемого массива, и он должен быть индивидуальным объектом. Правым операндом должна быть длина массива. Результатом операции будет массив, все элементы которого имеют тот же тип, что и левый аргумент. Первым элементом массива является левый аргумент; второй элемент формируется из байтов памяти, непосредственно следующих за байтами, содержащими первый элемент, и так далее. Например, если в программе есть строка int *array = (int *) malloc (len * sizeof (int));
то вы можете вывести содержимое array с помощью Левый операнд операции ‘@’ должен находиться в памяти. Значения массивов, полученных операцией ‘@’, при индескации ведут себя точно так же, как и другие массивы, и приводятся к указателям при использовании в выражениях. Искусственные массивы чаще всего появляются в выражениях через историю значений (см. Раздел 8.8 [История значений], с. 72), после вывода одного из них.
Другой способ создания искусственного массива—использование приведения типов. Оно заново интерпретирует значение так, как если бы оно было массивом. Значение не обязано находиться в памяти.
(gdb) p/x (short[2])0x $1 = {0x1234, 0x5678} Если вы опускаете длину массива (как в ‘(тип[])значение’), GDB для удобства вычисляет его размер для заполнения значениями (как ‘sizeof(значение)/sizeof(тип)’:
(gdb) p/x (short[])0x $2 = {0x1234, 0x5678} Иногда механизма искусственных массивов бывает недостаточно; в сравнительно сложных структурах данных, интересующие нас элементы могут не быть смежными— например, если вас интересуют значения указателей в массиве. Одно из полезных решений этой проблемы—использование вспомогательной переменной (см. Раздел 8.9 [Вспомогательные переменные], с. 73) в качестве счетчика в выражении, выводящем первое интересующее нас значение, а затем повторять это выражение нажатием RET. Предположим, например, у вас есть массив dtab указателей на структуры, и вас интересуют значения полей fv в каждой структуре. Ниже приведен пример ваших возможных действий:
p dtab[$i++]->fv 8.4 Форматы вывода По умолчанию, GDB печатает значение в соответствии с его типом. Это не всегда отвечает вашему желанию. Например, вы можете захотеть вывести число в шестнадцатеричной записи, или указатель в десятичной. Или вы можете захотеть просмотреть данные по некоторому адресу в памяти в виде строки символов или в виде инструкций. Для этого, при выводе значения укажите формат вывода.
Простейшим применением форматов вывода является форматирование вывода уже вычисленного выражения. Это осуществляется путем начала параметров команды print с косой черты и символа формата. Поддерживаются следующие символы формата:
Рассматривать биты значения как целое, и вывести целое в шестнадцатеричx Вывести как целое в двоичном виде. Буква ‘t’ означает “two”. Вывести в виде адреса, как абсолютного в шестнадцатеричной записи, так и в виде смещения от ближайшего предшествующего символа. Вы можете использовать этот формат для того, чтобы определить, где (в какой функции) расположен какой-либо неизвестный адрес:
Рассматривать как целое и вывести в виде строковой постоянной.
Рассматривать биты значения как число с плавающей точкой и вывести с исf пользованием обычного синтаксиса для чисел с плавающей точкой.
‘b’ не может быть использовано, потому что эти символы формата также используются с командой x, где ‘b’ означает “byte”; смотрите Раздел 8.5 [Исследование памяти], с. 65.
Например, чтобы вывести счетчик программы в шестнадцатеричном виде (см. Раздел 8.10 [Регистры], с. 74), введите Обратите внимание, что перед косой чертой не требуется пробела, потому что имена команд в GDB не могут содержать косую черту.
Чтобы вывести последнее значение из истории значений в другом формате, вы можете воспользоваться командой print лишь с указанием формата и без выражения. Например, ‘p/x’ выведет последнее значение в шестнадцатеричной форме.
8.5 Исследование памяти Вы можете использовать команду x (от слова “examine”) для исследования памяти в одном из нескольких форматов, независимо от типов данных вашей программы.
x/nfu адрес x адрес Для исследования памяти используйте команду x.
n, f и u—необязательные параметры, определяющие, сколько памяти отобразить и в каком формате; адрес—это выражение, задающее адрес, с которого вы хотите начать отображение памяти. Если вы используете значения по умолчанию для nfu, то вам не нужно вводить косую черту ‘/’. Некоторые команды устанавливают удобные значения по умолчанию для адреса.
n, счетчик повторений Счетчик повторений является десятичным целым числом; по умолчанию 1. Он определяет, сколько памяти отобразить (считая в единицах u).
f, формат отображения Формат отображения—это один из форматов, используемых командой print, ‘s’ (строка, оканчивающаяся нулем), или ‘i’ (машинная инструкция). Первоначально, значением по умолчанию установлено ‘x’ (шестнадцатеричная форма).
Значение по умолчанию изменяется каждый раз, когда вы используете либо x, u, размер единицы измерений Размер единицы измерений может быть одним из Слова (четыре байта). Это первоначальное значение по умолчанию.
Каждый раз, когда вы определяете размер единицы измерений командой x, этот размер становится размером по умолчанию при последующем использовании x.
(Для форматов ‘s’ и ‘i’, размер единицы измерений игнорируется и обычно не адрес, начальный адрес отображения адрес—это адрес, с которого вы хотите, чтобы GDB начинал отображение памяти. Значение выражения не обязано должно быть указателем (хотя может им быть); оно всегда интерпретируется как целый адрес байта в памяти. См.
Раздел 8.1 [Выражения], с. 61, для дополнительной информации о выражениях. Значением по умолчанию для адреса обычно является адрес, следующий за последним изученным адресом, но некоторые другие команды также устанавливают это значение: info breakpoints (в адрес последней выведенной точки останова), info line (в начальный адрес строки) и print (если вы используете эту команду для отображения значения из памяти).
Например, ‘x/3uh 0x54320’—запрос на вывод трех полуслов (h) памяти в формате беззнаковых десятичных целых (‘u’), начиная с адреса 0x54320. ‘x/4xw $sp’ выводит четыре слова (‘w’) памяти, расположенные над указателем стека (здесь ‘$sp’; см. Раздел 8. [Регистры], с. 74), в шестнадцатеричном виде (‘x’).
Так как все буквы, обозначающие размер единиц измерения, отличаются от букв, определяющих форматы вывода, вы не должны запоминать, формат или размер единиц измерений указывается раньше; это можно делать в любом порядке. Спецификации вывода ‘4xw’ и ‘4wx’ означают в точности одно и то же. (Однако, число n должно быть первым;
‘wx4’ не сработает.) Хотя размер единицы измерения u игнорируется для форматов ‘s’ и ‘i’, тем не менее вы можете воспользоваться счетчиком повторений n; например, ‘3i’ указывает, что вы хотите вывести три машинные инструкции, включая любые операнды. Команда disassemble предоставляет альтернативный способ исследования машинных инструкций;
смотрите Раздел 7.4 [Исходный и машинный код], с. 58.
Все значения по умолчанию для аргументов команды x разработаны таким образом, чтобы облегчить продолжение сканирования памяти с минимальными конкретизациями при очередном использовании x. Например, после того, как вы просмотрели три машинные инструкции с помощью ‘x/3i адрес’, вы можете просмотреть следующие семь, используя просто ‘x/7’. Если вы повторяете команду x нажатием RET, число повторений n остается прежним; другие параметры берутся по умолчанию, как для последовательных использований x.
Адреса и их содержимое, выводимые командой x, не сохраняются в истории значений, так как они мешали бы. Вместо этого, GDB делает их доступными для последующего использования в выражениях как значения вспомогательных переменных $_ и $. После команды x, последний исследованный адрес доступен для использования в выражениях во вспомогательной переменной $_. Содержимое этого адреса, исследованное только что, доступно во вспомогательной переменной $.
Если команде x задан счетчик повторений, адрес и его содержимое сохраняются из последнего выведенного элемента памяти; это не то же самое, что последний выведенный адрес, если в последней строке вывода были отображены несколько элементов.
8.6 Автоматическое отображение Если вам необходимо часто выводить значение какого-либо выражения (чтобы увидеть, как оно меняется), вы можете добавить его в список автоматического отображения, чтобы GDB выводил его значение каждый раз при остановке вашей программы. Каждому выражению, добавленному в список, присваивается идентификационный номер; чтобы удалить выражение из списка, вы указываете этот номер. Автоматическое отображение выглядит следующим образом:
3: bar[5] = (struct hack *) 0x Это отображение показывает номера элементов, выражения и их текущие значения. Как и при отображении, запрашиваемом вручную с помощью x или print, вы можете указать предпочитаемый формат вывода; фактически, display определяет, следует использовать print или x, в зависимости от того, на сколько жесткая ваша спецификация формата:
используется x, если вы указываете размер элемента или один из двух форматов (‘i’ и s), которые поддерживаются только x; в остальных случаях используется print.
display выраж Добавляет выражение выраж к списку выражений, отображаемых каждый раз, когда ваша программа останавливается. См. Раздел 8.1 [Выражения], с. 61.
display не повторяется, если вы повторно нажимаете RET после ее использования.
display/формат выраж Если формат определяет только формат вывода, а не размер или счетчик повторений, выражение выраж добавляется в список автоматического отображения, но его отображение осуществляется в указанном формате формат. См.
Раздел 8.4 [Форматы вывода], с. 64.
display/формат адрес Если форматом является ‘i’ или ‘s’, или он включает в себя размер элементов или их число, выражение адрес добавляется как адрес памяти для исследования при каждой остановке вашей программы. Под исследованием в данном случае подразумевается выполнение ‘x/формат адрес’. См. Раздел 8.5 [Исследование Например, команда ‘display/i $pc’ может быть полезна, чтобы при каждой остановке видеть машинную инструкцию, которая будет выполняться следующей (‘$pc’—это общее обозначение счетчика программы; см. Раздел 8.10 [Регистры], с. 74).
undisplay номера...
delete display номера...
Удалить элементы с номерами номера из списка выражений, подлежащих отображению.
undisplay не повторяется при последующем нажатии RET. (Иначе вы сразу получили бы сообщение об ошибке ‘No display number...’.) disable display номера...
Отключить отображение элементов с номерами номера. Отключенные элементы не выводятся автоматически, но и не забываются. Впоследствии их можно enable display номера...
Включить отображение элементов с номерами номера. Выражения, соответствующие этим номерам, снова будут выводиться автоматически, пока вы укажете обратное.
Отобразить текущие значения выражений из списка, точно так же, как это display происходит при остановке вашей программы.
info display Вывести список выражений, ранее установленных для автоматического отображения, каждое с его номером элемента, но не показывая значений. Список включает отключенные выражения, с соответствующей пометкой. Он также включает в себя выражения, которые не могут быть показаны прямо сейчас, потому что обращаются к автоматическим переменным, недоступным в данный момент.
Если отображаемое выражение обращается к локальным переменным, оно не имеет смысла вне того лексического контекста, для которого оно устанавливалось. Такое выражения отключается, как только выполнение входит в контекст, где одна из его переменных становится неопределенной. Например, если вы дадите команду display last_char, находясь внутри функции с аргументом last_char, GDB будет отображать этот аргумент, пока программа останавливается внутри этой функции. Как только она остановится гдето еще—где нет переменной last_char—отображение будет отключено автоматически.
Вы можете снова включить его при следующей остановке программы там, где last_char будет вновь иметь смысл.
8.7 Параметры вывода GDB предоставляет следующие способы управления выводом массивов, структур и символов.
Данные параметры полезны при отладке программ на любом языке:
set print address set print address on GDB выводит адреса памяти, показывающие положение стека, структур, указателей, точек останова, и так далее, даже когда он отображает также содержимое этих адресов. Значение по умолчанию установлено в on. Например, вот как выглядит отображение кадра стека с установленным set print address set print address off Не выводить адреса при отображении их содержимого. Вот, например, тот же кадр стека, отображенный с установкой set print address off:
Вы можете использовать ‘set print address off’, чтобы удалить все машиннозависимые отображения из интерфейса GDB. Например, с print address off, вы должны получить одинаковый текст для цепочек вызовов на всех машинах, независимо от того, включают они указатели в качестве аргументов или нет.
show print address Показать, должны выводиться адреса или нет.
При выводе адреса в символьной форме, GDB обычно выводит ближайший предшествующий символ плюс смещение. Если этот символ не определяет адрес однозначно (например, это имя, областью действия которого является один исходный файл), вам может потребоваться дать пояснения. Один из способов это сделать—с помощью info line;
например, ‘info line *0x4537’. Альтернативный способ заключается в том, чтобы GDB выводил имя исходного файла и номер строки при выводе символьного адреса:
set print symbol-filename on Велит GDB выводить имя исходного файла и номер строки символа в символьной форме адреса.
set print symbol-filename off Не выводить имя исходного файла и номер строки символа. Принимается по show print symbol-filename Показать, будет GDB выводить имя исходного файла и номер строки в символьной форме адреса или нет.
Другая ситуация, в которой полезно показывать имена файлов и номера строк, возникает при дисассемблировании кода; GDB показывает вам номер строки и исходный файл, которые соответствуют каждой инструкции.
Вы также можете захотеть видеть символьную форму только в том случае, если выводимый адрес достаточно близок к ближайшему предшествующему символу:
set print max-symbolic-offset макс-смещение Велит GDB выводить символьные формы только тех адресов, для которых смещение между ближайшим предшествующим символом и адресом меньше, чем макс-смещение. По умолчанию значение макс-смещение равно 0; в этом случае GDB всегда выводит адрес в символьной форме, если ему предшествует хоть какой-нибудь символ.
show print max-symbolic-offset Запрашивает информацию о максимальном смещении, для которого GDB выводит символьную форму адреса.
Если у вас есть указатель, и вы не знаете, на что он указывает, попробуйте ‘set print symbol-filename on’. Затем вы можете определить название и исходный файл переменной, на которую он указывает, используя ‘p/a указатель’. Это интерпретирует адрес в символьной форме. Например, здесь GDB показывает, что переменная ptt указывает на другую переменную t, определенную в файле ‘hi2.c’:
(gdb) set print symbol-filename on Предупреждение: Для указателей, указывающих на локальные переменные, ‘p/a’ не показывает символьное имя и имя файла, которому принадлежит объект ссылки, даже если установлен соответствующий параметр set print.
Другие установки управляют выводом объектов различных типов:
set print array set print array on Структурный вывод массивов. Этот формат удобенее для чтения, но занимает больше места. По умолчанию отключено.
set print array off Вернуться к сжатому формату вывода массивов.
show print array Показать, какой формат (сжатый или структурный) выбран для отображения set print elements число-элементов Установить ограничение на количество выводимых GDB элементов массива.
Если GDB выводит большой массив, вывод прерывается после того, как будет выведено установленное командой set print elements число элементов. Это ограничение также действует при отображении строк. Когда GDB стартует, этот предел принимается равным 200. Установка число-элементов в ноль означает, что вывод не ограничен.
show print elements Показать количество элементов большого массива, которые будут выведены GDB. Если это число равно 0, вывод не ограничивается.
set print null-stop Указывает GDB прекращать вывод символов массива, как только встретится первый null. Это полезно, когда большие массивы фактически содержат только короткие строки. По умолчанию отключено.
set print pretty on Велит GDB выводить структуры в формате с отступами, по одному элементу set print pretty off Указывает GDB выводить структуры в компактном формате, как здесь:
Этот формат устанавливается по умолчанию.
show print pretty Показать, какой формат GDB использует для вывода структур.
set print sevenbit-strings on Осуществлять вывод, используя только семибитные символы; если этот параметр установлен, GDB отображает любые восьмибитные символы (в строках или символьных значениях), используя запись \nnn. Эта установка очень удобна, если вы работаете на английском (ascii) и используете старший бит символов как маркер или “мета”-бит.
set print sevenbit-strings off Выводить восьмибитные символы полностью. Это позволяет использовать большее количество международных наборов символов, и устанавливается по show print sevenbit-strings Показать, выводит GDB только семибитные литеры или нет.
set print union on Велит GDB выводить объединения, содержащиеся в структурах. Устанавливается по умолчанию.
set print union off Указывает GDB не выводить объединения, содержащиеся в структурах.
show print union Запросить GDB, будет ли он выводить объединения, содержащиеся в структурах.
Например, пусть даны описания typedef enum {Big_tree, Acorn, Seedling} Tree_forms;
typedef enum {Caterpillar, Cocoon, Butterfly} с установленным set print union on, команда ‘p foo’ выведет а с установленным set print union off, эта же команда выведет Следующие установки представляют интерес при отладке программ на Си++:
set print demangle set print demangle on Печатать идентификаторы Си++ в их изначальной, а не в закодированной (“искаженной”) форме, передаваемой ассемблеру и компоновщику для сборки с контролем типа. Установлено по умолчанию.
show print demangle Показать, в искаженной или восстановленной форме выводятся идентификаторы Си++.
set print asm-demangle set print asm-demangle on Выводить идентификаторы Си++ в их исходной форме, а не в искаженной, даже при выводе ассемблерного кода, например при дисассемблировании инструкций. По умолчанию отключено.
show print asm-demangle Показать, в закодированной или восстановленной форме выводятся имена Си++ set demangle-style стиль Выбрать одну из нескольких схем кодирования, используемых различными компиляторами для представления имен Си++. Параметр стиль может быть следующим:
Позволить GDB выбрать стиль декодирования посредством изучеauto Декодирование основывается на алгоритме кодирования компилятоgnu Декодирование основывается на алгоритме кодирования HP ANSI Декодирование основывается на алгоритме кодирования компилятоlucid Декодировать, используя алгоритм из C++ Annotated Reference Manual. Предупреждение: одной этой установки недостаточно, чтобы производить отладку исполняемых программ, сгенерированных cfront. Чтобы реализовать это, GDB требует дальнейших усовершенствований.
Если вы опустите стиль, то увидите список возможных форматов.
show demangle-style Отобразить текущий стиль кодирования, используемый для декодирования set print object set print object on При отображении указателя на объект, идентифицировать фактический (производный), а не объявленный тип объекта, используя таблицу виртуальных set print object off Отображать только объявленный тип объекта, не ссылаясь на таблицу виртуальных функций. Устанавливается по умолчанию.
show print object Показать, какой из типов объекта выводится.
set print static-members set print static-members on Выводить статические члены при отображении объекта Си++. Установлено по set print static-members off Не выводить статические члены при отображении объекта Си++.
show print static-members Показать, выводятся статические члены Си++ или нет.
set print vtbl set print vtbl on Осуществлять структурный вывод таблиц виртуальных функций Си++. По умолчанию отключено. (Команды vtbl не работают для программ, скомпилированных компилятором HP ANSI Си++ (aCC).) set print vtbl off Не производить структурного вывода таблиц виртуальных функций Си++.
show print vtbl Показать, производится структурный вывод таблиц виртуальных функций 8.8 История значений Значения, выведенные командой print, сохраняются в истории значений GDB. Это позволяет вам обращаться к ним в других выражениях. Значения сохраняются, пока таблица символов не будет заново считана или уничтожена (например, командами file или symbol-file). При изменении таблицы символов, история значений уничтожается, так как значения могут содержать указатели на типы, определенные в таблице символов.
Выведенным значениям присваиваются номера в истории, по которым вы можете на них ссылаться. Эти номера являются последовательными целыми числами, начинающимися с единицы. Команда print показывает номер в истории, присвоенный значению, выводя перед ним ‘$номер = ’, где номер—это номер в истории.
Для обращения к какому-либо предшествующему значению, используйте ‘$’, за которым следует номер в истории. Способ, которым print маркирует вывод продуман так, чтобы напоминать вам об этом. Просто $ ссылается на самое последнее значение в истории, а $$—на предпоследнее. $$n ссылается на n-е с конца значение; $$2—значение, находящееся перед $$, $$1 эквивалентно $$, а $$0 эквивалентно $.
Предположим, например, вы только что вывели указатель на структуру и хотите посмотреть ее содержимое. Для этого достаточно ввести Если у вас есть цепочка структур, где компонента next указывает на следующую, вы можете вывести содержимое следующей структуры так:
Вы можете выводить последовательные звенья в цепочке повторяя эту команду. Это можно сделать простым нажатием RET.
Обратите внимание, что в историю записываются значения, а не выражения. Если значение x равно 4, и вы наберете:
то значение, записанное в историю значений командой print, будет по-прежнему равно 4, хотя значение x изменилось.
show values Вывести из истории последние десять значений, с их номерами. Это похоже на команду ‘p $$9’, повторенную десять раз, за исключением того, что show values не изменяет историю.
show values n Вывести десять значений из истории, расположенных вокруг элемента с номером n.
show values + Вывести десять значений из истории, следующих сразу после последнего выведенного значения. Если доступных значений больше нет, show values + не для повтора show values n действует точно так же, как ‘show values +’.
Нажатие RET 8.9 Вспомогательные переменные GDB предоставляет вспомогательные переменные, которые вы можете в нем использовать, чтобы сохранить значение и обратиться к нему позже. Эти переменные существуют только в GDB; они не являются частью вашей программы и установка вспомогательной переменной не оказывает непосредственного влияния на ее дальшейшее выполнение. Поэтому вы можете пользоваться ими совершенно свободно.
Имена вспомогательных переменных начинаются с ‘$’. Любое имя с приставкой ‘$’ может использоваться для вспомогательной переменной, если только оно не является предопределенным машинно-зависимым именем регистра, (см. Раздел 8.10 [Регистры], с. 74).
(Ссылки на историю значений, напротив, есть числа, которым предшествует ‘$’. См.
Раздел 8.8 [История значений], с. 72.) Вы можете сохранить значение во вспомогательной переменной с помощью выражения присваивания, как если бы вы устанавливали переменную в вашей программе. Например:
set $foo = *object_ptr сохранит в $foo значение объекта, на который указывает object_ptr.
Первое использование вспомогательной переменной создает ее, но значением переменной будет void, пока вы не присвоите ей новое. С помощью другого присваивания вы можете в любое время изменить значение.
Вспомогательные переменные не имеют фиксированного типа. Вы можете присваивать вспомогательной переменной значение любого типа, включая структуры и массивы, даже если у этой переменной уже было значение другого типа. Будучи использованной в выражении, вспомогательная переменная имеет тип своего текущего значения.
show convenience Вывести список используемых вспомогательных переменных с их значениями.
Один из способов использования вспомогательных переменных—в качестве увеличивающегося счетчика или продвигающегося указателя. Например, чтобы напечатать поле из последовательных элементов массива структур:
print bar[$i++]->contents Повторяйте эту команду нажатием RET.
Некоторые вспомогательные переменные создаются GDB автоматически, и им присваиваются значения, которые вероятно могут оказаться полезными.
Переменная $_ устанавливается автоматически командой x в последний исследованный адрес (см. Раздел 8.5 [Исследование памяти], с. 65). Другие команды, которые устанавливают адрес по умолчанию для исследования командой x, также присваивают $_ упомянутый адрес; эти команды включают info line и info breakpoint. Переменная $_ имеет тип void *, если только она не установлена командой x; в этом случае она является указателем на тип переменной Переменная $ устанавливается автоматически командой x в значение, находящееся по последнему исследованному адресу. Ее тип выбирается соответствующим формату, в котором это значение было выведено.
$_exitcode Переменной $_exitcode автоматически присваивается код завершения, когда отлаживаемая программа завершается.
В системах HP-UX, если вы ссылаетесь на функцию или переменную, чье имя начинается со знака доллара, GDB сначала производит поиск пользовательского или системного имени, перед поиском вспомогательной переменной.
8.10 Регистры В выражениях, вы можете обращаться к содержимому машинных регистров, обозначая их как переменные с именами, начинающимся с ‘$’. Имена регистров различаются от машины к машине; для вывода имен регистров, используемых на вашей машине, воспользуйтесь командой info registers.
info registers Вывести имена и содержимое всех регистров, кроме регистров с плавающей точкой (в выбранном кадре стека).
info all-registers Вывести имена и содержимое всех регистров, включая регистры с плавающей info registers имя-рег...
Выводит относительное значение каждого из указанных в имя-рег регистров.
Как подробно обсуждается ниже, значения регистров обычно относятся к выбранному кадру стека. Имя-рег может быть любым допустимым на вашей машине именем регистра, с ‘$’ в начале имени или без.
GDB распознает четыре “стандартных” имени регистров, которые доступны (в выражениях) на большинстве машин—если только они не конфликтуют с каноническим для архитектуры обозначением регистров. Названия регистров $pc и $sp используются для регистра счетчика программы и указателя вершины стека. $fp используется как имя регистра, содержащего указатель на текущий кадр стека, а $ps—как имя регистра, содержащего состояние процессора. Например, вы можете вывести счетчик программы в шестнадцатеричной записи с помощью или вывести следующую исполняемую инструкцию, используя или увеличить указатель вершины стека на четыре2 с помощью Когда возможно, эти четыре стандартных имени регистров доступны на вашей машине, даже если она имеет другую каноническую мнемонику, если не возникает конфликта. Команда info registers показывает канонические имена. В SPARC, например, info registers отображает регистр состояния процессора как $psr, но вы также можете называть его $ps; а на машинах, базирующихся на платформе x86, $ps является синонимом для регистра eflags.
Когда регистр изучается таким образом, GDB всегда рассматривает содержимое обычного регистра как целое. Некоторые машины имеют специальные регистры, которые могут содержать только значение с плавающей точкой; их значения трактуются как величины с плавающей точкой. Не существует способа сослаться на содержимое обычного регистра как на величину с плавающей точкой (хотя вы можете распечатать его значение командой print как величину с плавающей точкой, используя ‘print/f $имя-рег’).
Некоторые регистры имеют различные “необработанные” и “виртуальные” форматы данных. Это означает, что формат данных, в котором операционная система сохраняет содержимое регистра, не совпадает с тем, который обычно воспринимается вашей программой. Например, регистры сопроцессора с плавающей точкой 68881 всегда сохраняются в “расширенном” (необработанном) формате, но все программы на Си работают с “двойным” (виртуальным) форматом. В подобных случаях, GDB обычно работает только с виртуальным форматом (форматом, имеющим смысл в вашей программе), но команда info registers выводит данные в обоих форматах.
Обычно значения регистров относятся к выбранному кадру стека (см. Раздел 6.3 [Выбор кадра], с. 52). Это значит, что вы получаете значение, которое содержалось бы в регистре, если бы произошел выход из всех внутренних кадров стека и их сохраненные регистры были бы восстановлены. Для того чтобы увидеть истинное содержимое аппаратных регистров, вы должны выбрать самый внутренний кадр (с помощью ‘frame 0’).
Однако, GDB, исходя из машинного кода, сгенерированного вашим компилятором, должен установить, где сохранены регистры. Если некоторые регистры не сохранены, или если GDB не в состоянии найти сохраненные регистры, выбранный кадр стека не имеет значения.
8.11 Аппаратные средства поддержки вычислений с плавающей точкой В зависимости от конфигурации, GDB может выдать вам больше информации о состоянии аппаратных средств поддержки вычислений с плавающей точкой.
На машинах, где стек растет вниз в памяти (в наши дни, на большинстве машин), это способ удалить одно слово из стека. Это подразумевает, что выбран самый внутренний кадр; когда выбраны другие кадры стека, установка $sp не разрешена. Используйте return для извлечения целого кадра из стека, вне зависимости от архитектуры машины; смотрите Раздел 11.4 [Возврат из функции], с. 103.
info float Отобразить аппаратно-зависимую информацию о модуле поддержки вычислений с плавающей точкой. Ее точное содержание и размещение зависит от микросхемы поддержки вычислений с плавающей точкой. В настоящее время, ‘info float’ поддерживается на машинах ARM и x86.
Глава 9: Использование GDB с различными языками программирования 9 Использование GDB с различными языками программирования Хотя языки программирования обычно имеют общие аспекты, их выражения редко выглядят одинаково. Например, в ANSI Си, разыменование указателя p осуществляется операцией *p, а в Модуле-2 это выполняется как p^. Представление (и отображение) значений также может быть различным. Шестнадцатеричные числа в Си отображаются как ‘0x1ae’, в то время как в Модуле-2 они отображаются как ‘1AEH’.
В GDB встроена специальная информация о некоторых языках, которая позволяет описывать действия, подобные упомянутым, на языке вашей программы, и позволяет GDB выводить значения в виде, принятом в языке, на котором написана ваша программа. Язык, которым вы пользуетесь для построения выражений, называется рабочим языком.
9.1 Переход от одного языка к другому Существует два способа управления рабочим языком: либо GDB устанавливает его автоматически, либо вы можете сделать это самостоятельно. Для этих целей вы можете воспользоваться командой set language. По умолчанию, при старте GDB устанавливает язык автоматически. Рабочий язык используется чтобы определить, как интерпретируются вводимые вами выражения, как выводятся значения, и так далее.
В дополнение к рабочему языку, каждый исходный файл, с которым работает GDB, имеет свой собственный рабочий язык. Для некоторых форматов объектных файлов компилятор может указывать, на каком языке написан конкретный исходный файл. Однако, чаще всего GDB распознает язык по имени файла. Язык исходного файла определяет, будут ли восстанавливаться имена Си++; таким образом, backtrace может показывать каждый кадр в соответствии с исходным языком. Не существует способа установить язык исходного файла из GDB, но вы можете установить язык, ассоциированный с расширением файла. См. Раздел 9.2 [Отображение языка программирования], с. 78.
Наиболее часто эта проблема возникает, когда вы используете программу, такую как cfront или f2c, которая создает текст на Си, но написана на другом языке. В этом случае нужно сделать, чтобы программа использовала директивы #line в выводе текста Си;
тогда GDB будет знать правильный язык исходного текста первоначальной программы, и выведет этот исходный код, а не сгенерированный код Си.
9.1.1 Соответствие расширений файлов и языков Если имя исходного файла заканчивается одним из следующих расширений, то GDB воспринимает это как указание на обозначенный язык.
‘.c’ Исходный файл Си ‘.C’ ‘.cc’ ‘.cp’ ‘.cpp’ ‘.cxx’ ‘.c++’ Исходный файл Си++ ‘.f’ ‘.F’ Исходный файл Фортрана ‘.ch’ ‘.c186’ ‘.c286’ Исходный файл CHILL ‘.mod’ Исходный файл Модулы- ‘.s’ ‘.S’ Исходный файл Ассемблера. В действительности, восприниматся почти также, как Си, но GDB не пропускает вводные части функций при пошаговом В дополнение к этому, вы можете установить язык, ассоциированный с расширением имени файла. См. Раздел 9.2 [Отображение языка программирования], с. 78.
9.1.2 Установка рабочего языка Если вы позволяете GDB устанавливать язык автоматически, выражения в сеансе отладки и в вашей программе интерпретируются одинаково.
По желанию, вы можете установить язык сами. Для этого воспользуйтесь командой ‘set language язык’, где язык—название языка, например, c или modula-2. Чтобы получить перечень поддерживаемых языков, наберите ‘set language’.
Установка языка вручную запрещает GDB автоматически переключать рабочий язык.
Это может привести к неприятным последствиям, если вы попытаетесь отладить программу, когда рабочий язык не совпадает с исходным языком, когда выражение допустимо в обоих языках, но означает разные вещи. Например, если текущий исходный файл написан на Си, а в GDB выбрана Модула-2, команда может не привести к ожидаемому результату. В Си это означает сложить b и c и поместить результат в a. Выведенным результатом будет значение a. В Модуле-2 это означает сравнение a с результатом b+c, выдающее значение типа BOOLEAN.
9.1.3 Распознавание GDB исходного языка Для автоматической установки GDB рабочего языка, используйте ‘set language local’ или ‘set language auto’. Тогда GDB будет определять рабочий язык автоматически. То есть при остановке вашей программы в кадре стека (обычно, в точке останова), GDB устанавливает рабочий язык в тот, который записан для функции в этом кадре. Если язык для кадра неизвестен (то есть, если функция или блок, соответствующие кадру, были определены в исходном файле, не имевшем распознаваемого расширения), текущий рабочий язык не изменяется, а GDB выдает предупреждающее сообщение.
Для большинства программ, которые написаны целиком на одном языке, автоматическая установка языка может показаться ненужной. Однако, в основной программе, написанной на одном исходном языке, могут использоваться программные модули и библиотеки, написанные на другом исходном языке. Использование в этом случае ‘set language auto’ освобождает вас от установки рабочего языка вручную.
9.2 Отображение языка программирования Следующие команды помогают вам определить, какой язык является рабочим, а также на каком языке были написаны исходные файлы.
show language Отобразить текущий рабочий язык. Это тот язык, который вы можете использовать в командах типа print для построения и вычисления выражений, в которые могут входить переменные вашей программы.
info frame Отобразить исходный язык для данного кадра стека. Этот язык становится рабочим, если используется идентификатор из этого кадра. См. Раздел 6. [Информация о кадре], с. 53, для дополнительной информации.
Глава 9: Использование GDB с различными языками программирования info source Отобразить исходный язык данного исходного файла. См. Глава 10 [Исследование таблицы символов], с. 97, для получения дополнительной информации.
При необычных обстоятельствах, у вас могут быть исходные файлы с расширениями, не входящими в стандартный список. Вы можете явно установить расширение, ассоциированное с языком:
set extension-language.расш язык Установить соответствие исходных файлов с расширением.расш с исходным info extensions Перечислить все расширения имен файлов и соответствующие им языки.
9.3 Проверка диапазона и принадлежности типу Предупреждение: В этот выпуск включены команды GDB для проверки диапазона и соответствия типов, но они пока не оказывают никакого действия. Этот раздел описывает их предполагаемые возможности.
Некоторые языки обеспечивают защиту от достаточно общих ошибок с помощью набора проверок времени компиляции и времени выполнения. Это включает проверку типов аргументов функций и операторов и обеспечивает проверку математического переполнения во время выполнения. Проверки такого рода помогают убедиться в корректности программы после ее компиляции путем устранения несоответствия типов, и предоставляя активную проверку ошибок выхода за пределы диапазона во время выполнения.
По вашему желанию, GDB может проводить подобные проверки. Хотя GDB не проверяет операторы вашей программы, он может, например, проверять выражения, введенные непосредственно в GDB для вычисления командой print. Как и в случае рабочего языка, GDB может также автоматически решить, выполнять проверку или нет, основываясь на исходном языке вашей программы. См. Раздел 9.4 [Поддерживаемые языки], с. 81, для информации об установках по умолчанию для поддерживаемых языков.
9.3.1 Краткий обзор проверки соответствия типов Некоторые языки, такие как Модула-2, должны иметь жесткое соответствие типов, то есть аргументы операторов и функций должны иметь правильный тип, в противном случае возникает ошибка. Описанные здесь проверки предотвращают ошибки несоответствия типов, которые могут вызвать ошибки времени выполнения. Например, Во втором примере ошибка, потому что CARDINAL 1 не совместим по типу с REAL 2.3.
Для выражений, используемых вами в командах GDB, вы можете указать GDB не производить проверку; или же рассматривать любое несоответствие как ошибку и прекращать обработку выражения; или только выводить предупреждение в случае возникновения несоответствия, но вычислять выражение в любом случае. В последнем случае, GDB вычисляет выражения, подобные второму примеру, но также выводит предупреждающее сообщение.
Даже если вы отключили проверку типов, GDB может прекратить обработку выражения по другим причинам, связанным с типами. Например, GDB не знает, как сложить int и struct foo. Такие типы ошибок не имеют ничего общего с используемым языком и обычно возникают из выражений, подобных описанному выше, которые нет смысла вычислять.
Каждый язык определяет степень строгости контроля типов. Например, как Модулатак и Си требуют, чтобы аргументы арифметических операций были числами. В Си, перечисляемые типы и указатели могут быть представлены в виде чисел, так что они допустимы в качестве аргументов математических операторов. См. Раздел 9.4 [Поддерживаемые языки], с. 81, для более подробного обсуждения конкретных языков.
GDB предоставляет некоторые дополнительные команды для контроля проверки типов:
set check type auto Включить или отключить контроль типов, в зависимости от текущего рабочего языка. См. Раздел 9.4 [Поддерживаемые языки], с. 81, для установок по умолчанию для каждого языка.
set check type on set check type off Включить или отключить контроль типов, пренебрегая установкой по умолчанию для текущего рабочего языка. Вывести предупреждающее сообщение, если установка не соответствует используемой по умолчанию. Если возникает несоответствие типов во время вычисления выражения при включенном контроле типов, GDB выводит сообщение и прерывает вычисление выражения.
set check type warn При возникновении несоответствия типов вывести предупреждающее сообщение, но попытаться вычислить выражение. Вычисление выражения все же может быть невозможным по другим причинам. Например, GDB не может складывать числа со структурами.
show type Показать текущую установку проверки типов, а также была ли она установлена 9.3.2 Краткий обзор проверки диапазона В некоторых языках (например, в Модуле-2), выход за границы диапазона типа считается ошибкой; эти ошибки отслеживаются с помощью контроля времени выполнения. Эти проверки диапазона служат для того, чтобы избежать переполнения при вычислениях и не допустить превышения индексами элементов массива границ индексации.
В выражениях, используемых вами в командах GDB, вы можете указать GDB обрабатывать ошибки диапазона одним из трех способов: игнорировать их, всегда рассматривать как ошибки и прерывать обработку выражения, или выводить предупреждение и продолжать вычисление выражения.