EXDI を使用した QEMU カーネルモード デバッグの設定

このトピックでは、EXDI を使用して QEMU カーネル モード デバッグをセットアップする方法について説明します。 Windows デバッガーは、EXDI を使用した QEMU 環境のカーネル デバッグをサポートしています。 このドキュメントでは、ExdiGdbSrv.dll (GDB サーバー クライアント) と QEMU GDB サーバーの間で GdbServer RSP セッションを確立するために必要な手順について説明します。

説明するシナリオでは、Windows x64 仮想マシンと、同じく Windows 上で実行される QEMU GDB サーバーを使用します。

Linux など、ホストとして機能する他のオペレーティング システムに接続することも可能です。 仮想化およびマシン エミュレーション ソフトウェアである QEMU は、x64 や Arm64 などの多数のアーキテクチャ上で実行できます。 ExdiGdb デバッグ サーバーは他のプロセッサもサポートしています。たとえば、WinDbg を使用して Arm64 上で実行されている QEMU をデバッグできます。 これにより、Windows VM をデバッグするための複数のオプションが提供されるため、デバッガー ホスト EXDI GDB サーバー クライアントに接続された利用可能な QEMU GDB サーバーを介して Windows VM をハードウェア デバッグできます。

EXDI 接続の構成およびトラブルシューティングのセットアップに関する一般的な情報については、「EXDI デバッガー トランスポートの構成」を参照してください。

Note

EXDI は、特定の環境向けの高度で特殊な形式のデバッグです。 標準の KDNET 接続を使用する方が構成が簡単なので、お勧めします。 ネットワーク デバッグを自動的にセットアップするには、「KDNET ネットワーク カーネル デバッグの自動セットアップ」を参照してください。

EXDI COM サーバー

EXDI は、ハードウェア デバッガ (JTAG ベース、GdbServer ベースなど) のサポートを追加することで WinDbg を拡張できるインターフェイスです。 以下の図は、EXDI-GdbServer の役割を示しています。

Stack diagram showing the role of EXDI-GdbServer with WinDbg-DbgEng on top, an EXDI interface, and an EXDI COM server communicating with a GDB server.

重要

EXDI は KDNET プロトコルを使用しないため、接続されたデバッガーが PC 上で実行しているものに関する情報を大幅に少なくし、多くのコマンドが異なる動作をするか、まったく動作しない可能性があります。 デバッグ中のコードのプライベート シンボルにアクセスすると、デバッガーがターゲット システムのコード実行をより深く理解できるようになります。 詳細については、「パブリック シンボルとプライベート シンボル」を参照してください。

QEMU 上の Windows イメージへのデバッガー接続をセットアップする

このトピックでは、Windows 上で実行されている QEMU 仮想 Windows イメージにアタッチするプロセスについて説明します。

  1. Windows に QEMU をダウンロードしてインストールします。
  2. デバッグに必要なネットワークおよび BIOS/UEFI 設定を使用して起動するようにターゲット QEMU 仮想 Windows イメージを構成します。
  3. 構成された起動スクリプトを使用して、QEMU 環境を開始します。
  4. QEMU で gdbserver を起動します。
  5. ネットワーク接続を確認し、ターゲット イメージの IP アドレスを見つけて記録します。 (ホスト IP のデフォルト アドレス 1.2.3.4)。
  6. Windows デバッグ ツールをダウンロードしてホスト システムにインストールします。
  7. GitHub にある QEMU 用の EXDI サーバーをダウンロード、構築、登録、構成します。
  8. EXDI 構成 XML ファイルを編集して、デバッガー ホスト (WinDbg) を構成します。
  9. コマンド ラインを使用して WinDbg を起動し、EXDI サーバーに接続します。
  10. WinDbg を使用して、ターゲット QEMU Windows イメージをデバッグします。

Windows に QEMU をダウンロードしてインストールする

QEMU は、動的変換を行う汎用のオープンソース マシン エミュレーターおよびバーチャライザーです。 QEMU をマシン エミュレータとして使用すると、あるプロセッサ (Arm64 など) 用に作成された OS とプログラムを別のマシン (x64 PC) 上で実行できます。 さまざまな OS (Windows/Linux/Mac) の仮想マシン イメージを実行/ホストすることもできます。

