共用方式為


使用 EXDI 設定 QEMU 內核模式偵錯

本主題描述如何搭配 Windows 調試程式使用 EXDI 設定 QEMU 內核模式偵錯。

如需設定 EXDI 連線和疑難解答的一般資訊,請參閱 設定 EXDI 調試程式傳輸

使用 QEMU、虛擬化和機器模擬軟體,可以連線到做為主機的其他操作系統,例如 Linux。 QEMU 本身可以在許多架構上執行,例如 x64 和 Arm64。 ExdiGdb 偵錯伺服器也支援其他處理器,例如,您可以使用 WinDbg 來偵錯在 x64 上執行的 QEMU,模擬 Arm64。 使用EXDI也可讓VM在開機程式早期進行HW偵錯,甚至在OS載入之前也一直處於偵錯狀態。

注意

EXDI 是特定環境的進階特製化偵錯形式。 使用標準 KDNET 連線更容易設定,而且建議使用。 若要自動設定網路偵錯,請參閱 自動設定 KDNET 網路核心偵錯

EXDI COM 伺服器

EXDI 是一種介面,可藉由新增硬體調試程式的支持來擴充 WinDbg(例如 JTAG 型或 GdbServer 型)。 下圖說明 EXDI-GdbServer 的角色。

顯示 EXDI-GdbServer 角色的堆疊圖表,上面有 WinDbg-DbgEng、EXDI 介面,以及與 GDB 伺服器通訊的 EXDI COM 伺服器。

重要

由於 EXDI 不會使用 KDNET 通訊協定,因此連線的調試程式對於電腦上執行的內容明顯較少,而且許多命令的運作方式不同,或完全無法運作。 存取所偵錯程式代碼的私人符號,可協助調試程序進一步瞭解目標系統程式代碼執行。 如需詳細資訊,請參閱 公用和私人符號

在 QEMU 上設定與 Windows 映像的調試程式連線

這些步驟說明如何將 GDB 伺服器公開至 Windbg 用戶端的 Windows x64 虛擬機(使用 EXDI COM 伺服器),也會在 Windows 上執行。 會使用 WinDbg ExdiGdbSrv.dll (GDB 伺服器用戶端) 與 QEMU GDB 伺服器之間的 GdbServer RSP 工作階段。

  1. 在 Windows 上下載並安裝 QEMU。
  2. 設定目標 QEMU 虛擬 Windows 映像以使用必要的網路和 BIOS/UEFI 設定來啟動以進行偵錯。
  3. 使用啟動腳本啟動 QEMU 環境。
  4. 在 QEMU 上啟動 GdbServer。
  5. 檢查網路連線能力,並找出並記錄目標映像IP位址。 (LocalHost 的主機 IP 預設位址,以及 1234 的埠)。
  6. 在主機系統上下載並安裝 Windows 偵錯工具。
  7. 使用命令行或 UI 啟動 WinDbg 以連線到 EXDI 伺服器。
  8. 使用 WinDbg 對目標 QEMU Windows 映射進行偵錯。

QEMU 開放原始碼電腦模擬器

QEMU 是一種泛型且開放原始碼的計算機模擬器和虛擬化程式,可造成動態轉譯。 當 QEMU 作為電腦模擬器使用時,它可以在不同的電腦上執行作業系統和針對一個處理器 (例如 Arm64) 的程式(例如 Arm64 計算機)。 它也可以針對不同 OS 的 (Windows/Linux/Mac) 執行/裝載虛擬機映射。

QEMU 可以搭配 KVM 等其他 Hypervisor 運作,以使用 CPU 擴充功能 (HVM) 進行虛擬化。 當 QEMU 當做虛擬化工具使用時,QEMU 會直接在主機 CPU 上執行客體程式代碼,以達到接近原生效能。 QEMU 可以利用 OS Hypervisor 功能,將 CPU 和 MMU 模擬卸除至實際硬體。

下載並安裝 QEMU

在此逐步解說中,Windows x64 的 QEMU 將會安裝在 Windows 調試程式也會執行所在的 x64 計算機上。

從 QEMU 下載頁面下載 QEMU: https://www.qemu.org/download/

