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

このトピックでは、EXDI を使用してカーネル モード デバッグを設定する方法について説明します。 拡張デバッグ インターフェイス (EXDI) は、ソフトウェア デバッガーとデバッグ ターゲットの間の適合レイヤーです。 Windows デバッグ ツールでは、Windows バージョン 22000 以降の EXDI を使用したカーネル デバッグがサポートされています。

EXDI を使用して、QEMU 仮想環境との接続を確立できます。 詳細については、「EXDI を使用した QEMU カーネル モード デバッグの設定」を参照してください。

Note

EXDI は、特定の環境向けの高度で特殊な形式のデバッグです。 標準の KDNET 接続を使用するほうが構成が容易であり、推奨されます。 ネットワーク デバッグを自動的に設定するには、「KDNET ネットワーク カーネル デバッグの自動設定」を参照してください。

EXDI COM サーバーの概要

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

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

EXDI 接続は、ターゲット PC に読み込まれている Windows または KDNET プロトコルに依存しません。 これらのソフトウェア デバッガー コンポーネントが不要なため、EXDI は、デバイス導入の初期段階や、OS の起動の問題のデバッグに役立ちます。

重要

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

EXDI カーネル モード デバイスの要件

デバッガを実行するコンピューターはホスト コンピューターと呼ばれ、デバッグ対象のコンピューターはターゲット コンピューターと呼ばれます。

次が必要です。

  • ターゲット コンピューターとホスト コンピューターに、QEMU などの、目的の環境でサポートされているネットワーク カードが必要です。

  • ターゲットとホストの間の、TCP/IP を使用したネットワーク接続。

  • Windows 10 または Windows 11 のバージョン 22000 以降。

制限事項

  • EXDI ハードウェア デバッグは、XML ファイルを使用して手動で構成する必要があり、Windows デバッガーには関連 UI はありません。

  • 前述のように、EXDI は KDNET プロトコルを使用しないため、接続されたデバッガーではターゲット システムに関する情報が少なく、デバッガーの使用方法が異なります。 ターゲット コードのプライベート シンボルにアクセスしないと、ターゲット システムの状態を把握するためにシンボルを使用する多くのコマンドが機能しません。 この場合、メモリを表示し、内容を登録して、コードを逆アセンブルすることができます。 コードの実行場所の特定や、他の一般的なデバッガー タスクの実行は、プライベート シンボルがないと非常に困難で時間がかかる場合があります。

COM GDB サーバー クライアント

このトピックでは、EXDI COM デバッガー インターフェイスを実装する EXDI COM GDB サーバー クライアント (ExdiGdbSrv.dll) の使用について説明します。 同じ COM インターフェイスを使用して、JTAG-DCI 用 EXDI COM サーバーなど、他のインターフェイスを実装できます。

EXDI と KDNET の同時デバッグ

デバイス導入の初期段階など、一部の複雑なシナリオでは、ターゲット デバイスに 2 つの接続があると便利です。 1 つは EXDI で、1 つは KDNET です。 ターゲットが Windows OS の場合、KDNET ソフトウェア のデバッグは、仮想マシンへの接続など、通常と同様に構成されます。 この設定では、2 つの同時デバッガーのいずれかにターゲット コンピューターの処理を一時停止させてコードをデバッグすることができます。

EXDI 接続を構成するプロセスの概要

このトピックでは、EXDI 接続を構成するプロセスについて説明します。 EXDI 使用シナリオの例については、「EXDI を使用した QEMU カーネル モード デバッグの設定」を参照してください。

  1. Windows デバッグ ツールをホスト システムにダウンロードしてインストールします。
  2. EXDI サーバー DLL をダウンロードし、ビルドして登録します。
  3. EXDI 構成 XML ファイルを編集して、接続を構成します。
  4. -kx オプションを使用して WinDbg を起動し、EXDI サーバーに接続します。
  5. WinDbg を使用してターゲット システムをデバッグします。

Windows デバッグ ツールをダウンロードしてインストールする

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

EXDI サーバー DLL をダウンロードし、ビルドして登録する

microsoft/WinDbg-Samples, GitHub https://github.com/microsoft/WinDbg-Samples から対応する ExdiGdbSrv.dll バイナリ (EXDI COM サーバー クライアント) をダウンロードする

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 PowerShell スクリプト例」を参照してください。

EXDI 構成 XML ファイルを使用して WinDbg を構成する

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

  • exdiConfigData.xml
  • systemregisters.xml

EXDI_GDBSRV_XML_CONFIG_FILE – EXDI XML 構成ファイルへの完全なパスを記述します。

EXDI_SYSTEM_REGISTERS_MAP_XML_FILE – EXDI XML システム レジスター マップ ファイルへの完全なパスを記述します。

exdiConfigData.xml のタグと属性の詳細については、後述の「EXDI XML 構成ファイル」を参照してください。

このシナリオでは、次の値を 0 に設定して、デバッガーで nt!kdVersionBlock を探索しないようにします。

heuristicScanSize = "0"

XML 構成ファイルの場所を参照するように EXDI パス値を設定する

環境変数 EXDI_GDBSRV_XML_CONFIG_FILE and EXDI_SYSTEM_REGISTERS_MAP_XML_FILE を設定して、EXDI XML 構成ファイルへの完全なパスを記述します。 指定されたパス環境値が、ExdiGdbSrv.dll の場所から使用できることを確認します。

コマンド プロンプト

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

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 サーバーに接続する

環境変数 (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=NtBaseAddr,DataBreaks=Exdi

診断に役立つ追加の出力を表示するには、-v: 詳細セッションを使用できます。 WinDbg オプションの一般的な情報については、「WinDbg コマンド ライン オプション」を参照してください。 詳細については、後述の「EXDI WinDbg 読み込みパラメーター」を参照してください。

デバッガーに、成功した EXDI トランスポートの初期化が表示されます。

EXDI: DbgCoInitialize returned 0x00000001
EXDI: CoCreateInstance() returned 0x00000000
EXDI: QueryInterface(IExdiServer3) returned 0x00000000
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
Kernel Debugger connection established

Main WinDbg session displaying EXDI CLSID in the window title.

EXDIGdbServer コンソール ウィンドウにも、EXDI 接続の状態に関する情報を表示できます。 コンソールの詳細については、「トラブルシューティング」を参照してください。

EXDI WinDbg 読み込みパラメーター

以下のパラメーターは、EXDI カーネル セッションを開始するために WinDbg と共に使用されます。

-kx: EXDI:Options

以下の EXDI オプションは、-kx オプションで使用できます。

パラメーター 説明
CLSID LiveExdiGdbSrvServer に割り当てられたクラス ID (ExdiGdbSrv.idl ファイルで定義)。
Kd=NtBaseAddr デバッガー エンジンは NT ベース アドレスを検索します。
ForceX86 CPU コンテキストの取得/設定に IeXdiX86Context3 インターフェイスを使用するように、デバッガー エンジンに強制します。
DataBreaks=Exdi データ ブレークポイントの使用を許可します。
Inproc inproc Exdi-Server の使用を許可します。

WinDbg を使用してターゲット システムをデバッグする

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

これは、多くの接続シーケンスでは、break が期待どおりに機能しないことを意味します。 手動でコードを一時停止すると、その時点で 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 コマンド)」を参照してください。

