偵錯驅動程式 - 逐步實驗室 (Sysvad 核心模式)

此實驗室提供實際操作練習,示範如何偵錯 Sysvad 音訊核心模式設備驅動器。

Microsoft Windows 調試程式 (WinDbg) 是功能強大的 Windows 偵錯工具,可用來執行使用者模式和內核模式偵錯。 WinDbg 提供 Windows 核心、內核模式驅動程式和系統服務,以及使用者模式應用程式和驅動程式的來源層級偵錯。

WinDbg 可以逐步執行原始碼、設定斷點、檢視變數(包括 C++ 物件)、堆疊追蹤和記憶體。 其 [調試程式命令] 視窗可讓使用者發出各種不同的命令。

實驗室設定

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

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

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

  • Microsoft Visual Studio 2017
  • 適用於 Windows 10 的 Windows 軟體開發工具套件 (SDK)
  • 適用於 Windows 10 的 Windows 驅動程式套件 (WDK)
  • 適用於 Windows 10 的 Sysvad 音訊驅動程式範例

如需下載及安裝 WDK 的相關資訊,請參閱 下載 Windows 驅動程式套件 (WDK)

Sysvad 偵錯逐步解說

此實驗室會逐步引導您完成偵錯內核模式驅動程式的程式。 練習會使用 Syvad 虛擬音訊驅動程式範例。 由於 Syvad 音訊驅動程式不會與實際的音訊硬體互動,因此可在大部分的裝置上使用。 實驗室涵蓋下列工作:

Echo 驅動程序實驗室

Echo 驅動程式是比 Sysvad 音訊驅動程式更簡單的驅動程式。 如果您不熟悉 WinDbg,建議您先考慮先完成偵錯通用驅動程式 - 逐步實驗室 (Echo 核心模式)。 此實驗室會重複使用該實驗室的設定指示,因此如果您已完成該實驗室,您可以在這裡略過第 1 節和第 2 節。

第1節:連線至內核模式 WinDbg 工作階段

在第1節中,您會在主機和目標系統上設定網路偵錯。

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

此實驗室使用兩部計算機。 WinDbg 會在 主機 系統上執行,而 Sysvad 驅動程式會在 目標 系統上執行。

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

此圖顯示透過網路中樞/路由器連線的兩部計算機。

若要使用內核模式應用程式並使用 WinDbg,建議您使用透過乙太網路傳輸的 KDNET。 如需如何使用乙太網路傳輸通訊協定的資訊,請參閱 開始使用 WinDbg (Kernel-Mode) 。 如需設定目標計算機的詳細資訊,請參閱 準備計算機以進行手動驅動程式部署自動設定 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 命令來確認兩個系統之間的網路連線。 使用您記錄之主機系統的實際IP位址,而不是範例輸出中顯示的169.182.1.1。
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

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

  1. 找出這兩個檔案,並將其複製到網路共用或拇指磁碟驅動器,使其可在目標計算機上使用。

    kdnet.exe

    VerifiedNICList.xml

  2. 在目標計算機上,以 管理員 istrator 開啟命令提示字元視窗。 輸入此命令來驗證目標電腦上的 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位址。 使用您記錄之主機系統的實際IP位址,而不是範例輸出中顯示的169.182.1.1。 針對您使用的每個目標/主機組挑選唯一的埠位址,例如 50010。
C:\>kdnet 169.182.1.1 50010

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

重要

使用 BCDEdit 變更開機資訊之前,您可能需要暫時暫停測試電腦上的 Windows 安全性功能,例如 BitLocker 和安全開機。 在測試完成時重新啟用這些安全性功能,並在停用安全性功能時適當地管理測試計算機。 安全開機通常會在 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.

將自動產生的唯一密鑰複製到文字檔中,以避免必須在主計算機上輸入它。 將具有金鑰的文字檔複製到主機系統。

注意防火牆和調試程式

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

Windows 安全性 警示的螢幕快照,指出 Windows 防火牆已封鎖應用程式的某些功能。

<- 在主機系統上

  1. 在主計算機上,以 管理員 istrator 開啟命令提示字元視窗。 變更為 WinDbg.exe 目錄。 我們將使用 Windows 驅動程式套件 (WDK) 中安裝的 x64version WinDbg.exe 版本,作為 Windows 套件安裝的一部分。
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

