null

Анализируем ядро Linux с помощью SystemTap

Кстати я написал небольшое пособие по DTrace и SystemTap: Инструменты динамической трассировки DTrace и SystemTap


Администрируя Solaris, свыкаешься, что есть такие возможности, как Crossbow, DTrace, ZFS... И когда приходится работать с другими ОС, и от этой вкуснятины тяжело отказаться :-) В учебных целях я ковыряю ядро Linux, и естественно DTrace был бы прекрасным помошником в этом нелегком деле, но опыт использования порта DTrace под Linux (www.crisp.demon.co.uk/blog/) был не очень удачным - модуль ядра отказывался загружаться, было это правда год назад. Как оказалось, в Linux уже существует довольно мощное решение - SystemTap (sourceware.org/systemtap/), разработанный IBM, Oracle и Red Hat.

В отличие от DTrace, имеющего встроенный язык, компилируемый непосредственно в ядро, SystemTap же преобразует сначала исходник в C, а затем компилирует его в виде модуля ядра, что несколько увеличивает время запуска скрипта. С другой стороны, так как SystemTap работает также и с исходниками (в отличие от Solaris где они формально закрыты), и позволяет встраивать код на C в свои модули (наконец-то if/else вместо предикатов).

Установка SystemTap


Самый простой способ - это собрать свое ядро c опциями  CONFIG_DEBUG_INFO, CONFIG_KPROBES, CONFIG_RELAY, CONFIG_DEBUG_FS, CONFIG_MODULES, CONFIG_MODULE_UNLOAD.
После этого надо установить его и исходники ядра:

	# make modules_install install headers_install

И включить в GRUB / пересобрать initrd - тут уже все зависит от дистрибутива.

 


После того, как будет установлено ядро, systemtap попытается использовать файл vmlinux (бинарник ядра) и его исходники в директории /lib/modules/<версия ядра>/build/, я ее создал вручную:

	# ln -s /pool/leo4-devel/linux/linux-2.6.35.5 /lib/modules/2.6.35.5/build
# cp /pool/leo4-devel/linux/linux-2.6.35.5/arch/x86/boot/compressed/vmlinux \
/lib/modules/2.6.35.5/build/


Также можно собрать и systemtap из исходников, но для этого потребуется доустановить соответствующие пакеты. В Debian я делал это так:

	# apt-get install elfutils-devel libebl-dev libdw-dev libelf-dev libelf1



В Red Hat-подобных дистрибутивах необходимая для systemtap debuginfo располагается в специальных RPM-пакетах. Обычно они располагаются в отдельных репозиториях, например для CentOS 5.5 это http://debuginfo.centos.org/5/i386/ Самое главное, чтобы совпадали версии debug-пакетов и версия, однако признаться честно даже установив пакеты одной версии я получал ошибки и даже паники и в конце-концов забросил это дело. На systemtap wiki можно найти инструкции по установке для различных дистрибутивов.

 

Утилита stap


Основное приложение systemtap - stap, преобразующее скрипт stp в модуль ядра и запускающее его на исполнение. Ее синтаксис:

	stap [опции] FILE Запуск скрипта из файла
stap [опции] - Запуск скрипта из потока stdin
stap [опции] -e SCRIPT Запуск скрипта из командной строки
stap [опции] -l PROBE Вывод списка проб
stap [опции] -L PROBE Вывод списка проб и локальных переменных


Можно отметить следующие полезные опции:

 

  • -v - в зависимости от количества букв 'v' увеличивает подробность вывода systemtapом диагностической информации. Сюда же обычно входят и замеры производительности самого stap. Крайне полезна, особенно учитывая, что без этой опции systemtap никак не извещает о запуске модуля на исполнение
  • -p X - заставляет stap останавливаться после выполнения стадии X. Например, остановившись на 4й стадии мы не запустим модуль, но скомпилируем его
  • -k - stap не удаляет сгенерированные файлы (обычно располагаются в /tmp/stapXXXX)
  • -g - включает guru-mode, активирующий дополнительные пробы и позволяющий изменять состояние ядра
  • -c COMMAND / -x PID - при запуске stap запускает одновременно команду или цеплятся к уже запущенному процессу по pid. Этот pid можно узнать, используя встроенную функцию systemtap target()
  • -o FILE - перенаправляет вывод systemtap в файл
  • -m MODULE - указывает имя модуля вместо stap_YYYY. В сочетании с опцией -k это полезно в случае, если мы хотим использовать модуль повторно, не перекомпилируя его. Для запуска чистого модуля stap используется команда staprun. Но учитывайте, что собранный модуль подойдет только для того ядра, для которого он собран
  • --all-modules - разыменовывает адреса для всех модулей (по-умолчанию stap делает это только в рамках одного модуля)