如需安裝 QEMU 的相關信息,請參閱 QEMU 檔: https://www.qemu.org/documentation/

設定目標虛擬磁碟

找出或建立具有您要偵錯之軟體的虛擬磁碟映像。

在此範例中,將會使用 Windows x64 VHDX 虛擬機磁碟映像。 若要深入瞭解 Windows 虛擬機映射,請參閱 在 Windows 10 上使用 Hyper-V 建立虛擬機。

將 VirtIO 驅動程式插入 Windows 映像

若要允許網路功能和合理的儲存設備效能,請將 VirtIO 驅動程式插入或安裝到 Windows 虛擬機磁碟映像中。 VirtIO 驅動程式可在這裡取得: https://github.com/virtio-win/kvm-guest-drivers-windows

VirtIO 是一種標準化介面,可讓虛擬機存取抽象硬體,例如封鎖裝置、網路適配器和控制台。 VirtIO 可作為 QEMU 等虛擬化環境中硬體裝置的抽象層。

若要將 VirtIO 驅動程式插入 Windows 映射,請遵循下列步驟:

  1. 擷取資料夾中的 VirtIo 驅動程式,例如 C:\VirtIo_Drivers
  2. 按兩下 檔案總管中的 VHDX,掛接包含 Windows x64 虛擬機器的 VHDX(您也可以使用 diskpart)。 Windows 會使用特定字母掛接 VHDX,例如 “L:”
  3. 使用 Dism 在掛接的映射中插入驅動程式: dism /image:L: /Add-Driver /driver:C:\VirtIo_Drivers 如需 DISM 的詳細資訊,請參閱 DISM 概觀
  4. 當程式完成時,您可以取消掛接映像,並繼續將 VHDX 轉換為 QEMU。

將 VHDX 轉換為 QEMU

此步驟並非必要,但建議使用原生 QEMU QCOW 映射而非 VHDX 時達到更好的效能。

使用下列qemu-img.exe命令來轉換 vhdx。 此公用程式位於您安裝 QEMU 的位置, 例如 C:\Program Files\qemu

C:\Program Files\qemu> qemu-img convert -c -p -O qcow2 MyVHDXFile.vhdx MyQEMUFile.qcow2 

下載 UEFI 韌體

為了獲得最佳結果,請下載或編譯 UEFI 韌體檔案 (OVMF.fd)。 因為 QEMU 預設會模擬較舊的 BIOS 系統,因此需要韌體。

UEFI 韌體的其中一個來源是 Open Clear Linux 專案: https://clearlinux.org/

此處提供範例 UEFI OVMF.fd 檔案: https://github.com/clearlinux/common/tree/master/OVMF.fd

在中 C:\Program Files\qemu\Firmware擷取下載文件的內容。

對於 Intel AMD64 以外的平臺,您應該從 EDK2 編譯韌體。 如需詳細資訊,請參閱https://github.com/tianocore/tianocore.github.io/wiki/How-to-build-OVMF

設定 QEMU 啟動文稿

在 QEMU 中建立您的組態檔。 例如,在 QEMU 根目錄下建立 StartQEMUx64Windows.bat 檔案。 請參閱下面的範例檔案。

使用 QEMU 啟動文本啟動 QEMU

執行 QEMU 啟動文本以啟動 QEMU。

c:\Program Files\qemu\StartQEMUx64Windows.bat

如果出現防火牆 Defender 提示,請將所有許可權授與應用程式所有類型的網路,以透過主機調試程式計算機的 Windows 防火牆啟用 Windbg。

已核取所有三個選項的 Windows Defender 防火牆對話框。

在 QEMU 環境中啟動 Windows 虛擬機之後,QEMU UI 隨即出現。

QEMU 顯示檢視功能表選項的螢幕快照。

使用 CTRL+ALT+ 數位按鍵組合,即可在 QEMU 監視器控制台中執行。 您也可以使用 View-compatmonitor> 來使用此監視器。

輸入 gdbserver 以在 QEMU 上啟動前端 GDB 伺服器。

QEMU 應該會顯示 Waiting for gdb connection on device ‘tcp::1234’

使用 CTRL+ALT+1 鍵組合返回主視窗。