トラブルシューティング

ExdiGdbServer ウィンドウからの出力を使用して、接続シーケンスを監視します。

ExdiGdbServer text window displaying long hexadecimal numbers.

問題: エラー: GbDServer との接続を確立できません。 接続文字列 <hostname/ip>:portnumber を確認してください

この問題は、次の理由により発生する場合があります。

  • ExdiGdbSrv.dll がターゲット GDB サーバーに接続できない。
  • GDB サーバーがターゲットでまだ実行されていない。
  • ファイアウォールの問題については、ping、tracert、またはその他のツールを使用して両方の IP アドレスに到達できることを確認し、GDB トラフィックがファイアウォールを通過できることを確認します。

問題: EXDI を使用したカーネル デバッグを開始できませんでした。

この問題は、次の理由により発生する場合があります。

  • ホスト デバッガー コンピューター上に、実行中の ExdiGdbSrv.dll (dllhost.exe によってホストされる) の別のインスタンスがあります。
  • ExdiGdbSrv.dll をホストしている COM サービスの追加インスタンスを終了します。
    • まず、ホスト PC 上で TList などのユーティリティを使用して、プロセスを一覧表示します。 ExdiGdbSrv.dll をホストしている DLLHost に、ExdiGdbServer が表示されます。

      tlist 261928 dllhost.exe ExdiGdbServer

    • デバッガーのコマンド プロンプトで kill -f XXXXX を使用して、そのプロセス番号を使用しているプロセスを終了します。

問題: エラー: GdbServer セッションを構成できません。

この問題は、次の理由により発生する場合があります。

  • XML 構成ファイルへのパスなど、セッション情報の検索中にエラーが発生しました。

問題: エラー: EXDI_GDBSRV_XML_CONFIG_FILE 環境変数が定義されていません。

この問題は、次の理由により発生する場合があります。

  • ExdiGdbSrv.dll 環境変数が設定されていないか、環境で使用できません。

問題: エラー: EXDI_GDBSRV_XML_CONFIG_FILE 環境変数が定義されていません。Exdi-GdbServer サンプルは、この時点では続行されません。EXMI XML 構成ファイルへの完全なパスを設定してください。

この問題は、次の理由により発生する場合があります。

  • EXDI_GDBSRV_XML_CONFIG_FILE 環境変数が設定されていません。 状況によっては、[OK] ボタンを押しても ExdiGDbSrv.dll は動作し続けますが、windbg.exe でシステム レジスタのクエリの実行が失敗します (例: rdmsr/wrmsr 関数を使用)。

問題: ターゲット システムでのエラー シナリオが使用できない - DbgCoInitialize が 0x00000001 を返しました

ターゲット システムが読み込まれていない場合か使用できない場合は、次の出力が返される可能性があります。

Microsoft (R) Windows Debugger Version 10.0.20317.1 AMD64
Copyright (c) Microsoft Corporation. All rights reserved.

EXDI: DbgCoInitialize returned 0x00000001

これは、ExdiGdbSrv.dll COM サーバーが QEMU GDServer に接続できなかったときの一般的なエラーであり、原因には以下のようなものがあります。

  • dllhost.exe プロセス (COM 関連) を介して EXDI COM サーバー (ExdiGDbSrv.dll) を起動する際のエラー。 これを解決するには、ホスト デバッガー PC を再起動するか、Windows からサインアウトしてもう一度サインインします。 それでも問題が解決しない場合は、再起動またはサインイン後に EXDI COM サーバーを登録し直します。

    • regsvr32.exe <full path to the ExdiGdbSrv.dll)
  • ExdiGdbSrv.dll の前回のセッションが dllhost.exe プロセスによってホストされたままであるため、dllhost.exe プロセスを強制終了する必要があります。 ExdiGdbSrv.dll をホストする dllhost.exe の pid を tlist で確認し、関連付けられている pid を強制終了します。

  • QEMU gdbserver がまだ起動されていないか、exdiconfigdata.xml ファイルに無効な IP:Port 値が含まれています。 WinDbg セッションが QEMU Windows VM と同じホスト PC で起動された場合は、IP=LocalHost です。

問題: デバッグ セッションを開始できませんでした: FAILURE HR=0x80004005:AttachKernel に失敗しました。

この問題は、次の理由により発生する場合があります。

  • 前述のように、ExdiGdbSrv.dll の前回のセッションがまだアクティブである可能性があります。 前述のように、関連付けられている DLL ホストを特定して終了します。

WinDbg dialog box displaying failure with HR 0x80004005.

EXDI XML 構成ファイル

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

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

  2. Systemregister.xml - このファイルには、システム レジスタとそのアクセス コードの間のマッピングが含まれます。 これは、GDB サーバーはアクセス コードを XML ファイルで提供しておらず、デバッガーはアクセス コードを介して各システム レジスタにアクセスするためです。 このファイルが環境変数 EXDI_SYSTEM_REGISTERS_MAP_XML_FILE で設定されていない場合、ExdiGdbSrv.dll は引き続き動作しますが、デバッガーはどのシステム レジスタにも rdmsr コマンドまたは wrmsr コマンドでアクセスできません。 これらのレジスタの一覧は、GDB サーバー ハードウェア デバッガーでサポートされている必要があります (特定のシステム レジスタ名が、システム XML ファイルで送信されるレジスタ一覧に存在する必要があります)。

GDBServer のタグと属性

次の表で、exdiConfigData.xml ファイルで定義される GDBServer のタグと属性について説明しています。

