Отладка с помощью GDB - 4. Выполнение программ под управлением GDB

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


4. Выполнение программ под управлением GDB

Прежде чем выполнять программу под управлением GDB, при компиляции вы должны сгенерировать отладочную информацию.

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

4.1 Компиляция для отладки

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

Чтобы запросить генерацию отладочной информации, укажите ключ `-g' при вызове компилятора.

Многие компиляторы Си не могут обрабатывать ключи `-g' и `-O' вместе. Используя такие компиляторы, вы не можете создавать оптимизированные выполняемые файлы, содержащие отладочную информацию.

GCC, GNU компилятор Си, поддерживает `-g' с или без `-O', делая возможным отладку оптимизированного кода. Мы рекомендуем, чтобы вы всегда использовали `-g' при компиляции программ. Вы можете думать, что ваша программа правильная, но нет никакого смысла испытывать удачу.

Когда вы отлаживаете программу, откомпилированную с `-g -O', помните, что оптимизатор перестраивает ваш код; отладчик же показывает то, что там находится в действительности. Не удивляйтесь, если порядок выполнения не будет в точности соответствовать вашему исходному файлу! Крайний пример: если вы определяете переменную, но нигде ее не используете, GDB никогда не увидит этой переменной, потому что при оптимизации компилятор ее исключит.

Некоторые вещи не работают с `-g -O' также, как просто с `-g', в частности, на машинах с планированием инструкций. Если сомневаетесь, перекомпилируйте с одним ключем `-g', и если это устранит проблему, пожалуйста, сообщите нам об этом как об ошибке (включите тестовый пример!).

Ранние версии компилятора GNU Си допускали вариант ключа для отладочной информации `-gg'. GDB больше не поддерживает этот формат; если этот ключ есть у вашего компилятора GNU Си, не используйте его.

4.2 Начало выполнения вашей программы

run
r
Используйте команду run для запуска вашей программы под управлением GDB. Сначала вы должны задать имя программы (кроме как на VxWorks) с параметрами GDB (см. раздел 2. Вход и выход из GDB), или используя команды file или exec-file (см. раздел 12.1 Команды для задания файлов).

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

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

Параметры.
Задайте параметры, которые нужно передать вашей программе, как параметры команды run. Если на вашей системе доступна оболочка, она используется для передачи параметров, так что при их описании вы можете использовать обычные соглашения (такие как раскрывание шаблонов или подстановка переменных). В системах Unix, вы можете контролировать, какая оболочка используется, с помощью переменной среды SHELL. См. раздел 4.3 Аргументы вашей программы.
Среда.
Обычно ваша программа наследует свою среду от GDB, но вы можете использовать команды GDB set environment и unset environment, чтобы изменить часть настроек среды, влияющих на нее. См. раздел 4.4 Рабочая среда вашей программы.
Рабочий каталог.
Ваша программа наследует свой рабочий каталог от GDB. Вы можете установить рабочий каталог GDB командой cd. См. раздел 4.5 Рабочий каталог вашей программы.
Стандартный ввод и вывод.
Обычно ваша программа использует те же устройства для стандартного ввода и вывода, что и GDB. Вы можете перенаправить ввод и вывод в строке команды run, или использовать команду tty, чтобы установить другое устройство для вашей программы. См. раздел 4.6 Ввод и вывод вашей программы. Предупреждение: Хотя перенаправление ввода и вывода работает, вы не можете использовать каналы для передачи выходных данных отлаживаемой программы другой программе; если вы попытаетесь это сделать, скорее всего GDB перейдет к отладке неправильной программы.

Когда вы подаете команду run, ваша программа начинает выполняться немедленно. См. раздел 5. Остановка и продолжение исполнения, для обсуждения того, как остановить вашу программу. Как только ваша программа остановилась, вы можете вызывать функции вашей программы, используя команды print или call. См. раздел 8. Исследование данных.

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

4.3 Аргументы вашей программы

