Debugger QEMU Platforms¶
This document described different ways to debug on the QEMU platforms.
Debugging using UEFI debugger¶
Both Q35 and SBSA are setup to debug debugged using the MU debugger package. for more details on using this debugger, see the FeatureDebuggerPkg Readme.
By default the debugger is enabled to break in on exceptions, but not to break in on an initial breakpoint. To enable the initial breakpoint in DXE, you must pass:
stuart_build -c Platforms\QemuQ35Pkg\PlatformBuild.py BLD_*_DXE_DBG_BRK=TRUE --FlashRom
On Q35 this allows for debugging over a different port then the usual debug output
because Q35 has a seperate serial port available to it. On SBSA the serial port
will be shared with the logging output. As a result, on Q35, if SERIAL_PORT=<PORT>
is not passed on the cmdline, a default serial port at 50001 will be created. On SBSA,
no default port is set because it will prevent output from occuring on stdout, which
makes even telling if an exception occurred difficult.
Currently this will only enable the DXE debugger. The MM debugger will be added to Q35 once it support supervised Standalone MM.
When an exception occurs, the debugger will break in and wait for a debugger client to connect. This makes Q35 and SBSA very debuggable, because they will break in on exceptions always, meaning a reboot is not required.
Debugging using QEMU GDB Server¶
QEMU has the ability to expose a GDB port for debugging. This can be leveraged several ways. To start enable the GDB server, add the following parameter when launched QEMU through the QEMU runner.
GDB_SERVER=<port number>
Example ports can be: 1234, 5000, 5001, etc.
Windbg Integration¶
Windbg supports source debugging QEMU through an EXDI interface with the GDB port. Details can be found on the github readme. This supplies a EXDI server binary, a configuration file, and a script to start Windbg bound to the EXDI interface.
Once Windbg is connected, following the instruction in the readme, the symbols and source can be loaded. This is most easily done using the UEFI debugger extension. This can also be done manually by scanning memory for images using the image scan command. For example:
kd> r rip
rip=000000007d1fc64b
kd> .imgscan /l /r 0x07d000000 0x07e000000
This will scan for image headers between the specified addresses and load their symbols. More information on this command can be found in the Windbg help window.
Debugging Using GDB in VS Code¶
For GCC builds, GDB can be used to debug instead. The symbols can be loaded by
running source MU_BASECORE/BaseTools/Scripts/efi_gdb.py
from within GDB while
stopped. To connect GDB to the built in VS Code debugger, you can use the following
launch configuration to connect to a running instance of QEMU.
{
"name": "Connect to GDB Server (X64)",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceRoot}/Build/QemuQ35Pkg/DEBUG_GCC5/X64/DxeCore.debug",
"miDebuggerServerAddress": "localhost:1234",
"cwd": "${workspaceRoot}",
"environment": [],
"MIMode": "gdb",
"miDebuggerPath": "gdb",
"stopAtConnect": true
},
{
"name": "Connect to GDB Server (AARCH64)",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceRoot}/Build/QemuSbsaPkg/DEBUG_GCC5/AARCH64/DxeCore.debug",
"miDebuggerServerAddress": "localhost:1234",
"cwd": "${workspaceRoot}",
"environment": [],
"MIMode": "gdb",
"miDebuggerPath": "gdb-multiarch",
"stopAtConnect": true
},
Note that the program
value must be a legitimate binary, but does not seem to
have any affect on the debugging. Additionally, gdb
may need to be used instead
of gdb
if debugging x64 from an x64 machine.
Once attached, you can stop and run -exec source MU_BASECORE/BaseTools/Scripts/efi_gdb.py
from the DEBUG CONSOLE tab to load the EFI symbols and commands. You may need to
single step after this for symbols to take affect.
Debugging Windows on QEMU¶
Boot to OS¶
In order to kernel debug the OS, once need to boot to OS first.
-
Download original OS image in the format of VHDX or QCOW2. If the image has never been booted before, one can boot this image using Hyper-V once to get through the OOBE process, if any. Related reads:
-
Although QEMU supports both VHDX and QCOW2 images. For the sake of fail proof, it is recommended to use QCOW2 format image, which can be converted from VHDX image with:
qemu-img convert -f vhdx -p -c -O qcow2 foo.vhdx foo.qcow2
-
With the above QCOW2 image, set up the
PATH_TO_OS
parameter when launching QemuRunner.py:PATH_TO_OS=<absolute path to your OS image> SERIAL_PORT=<port number>
- More details on the
<port number>
in the corresponding section
- More details on the
Debug Windows with WinDbg on QEMU¶
Unlike EXDI debugger introduced above, this method will enlighten the target OS and debug the Windows more "traditionally", where Windows can communicate to the attached debugger with proper transports.
Configurations on Target QEMU¶
After booting to the desktop or command prompt of target Windows by following above steps, issue below commands:
bcdedit /dbgsettings serial debugport:1 baudrate:115200
bcdedit /set {default} debug on
# One can potentially enable boot debugger as well
bcdedit /set {default} bootdebug on
Configurations on Host that runs QEMU¶
Once the QEMU boots to the point where the target is accepting debugger commands, launch the WinDbg using:
windbg.exe -k com:ipport=<port number>,port=127.0.0.1 -v
where the <port number>
is the number you set when launching QEMU
Serial Console for UEFI¶
Launch terminal application such as Putty or Tera Term to connect to <port number>
you set when launching QEMU at 127.0.0.1
through raw TCP/IP
protocol.
Note:
- One needs to release this console in order for the KD to attach.
- Some terminal software would enable "local line editing" for raw connection, this needs to be turned off to prevent garbage keystrokes.