QEMU は、KVM などの他のハイパーバイザーを使用して、仮想化に CPU 拡張機能 (HVM) を使用できます。 QEMU がバーチャライザーとして使用される場合、QEMU はゲスト コードをホスト CPU 上で直接実行することにより、ネイティブに近いパフォーマンスを実現します。 QEMU は、OS ハイパーバイザー機能を利用して、CPU および MMU エミュレーションを実際のハードウェアにオフロードできます。

QEMU のダウンロードとインストール

このウォークスルーでは、Windows x64 用 QEMU が、Windows デバッガーも実行される x64 PC にインストールされます。

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 のような仮想化環境でハードウェア デバイスの抽象化レイヤーとして機能します。

VHDX から QEMU への変換

この手順は必須ではありませんが、VHDX の代わりにネイティブ QEMU QCOW イメージを使用するとパフォーマンスが向上するため、この手順をお勧めします。

次の 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 ファームウェアのソースの 1 つは、Open Clear Linux プロジェクトです。 https://clearlinux.org/

UEFI OVMF.fdファイルの例はここから入手できます。 https://github.com/clearlinux/common/blob/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

ファイアウォール防御プロンプトが表示された場合は、ホスト デバッガー マシンの Windows ファイアウォールを介して Windbg を有効にするために、アプリにすべての種類のネットワークに対するすべての権限を付与します。

Windows Defender Firewall dialog box with all three options checked.

Windows 仮想マシンが QEMU 環境で起動されると、QEMU UI が表示されます。

Screenshot of QEMU displaying view menu options.

CTRL+ALT+数字キーの組み合わせを使用して、QEMU モニター コンソールに移動します。 このモニターは、View->compatmonitor を使用しても利用できます。

QEMU でフロントエンド GDB サーバーを起動するためにgdbserverを入力します。

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 ファイルを指すリンクを PC 上の場所に置き換えます。

    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 D:\temp\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=D:\temp\x64_image_qcow2_for_windows\basex64Client.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
    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 DEAMON=-daemonize"
    %EXECUTABLE% %MACHINE% %CPU% %BIOS% %GFX% %USB_CTRL% %DRIVE0% %DISK0% %NETHOST% %NETGUEST%

ネットワーク接続を確認します

Windows IP アドレスを必ず取得してください (デバッガー ホスト セッションが QEMU VM と同じ Windows マシンに配置されない場合)。

GDB サーバーが正常に起動すると、GDB サーバーがリッスンするポート番号が表示されます。このポートを使用して、exdiConfigData.xml でホスト デバッガー (IP:ポートのペア) をセットアップする必要があります。

ホスト デバッガーが QEMU ゲストをホストする同じマシンに配置されている場合、Localhost 識別子は exdiconfigdata.xml で IP:Port ペアとして使用されます (例: LocalHost:Port:1234)。 この例では、サーバーとホスト デバッガが同じ PC 上にあるため、デフォルト値が使用されます。

ExdiConfigData.xml ファイルで、現在のターゲット名属性 (CurrentTarget) の値を「QEMU」に設定します。

リモート PC で作業している場合は、ターゲット QEMU IP <address>を設定します。GDB サーバーがリッスンしているポート:<number>

  • exdiCondifgData.xml で QEMU コンポーネントの Tag 要素を見つけます。
  • 次のようにして、QEMU GDB サーバーの IP:ポート番号 (デバッガーが QEMU VM と同じホスト上で実行されている場合は LocalHost) を設定します。
  • EXDI_GDBSRV_XML_CONFIG_FILE 環境変数で指定されたパスにある exdiConfigdata.xml ファイルに変更を保存します。

QEMU ネットワーキングの詳細については、次を参照してください。 https://wiki.qemu.org/Documentation/Networking

QEMU コンソール (compatmonitor0) で次のコマンドを実行すると、ネットワークと接続ステータスに関する情報を表示できます。

info network
info usernet

Windows デバッグ ツールをホスト システムにダウンロードしてインストールします。