パラメーター 説明
ExdiTargets GDB サーバー ターゲットとの GDB 接続を確立するために ExdiGgbSrv.dll によって使用される特定の GDB サーバー ターゲット構成を指定します。これは、exdiConfigData.xml ファイルには、ExdiGdbSrv.dll で現在サポートされているすべての GDB サーバーが含まれているためです (特定の GDB サーバーで ExdiGdbSrv.dll を使用する前に、このファイルに値が入力されている必要があります)。
CurrentTarget GDB サーバー ターゲットの名前を指定します (たとえば、exdiConfigData.xml ファイルに含まれる <ExdiTarget Name= タグのいずれかの名前値とこの属性値が一致する必要があります)。
ExdiTarget これは、各 GDB サーバー ターゲット コンポーネントに含まれるすべての構成データの開始タグです。
名前 GDB サーバーの名前を指定します (QEMU、BMC-OpenOCD、Trace32、VMWare など)。
agentNamePacket これは、GDB サーバー HW デバッガーによって認識される GDB クライアントの名前です。 これは、GDB サーバー HW デバッガーが特定の GDB クライアント向けに自身を構成するために使用できます (たとえば、Trace32 GDB サーバーでは、windbg-GDB クライアントを識別するために ExdiGdbSrv.dll が "QMS.windbg" という名前を送信した後に、MS GDB サーバー クライアント (exdiGdbSrv.dll) でのみサポートされるカスタマイズされた GDB メモリ パケットを有効にする必要があります)。
ExdiGdbServerConfigData ExdiGdbSrv.dll コンポーネント関連の構成パラメーターを指定します。
uuid ExdiGdbSrv.dll コンポーネントの UUI を指定します。
displayCommPackets "yes" の場合はフラグを設定し、コマンド ログ ウィンドウに RSP プロトコル通信文字を表示します。 "no" の場合は、要求と応答のペアのテキストだけが表示されます。
enableThrowExceptionOnMemoryErrors この属性は、GDB エラー応答パケット (E0x) がある場合に GDB サーバー クライアントによってチェックされ、クライアントが例外をスローしてメモリの読み取りを停止する必要があるかどうかを判断します。
qSupportedPacket これにより、XML ターゲット記述ファイルに続いて GDB サーバー HW デバッガーによって送信される XML レジスタ アーキテクチャ ファイルを要求するように、GDB クライアントを構成できます (クライアントは基本的に、クライアントでサポートされるアーキテクチャを GDB サーバーに通知します。現在、クライアントは現在、x64 アーキテクチャをサポートしています)。
ExdiGdbServerTargetData GdbServer セッションによってデバッグされるハードウェア ターゲットに関連するパラメーターを指定します。
targetArchitecture ターゲット ハードウェア アーキテクチャを含む文字列。 使用可能な値: X86、X64、ARM、ARM64。 現在、exdiGdbSrv.dll では X86 と ARM のみがサポートされています。
targetFamily ターゲット ハードウェア ファミリを含む文字列。 使用可能な値: ProcessorFamilyX86、ProcessorFamilyX64、ProcessorFamilyARM、ProcessorFamilyARM64。
numberOfCores ターゲットがサポートするプロセッサ コアの数。 このパラメーターは、マルチ Gdbserver セッション (T32-GdbServer セッション) を使用するときに検証されます。 後述の MultiCoreGdbServerSessions 属性を "yes" に設定する必要があります。
EnableSseContext "yes" の場合はフラグを設定し、'g' コンテキスト RSP パケットには浮動小数点レジスタ値が含まれます。 このパラメーターは、Intel ファミリのターゲットに対してのみ有効です。
heuristicScanSize 属性値が指定されていない (または "0" である) 場合、スキャンされたメモリ プローブを指定サイズだけ減らすためにデバッガー エンジンの高速ヒューリスティック アルゴリズムが構成され、その後、デバッガー エンジンは高速ヒューリスティックを使用せずに、PE DOS 署名を探してメモリ全体をスキャンする従来のヒューリスティックにフォールバックします。
targetDescriptionFile GDB サーバーが個別の XML ファイルを送信する前にターゲット記述ヘッダー ファイルを送信するかどうかを指定します。 このフィールドが空白の場合、GDB サーバー クライアントは XML アーキテクチャ システム レジスタを要求しません (たとえば、アーキテクチャ レジスタを個別の XML ファイルとして送信することをサポートしていない Trace32 GDBs サーバー)。
GdbServerConnectionParameters GdbServer セッション パラメーターを指定します。 これらのパラメーターは、ExdiGdbSrv.dll コンポーネントと GdbServer の間の RSP GdbServer セッションを制御するために使用されます。
MultiCoreGdbServerSessions "yes" の場合はフラグを設定し、マルチコア GdbServer セッション (T32-GdbServer バックエンドで使用されるセッション) が作成されます。 "no" の場合、GdbServer の 1 つのインスタンスとのみ通信します。
MaximumGdbServerPacketLength これは、1 パケットでサポートされる GdbServer の最大長です。
MaximumConnectAttempts これは、接続の最大試行回数です。 これは、GdbServer との RSP 接続の確立を試みる際に、ExdiGdbSrv.dll によって使用されます。
SendPacketTimeout これは RSP 送信タイムアウトです。
ReceivePacketTimeout これは RSP 受信タイムアウトです。
HostNameAndPort これは、<hostname/ip address:Port number> 形式の接続文字列です。 複数の GdbServer 接続文字列 (T32 マルチコア GdbServer セッションなど) が存在する可能性があります。 接続文字列の数は、コアの数と一致する必要があります。
ExdiGdbServerMemoryCommands さまざまな例外 CPU レベルでシステム レジスタ値または読み取り/書き込みアクセス メモリを取得するために、GDB メモリ コマンドを発行するさまざまな方法を指定します (たとえば、BMC-OpenOCD は、カスタマイズされたコマンド"aarch64 mrs nsec/sec <access code>" を使用して CP15 レジスタへのアクセスを提供します)。
GdbSpecialMemoryCommand "yes" の場合、GDB サーバーは、カスタマイズされたメモリ コマンドをサポートします (たとえばシステム レジスタは Trace32 GDB サーバー用に設定する必要があります)。
PhysicalMemory "yes" の場合、GDB サーバーは、物理メモリの読み取りに関するカスタマイズされたコマンドをサポートします (Trace32 GDB サーバー用に設定されています)。
SupervisorMemory "yes" の場合、GDB サーバーは、スーパーバイザー メモリの読み取りに関するカスタマイズされたコマンドをサポートします (Trace32 GDB サーバー用に設定されています)。
SpecialMemoryRegister "yes" の場合、GDB サーバーは、システム レジスタの読み取りに関するカスタマイズされたコマンドをサポートします (Trace32 GDB サーバー用に設定されています)
SystemRegistersGdbMonitor "yes" の場合、GDB サーバーは、GDB モニター コマンドを使用するカスタマイズされたコマンドをサポートします (BMC Open-OCD 用に設定されています)。
SystemRegisterDecoding "yes" の場合、GDB クライアントは、GDB モニター コマンドを送信する前にアクセス コードのデコードを受け入れます。
ExdiGdbServerRegisters 特定のアーキテクチャ レジスタ コア セットを指定します。
Architecture 定義されたレジスタ セットの CPU アーキテクチャ。
FeatureNameSupported これは、XML システム レジスタ記述ファイルによって提供されるシステム レジスタ グループの名前です。 GDB サーバーによって送信される際に、XML ファイルの一部であるシステム レジスタ XML グループを識別するために必要です。
SystemRegistersStart この目的は、コア レジスタ セットの一部として報告される最初のシステム レジスタ (レジスタ番号/順序が小さいもの) を識別することです (たとえば X64 では、QEMU は x64 システム レジスタ セットを別個の XML ターゲット記述ファイルとして報告しないため、システム レジスタはコア レジスタの一部となります)。
SystemRegistersEnd この目的は、コア レジスタ セットの一部として報告される最後のシステム レジスタ (レジスタ番号/順序が大きいもの) を識別することです。
名前 レジスタの名前。
注文 これは、レジスタの配列内のインデックスを識別する数値です。 この数値は、GDB クライアントとサーバーのセット/クエリ (p<number>”/”q<number>) レジスタ パケットによって使用されます。
サイズ これはレジスタ サイズ (バイト単位) です。

