디버그 드라이버 - 단계별 랩(Sysvad 커널 모드)

이 랩에서는 Sysvad 오디오 커널 모드 디바이스 드라이버를 디버그하는 방법을 보여 주는 실습 연습을 제공합니다.

WinDbg(Microsoft Windows 디버거)는 사용자 모드 및 커널 모드 디버깅을 수행하는 데 사용할 수 있는 강력한 Windows 기반 디버깅 도구입니다. WinDbg는 Windows 커널, 커널 모드 드라이버 및 시스템 서비스뿐만 아니라 사용자 모드 애플리케이션 및 드라이버에 대한 소스 수준 디버깅을 제공합니다.

WinDbg는 소스 코드를 단계별로 실행하고, 중단점을 설정하고, 변수(C++ 개체 포함), 스택 추적 및 메모리를 볼 수 있습니다. 디버거 명령 창을 사용하면 다양한 명령을 실행할 수 있습니다.

랩 설정

랩을 완료하려면 다음 하드웨어가 필요합니다.

  • Windows 10을 실행하는 랩톱 또는 데스크톱 컴퓨터(호스트)
  • Windows 10을 실행하는 랩톱 또는 데스크톱 컴퓨터(대상)
  • 두 PC를 연결하는 네트워크 허브/라우터 및 네트워크 케이블
  • 기호 파일을 다운로드하기 위한 인터넷 액세스

랩을 완료하려면 다음 소프트웨어가 필요합니다.

  • Microsoft Visual Studio 2017
  • Windows 10용 Windows SDK(소프트웨어 개발 키트)
  • Windows 10용 WDK(Windows 드라이버 키트)
  • Windows 10용 샘플 Sysvad 오디오 드라이버

WDK 다운로드 및 설치에 대한 자세한 내용은 WDK(Windows 드라이버 키트) 다운로드를 참조하세요.

Sysvad 디버깅 연습

이 랩에서는 커널 모드 드라이버를 디버깅하는 프로세스를 안내합니다. 연습에서는 Syvad 가상 오디오 드라이버 샘플을 사용합니다. Syvad 오디오 드라이버는 실제 오디오 하드웨어와 상호 작용하지 않으므로 대부분의 장치에서 사용할 수 있습니다. 랩은 다음 작업을 다룹니다.

Echo 드라이버 랩

Echo 드라이버는 Sysvad 오디오 드라이버보다 간단한 드라이버입니다. WinDbg를 처음 접하는 경우 먼저 디버그 유니버설 드라이버 - 단계별 랩(에코 커널 모드)을 완료하는 것이 좋습니다. 이 랩은 해당 랩의 설정 지침을 다시 사용하므로 해당 랩을 완료한 경우 여기서 섹션 1과 2를 건너뛸 수 있습니다.

섹션 1: 커널 모드 WinDbg 세션에 커넥트

섹션 1에서는 호스트 및 대상 시스템에서 네트워크 디버깅을 구성합니다.

이 랩의 PC는 커널 디버깅에 이더넷 네트워크 연결을 사용하도록 구성해야 합니다.

이 랩에서는 두 대의 컴퓨터를 사용합니다. WinDbg는 호스트 시스템에서 실행되고 Sysvad 드라이버는 대상 시스템에서 실행됩니다.

네트워크 허브/라우터 및 네트워크 케이블을 사용하여 두 PC를 연결합니다.

네트워크 허브/라우터를 통해 연결된 두 대의 PC를 보여 주는 다이어그램

커널 모드 애플리케이션을 사용하고 WinDbg를 사용하려면 이더넷 전송을 통해 KDNET을 사용하는 것이 좋습니다. 이더넷 전송 프로토콜을 사용하는 방법에 대한 자세한 내용은 WinDbg 시작(커널 모드)을 참조하세요. 대상 컴퓨터 설정에 대한 자세한 내용은 수동 드라이버 배포 를 위한 컴퓨터 준비 및 KDNET 네트워크 커널 디버깅 자동 설정을 참조하세요.

이더넷을 사용하여 커널 모드 디버깅 구성

대상 시스템에서 커널 모드 디버깅을 사용하도록 설정하려면 다음 단계를 수행합니다.

<- 호스트 시스템에서

  1. 호스트 시스템에서 명령 프롬프트를 열고 ipconfig /all을 입력하여 IP 주소를 확인합니다.
C:\>ipconfig /all
Windows IP Configuration

 Host Name . . . . . . . . . . . . : TARGETPC
...

Ethernet adapter Ethernet:
   Connection-specific DNS Suffix  . :
   Link-local IPv6 Address . . . . . : fe80::c8b6:db13:d1e8:b13b3
   Autoconfiguration IPv4 Address. . : 169.182.1.1
   Subnet Mask . . . . . . . . . . . : 255.255.0.0
   Default Gateway . . . . . . . . . :
  1. 호스트 시스템의 IP 주소 기록: ______________________________________

  2. 호스트 시스템의 호스트 이름을 기록합니다. ______________________________________

-> 대상 시스템에서

  1. 대상 시스템에서 명령 프롬프트를 열고 ping 명령을 사용하여 두 시스템 간의 네트워크 연결을 확인합니다. 샘플 출력에 표시된 169.182.1.1 대신 기록한 호스트 시스템의 실제 IP 주소를 사용합니다.
C:\> ping 169.182.1.1

Pinging 169.182.1.1 with 32 bytes of data:
Reply from 169.182.1.1: bytes=32 time=1ms TTL=255
Reply from 169.182.1.1: bytes=32 time<1ms TTL=255
Reply from 169.182.1.1: bytes=32 time<1ms TTL=255
Reply from 169.182.1.1: bytes=32 time<1ms TTL=255

Ping statistics for 169.182.1.1:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 0ms, Maximum = 1ms, Average = 0ms

KDNET 유틸리티를 사용하여 대상 시스템에서 커널 모드 디버깅을 사용하도록 설정하려면 다음 단계를 수행합니다.

  1. 호스트 시스템에서 WDK KDNET 디렉터리를 찾습니다. 기본적으로 여기에 있습니다.

    C:\Program Files (x86)\Windows Kits\10\Debuggers\x64

이 랩에서는 두 PC가 모두 대상과 호스트 모두에서 64비트 버전의 Windowson을 실행한다고 가정합니다. 그렇지 않은 경우 가장 좋은 방법은 대상이 실행 중인 호스트에서 동일한 "비트"의 도구를 실행하는 것입니다. 예를 들어 대상이 32비트 Windows를 실행하는 경우 호스트에서 32 버전의 디버거를 실행합니다. 자세한 내용은 32비트 또는 64비트 디버깅 도구 선택을 참조 하세요.

  1. 이러한 두 파일을 찾아 네트워크 공유 또는 썸 드라이브에 복사하여 대상 컴퓨터에서 사용할 수 있도록 합니다.

    kdnet.exe

    VerifiedNICList.xml

  2. 대상 컴퓨터에서 명령 프롬프트 창을 관리istrator로 엽니다. 대상 PC의 NIC가 허용되는지 확인하려면 이 명령을 입력합니다.

C:\KDNET>kdnet

Network debugging is supported on the following NICs:
busparams=0.25.0, Intel(R) 82579LM Gigabit Network Connection, KDNET is running on this NIC.kdnet.exe
  1. 호스트 시스템의 IP 주소를 설정하려면 이 명령을 입력합니다. 샘플 출력에 표시된 169.182.1.1 대신 기록한 호스트 시스템의 실제 IP 주소를 사용합니다. 작업하는 각 대상/호스트 쌍(예: 50010)에 대한 고유한 포트 주소를 선택합니다.
C:\>kdnet 169.182.1.1 50010

Enabling network debugging on Intel(R) 82577LM Gigabit Network Connection.
Key=2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p

Important

BCDEdit를 사용하여 부팅 정보를 변경하기 전에 테스트 PC에서 BitLocker 및 보안 부팅과 같은 Windows 보안 기능을 일시적으로 일시 중단해야 할 수 있습니다. 테스트가 완료되면 이러한 보안 기능을 다시 사용하도록 설정하고 보안 기능이 비활성화된 경우 테스트 PC를 적절하게 관리합니다. 보안 부팅은 일반적으로 UEFI에서 사용하지 않도록 설정됩니다. UEFI 설정에 액세스하려면 시스템, 복구, 고급 시작을 사용합니다. 다시 시작할 때 문제 해결, 고급 옵션, UEFI 펌웨어 설정을 선택합니다. UEFI 옵션을 잘못 설정하거나 BitLocker를 사용하지 않도록 설정하면 시스템이 작동하지 않을 수 있으므로 주의해야 합니다.

  1. dbgsettings가 제대로 설정되는지 확인하려면 이 명령을 입력합니다.
C:\> bcdedit /dbgsettings
busparams               0.25.0
key                     2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
debugtype               NET
hostip                  169.182.1.1
port                    50010
dhcp                    Yes
The operation completed successfully.

자동 생성된 고유 키를 텍스트 파일에 복사하여 호스트 PC에 입력하지 않아도 됩니다. 키와 함께 텍스트 파일을 호스트 시스템에 복사합니다.

방화벽 및 디버거 참고

방화벽에서 팝업 메시지를 수신하고 디버거를 사용하려는 경우 세 상자를 모두 검사.

Windows 방화벽이 앱의 일부 기능을 차단했음을 나타내는 Windows 보안 경고의 스크린샷

<- 호스트 시스템에서

  1. 호스트 컴퓨터에서 명령 프롬프트 창을 관리istrator로 엽니다. WinDbg.exe 디렉터리로 변경합니다. Windows 키트 설치의 일부로 설치된 WDK(Windows 드라이버 키트)의 x64version WinDbg.exe 사용합니다.
C:\> Cd C:\Program Files (x86)\Windows Kits\10\Debuggers\x64 
  1. 다음 명령을 사용하여 원격 사용자 디버그로 WinDbg를 시작합니다. 키 및 포트의 값은 대상에서 BCDEdit를 사용하여 이전에 설정한 값과 일치합니다.
C:\> WinDbg –k net:port=50010,key=2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p

->대상 시스템에서

대상 시스템을 다시 부팅합니다.

<-호스트 시스템에서

1~2분 후에 디버그 출력이 호스트 시스템에 표시되어야 합니다.

라이브 커널 연결의 명령 창 출력을 표시하는 Windows 디버거의 스크린샷.

디버거 명령 창은 WinDbg의 기본 디버깅 정보 창입니다. 디버거 명령을 입력하고 이 창에서 명령 출력을 볼 수 있습니다.

디버거 명령 창은 두 개의 창으로 분할됩니다. 창 아래쪽의 작은 창(명령 항목 창)에 명령을 입력하고 창 위쪽의 더 큰 창에서 명령 출력을 봅니다.

명령 입력 창에서 위쪽 화살표 키와 아래쪽 화살표 키를 사용하여 명령 기록을 스크롤합니다. 명령이 나타나면 명령을 편집하거나 Enter 키를 눌러 명령을 실행할 수 있습니다.

섹션 2: 커널 모드 디버깅 명령 및 기술

섹션 2에서는 디버그 명령을 사용하여 대상 시스템에 대한 정보를 표시합니다.

<- 호스트 시스템에서

.prefer_dml 사용하여 DML(디버거 태그 언어) 사용

일부 디버그 명령은 더 많은 정보를 빠르게 수집하기 위해 선택할 수 있는 디버거 태그 언어를 사용하여 텍스트를 표시합니다.

  1. WinDBg에서 Ctrl+Break(스크롤 잠금)를 사용하여 대상 시스템에서 실행되는 코드를 중단합니다. 대상 시스템이 응답하는 데 약간의 시간이 걸릴 수 있습니다.
  2. 디버거 명령 창에서 DML을 사용하도록 설정하려면 다음 명령을 입력합니다.
0: kd> .prefer_dml 1
DML versions of commands on by default

.hh를 사용하여 도움말 보기

.hh 명령을 사용하여 참조 명령 도움말에 액세스할 수 있습니다.

  1. 다음 명령을 입력하여 .prefer_dml 대한 명령 참조 도움말을 봅니다.
    0: kd> .hh .prefer_dml
    

디버거 도움말 파일은 .prefer_dml 명령에 대한 도움말을 표시합니다.

.prefer-dml 명령에 대한 도움말을 표시하는 디버거 도움말 애플리케이션의 스크린샷

대상 시스템에 Windows 버전 표시

  1. WinDbg 창에 꼭짓점(대상 컴퓨터 버전 표시) 명령을 입력하여 대상 시스템에 대한 자세한 버전 정보를 표시합니다.
0: kd> vertarget
Windows 10 Kernel Version 9926 MP (4 procs) Free x64
Product: WinNt, suite: TerminalServer SingleUserTS
Built by: 9926.0.amd64fre.fbl_awesome1501.150119-1648
Machine Name: ""
Kernel base = 0xfffff801`8d283000 PsLoadedModuleList = 0xfffff801`8d58aef0
Debug session time: Fri Feb 20 10:15:17.807 2015 (UTC - 8:00)
System Uptime: 0 days 01:31:58.931

로드된 모듈 나열

  1. WinDbg 창에 lm(로드된 모듈 나열) 명령을 입력하여 로드된 모듈을 표시하여 올바른 커널 모드 프로세스로 작업하고 있는지 확인할 수 있습니다.
0: Kd> lm
start             end                 module name
fffff801`09200000 fffff801`0925f000   volmgrx    (no symbols)           
fffff801`09261000 fffff801`092de000   mcupdate_GenuineIntel   (no symbols)           
fffff801`092de000 fffff801`092ec000   werkernel   (export symbols)       werkernel.sys
fffff801`092ec000 fffff801`0934d000   CLFS       (export symbols)       CLFS.SYS
fffff801`0934d000 fffff801`0936f000   tm         (export symbols)       tm.sys
fffff801`0936f000 fffff801`09384000   PSHED      (export symbols)       PSHED.dll
fffff801`09384000 fffff801`0938e000   BOOTVID    (export symbols)       BOOTVID.dll
fffff801`0938e000 fffff801`093f7000   spaceport   (no symbols)           
fffff801`09400000 fffff801`094cf000   Wdf01000   (no symbols)           
fffff801`094d9000 fffff801`09561000   CI         (export symbols)       CI.dll
...

생략된 참고 출력은 "... "이 랩에 있습니다.

아직 기호 경로 및 로드된 기호를 설정하지 않았기 때문에 디버거에서 제한된 정보를 사용할 수 있습니다.

섹션 3: Sysvad 오디오 드라이버 다운로드 및 빌드

섹션 3에서는 Sysvad 오디오 드라이버를 다운로드하고 빌드합니다.

