配置 EXDI 调试器传输

本主题介绍如何使用 EXDI 设置Kernel-Mode调试。 扩展调试接口 (EXDI) 是软件调试器和调试目标之间的适应层。 从 Windows 版本 22000 开始,Windows调试工具支持使用 EXDI 进行内核调试。

EXDI 可用于与 QEMU 虚拟环境建立连接。 有关详细信息,请参阅 使用 EXDI 设置 QEMU Kernel-Mode调试

注意

EXDI 是针对特定环境进行高级的专用调试形式。 使用标准 KDNET 连接更易于配置,建议使用。 若要自动设置网络调试,请参阅 “自动设置 KDNET 网络内核调试”。

EXDI COM 服务器概述

EXDI 是一个接口,通过添加对硬件调试器 (的支持(例如基于 JTAG 或基于 GdbServer) )来扩展 WinDbg。 下图说明了 EXDI-GdbServer 的角色。

A stack diagram showing role of EXDI-GdbServer with WinDbg-DbgEng on top, a exdi interface and a exdi com server talking down to a GDB server

由于 EXDI 连接不依赖于目标电脑上加载Windows或 KDNET 协议。 由于这些软件调试器组件不是必需的,因此 EXDI 在早期设备启动和调试 OS 启动问题中非常有用。

重要

由于 EXDI 不使用 KDNET 协议,因此连接的调试器对电脑上运行的内容的信息要少得多,并且许多命令的工作方式不同或根本不起作用。 访问所调试代码的专用符号可以帮助调试器更好地了解目标系统代码执行。 有关详细信息,请参阅 公共符号和专用符号

EXDI Kernel-Mode设备要求

运行调试器的计算机称为 主计算机,正在调试的计算机称为 目标计算机

将需要以下项:

  • 在目标计算机和主计算机上,所需环境(如 QEMU)支持的网卡。

  • 使用 TCP/IP 在目标与主机之间建立网络连接。

  • Windows 10或Windows 11 22000 或更高版本。

限制

  • 必须使用 XML 文件手动配置 EXDI 硬件调试,并且Windows调试器中没有相关的 UI。

  • 如上所述,由于 EXDI 不使用 KDNET 协议,因此连接的调试器对目标系统的信息较少,并且调试器的使用不同。 如果没有访问目标代码的专用符号,使用符号了解目标系统状态的许多命令将不起作用。 在这种情况下,可以查看内存并注册内容和反汇编代码。 确定运行代码的位置或执行其他常见调试器任务可能非常困难且耗时,并且使用专用符号。

COM GDB 服务器客户端

本主题介绍使用实现 EXDI COM 调试器接口的 EXDI COM GDB 服务器客户端 (ExdiGdbSrv.dll) 。 可以使用同一 COM 接口来实现其他接口,例如适用于 JTAG-DCI 的 EXDI COM 服务器。

并发 EXDI 和 KDNET 调试

在某些复杂的方案中,例如,在早期设备启动中,有两个与目标设备的连接很有用。 一个 EXDI 和一个 KDNET。 如果目标为Windows OS,则 KDNET 软件调试配置为通常,例如连接到虚拟机。 在此设置中,两个并发调试器中的任何一个都可以中断以调试目标计算机上的代码。

配置 EXDI 连接的过程摘要

在本主题中,我们将介绍配置 EXDI 连接的过程。 有关 EXDI 使用方案的示例,请参阅 使用 EXDI 设置 QEMU Kernel-Mode调试

  1. 在主机系统上下载并安装Windows调试工具。
  2. 下载、生成和注册 EXDI 服务器 DLL。
  3. 通过编辑 EXDI 配置 XML 文件来配置连接。
  4. 使用 -kx 选项启动 WinDbg 以连接到 EXDI 服务器。
  5. 使用 WinDbg 调试目标系统。

下载并安装Windows调试工具

在主机系统上安装Windows调试工具。 有关下载和安装调试器工具的信息,请参阅下载用于Windows的调试工具

下载、生成和注册 EXDI 服务器 DLL

从 microsoft/WinDbg-Samples 下载相应的二进制ExdiGdbSrv.dll二进制 (EXDI COM 服务器客户端) 源代码,GitHub https://github.com/microsoft/WinDbg-Samples)

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

根据 Exdi/exdigdbsrvsrv 中主机调试器的安装体系结构,生成 VS 解决方案 (ExdiGdbSrv.sln) 。

找到生成生成的ExdiGdbSrv.dll。