サンプル exdiConfigData.xml ファイル

<ExdiTargets CurrentTarget = "QEMU">
<!-- QEMU SW simulator GDB server configuration -->
    <ExdiTargets CurrentTarget="QEMU">
    <!--  QEMU SW simulator GDB server configuration  -->
    <ExdiTarget Name="QEMU">
    <ExdiGdbServerConfigData agentNamePacket="" uuid="72d4aeda-9723-4972-b89a-679ac79810ef" displayCommPackets="yes" debuggerSessionByCore="no" enableThrowExceptionOnMemoryErrors="yes" qSupportedPacket="qSupported:xmlRegisters=aarch64,i386">
    <ExdiGdbServerTargetData targetArchitecture="ARM64" targetFamily="ProcessorFamilyARM64" numberOfCores="1" EnableSseContext="no" heuristicScanSize="0xfffe" targetDescriptionFile="target.xml"/>
    <GdbServerConnectionParameters MultiCoreGdbServerSessions="no" MaximumGdbServerPacketLength="1024" MaximumConnectAttempts="3" SendPacketTimeout="100" ReceivePacketTimeout="3000">
    <Value HostNameAndPort="LocalHost:1234"/>
    </GdbServerConnectionParameters>
    <ExdiGdbServerMemoryCommands GdbSpecialMemoryCommand="no" PhysicalMemory="no" SupervisorMemory="no" HypervisorMemory="no" SpecialMemoryRegister="no" SystemRegistersGdbMonitor="no" SystemRegisterDecoding="no"> </ExdiGdbServerMemoryCommands>
        <ExdiGdbServerRegisters Architecture = "ARM64" FeatureNameSupported = "sys">
            <Entry Name ="X0"  Order = "0" Size = "8" />
            <Entry Name ="X1"  Order = "1" Size = "8" />
            <Entry Name ="X2"  Order = "2" Size = "8" />
            <Entry Name ="X3"  Order = "3" Size = "8" />
            <Entry Name ="X4"  Order = "4" Size = "8" />
            <Entry Name ="X5"  Order = "5" Size = "8" />
            <Entry Name ="X6"  Order = "6" Size = "8" />
            <Entry Name ="X7"  Order = "7" Size = "8" />
            <Entry Name ="X8"  Order = "8" Size = "8" />
            <Entry Name ="X9"  Order = "9" Size = "8" />
            <Entry Name ="X10" Order = "a"  Size = "8" />
            <Entry Name ="X11" Order = "b"  Size = "8" />
            <Entry Name ="X12" Order = "c"  Size = "8" />
            <Entry Name ="X13" Order = "d"  Size = "8" />
            <Entry Name ="X14" Order = "e"  Size = "8" />
            <Entry Name ="X15" Order = "f"  Size = "8" />
            <Entry Name ="X16" Order = "10" Size = "8" />
            <Entry Name ="X17" Order = "11" Size = "8" />
            <Entry Name ="X18" Order = "12" Size = "8" />
            <Entry Name ="X19" Order = "13" Size = "8" />
            <Entry Name ="X20" Order = "14" Size = "8" />
            <Entry Name ="X21" Order = "15" Size = "8" />
            <Entry Name ="X22" Order = "16" Size = "8" />
            <Entry Name ="X23" Order = "17" Size = "8" />
            <Entry Name ="X24" Order = "18" Size = "8" />
            <Entry Name ="X25" Order = "19" Size = "8" />
            <Entry Name ="X26" Order = "1a" Size = "8" />
            <Entry Name ="X27" Order = "1b" Size = "8" />
            <Entry Name ="X28" Order = "1c" Size = "8" />
            <Entry Name ="fp"  Order = "1d" Size = "8" />
            <Entry Name ="lr"  Order = "1e" Size = "8" />
            <Entry Name ="sp"  Order = "1f" Size = "8" />
            <Entry Name ="pc"  Order = "20" Size = "8" />
            <Entry Name ="cpsr" Order = "21" Size = "8" />
            <Entry Name ="V0" Order = "22" Size = "16" />
            <Entry Name ="V1" Order = "23" Size = "16" />
            <Entry Name ="V2" Order = "24" Size = "16" />
            <Entry Name ="V3" Order = "25" Size = "16" />
            <Entry Name ="V4" Order = "26" Size = "16" />
            <Entry Name ="V5" Order = "27" Size = "16" />
            <Entry Name ="V6" Order = "28" Size = "16" />
            <Entry Name ="V7" Order = "29" Size = "16" />
            <Entry Name ="V8" Order = "2a" Size = "16" />
            <Entry Name ="V9" Order = "2b" Size = "16" />
            <Entry Name ="V10" Order = "2c" Size = "16" />
            <Entry Name ="V11" Order = "2d" Size = "16" />
            <Entry Name ="V12" Order = "2e" Size = "16" />
            <Entry Name ="V13" Order = "2f" Size = "16" />
            <Entry Name ="V14" Order = "30" Size = "16" />
            <Entry Name ="V15" Order = "31" Size = "16" />
            <Entry Name ="V16" Order = "32" Size = "16" />
            <Entry Name ="V17" Order = "33" Size = "16" />
            <Entry Name ="V18" Order = "34" Size = "16" />
            <Entry Name ="V19" Order = "35" Size = "16" />
            <Entry Name ="V20" Order = "36" Size = "16" />
            <Entry Name ="V21" Order = "37" Size = "16" />
            <Entry Name ="V22" Order = "38" Size = "16" />
            <Entry Name ="V23" Order = "39" Size = "16" />
            <Entry Name ="V24" Order = "3a" Size = "16" />
            <Entry Name ="V25" Order = "3b" Size = "16" />
            <Entry Name ="V26" Order = "3c" Size = "16" />
            <Entry Name ="V27" Order = "3d" Size = "16" />
            <Entry Name ="V28" Order = "3e" Size = "16" />
            <Entry Name ="V29" Order = "3f" Size = "16" />
            <Entry Name ="V30" Order = "3f" Size = "16" />
            <Entry Name ="V31" Order = "3f" Size = "16" />
            <Entry Name ="fpsr" Order = "40" Size = "4" />
            <Entry Name ="fpcr" Order = "41" Size = "4" />
        </ExdiGdbServerRegisters>


        <!-- x64 GDB server core resgisters -->
        <ExdiGdbServerRegisters Architecture = "X64" FeatureNameSupported = "sys" SystemRegistersStart = "18" SystemRegistersEnd = "20" >
            <Entry Name ="rax" Order = "0" Size ="8" />
            <Entry Name ="rbx" Order = "1" Size ="8" />
            <Entry Name ="rcx" Order = "2" Size ="8" />
            <Entry Name ="rdx" Order = "3" Size ="8" />
            <Entry Name ="rsi" Order = "4" Size ="8" />
            <Entry Name ="rdi" Order = "5" Size ="8" />
            <Entry Name ="rbp" Order = "6" Size ="8" />
            <Entry Name ="rsp" Order = "7" Size ="8" />
            <Entry Name ="r8"  Order = "8" Size ="8" />
            <Entry Name ="r9"  Order = "9" Size ="8" />
            <Entry Name ="r10" Order = "a" Size ="8" />
            <Entry Name ="r11" Order = "b" Size ="8" />
            <Entry Name ="r12" Order = "c" Size ="8" />
            <Entry Name ="r13" Order = "d" Size ="8" />
            <Entry Name ="r14" Order = "e" Size ="8" />
            <Entry Name ="r15" Order = "f" Size ="8" />
            <Entry Name ="rip" Order = "10" Size ="8" />
            <!-- <flags id="x64_eflags" size="4">
                <field name="" start="22" end="31"/>
                <field name="ID" start="21" end="21"/>
                <field name="VIP" start="20" end="20"/>
                <field name="VIF" start="19" end="19"/>
                <field name="AC" start="18" end="18"/>
                <field name="VM" start="17" end="17"/>
                <field name="RF" start="16" end="16"/>
                <field name="" start="15" end="15"/>
                <field name="NT" start="14" end="14"/>
                <field name="IOPL" start="12" end="13"/>
                <field name="OF" start="11" end="11"/>
                <field name="DF" start="10" end="10"/>
                <field name="IF" start="9" end="9"/>
                <field name="TF" start="8" end="8"/>
                <field name="SF" start="7" end="7"/>
                <field name="ZF" start="6" end="6"/>
                <field name="" start="5" end="5"/>
                <field name="AF" start="4" end="4"/>
                <field name="" start="3" end="3"/>
                <field name="PF" start="2" end="2"/>
                <field name="" start="1" end="1"/>
                <field name="CF" start="0" end="0"/>
            </flags> -->
            <Entry Name ="eflags" Order = "11" Size ="4" />

            <!-- Segment registers -->
            <Entry Name ="cs" Order = "12" Size ="4" />
            <Entry Name ="ss" Order = "13" Size ="4" />
            <Entry Name ="ds" Order = "14" Size ="4" />
            <Entry Name ="es" Order = "15" Size ="4" />
            <Entry Name ="fs" Order = "16" Size ="4" />
            <Entry Name ="gs" Order = "17" Size ="4" />

            <!-- Segment descriptor caches and TLS base MSRs -->
            <!--Entry Name ="cs_base" Order = "18" Size="8"/
            <Entry Name ="ss_base" Order = "18" Size ="8" />
            <Entry Name ="ds_base" Order = "19" Size ="8" />
            <Entry Name ="es_base" Order = "1a" Size ="8" /> -->
            <Entry Name ="fs_base" Order = "18" Size ="8" />
            <Entry Name ="gs_base" Order = "19" Size ="8" />
            <Entry Name ="k_gs_base" Order = "1a" Size ="8" />

            <!-- Control registers -->
            <!-- the cr0 register format fields:
            <flags id="x64_cr0" size="8">
            <field name="PG" start="31" end="31"/>
            <field name="CD" start="30" end="30"/>
            <field name="NW" start="29" end="29"/>
            <field name="AM" start="18" end="18"/>
            <field name="WP" start="16" end="16"/>
            <field name="NE" start="5" end="5"/>
            <field name="ET" start="4" end="4"/>
            <field name="TS" start="3" end="3"/>
            <field name="EM" start="2" end="2"/>
            <field name="MP" start="1" end="1"/>
            <field name="PE" start="0" end="0"/>
            </flags> -->
            <Entry Name ="cr0" Order = "1b" Size ="8" />
            <Entry Name ="cr2" Order = "1c" Size ="8" />

            <!-- the cr3 register format fields:
            <flags id="x64_cr3" size="8">
                <field name="PDBR" start="12" end="63"/>
                <field name="PCID" start="0" end="11"/>
            </flags> -->
            <Entry Name ="cr3" Order = "1d" Size ="8" />

            <!-- the cr4 register format fields:
            <flags id="x64_cr4" size="8">
                <field name="PKE" start="22" end="22"/>
                <field name="SMAP" start="21" end="21"/>
                <field name="SMEP" start="20" end="20"/>
                <field name="OSXSAVE" start="18" end="18"/>
                <field name="PCIDE" start="17" end="17"/>
                <field name="FSGSBASE" start="16" end="16"/>
                <field name="SMXE" start="14" end="14"/>
                <field name="VMXE" start="13" end="13"/>
                <field name="LA57" start="12" end="12"/>
                <field name="UMIP" start="11" end="11"/>
                <field name="OSXMMEXCPT" start="10" end="10"/>
                <field name="OSFXSR" start="9" end="9"/>
                <field name="PCE" start="8" end="8"/>
                <field name="PGE" start="7" end="7"/>
                <field name="MCE" start="6" end="6"/>
                <field name="PAE" start="5" end="5"/>
                <field name="PSE" start="4" end="4"/>
                <field name="DE" start="3" end="3"/>
                <field name="TSD" start="2" end="2"/>
                <field name="PVI" start="1" end="1"/>
                <field name="VME" start="0" end="0"/>
            </flags> -->
            <Entry Name ="cr4" Order = "1e" Size ="8" />
            <Entry Name ="cr8" Order = "1f" Size ="8" />

            <!-- the efer register format fields:
            <flags id="x64_efer" size="8">
            <field name="TCE" start="15" end="15"/>
            <field name="FFXSR" start="14" end="14"/>
            <field name="LMSLE" start="13" end="13"/>
            <field name="SVME" start="12" end="12"/>
            <field name="NXE" start="11" end="11"/>
            <field name="LMA" start="10" end="10"/>
            <field name="LME" start="8" end="8"/>
            <field name="SCE" start="0" end="0"/>
            </flags> -->
            <Entry Name ="efer" Order = "20" Size ="8"/>

            <!-- x87 FPU -->
            <Entry Name ="st0" Order = "21" Size ="10" />
            <Entry Name ="st1" Order = "22" Size ="10" />
            <Entry Name ="st2" Order = "23" Size ="10" />
            <Entry Name ="st3" Order = "24" Size ="10" />
            <Entry Name ="st4" Order = "25" Size ="10" />
            <Entry Name ="st5" Order = "26" Size ="10" />
            <Entry Name ="st6" Order = "27" Size ="10" />
            <Entry Name ="st7" Order = "28" Size ="10" />
            <Entry Name ="fctrl" Order = "29" Size ="4" />
            <Entry Name ="fstat" Order = "2a" Size ="4" />
            <Entry Name ="ftag"  Order = "2b" Size ="4" />
            <Entry Name ="fiseg" Order = "2c" Size ="4" />
            <Entry Name ="fioff" Order = "2d" Size ="4" />
            <Entry Name ="foseg" Order = "2e" Size ="4" />
            <Entry Name ="fooff" Order = "2f" Size ="4" />
            <Entry Name ="fop" Order = "30" Size ="4" />
            <Entry Name ="xmm0" Order = "31" Size ="16"  />
            <Entry Name ="xmm1" Order = "32" Size ="16"  />
            <Entry Name ="xmm2" Order = "33" Size ="16"  />
            <Entry Name ="xmm3" Order = "34" Size ="16"  />
            <Entry Name ="xmm4" Order = "35" Size ="16"  />
            <Entry Name ="xmm5" Order = "36" Size ="16"  />
            <Entry Name ="xmm6" Order = "37" Size ="16"  />
            <Entry Name ="xmm7" Order = "38" Size ="16"  />
            <Entry Name ="xmm8" Order = "39" Size ="16"  />
            <Entry Name ="xmm9" Order = "3a" Size ="16"  />
            <Entry Name ="xmm10" Order = "3b" Size ="16"  />
            <Entry Name ="xmm11" Order = "3c" Size ="16"  />
            <Entry Name ="xmm12" Order = "3d" Size ="16"  />
            <Entry Name ="xmm13" Order = "3e" Size ="16"  />
            <Entry Name ="xmm14" Order = "3f" Size ="16"  />
            <Entry Name ="xmm15" Order = "40" Size ="16"  />
            
            <!-- the mxcsr register format fields:
            <flags id="x64_mxcsr" size="4">
                <field name="IE" start="0" end="0"/>
                <field name="DE" start="1" end="1"/>
                <field name="ZE" start="2" end="2"/>
                <field name="OE" start="3" end="3"/>
                <field name="UE" start="4" end="4"/>
                <field name="PE" start="5" end="5"/>
                <field name="DAZ" start="6" end="6"/>
                <field name="IM" start="7" end="7"/>
                <field name="DM" start="8" end="8"/>
                <field name="ZM" start="9" end="9"/>
                <field name="OM" start="10" end="10"/>
                <field name="UM" start="11" end="11"/>
                <field name="PM" start="12" end="12"/>
                <field name="FZ" start="15" end="15"/>
            </flags> -->
            <Entry Name ="mxcsr" Order = "41" Size ="4" />

        </ExdiGdbServerRegisters>
    </ExdiGdbServerConfigData>
    </ExdiTarget>
    </ExdiTargets>
