偵錯 Windows 驅動程式逐步實驗室 (回應核心模式)

此實驗室介紹 WinDbg 核心調試程式。 您可以使用 WinDbg 來偵錯回應核心模式範例驅動程式程式代碼。

實驗室目標

此實驗室包含介紹偵錯工具的練習、教授常見的偵錯命令、說明斷點的使用,以及示範如何使用偵錯延伸模組。

在此實驗室中,您會使用即時核心偵錯連線來探索下列動作:

  • 使用 Windows 調試程式命令
  • 使用標準指令(呼叫堆疊、變數、線程、IRQL)
  • 使用進階驅動程式偵錯指令 (!commands)
  • 使用符號
  • 在即時偵錯中設定斷點
  • 檢視呼叫堆疊
  • 顯示 隨插即用 裝置樹狀結構
  • 使用線程和進程內容

使用者和核心模式偵錯

使用 Windows 調試程式時,您可以執行兩種類型的偵錯:

使用者模式 - 應用程式與子系統會在使用者模式的電腦上執行。 在使用者模式中執行的進程會在自己的虛擬位址空間內執行。 它們受限於直接存取系統的許多部分,包括系統硬體、未配置供其使用的記憶體,以及可能會危害系統完整性的系統其他部分。 由於在使用者模式中執行的進程會有效地與系統和其他使用者模式進程隔離,因此它們不會干擾這些資源。

核心模式 - 作業系統和特殊許可權程式會在核心模式中執行。 內核模式程式代碼有權存取系統的任何部分。 它不受限制,例如使用者模式程序代碼。 它可以存取在使用者模式或核心模式中執行的任何其他進程的任何部分。 大部分的核心OS功能和許多硬體設備驅動器都會以核心模式執行。

本練習涵蓋使用者模式和內核模式偵錯期間經常使用的偵錯命令。 此練習也涵蓋偵錯延伸模組,有時稱為 !命令,用於內核模式偵錯。

實驗室設定

您需要下列硬體才能完成實驗室:

  • 執行 Windows 10 的膝上型電腦或桌面電腦(主機)
  • 執行 Windows 10 的第二部膝上型電腦或桌面電腦 (目標)
  • 用來連接兩部計算機的網路中樞或路由器和網路纜線
  • 存取因特網以下載符號檔

您需要下列軟體才能完成實驗室:

  • Visual Studio
  • 適用於 Windows 10 的 Windows 軟體開發工具套件 (SDK)
  • 適用於 Windows 10 的 Windows 驅動程式套件 (WDK)
  • 適用於 Windows 10 的響應驅動程式範例

實驗室有下列各節:

連線 至內核模式 WinDbg 工作階段

在本節中,設定主機和目標系統上的網路偵錯。

此實驗室中的計算機必須設定為使用乙太網路連線進行核心偵錯。

此實驗室使用兩部計算機。 Windows 調試程式會在 主機 系統上執行,而核心模式驅動程式架構 (KMDF) 回應驅動程式會在 目標 系統上執行。

使用網路中樞或路由器和網路纜線來連接兩部計算機。

圖表說明兩部透過網路中樞或路由器連線的計算機。

若要使用內核模式應用程式並使用 WinDbg,建議您使用透過乙太網路傳輸的 KDNET。 如需如何使用乙太網路傳輸通訊協定的資訊,請參閱 開始使用 WinDbg (核心模式) 。 如需設定目標計算機的詳細資訊,請參閱 準備計算機以進行手動驅動程式部署自動設定 KDNET 網路核心偵錯。

使用乙太網路設定內核模式偵錯

若要在目標系統上啟用內核模式偵錯:

  1. 在主機系統上,開啟 [命令提示字元] 視窗,然後輸入 ipconfig 以判斷其IP位址。

    Windows IP Configuration
    Ethernet adapter Ethernet:
       Connection-specific DNS Suffix  . :
       Link-local IPv6 Address . . . . . : fe80::c8b6:db13:d1e8:b13b%3
       Autoconfiguration IPv4 Address. . : 169.182.1.1
       Subnet Mask . . . . . . . . . . . : 255.255.0.0
       Default Gateway . . . . . . . . . :
    
  2. 記錄主機系統的 IP 位址:______________________________________

  3. 在目標系統上,開啟 [命令提示字元] 視窗,並使用 ping 命令來確認兩個系統之間的網路連線。

    ping 169.182.1.1
    

    使用您記錄之主機系統的實際IP位址,而不是範例輸出中顯示的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
    

完成下列步驟,在目標系統上啟用內核模式偵錯。

重要

使用 BCDEdit 變更開機資訊之前,您可能需要暫時暫停測試電腦上的 Windows 安全性功能,例如 BitLocker 和安全開機。 測試完成時重新啟用這些安全性功能。 在停用安全性功能時,適當地管理測試計算機。 安全開機通常會在 UEFI 中停用。 若要存取 UEFI 設定,請使用系統、復原、進階啟動。 重新啟動時,選取 [疑難解答]、[進階選項]、[UEFI 韌體設定]。 請小心,因為未正確設定 UEFI 選項或停用 BitLocker,可能會使系統無法運作。

  1. 在目標計算機上,以 管理員 istrator 開啟命令提示字元視窗。 輸入此指令以開啟偵錯:

    bcdedit /set {default} DEBUG YES
    
  2. 輸入此指令以啟用測試簽署:

    bcdedit /set TESTSIGNING ON 
    
  3. 輸入此命令以設定主機系統的IP位址。 使用您稍早記錄之主機系統的IP位址,而不是顯示的IP位址。

    bcdedit /dbgsettings net hostip:192.168.1.1 port:50000 key:2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
    

    警告

    若要提高連線的安全性,並降低隨機用戶端調試程式連線要求的風險,請使用自動產生的隨機密鑰。 如需詳細資訊,請參閱 自動設定 KDNET 網路核心偵錯。

  4. 輸入此指令以確認 dbgsettings 的值已正確設定:

    bcdedit /dbgsettings
    
    key                     2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
    debugtype               NET
    hostip                  169.168.1.1
    port                    50000
    dhcp                    Yes
    The operation completed successfully.
    

    注意

    如果您收到來自防火牆的訊息,而且您想要使用調試程式,請選取這三個方塊。

    Windows 安全性 警示對話框的螢幕快照,指出 Windows 防火牆封鎖了應用程式的一些功能。

  5. 在主計算機上,以 管理員 istrator 開啟命令提示字元視窗。 此實驗室使用 Windows 驅動程式套件 (WDK) 中安裝的 x64 版本 WinDbg.exe ,作為 Windows 套件安裝的一部分。 變更為預設 WinDbg 目錄,預設位置如下所示。

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

    此實驗室假設這兩部計算機在目標和主機上都執行64位版本的Windows。 如果情況並非如此,最好的方法是在目標執行所在的主機上執行相同的 工具位 。 例如,如果目標執行 32 位 Windows,請在主機上執行 32 位版本的調試程式。 如需詳細資訊,請參閱 選擇 32 位或 64 位偵錯工具

  6. 使用下列命令以遠端使用者偵錯開啟 WinDbg。 索引鍵和埠的值符合您稍早在目標計算機上使用 BCDEdit 所設定的值。

    WinDbg –k net:port=50000,key=2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
    
  7. 重新啟動目標系統。

  8. 在一兩分鐘內,偵錯輸出應該會顯示在主機系統上。

    Microsoft (R) Windows Debugger Version 10.0.17074.1002 AMD64
    Copyright (c) Microsoft Corporation. All rights reserved.
    
    Using NET for debugging
    Opened WinSock 2.0
    Waiting to reconnect...
    Connected to target 169.182.1.1 on port 50005 on local IP 169.182.1.2
    You can get the target MAC address by running .kdtargetmac command.
    Connected to Windows 10 16299 x64 target at (Wed Feb 28 17:16:23.051 2018 (UTC - 8:00)), ptr64 TRUE
    Kernel Debugger connection established.  (Initial Breakpoint requested)
    Symbol search path is: srv*
    Executable search path is: 
    Windows 10 Kernel Version 16299 MP (4 procs) Free x64
    Product: WinNt, suite: TerminalServer SingleUserTS
    Built by: 16299.15.amd64fre.rs3_release.170928-1534
    Machine Name:
    Kernel base = 0xfffff800`9540d000 PsLoadedModuleList = 0xfffff800`95774110
    Debug session time: Wed Feb 28 17:16:23.816 2018 (UTC - 8:00)
    System Uptime: 0 days 0:00:20.534
    