提示:GDB 控制台窗口支援 system_reset 命令來快速重新啟動模擬。 輸入 help GDB 控制台命令清單。

QEMU x64 Windows VM 啟動腳本的範例

以下是可用於 AMD64 虛擬機器 的 QEMU 組態腳本範例。 將指向 DISK 和 CDROM 檔案的連結取代為您電腦上的位置。

    REM
    REM  This script is used to run a Windows x64 VM on QEMU that is hosted by a Windows x64 host system
    REM  The Host system is a PC with Intel(R) Xeon(R) CPU.
    REM
    set EXECUTABLE=qemu-system-x86_64
    set MACHINE=-m 6G -smp 4

    REM No acceleration
    REM generic cpu emulation.
    REM to find out which CPU types are supported by the QEMU version on your system, then run:
    REM	 qemu-system-x86_64.exe -cpu help
    REM the see if your host system CPU is listed
    REM

    set CPU=-machine q35 

    REM Enables x64 UEFI-BIOS that will be used by QEMU :
    set BIOS=-bios "C:\Program Files\qemu\Firmware\OVMF.fd"

    REM  Use regular GFX simulation
    set GFX=-device ramfb -device VGA 
    set USB_CTRL=-device usb-ehci,id=usbctrl
    set KEYB_MOUSE=-device usb-kbd -device usb-tablet

    REM # The following line enable the full-speed HD controller (requires separate driver)
    REM # Following line uses the AHCI controller for the Virtual Hard Disk:
    set DRIVE0=-device ahci,id=ahci -device ide-hd,drive=disk,bus=ahci.0

    REM
    REM This will set the Windows VM x64 disk image that will be launched by QEMU
    REM The disk image is in the qcow2 format accepted by QEMU.
    REM You get the .qcow2 image, once you get the VHDX Windows VM x64 image 
    REM and apply the script to inject the virtio x64 drivers and then run the 
    REM the QEMU tool to convert the .VHDX image to .qcow2 format
    REM 	i.e. 
    REM	qemu-img convert -c -p -O qcow2 Windows_VM_VHDX_with_injected_drivers_file.vhdx file.qcow2
    REM file : points to the specified qcow2 image path.
    REM
    set DISK0=-drive id=disk,file="C:\Program Files\qemu\MyQEMUFile.qcow2",if=none

    REM
    REM for kdnet on, then best option:
    REM   NETWORK0="-netdev user,id=net0,hostfwd=tcp::53389-:3389,hostfwd=tcp::50001-:50001 -device virtio-net,netdev=net0,disable-legacy=on"
    REM
    REM Create a mapping for the RDP service from port 3389 to 3589.
    REM
    set NETHOST=-netdev user,id=net0,hostfwd=tcp::3589-:3389
    set NETGUEST=-device e1000,netdev=net0

    REM # The following line should enable the Daemon (instead of interactive)
    set DAEMON=-daemonize"
    %EXECUTABLE% %MACHINE% %CPU% %BIOS% %GFX% %USB_CTRL% %DRIVE0% %DISK0% %NETHOST% %NETGUEST%

網路連線

本機主機

如果 GDB 伺服器已正確啟動,您會看到 GDB 伺服器將接聽的埠號碼,而您必須使用此埠來設定主機調試程式 IP:Port 組。

如果您的主機調試程式位於裝載 QEMU 客體所在的相同計算機,則會在 IP:Port 配對的 中使用 Localhost 識別碼。 在此範例中,將會在同一部計算機上搭配伺服器和主機調試程式使用 LocalHost:1234

遠端主機

如果在遠端電腦上運作,請找出 Windows IP 位址(如果調試程式主機會話不會位於與 QEMU VM 相同的 Windows 機器上)。

目標 QEMU IP <address><port number> 將會在 EXDI UI 中設定。

您可以在 QEMU 控制臺上發出下列命令(compatmonitor0),以顯示網路和聯機狀態的相關信息。

info network
info usernet

如需 QEMU 網路功能的其他資訊,請參閱 https://wiki.qemu.org/Documentation/Networking

在主機系統上下載並安裝 Windows 偵錯工具

在主機系統上安裝 Windows 偵錯工具。 如需下載及安裝調試程式工具的資訊,請參閱 Windows 的偵錯工具。