将 EXDI com 服务器 (ExdiGdbSrv.dll) 复制到包含调试器 .g 的目录中。 C:\Program Files (x86)\Windows Kits\10\Debuggers\x64C:\Debuggers)

使用 regsvr32 在管理员命令提示符中注册 DLL。

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

RegSvr32 应返回一条消息,指示 .DLLRegisterServer in ExdiGdbSrv.dll succeeded

此步骤只需完成一次,但如果更改ExdiGdbSrv.dll的位置,则需要再次注册 COM 服务器。

另一个选项是使用示例 PowerShell 脚本安装 EXDI DLL,并首次启动调试器。 有关详细信息,请参阅 示例 EXDI PowerShell 脚本

使用 EXDI 配置文件配置 WinDbg

找到两个所需的配置文件 WinDbg-Samples/Exdi/exdigdbsrv/ ,并将其复制到安装调试器的主机调试器计算机的本地。

  • exdiConfigData.xml
  • systemregisters.xml

EXDI_GDBSRV_XML_CONFIG_FILE – 描述 Exdi xml 配置文件的完整路径。

EXDI_SYSTEM_REGISTERS_MAP_XML_FILE – 描述 Exdi xml 系统注册映射文件的完整路径。

有关exdiConfigData.xml标记和属性的详细信息,请参阅下面的 EXDI XML 配置文件

在我们的方案中,我们将以下值设置为零,以禁用调试器尝试查找 nt!kdVersionBlock。

heuristicScanSize = "0"

设置 EXDI 路径值以引用 XML 配置文件的位置

设置环境变量EXDI_GDBSRV_XML_CONFIG_FILE并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 Command-Line选项。 有关详细信息,请参阅下面的 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 showing exdi CLSID on Window title

EXDIGdbServer 控制台窗口还可以显示有关 EXDI 连接状态的信息。 有关控制台的详细信息,请参阅 故障排除

EXDI WinDbg 加载参数

以下参数用于 WinDbg 来启动 EXDI 内核会话。

-kx:EXDI:Options

以下 EXDI 选项可用于 -kx 选项。

参数 说明
CLSID 分配给 LiveExdiGdbSrvServer 的类 ID (,如ExdiGdbSrv.idl 文件) 中定义。
Kd=NtBaseAddr 调试器引擎将查找 NT 基址。
ForceX86 强制调试器引擎使用 IeXdiX86Context3 接口获取/设置 CPU 上下文。
DataBreaks=Exdi 允许使用数据断点。
Inproc 允许使用 inproc Exdi-Server。

使用 WinDbg 调试目标系统

dbgeng.dll使用启发式算法查找发生中断命令时 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(查找映像标头)

Imgscan 可用于 EDXI 调试,与传统的基于 KDNET 的内核调试不同,基于符号的设置断点可能不可用。 定位所需的目标映像有助于使用其位置设置内存访问断点。

.exdicmd(EXDI 命令)

.exdicmd 使用活动 EXDI 调试连接将 EXDI 命令发送到目标系统。 有关详细信息,请参阅 .exdicmd (EXDI 命令)

疑难解答

使用 ExdiGdbServer 窗口的输出监视连接序列。

ExdiGdbServer text window showing long hex numbers

问题:错误:无法与 GbDServer 建立连接。 请验证连接字符串 <hostname/ip>:portnumber

此问题可能是由:

  • ExdiGdbSrv.dll无法连接到目标 GDB 服务器。
  • GDB 服务器尚未在目标上运行。
  • 防火墙问题,确保可以通过 ping、tracert 或其他工具访问这两个 IP 地址,以验证 GDB 流量是否可以通过防火墙。

问题:无法使用 EXDI 启动内核调试。

此问题可能是由:

  • 主机调试器计算机上运行dllhost.exe) 托管ExdiGdbSrv.dll (的另一个实例。
  • 终止托管ExdiGdbSrv.dll的 COM 服务的额外实例。
    • 首先使用主机电脑上的 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示例。请设置 Exdi xml 配置文件的完整路径。

此问题可能是由:

  • 设置EXDI_GDBSRV_XML_CONFIG_FILE环境变量。 在某些情况下,如果按“确定”按钮,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 时,这是一个常见错误,因此可能会因为以下原因而失败:

  • 通过与 COM 相关的) dllhost.exe (进程启动 EXDI COM 服务器 (ExdiGDbSrv.dll) 时失败。 若要解决此问题,请重启主机调试器电脑或注销Windows并再次登录。 如果不起作用,请再次重启/登录后重新注册 EXDI COM 服务器。

    • regsvr32.exe <full path to the ExdiGdbSrv.dll)
  • ExdiGdbSrv.dll的上一个会话仍由dllhost.exe进程托管,因此需要终止dllhost.exe进程。 检查托管ExdiGdbSrv.dll并终止关联 pid 的dllhost.exe的 pid 列表。

  • QEMU gdbserver 尚未启动,或者exdiconfigdata.xml文件包含无效的 IP:Port 值。 如果在 QEMU Windows VM 所在的主机电脑上启动 WinDbg 会话,则 IP=LocalHost。

