Чтение и фильтрация сообщений отладки

Подпрограммы DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix и KdPrintEx отправляют сообщение отладчику ядра в указанных условиях. Эта процедура позволяет отфильтровать сообщения с низким приоритетом.

Примечание.

В Microsoft Windows Server 2003 и более ранних версиях Windows подпрограммы DbgPrint и KdPrint отправляют сообщения в отладчик ядра безусловно. В Windows Vista и более поздних версиях Windows эти подпрограммы отправляют сообщения условно, например DbgPrintEx и KdPrintEx. Независимо от используемой версии Windows следует использовать DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix и KdPrintEx, так как эти подпрограммы позволяют управлять условиями отправки сообщения.

Фильтрация сообщений отладки

  1. Для каждого сообщения, которое нужно отправить отладчику, используйте DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix или KdPrintEx в коде драйвера. Передайте соответствующее имя компонента параметру ComponentId и передайте значение в параметр Level , который отражает серьезность или характер этого сообщения. Само сообщение передается параметрам формата и аргументов с помощью того же синтаксиса, что и printf.

  2. Задайте значение соответствующей маски фильтра компонентов. Каждый компонент имеет другую маску. Значение маски указывает, какие сообщения этого компонента отображаются. Маску фильтра компонентов в реестре можно задать с помощью редактора реестра или в памяти с помощью отладчика ядра.

  3. Подключите отладчик ядра к компьютеру. Каждый раз, когда драйвер передает сообщение DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix или KdPrintEx, значения, передаваемые в ComponentId и Level, сравниваются со значением соответствующей маски фильтра компонентов. Если эти значения соответствуют определенным критериям, сообщение отправляется отладчику ядра и отображается. В противном случае сообщение не отправляется.

Примечание.

Все ссылки на этой странице на DbgPrintEx применяются одинаково к KdPrintEx, vDbgPrintEx и vDbgPrintExWithPrefix.

Определение имени компонента

Каждый компонент имеет отдельную маску фильтра. Это позволяет отладчику настроить фильтр для каждого компонента отдельно.

Каждый компонент называется разными способами в зависимости от контекста. В параметре ComponentIddbgPrintEx имя компонента имеет префикс "DPFLTR_" и суффиксировано с "_ID". В реестре маска фильтра компонентов имеет то же имя, что и сам компонент. В отладчике маска фильтра компонентов содержит префикс "Kd_" и суффикс "_Mask".

Полный список всех имен компонентов (в формате DPFLTR_XXXXX_ID) в заголовке dpfilter.h в комплекте драйверов Microsoft Windows (WDK). Большинство этих имен компонентов зарезервированы для Windows и для драйверов, написанных корпорацией Майкрософт.

Существует шесть имен компонентов, зарезервированных для независимых поставщиков оборудования. Чтобы избежать смешивания выходных данных драйвера с выходными данными компонентов Windows, следует использовать одно из следующих имен компонентов:

Имя компонента Тип драйвера
IHVVIDEO Видео драйвер
IHVAUDIO Звуковой драйвер
IHVNETWORK Сетевой драйвер
IHVSTREAMING Драйвер потоковой передачи ядра
IHVBUS Водитель автобуса
IHVDRIVER Любой другой тип драйвера

Например, если вы пишете видеодрайвер, вы используете DPFLTR_IHVVIDEO_ID в качестве параметра ComponentIdDbgPrintEx, используете имя значения IHVVIDEO в реестре и обращаетесь к Kd_IHVVIDEO_Mask в отладчике.

Все сообщения, отправляемые DbgPrint и KdPrint , связаны с компонентом DEFAULT .

Выбор правильного уровня

Параметр Level подпрограммы DbgPrintEx имеет тип DWORD. Он используется для определения битового поля важности. Связь между параметром Level и этим битовым полем зависит от размера Level:

  • Если уровень равен числу от 0 до 31, включительно он интерпретируется как битовое сдвиг. Для битового поля важности задано значение 1 <<уровень. Таким образом, выбор значения от 0 до 31 для уровня приводит к битовому полю с точно одним установленным битом. Если уровень равен 0, битовое поле эквивалентно 0x00000001; Если уровень равен 31, битовое поле эквивалентно 0x80000000.

  • Если уровень равен числу от 32 до 0xFFFFFFFF включительно, значение битового поля важности присваивается самому значению уровня .

