Отладка
- Хорошая книжка по отладке: https://en.wikibooks.org/wiki/Linux_Applications_Debugging_Techniques 
О структуре исполняемых файлов (коротко)
ELF:
- nm для статически собранных объектников 
- readelf / objdump для динамически собранных объектников 
- ldd (LD_LIBRARY_PATH=, LD_PRELOAD= — в следующей лекции) 
Что нужно для отладки
- Без оптимизации
- Привязка к исходнику: без неё — только дизассемблер + имена
- Привязка к исходнику — debuginfo - Поиск исходника
 
- То же для всех библиотек - -debuginfo-версии пакетов с библиотеками 
- + их исходники (обычно содержатся в -debuginfo) 
 
⇒ cc -O0 -g
GDB
- Выполнение - run 
- continue 
- next 
- step 
- finish 
- advance 
 
- Точки останова - По номеру строки (оптимизация  ) breakpoint ) breakpoint- b main + run — это start 
 
- По изменению ячейки (=> выражения) watchpoint 
- По C++-исключению или syscall-у catchpoint 
 
- Просмотр - Ячейки (=> выражения, в т. ч. адресного) print, display, x 
- куска исходника вокруг точки останова list 
 
- Запись в файл dump 
- Стек вызовов - Просмотр backtrace 
- Переход up, down 
 
- …!
Пример на bt с несколькими функциями
- b fun2 + run + bt 
Пример игры со стеком:
- Он ещё и не падает, скотина! И компилируется без ошибок!! (Правда, ключ -Wall спасает, но не от всего). 
- Падает, если закомментировать вызов tst(&b); 
- Как поймать: - Посмотрим адрес b (локальная переменная ⇒ на стеке) p/x &b 
- Посмотрим состояние стека в tst() с помощью x/8x $sp и мусора под стеком x/20x $sp-0x20 (стек растёт вниз!) 
- Посмотрим адрес x в tst() и чему оно становится равно 
- Посмотрим адрес a в tst2(), какой «мусор» (ой ли?) там лежит, и что из всего этого получается! 
 
Такой вот этот ваш Си! Всё можно написать))
- Из чего состоит -devel пакет? 
- Из чего состоит -debuginfo пакет? 
- Вместо установки debuginfo-версий пакетов можно указать Debuginfod-сервер - В частности, для ALT: https://debuginfod.altlinux.org/ 
- Пример с libncursesw (если успеем) 
- ~/.cache/debuginfod_client 
 
Материалы:
- Шпаргалка по GDB: https://sourceware.org/gdb/onlinedocs/refcard.pdf 
- ptrace_scope и gdb -p - ALT: # cat /etc/sysctl.d/99-sysctl.conf kernel.yama.ptrace_scope = 0 
 
- ALT: 
- Способ отладки программ, работающих с экраном (например, с curses) - На сервере:  $ gdbserver localhost:port prog 
- На сервере же: $ gdb prog (gdb) target remote localhost:port …это вместо run …дальше как обычно 
 
- На сервере:  
 
- Способ отладки программ, работающих с экраном (например, с curses) 
- Удалённая отладка: - На свереве: - Зайти с пробросом порта: client$ ssh аккаунт@сервер -Lпорт:localhost:порт server$ gdbserver localhost:port prog 
 
- Зайти с пробросом порта: 
- На клиенте - получить исходник от prog (например, с помощью sftp / rsync, ssh) - $ gdb (gdb) target remote localhost:port … 
- debuginfo скачает сам! (или с $DEBUGINFOD_URLS) 
 
 
- На свереве: 
Интерфейсы для gdb
 Бонус: GDBFrontend Бонус: GDBFrontend- Проброс GDBFrontend с сервера практикума: - Установка GDBFrontend - Стартовый сценарий лежит в ~/.local/bin/; это хорошее место для добавления в $PATH 
 
- Проброс порта www-сервера [me@myhost ~]$ ssh myacc@linuxprac -L5000:localhost:5000 
- Запуск backend-а
- Запуск frontend-а
- Загрузить программу / нажать на жука   
 
- Установка GDBFrontend 
 
