다음을 통해 공유


디버깅 메시지 읽기 및 필터링

DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefixKdPrintEx 루틴은 사용자가 지정한 조건에 따라 커널 디버거에 메시지를 보냅니다. 이 절차를 통해 우선 순위가 낮은 메시지를 필터링할 수 있습니다.

비고

Microsoft Windows Server 2003 및 이전 버전의 Windows에서 DbgPrintKdPrint 루틴은 커널 디버거에 무조건 메시지를 보냅니다. Windows Vista 이상 버전의 Windows에서 이러한 루틴은 DbgPrintExKdPrintEx와 같은 메시지를 조건부로 보냅니다. 어떤 버전의 Windows를 사용하든 DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefixKdPrintEx를 사용해야 합니다. 이러한 루틴을 사용하면 메시지가 전송되는 조건을 제어할 수 있기 때문입니다.

디버깅 메시지를 필터링하려면

  1. 디버거에 보내려는 각 메시지에 대해 드라이버 코드에서 DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix 또는 KdPrintEx 를 사용합니다. 적절한 구성 요소 이름을 ComponentId 매개 변수에 전달하고 이 메시지의 심각도 또는 특성을 반영하는 값을 Level 매개 변수에 전달합니다. 메시지 자체는 printf와 동일한 구문을 사용하여 Format인수 매개 변수에 전달됩니다.

  2. 적절한 구성 요소 필터 마스크의 값을 설정합니다. 각 구성 요소에는 다른 마스크가 있습니다. 마스크 값은 해당 구성 요소의 메시지가 표시되는 것을 나타냅니다. 레지스트리 편집기를 사용하거나 커널 디버거를 사용하여 메모리에서 구성 요소 필터 마스크를 설정할 수 있습니다.

  3. 커널 디버거를 컴퓨터에 연결합니다. 드라이버가 DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix 또는 KdPrintEx에 메시지를 전달할 때마다 ComponentIdLevel 에 전달되는 값은 해당 구성 요소 필터 마스크의 값과 비교됩니다. 이러한 값이 특정 조건을 충족하는 경우 메시지가 커널 디버거로 전송되고 표시됩니다. 그렇지 않으면 메시지가 전송되지 않습니다.

비고

DbgPrintEx에 대한 이 페이지의 모든 참조는 KdPrintEx, vDbgPrintExvDbgPrintExWithPrefix에 동일하게 적용됩니다.

구성 요소 이름 식별

각 구성 요소에는 별도의 필터 마스크가 있습니다. 이렇게 하면 디버거가 각 구성 요소에 대한 필터를 개별적으로 구성할 수 있습니다.

각 구성 요소는 컨텍스트에 따라 다른 방식으로 참조됩니다. DbgPrintExComponentId 매개 변수에서 구성 요소 이름 앞에 "DPFLTR_"이 접두사로 붙고 접미사가 "_ID"로 접미사로 지정됩니다. 레지스트리에서 구성 요소 필터 마스크의 이름은 구성 요소 자체와 동일합니다. 디버거에서 구성 요소 필터 마스크의 접두사는 "Kd_"이고 접미사는 "_Mask"입니다.

Microsoft WDK(Windows 드라이버 키트) 헤더 dpfilter.h에는 모든 구성 요소 이름(DPFLTR_XXXX_ID 형식)의 전체 목록이 있습니다. 이러한 구성 요소 이름의 대부분은 Windows 및 Microsoft에서 작성한 드라이버용으로 예약되어 있습니다.

독립 하드웨어 공급업체를 위해 예약된 6개의 구성 요소 이름이 있습니다. 드라이버의 출력을 Windows 구성 요소의 출력과 혼합하지 않도록 하려면 다음 구성 요소 이름 중 하나를 사용해야 합니다.

구성 요소 이름 드라이버 유형
IHVVIDEO 비디오 드라이버
IHVAUDIO 오디오 드라이버
IHVNETWORK 네트워크 드라이버
IHVSTREAMING 커널 스트리밍 드라이버
IHVBUS 버스 드라이버
IHV드라이버 다른 유형의 드라이버

예를 들어 비디오 드라이버를 작성하는 경우 DPFLTR_IHVVIDEO_ID DbgPrintExComponentId 매개 변수로 사용하고, 레지스트리에서 값 이름 IHVVIDEO를 사용하고, 디버거에서 Kd_IHVVIDEO_Mask 참조합니다.

DbgPrintKdPrint에서 보낸 모든 메시지는 DEFAULT 구성 요소와 연결됩니다.

올바른 수준 선택