ホスト システムに Windows デバッグ ツールをインストールします。 デバッガー ツールのダウンロードとインストールについては、「Windows 用デバッグ ツール」を参照してください。

EXDI サーバー DLL をダウンロード、構築、登録します。

対応する ExdiGdbSrv.dll バイナリ (EXDI COM サーバー クライアント) ソース コードを Microsoft/WinDbg-Samples、GitHubhttps://github.com/microsoft/WinDbg-Samples からダウンロードします)

git clone https://github.com/microsoft/WinDbg-Samples

Exdi/exdigdbsrv にあるホスト デバッガー インストールのアーキテクチャに従って、VS ソリューション (ExdiGdbSrv.sln) を構築します。

ビルドによって生成された ExdiGdbSrv.dll を見つけます。

EXDI com サーバー (ExdiGdbSrv.dll) をホスト マシンのデバッガが含まれるディレクトリにコピーします (.g)。 C:\Program Files (x86)\Windows Kits\10\Debuggers\x64 またはC:\Debuggers

regsvr32 を使用して、管理者コマンド プロンプトに DLL を登録します。

C:\Program Files (x86)\Windows Kits\10\Debuggers\x64>regsvr32 ExdiGdbSrv.dll

RegSvr32 は、DLLRegisterServer in ExdiGdbSrv.dll succeededを示すためにメッセージを返します。 .

この手順は 1 回だけ実行する必要がありますが、ExdiGdbSrv.dll の場所を変更した場合は、COM サーバーを再度登録する必要があります。

もう 1 つのオプションは、サンプル PowerShell スクリプトを使用して、EXDI DLL をインストールし、デバッガーを初めて起動することです。 詳細については、「EXDI デバッガー トランスポートの構成」の「EXDI PowerShell スクリプトの例」を参照してください。

EXDI 構成 XML ファイルを編集してデバッガー ホスト (WinDbg) を構成します。

必要な 2 つの構成ファイルをWinDbg-Samples/Exdi/exdigdbsrv/で見つけて、デバッガがインストールされているホスト デバッガ マシンのローカルにコピーします。

  • exdiConfigData.xml
  • systemregisters.xml

EXDI_GDBSRV_XML_CONFIG_FILE – EXDI xml 構成ファイルへのフルパスを説明します。

EXDI_SYSTEM_REGISTERS_MAP_XML_FILE – EXDI xml システム レジスタ マップ ファイルへのフル パスを説明します。

EXDI 接続の構成とトラブルシューティングのセットアップ、および exdiConfigData.xml タグと属性に関する一般的な情報については、「EXDI デバッガー トランスポートの構成」を参照してください。

環境変数 EXDI_GDBSRV_XML_CONFIG_FILE および EXDI_SYSTEM_REGISTERS_MAP_XML_FILE を設定して、exdi xml 構成ファイルへのフルパスを記述します。

コマンド プロンプト

コマンド プロンプトを開き、次の環境変数を設定します。

set EXDI_GDBSRV_XML_CONFIG_FILE="C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\exdiConfigData.xml"

set EXDI_SYSTEM_REGISTERS_MAP_XML_FILE="C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\systemregisters.xml"

SETを入力して、指定されたパスが ExdiGdbSrvSample.dll の場所から利用できることを確認します。

Powershell

PowerShell プロンプトを開き、次の環境変数を設定します。

$env:EXDI_GDBSRV_XML_CONFIG_FILE = 'C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\exdiConfigData.xml'

$env:EXDI_SYSTEM_REGISTERS_MAP_XML_FILE = 'C:\Program Files (x86)\Windows Kits\10\Debuggers\x64\systemregisters.xml'

dir env:を入力して、指定されたパスが ExdiGdbSrvSample.dll の場所から利用できることを確認します。

ホスト システムで WinDbg を起動します。

環境変数 (EXDI_GDBSRV_XML_CONFIG_FILE および EXDI_SYSTEM_REGISTERS_MAP_XML_FILE) を設定したのと同じコマンド プロンプトで、exdi インターフェイスを介して Windbg セッションを起動します。

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

追加の出力を表示するには、-v:verbose セッションを使用できます。 WinDbg オプションの一般的な情報については、「WinDbg コマンド ライン オプション」を参照してください。