Аргументы к вашей программе могут быть заданы как аргументы к команде run. Они передаются оболочке, которая раскрывает символы шаблонов и выполняет перенаправление ввода-вывода, и с того момента попадают в вашу программу. Ваша переменная среды SHELL (если она существует) определяет, какую оболочку использует GDB. Если вы не определите SHELL, он использует оболочку по умолчанию (`/bin/sh' в Unix).

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

run без аргументов использует те же аргументы, которые использовались предыдущей командой run, или которые установлены командой set args.

set args
Задает аргументы, которые будут использоваться при следующем запуске вашей программы. Если у set args нет аргументов, run выполняет вашу программу без аргументов. Если вы запустили вашу программу с аргументами, то единственный способ запустить ее снова без аргументов--это использовать set args до следующего запуска командой run.
show args
Показать аргументы, которые будут переданы вашей программе при ее вызове.

4.4 Рабочая среда вашей программы

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

path каталог
Добавить каталог в начало переменной среды PATH (пути поиска выполняемых файлов), как для GDB, так и для вашей программы. Вы можете указать названия нескольких каталогов, разделив их пробелом или системно-зависимым разделителем (`:' в Unix, `;' в MS-DOS и MS-Windows). Если каталог уже находится в списке путей, он переносится в начало, так что поиск в нем будет производиться раньше. Вы можете использовать строку `cwd', чтобы сослаться на рабочий каталог, который является текущим в тот момент, когда GDB производит поиск. Если вместо этого вы используете `.', то она будет указывать на тот каталог, в котором вы выполнили команду path. GDB заменяет `.' в аргументе каталог (на текущий путь) до добавления каталога к списку путей поиска.
show paths
Отобразить список путей для поиска выполняемых файлов (переменную среды PATH).
show environment [имя-перем]
Вывести значение переменной среды имя-перем, которое будет передано вашей программе при ее старте. Если вы не указываете имя-перем, вывести названия и значения всех переменных среды, передаваемых вашей программе. Вы можете сократить environment как env.
set environment имя-перем [=значение]
Присваивает значение переменной среды имя-перем. Значение меняется только для вашей программы, но не для самого GDB. значение может быть любой строкой; значениями переменных среды являются просто строки, а их интерпретацию обеспечивает ваша программа. Параметр значение является необязательным; если он опущен, переменная устанавливается в пустое значение. Например, эта команда:
set env USER = foo
говорит отлаживаемой программе, что при последующих запусках именем пользователя является `foo'. (Пробелы, окружающие `=', использованы здесь для ясности; в действительности, они не обязательны.)
unset environment имя-перем
Удалить переменную имя-перем из среды, передаваемой вашей программе. Это отличается от `set env имя-перем ='; unset environment удаляет переменную из среды, а не присваивает ей пустое значение.

Предупреждение: В системах Unix, GDB вызывает вашу программу, используя оболочку, указанную вашей переменной среды SHELL, если она определена (или /bin/sh, если не определена). Если ваша переменная SHELL указывает на оболочку, которая выполняет файл инициализации--такой как `.cshrc' для оболочки C-shell, или `.bashrc' для BASH--любая переменная, которую вы установите в этом файле, воздействует на вашу программу. В этой связи, вы можете захотеть перенести установку переменных среды в файлы, которые выполняются только при вашем входе в систему, такие как `.login' или `.profile'.

4.5 Рабочий каталог вашей программы

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

Рабочий каталог GDB также служит каталогом по умолчанию для команд отладчика, определяющих действия с файлами. См. раздел 12.1 Команды для задания файлов.

cd каталог
Установить рабочий каталог GDB в каталог.
pwd
Вывести рабочий каталог GDB.

4.6 Ввод и вывод вашей программы

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

info terminal
Отображает информацию, записанную GDB о терминальных режимах, которые использует ваша программа.

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

run > выходной-файл

запускает вашу программу, перенаправляя ее вывод в `выходной-файл'.

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

tty /dev/ttyb

указывает, что процессы, запущенные последующими командами run, для ввода и вывода используют по умолчанию терминал `/dev/ttyb', и что он будет их управляющим терминалом.

Явное перенаправление в run замещает эффект команды tty для устройств ввода-вывода, но не ее воздействие на управляющий терминал.

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