</ExdiTargets>

EXDI Powershell スクリプトの例

このサンプル PowerShell スクリプトは、EXDI をインストールしてからデバッガーを起動します。 Start-ExdiDebugger.ps1 スクリプトは、必要に応じて ExdiGdbSrv.dll をインストールし、XML 設定ファイルを構成します。さらに、実行中の dllhost.exe プロセスをチェックし、デバッガーを起動して、既に実行中の GDB サーバー ハードウェア デバッグ ターゲットに接続します。

これは、スタートアップ スクリプトを呼び出す例です。

PS>.\Start-ExdiDebugger.ps1 -ExdiTarget "QEMU" -GdbPort 1234 -Architecture x64

必要に応じて、ビルドされたファイルを指定することもできます。

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

Start-ExdiDebugger.ps1 には、以下の設定オプションがあります。

パラメーター 説明
ExdiTarget 接続先となるターゲットの種類。 これは、設定 XML ファイル内の特定のセクションに対応します。
HostName GDB サーバー セッションをホストしているコンピューターの IP アドレスまたはホスト名 (既定値は "LocalHost")
GdbPort GDB サーバがリッスンしているポート。
Architecture ハードウェア デバッグ ターゲットのアーキテクチャ (このパラメーターは、XML 設定ファイルの ArchitectureFamily パラメーターも含みます)
ExdiDropPath ExdiGdbSrv.dll、exdiConfigData.xml、および systemregisters.xml ファイルの場所。 これらは、ExdiGdbSrv.dll がインストールされていない場合または正しくインストールされていない場合にのみコピーされます。
ExtraDebuggerArgs デバッガーのコマンド ラインで渡す追加の引数
PreNTAppDebugging heuristicScanSize の値を 0xfffe (NT に最適) から 0xffe (NT 以前のアプリの場合) に変更します
DontTryDllHostCleanup dllhost.exe 内で実行中の ExdiGdbSrv.dll の既存のインスタンスを確認するには、昇格が必要です。 このスイッチを指定すると、スクリプトを昇格なしで実行できます (デバッガーが正しく機能しない可能性があります)。