일반적으로 WinDbg를 사용할 때 사용자 고유의 드라이버 코드를 사용합니다. 오디오 드라이버 디버깅에 익숙해지기 위해 Sysvad 가상 오디오 샘플 드라이버가 사용됩니다. 이 샘플은 네이티브 커널 모드 코드를 한 단계씩 실행할 수 있는 방법을 설명하는 데 사용됩니다. 이 기술은 복잡한 커널 모드 코드 문제를 디버깅하는 데 매우 유용할 수 있습니다.

Sysvad 샘플 오디오 드라이버를 다운로드하고 빌드하려면 다음 단계를 수행합니다.

  1. GitHub에서 Sysvad 오디오 샘플 다운로드 및 추출

    브라우저를 사용하여 여기에서 Sysvad 샘플 및 Readme.md 파일을 볼 수 있습니다.

    https://github.com/Microsoft/Windows-driver-samples/tree/main/audio/sysvad

    일반 폴더 및 ZIP 다운로드 단추를 표시하는 GitHub 리포지토리의 스크린샷.

    이 랩에서는 하나의 zip 파일에서 유니버설 드라이버 샘플을 다운로드하는 방법을 보여줍니다.

    a. 로컬 하드 드라이브에 master.zip 파일을 다운로드합니다.

    https://github.com/Microsoft/Windows-driver-samples/archive/master.zip

    b. Windows-driver-samples-master.zip 길게 누르거나 마우스 오른쪽 단추로 클릭하고 모두 추출을 선택합니다. 새 폴더를 지정하거나 추출된 파일을 저장할 기존 폴더를 찾습니다. 예를 들어 C:\WDK_Samples\를 파일이 추출되는 새 폴더로 지정할 수 있습니다.

    c. 파일을 추출한 후 다음 하위 폴더로 이동합니다.

    C:\WDK_Samples\Sysvad

  2. Visual Studio에서 드라이버 솔루션 열기

    Visual Studio에서 파일>열기>프로젝트/솔루션을 선택하고 추출된 파일이 포함된 폴더(예: C:\WDK_Samples\Sysvad)로 이동합니다. Syvad 솔루션 파일을 두 번 클릭합니다.

    Visual Studio에서 솔루션 탐색기 찾습니다. (아직 열려 있지 않은 경우보기 메뉴에서 솔루션 탐색기.) 솔루션 탐색기 여러 프로젝트가 있는 하나의 솔루션을 볼 수 있습니다.

    Sysvad 프로젝트에서 로드된 adapter.cpp 파일이 있는 Visual Studio의 스크린샷

  3. 샘플의 구성 및 플랫폼 설정

    솔루션 탐색기 솔루션 'sysvad'(프로젝트 7개 중 7개)를 선택하고 길게 누르거나 마우스 오른쪽 단추로 클릭하고 Configuration Manager를 선택합니다. 4개의 프로젝트에 대해 구성 및 플랫폼 설정이 동일한지 확인합니다. 기본적으로 구성은 "Win10 디버그"로 설정되고 플랫폼은 모든 프로젝트에 대해 "Win64"로 설정됩니다. 한 프로젝트에 대해 구성 및/또는 플랫폼을 변경하는 경우 세 개의 프로젝트를 다시 기본 동일한 변경을 수행해야 합니다.

    참고 이 랩에서는 64비트 Windows가 사용되고 있다고 가정합니다. 32비트 Windows를 사용하는 경우 32비트용 드라이버를 빌드합니다.

  4. 드라이버 서명 확인

    TabletAudioSample을 찾습니다. Sysvad 드라이버의 속성 페이지를 열고 드라이버 서명>서명 모드가 테스트 서명으로 설정되어 있는지 확인합니다.

  5. 기존 드라이버와 겹치지 않는 값을 사용하도록 드라이버 샘플을 수정해야 합니다. 샘플 코드에서 프로덕션 드라이버로 - Windows에 설치된 기존 실제 드라이버와 공존하는 고유한 드라이버 샘플을 만드는 방법에 대한 샘플의 변경 내용을 참조하세요.

  6. Visual Studio를 사용하여 샘플 빌드

    Visual Studio에서 빌드 솔루션 빌드>를 선택합니다.

    빌드 창에는 6개 프로젝트 모두에 대한 빌드가 성공했음을 나타내는 메시지가 표시됩니다.

빌드 오류 메시지가 표시되면 빌드 오류 번호를 사용하여 수정 사항을 확인합니다. 예를 들어 MSBuild 오류 MSB8040 스펙터 완화 라이브러리를 사용하는 방법을 설명합니다.

  1. 빌드된 드라이버 파일 찾기

    파일 탐색기 샘플에 대해 추출된 파일이 포함된 폴더로 이동합니다. 예를 들어 이전에 지정한 폴더인 경우 C:\WDK_Samples\Sysvad로 이동합니다. 해당 폴더 내에서 컴파일된 드라이버 파일의 위치는 Configuration Manager에서 선택한 구성 및 플랫폼 설정에 따라 달라집니다. 예를 들어 기본 설정을 변경하지 않은 상태로 두면 컴파일된 드라이버 파일이 64비트 디버그 빌드에 대한 \x64\Debug 폴더에 저장됩니다.

    TabletAudioSample 드라이버에 대한 빌드된 파일이 포함된 폴더로 이동합니다.

    C:\WDK_Samples\Sysvad\TabletAudioSample\x64\Debug. 폴더에는 TabletAudioSample .SYS 드라이버, 기호 pdp 파일 및 inf 파일이 포함됩니다. DelayAPO, KWSApo 및 KeywordDetectorContosoAdapter dll 및 기호 파일도 찾아야 합니다.

    드라이버를 설치하려면 다음 파일이 필요합니다.

    File name 설명
    TabletAudioSample.sys 드라이버 파일입니다.
    TabletAudioSample.pdb 드라이버 기호 파일입니다.
    tabletaudiosample.inf 드라이버를 설치하는 데 필요한 정보가 포함된 정보(INF) 파일입니다.
    KeywordDetectorContosoAdapter.dll 샘플 키워드(keyword) 감지기입니다.
    KeywordDetectorContosoAdapter.pdb 샘플 키워드(keyword) 감지기 기호 파일입니다.
    DelayAPO.dll 샘플 지연 APO입니다.
    DelayAPO.pdb 지연 APO 기호 파일입니다.
    KWSApo.dll 샘플 키워드(keyword) 스포터 APO입니다.
    KWSApo.pdb 키워드(keyword) 스포터 기호 파일입니다.
    TabletAudioSample.cer TabletAudioSample 인증서 파일입니다.
  2. USB 썸 드라이브를 찾거나 네트워크 공유를 설정하여 호스트에서 대상 시스템으로 빌드된 드라이버 파일을 복사합니다.

다음 섹션에서는 대상 시스템에 코드를 복사하고 드라이버를 설치하고 테스트합니다.

섹션 4: 대상 시스템에 Sysvad 오디오 드라이버 샘플 설치

섹션 4에서는 devcon을 사용하여 Sysvad 오디오 드라이버를 설치합니다.

-> 대상 시스템에서

드라이버를 설치하는 컴퓨터를 대상 컴퓨터 또는 테스트 컴퓨터라고 합니다. 일반적으로 드라이버 패키지를 개발하고 빌드하는 컴퓨터와는 별개의 컴퓨터입니다. 드라이버를 개발하고 빌드하는 컴퓨터를 호스트 컴퓨터라고 합니다.

드라이버 패키지를 대상 컴퓨터로 이동하고 드라이버를 설치하는 프로세스를 드라이버 배포라고 합니다.

드라이버를 배포하기 전에 테스트 서명을 켜서 대상 컴퓨터를 준비해야 합니다. 그런 다음 대상 시스템에서 빌드된 드라이버 샘플을 실행할 준비가 되었습니다.

대상 시스템에 드라이버를 설치하려면 다음 단계를 수행합니다.

  1. 테스트 서명된 드라이버 사용

    테스트 서명된 드라이버를 실행하는 기능을 사용하도록 설정하려면 다음을 수행합니다.

    1. Windows 설정을 엽니다.

    2. 업데이트 및 보안에서 복구를 선택합니다.

    3. 고급 시작에서 지금 다시 시작을 선택합니다.

    4. PC가 다시 시작되면 문제 해결을 선택합니다.

    5. 그런 다음, 고급 옵션, 시작 설정 선택한 다음 다시 시작을 선택합니다.

    6. F7 키를 눌러 드라이버 서명 적용 사용 안 함을 선택합니다.

    7. PC는 새 값으로 시작됩니다.

  2. -> 대상 시스템에서

    드라이버 설치

    다음 지침에서는 샘플 드라이버를 설치하고 테스트하는 방법을 보여 줍니다.

    이 드라이버를 설치하는 데 필요한 INF 파일은 TabletAudioSample.inf입니다. 대상 컴퓨터에서 명령 프롬프트 창을 관리istrator로 엽니다. 드라이버 패키지 폴더로 이동하여 TabletAudioSample.inf 파일을 마우스 오른쪽 단추로 클릭한 다음 설치를 선택합니다.

    테스트 드라이버가 서명되지 않은 드라이버임을 나타내는 대화 상자가 나타납니다. 계속하려면 이 드라이버 설치를 선택합니다.

    Windows에서 게시자를 확인할 수 없다는 Windows 보안 경고 스크린샷

     설치에 문제가 있는 경우 자세한 내용은 다음 파일을 검사. %windir%\inf\setupapi.dev.log

    자세한 지침은 드라이버 배포, 테스트 및 디버깅을 위한 컴퓨터 구성을 참조 하세요.

    INF 파일에는 tabletaudiosample.sys 설치하기 위한 하드웨어 ID가 포함되어 있습니다. Syvad 샘플의 경우 하드웨어 ID는 다음과 같습니다. root\sysvad_TabletAudioSample

  3. 장치 관리자 드라이버 검사

    대상 컴퓨터의 명령 프롬프트 창에서 devmgmt를 입력하여 장치 관리자 엽니다. 장치 관리자 보기 메뉴에서 유형별로 디바이스를 선택합니다.

    디바이스 트리에서 오디오 디바이스 노드에서 WDM(가상 오디오 디바이스) - 태블릿 샘플을습니다. 일반적으로 소리, 비디오 및 게임 컨트롤러 노드 아래에 있습니다 . 설치 및 활성 상태인지 확인합니다.

    장치 관리자 PC의 실제 하드웨어에 대한 드라이버를 강조 표시합니다. 그런 다음 드라이버를 길게 누르거나 마우스 오른쪽 단추로 클릭하고 비활성화를 선택하여 드라이버를 사용하지 않도록 설정합니다.

    장치 관리자 오디오 하드웨어 드라이버가 아래쪽 화살표를 표시하여 사용하지 않도록 설정되어 있는지 확인합니다.

    가상 오디오 장치 태블릿 샘플이 강조 표시된 장치 관리자 트리의 스크린샷

    샘플 드라이버를 성공적으로 설치한 후 이제 테스트할 준비가 되었습니다.

Sysvad 오디오 드라이버 테스트

  1. 대상 컴퓨터의 명령 프롬프트 창에서 devmgmt를 입력하여 장치 관리자 엽니다. 장치 관리자 보기 메뉴에서 유형별로 디바이스를 선택합니다. 디바이스 트리에서 WDM(가상 오디오 디바이스) - 태블릿 샘플을습니다.

  2. 제어판 열고 하드웨어 및 소리>관리 오디오 장치이동합니다. 소리 대화 상자에서 WDM(가상 오디오 장치) - 태블릿 샘플로 레이블이 지정된 스피커 아이콘을 선택한 다음 기본값 설정을 선택하지만 확인을 선택하지 않습니다. 그러면 소리 대화 상자가 열린 상태로 유지됩니다.

  3. 대상 컴퓨터에서 MP3 또는 기타 오디오 파일을 찾아 두 번 클릭하여 재생합니다. 그런 다음 소리 대화 상자에서 WDM(가상 오디오 장치) - 태블릿 샘플 드라이버와 연결된 볼륨 수준 표시기에서 작업이 있는지 확인합니다.

섹션 5: WinDbg를 사용하여 드라이버에 대한 정보 표시

섹션 5에서는 기호 경로를 설정하고 커널 디버거 명령을 사용하여 Sysvad 샘플 드라이버에 대한 정보를 표시합니다.

기호를 사용하면 WinDbg에서 디버깅할 때 매우 유용할 수 있는 변수 이름과 같은 추가 정보를 표시할 수 있습니다. WinDbg는 원본 수준 디버깅에 Microsoft Visual Studio 디버그 기호 형식을 사용합니다. PDB 기호 파일이 있는 모듈에서 기호 또는 변수에 액세스할 수 있습니다.

디버거를 로드하려면 다음 단계를 수행합니다.

<-호스트 시스템에서

  1. 디버거를 닫은 경우 관리자 명령 프롬프트 창에서 다음 명령을 사용하여 다시 엽니다. 키와 포트를 이전에 구성한 항목으로 바꿉다.

    C:\> WinDbg –k net:port=50010,key=2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
    
  2. Ctrl+Break(스크롤 잠금)를 사용하여 대상 시스템에서 실행되는 코드를 중단합니다.

기호 경로 설정

  1. WinDbg 환경에서 Microsoft 기호 서버에 대한 기호 경로를 설정하려면 .symfix 명령을 사용합니다.

    0: kd> .symfix
    
  2. 로컬 기호를 사용할 로컬 기호 위치를 추가하려면 .sympath+를 사용하여 경로를 추가한 다음 /f를 .reload합니다.

    0: kd> .sympath+ C:\WDK_Samples\Sysvad
    0: kd> .reload /f
    

    /f force 옵션이 있는 .reload 명령은 지정된 모듈에 대한 모든 기호 정보를 삭제하고 기호를 다시 로드합니다. 경우에 따라 이 명령은 모듈 자체를 다시 로드하거나 언로드합니다.

참고 WinDbg에서 제공하는 고급 기능을 사용하려면 적절한 기호를 로드해야 합니다. 제대로 구성된 기호가 없는 경우 기호에 종속된 기능을 사용하려고 할 때 기호를 사용할 수 없다는 메시지를 받게 됩니다.

0:000> dv
Unable to enumerate locals, HRESULT 0x80004005
Private symbols (symbols.pri) are required for locals.
Type “.hh dbgerr005” for details.

참고기호 서버

기호를 사용하는 데 사용할 수 있는 여러 가지 방법이 있습니다. 대부분의 경우 필요한 경우 Microsoft에서 제공하는 기호 서버에서 기호에 액세스하도록 PC를 구성할 수 있습니다. 이 연습에서는 이 방법이 사용된다고 가정합니다. 환경의 기호가 다른 위치에 있는 경우 해당 위치를 사용하도록 단계를 수정합니다. 자세한 내용은 Windows 디버거의 기호 경로를 참조 하세요.

참고소스 코드 기호 요구 사항 이해

