다음을 통해 공유


KD(커널 디버거)를 사용하여 디바이스 설치 디버깅

Windows Vista부터 PnP(플러그 앤 플레이) 관리자가 시스템에서 새 디바이스를 감지하면 운영 체제에서 디바이스 설치 호스트 프로세스(DrvInst.exe)를 시작하여 디바이스에 대한 드라이버를 검색하고 설치합니다.

디바이스 설치는 이 사용자 모드 프로세스 내에서 발생하므로 일반적으로 사용자 모드 디버거를 사용하여 디바이스 설치 디버깅에 설명된 대로 사용자 모드 디버거를 사용하는 것이 가장 쉽습니다. 그러나 경우에 따라 KD(커널 디버거)를 사용하여 사용자 모드 디바이스 설치 프로세스를 모니터링하는 것이 유용할 수 있습니다.

예를 들어 사용자 모드 디바이스 설치를 디버깅하는 동안 KD를 사용하여 다음을 수행할 수 있습니다.

  • !devnode, !devobj, !drvobj, !irp 및 기타 KD 확장을 사용하여 커널 모드 문제를 동시에 디버그합니다.

  • KD 확장 !process 또는 .process /p를 사용하여 여러 디버거를 관리하지 않고 다른 사용자 모드 프로세스를 모니터링합니다.

KD 및 기타 디버깅 도구에 대한 자세한 내용은 Windows 디버깅을 참조하세요.

DebugInstall 레지스트리 값은 시스템에서 사용하도록 설정된 디바이스 설치 디버깅 지원 유형을 지정합니다. 이 레지스트리 값에 대한 자세한 내용은 디바이스 설치 디버깅 지원 설정을 참조하세요.

DebugInstall 레지스트리 값이 1로 설정되면 DrvInst.exe 먼저 커널 디버거가 활성화되어 있고 디버거에 침입하기 전에 현재 연결되어 있는지 확인합니다. 이 중단이 수행되면 현재 프로세스의 사용자 모드 모듈에서 중단점을 설정할 수 있습니다. 다음은 그 예입니다.

kd> .reload /user
kd> bp /p @$proc setupapi!SetupDiCallClassInstaller

프로세스 SETUPAPI!SetupDiCallClassInstaller 루틴에 대해 현재 프로세스에서만 중단점을 설정합니다.

드라이버 패키지 개발자의 경우 일반적으로 디바이스를 설치하는 동안 클래스 설치 관리자 또는 공동 설치 관리자 DLL의 작업을 디버그하는 것이 가장 좋습니다. 그러나 DrvInst.exe 디버거에 침입하는 경우 드라이버 패키지의 클래스 설치 관리자 또는 공동 설치 관리자 DLL이 로드되지 않습니다. 사용자 모드 디버거는 "sx e ld" 명령을 사용하여 사용자 모드 모듈이 프로세스에 로드될 때 디버거 예외를 설정하는 기능을 지원하지만 커널 디버거는 해당 명령을 사용하는 커널 모드 모듈만 지원합니다.

다음 코드 예제에서는 "디버거 명령 프로그램" 현재 프로세스에 특정 클래스 설치 관리자 또는 공동 설치 관리자의 로드를 모니터링 하는 방법을 보여 줍니다. 이 예제에서 디버거 명령 프로그램은 Mycoinst.dll 공동 설치 관리자의 주 진입점(CoInstallerProc)에 중단점을 설정합니다.

file: Z:\bpcoinst.txt

r $t1 = 0
!for_each_module .if ($spat("@#ModuleName", "mycoinst*") = 0) {r $t1 = 1}
.if (not @$t1 = 0) {.echo mycoinst is loaded, set bp on mycoinst!CoInstallerProc } .else {.echo mycoinst not loaded}
.if (not @$t1 = 0) {.reload mycoinst.dll}
.if (not @$t1 = 0) {bp[0x20] /p @$proc mycoinst!CoInstallerProc } .else {bc[0x20]}

디버거 명령 프로그램이 실행되면, 현재 프로세스에 로드된 모듈 목록을 확인하여 Mycoinst.dll을(를) 찾습니다. 이 공동 설치 관리자 DLL이 로드되면 디버거는 CoInstallerProc 진입점 함수에서 중단점(잘 알려진 중단점 ID 포함)을 설정합니다.