パケットを表示できるようにするには、displayCommPackets の値を "yes" に設定します。

    [pscustomobject]@{ Path = 'displayCommPackets'                                  ; value = "yes" } 
.\Start-ExdiDebugger.ps1 -ExdiTarget "QEMU" -GdbPort 1234 -Architecture x64 -ExdiDropPath "C:\path\to\built\exdi\files"

その他の設定オプションについては、コードのコメントを参照してください。

<#
.Synopsis
    Installs and launches exdi debugger (automating xml file editing)

.Description
    This script will install ExdiGdbSrv.dll if required, configure the xml settings
    files, check for running dllhost.exe processes, and launch the debugger to connect to
    an already running gdb server hardware debugging target.

.Parameter ExdiTarget
    Type of target to connect to. This corresponds to a specific section in the settings xml file

.Parameter HostName
    IP address or hostname of the computer hosting the gdb server session (defaults to "LocalHost")

.Parameter GdbPort
    Port that the gdb server is listening on.

.Parameter Architecture
    Architecture of the hardware debugging target (this parameter also implies the ArchitectureFamily
    parameter in the xml settings file)

.Parameter ExdiDropPath
    Location of the ExdiGdbSrv.dll, exdiConfigData.xml, and systemregisters.xml files. These will
    only be copied if ExdiGdbSrv.dll is not installed or is installed incorrectly.