问题:无法启动调试会话:FAILURE HR=0x80004005:Failed to AttachKernel。

此问题可能是由:

  • 如上所述,ExdiGdbSrv.dll的上一个会话可能仍然处于活动状态。 找到并终止关联的 DLL 主机,如上所述。

windbg dialog box showing failure HR 0x80004005

EXDI XML 配置文件

EXDI GDB COM 服务器 (ExdiGdbSrv.dll) 使用两个必需的 xml 文件。

  1. exdiConfigData.xml - 此文件包含 GDB 服务器客户端在 HW 调试器 GDB 服务器目标中成功建立 GDB 会话所需的主配置数据,因此,如果文件位置未由EXDI_GDBSRV_XML_CONFIG_FILE环境变量设置,则 GDB 服务器客户端 不会 运行。 每个 xml 标记都允许配置特定 GDB 服务器功能集。 有关可在 XML 中修改的属性列表以及示例 XML,请参阅下面。

  2. Systemregister.xml - 此文件包含系统寄存器及其访问代码之间的映射。 这是必需的,因为 XML 文件中 GDB 服务器不提供访问代码,调试器通过访问代码访问每个系统注册。 如果未通过环境变量 EXDI_SYSTEM_REGISTERS_MAP_XML_FILE设置文件,则ExdiGdbSrv.dll将继续工作,但调试器将无法通过 rdmsr 或 wrmsr 命令访问任何系统注册。 GDB 服务器硬件调试器应支持这些寄存器的列表, (特定系统注册名称应出现在系统 xml 文件) 中发送的寄存器列表中。

GDBServer 标记和属性

下表描述了文件中定义的 exdiConfigData.xml GDBServer 标记和属性。