在主機系統上啟動 WinDbg

在此所述的案例中,在 EXDI UI 中設定下列選項以連線。

目標類型 - QEMU

目標架構 - x64

目標 OS - Windows

影像掃描啟發學習法大小 - 0xFFE - NT

Gdb 伺服器和埠 - LocalHost:1234

中斷連線 -

Windbg EXDI 核心連線 UI,其中顯示連線選項,包括 IP 和埠位址。

雖然建議使用 EXDI UI,但也可以使用類似此處所示的命令行選項來啟動 WinDbg。

c:\Debuggers> windbg.exe -v -kx exdi:CLSID={29f9906e-9dbe-4d4b-b0fb-6acf7fb6d014},Kd=Guess,Inproc=ExdiGdbSrv.dll,DataBreaks=Exdi

使用命令行時,會使用 exdiConfigData.xml 檔案來設定 IP 位址和埠。 如需詳細資訊,請參閱 EXDI XML 組態檔

若要顯示其他輸出, 可以使用 -v: 詳細資訊會話。 如需 WinDbg 選項的一般資訊,請參閱 WinDbg 命令行選項

調試程式應該啟動並連線到 QEMU GdbServer。

在視窗標題中顯示 EXDI CLSID 的主要 WinDbg 工作階段。

調試程式會顯示成功的 EXDI 傳輸初始化。

EXDI: DbgCoInitialize returned 0x00000001
EXDI: CoCreateInstance() returned 0x00000000
EXDI: QueryInterface(IExdiServer3) returned 0x00000000
Target command response: QEMU
exdiCmd: The function: 'ExdiDbgType' was completed.
EXDI: Server::GetTargetInfo() returned 0x00000000
EXDI: Server::SetKeepaliveInterface() returned 0x00000000
EXDI: Server::GetNbCodeBpAvail() returned 0x00000000
EXDI: ExdiNotifyRunChange::Initialize() returned 0x00000000
EXDI: LiveKernelTargetInfo::Initialize() returned 0x00000000
EXDI: Target initialization succeeded

如果 [進階選項] 底下的 [顯示通訊封包記錄 ] 設定為 [開啟],EXDIServer 控制台封包視窗也可以顯示 EXDI 連線狀態的相關信息。 如需詳細資訊,請參閱設定 EXDI 調試程式傳輸中的疑難解答資訊。

使用 WinDbg 對目標 QEMU Windows 映射進行偵錯

dbgeng.dll會使用啟發學習演算法來尋找發生中斷命令時 NT 基底負載位址的位置。 如果私人符號無法使用,此程式將會失敗。

這表示在許多連接順序下,中斷將無法如預期般運作。 如果您手動中斷程式代碼,則會是 Windows 當時所執行的隨機位置。 由於目標程式代碼的符號可能無法使用,因此很難使用符號來設定斷點。

可用的調試程式記憶體存取命令

直接存取記憶體的命令如下。

k, kb, kc, kd, kp, kP, kv (顯示堆棧回溯)

r (快取器)

d, da, db, dc, dd, dD, df, dp, dq, du, dw (顯示記憶體)

u (Unassemble)

而且您可以逐步執行程序代碼。

p (步驟)

也有一個命令可用來嘗試尋找您想要偵錯的程序代碼。

s (搜尋記憶體)

.imgscan (尋找影像標頭)

Imgscan 對於 EDXI 偵錯很有説明,因為與傳統 KDNET 核心偵錯不同,根據符號設定斷點可能無法使用。 尋找所需的目標映像,有助於使用其位置來設定記憶體取斷點。

.exdicmd (EXDI 命令)

.exdicmd 會使用作用中的 EXDI 偵錯連線,將 EXDI 命令傳送至目標系統。 如需詳細資訊,請參閱 .exdicmd (EXDI 命令)

疑難排解

請參閱設定 EXDI 調試程式傳輸中的疑難解答資訊。

另請參閱

設定 EXDI 調試程式傳輸

EXDI XML 組態檔

.exdicmd (EXDI 命令)

自動設定 KDNET 網路核心偵錯

手動設定 KDNET 網路核心偵錯