.Parameter ExtraDebuggerArgs
    Extra arguments to pass on the debugger command line

.Parameter PreNTAppDebugging
    Changes the value of the heuristicScanSize from 0xfffe (best for NT) to 0xffe (for pre-NT Apps)

.Parameter DontTryDllHostCleanup
    Checking for existing running instances of ExdiGdbSrv.dll in dllhost.exe requires elevation.
    Providing this switch will allow the script to run without elevation (although the debugger may not
    function correctly).

.Example
    >---------------- (first run) ------------<
    .\Start-ExdiDebugger.ps1 -ExdiTarget "QEMU" -GdbPort 1234 -Architecture x64 -ExdiDropPath "C:\path\to\built\exdi\files"

.Example
    PS>.\Start-ExdiDebugger.ps1 -ExdiTarget "QEMU" -GdbPort 1234 -Architecture x64
#>

[CmdletBinding()]
param
(
    [ValidateSet("QEMU")]
    [string]
    $ExdiTarget = "QEMU",

    [string]
    $HostName = "LocalHost",

    [Parameter(Mandatory=$true)]
    [Int]
    $GdbPort,

    [Parameter(Mandatory=$true)]
    [string]
    [ValidateSet("x86", "x64", "arm64")]
    $Architecture,

    [string]
    $ExdiDropPath,

    [string]
    $DebuggerPath,

    [string[]]
    $ExtraDebuggerArgs = @(),

    [switch]
    $PreNTAppDebugging,

    [switch]
    $DontTryDllHostCleanup
)

$ErrorActionPreference = "Stop"

#region Functions

Function Test-Admin
{
    ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]"Administrator")
}

Function Find-PathToWindbgX
{
    $InternalWindbgXPath = "$env:LOCALAPPDATA\DBG\UI\WindbgX.exe"
    $ExternalWindbgXPath = "$env:LOCALAPPDATA\Microsoft\WindowsApps\WinDbgX.exe"

    if (Test-Path $InternalWindbgXPath -PathType Leaf)
    {
        return $InternalWindbgXPath
    }
    elseif (Test-Path $ExternalWindbgXPath -PathType Leaf)
    {
        return $ExternalWindbgXPath
    }
}

Function Test-ParameterValidation
{
    $CommandName = $PSCmdlet.MyInvocation.InvocationName
    $ParameterList = (Get-Command -Name $CommandName).Parameters

    foreach ($Parameter in $ParameterList) {
        Get-Variable -Name $Parameter.Values.Name -ErrorAction SilentlyContinue | Out-String | Write-Verbose
    }

    if (-not $DebuggerPath)
    {
        throw "WindbgX is not installed"
    }
    elseif (-not (Test-Path $DebuggerPath -PathType Leaf))
    {
        throw "DebuggerPath param ($DebuggerPath) does not point to a debugger."
    }

    # Searching for loaded instances of ExdiGdbSrv.dll in dllhost.exe requires elevation
    if (-not $DontTryDllHostCleanup -and
        -not $(Test-Admin))
    {
        throw "Searching for loaded instances of ExdiGdbSrv.dll in dllhost.exe requires elevation. Run with the -DontTryDllHostCleanup parameter to skip this check (debugger session init may fail)."
    }
}

Function Get-ExdiInstallPath
{
    Get-ItemPropertyValue -Path "Registry::HKEY_CLASSES_ROOT\CLSID\{29f9906e-9dbe-4d4b-b0fb-6acf7fb6d014}\InProcServer32" -Name "(default)" -ErrorAction SilentlyContinue
}

Function Test-ExdiServerInstalled
{
    # Check registration of exdi server class
    if ($(Get-ExdiInstallPath) -ne $null -and $(Test-Path "$(Get-ExdiInstallPath)"))
    {
        Write-Verbose "Exdi server is installed. Checking installation..."
        $ExdiInstallDir = [System.IO.Path]::GetDirectoryName($(Get-ExdiInstallPath))
        if (-not (Test-Path $ExdiInstallDir))
        {
            Write-Host "Currently Registered exdi server does not exist. Reinstalling..."
            return $false
        }
        elseif (-not ((Test-Path "$ExdiInstallDir\exdiConfigData.xml") -and (Test-Path "$ExdiInstallDir\systemregisters.xml")))
        {
            Write-Host "Currently Registered exdi server does not have required xml settings files. Reinstalling..."
            return $false
        }
        else
        {
            Write-Verbose "Exdi server is insalled correctly. Skipping installation..."
            return $true
        }
    }
    else
    {
        Write-Host "Exdi server is not installed. Installing..."
        return $false
    }
}