Таким образом, если вы хотите задать для битового поля значение 0x00004000, можно указать уровень как 0x00004000 или просто как 14. Обратите внимание, что определенные значения битового поля недоступны в этой системе, включая битовое поле, которое полностью равно нулю.

Для задания значения level можно использовать следующие константы. Они определяются в заголовке dpfilter.h в комплекте драйверов Microsoft Windows (WDK) и заголовке пакета SDK для Windows ntrtl.h:

#define   DPFLTR_ERROR_LEVEL     0
#define   DPFLTR_WARNING_LEVEL   1
#define   DPFLTR_TRACE_LEVEL     2
#define   DPFLTR_INFO_LEVEL      3
#define   DPFLTR_MASK   0x80000000

Один из простых способов использовать параметр Level — всегда использовать значения от 0 до 31— с использованием битов 0, 1, 2, 3 с значением, заданным DPFLTR_XXXXXX_LEVEL и используя другие биты, чтобы означать все, что вы выбрали.

Другой простой способ использования параметра Level — всегда использовать явные битовые поля. При выборе этого метода вы можете пожелать применить операцию ИЛИ со значением DPFLTR_MASK по отношению к вашему битовому полю; это гарантирует, что вы случайно не используете значение меньше 32.

Чтобы обеспечить совместимость драйвера с способом использования уровней сообщений Windows, необходимо задать только наименьший бит (0x1) значения битового поля важности, если возникает серьезная ошибка. Если вы используете значения уровня менее 32, это соответствует DPFLTR_ERROR_LEVEL. Если этот бит задан, ваше сообщение будет просматриваться в любой момент, когда кто-то подключает отладчик ядра к компьютеру, на котором работает драйвер.

Уровни предупреждения, отслеживания и информации должны использоваться в соответствующих ситуациях. Другие биты можно свободно использовать для любых целей, которые вы найдете полезными. Это позволяет иметь широкий спектр типов сообщений, которые можно выборочно видеть или скрывать.

Все сообщения, отправляемые DbgPrint и KdPrint, ведут себя как сообщения DbgPrintEx и KdPrintEx с уровнем, равным DPFLTR_INFO_LEVEL. Другими словами, эти сообщения имеют третий бит их значения битового поля.

Настройка маски фильтра компонентов

Существует два способа настройки маски фильтра компонентов:

  • Маску фильтра компонентов можно получить в разделе реестра HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Debug Print Filter. С помощью редактора реестра создайте или откройте этот ключ. Под этим ключом создайте значение с именем требуемого компонента в верхнем регистре. Задайте значение DWORD, которое вы хотите использовать в качестве маски фильтра компонентов.

  • Если отладчик ядра активен, он может получить доступ к значению маски фильтра компонента путем разыменовки адреса, хранящегося в символе Kd_XXXXX_Mask, где XXXX является нужным именем компонента. Значение этой маски можно отобразить в WinDbg или KD с помощью команды dd (Display DWORD) или ввести новую маску фильтра компонентов с помощью команды ed (ВВОД DWORD). Если существует опасность неоднозначности символов, может потребоваться указать этот символ как nt!Kd_XXXX_Mask.

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

Существует также маска на уровне системы, называемая WIN2000. Это равно 0x1 по умолчанию, хотя его можно изменить через реестр или отладчик, как и все остальные компоненты. При выполнении фильтрации каждая маска фильтра компонентов сначала отображается с помощью маски WIN2000 . В частности, это означает, что компоненты, маски которых никогда не были указаны по умолчанию для 0x1.

Критерии отображения сообщения

При вызове DbgPrintEx в коде в режиме ядра Windows сравнивает битовое поле важности сообщения, заданное уровнем , с маской фильтра компонента, указанного ComponentId.

Примечание.

Помните, что при значении параметра Level от 0 до 31 битовое поле важности равно 1 <<уровню. Но если параметр Level равен 32 или больше, битовое поле важности просто равно Level.

Windows выполняет операцию AND в битовом поле важности и маске фильтра компонентов. Если результат ненулевой, сообщение отправляется отладчику.

Пример фильтра отладки

Предположим, что перед последней загрузкой вы создали следующие значения в ключе Фильтр печати отладки :

  • IHVVIDEO с значением, равным DWORD 0x2

  • IHVBUS, равный DWORD 0x7FF

Теперь вы выдаете следующие команды в отладчике ядра:

