참고 이 기능을 사용하도록 설정하는 지침은 Windows 8용 WDK에만 적용됩니다. Windows 8.1의 경우 이 기능은 드라이버 검증 도구에 통합되었습니다. Windows 8.1을 실행하는 컴퓨터에서 체계적인 낮은 리소스 시뮬레이션 옵션을 사용합니다.
스택 기반 오류 주입 옵션은 커널 모드 드라이버에서 리소스 오류를 삽입합니다. 이 옵션은 특수 드라이버 KmAutoFail.sys을(를) 드라이버 검증 도구와 함께 사용하여 드라이버 오류 처리 경로를 철저히 검증합니다. 이러한 경로를 테스트하는 것은 역사적으로 매우 어려웠습니다. 스택 기반 오류 주입 옵션은 리소스 오류를 예측 가능한 방식으로 주입하여 검색된 문제를 재현할 수 있게 합니다. 오류 경로는 쉽게 재현할 수 있으므로 이러한 문제에 대한 수정 사항을 쉽게 확인할 수 있습니다.
오류의 근본 원인을 확인할 수 있도록 삽입된 오류와 순서를 정확하게 알 수 있는 디버거 확장이 제공됩니다.
특정 드라이버에서 스택 기반 오류 주입 옵션을 사용하도록 설정하면 해당 드라이버에서 커널로의 일부 호출을 가로채고 Ndis.sys과 관련된 작업을 수행합니다. 스택 기반 오류 주입은 호출 스택을 살펴보는데, 특히 드라이버에서 활성화된 부분의 호출 스택을 중점적으로 봅니다. 이 스택을 처음 본 경우 해당 호출의 의미 체계에 따라 호출이 실패합니다. 그렇지 않으면 이전에 그 호출을 본 적이 있다면 변경 없이 전달됩니다. 스택 기반 오류 주입에는 드라이버를 여러 번 로드하고 언로드할 수 있다는 사실을 처리하는 논리가 포함되어 있습니다. 드라이버가 다른 메모리 위치로 다시 로드되더라도 호출 스택이 동일하다는 것을 인식합니다.
이 옵션 활성화
드라이버를 테스트 컴퓨터에 배포할때 하나 이상의 드라이버에 대해 스택 기반 오류 주입 기능을 활성화할 수 있습니다. 드라이버 패키지 프로젝트 에 대한드라이버 검증 도구 속성을 구성할 때, 스택 기반 오류 주입 옵션을 선택할 수 있습니다. 스택 기반 오류 주입 옵션을 활성화하거나 비활성화하려면 컴퓨터를 다시 시작해야 합니다. 테스트 유틸리티를 실행하여 테스트 컴퓨터에서 드라이버 검증 도구와 이 기능을 사용하도록 설정할 수도 있습니다.
중요 테스트 컴퓨터에서 스택 기반 오류 주입을 활성화할 때, "낮은 리소스 시뮬레이션"을(를) 선택하지 않도록 주의하세요.
드라이버 검증기 속성 페이지 사용
- 드라이버 패키지의 속성 페이지를 엽니다. 솔루션 탐색기 드라이버 패키지 프로젝트를 마우스 오른쪽 단추로 클릭하고 속성선택합니다.
- 드라이버 패키지의 속성 페이지에서 구성 속성클릭하고 드라이버 설치 클릭한 다음 드라이버 검증 도구클릭합니다.
- 드라이버 검증 도구 사용하도록선택합니다. 테스트 컴퓨터에서 드라이버 검증 도구를 사용하도록 설정하면 컴퓨터의 모든 드라이버, 드라이버 프로젝트 전용 또는 지정된 드라이버 목록에 대해 드라이버 검증 도구를 사용하도록 선택할 수 있습니다.
- 스택 기반 오류 인젝터에서 스택 기반 오류 주입을 선택(확인)합니다.
- 클릭하거나 적용 확인.
- 자세한 내용은 드라이버를 테스트 컴퓨터에 배포하기를 참조하세요. 이 옵션을 활성화하려면 테스트 컴퓨터를 다시 시작해야 합니다.
드라이버 검증기 활성화 및 비활성화 테스트
유틸리티 테스트를 실행하여 드라이버 검증 도구를 사용하도록 설정할 수도 있습니다. Visual Studio사용하여 런타임에 드라이버를 테스트하는 방법에 설명된 지침을 따릅니다. 모든 테스트\드라이버 검증 도구 테스트 범주에서 드라이버 검증 도구 사용(재부팅 필요 가능) 및 드라이버 검증 도구 사용 안 함(재부팅 필요 가능) 테스트를 선택합니다.
드라이버 테스트 그룹 창에서 드라이버 검증 도구 사용(가능한 재부팅 필요) 테스트의 이름을 클릭하여 드라이버 검증 도구 옵션을 선택합니다.
스택 기반 오류 주입을 선택(확인)합니다.
이러한 테스트를 테스트 그룹에 추가한 후에는 테스트 그룹을 저장할 수 있습니다. 스택 기반 오류 주입을 사용하도록 설정하려면 테스트용으로 구성한 컴퓨터에서 드라이버 검증 도구 사용(가능한 재부팅 필요) 테스트를 실행합니다.
드라이버 검증 도구를 비활성화하려면 드라이버 검증 도구 사용 안 함(가능한 재부팅 필요) 테스트를 실행합니다.
스택 기반 오류 주입 옵션을 사용하기
스택 기반 오류 주입을 사용하여 테스트할 때 중요한 고려 사항 중 하나는 발견한 대부분의 버그로 인해 버그 검사가 발생한다는 것입니다. 이는 드라이버가 부팅 로드 드라이버인 경우 다소 고통스러울 수 있습니다. 이 때문에 드라이버 검증 도구가 비활성화된 경우 스택 기반 오류 주입을 자동으로 사용하지 않도록 설정합니다. 즉, !verifier -disable 명령을 사용하여 드라이버 검증 도구를 사용하지 않도록 설정하여 부팅 시 디버거에서 스택 기반 오류 주입을 사용하지 않도록 설정할 수 있습니다.
가능한 경우 스택 기반 오류 주입을 사용한 초기 테스트의 경우 부팅 시 로드되지 않도록 드라이버를 설정합니다. 그런 다음 몇 가지 간단한 부하 및 언로드 테스트를 실행할 수 있습니다. 스택 기반 오류 주입에서 발견된 많은 버그가 초기화 또는 정리 중에 발생합니다. 드라이버를 반복적으로 로드하고 언로드하는 것은 이러한 항목을 찾는 좋은 방법입니다.
부하 언로드 테스트를 성공하는 데 필요한 수정을 수행한 후 IOCTL 기반 테스트, 전체 기능 테스트 및 마지막으로 스트레스 테스트로 이동할 수 있습니다. 일반적으로 이 테스트 진행을 따르는 경우 대부분의 코드 경로가 이 이전에 이미 실행되었으므로 스트레스 테스트 중에 많은 새로운 문제가 발견되지 않습니다.
SBFI(스택 기반 오류 주입) 디버거 확장 사용
스택 기반 오류 주입과 관련된 대부분의 문제는 버그 검사를 초래합니다. 이러한 코드 버그의 원인을 확인하기 위해 WDK는 스택 기반 오류 주입 디버거 확장 및 필요한 기호를 제공합니다. 설치 절차는 디버거 시스템에 둘 다 설치됩니다. 기본 위치는 C:\Program Files (x86)\Windows Kits\8.0\Debuggers\<arch>.
디버거 확장 실행하려면
디버거 명령 프롬프트에서 다음 명령을 입력합니다: !<경로>\kmautofaildbg.dll.autofail. 예를 들어 디버거 확장이 c:\dbgext에 설치되고 kmautofail.pdb가 기호 경로에 있다고 가정하면 다음 명령을 입력합니다.
!c:\dbgext\kmautofaildbg.dll.autofail
이렇게 하면 삽입된 가장 최근 오류의 호출 스택을 보여 주는 정보가 디버거에 덤프됩니다. 각 항목은 실제 테스트 실행에서 가져온 다음과 같습니다. 다음 예제에서는 Mydriver.sys에 스택 기반 실패 주입을 활성화합니다.
Sequence: 2, Test Number: 0, Process ID: 0, Thread ID: 0
IRQ Level: 2, HASH: 0xea98a56083aae93c
0xfffff8800129ed83 kmautofail!ShimHookExAllocatePoolWithTag+0x37
0xfffff88003c77566 mydriver!AddDestination+0x66
0xfffff88003c5eeb2 mydriver!ProcessPacketDestination+0x82
0xfffff88003c7db82 mydriver!ProcessPacketSource+0x8b2
0xfffff88003c5d0d8 mydriver!ForwardPackets+0xb8
0xfffff88003c81102 mydriver!RoutePackets+0x142
0xfffff88003c83826 mydriver!RouteNetBufferLists+0x306
0xfffff88003c59a76 mydriver!DeviceSendPackets+0x156
0xfffff88003c59754 mydriver!ProcessingComplete+0x4a4
0xfffff88001b69b81 systemdriver2!ProcessEvent+0x1a1
0xfffff88001b3edc4 systemdriver1!CallChildDriver+0x20
0xfffff88001b3fc0a systemdriver1!ProcessEvent+0x3e
0xfffff800c3ea6eb9 nt!KiRetireDpcList+0x209
0xfffff800c3ea869a nt!KiIdleLoop+0x5a
출력 맨 위에 있는 시퀀스 번호는 삽입되는 오류 수를 계산합니다. 이 예제에서는 이 테스트 실행 중에 삽입된 두 번째 오류를 보여줍니다. 프로세스 ID는 0이므로 시스템 프로세스였습니다. IRQL은 2이므로 디스패치 수준에서 호출됩니다.
스택에서 KmAutoFail은 스택 기반 오류 주입 드라이버로 작동합니다. KmAutoFail 함수 이름은 Mydriver.sys에서 가로채고 오류가 주입된 함수 호출을 나타냅니다. 여기서 실패한 함수는 ExAllocatePoolWithTag. KmAutoFail의 모든 함수는 Ntoskrnl.sys 또는 Ndis.sys 호출을 가로채며, 이 명명 규칙을 사용합니다. 다음으로 테스트 중인 드라이버(Mydriver.sys)를 사용하여 호출 스택을 확인합니다. 스택의 고유성을 확인하는 데 사용되는 호출 스택의 부분입니다. 따라서 디버거 확장에 의해 덤프된 각 항목은 호출 스택의 이 부분에서 고유합니다. 호출 스택의 나머지 부분에는 드라이버를 호출한 사람이 표시됩니다. 가장 중요한 점은 드라이버가 사용자 모드(IOCTL을 통해)에서 호출되는지 또는 커널 모드 드라이버에서 호출되는지 여부입니다.
드라이버가 DriverEntry 루틴에서 오류를 반환한 경우 일반적으로 다른 메모리 위치에서 다시 로드 시도가 수행됩니다. 이 경우 이전 위치의 호출 스택에는 드라이버의 스택 정보가 아닌 "가비지"가 포함될 수 있습니다. 그러나 이것은 문제가 되지 않습니다. 드라이버가 오류를 삽입한 것을 올바르게 처리했음을 알려줍니다.
다음 항목은 사용자 모드에서 IOCTL을 통해 드라이버에 대한 호출을 보여줍니다. 프로세스 ID 및 IRQ 수준을 확인합니다. Mydriver.sys는 NDIS 필터 드라이버이므로 IOCTL은 Ndis.sys을 통해 전달되었습니다. 참고로 nt! NtDeviceIoControlFile이 스택에 있습니다. IOCTL을 사용하는 드라이버에서 실행하는 모든 테스트는 이 함수를 통과합니다.
Sequence: 5, Test Number: 0, Process ID: 2052, Thread ID: 4588
IRQ Level: 0, HASH: 0xecd4650e9c25ee4
0xfffff8800129ed83 kmautofail!ShimHookExAllocatePoolWithTag+0x37
0xfffff88003c6fb39 mydriver!SendMultipleOids+0x41
0xfffff88003c7157b mydriver!PvtDisconnect+0x437
0xfffff88003c71069 mydriver!NicDisconnect+0xd9
0xfffff88003ca3538 mydriver!NicControl+0x10c
0xfffff88003c99625 mydriver!DeviceControl+0x4c5
0xfffff88001559d93 NDIS!ndisDummyIrpHandler+0x73
0xfffff88001559339 NDIS!ndisDeviceControlIrpHandler+0xc9
0xfffff800c445cc96 nt!IovCallDriver+0x3e6
0xfffff800c42735ae nt!IopXxxControlFile+0x7cc
0xfffff800c4274836 nt!NtDeviceIoControlFile+0x56
0xfffff800c3e74753 nt!KiSystemServiceCopyEnd+0x13
스택 기반 오류 주입의 결과 분석
드라이버에서 테스트를 실행 중에 갑자기 문제가 생겼습니다. 대부분의 경우 이것은 버그 검사였지만 컴퓨터가 응답하지 않아서 발생할 수도 있습니다. 원인을 찾으려면 어떻게 해야 할까요? 버그 검사라고 가정하고 먼저 위의 확장을 사용하여 삽입된 오류 목록을 찾은 다음 디버거 명령을 사용합니다. !analyze –v.
가장 일반적인 버그 검사는 할당의 성공을 확인하지 않아서 발생합니다. 이 경우 버그 검사 분석의 스택은 주입된 마지막 오류와 거의 동일합니다. 할당이 실패한 후(종종 바로 다음 줄) 드라이버가 null 포인터에 액세스합니다. 이 유형의 버그를 수정하기가 매우 쉽습니다. 경우에 따라 실패한 할당이 목록에서 하나 또는 두 개이지만 이 형식은 여전히 찾기 쉽고 수정할 수 있습니다.
두 번째로 일반적인 버그 검사는 정리 중에 발생합니다. 이 경우 드라이버는 할당 오류를 감지하고 정리로 뛰어올랐을 것입니다. 그러나 정리하는 동안 드라이버가 포인터를 확인하지 않고 다시 한 번 null 포인터에 액세스했습니다. 관련된 사례는 정리 작업을 두 번 호출할 수 있는 경우입니다. 정리에서 구조체에 대한 포인터를 해제한 후 null로 설정하지 않으면 정리 함수가 호출될 때 두 번째로 구조체를 해제하여 버그 검사를 수행합니다.
컴퓨터가 응답하지 않는 오류는 진단하기가 더 어렵지만 디버깅 절차는 비슷합니다. 이러한 오류는 참조 수 또는 스핀 잠금 문제로 인해 발생하는 경우가 많습니다. 다행히, 드라이버 검증 도구는 문제가 발생하기 전에 많은 스핀 잠금 문제를 발견합니다. 이러한 경우 디버거에 침입하고 디버거 확장을 사용하여 스택 기반 오류 주입에 의해 주입된 오류 목록을 덤프합니다. 최신 오류와 관련한 코드를 간단히 살펴보면 오류 전에 수행되었지만 이후 릴리스되지 않은 참조 수가 표시될 수 있습니다. 그렇지 않은 경우, 드라이버에서 스핀 잠금을 기다리는 스레드나 분명히 잘못된 참조 수를 찾으십시오.