- Проброс GDBFrontend с сервера практикума: 
Сценарии для GDB
- обучающая статья — её имеет смысл отщёлкать! 
- Пример для кода с fun2() (кумулятивный, разберём понемногу) - set pagination off b fun2 if n > 98 command 1 bt cont end run quit
- .gdbinit - Пример (перекрашивание, сохранение истории и специальные функции для вывода содержимого QString): - set history save on set style address foreground yellow define printqs5static set $d=$arg0.d printf "(Qt5 QString)0x%x length=%i: \"",&$arg0,$d->size set $i=0 set $ca=(const ushort*)(((const char*)$d)+$d->offset) while $i < $d->size set $c=$ca[$i++] if $c < 32 || $c > 127 printf "\\u%04x", $c else printf "%c" , (char)$c end end printf "\"\n" end define printqs5dynamic set $d=(QStringData*)$arg0.d printf "(Qt5 QString)0x%x length=%i: \"",&$arg0,$d->size set $i=0 while $i < $d->size set $c=$d->data()[$i++] if $c < 32 || $c > 127 printf "\\u%04x", $c else printf "%c" , (char)$c end end printf "\"\n" end
 
- Сценарии для gdb на Питоне (в документации). А что, так можно было? 
Д/З
- Установить в сборочное окружение -debuginfo версии библиотек. В разных дистрибутивах могут называться по-разному, приезжать вместе с -devel версиями и даже отсутствовать. В ALT называются libчтототам-debuginfo-версия и лежат в отдельной секции репозитория (вот пример sources.list с сервера практикума) - frbrgeorge@linuxprac ~/src $ grep "^[^#]" /etc/apt/sources.list.d/yandex.list rpm [alt] http://mirror.yandex.ru/altlinux Sisyphus/x86_64 classic debuginfo rpm [alt] http://mirror.yandex.ru/altlinux Sisyphus/x86_64-i586 classic rpm [alt] http://mirror.yandex.ru/altlinux Sisyphus/noarch classic 
- Прощёлкать как минимум make-your-debugging-easier и gdb-scripting 
- Задача. - Написать простейшую (или нет, см. далее ☺) программу-генератор арифметической прогрессии range.c, принимающую от одного до трёх параметров по аналогии с питоновским range() - Без параметров — выводит help
- С одним параметром N — выводит в столбик последовательность [0, 1, … N-1]
- С двумя — M, N — последовательность [M, M+1, … N-1]
- С тремя — M, N, S — последовательность [M, M+S, M+2S, … N-1]
 
- Написать следующие gdb-сценарии (формат вывода произвольный): - Запустить ./range с параметрами 1 12 и вывести содержимое переменных, отвечающих на начало, конец, шаг и текущее значение элемента прогрессии, только когда этот элемент кратен 5 
- Запустить ./range с параметрами -100 100 3 и вывести содержимое переменных, отвечающих на начало, конец, шаг и текущее значение элемента прогрессии только для 28, 29, 30, 31, 32, 33, 34, и 35 по счёту элементов прогрессии 
 
- Написать Makefile, в котором будут - Компиляция бинарника с ключами -O0 -g 
- Цель test: — запуск этих gdb-сценариев и сравнение их вывода с эталонным - gdb любит выводить много лишней/динамической информации, например, адреса, которые вполне могут не повторяться при новом запуске. 
- я использовал в gdb-сценариях связку echo @@@ и print …, после чего grep-ал строки, начинающиеся на @@@, и с эталоном сравнивал только их. 
- Ещё я использовал --batch и --quiet, а вот logging не использовал 
- Чтобы вывод утилиты range не мешал, его надо перенаправлять в /dev/null прямо в самой команде run 
 
- Цель clean: — удаление всех генератов 
 
 
 Вариант для тех, кому скучно так тупо программировать на Си. Дописать функции и типы данных к этой программе, решить Д/З с ней: Вариант для тех, кому скучно так тупо программировать на Си. Дописать функции и типы данных к этой программе, решить Д/З с ней:- Заодно и поотлаживаете ☺!
 
- Создать в репозитории с решениями подкаталог 04_Debugging и положить туда все исходники решения этой задачи 
