Обновить

Что изменилось в task_struct между двумя ядрами? Написал diff для BTF

bpftool умеет показывать BTF-структуры, но сравнивать их между двумя ядрами уже приходится самому. Можно, конечно, открыть два дампа и искать отличия глазами. Только когда в них тысячи строк, а идентификаторы типов отличаются, занятие быстро надоедает.

Особенно если интересует одна конкретная структура и хочется понять, поменялся ли её размер, сместилось ли поле или появилось что-то новое.

Решил написать для этого небольшую утилиту - btf-layout-diff

Что она делает?

Это CLI-инструмент на C++20, который читает raw-дампы bpftool и сравнивает layout именованных STRUCT и UNION

Смотрит на размер структуры, поля, их битовые смещения и размеры bitfield. При этом не учитывает BTF type_id: идентификаторы могут отличаться между дампами, даже если сама структура не изменилась.

Получить дамп можно так:

bpftool btf dump file /sys/kernel/btf/vmlinux format raw > kernel.raw

Снимаем его на двух Linux-хостах, переносим файлы на одну машину и запускаем:

./build/btf-layout-diff kernel-old.raw kernel-new.raw --type task_struct

Для примера в репозитории есть две тестовые фикстуры. В одной task_struct занимает 24 байта, в другой - 32. Заодно добавлено поле new_field.

Вывод получается таким:

~ STRUCT task_struct  size: 24 -> 32 bytes  + new_field at 192 bits

Никакого настоящего изменения task_struct между версиями Linux здесь нет - оба дампа синтетические. Они нужны, чтобы пример можно было запустить без двух разных ядер.

А как насчёт CO-RE?

Собственно, из-за CO-RE мне и стало интересно сравнивать BTF.

Когда BPF-программа работает на одном ядре, но возникают проблемы на другом, хочется посмотреть, какие типы и смещения отличаются. CO-RE как раз использует BTF для адаптации обращений к структурам, но это не значит, что любые изменения layout автоматически ломают программу.

И наоборот: одинаковый layout ещё не гарантирует, что программа успешно загрузится.

Поэтому btf-layout-diff не проверяет совместимость CO-RE. Он не анализирует релокации из ELF, не отслеживает рекурсивно типы полей и ничего не знает о решениях verifier.

Задача гораздо проще: показать разницу между описаниями структур, чтобы не искать её вручную.

Что проверил?

Я добавил тесты на изменение размеров структур, смещений полей и bitfield. Отдельно проверил случай, когда меняются только type_id: ложных отличий в отчёте быть не должно.

Есть проверки неполной записи структуры и неоднозначных имён.

Локально собирал проект на macOS. В GitHub Actions сборка и тесты проходят на Linux и macOS.

Запустить можно из репозитория: sairex53/btf-layout-diff.

Пока следующий шаг — сравнить BTF двух реальных ядер, взять BPF-программу, которая обращается к изменившейся структуре, и посмотреть, как с этим работают её CO-RE-релокации.

Сейчас инструмент решает только первую часть задачи. Но для неё мне и хотелось иметь отдельный diff, а не разбирать два больших вывода bpftool вручную.

Теги:
+1
Комментарии0

Публикации