원본 디버깅을 수행하려면 이진 파일의 검사(디버그) 버전을 빌드해야 합니다. 컴파일러는 기호 파일(.pdb 파일)을 만듭니다. 이러한 기호 파일은 이진 명령이 소스 줄에 해당하는 방법을 디버거에 표시합니다. 실제 원본 파일 자체도 디버거에서 액세스할 수 있어야 합니다.

기호 파일에는 소스 코드의 텍스트가 포함되어 있지 않습니다. 디버깅의 경우 링커가 코드를 최적화하지 않는 것이 가장 좋습니다. 코드가 최적화된 경우 소스 디버깅 및 지역 변수에 대한 액세스가 더 어렵고 거의 불가능할 수 있습니다. 지역 변수 또는 소스 줄을 보는 데 문제가 있는 경우 다음 빌드 옵션을 설정합니다.

set COMPILE_DEBUG=1

set ENABLE_OPTIMIZER=0

  1. 디버거의 명령 영역에 다음을 입력하여 Sysvad 드라이버에 대한 정보를 표시합니다.

    0: kd> lm m tabletaudiosample v
    Browse full module list
    start             end                 module name
    fffff801`14b40000 fffff801`14b86000   tabletaudiosample   (private pdb symbols)  C:\Debuggers\sym\TabletAudioSample.pdb\E992C4803EBE48C7B23DC1596495CE181\TabletAudioSample.pdb
        Loaded symbol image file: tabletaudiosample.sys
        Image path: \SystemRoot\system32\drivers\tabletaudiosample.sys
        Image name: tabletaudiosample.sys
        Browse all global symbols  functions  data
        Timestamp:        Thu Dec 10 12:20:26 2015 (5669DE8A)
        CheckSum:         0004891E
    ...  
    

    자세한 내용은 lm을 참조 하세요.

  2. 디버그 출력에서 모든 전역 기호 찾아보기 링크를 선택하여 문자 A로 시작하는 항목 기호에 대한 정보를 표시합니다.

  3. DML을 사용하도록 설정했으므로 출력의 일부 요소는 선택할 수 있는 핫 링크입니다. 디버그 출력에서 데이터 링크를 선택하여 문자 A로 시작하는 항목 기호에 대한 정보를 표시합니다.

    0: kd> x /D /f tabletaudiosample!a*
     A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
    
    fffff806`9adb1000 tabletaudiosample!AddDevice (struct _DRIVER_OBJECT *, struct _DEVICE_OBJECT *)
    

    자세한 내용은 x(기호 검사)를 참조하세요.

  4. !lmi 확장은 모듈에 대한 자세한 정보를 표시합니다. !lmi tabletaudiosample을 입력합니다. 출력은 아래 표시된 텍스트와 유사해야 합니다.

    0: kd> !lmi tabletaudiosample
    Loaded Module Info: [tabletaudiosample] 
             Module: tabletaudiosample
       Base Address: fffff8069ad90000
         Image Name: tabletaudiosample.sys
       Machine Type: 34404 (X64)
         Time Stamp: 58ebe848 Mon Apr 10 13:17:12 2017
               Size: 48000
           CheckSum: 42df7
    Characteristics: 22  
    Debug Data Dirs: Type  Size     VA  Pointer
                 CODEVIEW    a7,  e5f4,    d1f4 RSDS - GUID: {5395F0C5-AE50-4C56-AD31-DD5473BD318F}
                   Age: 1, Pdb: C:\Windows-driver-samples-master\audio\sysvad\TabletAudioSample\x64\Debug\TabletAudioSample.pdb
                       ??   250,  e69c,    d29c [Data not mapped]
         Image Type: MEMORY   - Image read successfully from loaded memory.
        Symbol Type: PDB      - Symbols loaded successfully from image header.
                     C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\sym\TabletAudioSample.pdb\5395F0C5AE504C56AD31DD5473BD318F1\TabletAudioSample.pdb
           Compiler: Resource - front end [0.0 bld 0] - back end [14.0 bld 24210]
        Load Report: private symbols & lines, not source indexed 
                     C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\sym\TabletAudioSample.pdb\5395F0C5AE504C56AD31DD5473BD318F1\TabletAudioSample.pdb
    
  5. 아래와 같이 !dh 확장을 사용하여 헤더 정보를 표시합니다.

    0: kd> !dh tabletaudiosample 
    
    File Type: EXECUTABLE IMAGE
    FILE HEADER VALUES
        8664 machine (X64)
           9 number of sections
    5669DE8A time date stamp Thu Dec 10 12:20:26 2015
    
           0 file pointer to symbol table
           0 number of symbols
          F0 size of optional header
          22 characteristics
                Executable
                App can handle >2gb addresses
    ...
    

섹션 6: 플러그 앤 플레이 디바이스 트리 정보 표시

섹션 6에서는 Sysvad 샘플 디바이스 드라이버와 해당 드라이버가 플러그 앤 플레이 디바이스 트리에 있는 위치에 대한 정보를 표시합니다.

플러그 앤 플레이 디바이스 트리의 디바이스 드라이버에 대한 정보는 문제 해결에 유용할 수 있습니다. 예를 들어 디바이스 드라이버가 디바이스 트리에 상주하지 않는 경우 디바이스 드라이버 설치에 문제가 있을 수 있습니다.

디바이스 노드 디버그 확장에 대한 자세한 내용은 !devnode를 참조하세요.

<-호스트 시스템에서

  1. 플러그 앤 플레이 디바이스 트리에서 모든 디바이스 노드를 보려면 !devnode 0 1 명령을 입력합니다. 이 명령을 실행하는 데 1~2분 정도 걸릴 수 있습니다. 이 시간 동안 WinDbg의 상태 영역에 "*Busy"가 표시됩니다.

    0: kd> !devnode 0 1
    Dumping IopRootDeviceNode (= 0xffffe0005a3a8d30)
    DevNode 0xffffe0005a3a8d30 for PDO 0xffffe0005a3a9e50
      InstancePath is "HTREE\ROOT\0"
      State = DeviceNodeStarted (0x308)
      Previous State = DeviceNodeEnumerateCompletion (0x30d)
      DevNode 0xffffe0005a3a3d30 for PDO 0xffffe0005a3a4e50
        InstancePath is "ROOT\volmgr\0000"
        ServiceName is "volmgr"
        State = DeviceNodeStarted (0x308)
        Previous State = DeviceNodeEnumerateCompletion (0x30d)
        DevNode 0xffffe0005a324560 for PDO 0xffffe0005bd95ca0…
    ...
    
  2. Ctrl+F를 사용하여 생성된 출력을 검색하여 디바이스 드라이버 sysvad의 이름을 찾습니다.

    검색 필드에 'sysvad'라는 용어가 입력된 대화 상자를 찾습니다.

    이름이 sysvad_TabletAudioSample 지정된 디바이스 노드 항목이 Syvad의 !devnode 출력에 표시됩니다.

      DevNode 0xffffe00086e68190 for PDO 0xffffe00089c575a0
        InstancePath is "ROOT\sysvad_TabletAudioSample\0000"
        ServiceName is "sysvad_tabletaudiosample"
        State = DeviceNodeStarted (0x308)
    ...
    

    PDO 주소와 DevNode 주소가 표시됩니다.

  3. 명령을 !devnode 0 1 sysvad_TabletAudioSample 사용하여 Sysvad 디바이스 드라이버와 연결된 플러그 앤 플레이 정보를 표시합니다.

    0: kd> !devnode 0 1 sysvad_TabletAudioSample
    Dumping IopRootDeviceNode (= 0xffffe00082df8d30)
    DevNode 0xffffe00086e68190 for PDO 0xffffe00089c575a0
      InstancePath is "ROOT\sysvad_TabletAudioSample\0000"
      ServiceName is "sysvad_tabletaudiosample"
      State = DeviceNodeStarted (0x308)
      Previous State = DeviceNodeEnumerateCompletion (0x30d)
      DevNode 0xffffe000897fb650 for PDO 0xffffe00089927e30
        InstancePath is "SWD\MMDEVAPI\{0.0.0.00000000}.{64097438-cdc0-4007-a19e-62e789062e20}"
        State = DeviceNodeStarted (0x308)
        Previous State = DeviceNodeStartPostWork (0x307)
      DevNode 0xffffe00086d2f5f0 for PDO 0xffffe00089939ae0
        InstancePath is "SWD\MMDEVAPI\{0.0.0.00000000}.{78880f4e-9571-44a4-a9df-960bde446487}"
        State = DeviceNodeStarted (0x308)
        Previous State = DeviceNodeStartPostWork (0x307)
      DevNode 0xffffe00089759bb0 for PDO 0xffffe000875aa060
        InstancePath is "SWD\MMDEVAPI\{0.0.0.00000000}.{7cad07f2-d0a0-4b9b-8100-8dc735e9c447}"
        State = DeviceNodeStarted (0x308)
        Previous State = DeviceNodeStartPostWork (0x307)
      DevNode 0xffffe00087735010 for PDO 0xffffe000872068c0
        InstancePath is "SWD\MMDEVAPI\{0.0.0.00000000}.{fc38551b-e69f-4b86-9661-ae6da78bc3c6}"
        State = DeviceNodeStarted (0x308)
        Previous State = DeviceNodeStartPostWork (0x307)
      DevNode 0xffffe00088457670 for PDO 0xffffe0008562b830
        InstancePath is "SWD\MMDEVAPI\{0.0.1.00000000}.{0894b831-c9fe-4c56-86a6-092380fc5628}"
        State = DeviceNodeStarted (0x308)
        Previous State = DeviceNodeStartPostWork (0x307)
      DevNode 0xffffe000893dbb70 for PDO 0xffffe00089d68060
        InstancePath is "SWD\MMDEVAPI\{0.0.1.00000000}.{15eb6b5c-aa54-47b8-959a-0cff2c1500db}"
        State = DeviceNodeStarted (0x308)
        Previous State = DeviceNodeStartPostWork (0x307)
      DevNode 0xffffe00088e6f250 for PDO 0xffffe00089f6e990
        InstancePath is "SWD\MMDEVAPI\{0.0.1.00000000}.{778c07f0-af9f-43f2-8b8d-490024f87239}"
        State = DeviceNodeStarted (0x308)
        Previous State = DeviceNodeStartPostWork (0x307)
      DevNode 0xffffe000862eb4b0 for PDO 0xffffe000884443a0
        InstancePath is "SWD\MMDEVAPI\{0.0.1.00000000}.{e4b72c7c-be50-45df-94f5-0f2922b85983}"
        State = DeviceNodeStarted (0x308)
        Previous State = DeviceNodeStartPostWork (0x307)
    
  4. 이전 명령에 표시된 출력에는 드라이버의 실행 중인 인스턴스와 연결된 PDO가 포함되어 있으며 , 이 예제에서는 0xffffe00089c575a0. !devobj<PDO 주소> 명령을 입력하여 Sysvad 디바이스 드라이버와 연결된 플러그 앤 플레이 정보를 표시합니다. 여기에 표시된 주소가 아니라 !devnode 가 PC에 표시하는 PDO 주소를 사용합니다.

    0: kd> !devobj 0xffffe00089c575a0
    Device object (ffffe00089c575a0) is for:
    0000004e \Driver\PnpManager DriverObject ffffe00082d47e60
    Current Irp 00000000 RefCount 65 Type 0000001d Flags 00001040
    SecurityDescriptor ffffc102b0f6d171 DevExt 00000000 DevObjExt ffffe00089c576f0 DevNode ffffe00086e68190 
    ExtensionFlags (0000000000)  
    Characteristics (0x00000180)  FILE_AUTOGENERATED_DEVICE_NAME, FILE_DEVICE_SECURE_OPEN
    AttachedDevice (Upper) ffffe00088386a50 \Driver\sysvad_tabletaudiosample
    Device queue is not busy.
    
  5. !devobj 명령에 표시되는 출력에는 연결된 디바이스의 이름 \Driver\sysvad_tabletaudiosample 포함됩니다. 연결된 디바이스와 연결된 정보를 표시하려면 비트 마스크가 2인 !drvobj 명령을 사용합니다.

    0: kd> !drvobj \Driver\sysvad_tabletaudiosample 2
    Driver object (ffffe0008834f670) is for:
    \Driver\sysvad_tabletaudiosample
    DriverEntry:   fffff80114b45310  tabletaudiosample!FxDriverEntry
    DriverStartIo: 00000000 
    DriverUnload:  fffff80114b5fea0                tabletaudiosample!DriverUnload
    AddDevice:     fffff80114b5f000  tabletaudiosample!AddDevice
    
    Dispatch routines:
    [00] IRP_MJ_CREATE                      fffff80117b49a20             portcls!DispatchCreate
    [01] IRP_MJ_CREATE_NAMED_PIPE           fffff8015a949a00          nt!IopInvalidDeviceRequest
    [02] IRP_MJ_CLOSE                       fffff80115e26f90                ks!DispatchCleanup
    [03] IRP_MJ_READ                        fffff80115e32710                ks!DispatchRead
    [04] IRP_MJ_WRITE                       fffff80115e327e0              ks!DispatchWrite
    [05] IRP_MJ_QUERY_INFORMATION           fffff8015a949a00         nt!IopInvalidDeviceRequest
    [06] IRP_MJ_SET_INFORMATION             fffff8015a949a00              nt!IopInvalidDeviceRequest
    [07] IRP_MJ_QUERY_EA                    fffff8015a949a00         nt!IopInvalidDeviceRequest
    [08] IRP_MJ_SET_EA                      fffff8015a949a00              nt!IopInvalidDeviceRequest
    [09] IRP_MJ_FLUSH_BUFFERS               fffff80115e32640  ks!DispatchFlush
    [0a] IRP_MJ_QUERY_VOLUME_INFORMATION    fffff8015a949a00           nt!IopInvalidDeviceRequest
    [0b] IRP_MJ_SET_VOLUME_INFORMATION      fffff8015a949a00               nt!IopInvalidDeviceRequest
    [0c] IRP_MJ_DIRECTORY_CONTROL           fffff8015a949a00           nt!IopInvalidDeviceRequest
    [0d] IRP_MJ_FILE_SYSTEM_CONTROL         fffff8015a949a00         nt!IopInvalidDeviceRequest
    [0e] IRP_MJ_DEVICE_CONTROL              fffff80115e27480               ks!DispatchDeviceIoControl
    [0f] IRP_MJ_INTERNAL_DEVICE_CONTROL     fffff8015a949a00   nt!IopInvalidDeviceRequest
    [10] IRP_MJ_SHUTDOWN                    fffff8015a949a00      nt!IopInvalidDeviceRequest
    [11] IRP_MJ_LOCK_CONTROL                fffff8015a949a00  nt!IopInvalidDeviceRequest
    [12] IRP_MJ_CLEANUP                     fffff8015a949a00           nt!IopInvalidDeviceRequest
    [13] IRP_MJ_CREATE_MAILSLOT             fffff8015a949a00               nt!IopInvalidDeviceRequest
    [14] IRP_MJ_QUERY_SECURITY              fffff80115e326a0 ks!DispatchQuerySecurity
    [15] IRP_MJ_SET_SECURITY                fffff80115e32770      ks!DispatchSetSecurity
    [16] IRP_MJ_POWER                       fffff80117b3dce0            portcls!DispatchPower
    [17] IRP_MJ_SYSTEM_CONTROL              fffff80117b13d30              portcls!PcWmiSystemControl
    [18] IRP_MJ_DEVICE_CHANGE               fffff8015a949a00 nt!IopInvalidDeviceRequest
    [19] IRP_MJ_QUERY_QUOTA                 fffff8015a949a00  nt!IopInvalidDeviceRequest
    [1a] IRP_MJ_SET_QUOTA                   fffff8015a949a00       nt!IopInvalidDeviceRequest
    [1b] IRP_MJ_PNP                         fffff80114b5f7d0 tabletaudiosample!PnpHandler
    
  6. !devstack<PDO 주소> 명령을 입력하여 디바이스 드라이버와 연결된 플러그 앤 플레이 정보를 표시합니다. !devnode 0 1 명령에 표시되는 출력에는 드라이버의 실행 중인 인스턴스와 연결된 PDO 주소가 포함됩니다. 이 예제 에서는 0xffffe00089c575a0. !devnodePC에 표시하는 PDO 주소를 사용합니다( 아래 표시된 주소가 아님).

    0: kd> !devstack 0xffffe00089c575a0
      !DevObj           !DrvObj            !DevExt           ObjectName
      ffffe00088d212e0  \Driver\ksthunk    ffffe00088d21430  0000007b
      ffffe00088386a50  \Driver\sysvad_tabletaudiosampleffffe00088386ba0  0000007a
    > ffffe00089c575a0  \Driver\PnpManager 00000000  0000004e
    !DevNode ffffe00086e68190 :
      DeviceInst is "ROOT\sysvad_TabletAudioSample\0000"
      ServiceName is "sysvad_tabletaudiosample"
    

출력은 훨씬 간단한 디바이스 드라이버 스택이 있음을 보여줍니다. sysvad_TabletAudioSample 드라이버는 PnPManager 노드의 자식입니다. PnPManager는 루트 노드입니다.

이 다이어그램은 더 복잡한 디바이스 노드 트리를 보여줍니다.

약 20개의 노드로 구성된 디바이스 노드 트리의 다이어그램입니다.

참고 더 복잡한 드라이버 스택에 대한 자세한 내용은 드라이버 스택 및디바이스 노드 및 디바이스 스택을 참조하세요.

섹션 7: 중단점 작업

섹션 7에서는 중단점을 사용하여 특정 지점에서 코드 실행을 중지합니다.

명령을 사용하여 중단점 설정

중단점은 특정 코드 줄에서 코드 실행을 중지하는 데 사용됩니다. 그런 다음, 해당 지점에서 코드에서 한 단계 앞으로 이동하여 코드의 특정 섹션을 디버그할 수 있습니다.

디버그 명령을 사용하여 중단점을 설정하려면 다음 b 명령 중 하나를 사용합니다.

bp

있는 모듈이 언로드될 때까지 활성화될 중단점을 설정합니다.

모듈이 언로드될 때 확인되지 않는 중단점을 설정하고 모듈이 다시 로드될 때 다시 사용하도록 설정합니다.

bm

기호의 중단점을 설정합니다. 이 명령은 bu 또는 bp를 적절하게 사용하고 wild카드s *를 사용하여 일치하는 모든 기호(예: 클래스의 모든 메서드)에 중단점을 설정할 수 있습니다.

  1. WinDbg UI를 사용하여 현재 WinDbg 세션에서 디버그>소스 모드가 사용하도록 설정되어 있는지 확인합니다.

  2. 다음 명령을 입력하여 소스 경로에 로컬 코드 위치를 추가합니다.

    .sympath+ C:\WDK_Samples\Sysvad
    
  3. 다음 명령을 입력하여 기호 경로에 로컬 기호 위치를 추가합니다.

    .sympath+ C:\WDK_Samples\Sysvad
    
  4. 디버그 마스크 설정

    드라이버로 작업할 때 표시할 수 있는 모든 메시지를 보는 것이 편리할 수 있습니다. 대상 시스템의 모든 디버그 메시지가 디버거에 표시되도록 기본 디버그 비트 마스크를 변경하려면 다음을 입력합니다.

    0: kd> ed nt!Kd_DEFAULT_MASK 0xFFFFFFFF
    
  5. 드라이버의 이름을 사용하여 bm 명령으로 중단점을 설정한 다음 중단점을 느낌표로 구분하여 설정하려는 함수 이름(AddDevice)을 붙입니다.

    0: kd> bm tabletaudiosample!AddDevice
    breakpoint 1 redefined
      1: fffff801`14b5f000 @!"tabletaudiosample!AddDevice"
    

    모듈>과 같은 <변수 설정과 함께 다른 구문을 사용할 수 있습니다.<symbol>, <class>::<method>,'<file.cpp>:<line number>'이거나 조건><#>을 여러 번 <건너뜁니다. 자세한 내용은 Using Breakpoints을 참조하세요.

  6. 현재 중단점을 나열하여 Bl 명령을 입력하여 중단점이 설정되었는지 확인합니다.

    0: kd> bl
    1 e fffff801`14b5f000     0001 (0001) tabletaudiosample!AddDevice
    
  7. go 명령 g를 입력하여 대상 시스템에서 코드 실행을 다시 시작합니다.

  8. ->대상 시스템에서

    Windows에서 아이콘을 사용하거나 mmc devmgmt.msc를 입력하여 장치 관리자 엽니다. 장치 관리자 소리, 비디오 및 게임 컨트롤러 노드를 확장합니다. 가상 오디오 드라이버 항목을 선택하고 길게 누르거나 마우스 오른쪽 단추로 클릭하고 메뉴에서 사용 안 함을 선택합니다.

  9. 가상 오디오 드라이버 항목을 다시 선택하고 길게(또는 마우스 오른쪽 단추로 클릭) 메뉴에서 [사용]을 선택합니다.

  10. <- 호스트 시스템에서

    이로 인해 Windows에서 AddDevice를 호출하는 드라이버를 다시 로드해야 합니다. 이로 인해 AddDevice 디버그 중단점이 실행되고 대상 시스템에서 드라이버 코드 실행이 중단됩니다.

    Breakpoint 1 hit
    tabletaudiosample!AddDevice:
    fffff801`14baf000 4889542410      mov     qword ptr [rsp+10h],rdx
    

    원본 경로가 제대로 설정된 경우 adapter.cpp AddDevice 루틴에서 중지해야 합니다.

    {
        PAGED_CODE();
    
        NTSTATUS        ntStatus;
        ULONG           maxObjects;
    
        DPF(D_TERSE, ("[AddDevice]"));
    
        maxObjects = g_MaxMiniports;
    
        #ifdef SYSVAD_BTH_BYPASS
        // 
        // Allow three (3) Bluetooth hands-free profile devices.
        //
        maxObjects += g_MaxBthHfpMiniports * 3; 
        #endif // SYSVAD_BTH_BYPASS
    
        // Tell the class driver to add the device.
        //
        ntStatus = 
            PcAddAdapterDevice
            ( 
                DriverObject,
                PhysicalDeviceObject,
                PCPFNSTARTDEVICE(StartDevice),
                maxObjects,
                0
            );
        return ntStatus;
    } // AddDevice
    
  11. p 명령을 입력하거나 F10 키를 눌러 코드를 한 줄씩 단계별로 실행합니다. sysvad AddDevice 코드에서 PpvUtilCall, PnpCallAddDevice, PipCallDriverAddDevice Windows 코드로 한 단계씩 앞으로 나아갈 수 있습니다. p 명령에 숫자를 제공하여 여러 줄 앞으로 나아갈 수 있습니다(예: p 5).

  12. 코드를 단계별로 실행했으면 go 명령 g 를 사용하여 대상 시스템에서 실행을 다시 시작합니다.