Function Install-ExdiServer
{
    [CmdletBinding()]
    param
    (
        [string] $InstallFrom,
        [string] $InstallTo
    )
    
    if (-not $(Test-Admin))
    {
        throw "Script needs to be run as an Admin to install exdi software."
    }

    New-Item -ItemType Directory $InstallTo -ErrorAction SilentlyContinue | Write-Verbose
    Copy-Item -Path "$InstallFrom\ExdiGdbSrv.dll" -Destination $InstallTo -ErrorAction stop | Write-Verbose
    Copy-Item -Path "$InstallFrom\exdiConfigData.xml" -Destination $InstallTo -ErrorAction stop | Write-Verbose
    Copy-Item -Path "$InstallFrom\systemregisters.xml" -Destination $InstallTo -ErrorAction stop | Write-Verbose
    regsvr32 /s "$InstallTo\ExdiGdbSrv.dll"

    if ($(Get-ExdiInstallPath) -eq $null)
    {
        throw "Unable to install exdi server"
    }
}

Function Edit-ExdiConfigFile
{
    [CmdletBinding()]
    param
    (
        [string] $ExdiFilePath,
        [string] $ExdiTargetType,
        [PSCustomObject[]] $XmlSettingPathValueList
    )
    
    # Edit exdiConfigData.xml
    [xml]$exdiConfigXml = Get-Content "$ExdiFilePath"

    # Set current target
    $exdiConfigXml.ExdiTargets.CurrentTarget = $ExdiTarget

    # set HostNameAndPort
    $ExdiTargetXmlNode = $exdiConfigXml.SelectSingleNode("//ExdiTargets/ExdiTarget[@Name='$ExdiTarget']/ExdiGdbServerConfigData")

    foreach ($XmlSettingPathValue in $XmlSettingPathValueList)
    {
        Write-Verbose "Processing $XmlSettingPathValue"
        if ($XmlSettingPathValue.Value -eq $null)
        {
            continue
        }

        $PathParts = $XmlSettingPathValue.Path.Split(".")
        $curNode = $ExdiTargetXmlNode
        if ($PathParts.Count -gt 1)
        {
            foreach ($PathPart in $PathParts[0..($PathParts.Count-2)])
            {
                Write-Verbose $PathPart
                $curNode = $curNode.($PathPart)
            }
        }
        $curNode.($PathParts[-1]) = $XmlSettingPathValue.Value
    }

    $exdiConfigXml.Save("$ExdiFilePath")
}

Function Stop-ExdiContainingDllHosts
{
    $DllHostPids = Get-Process dllhost | ForEach-Object { $_.Id }
    foreach ($DllHostPid in $DllHostPids)
    {
        $DllHostExdiDlls = Get-Process -Id $DllHostPid -Module | Where-Object { $_.FileName -like "*ExdiGdbSrv.dll" }
        if ($DllHostExdiDlls.Count -ne 0)
        {
            Write-Verbose "Killing dllhost.exe with pid $DllHostPid (Contained instance of ExdiGdbSrv.dll)"
            Stop-Process -Id $DllHostPid -Force
        }
    }
}

#endregion

#region Script

# Apply defaults for $DebuggerPath before Parameter validation
if (-not $DebuggerPath)
{
    $DebuggerPath = Find-PathToWindbgX
}

Test-ParameterValidation

# look clean up dllhost.exe early since it can hold a lock on files which
# need to be overwritten
if (-not $DontTryDllHostCleanup)
{
    Stop-ExdiContainingDllHosts
}

if (-not $(Test-ExdiServerInstalled))
{
    if (-not $ExdiDropPath)
    {
        throw "ExdiServer is not installed and -ExdiDropPath is not valid"
    }

    $ExdiInstallDir = Join-Path -Path "$([System.IO.Path]::GetDirectoryName($DebuggerPath))" -ChildPath "exdi"
    Install-ExdiServer -InstallFrom "$ExdiDropPath" -InstallTo "$ExdiInstallDir"
}

$SystemRegistersFilepath = Join-Path -Path "$([System.IO.Path]::GetDirectoryName($(Get-ExdiInstallPath)))" -ChildPath "systemregisters.xml"
$ExdiConfigFilepath      = Join-Path -Path "$([System.IO.Path]::GetDirectoryName($(Get-ExdiInstallPath)))" -ChildPath "exdiConfigData.xml"

# Calculate implied parameters
$HeuristicScanSize = if ($PreNTAppDebugging) { "0xffe" } else { "0xfffe" }
$ArchitectureFamily = switch($Architecture)
{
    x64   { "ProcessorFamilyx64" }
    x86   { "ProcessorFamilyx86" }
    arm64 { "ProcessorFamilyARM64" }
}

# Path is evaluated relative to the relevant ExdiTarget's ExdiGdbServerConfigData node in the xml schema
$SettingsToChange = @(
    [pscustomobject]@{ Path = 'GdbServerConnectionParameters.Value.HostNameAndPort' ; Value = "${HostName}:$GdbPort" },
    [pscustomobject]@{ Path = 'ExdiGdbServerTargetData.targetArchitecture'          ; Value = "$Architecture" },
    [pscustomobject]@{ Path = 'ExdiGdbServerTargetData.targetFamily'                ; Value = "$ArchitectureFamily" },
    [pscustomobject]@{ Path = 'ExdiGdbServerTargetData.heuristicScanSize'           ; Value = "$HeuristicScanSize" },
    [pscustomobject]@{ Path = 'displayCommPackets'                                  ; value = "no" }
)
Edit-ExdiConfigFile -ExdiFilePath "$ExdiConfigFilepath" -ExdiTargetType "$ExdiTarget" -XmlSettingPathValueList $SettingsToChange

# Set env vars for debugger
[System.Environment]::SetEnvironmentVariable('EXDI_GDBSRV_XML_CONFIG_FILE',"$ExdiConfigFilepath")
[System.Environment]::SetEnvironmentVariable('EXDI_SYSTEM_REGISTERS_MAP_XML_FILE',"$SystemRegistersFilepath")

$DebuggerArgs = @("-v", "-kx exdi:CLSID={29f9906e-9dbe-4d4b-b0fb-6acf7fb6d014},Kd=Guess,DataBreaks=Exdi")
Write-Verbose "DebuggerPath = $DebuggerPath"
Start-Process -FilePath "$DebuggerPath" -ArgumentList ($DebuggerArgs + $ExtraDebuggerArgs)

#endregion

関連項目

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

.exdicmd (EXDI コマンド)

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

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

カーネル モードのデバッグを手動でセットアップする