Чтение и фильтрация сообщений отладки
Подпрограммы DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix и KdPrintEx отправляют сообщение в отладчик ядра при указанных вами условиях. Эта процедура позволяет отфильтровать сообщения с низким приоритетом.
Примечание
В Microsoft Windows Server 2003 и более ранних версиях Windows подпрограммы DbgPrint и KdPrint безоговорочно отправляют сообщения в отладчик ядра. В Windows Vista и более поздних версиях Windows эти подпрограммы отправляют сообщения условно, например DbgPrintEx и KdPrintEx. Какую бы версию Windows вы ни использовали, следует использовать DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix и KdPrintEx, так как эти подпрограммы позволяют управлять условиями отправки сообщения.
Фильтрация сообщений отладки
Для каждого сообщения, которое вы хотите отправить в отладчик, используйте DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix или KdPrintEx в коде драйвера. Передайте соответствующее имя компонента параметру ComponentId и значение в параметр Level , отражающее серьезность или характер этого сообщения. Само сообщение передается в параметры Format и arguments с использованием того же синтаксиса, что и printf.
Задайте значение соответствующей маски фильтра компонента. Каждый компонент имеет разные маски. Значение маски указывает, какие сообщения этого компонента отображаются. Маску фильтра компонентов можно задать в реестре с помощью редактора реестра или в памяти с помощью отладчика ядра.
Подключите отладчик ядра к компьютеру. Каждый раз, когда драйвер передает сообщение в DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix или KdPrintEx, значения, передаваемые в ComponentId и Level , сравниваются со значением соответствующей маски фильтра компонента. Если эти значения удовлетворяют определенным критериям, сообщение отправляется в отладчик ядра и отображается. В противном случае сообщение не отправляется.
Примечание
Все ссылки на dbgPrintEx на этой странице в равной степени относятся к KdPrintEx, vDbgPrintEx и vDbgPrintExWithPrefix.
Определение имени компонента
Каждый компонент имеет отдельную маску фильтра. Это позволяет отладчику настраивать фильтр для каждого компонента отдельно.
Каждый компонент ссылается по-разному в зависимости от контекста. В параметре ComponentIddbgPrintEx имя компонента имеет префикс "DPFLTR_" и суффикс "_ID". В реестре маска фильтра компонента имеет то же имя, что и сам компонент. В отладчике маска фильтра компонента имеет префикс "Kd_" и суффикс "_Mask".
Полный список всех имен компонентов (в формате DPFLTR_XXXX_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:
Если значение Level равно числу от 0 до 31 включительно, оно интерпретируется как битовое смещение. Для битового поля важности задано значение 1 <<Уровень. Таким образом, при выборе значения от 0 до 31 для параметра Уровень создается битовое поле с набором битов. Если значение Level равно 0, битовое поле эквивалентно 0x00000001; Если значение Level равно 31, битовое поле эквивалентно 0x80000000.
Если значение Level является числом от 32 до 0xFFFFFFFF включительно, то для битового поля важности устанавливается значение Самого уровня .
Таким образом, если вы хотите задать для битового поля значение 0x00004000, вы можете указать Уровень как 0x00004000 или просто как 14. Обратите внимание, что некоторые значения битовых полей недоступны в этой системе, включая битовое поле, которое полностью равно нулю.
Следующие константы могут быть полезны для задания значения Level. Они определены в заголовке пакета драйверов Microsoft Windows (WDK) dpfilter.h и в заголовке windows SDK 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_XXXX_LEVEL, а другие биты означают все, что вы выберете.
Еще один простой способ использования параметра Level — всегда использовать явные битовые поля. При выборе этого метода может потребоваться ИЛИ значение, DPFLTR_MASK с битовое поле; это гарантирует, что вы не будете случайно использовать значение меньше 32.
Чтобы обеспечить совместимость драйвера с тем, как Windows использует уровни сообщений, следует задать самый низкий бит (0x1) поля бита важности только в случае серьезной ошибки. Если вы используете значения Level меньше 32, это соответствует DPFLTR_ERROR_LEVEL. Если этот бит задан, сообщение будет просматриваться каждый раз, когда кто-то подключит отладчик ядра к компьютеру, на котором работает драйвер.
Уровни предупреждения, трассировки и информации должны использоваться в соответствующих ситуациях. Другие биты можно свободно использовать для любых целей, которые вы найдете полезными. Это позволяет иметь широкий спектр типов сообщений, которые можно выборочно просматривать или скрывать.
Все сообщения , отправляемые DbgPrint и KdPrint , ведут себя как сообщения DbgPrintEx и KdPrintEx с уровнем , равным DPFLTR_INFO_LEVEL. Другими словами, эти сообщения имеют третий бит их битового поля важности.
Настройка маски фильтра компонентов
Настроить маску фильтра компонентов можно двумя способами.
Доступ к маске фильтра компонентов можно получить в разделе реестра HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Debug Print Filter. С помощью редактора реестра создайте или откройте этот раздел. В этом разделе создайте значение с именем нужного компонента в верхнем регистре. Задайте для него значение DWORD, которое вы хотите использовать в качестве маски фильтра компонента.
Если отладчик ядра активен, он может получить доступ к значению маски фильтра компонента, разыменовав адрес, хранящийся в символе Kd_XXXX_Mask, где XXXX — нужное имя компонента. Вы можете отобразить значение этой маски в WinDbg или KD с помощью команды dd (Display DWORD) или ввести новую маску фильтра компонента с помощью команды ed (Ввод DWORD). Если существует опасность неоднозначности символов, вы можете указать этот символ как nt! Kd_XXXX_Mask.
Маски фильтров, хранящиеся в реестре, вступают в силу во время загрузки. Маски фильтров, созданные отладчиком, вступают в силу немедленно и сохраняются до перезагрузки Windows. Значение, заданное в реестре, может быть переопределено отладчиком, но при перезагрузке системы маска фильтра компонента вернется к значению, указанному в реестре.
Существует также общесистемная маска под названием WIN2000. По умолчанию это значение равно 0x1, хотя его можно изменить с помощью реестра или отладчика, как и все остальные компоненты. При выполнении фильтрации каждый компонент маски фильтра сначала определяется с WIN2000 маской. В частности, это означает, что компоненты, маски которых никогда не были указаны, по умолчанию 0x1.
Критерии для отображения сообщения
При вызове DbgPrintEx в коде в режиме ядра Windows сравнивает битовое поле важности сообщения, указанное в параметре Level , с маской фильтра компонента, заданного параметром 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. Затем выполняется anded с маской фильтра компонента 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 . Содержимое этого буфера отображается сразу в окне Командная команда отладчика, если только вы не отключили это отображение с помощью параметра Выходные данные буфера DbgPrint для 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 , оно не передается через соединение отладки. Поэтому невозможно отобразить это сообщение в отладчике.