[調試程式命令] 視窗是 WinDbg 中的主要偵錯信息視窗。 您可以輸入除錯程式命令,並在此視窗中檢視命令輸出。

[調試程式命令] 視窗會分割成兩個窗格。 在較小的窗格中輸入命令,也就是視窗底部的命令進入窗格,並在視窗頂端的較大窗格中檢視命令輸出。

在命令進入窗格中,使用向上鍵和向下鍵捲動命令歷程記錄。 當命令出現時,您可以編輯命令,或按 Enter 來執行命令。

內核模式偵錯命令和技術

在本節中,使用偵錯命令來顯示目標系統的相關信息。

某些偵錯命令會使用調試程式標記語言 (DML) 顯示文字,您可以選取以快速收集詳細資訊。

  1. 在主機系統上,使用 WinDBg 中的 Ctrl+Scroll Lock 來中斷在目標系統上執行的程式代碼。 目標系統可能需要一些時間才能回應。

    調試程式中的主畫面,顯示即時核心連線的命令窗口輸出。

  2. 在 [除錯程式指令] 視窗中輸入下列命令以啟用 DML:

    0: kd> .prefer_dml 1
    DML versions of commands on by default
    
  3. 您可以使用 命令存取參考命令說明 .hh 。 輸入下列命令以檢視 的 .prefer_dml命令參考說明:

    0: kd> .hh .prefer_dml
    

    調試程序說明檔會顯示命令的說明 .prefer_dml

    調試程序說明應用程式的螢幕快照,其中顯示 .prefer-dml 命令的說明。

  4. 若要在目標系統上顯示詳細的版本資訊,請在 WinDbg 視窗中輸入 vertarget (顯示目標電腦版本) 命令:

    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
    
  5. 若要確認您使用的是正確的內核模式程式,請在 WinDbg 視窗中輸入 lm (List Loaded Modules) 命令,以顯示載入的模組:

    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
    ...
    

    省略的輸出會以 “...”在此實驗室中。

  6. 若要要求特定模組的詳細資訊,請使用 v (verbose) 選項:

    0: Kd> lm v m tcpip
    Browse full module list
    start             end                 module name
    fffff801`09eeb000 fffff801`0a157000   tcpip      (no symbols)           
        Loaded symbol image file: tcpip.sys
        Image path: \SystemRoot\System32\drivers\tcpip.sys
        Image name: tcpip.sys
        Browse all global symbols  functions  data
        Timestamp:        Sun Nov 09 18:59:03 2014 (546029F7)
        CheckSum:         00263DB1
        ImageSize:        0026C000
        Translations:     0000.04b0 0000.04e4 0409.04b0 0409.04e4
    
    Unable to enumerate user-mode unloaded modules, Win32 error 0n30
    

    沒有設定符號路徑和已載入的符號,因此調試程式中有有限的資訊可用。

下載並建置 KMDF 回應驅動程式

在本節中,下載並建置 KMDF 回應驅動程式。

一般而言,當您使用 WinDbg 時,您將會使用自己的驅動程式程式代碼。 為了熟悉 WinDbg 作業,此實驗室會使用 KMDF 範本 「Echo」 範例驅動程式。 原始程式碼可用來協助瞭解 WinDbg 中顯示的資訊。 此範例也可用來說明如何透過原生內核模式程式代碼進行單一步驟。 這項技術對於偵錯複雜的內核模式程式代碼問題來說可能很實用。