DbgPrintEx 루틴의 Level 매개 변수는 DWORD 형식입니다. 중요도 비트 필드를 확인하는 데 사용됩니다. Level 매개 변수와 이 비트 필드 간의 연결은 Level의 크기에 따라 달라집니다.

  • Level이 0에서 31 사이의 숫자(포함)와 같으면 비트 시프트로 해석됩니다. 중요도 비트 필드는 값 1 <<수준으로 설정됩니다. 따라서 수준에 대해 0에서 31 사이의 값을 선택하면 정확히 하나의 비트 집합이 있는 비트 필드가 생성됩니다. Level이 0이면 비트 필드가 0x00000001; 수준이 31이면 비트 필드가 0x80000000 같습니다.

  • Level이 32에서 0xFFFFFFFF 사이의 숫자인 경우 중요도 비트 필드는 수준 자체의 값으로 설정됩니다.

따라서 비트 필드를 0x00004000 설정하려는 경우 수준을 0x00004000 또는 단순히 14로 지정할 수 있습니다. 이 시스템에서는 완전히 0인 비트 필드를 포함하여 특정 비트 필드 값을 사용할 수 없습니다.

다음 상수는 수준 값을 설정하는 데 유용할 수 있습니다. Microsoft WDK(Windows 드라이버 키트) 헤더 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 값을 비트 OR 연산하여 사용할 수 있습니다. 이렇게 하면 실수로 32보다 작은 값을 사용하지 않도록 보장됩니다.

드라이버가 Windows에서 메시지 수준을 사용하는 방식과 호환되도록 하려면 심각한 오류가 발생하는 경우에만 중요도 비트 필드의 가장 낮은 비트(0x1)만 설정해야 합니다. 수준 값이 32보다 작은 경우 DPFLTR_ERROR_LEVEL 해당합니다. 이 비트를 설정하면 드라이버가 실행 중인 컴퓨터에 커널 디버거를 연결할 때마다 메시지가 표시됩니다.

경고, 추적 및 정보 수준은 적절한 상황에서 사용해야 합니다. 다른 비트는 유용한 용도로 자유롭게 사용할 수 있습니다. 이렇게 하면 선택적으로 보거나 숨길 수 있는 다양한 메시지 유형을 가질 수 있습니다.

DbgPrintKdPrint에서 보낸 모든 메시지는 DPFLTR_INFO_LEVEL 수준이 같은 DbgPrintExKdPrintEx 메시지처럼 동작합니다. 즉, 이러한 메시지에는 중요도 비트 필드 집합의 세 번째 비트가 있습니다.

구성 요소 필터 마스크 설정

구성 요소 필터 마스크를 설정하는 방법에는 두 가지가 있습니다.

  • 구성 요소 필터 마스크는 레지스트리 키 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Debug Print Filter액세스할 수 있습니다. 레지스트리 편집기를 사용하여 이 키를 만들거나 엽니다. 이 키 아래에 원하는 구성 요소의 이름을 대문자로 사용하여 값을 만듭니다. 구성 요소 필터 마스크로 사용하려는 DWORD 값과 동일하게 설정합니다.

  • 커널 디버거가 활성화된 경우, 원하는 구성 요소 이름인 XXXX가 포함된 기호 Kd_XXXX_Mask에 저장된 주소를 역참조하여 구성 요소 필터 마스크 값에 액세스할 수 있습니다. dd(DWORD 표시) 명령을 사용하여 WinDbg 또는 KD에서 이 마스크의 값을 표시하거나 ed(DWORD 입력) 명령을 사용하여 새 구성 요소 필터 마스크를 입력할 수 있습니다. 기호에 모호성이 발생할 위험이 있는 경우, 이 기호를 nt!Kd_XXXX_Mask로 지정할 수 있습니다.

레지스트리에 저장된 필터 마스크는 부팅 중에 적용됩니다. 디버거에서 만든 필터 마스크는 즉시 적용되며 Windows가 다시 부팅될 때까지 유지됩니다. 레지스트리의 값 집합은 디버거에 의해 재정의될 수 있지만 시스템이 다시 부팅되면 구성 요소 필터 마스크가 레지스트리에 지정된 값으로 돌아갑니다.

WIN2000 시스템 전체 마스크도 있습니다. 이는 다른 모든 구성 요소와 마찬가지로 레지스트리 또는 디버거를 통해 변경할 수 있지만 기본적으로 0x1 동일합니다. 필터링이 수행되면 각 구성 요소 필터 마스크는 먼저 WIN2000 마스크를 사용하여 ORed됩니다. 특히 마스크가 한 번도 지정되지 않은 구성 요소는 기본값으로 0x1이 할당됩니다.

메시지를 표시하기 위한 조건