메모리 액세스 중단점 설정

메모리 위치에 액세스할 때 발생하는 중단점을 설정할 수도 있습니다. 다음 구문과 함께 ba(액세스 중단) 명령을 사용합니다.

ba <access> <size> <address> {options}
옵션 설명

e

execute(CPU가 주소에서 명령을 가져오는 경우)

r

읽기/쓰기(CPU가 주소에 읽거나 쓰는 경우)

w

쓰기(CPU가 주소에 쓰는 경우)

지정된 시간에 4개의 데이터 중단점만 설정할 수 있으며 데이터를 올바르게 정렬하거나 중단점을 트리거하지 않도록 하는 것은 사용자에게 달려 있습니다(단어는 2로 나눌 수 있는 주소로 끝나야 하고, dword는 4로 나눌 수 있어야 하고, 쿼드워드는 0 또는 8로 나눌 수 있어야 함).

예를 들어 특정 메모리 주소에 읽기/쓰기 중단점을 설정하려면 다음과 같은 명령을 사용합니다.

ba r 4 fffff800`7bc9eff0

중단점 상태 수정

다음 명령을 사용하여 기존 중단점을 수정할 수 있습니다.

bl

중단점을 나열합니다.

기원전

목록에서 중단점을 지웁니다. bc *를 사용하여 모든 중단점을 지웁니다.

bd

중단점을 사용하지 않도록 설정합니다. bd *를 사용하여 모든 중단점을 사용하지 않도록 설정합니다.

be

중단점을 사용하도록 설정합니다. *를 사용하여 모든 중단점을 사용하도록 설정합니다.

또는 중단점 편집>을 선택하여 중단점을 수정할 수도 있습니다. 중단점 대화 상자는 기존 중단점에서만 작동합니다. 명령줄에서 새 중단점을 설정해야 합니다.

MixerVolume에서 중단점 설정

디바이스 드라이버가 로드된 후 다양한 이벤트에 응답하기 위해 오디오 드라이버 코드의 다른 부분이 호출됩니다. 다음 섹션에서는 사용자가 가상 오디오 드라이버의 볼륨 컨트롤을 조정할 때 발생하는 중단점을 설정합니다.

MixerVolume에서 중단점을 설정하려면 다음 단계를 수행합니다.

  1. <- 호스트 시스템에서

    볼륨을 변경하는 메서드를 찾으려면 x 명령을 사용하여 문자열 볼륨을 포함하는 CAdapterCommon의 기호를 나열합니다.

    kd> x tabletaudiosample!CAdapterCommon::*
    ...
    fffff800`7bce26a0 tabletaudiosample!CAdapterCommon::MixerVolumeWrite (unsigned long, unsigned long, long)
    …
    

    Ctrl+F를 사용하여 출력에서 볼륨을 위쪽으로 검색하고 MixerVolumeWrite 메서드를 찾습니다.

  2. bc *를 사용하여 이전 중단점을 지웁니다.

  3. 다음 명령을 사용하여 CAdapterCommon::MixerVolumeWrite 루틴에 기호 중단점을 설정합니다.

    kd> bm tabletaudiosample!CAdapterCommon::MixerVolumeWrite
      1: fffff801`177b26a0 @!"tabletaudiosample!CAdapterCommon::MixerVolumeWrite"
    
  4. 중단점을 나열하여 중단점이 제대로 설정되어 있는지 확인합니다.

    kd> bl
    1 e fffff801`177b26a0 [c:\WDK_Samples\audio\sysvad\common.cpp @ 1668]    0001 (0001) tabletaudiosample!CAdapterCommon::MixerVolumeWrite
    
  5. go 명령 g를 입력하여 대상 시스템에서 코드 실행을 다시 시작합니다.

  6. 제어판 하드웨어 및 사운드 사운드>를 선택합니다. 싱크 설명 샘플을 선택하고 길게 누르거나 마우스 오른쪽 단추로 클릭하고 속성을 선택합니다. 수준 탭을 선택합니다. 슬라이더 볼륨을 조정합니다.

  7. 이렇게 하면 SetMixerVolume 디버그 중단점이 실행되고 대상 시스템에서 드라이버 코드 실행이 중단됩니다.

    kd> g
    Breakpoint 1 hit
    tabletaudiosample!CAdapterCommon::MixerVolumeWrite:
    fffff801`177b26a0 44894c2420      mov     dword ptr [rsp+20h],r9d
    

    common.cpp 이 줄에서 중지해야 합니다.

    {
        if (m_pHW)
        {
            m_pHW->SetMixerVolume(Index, Channel, Value);
        }
    } // MixerVolumeWrite
    
  8. dv 명령을 사용하여 현재 변수와 해당 값을 표시합니다. 변수에 대한 자세한 내용은 이 랩의 다음 섹션에서 제공합니다.

    2: kd> dv
               this = 0x00000000`00000010
             ulNode = 0x344
          ulChannel = 0x210a45f8
            lVolume = 0n24
    
  9. F10 키를 눌러 코드를 한 단계씩 실행합니다.

  10. F5 키를 눌러 MixerVolumeWrite 코드 실행을 완료합니다.

요약 - 디버거 명령 창에서 코드 단계별 실행

다음은 코드를 단계별로 진행하는 데 사용할 수 있는 명령입니다(연결된 키보드 바로 가기가 괄호로 표시됨).

  • 중단(Ctrl+Break) - 이 명령은 시스템이 실행되고 WinDbg와 통신하는 동안 시스템을 중단합니다(커널 디버거의 시퀀스는 Ctrl+C).

  • 단계별 실행(F10) – 이 명령을 사용하면 코드 실행이 한 번에 하나의 문 또는 한 명령씩 진행됩니다. 호출이 발생하면 호출 루틴을 입력하지 않고 코드 실행이 호출을 통해 전달됩니다. (프로그래밍 언어가 C 또는 C++이고 WinDbg가 소스 모드인 경우 원본 모드를 사용하여 설정하거나 해제할 수 있습니다.소스 모드 디버그>).

  • 단계별 실행(F11) – 호출 실행이 호출 루틴으로 이동한다는 점을 제외하고 이 명령은 단계별 실행과 같습니다.

  • 프로시저 나가기(Shift+F11) – 이 명령을 실행하면 현재 루틴(호출 스택의 현재 위치)에서 실행이 실행되고 종료됩니다. 이 기능은 루틴을 충분히 본 경우 유용합니다.

  • 커서 실행(F7 또는 Ctrl+F10) – 실행을 중단하려는 원본 또는 디스어셈블리 창에 커서를 놓고 F7 키를 누릅니다. 코드 실행이 해당 지점까지 실행됩니다. 코드 실행 흐름이 커서로 표시된 지점에 도달하지 않는 경우(예: IF 문이 실행되지 않음) 코드 실행이 표시된 지점에 도달하지 않았기 때문에 WinDbg는 중단되지 않습니다.

  • 실행(F5) – 중단점이 발생하거나 버그 검사 같은 이벤트가 발생할 때까지 실행합니다.

