Pull to refresh

Сделаем код чище: Нюансы вывода отладочных сообщений в драйверах Linux

Reading time 2 min
Views 4.7K
Как многим извесно вывод отладочных сообщений в Linux в отношении драйверов осуществляется несколькими подмножествами макросов и функций. Не все аналоги взаимозаменяемы и работают так, как кажется логичным на первый взгляд. Вот об этом и пойдёт речь в этой короткой заметке.

Для начала посмотрим, какие известные функции вывода сообщений предоставлены во внутреннем API ядра.

Базовая функция
printk(LEVEL "message\n");

От неё есть набор макросов (наиболее часто используемые):
pr_err("message\n");
pr_warn("message\n");
pr_info("message\n");
pr_debug("message\n");

И так далее.

Для драйверов же используется набор функций с префиксом dev_* с соответствющими уровнями вывода, и отдельно для драйверов сетевых карт c префиксом netdev_*. И вообще, общее правило, что подсистема ядра или драйвер использует свой префикс с суффиксом уровня вывода сообщения.

Все они являются полноценными аналогами записи printk(LEVEL …) для pr_* и таким же образом для dev_* и netdev_* за исключением pr_debug(), dev_dbg() и, как уже все догадались, netdev_dbg().

Итак, при каких условиях мы увидим сообщение, выводимое разными вариантами?

С помощью printk(KERN_DEBUG "message\n"):
  • уровень вывода в командной строке ядра выставлен равным или более 7 или передан параметр ignore_loglevel

и pr_debug("message\n"):
  • уровень вывода в командной строке ядра выставлен равным или более 7 или передан параметр ignore_loglevel
  • интересуемый нас модуль собран с опцией DEBUG или включена опция конфигурации ядра CONFIG_DYNAMIC_DEBUG, а соответствующие сообщения (например, указанием имя модуля: номер строки) включены в список выводимых

То же самое и для dev_dbg(), и для netdev_dbg().

Помимо этого особое внимание стоит уделить полезной опции CONFIG_DYNAMIC_DEBUG. При всей её динамичности работать она начинает не самой загрузки ядра, поэтому не во всех модулях можно полагаться на неё.

Ещё одна дилемма о том, что использовать в продуктовой версии: CONFIG_DYNAMIC_DEBUG или стандартный вывод, префиксируемый условием типа:
#define mydbg(dev, format, arg…) \
do { \
  if (mycooldriver->debug > 0) \
    dev_printk(KERN_DEBUG, dev,  format, ##arg); \
} while (0)

Так вот разница здесь вполне очевидна, если копнуть в недра исходного кода ядра, а именно в первом случае вывод будет приравнен к no-op (пустой операции), что не так во втором случае. Соответственно критичные по времени исполнения модули не стоит заполнять кодом, показанным выше. Более того, лучшим вариантом будет применение трассировочных точек в таких местах, но об этом я расскажу когда-нибудь в будущем.

Бонусом добавлю, что функция print_hex_dump_bytes() относительно недавно обзавелась поддержкой со стороны Dynamic Debug.
Tags:
Hubs:
+4
Comments 2
Comments Comments 2

Articles