다음을 통해 공유


EXDI 디버거 전송 구성

이 항목에서는 EXDI를 사용하여 커널 모드 디버깅을 설정하는 방법을 설명합니다. EXDI(확장 디버깅 인터페이스)는 소프트웨어 디버거와 디버깅 대상 간의 적응 계층입니다. Windows용 디버깅 도구는 Windows 버전 22000부터 EXDI를 사용하여 커널 디버깅을 지원합니다.

EXDI를 사용하여 QEMU 가상 환경과의 연결을 설정할 수 있습니다. 자세한 내용은 EXDI를 사용하여 QEMU 커널 모드 디버깅 설정을 참조하세요.

참고 항목

EXDI는 특정 환경에 대한 고급 특수한 형태의 디버깅입니다. 표준 KDNET 연결을 사용하는 것이 더 쉽게 구성할 수 있으며 권장됩니다. 네트워크 디버깅을 자동으로 설정하려면 KDNET 네트워크 커널 디버깅 자동 설정을 참조 하세요.

EXDI COM 서버 개요

EXDI는 하드웨어 디버거(예: JTAG 기반 또는 GdbServer 기반)에 대한 지원을 추가하여 WinDbg를 확장할 수 있는 인터페이스입니다. 아래 다이어그램은 EXDI-GdbServer의 역할을 보여 줍니다.

위에 WinDbg-DbgEng을 사용하는 EXDI-GdbServer의 역할, EXDI 인터페이스 및 GDB 서버와 통신하는 EXDI COM 서버를 보여 주는 스택 다이어그램

EXDI 연결은 대상 PC에 로드되는 Windows 또는 KDNET 프로토콜에 종속되지 않습니다. 이러한 소프트웨어 디버거 구성 요소는 필요하지 않으므로 EXDI는 초기 디바이스를 불러오고 OS 시작 문제를 디버깅할 때 유용할 수 있습니다.

Important

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 디버깅

일부 복잡한 시나리오에서 예를 들어 초기 디바이스를 불러올 때 대상 디바이스에 두 개의 연결을 갖는 것이 유용할 수 있습니다. EXDI 1개와 KDNET 1개. 대상이 Windows OS인 경우 KDNET 소프트웨어 디버깅은 일반적으로 가상 머신에 연결하는 것과 같이 구성됩니다. 이 설정에서는 두 개의 동시 디버거 중 하나가 중단되어 대상 컴퓨터의 코드를 디버그할 수 있습니다.

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를 사용하여 관리istrator 명령 프롬프트에 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 구성 XML 파일을 사용하여 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을 찾지 못하도록 하려면 다음 값을 0으로 설정합니다.

heuristicScanSize = "0"

XML 구성 파일의 위치를 참조하도록 EXDI 경로 값을 설정합니다.

환경 변수 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"

지정된 경로를 ExdiGdbSrvSample.dll 위치에서 사용할 수 있는지 확인하는 형식 SET 입니다.

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'

지정된 경로를 ExdiGdbSrvSample.dll 위치에서 사용할 수 있는지 확인하는 형식 dir env: 입니다.

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

창 제목에 EXDI CLSID를 표시하는 기본 WinDbg 세션입니다.

EXDIGdbServer 콘솔 창에는 EXDI 연결의 상태 대한 정보도 표시할 수 있습니다. 콘솔에 대한 자세한 내용은 문제 해결을 참조 하세요.

EXDI WinDbg 로드 매개 변수

다음 매개 변수는 WinDbg와 함께 EXDI 커널 세션을 시작하는 데 사용됩니다.

-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 기본 부하 주소의 위치를 찾습니다. 프라이빗 기호를 사용할 수 없는 경우 이 프로세스가 실패합니다.

즉, 많은 연결 시퀀스에서 중단이 예상대로 작동하지 않습니다. 코드를 수동으로 중단하면 해당 시점에 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은 기존 KDNET 기반 커널 디버깅과 달리 기호를 기반으로 중단점을 설정할 수 없으므로 EDXI 디버깅에 유용할 수 있습니다. 원하는 대상 이미지를 찾은 경우 해당 위치를 사용하여 메모리 액세스 중단점을 쉽게 설정할 수 있습니다.

.exdicmd(EXDI 명령)