kd> ed Kd_IHVVIDEO_Mask 0x8 
kd> ed Kd_IHVAUDIO_Mask 0x7 

На этом этапе компонент IHVVIDEO имеет маску фильтра 0x8, компонент IHVAUDIO имеет маску фильтра 0x7, а компонент IHVBUS имеет маску фильтра 0x7FF.

Тем не менее, поскольку эти маски автоматически объединяются по маске «ИЛИ» с системной маской WIN2000 (которая обычно равна 0x1), маска IHVVIDEO фактически равна 0x9. Действительно, компоненты, маски фильтров которых не заданы вообще (например, IHVSTREAMING или DEFAULT), будут иметь маску фильтра 0x1.

Теперь предположим, что следующие вызовы функций происходят в различных драйверах:

DbgPrintEx( DPFLTR_IHVVIDEO_ID,  DPFLTR_INFO_LEVEL,   "First message.\n");
DbgPrintEx( DPFLTR_IHVAUDIO_ID,  7,                   "Second message.\n");
DbgPrintEx( DPFLTR_IHVBUS_ID,    DPFLTR_MASK | 0x10,  "Third message.\n");
DbgPrint( "Fourth message.\n");

Первое сообщение имеет параметр Level , равный DPFLTR_INFO_LEVEL, что равно 3. Так как это меньше 32, оно обрабатывается как битовый сдвиг, что приводит к битовому полю с важностью 0x8. Затем это значение подвергается побитовой операции И с эффективной маской фильтра компонентов IHVVIDEO, имеющей значение 0x9, что дает не нулевой результат. Поэтому первое сообщение передается отладчику.

Второе сообщение имеет параметр Level равным 7. Опять же, это обрабатывается как битовый сдвиг, что приводит к битовому полю важности 0x80. Затем это anDed с маской фильтра компонентов IHVAUDIO 0x7, что дает результат нуля. Поэтому второе сообщение не передается.

Третье сообщение имеет параметр Level , равный DPFLTR_MASK | 0x10. Это больше 31, поэтому значение битового поля важности равно значению уровня , иными словами, 0x80000010. Затем это выполняется операция AND с маской фильтра компонентов IHVBUS 0x7FF, что дает ненулевой результат. Поэтому третье сообщение передается отладчику.

Четвертое сообщение было передано dbgPrint вместо DbgPrintEx. В Windows Server 2003 и более ранних версиях Windows сообщения, передаваемые этой подпрограмме, всегда передаются. В Windows Vista и более поздних версиях Windows сообщения, передаваемые этой подпрограмме, всегда получают фильтр по умолчанию. Битовое поле важности равно 1 << DPFLTR_INFO_LEVEL, которое 0x00000008. Компонент этой подпрограммы — DEFAULT. Так как маска фильтра компонентов DEFAULT не задана, поэтому она имеет значение 0x1. Если это anDed с битовым полем важности, результат равен нулю. Поэтому четвертое сообщение не передается.

Буфер DbgPrint и отладчик

Когда подпрограммы DbgPrint, DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix, KdPrint или KdPrintEx передают сообщение в отладчик, отформатированная строка отправляется в буфер DbgPrint. Содержимое этого буфера сразу отображается в окне команд отладчика, если только вы не отключили это отображение с помощью опции Buffer DbgPrint Output в GFlags.

Во время локальной отладки ядра и при отключении этого отображения содержимое буфера DbgPrint можно просматривать только с помощью команды расширения !dbgprint .

Любой одиночный вызов DbgPrint, DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix, KdPrint или KdPrintEx передает только 512 байт информации. Все выходные данные, превышающие 512 байт, теряются. Сам буфер DbgPrint может содержать до 4 КБ данных в бесплатной сборке Windows и до 32 КБ данных в проверенной сборке Windows. В Windows Server 2003 и более поздних версиях Windows можно использовать средство KDbgCtrl для изменения размера буфера DbgPrint. Это средство входит в состав средств отладки для Windows.

Примечание.

Проверенные сборки были доступны в более ранних версиях Windows до Windows 10 версии 1803. Используйте такие средства, как средство проверки драйверов и GFlags, чтобы проверить код драйвера в более поздних версиях Windows.

Если сообщение отфильтровывается из-за значений ComponentId и Level , оно не передается через отладчик. Поэтому в отладчике нет способа отобразить это сообщение.