4.7 Отладка запущенного ранее процесса

attach идент-процесса
Эта команда присоединяется к выполняющемуся процессу--процессу, который был запущен вне GDB. (Команда info files показывает ваши активные цели.) В качестве аргумента команда получает идентификатор процесса. Обычный способ узнать идентификатор Unix-процесса--воспользоваться утилитой ps или командой оболочки `jobs -l'. attach не повторяется, если вы нажмете RET второй раз после выполнения команды.

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

Когда вы используете attach, отладчик находит программу выполняющегося процесса, производя поиск сперва в текущем рабочем каталоге, а затем (если программа не найдена), используя пути поиска исходных файлов (см. раздел 7.3 Определение каталогов с исходными файлами). Также, для загрузки программы вы можете использовать команду file. См. раздел 12.1 Команды для задания файлов.

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

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

Если вы выйдете из GDB или используете команду run, пока у вас есть присоединенный процесс, вы убьете этот процесс. По умолчанию, GDB запрашивает подтверждение, если вы пытаетесь сделать одну из этих вещей; вы можете контролировать, нужно вам это подтверждение или нет, используя команду set confirm (см. раздел 15.6 Необязательные предупреждения и сообщения).

4.8 Уничтожение дочернего процесса

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

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

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

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

4.9 Отладка программ с несколькими нитями

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

GDB предоставляет следующие возможности для отладки многонитевых программ:

  • автоматическое уведомление о новых нитях
  • `thread номер-нити', команда для переключения между нитями
  • `info threads', команда для запроса информации о существующих нитях
  • `thread apply [номер-нити] [all] арг', команда для применения некоторой команды к списку нитей
  • точки останова, определяемые отдельно для каждой нити

Предупреждение: Эти возможности доступны еще не в любой конфигурации GDB, где операционная система поддерживает нити. Если ваш GDB не поддерживает нити, эти команды не имеют эффекта. Например, в системах без поддержки нитей, GDB ничего не выводит на команду `info threads', и всегда отвергает команду thread, как в этом примере:

(gdb) info threads
(gdb) thread 1
Thread ID 1 not known.  Use the "info threads" command to
see the IDs of currently known threads.(5)

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

Когда GDB обнаруживает новую нить в вашей программе, он выводит для нее идентификатор на целевой системе с сообщением в форме `[New сист-тег]'. Сист-тег является идентификатором нити, чья форма различается в зависимости от конкретной системы. Например, в LynxOS вы можете увидеть

[New process 35 thread 27]

когда GDB замечает новую нить. Напротив, в системе SGI, сист-тег выглядит просто как `process 368', без дополнительных спецификаций.

Для отладочных целей, GDB присваивает свои собственные номера нитей--всегда в виде одного целого числа--каждой нити в вашей программе.

info threads
Вывести краткую информацию обо всех имеющихся в данный момент в вашей программе нитях. Для каждой нити, GDB отображает (в этом порядке):
  1. номер нити, назначенный GDB
  2. идентификатор нити на целевой системе (сист-тег)
  3. краткие сведения о текущем кадре стека для этой нити
Звездочка `*' слева от номера нити GDB обозначает текущую нить. Например,
(gdb) info threads
  3 process 35 thread 27  0x34e5 in sigpause ()
  2 process 35 thread 23  0x34e5 in sigpause ()
* 1 process 35 thread 13  main (argc=1, argv=0x7ffffff8)
    at threadtest.c:68

В системах HP-UX:

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

Когда GDB обнаруживает новую нить в вашей программе, он выводит как номер нити, присвоенный GDB, так и идентификатор на целевой системе для нити с сообщением в форме `[New сист-тег]'. сист-тег является идентификатором нити, чья форма различается в зависимости от конкретной системы. Например, в HP-UX, когда GDB замечает новую нить, вы увидите

[New thread 2 (system thread 26594)]
info threads
Вывести краткую информацию обо всех имеющихся в данный момент в вашей программе нитях. Для каждой нити, GDB отображает (в этом порядке):
  1. номер нити, назначенный GDB
  2. идентификатор нити на целевой системе (сист-тег)
  3. краткие сведения о текущем кадре стека для этой нити
Звездочка `*' слева от номера нити GDB означает текущую нить. Например,
(gdb) info threads
    * 3 system thread 26607  worker (wptr=0x7b09c318 "@") \
