Как многим извесно вывод отладочных сообщений в 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(mydev, format, arg…) \ do { \ if (mycooldriver->debug > 0) \ dev_printk(KERN_DEBUG, dev, format, ##arg); \ } while (0)
Так вот разница здесь вполне очевидна, если копнуть в недра исходного кода ядра, а именно в первом случае вывод будет приравнен к no-op (пустой операции), что не так во втором случае. Соответственно критичные по времени исполнения модули не стоит заполнять кодом, показанным выше. Более того, лучшим вариантом будет применение трассировочных точек в таких местах, но об этом я расскажу когда-нибудь в будущем.
Бонусом добавлю, что функция print_hex_dump_bytes()
относительно недавно обзавелась поддержкой со стороны Dynamic Debug.
ссылка на оригинал статьи http://habrahabr.ru/post/262791/
Добавить комментарий