.exdicmd는 활성 EXDI 디버깅 연결을 사용하여 대상 시스템에 EXDI 명령을 보냅니다. 자세한 내용은 .exdicmd(EXDI 명령)를 참조하세요.

문제 해결

ExdiGdbServer 창의 출력을 사용하여 연결 시퀀스를 모니터링합니다.

긴 16진수를 표시하는 ExdiGdbServer 텍스트 창입니다.

문제: 오류: 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 샘플은 계속되지 않습니다. 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에 연결할 수 없으므로 다음으로 인해 실패할 수 있는 일반적인 오류입니다.

  • 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:포트 값이 포함되어 있습니다. WinDbg 세션이 QEMU Windows VM과 동일한 호스트 PC에서 시작되면 IP=LocalHost입니다.

문제: 디버깅 세션을 시작할 수 없습니다. FAILURE HR=0x80004005:AttachKernel에 실패했습니다.

이 문제는 다음으로 인해 발생할 수 있습니다.

  • 위에서 설명한 대로 ExdiGdbSrv.dll 이전 세션이 여전히 활성 상태일 수 있습니다. 위에서 설명한 대로 연결된 DLL 호스트를 찾아서 종료합니다.

HR 0x80004005 오류를 표시하는 WinDbg 대화 상자

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 - 이 파일에는 시스템 레지스터와 해당 액세스 코드 간의 매핑이 포함되어 있습니다. 액세스 코드는 GDB 서버에서 xml 파일에서 제공되지 않고 디버거가 액세스 코드를 통해 각 시스템 레지스터에 액세스하기 때문에 필요합니다. 환경 변수 EXDI_SYSTEM_REGISTERS_MAP_XML_FILE를 통해 파일을 설정하지 않으면 ExdiGdbSrv.dll 계속 작동하지만 디버거는 rdmsr 또는 wrmsr 명령을 통해 시스템 레지스터에 액세스할 수 없습니다. 이러한 레지스터 목록은 GDB 서버 하드웨어 디버거에서 지원해야 합니다(특정 시스템 레지스터 이름은 시스템 xml 파일에 전송된 레지스터 목록에 있어야 함).

GDBServer 태그 및 특성

다음 표에서는 파일에 정의된 GDBServer 태그 및 특성에 대해 exdiConfigData.xml 설명합니다.