Попробуем запустить простенький скрипт на systemtap:

	lktest:/home/myaut# stap -c 'cat /etc/fstab > /dev/null'
 -e 'probe syscall.open { printf("Open file [%s] %s\n", execname(), filename); } '
WARNING: Number of errors: 0, skipped probes: 4
Open file [sh] /etc/ld.so.cache
Open file [sh] /lib/libncurses.so.5
Open file [sh] /lib/libdl.so.2
Open file [sh] /lib/libc.so.6
Open file [sh] <unknown>
Open file [sh] <unknown>
Open file [sh] /proc/meminfo
Open file [sh] <unknown>
Open file [sh] /dev/null
Open file [cat] /etc/ld.so.cache
Open file [cat] /lib/libc.so.6
Open file [cat] <unknown>
Open file [cat] /etc/fstab

 

Пробы systemtap


Как можно заметить, пробы в systemtap именуются несколько по-иному чем в DTrace: они имеют форму имя_провайдера.имя_пробы.квалификатор_пробы.
Самые простые пробы - begin и end, связываемые с началом и окончанием выполнением скрипта соответственно. Как и в DTrace, systemtap имеет таймер: timer.единицы_измерения(количество), например: timer.s(5), timer.ms(100) Одна из возможных единиц измерения - jiffies, привязанная не физическому времени, а вездесущему таймеру Linux.

Ну и безусловно, самая популярная группа проб (однако не единственная, кроме нее в последних версиях ядра/systemtap появилась интеграция с интерфейсами tracepoint и kprobe) - связана с DWARF ядра и процессов, позволяющая привязыватся к функциям ядра. В отличие от DTrace systemtap, анализирует еще и исходники, что позволяет прибегать например и к таким конструкциям:

	kernel.function("*@block/blk-*.c")

В этом случае привязка будет произведена ко всем функциям, располагающимся в файлах block/blk-*.c ядра Linux. В случае если нужно привязаться к функции внутри модуля, нужно указать его имя:

	module("scsi_mod").function("scsi_done")

Квалификатор .return указывает на привязку к завершению функции.

Безусловно kernel/module - это мощный интерфейс, но не всегда достаточно удобный. Поэтому в SystemTap существуют т.н. tapsets - алиасы к DWARF-пробам. Примером такого tapset является syscall, с которым мы уже сталкивались.  Более подробную информацию по пробам можно найти в документации по stapprobes на сайте systemtap: sourceware.org/systemtap/man/stapprobes.3stap.html или в соответствующих man-pages

В следующей статье я постараюсь более подробно остановиться на программировании на скриптовом языке SystemTap
 

К списку статей

 

Интересуюсь по большей части системным анализом программного обеспечения: поиском багов и анализом неисправностей, а также системным программированием (и не оставляю надежд запилить свою операционку, хотя нехватка времени сказывается :) ). Программированием увлекаюсь с 12 лет, но так уж получилось, что стал я инженером.

Основная сфера моей деятельности связана с поддержкой Solaris и оборудования Sun/Oracle, хотя в последнее время к ним прибавились технологии виртуализации (линейка Citrix Xen) и всякое разное от IBM - от xSeries до Power. Учусь на кафедре Вычислительной Техники НИУ ИТМО.

See you...out there!

http://www.facebook.com/profile.php?id=100001947776045
https://twitter.com/AnnoyingBugs

Ничего не найдено. n is 0