Отладка с помощью GDB - 6. Исследование стека

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


6. Исследование стека

Когда ваша программа остановилась, первое, что вам нужно знать--где она остановилась и как она туда попала.

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

Команды GDB для исследования стека позволяют вам увидеть всю эту информацию при остановке вашей программы.

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

Когда ваша программа останавливается, GDB автоматически выбирает текущий выполняющийся кадр и выдает его краткое описание, аналогично команде frame (см. раздел 6.4 Информация о кадре стека).

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
bt
Вывести цепочку вызовов всего стека: по одной строке на кадр, для всех кадров в стеке. Вы можете прервать цепочку вызовов в любое время, введя знак системного прерывания, обычно C-c.
backtrace n
bt n
То же самое, но выводятся только n внутренних кадров.
backtrace -n
bt -n
То же самое, но выводятся только n внешних кадров.

where и info stack (сокращенно info s)---дополнительные синонимы для backtrace.

Каждая строка в цепочке вызовов показывает номер кадра и имя функции. Счетчик команд также показывается, если только вы не используете set print address off. Цепочка вызовов также показывает имя исходного файла, номер строки и аргументы функции. Значение счетчика команд опускается, если он указывает на начало кода для данной строки.

Ниже приведен пример цепочки вызовов. Она была получена командой `bt 3', так что она показывает три внутренних кадра.

#0  m4_traceon (obs=0x24eb0, argc=1, argv=0x2b8c8)
    at builtin.c:993
#1  0x6e38 in expand_macro (sym=0x2b600) at macro.c:242
#2  0x6840 in expand_token (obs=0x0, t=177664, td=0xf7fffb08)
    at macro.c:71
(More stack frames follow...)

Информация о нулевом кадре не начинается со значения счетчика команд, что указывает на то, что ваша программа остановилась в начале кода для строки 993 файла builtin.c.

6.3 Выбор кадра

Большинство команд для исследования стека и других данных в вашей программе применяются выбранному в данный момент кадру. Здесь приведены команды для выбора кадра стека; все они завершаются выводом краткого описания выбранного кадра стека.

frame n
f n
Выбрать кадр номер n. Напоминаем, что нулевой кадр--это внутренний (исполняемый в данный момент) кадр, первый кадр--тот, из которого вызван нулевой, и так далее. Кадр с наибольшим номером--это кадр для функции main.
frame адрес
f адрес
Выбрать кадр, расположенный по адресу адрес. В основном это полезно, если формирование цепочки кадров стека было нарушено из-за ошибки, сделавшей невозможным для GDB правильное присвоение номеров всем кадрам. Кроме того, это может быть полезным, когда у вашей программы есть несколько стеков и происходит переключение от одного к другому. В архитектуре SPARC, команде frame для выбора произвольного кадра необходимо указать два адреса: указатель кадра и указатель вершины стека. В архитектурах MIPS и Alpha требуется два адреса: указатель вершины стека и указатель команд. В архитектуре 29k требуется три адреса: указатель вершины стека регистров, указатель команд и указатель вершины стека памяти.
up n
Переместиться вверх по стеку на n кадров. Для положительных значений n, это перемещение происходит по направлению к внешнему кадру, к кадрам с большими номерами, к кадрам, которые существуют дольше. По умолчанию n принимается равным единице.
down n
Передвинуться вниз по стеку на n кадров. Для положительных значений n, это продвижение происходит по направлению к внутреннему кадру, к кадру с меньшим номером, к кадрам, которые были созданы позже. По умолчанию, значение n принимается равным единице. Вы можете сокращать down как do.

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

Например:

(gdb) up
#1  0x22f0 in main (argc=1, argv=0xf7fffbf4, env=0xf7fffbfc)
    at env.c:10
10              read_input_file (argv[i]);

После такого вывода, команда list без аргументов выводит десять строк, расположенных вокруг точки выполнения в кадре. См. раздел 7.1 Вывод строк исходного текста.

up-silently n
down-silently n
Эти две команды являются вариантами up и down соответственно, отличаясь от них тем, что делают свою работу "тихо", не отображая новый кадр. Они предназначены для использования в основном в командных сценариях GDB, где вывод может быть ненужным и отвлекающим.

6.4 Информация о кадре стека

Существуют несколько других команд для вывода информации о выбранном кадре стека.

frame
f
При использовании без аргументов, эта команда не выбирает новый кадр, а выводит краткое описание текущего выбранного кадра стека. Эту команду можно сокращать как f. С аргументом, эта команда используется для выбора кадра стека. См. раздел 6.3 Выбор кадра.
info frame
info f
Эта команда выводит подробное описание выбранного кадра стека, включающее:
  • адрес кадра
  • адрес следующего вниз по стеку кадра (вызываемого из данного)
  • адрес следующего вверх по стеку кадра (того, из которого был вызван данный)
  • язык, на котором написан исходный код, соответствующий этому кадру
  • адрес аргументов кадра
  • адрес локальных переменных кадра
  • сохраненный в кадре счетчик команд (адрес выполнения в кадре, вызвавшем данный)
  • регистры, которые были сохранены в кадре
Подробное описание полезно, если из-за какой-либо ошибки формат стека не соответствует обычным соглашениям.
info frame адрес
info f адрес
Вывести подробное описание кадра стека, расположенного по адресу адрес, не выбирая этот кадр. Выбранный кадр этой командой не изменяется. Она требует параметр адрес того же типа, что и команда frame (для некоторых архитектур не один, а несколько). См. раздел 6.3 Выбор кадра.
info args
Вывести аргументы выбранного кадра, каждый на отдельной строке.
info locals
Вывести локальные переменные выбранного кадра, каждую на отдельной строке. Выводятся все переменные (объявленные как статические или как автоматические), доступные в точке выполнения выбранного кадра стека.
info catch
Выводит список всех обработчиков исключительных ситуаций, являющихся активными в текущей точке выполнения текущего кадра стека. Чтобы увидеть другие обработчики исключительных ситуаций, перейдите в соответствующую секцию (используя команды up, down или frame); затем наберите info catch. См. раздел 5.1.3 Установка точек перехвата.


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