at quicksort.c:137 2 system thread 26606 0x7b0030d8 in __ksleep () \
from /usr/lib/libc.2 1 system thread 27905 0x7b003498 in _brk () \
from /usr/lib/libc.2
thread номер-нити
Сделать нить с номером номер-нити текущей. Аргумент команды, номер-нити, является внутренним номером нити GDB, который показан в первом поле `info threads'. GDB отвечает, выводя системный идентификатор выбранной вами нити, и обзор ее кадра стека:
(gdb) thread 2
[Switching to process 35 thread 23]
0x34e5 in sigpause ()
Также как и с сообщением `[New ...]', форма текста после `Switching to' зависит от соглашений для идентификации нитей в вашей системе.
threads apply [номер-нити] [all] арг
Команда thread apply позволяет вам применить команду к одной или нескольким нитям. Задайте номера нитей, на которые вы хотите воздействовать, в аргументе номер-нити. Номер-нити---это внутренний номер нити GDB, который показан в первом поле `info threads'. Чтобы применить команду ко всем нитям, используйте thread apply all арг.

Когда GDB останавливает вашу программу, вследствие точки останова или по сигналу, он автоматически выбирает нить, в которой появилась точка останова или сигнал. GDB предупреждает вас о переключении контекста сообщением в форме `[Switching to сист-тег]' для идентификации нити.

См. раздел 5.4 Остановка и запуск многонитевых программ, для дополнительной информации о поведении GDB, когда вы останавливаете и запускаете многонитевую программу.

См. раздел 5.1.2 Установка точек наблюдения, для информации о точках наблюдения в многонитевых программах.

4.10 Отладка многонитевых программ

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

Однако, если вы хотите отладить дочерний процесс, существует достаточно простое решение. Поместите вызов sleep в код программы, который дочерний процесс выполнит после fork. Может быть удобным вызывать sleep только если установлена определенная переменная среды или если существует определенный файл, так что задержка не будет происходить, если вы не захотите отлаживать дочерний процесс. Пока дочерний процесс спит, используйте программу ps для получения ее идентификатора процесса. Затем укажите GDB (новому экземпляру GDB, если вы отлаживаете также и родительский процесс) присоединиться к дочернему процессу (см. раздел 4.7 Отладка запущенного ранее процесса). Начиная с этого момента, вы можете отлаживать дочерний процесс точно также, как любой другой процесс, к которому вы присоединились.

В системе HP-UX (только в версиях 11.x и более поздних?) GDB предоставляет средства для отладки программ, которые создают дополнительные процессы, используя функции fork или vfork.

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

Если вы хотите отлаживать дочерний процесс вместо родительского, используйте команду set follow-fork-mode.

set follow-fork-mode режим
Устанавливает реакцию отладчика на вызов fork или vfork в программе. Вызов fork или vfork создает новый процесс. режим может быть:
parent
После ветвления отлаживается исходный процесс. Дочерний процесс выполняется беспрепятственно. Это поведение по умолчанию.
child
После ветвления отлаживается новый процесс. Родительский процесс выполняется беспрепятственно.
ask
Отладчик будет запрашивать один из этих вариантов.
show follow-fork-mode
Отображает текущую реакцию отладчика на вызов fork или vfork.

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

Когда дочерний процесс порождается вызовом vfork, вы не можете отлаживать дочерний или родительский процесс до тех пор, пока не завершится вызов exec.

Если вы даете GDB команду run после выполнения exec, новая программа стартует заново. Чтобы перезапустить родительский процесс, используйте команду file с именем выполняемого файла родительской программы в качестве аргумента.

Вы можете использовать команду catch, чтобы остановить GDB, когда сделан вызов fork, vfork или exec. См. раздел 5.1.3 Установка точек перехвата.


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