参数 说明
ExdiTargets 指定ExdiGgbSrv.dll将使用哪些特定的 GDB 服务器目标配置与 GDB 服务器目标建立 GDB 连接,因为exdiConfigData.xml文件包括当前ExdiGdbSrv.dll (此文件支持的所有 GDB 服务器,然后才能将ExdiGdbSrv.dll与特定 GDB 服务器) 一起使用。
CurrentTarget 指定 GDB 服务器目标的名称 (,例如,此属性值应与exdiConfigData.xml文件包含的 <ExdiTarget Name= 标记之一的名称值匹配。
ExdiTarget 这是每个 GDB 服务器目标组件包含的所有配置数据的起始标记。
名称 指定 GDB 服务器的名称 (,例如 QEMU、BMC-OpenOCD、Trace32、VMWare) 。
agentNamePacket 这是 GDB 客户端的名称,因为它由 GDB 服务器 HW 调试器识别。 GDB 服务器 HW 调试器可用于为特定 GDB 客户端配置自身 (,例如 Trace32 GDB 服务器要求ExdiGdbSrv.dll发送“QMS.windbg”名称来标识 windbg-GDB 客户端,然后启用仅支持 MS GDB 服务器客户端 (exdiGdbSrv.dll) 的自定义 GDB 内存数据包。
ExdiGdbServerConfigData 指定与组件相关的ExdiGdbSrv.dll配置参数。
uuid 指定ExdiGdbSrv.dll组件的 UUI。
displayCommPackets 如果为“是”,则会在命令日志窗口中显示 RSP 协议通信字符。 如果为“否”,则仅显示请求-响应配对文本。
enableThrowExceptionOnMemoryErrors 当 GDB 错误响应数据包 (E0x) 时,GDB 服务器客户端将检查此属性,以确定客户端是否应引发异常并停止读取内存。
qSupportedPacket 这允许将 GDB 客户端配置为请求 GDB 服务器 HW 调试器应发送哪些 xml 寄存器体系结构文件,但基本 (xml 目标说明文件后,客户端会通知 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 如果为“是”,则“g”上下文 RSP 数据包将包含浮点寄存器值。 此参数仅适用于 Intel 系列目标。
heuristicScanSize 这将配置调试器引擎快速启发式算法,以按指定大小减少扫描的内存探测, 如果未指定属性值 (或“0”) ,则调试器引擎不会使用快速启发式,并回退到扫描整个内存以查找 PE DOS 签名的旧启发式。
targetDescriptionFile 指定 GDB 服务器是否在发送每个单独的 xml 文件之前发送目标说明头文件。 此字段为空,则 GDB 服务器客户端不会请求 xml 体系结构系统注册 (例如,不支持在单独的 xml 文件中发送体系结构寄存器的 Trace32 GDB 服务器) 。
GdbServerConnectionParameters 指定 GdbServer 会话参数。 这些参数用于控制ExdiGdbSrv.dll组件与 GdbServer 之间的 RSP GdbServer 会话。
MultiCoreGdbServerSessions 标志如果为“是”,则我们将具有多核 GdbServer 会话, (T32-GdbServer后端) 使用的会话。 如果“否”,我们将仅与 GdbServer 的一个实例通信。
MaximumGdbServerPacketLength 这是一个数据包支持的最大 GdbServer 长度。
MaximumConnectAttempts 这是最大连接尝试次数。 尝试建立与 GdbServer 的 RSP 连接时,ExdiGdbSrv.dll使用它。
SendPacketTimeout 这是 RSP 发送超时。
ReceivePacketTimeout 这是 RSP 接收超时。
HostNameAndPort 这是采用格式 <hostname/ip address:Port number>的连接字符串。 可以有多个 GdbServer 连接字符串 (,例如 T32 多核 GdbServer 会话) 。 连接字符串数应与核心数匹配。
ExdiGdbServerMemoryCommands 指定发出 GDB 内存命令的各种方法,以便在不同的异常 CPU 级别获取系统寄存器值或读/写访问内存 (,例如,BMC-OpenOCD通过“aarch64 mrs nsec/sec <access code>”自定义命令) 提供对 CP15 寄存器的访问权限。
GdbSpecialMemoryCommand 如果为“是”,则 GDB 服务器支持自定义内存命令 (例如系统寄存器,则应为 Trace32 GDB 服务器) 设置此命令。
PhysicalMemory 如果为“是”,则 GDB 服务器支持用于读取物理内存的自定义命令, (它设置为 Trace32 GDB 服务器) 。
SupervisorMemory 如果为“是”,则 GDB 服务器支持用于读取监督器内存的自定义命令, (它设置为 Trace32 GDB 服务器) 。
SpecialMemoryRegister 如果为“是”,则 GDB 服务器支持用于读取系统寄存器的自定义命令, (它设置为 Trace32 GDB 服务器)
SystemRegistersGdbMonitor 如果为“是”,则 GDB 服务器通过 GDB 监视器命令支持自定义命令, (它设置为 BMC Open-OCD) 。
SystemRegisterDecoding 如果为“是”,则 GDB 客户端在发送 GDB 监视器命令之前接受解码访问代码。
ExdiGdbServerRegisters 指定特定的体系结构注册核心集。
体系结构 定义的寄存器集的 CPU 体系结构。
FeatureNameSupported 这是由 xml 系统注册说明文件提供的系统注册组的名称。 需要标识系统注册 xml 组,该组是 XML 文件的一部分,因为它由 GDB 服务器发送。
SystemRegistersStart 这是为了标识作为核心寄存器集 ((例如在 X64 上)报告的第一个系统寄存器 (低寄存器号/顺序) ,QEMU 不会将 x64 系统寄存器设置为单独的 xml 目标析构文件,因此系统 regs 是核心寄存器) 的一部分。
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 服务器正在侦听的端口。
体系结构 硬件调试目标的体系结构 (此参数还意味着 xml 设置文件中的 ArchitectureFamily 参数)
ExdiDropPath ExdiGdbSrv.dll、exdiConfigData.xml和systemregisters.xml文件的位置。 仅当ExdiGdbSrv.dll未安装或安装不正确时,才会复制这些副本。
ExtraDebuggerArgs 用于在调试器命令行上传递的额外参数
PreNTAppDebugging 将启发式ScanSize 的值从最适合 NT) 的0xfffe (更改为预 NT 应用) 0xffe (
DontTryDllHostCleanup 检查dllhost.exe中现有运行ExdiGdbSrv.dll实例需要提升。 提供此开关将允许脚本在没有提升 (的情况下运行,尽管调试器可能无法正常工作) 。

若要启用要显示的数据包,请将 displayCommPackets 的值设置为“是”。

    [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 网络内核调试

手动设置内核模式调试