若要下載並建置 Echo 範例音訊驅動程式:

  1. 從 GitHub 下載並擷取 KMDF Echo 範例。

    KMDF Echo 範例位於 一般 資料夾中。

    GitHub windows-driver-samples 頁面的螢幕快照,其中醒目提示一般資料夾和下載 zip 按鈕。

    1. 在一個 zip 檔案中下載驅動程式範例: 驅動程式範例

    2. 將 zip 檔案下載到本機硬碟。

    3. 選取並按住或以滑鼠右鍵按兩下 zip 檔案,然後選取[ 全部解壓縮]。 指定新的資料夾,或瀏覽至現有的資料夾來儲存解壓縮的檔案。 例如,您可以將 C:\DriverSamples\ 指定為要在其中擷取檔案的新資料夾。

    4. 擷取檔案之後,請移至下列子資料夾: C:\DriverSamples\general\echo\kmdf

  2. 在 Microsoft Visual Studio 中,選取 [檔案>開啟>專案/方案...],然後移至包含解壓縮檔案的資料夾,例如 C:\DriverSamples\general\echo\kmdf。 按兩下 kmdfecho 方案檔案加以開啟。

    在 Visual Studio 中,找出 方案總管。 如果此視窗尚未開啟,請從[檢視] 功能選取 [方案總管]。 在 方案總管 中,您可以看到一個有三個項目的解決方案。

    Visual Studio 的螢幕快照,其中顯示從 kmdfecho 專案載入的 device.c 檔案。

  3. 設定範例的組態和平臺。 在 方案總管 中,選取並按住或以滑鼠右鍵按兩下 [方案 'kmdfecho' [3 個專案],然後選取 [Configuration Manager]。 請確定這三個專案的組態和平台設定都相同。 根據預設,組態會設定為 Win10 Debug,而平臺會針對所有項目設定為 Win64 。 如果您對一個項目進行任何組態或平台變更,請對其餘三個項目進行相同的變更。

  4. 驅動程式範例必須修改,才能使用未與現有驅動程式重疊的值。 請參閱從範例程式代碼到生產驅動程式 - 範例中要變更的內容,瞭解如何建立唯一的驅動程式範例,以與 Windows 中已安裝的現有實際驅動程式共存。

  5. 設定運行時間連結庫。 開啟 echo 驅動程式屬性頁,並找出 C/C++>Code Generation。 將運行時間連結庫變更為多線程偵錯 (/MTd)。 如需組建選項的詳細資訊,請參閱 /MD、/MT、/LD(使用運行時間連結庫)。

    Visual Studio 中 echo 屬性頁的螢幕快照,其中醒目提示運行時間連結庫設定。

  6. 在驅動程式屬性中,確定 [驅動程式簽署簽署>模式] 已設定為 [測試簽署]。

    Visual Studio 中 echo 屬性頁的螢幕快照,其中醒目提示簽署模式設定。

  7. 在 Visual Studio 中,選取 [建>置建置方案]。

    建置視窗應該會顯示訊息,指出這三個項目的組建都成功。

提示

如果您遇到組建錯誤訊息,請使用組建錯誤編號來判斷修正。 例如, MSBuild 錯誤MSB8040 描述如何使用可降低規格的連結庫。

  1. 在 檔案總管 中,移至包含範例解壓縮檔案的資料夾。 例如,如果這是您稍早指定的資料夾,請移至 C:\DriverSamples\general\echo\kmdf。 在該資料夾中,已編譯驅動程式檔案的位置會根據您在 Configuration Manager 中選取的組態和平台設定而有所不同。 如果您保留預設設定不變,則編譯的驅動程式檔案會儲存至名為 \x64\Debug 的資料夾,以供 64 位偵錯組建使用。

    移至包含自動同步驅動程式建置檔案的資料夾: C:\DriverSamples\general\echo\kmdf\driver\AutoSync\x64\Debug

    資料夾應該包含下列檔案:

    檔案 說明
    Echo.sys 驅動程式檔案。
    Echo.inf 資訊 (INF) 檔案,其中包含安裝驅動程式所需的資訊。

    此外, 已建置echoapp.exe 檔案,且應該位於此處: C:\DriverSamples\general\echo\kmdf\exe\x64\Debug

    檔案 說明
    EchoApp.exe 與echo.sys驅動程式通訊的命令提示字元可執行檔。
  2. 找出 USB 拇指磁碟驅動器,或設定網路共用,將建置的驅動程式檔案和測試 EchoApp 從主機複製到目標系統。

在下一節中,將程式代碼複製到目標系統,然後安裝及測試驅動程式。

在目標系統上安裝 KMDF 回應驅動程式範例

在本節中,使用 DevCon 工具來安裝回應範例驅動程式。

您安裝驅動程式的電腦稱為 目標電腦測試計算機。 一般而言,這部計算機與您開發及建置驅動程式套件的計算機不同。 您開發和建置驅動程式的計算機稱為 主計算機

將驅動程式套件移至目標計算機並安裝驅動程式的程式稱為 部署 驅動程式。

部署測試簽署驅動程式之前,請先啟用測試簽署來準備目標計算機。 您也需要在 WDK 安裝中找到 DevCon 工具,並將此工具複製到目標系統。

若要在目標系統上安裝驅動程式,請執行下列步驟。

在目標系統上,啟用測試簽署的驅動程式:

  1. 開啟 Windows 設定

  2. 在 [更新和安全性],選取 [復原]。

  3. 在 [進階啟動] 底下,選取 [立即重新啟動]。

  4. 當電腦重新啟動時,請選取 [ 啟動選項]。 在 Windows 10 中,選取 [疑難解答>進階選項>啟動] 設定 ,然後選取 [重新啟動]。

  5. 按 F7 鍵選取 [停用驅動程序簽章強制執行]。

  6. 重新啟動目標電腦。

在主機系統上,移至 WDK 安裝中的 [工具 ] 資料夾,並找出 DevCon 工具。 例如,請查看下列資料夾: C:\Program Files (x86)\Windows Kits\10\Tools\x64\devcon.exe

在建置驅動程式套件的目標上建立資料夾,例如 C:\EchoDriver。 將devcon.exe複製到目標系統。 在主機系統上找出 .cer 憑證。 它位於包含所建置驅動程式檔案之資料夾中主電腦上的相同資料夾中。 從先前在主計算機上所述的建置驅動程式複製所有檔案,並將其儲存至您在目標計算機上建立的相同資料夾。

在目標計算機上,選取並按住或以滑鼠右鍵單擊憑證檔案,然後選取 [安裝],然後遵循提示來安裝測試憑證。

如果您需要設定目標計算機的詳細指示,請參閱 準備計算機以進行手動驅動程式部署

下列指示說明如何安裝和測試範例驅動程式。 以下是用來安裝驅動程式之 devcon 工具的一般語法:

devcon install <INF file> <hardware ID>

安裝此驅動程式所需的 INF 檔案是 echo.inf。 inf 檔案包含安裝 echo.sys的硬體識別碼。 針對回應範例,硬體標識碼為 root\ECHO

在目標計算機上,以 管理員 istrator 開啟命令提示字元視窗。 移至驅動程式套件資料夾,然後輸入下列命令:

devcon install echo.inf root\ECHO

如果您收到無法辨識 devcon 的錯誤訊息,請嘗試將路徑新增至 devcon 工具。 例如,如果您將它複製到名為 C:\Tools 的資料夾,請嘗試使用下列命令:

c:\tools\devcon install echo.inf root\ECHO

此時會出現一個對話框,指出測試驅動程式是未簽署的驅動程式。 請選取 [ 無論如何 安裝此驅動程式] 繼續進行。

指出 Windows 無法驗證驅動程式軟體發行者的 Windows 安全性 警告螢幕快照。

提示

 如果您有安裝任何問題,請檢查下列檔案以取得詳細資訊。 %windir%\inf\setupapi.dev.log

成功安裝範例驅動程序之後,您就可以進行測試。

在目標計算機上,在 [命令提示字元] 視窗中,輸入 devmgmt 以開啟 裝置管理員。 在 [裝置管理員] 的 [檢視] 功能表上,依類型選擇 [裝置]。在裝置樹狀目錄中,於 [範例裝置] 節點中找到 [範例 WDF Echo Driver]。

醒目提示範例 WDF 回應驅動程式之 裝置管理員 樹狀結構的螢幕快照。

輸入 echoapp 以啟動測試回應應用程式,以確認驅動程式正常運作。

C:\Samples\KMDF_Echo_Sample> echoapp
DevicePath: \\?\root#sample#0005#{cdc35b6e-0be4-4936-bf5f-5537380a7c1a}
Opened device successfully
512 Pattern Bytes Written successfully
512 Pattern Bytes Read successfully
Pattern Verified successfully
30720 Pattern Bytes Written successfully
30720 Pattern Bytes Read successfully
Pattern Verified successfully

使用 WinDbg 來顯示驅動程式的相關信息

在本節中,設定符號路徑,並使用核心調試程式命令來顯示 KMDF 回應範例驅動程式的相關信息。

若要檢視驅動程序的相關信息:

  1. 在主機系統上,如果您關閉調試程式,請在系統管理員命令提示字元視窗中使用下列命令再次開啟它。

    WinDbg -k net:port=50000,key=2steg4fzbj2sz.23418vzkd4ko3.1g34ou07z4pev.1sp3yo9yz874p
    
  2. 使用 Ctrl+Break (Scroll Lock) 來中斷在目標系統上執行的程序代碼。

  3. 若要在 WinDbg 環境中將符號路徑設定為 Microsoft 符號伺服器,請使用 .symfix 命令。

    0: kd> .symfix
    
  4. 若要新增本機符號位置以使用本機符號,請使用 和 新增.reload /f路徑.sympath+

    0: kd> .sympath+ C:\DriverSamples\general\echo\kmdf
    0: kd> .reload /f
    

    具有 .reload force 選項的 /f 命令會刪除指定模組的所有符號資訊,並重載符號。 在某些情況下,此命令也會重載或卸除模組本身。

您必須載入適當的符號,才能使用 WinDbg 提供的進階功能。 如果您沒有正確設定符號,當您嘗試使用相依於符號的功能時,您會收到指出符號無法使用的訊息。

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

有許多方法可用來處理符號。 在許多情況下,您可以將計算機設定為從 Microsoft 在需要時提供的符號伺服器存取符號。 此實驗室會使用該方法。 如果環境中的符號位於不同的位置,請修改步驟以使用該位置。 如需詳細資訊,請參閱 Windows 調試程式的符號路徑。

若要執行來源偵錯,您必須建置已核取的二進位檔版本。 編譯程式會建立符號檔 (.pdb 檔案)。 這些符號檔會顯示調試程式二進位指令如何對應至來源行。 調試程式也必須能夠存取實際的原始程序檔本身。

符號檔不包含原始碼的文字。 若要進行偵錯,最好是連結器未優化您的程序代碼。 如果程式代碼已優化,來源偵錯和本機變數的存取會比較困難,有時幾乎是不可能的。 如果您在檢視局部變數或來源行時遇到問題,請設定下列建置選項:

set COMPILE_DEBUG=1
set ENABLE_OPTIMIZER=0
  1. 在調試程式的命令區域中輸入下列命令,以顯示響應驅動程式的相關信息:

    0: kd> lm m echo* v
    Browse full module list
    start             end                 module name
    fffff801`4ae80000 fffff801`4ae89000   ECHO       (private pdb symbols)  C:\Samples\KMDF_ECHO_SAMPLE\echo.pdb
        Loaded symbol image file: ECHO.sys
        Image path: \SystemRoot\system32\DRIVERS\ECHO.sys
        Image name: ECHO.sys
    ...  
    

    如需詳細資訊,請參閱 lm

  2. 由於此實驗室稍早設定 prefer_dml ,因此輸出的某些元素是您可以選取的熱門連結。 選取偵錯輸出中的 [ 流覽所有全域符號 ] 連結,以顯示以字母 “a” 開頭的專案符號相關信息。

    0: kd> x /D Echo!a*
    
  3. 回應範例不包含以字母 「a」 開頭的任何符號,因此輸入 x ECHO!Echo* 以顯示與以 「Echo」 開頭之響應驅動程式相關聯之所有符號的相關信息。

    0: kd> x ECHO!Echo*
    fffff801`0bf95690 ECHO!EchoEvtIoQueueContextDestroy (void *)
    fffff801`0bf95000 ECHO!EchoEvtDeviceSelfManagedIoStart (struct WDFDEVICE__ *)
    fffff801`0bf95ac0 ECHO!EchoEvtTimerFunc (struct WDFTIMER__ *)
    fffff801`0bf9b120 ECHO!EchoEvtDeviceSelfManagedIoSuspend (struct WDFDEVICE__ *)
    ...
    

    如需詳細資訊,請參閱 x(檢查符號)。

  4. 延伸 !lmi 模組會顯示模組的詳細資訊。 輸入 !lmi echo。 您的輸出應該類似此範例所示的文字:

    0: kd> !lmi echo
    Loaded Module Info: [echo] 
             Module: ECHO
       Base Address: fffff8010bf94000
         Image Name: ECHO.sys
    … 
    
  5. !dh使用 延伸模組來顯示標頭資訊,如下列範例所示:

    0: kd> !dh echo
    
    File Type: EXECUTABLE IMAGE
    FILE HEADER VALUES
         14C machine (i386)
           6 number of sections
    54AD8A42 time date stamp Wed Jan 07 11:34:26 2015
    ...
    
  6. 輸入下列命令來變更預設偵錯位掩碼,讓來自目標系統的所有偵錯訊息都會顯示在調試程式中:

    0: kd> ed nt!Kd_DEFAULT_MASK 0xFFFFFFFF
    

    某些驅動程式會在使用0xFFFFFFFF遮罩時顯示其他資訊。 如果您想要減少顯示的資訊量,請將遮罩設定為0x00000000。

    0: kd> ed nt!Kd_DEFAULT_MASK 0x00000000
    

    dd使用 命令來確認遮罩已設定為顯示所有調試程式訊息。

    0: kd> dd nt!kd_DEFAULT_MASK 
    fffff802`bb4057c0  ffffffff 00000000 00000000 00000000
    fffff802`bb4057d0  00000000 00000000 00000000 00000000
    fffff802`bb4057e0  00000001 00000000 00000000 00000000
    fffff802`bb4057f0  00000000 00000000 00000000 00000000
    fffff802`bb405800  00000000 00000000 00000000 00000000
    fffff802`bb405810  00000000 00000000 00000000 00000000
    fffff802`bb405820  00000000 00000000 00000000 00000000
    fffff802`bb405830  00000000 00000000 00000000 00000000
    

顯示 隨插即用 裝置樹狀結構資訊

在本節中,顯示回應範例設備驅動器的相關信息,以及其位於 隨插即用 裝置樹狀結構中的位置。

隨插即用 裝置樹狀結構中裝置驅動程式的相關信息對於疑難解答很有用。 例如,如果設備驅動器不在裝置樹狀結構中,則裝置驅動程式的安裝可能會發生問題。

如需裝置節點偵錯延伸模組的詳細資訊,請參閱 !devnode

  1. 在主機系統上,若要查看 隨插即用 裝置樹狀目錄中的所有裝置節點,請輸入 !devnode 0 1 命令。

    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 在產生的輸出中搜尋,以尋找設備驅動器的名稱回應

    WinDbg 中搜尋 'echo' 一詞的 [尋找] 對話框螢幕快照。

  3. 應載入回應裝置驅動程式。 !devnode 0 1 echo使用 命令來顯示與回應設備驅動器相關聯的 隨插即用 資訊,如下列範例所示:

    0: Kd> !devnode 0 1 echo
    Dumping IopRootDeviceNode (= 0xffffe0007b725d30)
    DevNode 0xffffe0007b71a630 for PDO 0xffffe0007b71a960
      InstancePath is "ROOT\SAMPLE\0000"
      ServiceName is "ECHO"
      State = DeviceNodeStarted (0x308)
      Previous State = DeviceNodeEnumerateCompletion (0x30d)
    …
    
  4. 上一個命令中顯示的輸出包含與驅動程式執行中實例相關聯的 PDO,在此範例中為 0xffffe0007b71a960!devobj <PDO address>輸入 命令以顯示與回應設備驅動器相關聯的 隨插即用 資訊。 使用計算機上顯示的 PDO 位址,而不是此處顯示的位址 !devnode

    0: kd> !devobj 0xffffe0007b71a960
    Device object (ffffe0007b71a960) is for:
     0000000e \Driver\PnpManager DriverObject ffffe0007b727e60
    Current Irp 00000000 RefCount 0 Type 00000004 Flags 00001040
    Dacl ffffc102c9b36031 DevExt 00000000 DevObjExt ffffe0007b71aab0 DevNode ffffe0007b71a630 
    ExtensionFlags (0x00000800)  DOE_DEFAULT_SD_PRESENT
    Characteristics (0x00000180)  FILE_AUTOGENERATED_DEVICE_NAME, FILE_DEVICE_SECURE_OPEN
    AttachedDevice (Upper) ffffe000801fee20 \Driver\ECHO
    Device queue is not busy.
    
  5. 命令中顯示的 !devnode 0 1 輸出包含與驅動程式執行中實例相關聯的 PDO 位址,在此範例中為 0xffffe0007b71a960!devstack <PDO address>輸入 命令以顯示與設備驅動器相關聯的 隨插即用 資訊。 使用計算機上顯示的 PDO 位址,而不是此範例中顯示的位址 !devnode

    0: kd> !devstack 0xffffe0007b71a960
      !DevObj           !DrvObj            !DevExt           ObjectName
      ffffe000801fee20  \Driver\ECHO       ffffe0007f72eff0  
    > ffffe0007b71a960  \Driver\PnpManager 00000000  0000000e
    !DevNode ffffe0007b71a630 :
      DeviceInst is "ROOT\SAMPLE\0000"
      ServiceName is "ECHO"
    

輸出會顯示您有相當簡單的設備驅動器堆疊。 響應驅動程式是 PnPManager 節點的子系。 PnPManager 是根節點。

\Driver\ECHO
\Driver\PnpManager

此圖顯示更複雜的裝置節點樹狀結構。

說明由大約 20 個節點組成的裝置節點樹狀結構的圖表。

如需更多複雜驅動程式堆疊的詳細資訊,請參閱 驅動程式堆疊裝置節點和裝置堆疊

使用斷點和原始程式碼

在本節中,設定斷點,並透過內核模式原始程式碼進行單一步驟。

若要能夠逐步執行程式碼並即時檢查變數的值,請啟用斷點並設定原始碼的路徑。

斷點會在特定程式代碼行停止程式代碼執行。 從該點往前逐步執行程序代碼,以偵錯該程式代碼的特定區段。

若要使用偵錯命令設定斷點,請使用下列 b 其中一個命令。

Command 描述
bp 設定作用中的斷點,直到卸除其位於 的模組為止。
bu 設定在卸除模組時無法解析的斷點,並在模組重載時重新啟用。
bm 設定符號的斷點。 此命令會使用 bubp 適當地,並允許使用通配符 (*) 在符合的每個符號上設定斷點,就像類別中的所有方法一樣。

如需詳細資訊,請參閱 WinDbg 中的原始程式碼偵錯。

  1. 在主機系統上,使用 WinDbg UI 確認>目前 WinDbg 工作階段中已啟用偵錯來源模式。

  2. 輸入下列命令,將本機程式代碼位置新增至來源路徑:

    .srcpath+ C:\DriverSamples\KMDF_Echo_Sample\driver\AutoSync
    
  3. 輸入下列命令,將本機符號位置新增至符號路徑:

    .sympath+ C:\DriverSamples\KMDF_Echo_Sample\driver\AutoSync
    
  4. x使用 命令來檢查與響應驅動程式相關聯的符號,以判斷要用於斷點的函式名稱。 您可以使用通配符或 Ctrl+F 來尋找函 DeviceAdd 式名稱。

    0: kd> x ECHO!EchoEvt*
    8b4c7490          ECHO!EchoEvtIoQueueContextDestroy (void *)
    8b4c7000          ECHO!EchoEvtDeviceSelfManagedIoStart (struct WDFDEVICE__ *)
    8b4c7820          ECHO!EchoEvtTimerFunc (struct WDFTIMER__ *)
    8b4cb0e0          ECHO!EchoEvtDeviceSelfManagedIoSuspend (struct WDFDEVICE__ *)
    8b4c75d0          ECHO!EchoEvtIoWrite (struct WDFQUEUE__ *, struct WDFREQUEST__ *, unsigned int)
    8b4cb170          ECHO!EchoEvtDeviceAdd (struct WDFDRIVER__ *, struct 
    …
    

    輸出顯示 DeviceAdd 回應驅動程式的方法為 ECHO!EchoEvtDeviceAdd

    或者,請檢閱原始程式碼,以尋找斷點的函式名稱。

  5. 使用驅動程式的名稱設定斷點 bm ,後面接著函式名稱,例如 AddDevice,您想要設定斷點,並以驚嘆號分隔。 此實驗室會使用 AddDevice 來監看載入的驅動程式。

    0: kd> bm ECHO!EchoEvtDeviceAdd
      1: fffff801`0bf9b1c0 @!"ECHO!EchoEvtDeviceAdd"
    

    您可以搭配使用不同的語法來設定 、、 或 等變數<module>!<symbol>,或略過多次 <condition> <#>'<file.cpp>:<line number>'<class>::<method> 如需詳細資訊,請參閱 WinDbg 和其他 Windows 調試程式中的條件式斷點。

  6. 列出目前的斷點,藉由輸入 bl 命令來確認已設定斷點:

    0: kd> bl
    1 e fffff801`0bf9b1c0     0001 (0001) ECHO!EchoEvtDeviceAdd
    

    此處所示輸出中的 「e」 表示已啟用斷點數位 1 來引發。

  7. 輸入 g (go) 命令,以重新啟動目標系統上的程式碼執行。

  8. 在目標系統上,在 Windows 中,使用圖示開啟 裝置管理員,或輸入 mmc devmgmt.msc。 在 裝置管理員 中,展開 [範例] 節點。

  9. 選取並按住或以滑鼠右鍵按下 KMDF 回應驅動程式項目,然後從功能表中選取 [ 停用 ]。

  10. 再次選取並按住或以滑鼠右鍵按下 KMDF 回應驅動程式項目,然後從功能表中選取 [ 啟用 ]。

  11. 在主機系統上,啟用驅動程式時, 應該引發 AddDevice 偵錯斷點。 目標系統上的驅動程式程式代碼執行應該會停止。 叫用斷點時,應該在 AddDevice 例程的開頭停止執行。 偵錯指令輸出會顯示 Breakpoint 1 hit

    顯示範例程式代碼局部變數和命令視窗的 WinDbg 螢幕快照。

  12. 輸入 命令或按 F10 逐行p逐步執行程式代碼行,直到您到達 AddDevice 例程的下列結尾為止。 大括號字元 (}) 會反白顯示,如下所示。

    程式代碼視窗的螢幕快照,其中在 AddDevice 例程開頭反白顯示大括號字元。

在下一節中,檢查 DeviceAdd 程式代碼執行之後變數的狀態。

您可以使用下列命令來修改現有的斷點:

Command 描述
bl 列出斷點。
bc 從清單中清除斷點。 使用 bc * 來清除所有斷點。
bd 停用斷點。 使用 bd * 停用所有斷點。
be 啟用斷點。 使用 be * 來啟用所有斷點。

或者,您也可以修改 WinDbg UI 中的斷點。

您也可以設定在存取記憶體位置時引發的斷點。 使用 [ ba 存取中斷] 命令,語法如下:

ba <access> <size> <address> {options}
選項 描述
e execute:當 CPU 從位址擷取指令時
r 讀取/寫入:當 CPU 讀取或寫入位址時
w write:當 CPU 寫入位址時

您隨時只能設定四個數據斷點。 您必須確定您已正確對齊數據,以觸發斷點。 單字必須以 2 分隔的地址結尾,dword 必須以 4 除,而四個字必須以 0 或 8 來分隔。

例如,若要在特定記憶體位址上設定讀取/寫入斷點,您可以使用類似此範例的命令。

ba r 4 0x0003f7bf0

您可以使用下列命令,透過括弧中顯示的相關聯鍵盤快捷方式逐步執行程序代碼。

  • 中斷 (Ctrl+Break)。 只要系統正在執行且與 WinDbg 通訊,此命令會中斷系統。 內核調試程式中的序列為 Ctrl+C。
  • 執行至游標 (F7 或 Ctrl+F10)。 將游標放在您想要執行中斷的來源或反組譯碼視窗中,然後按 F7。 程式代碼執行會執行至該點。 如果程式代碼執行流程未到達數據指標所指出的點,WinDbg 就不會中斷。 如果未執行 IF 語句,就可能發生這種情況。
  • 執行 (F5)。 執行直到遇到斷點或發生錯誤檢查之類的事件為止。
  • 跳過 (F10) 。 此命令會讓程式代碼執行一次繼續一個語句或一個指令。 如果遇到呼叫,程式代碼執行會經過呼叫,而不需要輸入呼叫的例程。 如果程式設計語言為 C 或 C++ 且 WinDbg 處於來源模式,則可以使用>偵錯來源模式來開啟或關閉來源模式。
  • 步驟 (F11)。 此命令就像逐步執行,不同之處在於呼叫的執行會進入呼叫例程。
  • 跳出 (Shift+F11)。 此命令會執行 至呼叫堆疊中目前的例程或目前位置,並結束。 如果您已看到足夠的例程,此命令就很有用。

如需詳細資訊,請參閱 WinDbg 中的原始程式碼偵錯。

檢視變數和呼叫堆疊

在本節中,顯示變數和呼叫堆疊的相關信息。

此實驗室假設您已使用稍早所述的程式,在 AddDevice 例程停止。 若要檢視此處顯示的輸出,請視需要重複先前所述的步驟。

在主系統上,若要顯示變數,請使用檢視>本機功能表項來顯示局部變數。

顯示局部變數視窗的 WinDbg 螢幕快照。

若要尋找全域變數位址的位置,請輸入 ? <variable name>

  • 跳出 (Shift+F11) - 此命令會執行到目前的例程,並從目前的例程結束(呼叫堆棧中的目前位置)。 如果您已經看到足夠的例程,這會很有用。

如需詳細資訊,請參閱 偵錯參考檔中的 WinDbg (傳統) 原始程式碼偵錯。

第8節:檢視變數和呼叫堆疊

在第 8 節中,您將顯示變數和呼叫堆疊的相關信息。

此實驗室假設您已使用稍早所述的程式,在 AddDevice 例程上停止。 若要檢視此處顯示的輸出,請視需要重複先前所述的步驟。

<- 在主機系統上

顯示變數

使用檢視>本機功能表項來顯示局部變數。

顯示局部變數視窗的 WinDbg 螢幕快照。

全域變數

您可以輸入 來尋找全域變數位址的位置? <變數名稱>

局部變數

您可以輸入 dv 命令,顯示指定框架之所有局部變數的名稱和值。 若要顯示特定框架之所有局部變數的名稱和值,請輸入 dv 命令:

0: kd> dv
         Driver = 0x00001fff`7ff9c838
     DeviceInit = 0xffffd001`51978190
         status = 0n0

呼叫堆疊是導致程式計數器目前位置的函式呼叫鏈結。 呼叫堆疊上的頂端函式是目前的函式,而下一個函式是呼叫目前函式的函式,依此命名。

若要顯示呼叫堆疊,請使用 k* 命令。

Command 描述
kb 顯示堆疊和前三個參數。
kp 顯示堆疊和參數的完整清單。
kn 可讓您查看堆疊,其中包含其旁的框架資訊。
  1. 在主機系統上,如果您想要保留可用的呼叫堆疊,請選取檢視>呼叫堆疊以檢視它。 選取視窗頂端的數據行,以切換顯示其他資訊。

    顯示呼叫堆疊視窗的 WinDbg 螢幕快照。

  2. kn使用 命令,在偵錯處於中斷狀態的範例配接器程式代碼時顯示呼叫堆疊。

    3: kd> kn
    # Child-SP          RetAddr           Call Site
    00 ffffd001`51978110 fffff801`0942f55b ECHO!EchoEvtDeviceAdd+0x66 [c:\Samples\kmdf echo sample\c++\driver\autosync\driver.c @ 138]
    01 (Inline Function) --------`-------- Wdf01000!FxDriverDeviceAdd::Invoke+0x30 [d:\wbrtm\minkernel\wdf\framework\shared\inc\private\common\fxdrivercallbacks.hpp @ 61]
    02 ffffd001`51978150 fffff801`eed8097d Wdf01000!FxDriver::AddDevice+0xab [d:\wbrtm\minkernel\wdf\framework\shared\core\km\fxdriverkm.cpp @ 72]
    03 ffffd001`51978570 fffff801`ef129423 nt!PpvUtilCallAddDevice+0x35 [d:\9142\minkernel\ntos\io\pnpmgr\verifier.c @ 104]
    04 ffffd001`519785b0 fffff801`ef0c4112 nt!PnpCallAddDevice+0x63 [d:\9142\minkernel\ntos\io\pnpmgr\enum.c @ 7397]
    05 ffffd001`51978630 fffff801`ef0c344f nt!PipCallDriverAddDevice+0x6e2 [d:\9142\minkernel\ntos\io\pnpmgr\enum.c @ 3390]
    ...
    

呼叫堆疊會顯示呼叫至 隨插即用 程式代碼 (PnP) 的核心 (nt), 稱為驅動程式架構程式代碼 (WDF) 之後呼叫 echo 驅動程式函DeviceAdd式。

顯示進程和線程

在本節中,顯示核心模式中執行之進程和線程的相關信息。

程序

您可以使用 !process 調試程式延伸模組來顯示或設定行程資訊。 設定斷點來檢查播放音效時所使用的程式。

  1. 在主機系統上,輸入 dv 命令來檢查與 EchoEvtIo 例程相關聯的地區設定變數:

    0: kd> dv ECHO!EchoEvtIo*
    ECHO!EchoEvtIoQueueContextDestroy
    ECHO!EchoEvtIoWrite
    ECHO!EchoEvtIoRead         
    
  2. 使用 bc *清除先前的斷點:

    0: kd> bc *  
    
  3. 使用下列命令在 EchoEvtIo 例程上設定符號斷點:

    0: kd> bm ECHO!EchoEvtIo*
      2: aade5490          @!”ECHO!EchoEvtIoQueueContextDestroy”
      3: aade55d0          @!”ECHO!EchoEvtIoWrite”
      4: aade54c0          @!”ECHO!EchoEvtIoRead”
    
  4. 列出斷點,以確認斷點已正確設定:

    0: kd> bl
    1 e aabf0490 [c:\Samples\kmdf echo sample\c++\driver\autosync\queue.c @ 197]    0001 (0001) ECHO!EchoEvtIoQueueContextDestroy
    ...
    
  5. 輸入 g 重新啟動程式代碼執行:

    0: kd> g
    
  6. 在目標系統上,在 EchoApp.exe 目標系統上執行驅動程式測試程式。

  7. 在主機系統上,當測試應用程式執行時,會呼叫驅動程式中的 I/O 例程。 此呼叫會導致斷點引發,並在目標系統上執行驅動程式程式代碼會停止。

    Breakpoint 2 hit
    ECHO!EchoEvtIoWrite:
    fffff801`0bf95810 4c89442418      mov     qword ptr [rsp+18h],r8
    
  8. !process使用 命令來顯示執行echoapp.exe所涉及的目前進程:

    0: kd> !process
    PROCESS ffffe0007e6a7780
        SessionId: 1  Cid: 03c4    Peb: 7ff7cfec4000  ParentCid: 0f34
        DirBase: 1efd1b000  ObjectTable: ffffc001d77978c0  HandleCount:  34.
        Image: echoapp.exe
        VadRoot ffffe000802c79f0 Vads 30 Clone 0 Private 135. Modified 5. Locked 0.
        DeviceMap ffffc001d83c6e80
        Token                             ffffc001cf270050
        ElapsedTime                       00:00:00.052
        UserTime                          00:00:00.000
        KernelTime                        00:00:00.000
        QuotaPoolUsage[PagedPool]         33824
        QuotaPoolUsage[NonPagedPool]      4464
        Working Set Sizes (now,min,max)  (682, 50, 345) (2728KB, 200KB, 1380KB)
        PeakWorkingSetSize                652
        VirtualSize                       16 Mb
        PeakVirtualSize                   16 Mb
        PageFaultCount                    688
        MemoryPriority                    BACKGROUND
        BasePriority                      8
        CommitCharge                      138
    
            THREAD ffffe00080e32080  Cid 03c4.0ec0  Teb: 00007ff7cfece000 Win32Thread: 0000000000000000 RUNNING on processor 1
    

    輸出顯示進程與 叫用驅動程式寫入事件上的斷點時所執行的echoapp.exe 線程相關聯。 如需詳細資訊,請參閱 !process

  9. !process 0 0使用 來顯示所有進程的摘要資訊。 在輸出中,使用 Ctrl+F 來尋找與 echoapp.exe 影像相關聯之進程的相同進程位址。 在這裡範例中,行程位址為 ffffe0007e6a7780

    ...
    
    PROCESS ffffe0007e6a7780
        SessionId: 1  Cid: 0f68    Peb: 7ff7cfe7a000  ParentCid: 0f34
        DirBase: 1f7fb9000  ObjectTable: ffffc001cec82780  HandleCount:  34.
        Image: echoapp.exe
    
    ...
    
  10. 記錄與 echoapp.exe 相關聯的進程標識符,以供本實驗室稍後使用。 您也可以使用 Ctrl+C 將位址複製到複製緩衝區,以供稍後使用。

    _____________________________________________________(echoapp.exe行程位址)

  11. 在調試程式中視需要輸入 g ,以向前執行程序代碼,直到 echoapp.exe 完成執行為止。 它會多次叫用讀取和寫入事件中的斷點。 當echoapp.exe完成時,請按 Ctrl+ScrLk (Ctrl+Break) 以進入調試程式。

  12. !process使用 命令來確認您正在執行不同的進程。 在此顯示的輸出中,系統影像值的程式與 Echo Image 值不同

    1: kd> !process
    PROCESS ffffe0007b65d900
        SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
        DirBase: 001ab000  ObjectTable: ffffc001c9a03000  HandleCount: 786.
        Image: System
        VadRoot ffffe0007ce45930 Vads 14 Clone 0 Private 22. Modified 131605. Locked 64.
        DeviceMap ffffc001c9a0c220
        Token                             ffffc001c9a05530
        ElapsedTime                       21:31:02.516
    ...
    

    輸出顯示當您停止 OS 時,系統進程 ffffe0007b65d900 正在執行。

  13. !process使用 命令嘗試查看與您先前記錄echoapp.exe相關聯的進程標識碼。 提供您稍早記錄的echoapp.exe進程位址,而不是此範例中顯示的範例進程位址。

    0: kd> !process ffffe0007e6a7780
    TYPE mismatch for process object at 82a9acc0
    

    進程物件已無法使用,因為 echoapp.exe 進程不再執行。

執行緒

用來檢視和設定線程的命令類似於進程的命令。 使用 !thread 命令來檢視線程。 使用 .thread 來設定目前的線程。

  1. 在主機系統上,輸入 g 調試程式以重新啟動目標系統上的程式代碼執行。

  2. 在目標系統上,執行EchoApp.exe驅動程式測試程式。

  3. 在主機系統上,會叫用斷點並停止程式代碼執行。

    Breakpoint 4 hit
    ECHO!EchoEvtIoRead:
    aade54c0 55              push    ebp
    
  4. 若要檢視正在執行的線程,請輸入 !thread。 應該會顯示類似下列範例的資訊:

    0: kd>  !thread
    THREAD ffffe000809a0880  Cid 0b28.1158  Teb: 00007ff7d00dd000 Win32Thread: 0000000000000000 RUNNING on processor 0
    IRP List:
        ffffe0007bc5be10: (0006,01f0) Flags: 00060a30  Mdl: 00000000
    Not impersonating
    DeviceMap                 ffffc001d83c6e80
    Owning Process            ffffe0008096c900       Image:         echoapp.exe
    ...
    

    請注意echoapp.exe影像名稱。 這表示您正在查看與測試應用程式相關聯的線程。

  5. !process使用 命令來判斷此線程是否是唯一在與echoapp.exe相關聯的進程中執行的線程。 進程中執行中線程的線程數目與命令所顯示的線程 !thread 相同。

    0: kd> !process
    PROCESS ffffe0008096c900
        SessionId: 1  Cid: 0b28    Peb: 7ff7d00df000  ParentCid: 0f34
        DirBase: 1fb746000  ObjectTable: ffffc001db6b52c0  HandleCount:  34.
        Image: echoapp.exe
        VadRoot ffffe000800cf920 Vads 30 Clone 0 Private 135. Modified 8. Locked 0.
        DeviceMap ffffc001d83c6e80
        Token                             ffffc001cf5dc050
        ElapsedTime                       00:00:00.048
        UserTime                          00:00:00.000
        KernelTime                        00:00:00.000
        QuotaPoolUsage[PagedPool]         33824
        QuotaPoolUsage[NonPagedPool]      4464
        Working Set Sizes (now,min,max)  (681, 50, 345) (2724KB, 200KB, 1380KB)
        PeakWorkingSetSize                651
        VirtualSize                       16 Mb
        PeakVirtualSize                   16 Mb
        PageFaultCount                    686
        MemoryPriority                    BACKGROUND
        BasePriority                      8
        CommitCharge                      138
    
            THREAD ffffe000809a0880  Cid 0b28.1158  Teb: 00007ff7d00dd000 Win32Thread: 0000000000000000 RUNNING on processor 0
    
  6. !process 0 0使用 命令來找出兩個相關進程的進程位址,並在這裏記錄這些進程位址。

    Cmd.exe:____________________________________________________________

    EchoApp.exe:_______________________________________________________

    0: kd> !process 0 0 
    
    …
    
    PROCESS ffffe0007bbde900
        SessionId: 1  Cid: 0f34    Peb: 7ff72dfa7000  ParentCid: 0c64
        DirBase: 19c5fa000  ObjectTable: ffffc001d8c2f300  HandleCount:  31.
        Image: cmd.exe
    …
    PROCESS ffffe0008096c900
        SessionId: 1  Cid: 0b28    Peb: 7ff7d00df000  ParentCid: 0f34
        DirBase: 1fb746000  ObjectTable: ffffc001db6b52c0  HandleCount:  34.
        Image: echoapp.exe
    …
    

    您也可以使用 !process 0 17 來顯示每個程式的詳細資訊。 此命令的輸出可能很長。 您可以使用 Ctrl+F 來搜尋輸出。

  7. !process使用 命令來列出執行電腦之兩個進程的處理程序資訊。 提供 !process 0 0 輸出中的進程位址,而不是此範例中顯示的位址。

    此範例輸出適用於 先前記錄的 cmd.exe進程標識碼。 此進程識別碼的映像名稱cmd.exe

    0: kd>  !process ffffe0007bbde900
    PROCESS ffffe0007bbde900
        SessionId: 1  Cid: 0f34    Peb: 7ff72dfa7000  ParentCid: 0c64
        DirBase: 19c5fa000  ObjectTable: ffffc001d8c2f300  HandleCount:  31.
        Image: cmd.exe
        VadRoot ffffe0007bb8e7b0 Vads 25 Clone 0 Private 117. Modified 20. Locked 0.
        DeviceMap ffffc001d83c6e80
        Token                             ffffc001d8c48050
        ElapsedTime                       21:33:05.840
        UserTime                          00:00:00.000
        KernelTime                        00:00:00.000
        QuotaPoolUsage[PagedPool]         24656
        QuotaPoolUsage[NonPagedPool]      3184
        Working Set Sizes (now,min,max)  (261, 50, 345) (1044KB, 200KB, 1380KB)
        PeakWorkingSetSize                616
        VirtualSize                       2097164 Mb
        PeakVirtualSize                   2097165 Mb
        PageFaultCount                    823
        MemoryPriority                    FOREGROUND
        BasePriority                      8
        CommitCharge                      381
    
            THREAD ffffe0007cf34880  Cid 0f34.0f1c  Teb: 00007ff72dfae000 Win32Thread: 0000000000000000 WAIT: (UserRequest) UserMode Non-Alertable
                ffffe0008096c900  ProcessObject
            Not impersonating
    ...
    

    此範例輸出適用於 先前記錄的 echoapp.exe進程標識碼。

    0: kd>  !process ffffe0008096c900
    PROCESS ffffe0008096c900
        SessionId: 1  Cid: 0b28    Peb: 7ff7d00df000  ParentCid: 0f34
        DirBase: 1fb746000  ObjectTable: ffffc001db6b52c0  HandleCount:  34.
        Image: echoapp.exe
        VadRoot ffffe000800cf920 Vads 30 Clone 0 Private 135. Modified 8. Locked 0.
        DeviceMap ffffc001d83c6e80
        Token                             ffffc001cf5dc050
        ElapsedTime                       00:00:00.048
        UserTime                          00:00:00.000
        KernelTime                        00:00:00.000
        QuotaPoolUsage[PagedPool]         33824
        QuotaPoolUsage[NonPagedPool]      4464
        Working Set Sizes (now,min,max)  (681, 50, 345) (2724KB, 200KB, 1380KB)
        PeakWorkingSetSize                651
        VirtualSize                       16 Mb
        PeakVirtualSize                   16 Mb
        PageFaultCount                    686
        MemoryPriority                    BACKGROUND
        BasePriority                      8
        CommitCharge                      138
    
            THREAD ffffe000809a0880  Cid 0b28.1158  Teb: 00007ff7d00dd000 Win32Thread: 0000000000000000 RUNNING on processor 0
            IRP List:
                ffffe0007bc5be10: (0006,01f0) Flags: 00060a30  Mdl: 00000000
            Not impersonating
    ...
    
  8. 在此記錄與兩個進程相關聯的第一個線程位址。

    Cmd.exe:____________________________________________________

    EchoApp.exe:_________________________________________________

  9. !Thread使用 命令來顯示目前線程的相關信息。

    0: kd>  !Thread
    THREAD ffffe000809a0880  Cid 0b28.1158  Teb: 00007ff7d00dd000 Win32Thread: 0000000000000000 RUNNING on processor 0
    IRP List:
        ffffe0007bc5be10: (0006,01f0) Flags: 00060a30  Mdl: 00000000
    Not impersonating
    DeviceMap                 ffffc001d83c6e80
    Owning Process            ffffe0008096c900       Image:         echoapp.exe
    Attached Process          N/A            Image:         N/A
    ...
    

    如預期般,目前的線程是與 echoapp.exe 相關聯的線程,且處於執行中狀態。

  10. !Thread使用 命令來顯示與cmd.exe進程相關聯的線程相關信息。 提供您稍早記錄的線程位址。

    0: kd> !Thread ffffe0007cf34880
    THREAD ffffe0007cf34880  Cid 0f34.0f1c  Teb: 00007ff72dfae000 Win32Thread: 0000000000000000 WAIT: (UserRequest) UserMode Non-Alertable
        ffffe0008096c900  ProcessObject
    Not impersonating
    DeviceMap                 ffffc001d83c6e80
    Owning Process            ffffe0007bbde900       Image:         cmd.exe
    Attached Process          N/A            Image:         N/A
    Wait Start TickCount      4134621        Ticks: 0
    Context Switch Count      4056           IdealProcessor: 0             
    UserTime                  00:00:00.000
    KernelTime                00:00:01.421
    Win32 Start Address 0x00007ff72e9d6e20
    Stack Init ffffd0015551dc90 Current ffffd0015551d760
    Base ffffd0015551e000 Limit ffffd00155518000 Call 0
    Priority 14 BasePriority 8 UnusualBoost 3 ForegroundBoost 2 IoPriority 2 PagePriority 5
    Child-SP          RetAddr           : Args to Child                                                           : Call Site
    ffffd001`5551d7a0 fffff801`eed184fe : fffff801`eef81180 ffffe000`7cf34880 00000000`fffffffe 00000000`fffffffe : nt!KiSwapContext+0x76 [d:\9142\minkernel\ntos\ke\amd64\ctxswap.asm @ 109]
    ffffd001`5551d8e0 fffff801`eed17f79 : ffff03a5`ca56a3c8 000000de`b6a6e990 000000de`b6a6e990 00007ff7`d00df000 : nt!KiSwapThread+0x14e [d:\9142\minkernel\ntos\ke\thredsup.c @ 6347]
    ffffd001`5551d980 fffff801`eecea340 : ffffd001`5551da18 00000000`00000000 00000000`00000000 00000000`00000388 : nt!KiCommitThreadWait+0x129 [d:\9142\minkernel\ntos\ke\waitsup.c @ 619]
    ...
    

    此線程與 cmd.exe相關聯, 且處於等候狀態。

  11. 提供等候 CMD.exe 線程的線程位址,以將內容變更為該等候線程。

    0: kd> .Thread ffffe0007cf34880
    Implicit thread is now ffffe000`7cf34880
    
  12. k使用 命令來檢視與等候線程相關聯的呼叫堆疊。

    0: kd> k
      *** Stack trace for last set context - .thread/.cxr resets it
    # Child-SP          RetAddr           Call Site
    00 ffffd001`5551d7a0 fffff801`eed184fe nt!KiSwapContext+0x76 [d:\9142\minkernel\ntos\ke\amd64\ctxswap.asm @ 109]
    01 ffffd001`5551d8e0 fffff801`eed17f79 nt!KiSwapThread+0x14e [d:\9142\minkernel\ntos\ke\thredsup.c @ 6347]
    02 ffffd001`5551d980 fffff801`eecea340 nt!KiCommitThreadWait+0x129 [d:\9142\minkernel\ntos\ke\waitsup.c @ 619]
    03 ffffd001`5551da00 fffff801`ef02e642 nt!KeWaitForSingleObject+0x2c0 [d:\9142\minkernel\ntos\ke\wait.c @ 683]
    ...
    

    呼叫堆棧專案,例如 KiCommitThreadWait ,表示此線程未如預期般執行。

如需線程和進程的詳細資訊,請參閱下列參考:

IRQL、註冊和結束 WinDbg 工作階段

在本節中,顯示中斷要求層級 (IRQL) 和緩存器的內容。

檢視儲存的 IRQL

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

或者,您可以選取 [檢視>緩存器] 來顯示緩存器的內容。 如需詳細資訊,請參閱 r (Registers)

在逐步執行元件語言程式代碼執行和其他案例時,檢視緩存器的內容會很有説明。 如需彙編語言反組譯碼的詳細資訊,請參閱批注 x86 反組譯碼和批註 x64 反組譯碼。

如需快取器內容的相關信息,請參閱 x86 架構x64 架構

結束 WinDbg 工作階段

如果您想要讓調試程式保持附加,但想要在目標上運作,請使用 清除任何斷點 bc *,讓目標計算機不會嘗試連線到主計算機調試程式。 g然後使用 命令讓目標計算機再次執行。

若要結束偵錯會話,請在主機系統上中斷調試程式,然後輸入 qd (Quit and Detach) 命令,或從功能表中選取 [ 停止偵錯 ]。

0: kd> qd

如需詳細資訊,請參閱 在 WinDbg 中結束偵錯會話。

Windows 偵錯資源

如需詳細資訊,請於 Windows 偵錯中取得。 其中一些書籍在範例中使用舊版的 Windows,例如 Windows Vista,但所討論的概念適用於大部分版本的 Windows。

另請參閱