Что изменилось в 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 вручную.