もう 1 つのオプションは、サンプル PowerShell スクリプトを使用して、EXDI DLL をインストールし、デバッガーを初めて起動することです。 詳細については、「EXDI デバッガー トランスポートの構成」「EXDI PowerShell スクリプトの例」を参照してください。

PS>.\Start-ExdiDebugger.ps1 -ExdiTarget "QEMU" -GdbPort 1234 -Architecture x64 -ExdiDropPath "C:\path\to\built\exdi\files"

デバッガーが起動し、QEMU GdbServer に接続する必要があります。

Main WinDbg session displaying EXDI CLSID in the window title.

デバッガーには、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

exdiConfigData.xml ファイルで displayCommPackets="yes" が設定されている場合、EXDIGdbServer コンソールのパケット ウィンドウには、EXDI 接続のステータスに関する情報も表示できます。 詳細については、「EXDI デバッガー トランスポートの構成」のトラブルシューティング情報を参照してください。

WinDbg を使用してターゲット QEMU Windows イメージをデバッグする

dbgeng.dll はヒューリスティック アルゴリズムを使用して、break コマンドが発生した時点の NT ベース ロード アドレスの場所を見つけます。 プライベート シンボルが使用できない場合、このプロセスは失敗します。

これは、多くの接続シーケンスでは、ブレークが期待どおりに機能しないことを意味します。 コードに手動で侵入した場合、そのコードは Windows がその瞬間にたまたま実行していたランダムな場所になります。 ターゲット コードのシンボルが利用できない場合があるため、シンボルを使用してブレークポイントを設定するのが難しい場合があります。

メモリに直接アクセスする次のようなコマンドは機能します。

k、kb、kc、kd、kp、kP、kv (スタック バックトレースの表示)

r (レジスタ)

d、da、db、dc、dd、dD、df、dp、dq、du、dw (表示メモリ)

u (逆アセンブル)

コードをステップ実行することもできます。

p(ステップ)

デバッグしたいコードを見つけるために使用できるコマンドもあります。

s (メモリの検索)

.imgscan (イメージ ヘッダーの検索)

従来の KDNET ベースのカーネル デバッグとは異なり、シンボルに基づいてブレークポイントを設定できない場合があるため、imgscan は EDXI デバッグに役立ちます。 目的のターゲット イメージを見つけると、その場所を使用してメモリ アクセス ブレークポイントを設定することが容易になります。

.exdicmd (EXDI コマンド)

.exdicmd は、アクティブな EXDI デバッグ接続を使用して、EXDI コマンドをターゲット システムに送信します。 詳細については、「.exdicmd (EXDI コマンド)」を参照してください。

EXDI XML 構成ファイル

EXDI GDB COM サーバー (ExdiGdbSrv.dll) によって使用される 2 つの必須 XML ファイルがあります。

  1. exdiConfigData.xml - このファイルには、GDB サーバー クライアントが HW デバッガー GDB サーバー ターゲットとの GDB セッションを正常に確立するために必要な主要な構成データが含まれているため、ファイルの場所が設定されていない場合、GDB サーバー クライアントは実行されません。 EXDI_GDBSRV_XML_CONFIG_FILE 環境変数。 各 XML タグを使用すると、GDB サーバー機能の特定のセットを構成できます。 XML で変更できる属性のリストとサンプル XML については、以下を参照してください。

  2. Systemregister.xml - このファイルには、システム レジスタとそのアクセス コード間のマッピングが含まれています。 これが必要なのは、アクセス コードが GDB サーバーによって xml ファイルで提供されず、デバッガがアクセス コードを介して各システム レジスタにアクセスするためです。

XML 構成ファイルで定義されている GDBServer タグと属性の詳細と説明については、「EXDI デバッガー トランスポートの構成」を参照してください。

トラブルシューティング

EXDI デバッガー トランスポートの構成」のトラブルシューティング情報を参照してください。

関連項目

EXDI デバッガー トランスポートの構成

.exdicmd (EXDI コマンド)

KDNET ネットワーク カーネル デバッグの自動設定

KDNET ネットワーク カーネル デバッグの手動設定