고급 옵션

  • 현재 줄로 명령 설정(Ctrl+Shift+I) – 원본 창에서 커서를 한 줄에 배치하고 이 바로 가기 키를 입력하면 계속 진행하는 즉시 코드 실행이 시작됩니다(예: F5 또는 F10 사용). 시퀀스를 다시 시도하려는 경우 편리하지만 주의가 필요합니다. 예를 들어 레지스터 및 변수는 코드 실행이 해당 줄에 자연스럽게 도달한 경우의 값으로 설정되지 않습니다.

  • eip 레지스터의 직접 설정 - eip 레지스터에 값을 넣을 수 있으며 F5(또는 F10, F11 등)를 누르면 해당 주소에서 실행이 시작됩니다. 어셈블리 명령의 주소를 지정한다는 점을 제외하고 커서가 지정한 현재 줄에 명령을 설정하는 것과 비슷합니다.

명령줄 대신 UI를 단계별로 진행하는 것이 더 쉬울 수 있으므로 이 메서드를 사용하는 것이 좋습니다. 필요한 경우 다음 명령을 사용하여 명령줄에서 소스 파일을 단계별로 실행할 수 있습니다.

  • .lines - 소스 줄 정보를 사용하도록 설정합니다.

  • bp 기본 - 모듈의 시작 부분에 초기 중단점을 설정합니다.

  • l+t - 단계별 실행은 소스 줄별로 수행됩니다.

  • 소스 모드 디버그>를 선택하여 소스 모드로 전환합니다. 명령으로 L+t 는 충분하지 않습니다.

  • l+s - 프롬프트에 원본 줄이 표시됩니다.

  • g - "기본"가 입력될 때까지 프로그램을 실행합니다.

  • p - 하나의 소스 줄을 실행합니다.

자세한 내용은 디버깅 참조 설명서의 WinDbg(클래식) 에서 소스 코드 디버깅을 참조하세요.

코드에서 중단점 설정

문을 추가하고 DebugBreak() 프로젝트를 다시 빌드하고 드라이버를 다시 설치하여 코드에서 중단점을 설정할 수 있습니다. 이 중단점은 드라이버가 활성화될 때마다 발생하므로 프로덕션 코드가 아닌 초기 개발 단계에서 사용할 수 있는 기술입니다. 이 기술은 중단점 명령을 사용하여 중단점을 동적으로 설정하는 것만큼 유연하지 않습니다.

팁: 추가 랩 작업을 위해 추가된 중단점을 사용하여 Sysvad 드라이버의 복사본을 유지할 수 있습니다.

  1. 샘플 코드에 문을 추가하여 AddDevice 메서드를 실행할 때마다 중단이 DebugBreak() 발생하도록 설정합니다.

    ...
        // Insert the DebugBreak() statment before the  PcAddAdapterDevice is called.
        //
    
        DebugBreak()
    
        // Tell the class driver to add the device.
        //
        ntStatus = 
            PcAddAdapterDevice
            ( 
                DriverObject,
                PhysicalDeviceObject,
                PCPFNSTARTDEVICE(StartDevice),
                maxObjects,
                0
            );
    
        return ntStatus;
    } // AddDevice
    
  2. 이전에 설명한 모든 단계에 따라 Microsoft Visual Studio에서 드라이버를 다시 빌드하고 대상 컴퓨터에 다시 설치합니다. 업데이트된 드라이버를 설치하기 전에 기존 드라이버를 제거해야 합니다.

  3. 이전 중단점을 지우고 디버거가 대상 PC에 연결되어 있는지 확인합니다.

  4. 코드가 실행되고 문에 DebugBreak 도달하면 실행이 중지되고 메시지가 표시됩니다.

    KERNELBASE!DebugBreak:
    77b3b770 defe     __debugbreak
    

섹션 8: 변수 표시

섹션 8에서는 디버거 명령을 사용하여 변수를 표시합니다.

