다음을 통해 공유


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

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와 동일한 구문을 사용하여 형식인수 매개 변수에 전달됩니다.

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

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

참고

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

구성 요소 이름 식별

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

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

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

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

구성 요소 이름 드라이버 유형
IHVVIDEO 동영상 드라이버
IHVAUDIO 오디오 드라이버
IHVNETWORK 네트워크 드라이버
IHVSTREAMING 커널 스트리밍 드라이버
IHVBUS 버스 운전사
IHVDRIVER 다른 유형의 드라이버

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

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

올바른 수준 선택

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

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

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

따라서 비트 필드를 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 값과 동일하게 설정합니다.

  • 커널 디버거가 활성 상태인 경우 기호 Kd_XXXX_Mask에 저장된 주소를 역참조하여 구성 요소 필터 마스크 값에 액세스할 수 있습니다. 여기서 XXXX는 원하는 구성 요소 이름입니다. 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이 아닌 경우 메시지가 디버거로 전송됩니다.

디버그 필터 예제

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

  • 값이 DWORD와 같은 IHVVIDEO 0x2

  • DWORD와 동일한 IHVBUS 0x7FF

이제 커널 디버거에서 다음 명령을 실행합니다.

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

이 시점에서 IHVVIDEO 구성 요소에는 0x8 필터 마스크가 있고, IHVAUDIO 구성 요소에는 0x7 필터 마스크가 있고, IHVBUS 구성 요소에는 0x7FF 필터 마스크가 있습니다.

그러나 이러한 마스크는 WIN2000 시스템 전체 마스크(일반적으로 0x1 동일)로 자동으로 ORed되므로 IHVVIDEO 마스크는 사실상 0x9 같습니다. 실제로 필터 마스크가 전혀 설정되지 않은 구성 요소(instance, 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. 그런 다음, 0x7 IHVAUDIO 구성 요소 필터 마스크를 사용하여 ANDed가 생성되어 결과가 0이 됩니다. 따라서 두 번째 메시지는 전송되지 않습니다.

세 번째 메시지에는 level 매개 변수가 DPFLTR_MASK | 0x10. 이 값이 31보다 크므로 중요도 비트 필드는 수준 값(즉, 0x80000010)과 동일하게 설정됩니다. 그런 다음, 0x7FF IHVBUS 구성 요소 필터 마스크를 사용하여 ANDed를 사용하여 0이 아닌 결과를 제공합니다. 따라서 세 번째 메시지가 디버거로 전송됩니다.

네 번째 메시지는 DbgPrintEx 대신 DbgPrint에 전달되었습니다. Windows Server 2003 및 이전 버전의 Windows에서는 이 루틴에 전달된 메시지가 항상 전송됩니다. Windows Vista 이상 버전의 Windows에서는 이 루틴에 전달된 메시지에 항상 기본 필터가 제공됩니다. 중요도 비트 필드는 0x00000008 DPFLTR_INFO_LEVEL 1 << 과 같습니다. 이 루틴의 구성 요소는 DEFAULT입니다. DEFAULT 구성 요소 필터 마스크를 설정하지 않았으므로 값이 0x1. 중요도 비트 필드가 있는 ANDed이면 결과는 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 값으로 인해 메시지가 필터링되면 디버깅 연결을 통해 전송되지 않습니다. 따라서 디버거에서 이 메시지를 표시할 수 있는 방법은 없습니다.