DrvInst.exe 호스트 프로세스에서 시작된 디버그 중단에서 먼저 DrvInst.exe이 커널 디버거로 넘어간 호출의 반환 주소에 중단점을 설정해야 합니다. 이 중단점은 디바이스 설치 중에 설정된 모든 중단점을 지우고 실행을 계속합니다.

DRVINST.EXE: Entering debugger during PnP device installation.
Device instance = "X\Y\Z" ...

Break instruction exception - code 80000003 (first chance)
010117b7 cc               int     3

kd> bp[0x13] /p @$proc @$ra "bc *;g"

다음으로, 디바이스를 설치하는 동안 디버거 명령 프로그램의 명령이 적절한 시간에 실행되도록 프로세스 내에서 몇 가지 중단점을 설정해야 합니다.

디바이스 설치를 위해 함수를 호출하기 전에 클래스 설치 관리자 또는 공동 설치 관리자 DLL 진입점에 대한 중단점이 설정되었는지 확인하려면 새 DLL이 현재 프로세스에 로드될 때마다 디버거 명령 프로그램을 실행해야 합니다. 즉, LoadLibraryExW를 호출한 후 반환됩니다.

kd> .reload
kd> bp[0x10] /p @$proc kernel32!LoadLibraryExW "gu;$$><Z:\\bpcoinst.txt;g"

프로세스 내의 모든 LoadLibraryEx 호출(bp[0x10])에서 프로그램을 실행하는 대신, 개발자는 클래스 설치 관리자 및 공동 설치 관리자 DLL이 프로세스에 로드될 때만 실행하도록 제한할 수 있습니다. SetupDiCallClassInstaller는 디바이스에 등록된 클래스 설치 관리자 및 공동 설치 관리자를 호출하는 루틴이므로 이러한 DLL은 해당 호출 중에 프로세스에 로드됩니다.

이러한 DLL이DrvInst.exe호스트 프로세스에서 언로드되는 시기에 대해 가정해서는 안 되므로 중단점이 DrvInst.exe 호스트 프로세스에서 SetupDiCallClassInstaller를 호출하는 동안 DLL 진입점 찾기를 처리할 수 있는지 확인해야 합니다.

kd> bd[0x10]
kd> bp[0x11] /p @$proc setupapi!SetupDiCallClassInstaller "be[0x10];bp[0x12] /p @$proc @$ra \"bd[0x10];bc[0x12];g\";g"
kd> g

디버거 명령 프로그램(bp[0x10])을 실행하는 중단점은 처음에 사용하지 않도록 설정됩니다. SetupDiCallClassInstaller가 호출되고(bp[0x11]) 실행이 계속될 때마다 사용하도록 설정됩니다. SetupDiCallClassInstaller가 해당 루틴 자체의 반환 주소(bp[0x12])에 중단점을 설정하여 반환할 때 디버거 명령 프로그램(bp[0x10])이 다시 비활성화됩니다.

디버거 명령 프로그램을 사용하지 않도록 설정하는 중단점도 자체 지우고 SetupDiCallClassInstaller 가 다시 호출되거나 설치 프로그램이 완료되고 모든 중단점이 지워질 때까지(bp[0x13]) 실행을 계속합니다.

위의 중단점이 설정된 후 실행이 시작되면 mycoinst에 대한 각 호출에서 프로세스가 중단됩니다. CoInstallerProc. 이렇게 하면 핵심 디바이스 설치 중에 클래스 설치 관리자 또는 공동 설치 관리자 DLL의 실행을 디버그할 수 있습니다.

설치 프로세스가 완료되는 기본 기간은 5분입니다. 지정된 기간 내에 프로세스가 완료되지 않으면 시스템은 프로세스가 응답을 중지하고 종료되었다고 가정합니다.

커널 디버거를 통해 프로세스를 디버그하는 동안 디바이스 설치에 적용되는 기본 시간 제한은 계속 적용됩니다. 디버거로 분할되는 동안 시스템의 모든 프로그램 실행이 중지되므로 설치 프로세스에서 소요된 시간은 디버그되지 않는 시스템에 있는 것과 동일하게 추적됩니다.