Если вы думаете, что нашли ошибку в своей программе, вы можете захотеть выяснить наверняка, приведет ли исправление кажущейся ошибки к правильным результатам в остальной части программы. Вы можете получить ответ экспериментируя, используя средства GDB для изменения выполнения программы.
Например, вы можете сохранить новые значения в переменных или ячейках памяти, подать своей программе сигнал, перезапустить ее с другого адреса или даже преждевременно вернуться из функции.
Для изменения значения переменной, вычислите выражение присваивания. См. раздел 8.1 Выражения. Например,
print x=4
сохраняет значение 4 в переменной x
и затем выводит значение данного
выражения (которое равно 4). См. раздел 9. Использование GDB с различными языками программирования, для получения большей информации
об операторах в поддерживаемых языках.
Если вы не хотите видеть значение присваивания, используйте команду
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.
Обычно, когда вы продолжаете выполнение программы, вы делаете это
с того места, где она остановилась, командой continue
. Вместо
этого, вы можете продолжить выполнение с любого выбранного адреса
при помощи следующих команд:
jump указ-стр
tbreak
вместе с jump
является
обычной практикой. См. раздел 5.1.1 Установка точек останова.
Команда jump
не изменяет ни текущий кадр стека, ни
указатель стека, ни содержимое каких-либо ячеек памяти или регистров, кроме
счетчика программы. Если строка указ-стр находится вне
выполняющейся в настоящее время функции,
результаты могут быть странными, если эти
функции используют аргументы или локальные переменные разных типов. По
этой причине, команда jump
запрашивает подтверждение, если
указанная строка не находится в функции, выполняющейся в настоящее
время. Однако, даже странные результаты предсказуемы, если вы хорошо
знакомы с машинным кодом вашей программы.
jump *адрес
На многих системах вы можете достичь такого же результата, как и с командой
jump
, сохранив новое значение в регистр $pc
. Отличие
заключается в том, что это не начинает выполнение вашей программы, а лишь
изменяет адрес, с которого будет выполняться программа,
когда вы продолжите выполнение. Например,
set $pc = 0x485
выполняет следующую команду continue
или команду пошагового
выполнения с адреса 0x485
, а не с того адреса, где ваша программа
остановилась. См. раздел 5.2 Продолжение и выполнение по шагам.
Наиболее общий случай использования команды jump
состоит в
возврате к выполнению уже пройденной части программы, возможно с большим
количеством установленных точек останова, чтобы исследовать выполнение
более детально.
signal сигнал
signal 2
и signal
SIGINT
-- два способа подать сигнал прерывания.
Наоборот, если сигнал является нулем, выполнение продолжается без
подачи сигнала. Это полезно, если ваша программа остановилась из-за
сигнала и в обычном случае увидит его при возобновлении выполнения командой
continue
; `signal 0' продолжит выполнение без сигнала.
signal
не повторяется, когда вы нажимаете RET второй раз
после выполнения команды.
Вызов команды signal
отличается от вызова утилиты kill
из
оболочки. Подача сигнала посредством kill
заставляет
GDB решать, что делать с сигналом, в зависимости от таблиц
обработки сигналов (см. раздел 5.3 Сигналы). Команда signal
передает
сигнал непосредственно вашей программе.
return
return выражение
return
.
Если вы задаете параметр выражение, его значение используется
в качестве возвращаемого значения.
Когда вы используете return
, GDB уничтожает выбранный
кадр стека (и все кадры внутри него). Вы можете считать это
преждевременным возвратом из уничтоженного кадра. Если вы хотите
указать возвращаемое значение, задайте его в качестве аргумента к
return
.
Это выталкивает выбранный кадр стека (см. раздел 6.3 Выбор кадра) и все другие кадры внутри него, оставляя самым внутренним кадр, из которого произошел вызов. Этот кадр становится выбранным. Указанное значение сохраняется в регистрах, используемых для возвращаемых функцией значений.
Команда return
не возобновляет выполнение; она оставляет
программу остановленной в том состоянии, в котором бы она была сразу
после возврата из функции. Напротив, команда finish
(см. раздел 5.2 Продолжение и выполнение по шагам) возобновляет выполнение до естественного возврата из
выбранного кадра стека.
call выраж
void
)
возвращенных значений.
Вы можете использовать этот вариант команды print
, если хотите
выполнить функцию из вашей программы, не засоряя вывод пустыми возвращенными
значениями. Если результат не пустой, он выводится и
сохраняется в истории значений.
Для A29K, устанавливаемая пользователем переменная
call_scratch_address
задает положение рабочей области, которая
будет использоваться, когда GDB вызывает функцию на целевой машине.
Это необходимо, так как обычный метод размещения рабочей области в стеке
не работает в системах с раздельными областями команд и данных.
По умолчанию, GDB открывает файл, содержащий исполняемый код вашей программы (или файл дампа памяти), в режиме только для чтения. Это предотвращает случайные изменения машинного кода; но это также предотвращает и преднамеренное исправление двоичного файла вашей программы.
Если вы хотите иметь возможность исправлять двоичный код, вы можете
указать это явно с помощью команды set write
. Например, вы
можете захотеть установить внутренние флаги отладки или даже сделать
аварийные исправления.
set write on
set write off
set write
вам
необходимо загрузить его снова (используя команды exec-file
или
core-file
), чтобы новые установки вступили в силу.
show write