Различия между версиями 6 и 7
Версия 6 от 2021-10-17 15:42:17
Размер: 9298
Редактор: FrBrGeorge
Комментарий:
Версия 7 от 2021-10-17 15:43:42
Размер: 9410
Редактор: FrBrGeorge
Комментарий:
Удаления помечены так. Добавления помечены так.
Строка 162: Строка 162:
    * Ещё я использовал `--batch` и `--quiet`, а вот `logging` не использовал

Отладка

TODO: раскрыть пункты, больше примеров!

О структуре исполняемых файлов (коротко)

ELF:

  • nm

  • readelf / objdump

  • ldd (LD_LIBRARY_PATH=, LD_PRELOAD=)

Что нужно для отладки

  • Без оптимизации
  • В ассемблерном виде + имена
  • Привязка к исходнику — debuginfo

  • То же для всех библиотек
    • + их исходники
    • -debuginfo-версии пакетов с библиотеками

cc -O0 -g

GDB

Документация

* Выполнение

  • run

  • continue

  • next

  • step

  • finish

  • advance

  • Точки останова
    • По номеру строки (оптимизация :( ) breakpoint

    • По изменению ячейки (=> выражения) watchpoint

    • По C++-исключению или syscall-у catchpoint

  • Просмотр
    • Ячейки (=> выражения, в т. ч. адресного) print, display, x

    • куска исходника вокруг точки останова list

    • дампа памяти dump

  • Стек вызовов
    • Просмотр backtrace

    • Переход up, down

  • «Отладка назад»

  • Запись/воспроизведение

  • …!

TODO пример на bt с несколькими функциями

Пример игры со стеком:

   1 #include <stdio.h>
   2 
   3 int tst(long *p) {
   4   long x;
   5   x = (long) p;
   6   return 0;
   7 }
   8 
   9 int tst2() {
  10   long int *a;
  11   *a = 42;
  12   return 0;
  13 }
  14 
  15 int main(int argc, char *argv[]) {
  16         long b=7;
  17         tst(&b);
  18         tst2();
  19         printf("⇒ %ld\n", b);
  20         return 0;
  21 }
  • Он ещё и не падает, скотина!
  • Падает, если закомментировать вызов tst(&b);

Материалы:

Интерфейсы для gdb

  • gdb -tui

  • cgdb

  • Nemiver, KDbg

  • Встроенные в IDE
  • <!> Бонус: gdbgui

    • Проброс GUI с сервера практикума!

Сценарии для GDB

TODO упорядочить

  • вот так всё просто

  • обучающая статья

  • на примерах

  • .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-сценарии (формат вывода произвольный):
      1. Запустить ./range с параметрами 1 12 и вывести содержимое переменных, отвечающих на зачало, конец, шаг и текущее значение элемента прогрессии, только когда этот элемент кратен 5

      2. Запустить ./range с параметрами -100 100 3 и вывести содержимое переменных, отвечающих на зачало, конец, шаг и текущее значение элемента прогрессии только для 28, 29, 30, 31, 32, 33, 34, и 35 по счёту элементов прогрессии

    • Написать Makefile, в котором будут

      1. Компиляция бинарника с ключами -O0 -g

      2. Цель test: — запуск gdb-сценариев и сравнение их вывода с эталонным

        • gdb любит выводить много лишней информации, я использовал в сценариях связку echo @@@ и print …, после чего grep-ал строки, начинающиеся на @@@

        • Ещё я использовал --batch и --quiet, а вот logging не использовал

        • Чтобы вывод утилиты range не мешал, его надо перенаправлять в /dev/null прямо в самой команде run

      3. Цель clean: — удаление всех генератов

  • <!> Вариант для тех, кому скучно так тупо программировать на Си. Дописать функции и типы данных к этой программе, решить Д/З с ней:

       1 int main(int argc, char *argv[]) {
       2         range I;
       3         argparse(argc, argv, &I.start, &I.stop, &I.step);
       4         for(range_init(&I); range_run(&I); range_next(&I))
       5                 printf("%d\n", range_get(&I));
       6         return 0;
       7 }
    
    • Заодно и поотлаживаете ☺!
  • Создать в репозитории с решениями подкаталог 05_Debugging и положить туда все исходники решения этой задачи

LecturesCMC/LinuxApplicationDevelopment2021/05_Debugging (последним исправлял пользователь FrBrGeorge 2021-10-17 15:43:42)