->在目標系統上

重新啟動目標系統。

<-在主機系統上

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

顯示即時核心連線命令窗口輸出的 Windows 調試程式螢幕快照。

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

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

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

第2節:內核模式偵錯命令和技術

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

<- 在主機系統上

使用.prefer_dml啟用除錯程式標記語言 (DML)

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

  1. 在 WinDBg 中使用 Ctrl+Break (Scroll Lock) 來中斷在目標系統上執行的程式代碼。 目標系統可能需要一點時間才能回應。
  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 視窗中輸入 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

列出載入的模組

  1. 您可以在 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
...

注意 已省略的輸出會以 「... 「在此實驗室中。

由於我們尚未設定符號路徑和已載入的符號,因此調試程式中有有限的資訊可供使用。

第3節:下載並建置 Sysvad 音訊驅動程式

在第 3 節中,您將下載並建置 Sysvad 音訊驅動程式。

一般而言,當您使用 WinDbg 時,您將會使用自己的驅動程式程式代碼。 若要熟悉偵錯音訊驅動程式,會使用 Sysvad 虛擬音訊範例驅動程式。 此範例用來說明如何透過原生內核模式程式代碼進行單一步驟。 這項技術對於偵錯複雜的內核模式程式代碼問題非常有價值。

若要下載並建置 Sysvad 範例音訊驅動程式,請執行下列步驟。

  1. 從 GitHub 下載並擷取 Sysvad 音訊範例

    您可以使用瀏覽器在這裡檢視 Sysvad 範例和 Readme.md 檔案:

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

    GitHub 存放庫的螢幕快照,其中顯示 [一般資料夾] 和 [下載 ZIP] 按鈕。

    此實驗室示範如何在一個 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 中,找出 方案總管。 (如果尚未開啟,請選擇從 [檢視] 功能表 方案總管。在 方案總管 中,您可以看到一個有數個項目的解決方案。

    Visual Studio 的螢幕快照,其中已從 Sysvad 專案載入adapter.cpp檔案。

  3. 設定範例的組態和平臺

    在 方案總管 中,選取並按住 [或以滑鼠右鍵按兩下] 解決方案 'sysvad' (7 個專案中的 7 個),然後選擇 [Configuration Manager]。 請確定這四個專案的組態和平台設定都相同。 根據預設,組態會設定為 「Win10 Debug」,而平臺會針對所有項目設定為 「Win64」。。 如果您對一個項目進行任何組態和/或平台變更,則必須對其餘三個專案進行相同的變更。

    注意 此實驗室假設正在使用 64 位 Windows。 如果您使用 32 位 Windows,請建置 32 位的驅動程式。

  4. 檢查驅動程序簽署

    找出 TabletAudioSample。 開啟 Sysvad 驅動程式的屬性頁面,並確定 [驅動程式簽署簽署>模式] 設定為 [測試簽署]。

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

  6. 使用 Visual Studio 建置範例

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

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

提示

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

  1. 找出建置的驅動程序檔案

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

    瀏覽至包含 TabletAudioSample 驅動程式建置檔案的資料夾:

    C:\WDK_Samples\Sysvad\TabletAudioSample\x64\Debug。 資料夾將包含TabletAudioSample .SYS 驅動程式、符號 pdp 檔案和 inf 檔案。 您也必須找出 DelayAPO、KWSApo 和 KeywordDetectorContosoAdapter dll 和符號檔。

    若要安裝驅動程式,您需要下列檔案。

    檔案名稱 描述
    TabletAudioSample.sys 驅動程式檔案。
    TabletAudioSample.pdb 驅動程式符號檔。
    tabletaudiosample.inf 資訊 (INF) 檔案,其中包含安裝驅動程式所需的資訊。
    KeywordDetectorContosoAdapter.dll 範例關鍵詞偵測器。
    KeywordDetectorContosoAdapter.pdb 範例關鍵詞偵測器符號檔。
    DelayAPO.dll 範例延遲 APO。
    DelayAPO.pdb 延遲 APO 符號檔。
    KWSApo.dll 範例關鍵詞 Spotter APO。
    KWSApo.pdb 關鍵詞 Spotter 符號檔。
    TabletAudioSample.cer TabletAudioSample 憑證檔案。
  2. 找出 USB 拇指磁碟驅動器,或設定網路共用,將建置的驅動程式檔案從主機複製到目標系統。

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

第 4 節:在目標系統上安裝 Sysvad 音訊驅動程式範例

在第 4 節中,您將使用 devcon 來安裝 Sysvad 音訊驅動程式。

-> 在目標系統上

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

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

部署驅動程式之前,您必須開啟測試簽署來準備目標計算機。 之後,您就可以在目標系統上執行建置的驅動程式範例。

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

  1. 啟用測試簽署的驅動程式

    若要啟用執行測試已簽署驅動程式的功能:

    1. 開啟 Windows 設定。

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

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

    4. 當計算機重新啟動時,請選取 [ 疑難解答]。

    5. 然後選取 [進階選項]、[啟動 設定],然後選取 [重新啟動]。

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

    7. 計算機會從新的值開始。

  2. -> 在目標系統上

    安裝驅動程式

    下列指示說明如何安裝和測試範例驅動程式。

    安裝此驅動程式所需的 INF 檔案是 TabletAudioSample.inf。 在目標計算機上,以 管理員 istrator 開啟命令提示字元視窗。 流覽至驅動程式套件資料夾,以滑鼠右鍵按兩下TabletAudioSample.inf檔案,然後選取 [ 安裝]。

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

    Windows 安全性 警告的螢幕快照,指出 Windows 無法驗證發行者。

    提示

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

    如需更詳細的指示,請參閱 設定計算機以進行驅動程式部署、測試和偵錯

    INF 檔案包含用來安裝 tabletaudiosample.sys的硬體識別碼。 針對 Syvad 範例,硬體識別碼為: root\sysvad_TabletAudioSample

  3. 檢查 裝置管理員 中的驅動程式

    在目標計算機上,在 [命令提示字元] 視窗中,輸入 devmgmt 以開啟 裝置管理員。 在 [裝置管理員] 的 [檢視] 功能表上,依類型選取 [裝置]。

    在裝置樹狀目錄中,找出 [音訊裝置] 節點中的 [虛擬音訊裝置] [WDM] - [平板計算機範例 ]。 這通常位於音效、視訊和遊戲控制器節點之下。 確認其已安裝且作用中。

    反白顯示計算機上實際硬體的驅動程式,裝置管理員。 然後選取並按住驅動程式,或以滑鼠右鍵按下驅動程式,然後選取 [停用] 以停用驅動程式。

    確認 裝置管理員 音訊硬體驅動程式會顯示向下箭號,指出它已停用。

    裝置管理員 樹狀結構的螢幕快照,其中已醒目提示虛擬音訊裝置平板電腦範例。

    成功安裝範例驅動程序之後,您現在已準備好進行測試。

測試 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 (Scroll Lock) 來中斷在目標系統上執行的程序代碼。

設定符號路徑

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

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

    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 在需要時提供的符號伺服器存取符號。 本逐步解說假設將使用此方法。 如果環境中的符號位於不同的位置,請修改步驟以使用該位置。 如需詳細資訊,請參閱 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 命令。 此命令可能需要一兩分鐘的時間才能執行。 在此期間,“*Busy” 會顯示在 WinDbg 的狀態區域中。

    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 在您的計算機上顯示的 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。 使用 !devnode 在您的計算機上顯示的 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,並允許通配符 * 用於設定符合的每個符號斷點(就像類別中的所有方法一樣)。

  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>',或略過 condition><#> 的次數<。 如需詳細資訊,請參閱 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 (break on access) 命令,並搭配下列語法。

ba <access> <size> <address> {options}
選項 描述

e

execute (當 CPU 從位址擷取指令時)

r

讀取/寫入(當 CPU 讀取或寫入位址時)

w

write (當 CPU 寫入位址時)

請注意,您只能在任何指定時間設定四個數據斷點,而且必須確定您正確對齊數據,否則不會觸發斷點(單字必須以 2 分隔的地址結束,dword 必須以 4 來除,而四字則以 0 或 8 為單位)

例如,若要在特定記憶體位址上設定讀取/寫入斷點,請使用如下的命令。

ba r 4 fffff800`7bc9eff0

修改斷點狀態

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

bl

列出斷點。

西元前

從清單中清除斷點。 使用 bc * 清除所有斷點。

bd

停用斷點。 使用 bd * 停用所有斷點。

be

啟用斷點。 使用 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 main - 在模組開頭設定初始斷點。

  • l+t - 逐步執行將會由來源行完成。

  • 選取 [>錯來源模式] 以進入來源模式;L+t命令不足。

  • l+s - 系統會在提示字元中顯示來源行。

  • g - 執行程式,直到輸入 「main」。

  • p - 執行一個來源行。

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

在程式代碼中設定斷點

您可以在程式代碼中設定斷點, DebugBreak() 方法是新增 語句並重建專案並重新安裝驅動程式。 每次啟用驅動程式時,此斷點都會引發,因此在早期開發階段使用的技術,而不是在生產程式代碼中使用。 這項技術不像使用斷點命令動態設定斷點那麼有彈性。

秘訣:您可能想要保留 Sysvad 驅動程式的複本,但已新增斷點以供進一步的實驗室工作。

  1. 將語句新增 DebugBreak() 至範例程序代碼,將每次 AddDevice 方法執行時,設定要發生的中斷。

    ...
        // 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. 清除任何先前的斷點,並確定調試程式已連結至目標計算機。

  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 在程式代碼中向前推進大約 10 行,直到您反白顯示 ntStatus = IsFormatSupported(Pin、Capture、DataFormat):程式代碼行。

        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 (Set Local Context) 命令來設定內容,然後 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

請注意,與此進程相關聯的其中一個線程處於 RUNNING 狀態。 此線程支援在叫用斷點時播放媒體剪輯。

使用 !process 0 0 命令來顯示所有進程的摘要資訊。 在命令輸出中,使用 CTRL+F 來尋找與audiodg.exe映像相關聯的進程識別碼。 在如下所示的範例中,進程標識符為 ffffe001d147c840

記錄計算機上與audiodg.exe相關聯的進程標識碼,以便稍後在此實驗室中使用。 ________________________

...

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。

現在,使用 !process 命令切換至與audiodg.exe相關聯的進程。 在此範例中,進程標識碼為 ffffe001d147c840。 將範例中的進程標識碼取代為您稍早記錄的進程標識碼。

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 來顯示目前線程的簡短資訊。 這會顯示線程位址、線程和進程標識符、線程環境區塊 (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,以及重新登錄的內容。

<- 在主機系統上

中斷要求層級 (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 (Registers)

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

拆卸

您可以藉由選取 >[檢視反組譯碼],來反組譯正在執行的程序代碼,以檢視正在執行的元件語言程序代碼。

顯示元件語言程式代碼的 WinDbg 反組譯碼視窗螢幕快照。

如需彙編語言反組譯碼的詳細資訊,請參閱批注 x86 反組譯碼和批註 x64 反組譯碼。

第 12 節:使用記憶體

在第 12 節中,您將使用調試程式命令來顯示記憶體的內容。

檢視記憶體

您可能需要檢查記憶體來識別問題,或檢查變數、指標等等。 您可以輸入下列 其中一個 d* <位址> 命令來顯示記憶體。

db

以位元組值和 ASCII 字元顯示數據。

dd

將數據顯示為雙寬文字(4 個字節)。

du

將數據顯示為 Unicode 字元。

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 (Display Type) 命令,在 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 來顯示位址的前四個字節。

    kd> dd ffffb780`b7eee664 l4
    ffffb780`b7eee664  ffa00000 00000018 00000000 c52d7008
    
  14. 若要查看顯示的不同類型的記憶體輸出,請輸入 dudadb 命令。

    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* 命令來變更記憶體內容。

Command 描述

ea

ASCII 字串 (非 NULL 終止)

eu

Unicode 字串 (非 NULL 終止

ew

文字值 (2 個字節)

eza

NULL 終止的 ASCII 字串

ezu

NULL 終止的 Unicode 字串

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 (Quit and Detach) 命令,或從功能表中選取 [ 停止偵錯 ]。

0: kd> qd

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

第 14 節:Windows 偵錯資源

Windows 偵錯提供其他資訊。 請注意,這些書籍中有一些會在其範例中使用舊版的 Windows,例如 Windows Vista,但所討論的概念適用於大部分的 Windows 版本。

影片

重組工具顯示 WinDbg 情節 13-29: </show/defrag-tools/>

訓練廠商:

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

另請參閱

開始使用 Windows 偵錯