매개 변수 설명
ExdiTargets exdiConfigData.xml 파일에는 현재 ExdiGdbSrv.dll 지원되는 모든 GDB 서버가 포함되어 있으므로 ExdiGgbSrv.dll GDB 서버 대상과의 GDB 연결을 설정하는 데 사용할 특정 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 서버는 "QMS.windbg" 이름을 보내서 windbg-GDB 클라이언트를 식별한 다음 MS GDB 서버 클라이언트(exdiGdbSrv.dll)에 대해서만 지원되는 사용자 지정된 GDB 메모리 패킷을 사용하도록 설정 ExdiGdbSrv.dll해야 합니다.
ExdiGdbServerConfigData ExdiGdbSrv.dll 구성 요소 관련 구성 매개 변수를 지정합니다.
uuid 는 ExdiGdbSrv.dll 구성 요소의 UUI를 지정합니다.
displayCommPackets '예'인 경우 플래그를 지정하면 명령 로그 창에 RSP 프로토콜 통신 문자가 표시됩니다. '아니요'이면 요청-응답 쌍 텍스트만 표시합니다.
enableThrowExceptionOnMemoryErrors 이 특성은 GDB 오류 응답 패킷(E0x)이 있을 때 GDB 서버 클라이언트가 검사 예외를 throw하고 메모리 읽기를 중지해야 하는지 여부를 확인합니다.
qSupportedPacket 이렇게 하면 GDB 클라이언트가 xml 대상 설명 파일 다음에 GDB 서버 HW 디버거가 전송해야 하는 xml 레지스터 아키텍처 파일을 요청하도록 구성할 수 있습니다(기본적으로 클라이언트는 클라이언트에서 지원하는 아키텍처를 GDB 서버에 알릴 것이며, 현재 클라이언트는 x64 아키텍처를 지원합니다).
ExdiGdbServerTargetData GdbServer 세션에서 디버그하는 하드웨어 대상과 관련된 매개 변수를 지정합니다.
targetArchitecture 대상 하드웨어 아키텍처를 포함하는 문자열입니다. 가능한 값: X86, X64, ARM, ARM64. 현재 exdiGdbSrv.dll X86 및 ARM만 지원합니다.
targetFamily 대상 하드웨어 패밀리를 포함하는 문자열입니다. 가능한 값: ProcessorFamilyX86, ProcessorFamilyX64, ProcessorFamilyARM, ProcessorFamilyARM64.
numberOfCores 대상이 지원하는 프로세서 코어 수입니다. 이 매개 변수는 다중 Gdbserver 세션(T32-GdbServer 세션)을 사용할 때 유효성이 검사됩니다. 아래 'MultiCoreGdbServerSessions' 특성은 '예'로 설정해야 합니다.
EnableSseContext 'yes'인 경우 플래그를 지정하면 'g' 컨텍스트 RSP 패킷에 부동 소수점 레지스터 값이 포함됩니다. 이 매개 변수는 Intel 제품군 대상에만 적합합니다.
heuristicScanSize 이렇게 하면 지정된 크기로 스캔된 메모리 프로브를 줄이도록 디버거 엔진의 빠른 추론 알고리즘이 구성됩니다. 특성 값 이 지정되지 않은 경우(또는 "0"), 디버거 엔진은 빠른 추론을 사용하지 않고 PE DOS 서명을 찾는 전체 메모리를 검사하는 레거시 추론으로 대체됩니다.
targetDescriptionFile 는 GDB 서버가 각 개별 xml 파일을 보내기 전에 대상 설명 헤더 파일을 보내는지 지정합니다. 이 필드는 비어 있으면 GDB 서버 클라이언트가 xml 아키텍처 시스템 레지스터를 요청하지 않습니다(예: 별도의 xml 파일에서 아키텍처 레지스터 전송을 지원하지 않는 Trace32 GDBs 서버).
GdbServer커넥트ionParameters GdbServer 세션 매개 변수를 지정합니다. 이러한 매개 변수는 ExdiGdbSrv.dll 구성 요소와 GdbServer 간의 RSP GdbServer 세션을 제어하는 데 사용됩니다.
MultiCoreGdbServerSessions 플래그가 '예'이면 다중 코어 GdbServer 세션(T32-GdbServer 백 엔드에서 사용되는 세션)이 있습니다. '아니요'이면 GdbServer의 인스턴스 하나만 통신합니다.
MaximumGdbServerPacketLength 이는 한 패킷에 대해 지원되는 최대 GdbServer 길이입니다.
최대커넥트미트 최대 연결 시도입니다. 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 "예"이면 GDB 서버는 사용자 지정된 메모리 명령을 지원합니다(예: 시스템 레지스터, Trace32 GDB 서버에 대해 설정해야 함).
PhysicalMemory "예"이면 GDB 서버는 실제 메모리를 읽기 위한 사용자 지정된 명령을 지원합니다(Trace32 GDB 서버에 대해 설정됨).
SupervisorMemory "yes"이면 GDB 서버는 감독자 메모리를 읽기 위한 사용자 지정된 명령을 지원합니다(Trace32 GDB 서버에 대해 설정됨).
SpecialMemoryRegister "예"이면 GDB 서버는 시스템 레지스터를 읽기 위한 사용자 지정된 명령을 지원합니다(Trace32 GDB 서버에 대해 설정됨).
SystemRegistersGdbMonitor "예"이면 GDB 서버는 GDB 모니터 명령을 통해 사용자 지정된 명령을 지원합니다(BMC Open-OCD에 대해 설정됨).
SystemRegisterDecoding "예"이면 GDB 클라이언트는 GDB 모니터 명령을 보내기 전에 액세스 코드 디코딩을 허용합니다.
ExdiGdbServerRegisters 특정 아키텍처 레지스터 코어 집합을 지정합니다.
아키텍처 정의된 레지스터 집합의 CPU 아키텍처입니다.
FeatureNameSupported xml 시스템 레지스터 설명 파일에서 제공하는 시스템 레지스터 그룹의 이름입니다. GDB 서버에서 보낸 xml 파일의 일부인 시스템 레지스터 xml 그룹을 식별해야 합니다.
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 heuristicScanSize의 값을 0xfffe(NT에 가장 적합)에서 0xffe(사전 NT 앱의 경우)로 변경합니다.
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 네트워크 커널 디버깅 설정

수동으로 커널 모드 디버깅 설정