Памятка по отладке ядра и драйверов во FreeBSD
7 апреля 2016
Недавно мы научились собирать FreeBSD из исходных кодов. Этих знаний достаточно, если вы хотите просто попробовать самые свежие фичи системы или оптимизировать FreeBSD под конкретное железо. Но если вы собираетесь как следует порыться в кишках системы, дабы лучше разобраться в ее работае, или даже что-то изменить в ней, необходимо уметь цепляться к системе отладчиком. Да и если вы админите сервера под управлением FreeBSD, знания о том, как анализировать корку упавшего ядра, пожалуй, будут не лишними.
Несколько замечаний
Хочу отметить, что мир отлаживать мы уже умеем, так как он представляет собой обычные пользовательские приложения, которые прекрасно отлаживаются при помощи GDB, LLDB и так далее. Поэтому далее мы сосредоточимся на отладке ядра и драйверов.
Упомянутая чуть выше заметка «Собираем ядро и мир FreeBSD из исходников» является обязательной к предварительному прочтению. В частности, в ней рассказывается, как загрузиться с альтернативным ядром, если с текущим что-то очень сильно не так.
Отмечу также, что чтобы повторить действия, описанные далее, тратить время на компиляцию ядра и мира не обязательно. Вместо этого можно просто скачать ISO-образ с CURRENT-веткой FreeBSD. Заметьте, что RELEASE и STABLE не подходят, так как в них по умолчанию отключены отладочные опции, и ядро таки придется пересобрать.
Анализ корок при помощи отладчика KGDB
Самый простой способ отладки кода уровня ядра во FreeBSD — это уронить ядро, перезагрузиться, и изучить записанную корку. Зачастую это является единственным доступным способом отладки, так как ядро упало где-то там у пользователя, не умеющего и не желающего отлаживать систему на лету, а локально проблема не воспроизводится.
Запись kernel dump’ов включается путем записи в /etc/rc.conf:
ddb_enable="YES"
Также в /etc/sysctl.conf дописываем:
Теперь проще всего уронить ядро, дернув специальную отладочную ручку:
После перезагрузки можно проверить, что корка действительно записалась:
Должны увидеть файлы с именами core.txt.0 и vmcore.0. Первый представляет собой обычный текстовый файл со стэктрейсом того места, в котором все упало, выводом dmesg, списком параметров, с которыми было собрано ядро, и прочей отладочной информацией.
Иногда core.txt.* могут по каким-то причинам не создаваться. Тогда используйте команду вроде следующей:
Файлы vmcore.* — это корки, которые можно проанализировать отладчиком:
Важно! Если вдруг вы собрали ядро следующей мажорной версии FreeBSD, и пытаетесь дебажить его отладчиком из мира предыдущей мажороной версии, это может не работать. Я в этом случае получил пустые стэктрейсы, все нити выполнялись по адресу 0x00000000 и так далее. Для решения этой проблемы требуется также обновить и мир.
Все команды в KGDB такие же, как и в GDB. Смотрим нити, стэктрейсы, значения переменных и аргументов процедур — все то же самое.
Дополнение: Во FreeBSD для записи корок обязательно требуется swap-раздел. Подробности см в посте Пример переразбиения диска во FreeBSD с помощью gpart.
Отладка на лету при помощи DDB
К сожалению, анализ корок не позволяет посмотреть на работу системы в реальном времени. Есть несколько способов решить эту проблему. Один из них заключается в использовании отладчика DDB. Сразу скажу, что отлаживать систему удаленно исключительно при помощи DDB не представляется возможным. Смотреть нужно прямо в монитор.
Важно! Для поддержки DDB система должна быть собрана с опциями KDB и DDB. Заметьте, что GENERIC-ядро RC- и RELEASE-сборок FreeBSD по умолчанию этих опций не имеет. В CURRENT эти опции есть из коробки.
Провалиться в DDB можно несколькими способами.
Во-первых, выбрав на этапе загрузки Escape to a loader prompt (нажатием 3) и загрузив ядро с флагом -d:
Во-вторых, прямо в процессе работы системы сказав:
Наконец, можно выйти из иксов (например, Ctr+Alt+F1) и нажать Ctr+Alt+Escape.
Основные команды DDB перечислены ниже.
Подсказка:
Step и next — как в GDB:
n
Бэктрейс:
Поставить бряк:
Показать список бряков:
Удалить бряк:
Продолжить работу системы:
Показать значения регистров:
Информация о текущей нитке:
Показать все нитки:
Список процессов:
Информация обо все локах:
Информация обо всех файлах в системе:
Записать дамп для анализа потом:
Перезагрузить систему:
Прочие команды DDB можно подсмотреть в man 4 ddb. Помимо перечисленных выше основных команд DDB предоставляет действительно впечатляющий список других возможностей. К сожалению, насколько я смог разобраться, сам по себе DDB не позволяет просматривать в удобочитаемом виде значения локальных переменных и аргументов процедур, переключаться между фреймами стека или нитками, ровно как и смотреть исходный или ассемблерный код того места, на котором мы сейчас остановились.
Поэтому рассматрим еще один способ.
Отладка через последовательный порт при помощи KGDB
Этот способ позволяет отлаживать систему в реальном времени с удобным просмотром значений переменных, переключением между фреймами стэка, и так далее. Однако он требует наличия двух машин, соединенных через последовательный порт. Сказать по правде, компьютеров, оснащенных последовательным портом, я очень давно не видел. Вроде как делают переходники в/из USB, но сам я их не пробовал, к тому же, они требуют установки драйверов. Поэтому далее мы будем использовать не настоящие машины, а виртуальные. Желательно клонировать одну и ту же виртуальную машину, чтобы ядро и мир на них не отличались.
Ядро должно быть собрано со следующими опциями (уже есть в CURRENT):
options KDB
options GDB
makeoptions DEBUG=-g
Какая из опций что означает можно прочитать здесь. Еще не лишено смысла собирать ядро с флагом -O0
, иначе вместо значений переменных вы будете часто видеть «value optimized out».
Если вы используете VirtualBox, то соединить машины по последовательному порту достаточно просто. На первой машине, которую будете отлаживать, идете в Settings → Serial Ports, ставите галочку Enable Serial Port, в Path/Address пишите что-то вроде /tmp/com1. На второй машине, с которой будем отлаживать первую, повторяете все то же самое, плюс ставите галочку Connect to existing pipe/socket. Если вы клонировали виртуалки, проверьте также, что у них прописаны разные MAC-адреса.
Если же вы предпочитаете KVM, то создаем пайпы следующим образом:
cd /var/lib/libvirt/pipes
mkfifo null-cable-1.{in,out}
ln null-cable-1.in null-cable-2.out
ln null-cable-1.out null-cable-2.in
Затем в virt-manager в свойствах виртуальных машин заводим последовательные порты, указывая путь до null-cable-1 в случае одной виртуальной машины и null-cable-2 в случае второй:
В результате машины будут соединены друг с другам через виртуальный serial port, который они будут видеть как /dev/cuau0.
На машине, с которой будем отлаживаеть (на ней для удобства можно сидать по SSH), переходим в /usr/src. Затем говорим:
На целевой машине открываем /boot/device.hints и правим следующее значение:
Флаг 0x80 говорит ядру использовать последовательный порт для удаленной отладки, см man uart. При этом значение 0x10 стоит там по дэфолту (device is potential system console), отсюда получаем значение 0x90.
Затем все также на целевой машине перезагружаемся и попадем в отладчик DDB одним из описанных ранее способов, в нем говорим:
На второй машине внутри отладчика говорим:
Должны в результате увидеть что-то вроде:
Remote debugging using /dev/cuau0
0xffffffff80a3fdae in kdb_enter ()
На случай, если вам нравится вводить поменьше команд в отладчике, сообщаю, что вместо запуска KGDB и затем выполнения в нем команд можно просто сказать:
После выполнения команды c
вернуться обратно в отладчик нажатием Ctr+C, как это обычно делается в GDB, нельзя. Вместо этого нужно либо нажать в окне целевой системы сочетание Ctr+Alt+Escape, либо выполнить на ней команду:
В итоге получаем отладку живой операционной системы, которая мало чем отличается от отладки обычных приложений в GDB.
Заключение
Согласитесь, в итоге все оказалось не так уж и сложно!
Некоторые ссылки по теме:
- FreeBSD Device Drivers: A Guide for the Intrepid;
- The Design and Implementation of the FreeBSD Operating System, 2nd ed;
- Profiling and Debugging the FreeBSD Kernel [PDF];
- FreeBSD Project "ideas" List: Kernel Projects;
- FreeBSD Google Summer of Code Ideas;
- Performance Improvements for FreeBSD Kernel Debugging;
А ковыряетесь ли вы в кишках операционных систем и если да, то каких и что за инструменты при этом используете?
Дополнение: Вас также могут заинтересовать статьи Скандальная правда об отладке ядерного кода в Linux и Использование DTrace на примере FreeBSD и Linux.
Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.