DbgPrintEx가 커널 모드 코드에서 호출되면 Windows는 Level에 지정된 메시지 중요도 비트 필드를 ComponentId에 지정된 구성 요소의 필터 마스크와 비교합니다.

비고

Level 매개 변수가 0에서 31 사이인 경우 중요도 비트필드는 1 <<수준과 같습니다. 그러나 Level 매개 변수가 32 이상인 경우 중요도 비트필드는 단순히 Level과 같습니다.

Windows는 중요도 비트 필드 및 구성 요소 필터 마스크에 대해 AND 작업을 수행합니다. 결과가 0이 아니면 메시지가 디버거로 전송됩니다.

디버그 필터 예제

마지막 부팅 전에 디버그 인쇄 필터 키에 다음 값을 만들었다고 가정합니다.

  • 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와 동일함)와 자동으로 ORed되기 때문에 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. 그런 다음 이 값은 0x9 유효 IHVVIDEO 구성 요소 필터 마스크로 ANDed되어 0이 아닌 결과를 제공합니다. 따라서 첫 번째 메시지가 디버거로 전송됩니다.

두 번째 메시지에는 Level 매개 변수가 7과 같습니다. 다시 말하지만, 이는 비트 시프트로 처리되므로 중요도 비트 필드가 0x80. 그런 다음, IHVAUDIO 구성 요소 필터 마스크 0x7과 함께 AND 연산을 수행하여 결과가 0이 됩니다. 따라서 두 번째 메시지는 전송되지 않습니다.

세 번째 메시지에는 Level 매개 변수가 DPFLTR_MASK | 0x10입니다. 이 값이 31보다 크므로 중요도 비트 필드는 수준 값과 같게 설정됩니다. 즉, 0x80000010. 그런 다음 IHVBUS 구성 요소 필터 마스크에 0x7FF을 AND 연산하여 0이 아닌 결과를 얻습니다. 따라서 세 번째 메시지가 디버거로 전송됩니다.

네 번째 메시지는 DbgPrintEx 대신 DbgPrint에 전달되었습니다. Windows Server 2003 및 이전 버전의 Windows에서는 이 루틴에 전달된 메시지가 항상 전송됩니다. Windows Vista 이상 버전의 Windows에서는 이 루틴에 전달된 메시지에 항상 기본 필터가 제공됩니다. 중요도 비트 필드는 1 << DPFLTR_INFO_LEVEL와 같으며, 이는 0x00000008입니다. 이 루틴의 구성 요소는 DEFAULT입니다. DEFAULT 구성 요소 필터 마스크를 설정하지 않았으므로 값이 0x1. 중요도 비트 필드에 AND 연산이 수행되면 결과는 0이 됩니다. 따라서 네 번째 메시지는 전송되지 않습니다.

DbgPrint 버퍼 및 디버거

DbgPrint, DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix, KdPrint 또는 KdPrintEx 루틴이 메시지를 디버거로 전송하면 서식이 지정된 문자열이 DbgPrint 버퍼로 전송됩니다. GFlags의 버퍼 DbgPrint 출력 옵션을 사용하여 이 표시를 사용하지 않도록 설정하지 않은 경우 이 버퍼의 내용은 디버거 명령 창에 즉시 표시됩니다.

로컬 커널 디버깅 중에 이 표시를 사용하지 않도록 설정한 경우 DbgPrint 버퍼의 내용은 !dbgprint 확장 명령을 사용해야만 볼 수 있습니다.

DbgPrint, DbgPrintEx, vDbgPrintEx, vDbgPrintExWithPrefix, KdPrint 또는 KdPrintEx 대한 단일 호출은 512바이트의 정보만 전송합니다. 512바이트보다 긴 출력은 손실됩니다. DbgPrint 버퍼 자체는 Windows의 무료 빌드에 최대 4KB의 데이터를 저장할 수 있으며 확인된 Windows 빌드에서는 최대 32KB의 데이터를 보유할 수 있습니다. Windows Server 2003 이상 버전의 Windows에서 KDbgCtrl 도구를 사용하여 DbgPrint 버퍼의 크기를 변경할 수 있습니다. 이 도구는 Windows용 디버깅 도구의 일부입니다.

비고

확인된 빌드는 Windows 10 버전 1803 이전 버전의 Windows에서 사용할 수 있었습니다. 드라이버 검증 도구 및 GFlags와 같은 도구를 사용하여 이후 버전의 Windows에서 드라이버 코드를 확인합니다.

ComponentIdLevel 값으로 인해 메시지가 필터링되면 디버깅 연결을 통해 전송되지 않습니다. 따라서 디버거에 이 메시지를 표시할 방법이 없습니다.