Лабораторная работа №9. Методы отладки программ
9.3.1. Описание последовательности выполнения работы
Первым шагом для выполнения задания необходимо воспроизвести описанную неисправность вне отладчика путем запуска программы в RISC-V ОС и передачи ей строки, вызывающей ошибку. Это необходимо для того, чтобы в дальнейшем вести отладку с учетом максимально достоверной картины - в ряде случаев использование отладчиков может само по себе изменять поведение программы.
Далее, программу необходимо запустить в gdb и зафиксировать момент ее аварийной остановки. После этого необходимо визуализировать исходный код программы через команды gdb и путем изучения значений переменных, определить - какая именно операция привела к ошибке. Затем завершить выполнение программы.
Далее, необходимо установить точку останова до момента сбоя так, чтобы на момент остановки у вас была возможность вмешаться в ее работу путем изменения значений переменных. Далее запустите программу через gdb и введите данные, вызывающие ошибку. После остановки на точке останова, измените значения нужных переменных в программе и продолжите ее выполнение. Убедитесь, что после данного вмешательства не происходит ошибок и программа корректно завершает работу. Зафиксируйте ее вывод в отчете.
9.3.2. Пример выполнения задания на защиту
Для примера рассмотрим измененный пример программы из теоретической части:
#include <stdio.h> int main(){ int a=0; int b; int c= 13; scanf("%d", &b); a = a / b; printf("%d", b + c); return 0; }
Мы знаем, что программа должна выводить некоторую контрольную сумму, но при вводе значения 0 происходит ошибка. Воспроизводим ошибку в gdb:
$ gdb a.out Starting program: /home/user/ws/a.out 0 Program received signal SIGFPE, Arithmetic exception. 0x0000555555554717 in main () at example.c:9 9 a = a / b;
Последнее сообщение содержит номер строки, в которой произошла ошибка - строка №9. Выведем часть исходного кода через отладчик
(gdb) l 4 int a=0; 5 int b; 6 int c= 13; 7 8 scanf("%d", &b); 9 a = a / b; 10 printf("%d", b + c); 11 12 return 0; 13 }
Таким образом мы видим проблему в исходном коде - результат ввода пользователя в переменной b используется для деления. В случае если b=0 происходит ошибка деления на ноль. При этом результат деления никак не используется. Поэтому, при использовании точек останова и редактирования значений переменных мы можем вмешаться в поведение программы и преодолеть сбой:
(gdb) continue Continuing. Program terminated with signal SIGFPE, Arithmetic exception. The program no longer exists. (gdb) break 9 Breakpoint 1 at 0x555555554757: file example.c, line 9. (gdb) break 10 Breakpoint 2 at 0x555555554763: file example.c, line 10. (gdb) run Starting program: /home/vood/ws/a.out 0 Breakpoint 1, main () at example.c:9 9 a = a / b; (gdb) set variable b=1 (gdb) continue Continuing. Breakpoint 2, main () at example.c:10 10 printf("%d", b + c); (gdb) set variable b=0 (gdb) continue Continuing. 13[Inferior 1 (process 26853) exited normally]
9.4. Вопросы для контроля
- Приведите примеры кода на языке С, который может вызвать ошибку времени выполнения.
- Что необходимо сделать в процессе сборки программы компилятором gcc, чтобы ее бинарный файл включал отладочную информацию?
- Объясните, как с точки зрения программиста выглядит работа механизма точек останова.