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

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


11. Изменение выполнения

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

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

11.1 Присваивание значений пеpеменным

Для изменения значения переменной, вычислите выражение присваивания. См. раздел 8.1 Выражения. Например,

print x=4

сохраняет значение 4 в переменной x и затем выводит значение данного выражения (которое равно 4). См. раздел 9. Использование GDB с различными языками программирования, для получения большей инфоpмации об операторах в поддерживаемых языках.

Если вы не хотите видеть значение присваивания, используйте команду set вместо print. Команда set аналогична команде print за исключением того, что значение выражения не выводится и не заносится в историю значений (см. раздел 8.8 История значений). Выражение вычисляется только ради его действия.

Если начало строки параметров команды set выглядит идентично подкоманде set, используйте вместо нее команду set variable. Эта команда аналогична set, но не имеет подкоманд. Например, если в вашей программе есть переменная width, то вы получите ошибку, если попытаетесь установить новое значение просто с помощью `set width=13', потому что GDB имеет команду set width:

(gdb) whatis width
type = double
(gdb) p width
$4 = 13
(gdb) set width=47
Invalid syntax in expression.

Недопустимое выражение, это, конечно, `=47'. Для того чтобы действительно установить переменную программы width, используйте

(gdb) set var width=47

Так как команда set имеет много подкоманд, которые могут конфликтовать с именами переменных в программе, то хорошей практикой является использование команды set variable вместо просто set. Например, если ваша программа имеет переменную g, у вас возникнут проблемы, если вы попытаетесь установить новое значение с помощью `set g=4', потому что GDB имеет команду set gnutarget, которая сокращается как set g:

(gdb) whatis g
type = double
(gdb) p g
$1 = 1
(gdb) set g=4
(gdb) p g
$2 = 1
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/smith/cc_progs/a.out
"/home/smith/cc_progs/a.out": can't open to read symbols:
                                 Invalid bfd target.
(gdb) show g
The current BFD target is "=4".

Переменная программы g не изменилась, и вы незаметно установили gnutarget в неверное значение. Для установки значения переменной g, используйте

(gdb) set var g=4

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

Для сохранения значений в произвольных местах памяти, используйте конструкцию `{...}' для создания значения определенного типа по определенному адресу памяти (см. раздел 8.1 Выражения). Например, {int}0x83040 ссылается на ячейку памяти 0x83040 как на целое (что предполагает соответствующий размер и представление в памяти), и

set {int}0x83040 = 4

записывает в эту ячейку памяти значение 4.

11.2 Продолжение исполнения с другого адреса

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

jump указ-стр
Возобновить выполнение со строки указ-стр. Если там есть точка останова, выполнение немедленно прекращается. См. раздел 7.1 Вывод строк исходного текста, для описания различных форм указ-стр. Использование команды tbreak вместе с jump является обычной практикой. См. раздел 5.1.1 Установка точек останова. Команда jump не изменяет ни текущий кадр стека, ни указатель стека, ни содержимое каких-либо ячеек памяти или регистров, кроме счетчика программы. Если строка указ-стр находится вне выполняющейся в настоящее время функции, результаты могут быть странными, если эти функции используют аргументы или локальные переменные разных типов. По этой причине, команда jump запрашивает подтверждение, если указанная строка не находится в функции, выполняющейся в настоящее время. Однако, даже странные результаты предсказуемы, если вы хорошо знакомы с машинным кодом вашей программы.
jump *адрес
Возобновить выполнение с инструкции, находящейся по адресу адрес.

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

set $pc = 0x485

выполняет следующую команду continue или команду пошагового выполнения с адреса 0x485, а не с того адреса, где ваша программа остановилась. См. раздел 5.2 Продолжение и выполнение по шагам.

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

11.3 Подача сигнала вашей программе

signal сигнал
Возобновить выполнение с места остановки вашей программы, но немедленно подать ей сигнал сигнал. Сигнал может быть именем или номером сигнала. Например, во многих системах signal 2 и signal SIGINT---два способа подать сигнал прерывания. Наоборот, если сигнал является нулем, выполнение продолжается без подачи сигнала. Это полезно, если ваша программа остановилась из-за сигнала и в обычном случае увидит его при возобновлении выполнения командой continue; `signal 0' продолжит выполнение без сигнала. signal не повторяется, когда вы нажимаете RET второй раз после выполнения команды.

Вызов команды signal отличается от вызова утилиты kill из оболочки. Подача сигнала посредством kill заставляет GDB решать, что делать с сигналом, в зависимости от таблиц обработки сигналов (см. раздел 5.3 Сигналы). Команда signal передает сигнал непосредственно вашей программе.

11.4 Возврат из функции

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

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

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

Команда return не возобновляет выполнение; она оставляет программу остановленной в том состоянии, в котором бы она была сразу после возврата из функции. Напротив, команда finish (см. раздел 5.2 Продолжение и выполнение по шагам) возобновляет выполнение до естественного возврата из выбранного кадра стека.

11.5 Вызов функций программы

call выраж
Вычислить выражение выраж без отображения пустых (void) возвращенных значений.

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

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

11.6 Внесение изменений в программу

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

Если вы хотите иметь возможность исправлять двоичный код, вы можете указать это явно с помощью команды set write. Например, вы можете захотеть установить внутренние флаги отладки или даже сделать аварийные исправления.

set write on
set write off
Если вы установите `set write on', GDB открывает исполняемые файлы и файлы дампов памяти в режиме для чтения и записи; если вы укажете `set write off' (устанавливается по умолчанию), GDB открывает их в режиме только для чтения. Если вы уже загрузили файл, то после установки set write вам необходимо загрузить его снова (используя команды exec-file или core-file), чтобы новые установки вступили в силу.
show write
Показать, открыты исполняемые файлы и файлы дампов памяти для записи или нет.


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