코드가 실행될 때 변수를 검사하여 코드가 예상대로 작동하는지 확인하는 것이 유용할 수 있습니다. 이 랩은 오디오 드라이버가 소리를 생성할 때 변수를 검사합니다.

  1. dv 명령을 사용하여 tabletaudiosample과 연결된 로캘 변수를 검사합니다. CMiniportWaveRT::New*.

    kd> dv tabletaudiosample!CMiniportWaveRT::New*
    
  2. 이전 중단점 지우기

    bc *
    
  3. 다음 명령을 사용하여 CMiniportWaveCyclicStreamMSVAD 루틴에 기호 중단점을 설정합니다.

    0: kd> bm tabletaudiosample!CMiniportWaveRT::NewStream
      1: fffff801`177dffc0 @!"tabletaudiosample!CMiniportWaveRT::NewStream"
    
  4. go 명령 g를 입력하여 대상 시스템에서 코드 실행을 다시 시작합니다.

  5. -> 대상 시스템에서

    작은 미디어 파일(예: .wav 파일 확장자를 가진 Windows 알림 사운드 파일)을 찾아 재생할 파일을 선택합니다. 예를 들어 Windows\Media 디렉터리에 있는 Ring05.wav 사용할 수 있습니다.

  6. <- 호스트 시스템에서

    미디어 파일이 재생되면 중단점이 실행되고 대상 시스템에서 드라이버 코드 실행이 중단됩니다.

    Breakpoint 1 hit
    tabletaudiosample!CMiniportWaveRT::NewStream:
    fffff801`177dffc0 44894c2420      mov     dword ptr [rsp+20h],r9d
    

    소스 코드 창은 NewStream 함수 입구의 중괄호를 강조 표시해야 합니다.

    /*++
    
    Routine Description:
    
      The NewStream function creates a new instance of a logical stream 
      associated with a specified physical channel. Callers of NewStream should 
      run at IRQL PASSIVE_LEVEL.
    
    Arguments:
    
      OutStream -
    
      OuterUnknown -
    
      Pin - 
    
      Capture - 
    
      DataFormat -
    
    Return Value:
    
      NT status code.
    
    --*/
    {
    
    ...
    
  7. 지역 변수

    dv 명령을 입력하여 지정된 프레임에 대한 모든 지역 변수의 이름과 값을 표시할 수 있습니다.

    0: kd> dv
                    this = 0xffffe000`4436f8e0
               OutStream = 0xffffe000`49d2f130
            OuterUnknown = 0xffffe000`4436fa30
                     Pin = 0
                 Capture = 0x01 '
              DataFormat = 0xffffe000`44227790
    signalProcessingMode = {487E9220-E000-FFFF-30F1-D24900E0FFFF}
                ntStatus = 0n1055
                  stream = 0x00000000`00000200
    
  8. DML을 사용하여 변수 표시

    DML을 사용하여 변수를 탐색하려면 밑줄이 그은 요소를 선택합니다. 선택 작업은 중첩된 데이터 구조를 드릴다운할 수 있는 dx(NatVis 식 표시) 명령을 빌드합니다.

    0: kd> dx -r1 (*((tabletaudiosample!CMiniportWaveRT *)0xffffe001d10b8380))
    (*((tabletaudiosample!CMiniportWaveRT *)0xffffe001d10b8380)) :  [Type: CMiniportWaveRT]
        [+0x020] m_lRefCount      : 0
        [+0x028] m_pUnknownOuter  : 0xffffe001d1477e50 : [Type: IUnknown *]
        [+0x030] m_ulLoopbackAllocated : 0x2050
        [+0x034] m_ulSystemAllocated : 0x180
        [+0x038] m_ulOffloadAllocated : 0x0
        [+0x03c] m_dwCaptureAllocatedModes : 0x0
    
    0: kd> dx -r1 (*((tabletaudiosample!_GUID *)0xffffd001c8acd348))
    (*((tabletaudiosample!_GUID *)0xffffd001c8acd348)) : {487E9220-E000-FFFF-30F1-D24900E0FFFF} [Type: _GUID]
        [<Raw View>]    
    
    0: kd> dx -r1 -n (*((tabletaudiosample!_GUID *)0xffffd001c8acd348))
    (*((tabletaudiosample!_GUID *)0xffffd001c8acd348)) :  [Type: _GUID]
        [+0x000] Data1            : 0x487e9220
        [+0x004] Data2            : 0xe000
        [+0x006] Data3            : 0xffff
        [+0x008] Data4            :  [Type: unsigned char [8]]
    
    0: kd> dx -r1 -n (*((tabletaudiosample!unsigned char (*)[8])0xffffd001c8acd350))
    (*((tabletaudiosample!unsigned char (*)[8])0xffffd001c8acd350)) :  [Type: unsigned char [8]]
        [0]              : 0x30
        [1]              : 0xf1
        [2]              : 0xd2
        [3]              : 0x49
        [4]              : 0x0
        [5]              : 0xe0
        [6]              : 0xff
        [7]              : 0xff
    
  9. 전역 변수

    ? < 을 입력하여 전역 변수의 메모리 위치를 찾을 수 있습니다.변수 이름>입니다.

    0: kd> ? signalProcessingMode
    Evaluate expression: -52768896396472 = ffffd001`c8acd348
    
  10. 이 경우 변수의 메모리 위치(이 경우 ffffd001'c8acd348)가 반환됩니다. 이전 명령에서 반환한 메모리 위치를 사용하여 dd 명령을 입력하는 해당 위치의 값을 덤프하여 메모리 위치의 내용을 볼 수 있습니다.

    0: kd> dd ffffd001`c8acd348
    ffffd001`c8acd348  487e9220 ffffe000 49d2f130 ffffe000
    ffffd001`c8acd358  4837c468 ffffe000 18221570 ffffc000
    ffffd001`c8acd368  4436f8e0 ffffe000 487e9220 ffffe000
    ffffd001`c8acd378  18ab145b fffff801 4837c420 ffffe000
    ffffd001`c8acd388  4436f8e0 ffffe000 49d2f130 ffffe000
    ffffd001`c8acd398  4436fa30 ffffe000 00000000 00000000
    ffffd001`c8acd3a8  00000001 00000000 44227790 ffffe000
    ffffd001`c8acd3b8  18adc7f9 fffff801 495972a0 ffffe000
    
  11. dd 명령과 함께 변수 이름을 사용할 수도 있습니다.

    0: kd> dd signalProcessingMode
    ffffd001`c8acd348  487e9220 ffffe000 49d2f130 ffffe000
    ffffd001`c8acd358  4837c468 ffffe000 18221570 ffffc000
    ffffd001`c8acd368  4436f8e0 ffffe000 487e9220 ffffe000
    ffffd001`c8acd378  18ab145b fffff801 4837c420 ffffe000
    ffffd001`c8acd388  4436f8e0 ffffe000 49d2f130 ffffe000
    ffffd001`c8acd398  4436fa30 ffffe000 00000000 00000000
    ffffd001`c8acd3a8  00000001 00000000 44227790 ffffe000
    ffffd001`c8acd3b8  18adc7f9 fffff801 495972a0 ffffe000
    
  12. 변수 표시

    로컬 보기>메뉴 항목을 사용하여 지역 변수를 표시합니다. 또한 이 인터페이스는 더 복잡한 데이터 구조를 드릴다운하는 기능을 제공합니다.

    샘플 코드 로컬 및 명령 창을 표시하는 WinDbg 인터페이스입니다.

  13. p 또는 F10을 사용하여 ntStatus = IsFormatSupported(Pin, Capture, DataFormat)를 강조 표시할 때까지 코드에서 약 10줄 앞으로 이동; 코드 줄입니다.

        PAGED_CODE();
    
        ASSERT(OutStream);
        ASSERT(DataFormat);
    
        DPF_ENTER(("[CMiniportWaveRT::NewStream]"));
    
        NTSTATUS                    ntStatus = STATUS_SUCCESS;
        PCMiniportWaveRTStream      stream = NULL;
        GUID                        signalProcessingMode = AUDIO_SIGNALPROCESSINGMODE_DEFAULT;
    
        *OutStream = NULL;
    
         //
        // If the data format attributes were specified, extract them.
        //
        if ( DataFormat->Flags & KSDATAFORMAT_ATTRIBUTES )
        {
            // The attributes are aligned (QWORD alignment) after the data format
            PKSMULTIPLE_ITEM attributes = (PKSMULTIPLE_ITEM) (((PBYTE)DataFormat) + ((DataFormat->FormatSize + FILE_QUAD_ALIGNMENT) & ~FILE_QUAD_ALIGNMENT));
            ntStatus = GetAttributesFromAttributeList(attributes, attributes->Size, &signalProcessingMode);
        }
    
        // Check if we have enough streams.
        //
        if (NT_SUCCESS(ntStatus))
        {
            ntStatus = ValidateStreamCreate(Pin, Capture, signalProcessingMode);
        }
    
        // Determine if the format is valid.
        //
        if (NT_SUCCESS(ntStatus))
        {
            ntStatus = IsFormatSupported(Pin, Capture, DataFormat);
        }
    
    ...
    
  14. dv 명령을 사용하여 지정된 프레임에 대한 모든 지역 변수의 이름과 값을 표시합니다. 예상대로 지역 변수를 변경하는 추가 코드가 실행되고 일부 변수가 현재 프레임에 없거나 해당 값이 변경되었기 때문에 이 명령을 마지막으로 실행했을 때와 값이 다릅니다.

    2: kd> dv
                    this = 0xffffe001`d1182000
               OutStream = 0xffffe001`d4776d20
            OuterUnknown = 0xffffe001`d4776bc8
                     Pin = 0
                 Capture = 0x00 '
              DataFormat = 0xffffe001`cd7609b0
    signalProcessingMode = {4780004E-7133-41D8-8C74-660DADD2C0EE}
                ntStatus = 0n0
                  stream = 0x00000000`00000000
    

섹션 9: 호출 스택 보기

섹션 9에서는 호출자/호출 코드를 검사하는 호출 스택을 볼 수 있습니다.

호출 스택은 프로그램 카운터의 현재 위치로 이어진 함수 호출 체인입니다. 호출 스택의 최상위 함수는 현재 함수이고, 다음 함수는 현재 함수를 호출하는 함수입니다.

호출 스택을 표시하려면 k* 명령을 사용합니다.

kb

스택과 처음 세 개의 매개 변수를 표시합니다.

kp

스택과 전체 매개 변수 목록을 표시합니다.

kn

옆에 프레임 정보가 있는 스택을 볼 수 있습니다.

호출 스택을 계속 사용할 수 있도록 하려면 호출 스택 보기를>선택하여 볼 수 있습니다. 창 맨 위에 있는 열을 선택하여 추가 정보 표시를 전환합니다.

호출 스택 창을 표시하는 WinDbg 인터페이스입니다.

이 출력은 중단 상태에서 샘플 어댑터 코드를 디버깅하는 동안 호출 스택을 보여줍니다.

0: kd> kb
# RetAddr           : Args to Child                                                           : Call Site
00 fffff800`7a0fa607 : ffffe001`d1182000 ffffe001`d4776d20 ffffe001`d4776bc8 ffffe001`00000000 : tabletaudiosample!CMiniportWaveRT::NewStream+0x1dc [c:\data1\threshold\audio\endpointscommon\minwavert.cpp @ 597]
01 fffff800`7a0fb2c3 : 00000000`00000000 ffffe001`d122bb10 ffffe001`ceb81750 ffffe001`d173f058 : portcls!CPortPinWaveRT::Init+0x2e7
02 fffff800`7a0fc7f9 : ffffe001`d4776bc0 00000000`00000000 ffffe001`d10b8380 ffffe001`d122bb10 : portcls!CPortFilterWaveRT::NewIrpTarget+0x193
03 fffff800`7a180552 : 00000000`00000000 ffffe001`d10b8380 ffffe001`d122bb10 ffffe001`d4565600 : portcls!xDispatchCreate+0xd9
04 fffff800`7a109a9a : ffffe001`d10b84d0 ffffe001`d10b8380 00000000`00000000 ffffe001`00000000 : ks!KsDispatchIrp+0x272
05 fffff800`7bd314b1 : ffffe001`d122bb10 ffffd001`c3098590 ffffe001`d122bd90 ffffe001`ce80da70 : portcls!DispatchCreate+0x7a
06 fffff803`cda1bfa8 : 00000000`00000024 00000000`00000000 00000000`00000000 ffffe001`d122bb10 : ksthunk!CKernelFilterDevice::DispatchIrp+0xf9
07 fffff803`cda7b306 : 00000000`000001f0 ffffe001`d48ce690 ffffe001`d13d6400 ffffe001`d13d64c0 : nt!IopParseDevice+0x7c8
08 fffff803`cda12916 : 00000000`000001f0 ffffd001`c30988d0 ffffe001`d13d6490 fffff803`cda7b250 : nt!IopParseFile+0xb6
09 fffff803`cda1131c : ffffe001`d2ccb001 ffffd001`c30989e0 00ffffe0`00000040 ffffe001`cd127dc0 : nt!ObpLookupObjectName+0x776
0a fffff803`cd9fedb8 : ffffe001`00000001 ffffe001`d48ce690 00000000`00000000 00000000`00000000 : nt!ObOpenObjectByNameEx+0x1ec
0b fffff803`cd9fe919 : 000000ee`6d1fc8d8 000000ee`6d1fc788 000000ee`6d1fc7e0 000000ee`6d1fc7d0 : nt!IopCreateFile+0x3d8
0c fffff803`cd752fa3 : ffffc000`1f296870 fffff803`cd9d9fbd ffffd001`c3098be8 00000000`00000000 : nt!NtCreateFile+0x79
0d 00007fff`69805b74 : 00007fff`487484e6 0000029b`00000003 00000000`0000012e 00000000`00000000 : nt!KiSystemServiceCopyEnd+0x13
0e 00007fff`487484e6 : 0000029b`00000003 00000000`0000012e 00000000`00000000 00000000`00000000 : 0x00007fff`69805b74
0f 0000029b`00000003 : 00000000`0000012e 00000000`00000000 00000000`00000000 00000000`00000000 : 0x00007fff`487484e6
10 00000000`0000012e : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000080 : 0x0000029b`00000003
11 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000080 00000000`00000000 : 0x12e

DML을 사용하여 코드를 추가로 탐색할 수 있습니다. 처음 00개 항목을 선택하면 .frame(로컬 컨텍스트 설정) 명령을 사용하여 컨텍스트를 설정한 다음 dv(지역 변수 표시) 명령에 지역 변수가 표시됩니다.

0: kd> .frame 0n0;dv /t /v
00 ffffd001`c30981d0 fffff800`7a0fa607 tabletaudiosample!CMiniportWaveRT::NewStream+0x1dc [c:\data1\threshold\audio\endpointscommon\minwavert.cpp @ 597]
ffffd001`c30982b0 class CMiniportWaveRT * this = 0xffffe001`d1182000
ffffd001`c30982b8 struct IMiniportWaveRTStream ** OutStream = 0xffffe001`d4776d20
ffffd001`c30982c0 struct IPortWaveRTStream * OuterUnknown = 0xffffe001`d4776bc8
ffffd001`c30982c8 unsigned long Pin = 0
ffffd001`c30982d0 unsigned char Capture = 0x00 '
ffffd001`c30982d8 union KSDATAFORMAT * DataFormat = 0xffffe001`cd7609b0
ffffd001`c3098270 struct _GUID signalProcessingMode = {4780004E-7133-41D8-8C74-660DADD2C0EE}
ffffd001`c3098210 long ntStatus = 0n0
ffffd001`c3098218 class CMiniportWaveRTStream * stream = 0x00000000`00000000

섹션 10: 프로세스 및 스레드 표시

섹션 10에서는 디버거 명령을 사용하여 프로세스와 스레드를 표시합니다.

처리

현재 프로세스 컨텍스트를 변경하려면 .process <process> 명령을 사용합니다. 다음 예제에서는 프로세스를 식별하고 컨텍스트를 프로세스로 전환하는 방법을 보여 줍니다.

  • !process 명령을 사용하여 소리 재생과 관련된 현재 프로세스를 표시합니다.

    자세한 내용은 !process를 참조 하세요.

출력은 프로세스가 audiodg.exe 연결되어 있음을 보여줍니다. 이 항목의 이전 섹션에서 설명한 중단점에 있는 경우 현재 프로세스는 audiodg.exe 이미지와 연결되어야 합니다.

<- 호스트 시스템에서

0: kd> !process
PROCESS ffffe001d147c840
    SessionId: 0  Cid: 10f0    Peb: ee6cf8a000  ParentCid: 0434
    DirBase: d2122000  ObjectTable: ffffc0001f191ac0  HandleCount: <Data Not Accessible>
    Image: audiodg.exe
    VadRoot ffffe001d4222f70 Vads 70 Clone 0 Private 504. Modified 16. Locked 0.
    DeviceMap ffffc00019113080
    Token                             ffffc0001f1d4060
    ElapsedTime                       <Invalid>
    UserTime                          00:00:00.000
    KernelTime                        00:00:00.000
    QuotaPoolUsage[PagedPool]         81632
    QuotaPoolUsage[NonPagedPool]      9704
    Working Set Sizes (now,min,max)  (2154, 1814, 2109) (8616KB, 7256KB, 8436KB)
    PeakWorkingSetSize                2101
    VirtualSize                       2097192 Mb
    PeakVirtualSize                   2097192 Mb
    PageFaultCount                    2336
    MemoryPriority                    BACKGROUND
    BasePriority                      8
    CommitCharge                      1573

        THREAD ffffe001d173e840  Cid 10f0.1dac  Teb: 000000ee6cf8b000 Win32Thread: ffffe001d1118cf0 WAIT: (UserRequest) UserMode Non-Alertable
            ffffe001d16c4dd0  NotificationEvent
            ffffe001d08b0840  ProcessObject

        THREAD ffffe001ceb77080  Cid 10f0.16dc  Teb: 000000ee6cf8d000 Win32Thread: 0000000000000000 WAIT: (WrQueue) UserMode Alertable
            ffffe001cf2d1840  QueueObject

        THREAD ffffe001d112c840  Cid 10f0.0a4c  Teb: 000000ee6cf8f000 Win32Thread: 0000000000000000 WAIT: (WrQueue) UserMode Alertable
            ffffe001cf2d1840  QueueObject

        THREAD ffffe001d16c7840  Cid 10f0.13c4  Teb: 000000ee6cf91000 Win32Thread: 0000000000000000 WAIT: (WrQueue) UserMode Alertable
            ffffe001cf2d1840  QueueObject

        THREAD ffffe001cec67840  Cid 10f0.0dbc  Teb: 000000ee6cf93000 Win32Thread: 0000000000000000 WAIT: (WrQueue) UserMode Alertable
            ffffe001d173e5c0  QueueObject

        THREAD ffffe001d1117840  Cid 10f0.1d6c  Teb: 000000ee6cf95000 Win32Thread: 0000000000000000 WAIT: (WrQueue) UserMode Alertable
            ffffe001d173e5c0  QueueObject

        THREAD ffffe001cdeae840  Cid 10f0.0298  Teb: 000000ee6cf97000 Win32Thread: 0000000000000000 RUNNING on processor 2

이 프로세스와 연결된 스레드 중 하나가 실행 중 상태입니다. 이 스레드는 중단점에 도달했을 때 미디어 클립 재생을 지원했습니다.

!process 0 0 명령을 사용하여 모든 프로세스에 대한 요약 정보를 표시합니다. 명령 출력에서 Ctrl+F를 사용하여 audiodg.exe 이미지와 연결된 프로세스의 프로세스 ID를 찾습니다. 아래 예제에서 프로세스 ID는 ffffe001d147c840입니다.

이 랩의 뒷부분에서 사용할 수 있도록 PC의 audiodg.exe 연결된 프로세스 ID를 기록합니다. ________________________

...

PROCESS ffffe001d147c840
    SessionId: 0  Cid: 10f0    Peb: ee6cf8a000  ParentCid: 0434
    DirBase: d2122000  ObjectTable: ffffc0001f191ac0  HandleCount: <Data Not Accessible>
    Image: audiodg.exe
...

디버거에 g를 입력하여 미디어 클립 재생이 완료될 때까지 코드를 앞으로 실행합니다. 그런 다음 Ctrl+ScrLk(Ctrl+Break)를 눌러 디버거에 침입합니다. !process 명령을 사용하여 현재 다른 프로세스를 실행하고 있는지 확인합니다.

!process
PROCESS ffffe001cd0ad040
    SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
    DirBase: 001aa000  ObjectTable: ffffc00017214000  HandleCount: <Data Not Accessible>
    Image: System
    VadRoot ffffe001d402b820 Vads 438 Clone 0 Private 13417. Modified 87866. Locked 64.
    DeviceMap ffffc0001721a070
    Token                             ffffc00017216a60
    ElapsedTime                       05:04:54.716
    UserTime                          00:00:00.000
    KernelTime                        00:00:20.531
    QuotaPoolUsage[PagedPool]         0
    QuotaPoolUsage[NonPagedPool]      0
    Working Set Sizes (now,min,max)  (1720, 50, 450) (6880KB, 200KB, 1800KB)
    PeakWorkingSetSize                15853
    VirtualSize                       58 Mb
    PeakVirtualSize                   74 Mb
    PageFaultCount                    46128
   MemoryPriority                    BACKGROUND
    BasePriority                      8
    CommitCharge                      66

        THREAD ffffe001cd0295c0  Cid 0004.000c  Teb: 0000000000000000 Win32Thread: 0000000000000000 WAIT: (Executive) KernelMode Non-Alertable
            fffff803cd8e0120  SynchronizationEvent

        THREAD ffffe001cd02a6c0  Cid 0004.0010  Teb: 0000000000000000 Win32Thread: 0000000000000000 WAIT: (Executive) KernelMode Non-Alertable
            fffff803cd8e0ba0  Semaphore Limit 0x7fffffff
...

위의 출력은 ffffe001cd0ad040다른 시스템 프로세스가 실행 중임을 보여줍니다. 이미지 이름은 audiodg.exe 아니라 System을 표시합니다.

이제 !process 명령을 사용하여 audiodg.exe 연결된 프로세스로 전환합니다. 이 예제에서 프로세스 ID는 ffffe001d147c840입니다. 예제의 프로세스 ID를 이전에 기록한 프로세스 ID로 바꿉니다.

0: kd> !process  ffffe001d147c840
PROCESS ffffe001d147c840
    SessionId: 0  Cid: 10f0    Peb: ee6cf8a000  ParentCid: 0434
    DirBase: d2122000  ObjectTable: ffffc0001f191ac0  HandleCount: <Data Not Accessible>
    Image: audiodg.exe
    VadRoot ffffe001d4222f70 Vads 60 Clone 0 Private 299. Modified 152. Locked 0.
    DeviceMap ffffc00019113080
    Token                             ffffc0001f1d4060
    ElapsedTime                       1 Day 01:53:14.490
    UserTime                          00:00:00.031
    KernelTime                        00:00:00.031
    QuotaPoolUsage[PagedPool]         81552
    QuotaPoolUsage[NonPagedPool]      8344
    Working Set Sizes (now,min,max)  (1915, 1814, 2109) (7660KB, 7256KB, 8436KB)
    PeakWorkingSetSize                2116
    VirtualSize                       2097189 Mb
    PeakVirtualSize                   2097192 Mb
    PageFaultCount                    2464
    MemoryPriority                    BACKGROUND
    BasePriority                      8
    CommitCharge                      1418

        THREAD ffffe001d173e840  Cid 10f0.1dac  Teb: 000000ee6cf8b000 Win32Thread: ffffe001d1118cf0 WAIT: (UserRequest) UserMode Non-Alertable
            ffffe001d16c4dd0  NotificationEvent
            ffffe001d08b0840  ProcessObject
        Not impersonating
        DeviceMap                 ffffc00019113080
        Owning Process            ffffe001d147c840       Image:         audiodg.exe
        Attached Process          N/A            Image:         N/A
        Wait Start TickCount      338852         Ticks: 197682 (0:00:51:28.781)
        Context Switch Count      36             IdealProcessor: 0             
        UserTime                  00:00:00.015
        KernelTime                00:00:00.000
        Win32 Start Address 0x00007ff7fb928de0
        Stack Init ffffd001c2ec6dd0 Current ffffd001c2ec60c0
        Base ffffd001c2ec7000 Limit ffffd001c2ec1000 Call 0
        Priority 8 BasePriority 8 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5
        Kernel stack not resident.

        THREAD ffffe001d115c080  Cid 10f0.15b4  Teb: 000000ee6cf9b000 Win32Thread: 0000000000000000 WAIT: (WrQueue) UserMode Alertable
            ffffe001d0bf0640  QueueObject
        Not impersonating
        DeviceMap                 ffffc00019113080
        Owning Process            ffffe001d147c840       Image:         audiodg.exe
        Attached Process          N/A            Image:         N/A
        Wait Start TickCount      338852         Ticks: 197682 (0:00:51:28.781)
        Context Switch Count      1              IdealProcessor: 0             
        UserTime                  00:00:00.000
        KernelTime                00:00:00.000
        Win32 Start Address 0x00007fff6978b350
        Stack Init ffffd001c3143dd0 Current ffffd001c3143520
        Base ffffd001c3144000 Limit ffffd001c313e000 Call 0
        Priority 8 BasePriority 8 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5
        Kernel stack not resident.

        THREAD ffffe001d3a27040  Cid 10f0.17f4  Teb: 000000ee6cf9d000 Win32Thread: 0000000000000000 WAIT: (WrQueue) UserMode Alertable
            ffffe001d173e5c0  QueueObject
        Not impersonating
        DeviceMap                 ffffc00019113080
        Owning Process            ffffe001d147c840       Image:         audiodg.exe
        Attached Process          N/A            Image:         N/A
        Wait Start TickCount      518918         Ticks: 17616 (0:00:04:35.250)
        Context Switch Count      9              IdealProcessor: 1             
        UserTime                  00:00:00.000
        KernelTime                00:00:00.000
        Win32 Start Address 0x00007fff6978b350
        Stack Init ffffd001c70c6dd0 Current ffffd001c70c6520
        Base ffffd001c70c7000 Limit ffffd001c70c1000 Call 0
        Priority 9 BasePriority 8 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5
        Kernel stack not resident.

이 코드는 활성 상태가 아니므로 모든 스레드는 예상대로 WAIT 상태입니다.

스레드

스레드를 보고 설정하는 명령은 프로세스의 명령과 매우 유사합니다. !thread 명령을 사용하여 스레드를 봅니다. .thread를 사용하여 현재 스레드를 설정합니다.

미디어 플레이어와 연결된 스레드를 탐색하려면 미디어 클립을 다시 재생합니다. 이전 섹션에서 설명한 중단점이 여전히 있는 경우 audiodg.exe 컨텍스트에서 중지됩니다.

!thread -1 0을 사용하여 현재 스레드에 대한 간략한 정보를 표시합니다. 스레드 주소, 스레드 및 프로세스 ID, TEB(스레드 환경 블록) 주소, 실행할 스레드가 만들어진 Win32 함수의 주소(있는 경우) 및 스레드의 예약 상태를 보여 줍니다.

0: kd> !thread -1 0
THREAD ffffe001d3a27040  Cid 10f0.17f4  Teb: 000000ee6cf9d000 Win32Thread: 0000000000000000 RUNNING on processor 0

실행 중인 스레드에 대한 자세한 내용을 보려면 !thread를 입력합니다. 다음과 유사한 정보가 표시됩니다.

0: kd> !thread
THREAD ffffe001d3a27040  Cid 10f0.17f4  Teb: 000000ee6cf9d000 Win32Thread: 0000000000000000 RUNNING on processor 0
IRP List:
    ffffe001d429e580: (0006,02c8) Flags: 000008b4  Mdl: 00000000
Not impersonating
DeviceMap                 ffffc00019113080
Owning Process            ffffe001d147c840       Image:         audiodg.exe
Attached Process          N/A            Image:         N/A
Wait Start TickCount      537630         Ticks: 0
Context Switch Count      63             IdealProcessor: 1             
UserTime                  00:00:00.000
KernelTime                00:00:00.015
Win32 Start Address 0x00007fff6978b350
Stack Init ffffd001c70c6dd0 Current ffffd001c70c6520
Base ffffd001c70c7000 Limit ffffd001c70c1000 Call 0
Priority 8 BasePriority 8 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5
Child-SP          RetAddr           : Args to Child                                                           : Call Site
ffffd001`c70c62a8 fffff800`7a0fa607 : ffffe001`d4aec5c0 ffffe001`cdefd3d8 ffffe001`d4aec5c0 ffffe001`cdefd390 : tabletaudiosample!CMiniportWaveRT::NewStream [c:\data1\threshold\audio\endpointscommon\minwavert.cpp @ 562]
ffffd001`c70c62b0 fffff800`7a0fb2c3 : 00000000`00000000 ffffe001`d429e580 ffffe001`d4ea47b0 ffffe001`cdefd3d8 : portcls!CPortPinWaveRT::Init+0x2e7
ffffd001`c70c6340 fffff800`7a0fc7f9 : ffffe001`d4aec430 00000000`00000000 ffffe001`d10b8380 ffffe001`d429e580 : portcls!CPortFilterWaveRT::NewIrpTarget+0x193
ffffd001`c70c63c0 fffff800`7a180552 : 00000000`00000000 ffffe001`d10b8380 ffffe001`d429e580 ffffe001`d4565600 : portcls!xDispatchCreate+0xd9
ffffd001`c70c6450 fffff800`7a109a9a : ffffe001`d10b84d0 ffffe001`d10b8380 00000000`00000000 ffffe001`00000000 : ks!KsDispatchIrp+0x272
ffffd001`c70c6510 fffff800`7bd314b1 : ffffe001`d429e580 ffffd001`c70c6590 ffffe001`d429e800 ffffe001`ce80da70 : portcls!DispatchCreate+0x7a
ffffd001`c70c6540 fffff803`cda1bfa8 : 00000000`00000025 00000000`00000000 00000000`00000000 ffffe001`d429e580 : ksthunk!CKernelFilterDevice::DispatchIrp+0xf9
ffffd001`c70c65a0 fffff803`cda7b306 : 00000000`000002fc ffffe001`d5e0d510 00000000`00000000 ffffe001`d3341bd0 : nt!IopParseDevice+0x7c8
ffffd001`c70c6770 fffff803`cda12916 : 00000000`000002fc ffffd001`c70c68d0 ffffe001`d3341ba0 fffff803`cda7b250 : nt!IopParseFile+0xb6
ffffd001`c70c67d0 fffff803`cda1131c : ffffe001`ceb6c601 ffffd001`c70c69e0 00000000`00000040 ffffe001`cd127dc0 : nt!ObpLookupObjectName+0x776
ffffd001`c70c6970 fffff803`cd9fedb8 : ffff8ab8`00000001 ffffe001`d5e0d510 00000000`00000000 00000000`00000000 : nt!ObOpenObjectByNameEx+0x1ec
ffffd001`c70c6a90 fffff803`cd9fe919 : 000000ee`6d37c6e8 00000004`6d37c500 000000ee`6d37c5f0 000000ee`6d37c5e0 : nt!IopCreateFile+0x3d8
ffffd001`c70c6b40 fffff803`cd752fa3 : fffff6fb`7da05360 fffff6fb`40a6c0a8 fffff681`4d815760 ffff8ab8`92895e23 : nt!NtCreateFile+0x79
ffffd001`c70c6bd0 00007fff`69805b74 : 00007fff`487484e6 0000029b`00000003 00000000`0000012e 00000000`00000000 : nt!KiSystemServiceCopyEnd+0x13 (TrapFrame @ ffffd001`c70c6c40)
000000ee`6d37c568 00007fff`487484e6 : 0000029b`00000003 00000000`0000012e 00000000`00000000 00000000`00000000 : 0x00007fff`69805b74
000000ee`6d37c570 0000029b`00000003 : 00000000`0000012e 00000000`00000000 00000000`00000000 00000000`00000000 : 0x00007fff`487484e6
000000ee`6d37c578 00000000`0000012e : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000080 : 0x0000029b`00000003
000000ee`6d37c580 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000080 00000000`00000000 : 0x12e

k 명령을 사용하여 스레드와 연결된 호출 스택을 봅니다.

0: kd> k
# Child-SP          RetAddr           Call Site
00 ffffd001`c70c62a8 fffff800`7a0fa607 tabletaudiosample!CMiniportWaveRT::NewStream [c:\data1\threshold\audio\endpointscommon\minwavert.cpp @ 562]
01 ffffd001`c70c62b0 fffff800`7a0fb2c3 portcls!CPortPinWaveRT::Init+0x2e7
02 ffffd001`c70c6340 fffff800`7a0fc7f9 portcls!CPortFilterWaveRT::NewIrpTarget+0x193
03 ffffd001`c70c63c0 fffff800`7a180552 portcls!xDispatchCreate+0xd9
04 ffffd001`c70c6450 fffff800`7a109a9a ks!KsDispatchIrp+0x272
05 ffffd001`c70c6510 fffff800`7bd314b1 portcls!DispatchCreate+0x7a
06 ffffd001`c70c6540 fffff803`cda1bfa8 ksthunk!CKernelFilterDevice::DispatchIrp+0xf9
07 ffffd001`c70c65a0 fffff803`cda7b306 nt!IopParseDevice+0x7c8
08 ffffd001`c70c6770 fffff803`cda12916 nt!IopParseFile+0xb6
09 ffffd001`c70c67d0 fffff803`cda1131c nt!ObpLookupObjectName+0x776
0a ffffd001`c70c6970 fffff803`cd9fedb8 nt!ObOpenObjectByNameEx+0x1ec
0b ffffd001`c70c6a90 fffff803`cd9fe919 nt!IopCreateFile+0x3d8
0c ffffd001`c70c6b40 fffff803`cd752fa3 nt!NtCreateFile+0x79
0d ffffd001`c70c6bd0 00007fff`69805b74 nt!KiSystemServiceCopyEnd+0x13
0e 000000ee`6d37c568 00007fff`487484e6 0x00007fff`69805b74
0f 000000ee`6d37c570 0000029b`00000003 0x00007fff`487484e6
10 000000ee`6d37c578 00000000`0000012e 0x0000029b`00000003
11 000000ee`6d37c580 00000000`00000000 0x12e

디버거에 g를 입력하여 미디어 클립 재생이 완료될 때까지 코드를 앞으로 실행합니다. 그런 다음 Ctrl - ScrLk(Ctrl-Break)를 눌러 디버거에 침입합니다. !thread 명령을 사용하여 현재 다른 스레드를 실행하고 있는지 확인합니다.

0: kd> !thread
THREAD ffffe001ce80b840  Cid 17e4.01ec  Teb: 00000071fa9b9000 Win32Thread: ffffe001d41690d0 RUNNING on processor 0
Not impersonating
DeviceMap                 ffffc0001974e2c0
Owning Process            ffffe001d1760840       Image:         rundll32.exe
Attached Process          N/A            Image:         N/A
Wait Start TickCount      538040         Ticks: 0
Context Switch Count      3181840        IdealProcessor: 0             
UserTime                  00:00:08.250
KernelTime                00:00:10.796
Win32 Start Address 0x00007ff6d2f24270
Stack Init ffffd001cd16afd0 Current ffffd001cd16a730
Base ffffd001cd16b000 Limit ffffd001cd165000 Call 0
Priority 8 BasePriority 8 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5

Child-SP          RetAddr           : Args to Child                                                           : Call Site
fffff803`cf373d18 fffff800`7a202852 : fffff803`cf373e60 00000000`00000001 ffffe001`cf4ed330 00000000`0000ffff : nt!DbgBreakPointWithStatus
fffff803`cf373d20 fffff803`cd6742c6 : ffffe001`cf4ed2f0 fffff803`cf373e60 00000000`00000001 00000000`0004e4b8 : kdnic!TXSendCompleteDpc+0x142
fffff803`cf373d60 fffff803`cd74d495 : 00000000`00000000 fffff803`cd923180 fffff803`cde1f4b0 fffff901`40669010 : nt!KiRetireDpcList+0x5f6
fffff803`cf373fb0 fffff803`cd74d2a0 : 00000000`00000090 0000000e`0000006a 00000000`00000092 00000000`00000000 : nt!KxRetireDpcList+0x5 (TrapFrame @ fffff803`cf373e70)
ffffd001`cd16a6c0 fffff803`cd74bd75 : 00000000`00000000 fffff803`cd74a031 00000000`00000000 00000000`00000000 : nt!KiDispatchInterruptContinue
ffffd001`cd16a6f0 fffff803`cd74a031 : 00000000`00000000 00000000`00000000 ffffe001`cff4d2a0 fffff803`cd67738e : nt!KiDpcInterruptBypass+0x25
ffffd001`cd16a700 fffff960`50cdb5a4 : fffff901`400006d0 00000000`00000001 fffff901`40000d60 ffffd001`cd16a9f0 : nt!KiInterruptDispatchNoLockNoEtw+0xb1 (TrapFrame @ ffffd001`cd16a700)
ffffd001`cd16a890 fffff960`50c66b2f : 00000000`00000000 fffff901`40669010 fffff901`42358580 fffff901`40000d60 : win32kfull!Win32FreePoolImpl+0x34
ffffd001`cd16a8c0 fffff960`50c68cd6 : 00000000`00000000 ffffd001`cd16a9f0 fffff901`400006d0 fffff901`400c0460 : win32kfull!EXLATEOBJ::vAltUnlock+0x1f
ffffd001`cd16a8f0 fffff803`cd752fa3 : 00000000`00000000 00000000`00000000 ffffe001`ce80b840 00000000`00000000 : win32kfull!NtGdiAlphaBlend+0x1d16
ffffd001`cd16add0 00007fff`674c1494 : 00007fff`674b1e97 0000a7c6`daee0559 00000000`00000001 0000020b`741f3c50 : nt!KiSystemServiceCopyEnd+0x13 (TrapFrame @ ffffd001`cd16ae40)
00000071`fa74c9a8 00007fff`674b1e97 : 0000a7c6`daee0559 00000000`00000001 0000020b`741f3c50 00000000`00ffffff : 0x00007fff`674c1494
00000071`fa74c9b0 0000a7c6`daee0559 : 00000000`00000001 0000020b`741f3c50 00000000`00ffffff 00000000`00000030 : 0x00007fff`674b1e97
00000071`fa74c9b8 00000000`00000001 : 0000020b`741f3c50 00000000`00ffffff 00000000`00000030 00000000`01010bff : 0x0000a7c6`daee0559
00000071`fa74c9c0 0000020b`741f3c50 : 00000000`00ffffff 00000000`00000030 00000000`01010bff 00000000`00000000 : 0x1
00000071`fa74c9c8 00000000`00ffffff : 00000000`00000030 00000000`01010bff 00000000`00000000 00000000`000000c0 : 0x0000020b`741f3c50
00000071`fa74c9d0 00000000`00000030 : 00000000`01010bff 00000000`00000000 00000000`000000c0 00000000`00000030 : 0xffffff
00000071`fa74c9d8 00000000`01010bff : 00000000`00000000 00000000`000000c0 00000000`00000030 00000071`00000030 : 0x30
00000071`fa74c9e0 00000000`00000000 : 00000000`000000c0 00000000`00000030 00000071`00000030 00000071`01ff8000 : 0x1010bff

이미지 이름은 rundll32.exe, 실제로 미디어 클립 재생과 관련된 이미지 이름이 아닙니다.

참고 현재 스레드를 설정하려면 .thread 스레드 <번호를 입력합니다>.

스레드 및 프로세스에 대한 자세한 내용은 다음 참조를 참조하세요.

스레드 및 프로세스

컨텍스트 변경

섹션 11: IRQL, 레지스터 및 디스어셈블리

저장된 IRQL 보기

섹션 11에서는 IRQL 및 regsisters의 내용을 표시합니다.

<- 호스트 시스템에서

IRQL(인터럽트 요청 수준)은 인터럽트 서비스의 우선 순위를 관리하는 데 사용됩니다. 각 프로세서에는 스레드가 발생하거나 낮을 수 있는 IRQL 설정이 있습니다. 프로세서의 IRQL 설정 또는 그 아래에서 발생하는 인터럽트는 마스킹되며 현재 작업을 방해하지 않습니다. 프로세서의 IRQL 설정 위에서 발생하는 인터럽트는 현재 작업보다 우선합니다. !irql 확장은 디버거 중단이 발생하기 전에 대상 컴퓨터의 현재 프로세서에 IRQL(인터럽트 요청 수준)을 표시합니다. 대상 컴퓨터가 디버거에 침입하면 IRQL이 변경되지만 디버거 중단 직전에 유효했던 IRQL이 저장되고 !irql에 의해 표시됩니다.

0: kd> !irql
Debugger saved IRQL for processor 0x0 -- 2 (DISPATCH_LEVEL)

<레지스터 및 디스어셈블리 보기

레지스터 보기

r(Registers) 명령을 사용하여 현재 프로세서에서 현재 스레드에 대한 레지스터의 내용을 표시합니다.

0: kd> r
rax=000000000000c301 rbx=ffffe00173eed880 rcx=0000000000000001
rdx=000000d800000000 rsi=ffffe00173eed8e0 rdi=ffffe00173eed8f0
rip=fffff803bb757020 rsp=ffffd001f01f8988 rbp=ffffe00173f0b620
 r8=000000000000003e  r9=ffffe00167a4a000 r10=000000000000001e
r11=ffffd001f01f88f8 r12=0000000000000000 r13=ffffd001f01efdc0
r14=0000000000000001 r15=0000000000000000
iopl=0         nv up ei pl nz na pe nc
cs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
nt!DbgBreakPointWithStatus:
fffff803`bb757020 cc              int     3

또는 레지스터 보기를>선택하여 레지스터의 내용을 표시할 수 있습니다.

약 12개의 레지스터를 표시하는 WinDbg 레지스터 창의 스크린샷

어셈블리 언어 코드 실행을 단계별로 실행하고 다른 시나리오에서 레지스터의 내용을 보는 것이 유용할 수 있습니다. 자세한 내용은 r(레지스터)을 참조하세요.

레지스터의 내용에 대한 자세한 내용은 x86 아키텍처x64 아키텍처를 참조하세요.

디스어셈블리

실행 중인 코드를 디스어셈블하여 디스어셈블리 보기를 선택하여 실행 중인 어셈블리 언어 코드를 볼>수 있습니다.

어셈블리 언어 코드를 보여 주는 WinDbg 디스어셈블리 창의 스크린샷

어셈블리 언어 디스어셈블리 에 대한 자세한 내용은 주석이 추가된 x86 디스어셈블리주석이 추가된 x64 디스어셈블리를 참조하세요.

섹션 12: 메모리 작업

섹션 12에서는 디버거 명령을 사용하여 메모리의 내용을 표시합니다.

메모리 보기

메모리를 검사하여 문제를 식별하거나 변수, 포인터 등을 검사해야 할 수 있습니다. 다음 d* <주소> 명령 중 하나를 입력하여 메모리를 표시할 수 있습니다.

db

데이터를 바이트 값 및 ASCII 문자로 표시합니다.

dd

데이터를 더블 와이드 단어(4바이트)로 표시합니다.

du

데이터를 유니코드 문자로 표시합니다.

dw

데이터를 단어 값(2바이트) 및 ASCII 문자로 표시합니다.

참고 잘못된 주소를 표시하려고 하면 해당 내용이 물음표(?)로 표시됩니다.

또는 메모리 보기를 선택하여 메모리를 >수 있습니다. 디스플레이 형식 풀다운을 사용하여 메모리 표시 방법을 변경합니다.

다양한 표시 형식 옵션이 있는 WinDbg 보기 메모리 창의 스크린샷

  1. 볼륨 컨트롤과 연결된 데이터를 보려면 bm 명령을 사용하여 PropertyHandlerAudioEngineVolumeLevel 루틴에서 실행되도록 중단점을 설정합니다. 새 중단점을 설정하기 전에 bc *를 사용하여 이전 중단점을 모두 지웁니다.

    kd> bc *
    
  2. bm 명령을 사용하여 PropertyHandlerAudioEngineVolumeLevel 루틴에서 실행되도록 중단점을 설정합니다.

    kd> bm tabletaudiosample!CMiniportWaveRT::SetDeviceChannelVolume
      1: fffff80f`02c3a4b0 @!"tabletaudiosample!CMiniportWaveRT::SetDeviceChannelVolume"
    
  3. 중단점을 나열하여 중단점이 제대로 설정되어 있는지 확인합니다.

    kd> bl
      1: fffff80f`02c3a4b0 @!"tabletaudiosample!CMiniportWaveRT::SetDeviceChannelVolume"
    
  4. g 명령을 사용하여 코드 실행을 다시 시작합니다.

    대상 시스템에서 시스템 트레이의 볼륨을 조정합니다. 이로 인해 중단점이 발생합니다.

    Breakpoint 1 hit
    tabletaudiosample!CMiniportWaveRT::SetDeviceChannelVolume:
    fffff80f`02c3a4b0 44894c2420      mov     dword ptr [rsp+20h],r9d
    
  5. 로컬 보기>메뉴 항목을 사용하여 지역 변수를 표시합니다. IVolume 변수의 현재 값을 확인합니다.

  6. dt 명령과 변수의 이름을 입력하여 샘플 코드에서 IVolume 변수의 데이터 형식 및 현재 값을 표시할 수 있습니다.

    kd> dt lVolume
    Local var @ 0xa011ea50 Type long
    0n-6291456
    
  7. SetDeviceChannelVolume을 입력할 때 중단점이 적중됩니다.

    STDMETHODIMP_(NTSTATUS) CMiniportWaveRT::SetDeviceChannelVolume(_In_  ULONG _ulNodeId, _In_ UINT32 _uiChannel, _In_  LONG  _Volume)
    {
        NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
    
        PAGED_CODE ();
    
        DPF_ENTER(("[CMiniportWaveRT::SetEndpointChannelVolume]"));
        IF_TRUE_ACTION_JUMP(_ulNodeId != KSNODE_WAVE_AUDIO_ENGINE, ntStatus = STATUS_INVALID_DEVICE_REQUEST, Exit);
    
        // Snap the volume level to our range of steppings.
        LONG lVolume = VOLUME_NORMALIZE_IN_RANGE(_Volume); 
    
        ntStatus = SetChannelVolume(_uiChannel, lVolume);
    Exit:
        return ntStatus;
    }
    
  8. dt(표시 형식) 명령을 사용하여 IVolume의 메모리 위치에 값을 표시하려고 시도합니다.

    kd> dt dt lVolume
    Local var @ 0xffffb780b7eee664 Type long
    0n0
    

    변수는 아직 정의되지 않았으므로 정보가 포함되지 않습니다.

  9. F10 키를 눌러 SetDeviceChannelVolume의 마지막 코드 줄로 앞으로 실행합니다.

        return ntStatus;
    
  10. dt(표시 형식) 명령을 사용하여 IVolume의 메모리 위치에 값을 표시합니다.

    kd> dt lVolume
    Local var @ 0xffffb780b7eee664 Type long
    0n-6291456
    

    이제 변수가 활성화되었으므로 이 예제에서는 6291456 값이 표시됩니다.

  11. ??을 사용하여 IVolume의 메모리 위치를 표시할 수도 있습니다. (식 계산) 명령.

    kd> ? lVolume
    Evaluate expression: -79711507126684 = ffffb780`b7eee664
    
  12. 표시된 주소인 ffffb780'b7eee664 는 lVolume 변수의 주소입니다. dd 명령을 사용하여 해당 위치에 메모리의 내용을 표시합니다.

    kd>  dd ffffb780`b7eee664
    ffffb780`b7eee664  ffa00000 00000018 00000000 c52d7008
    ffffb780`b7eee674  ffffc98e e0495756 fffff80e c52d7008
    ffffb780`b7eee684  ffffc98e 00000000 fffff80e 00000000
    ffffb780`b7eee694  ffffc98e ffa00000 ffffb780 b7eee710
    ffffb780`b7eee6a4  ffffb780 00000000 00000000 c7477260
    ffffb780`b7eee6b4  ffffc98e b7eee7a0 ffffb780 b7eee6f0
    ffffb780`b7eee6c4  ffffb780 e04959ca fffff80e 00000000
    ffffb780`b7eee6d4  00000000 00000028 00000000 00000002
    
  13. 범위 매개 변수 L4를 지정하여 주소의 처음 4바이트를 표시할 수 있습니다.

    kd> dd ffffb780`b7eee664 l4
    ffffb780`b7eee664  ffa00000 00000018 00000000 c52d7008
    
  14. 표시되는 다양한 유형의 메모리 출력을 보려면 du, dadb 명령을 입력합니다.

    kd> du ffffb780`b7eee664 
    ffffb780`b7eee664  ""
    
    kd> a ffffb780`b7eee664 
    ffffb780`b7eee664  ""
    
    kd> db 0xffffae015ff97664 
    ffffae01`5ff97664  00 80 bc ff 18 00 00 00-00 00 00 00 08 50 e0 51  .............P.Q
    ffffae01`5ff97674  00 c0 ff ff 56 57 da 56-0e f8 ff ff 08 50 e0 51  ....VW.V.....P.Q
    ffffae01`5ff97684  00 c0 ff ff 00 00 00 00-0e f8 ff ff 00 00 00 00  ................
    ffffae01`5ff97694  00 c0 ff ff aa 80 bc ff-01 ae ff ff 10 77 f9 5f  .............w._
    ffffae01`5ff976a4  01 ae ff ff 40 00 00 00-00 e6 ff ff 10 dc 30 55  ....@.........0U
    ffffae01`5ff976b4  00 c0 ff ff a0 77 f9 5f-01 ae ff ff f0 76 f9 5f  .....w._.....v._
    ffffae01`5ff976c4  01 ae ff ff ca 59 da 56-0e f8 ff ff 00 00 00 00  .....Y.V........
    ffffae01`5ff976d4  00 00 00 00 28 00 00 00-00 00 00 00 02 00 00 00  ....(...........
    

    df float 옵션을 사용하여 데이터를 단정밀도 부동 소수점 숫자(4바이트)로 표시합니다.

    df ffffb780`b7eee664 
    ffffb780`b7eee664          -1.#QNAN   3.3631163e-044                0        -2775.002
    ffffb780`b7eee674          -1.#QNAN  -5.8032637e+019         -1.#QNAN        -2775.002
    ffffb780`b7eee684          -1.#QNAN                0         -1.#QNAN                0
    ffffb780`b7eee694          -1.#QNAN         -1.#QNAN         -1.#QNAN  -2.8479408e-005
    

메모리에 쓰기

메모리를 읽는 데 사용되는 명령과 마찬가지로 e* 명령을 사용하여 메모리 내용을 변경할 수 있습니다.

명령 설명

ea

ASCII 문자열(NULL로 종료되지 않음)

eu

유니코드 문자열(NULL로 종료되지 않음)

ew

Word 값(2바이트)

Eza

NULL로 종료된 ASCII 문자열

ezu

NULL로 종료된 유니코드 문자열

Eb

바이트 값

ed

두 단어 값(4바이트)

다음 예제에서는 메모리를 덮어쓰는 방법을 보여줍니다.

  1. 먼저 샘플 코드에 사용되는 lVolume의 주소를 찾습니다.

    kd> ? lVolume
    Evaluate expression: -79711507126684 = ffffb780`b7eee664
    
  2. eb 명령을 사용하여 새 문자로 해당 메모리 주소를 덮어씁니다.

    kd> eb 0xffffb780`b7eee664 11 11 11 11 11
    
  3. db 명령을 입력하여 문자가 덮어쓰여졌는지 확인하려면 메모리 위치를 표시합니다.

    kd> db 0xffffb780`b7eee664
    ffffb780`b7eee664  11 11 11 11 11 00 00 00-00 00 00 00 08 70 2d c5  .............p-.
    ffffb780`b7eee674  8e c9 ff ff 56 57 49 e0-0e f8 ff ff 08 70 2d c5  ....VWI......p-.
    ffffb780`b7eee684  8e c9 ff ff 00 00 00 00-0e f8 ff ff 00 00 00 00  ................
    ffffb780`b7eee694  8e c9 ff ff 00 00 a0 ff-80 b7 ff ff 10 e7 ee b7  ................
    ffffb780`b7eee6a4  80 b7 ff ff 00 00 00 00-00 00 00 00 60 72 47 c7  ............`rG.
    ffffb780`b7eee6b4  8e c9 ff ff a0 e7 ee b7-80 b7 ff ff f0 e6 ee b7  ................
    ffffb780`b7eee6c4  80 b7 ff ff ca 59 49 e0-0e f8 ff ff 00 00 00 00  .....YI.........
    ffffb780`b7eee6d4  00 00 00 00 28 00 00 00-00 00 00 00 02 00 00 00  ....(...........
    

또는 조사식 또는 로컬 창에서 메모리의 내용을 수정할 수 있습니다. 조사식 창의 경우 현재 프레임의 컨텍스트를 벗어난 변수가 표시되어 있을 수 있습니다. 수정은 컨텍스트에 없는 경우 관련이 없습니다.

섹션 13: WinDbg 세션 종료

<-호스트 시스템에서

디버거를 연결된 상태로 유지하지만 대상에서 작업하려면 대상 컴퓨터가 호스트 컴퓨터 디버거에 연결하지 않도록 중단점을 bc *지웁니다. 그런 다음, g 명령을 사용하여 대상 컴퓨터가 다시 실행되도록 합니다.

디버깅 세션을 종료하려면 호스트 시스템에서 디버거에 침입하여 (종료 및 분리) 명령을 입력 qd 하거나 메뉴에서 디버깅 중지를 선택합니다.

0: kd> qd

자세한 내용은 디버깅 참조 설명서의 WinDbg(클래식) 에서 디버깅 세션 종료를 참조하세요.

섹션 14: Windows 디버깅 리소스

추가 정보는 Windows 디버깅에서 사용할 수 있습니다. 이러한 책 중 일부는 예제에서 Windows Vista와 같은 이전 버전의 Windows를 사용하지만 설명된 개념은 대부분의 Windows 버전에 적용할 수 있습니다.

동영상

조각 모음 도구 쇼 WinDbg 에피소드 13-29: </show/defrag-tools/>

교육 공급업체:

Osr- https://www.osr.com/

참고 항목

Windows 디버깅 시작