Debugging a Virtual Machine Using KDBG Protocol

By default, Parallels Desktop for Mac supports GDB for debugging virtual machines. However, there is a way to enable KDBG support and allow the use of clients like WinDbg or KD.

Note: This implementation enables debugging at the virtual machine level, regardless of what OS it is running. However, since KDBG is largely Windows-specific, some of the functionality may not be available because the kernel information is unknown and/or encrypted (e.g., kernel debug block).

Known Limitations and Unsupported Commands

The current implementation of KDBG support in Parallels Desktop for Mac can only be used as a raw debugger, with little to no connection with the kernel itself.

The following commands are not supported or have limited support for now:

  • Software breakpoints (not supported).

  • Read and write I/O ports (not supported).

  • Read and write bus data (not supported).

  • Reboot and bugchecks (these will force a disconnection)

  • Special calls (not supported).

Enabling KDBG Support in Parallels Desktop

To enable KDBG support, you have to manually edit the configuration file for the target machine:

  1. In the Control Center, right-click on the target machine and select Show in Finder.

  2. Right-click on the virtual machine's .pvm file and select Show Package Contents.

  3. Right-click on the config.pvs file, select Open With, and choose your preferred text editor.

  4. Use the search functon to find the <SystemFlags> section, which should be empty by default, and populate it following the table below.

  5. Save the edits to the config.pvs file.

Here are the system flags that you may want to use:

Flag
Description

vm.debug

Enable (1) or disable (0) the debugger.

vm.debug.protocol

Select the debug protocol that should be used: 0 for GDB protocol or 1 for KDBG/WinDbg protocol.

vm.debug.local_addr

Local IPv4 address to bind the UDP socket.

vm.debug.host_addr

Remote IPv4 address where the host is located.

vm.debug.windbg_stub.guest.port

UDP port used to communicate with the host.

vm.debug.key

A preset encryption key used to communicate with the host: a string of exactly four values in the format

<text>.<text>.<text>.<text>, where <text> is a sequence of decimal digits or letters with a maximum size of 12 characters (i.e. regular expression: [0-9a-z]{1,12}). Examples: 1a.2b.3c.4d, or this.is.my.key, or aaaaaaaaaaaa.bbbbbbbbbbbb.cccccccccccc.dddddddddddd.

vm.efi.monitor

Enable (1) or disable (0) the monitor functions in the EFI BIOS.

vm.efi.kernel_address

Enable (1) or disable (0) the search for the kernel base address.

vm.efi.kernel_modules

Enable (1) or disable (0) the search for the list of modules loaded by the kernel.

Here is an example of a configuation:

<SystemFlags>
vm.efi.monitor=1;
vm.efi.kernel_address=1;
vm.efi.kernel_modules=1;
vm.debug=1;
vm.debug.protocol=1;
vm.debug.local_addr=192.168.1.189;
vm.debug.windbg_stub.guest.port=50000;
vm.debug.key=aaaaaaaaaaaa.bbbbbbbbbbbb.cccccccccccc.dddddddddddd;
vm.debug.host_addr=192.168.1.205;
</SystemFlags>

This configuration implies a host located at 192.168.1.205 using a pre-shared encryption key aaaaaaaaaaaa.bbbbbbbbbbbb.cccccccccccc.dddddddddddd to debug a target at 192.168.1.189 via port 50000.

You may forgo explicitly specifying the host address, in which case you will have to specify the target's address in the debugging software that you use, prompting the host to send a special "poke" packet first to help the target identify it.

Following a reboot, the target machine will start sending packets to the host, ready to be debugged.

What Happens When the Connection Gets Interrupted

KDBG protocol doesn’t have a mechanism to terminate a connection, so the Parallels implementation forces the disconnect after 16 bad packets, or no packets at all for 10 minutes.

Since all traffic is encrypted using a data channel/session key, attemting to reestablish a dropped connection is not feasible.

Since UDP is not the most reliable protocol, the data channel may sometimes get out of sync, in which case the debugger appears to freeze. When that happens, the only way to fix it is to wait for the 10 minutes for a forced disconnection.

Most Common Commands

These are the most common commands that you can use and that are supported:

  • r - read/write registers. Ex.: “r”, “r x0 = 0”

  • u - unassemble. Ex.: “u pc”

  • d - display memory. Ex.: “d sp”, “db sp” (display as bytes), “dw sp” (display as words)

  • e - edit memory. Ex.: “eb sp ff”, “ew x0 1234”

  • rdmsr - read machine specific register. Ex.: “rdmsr c100” (c100 = TTBR0)

  • wrmsr - write machine specific register. Ex.: “wrmsr c100 00000000`00000000” (c100 = TTBR0)

  • ba - set break on access. Ex: “ba 1 e ffffeeee” (break on execute, 1 byte at ffffeeee)

  • be - enable breakpoint. Ex: “be 0” (enable breakpoint 0)

  • bd - disable breakpoint. Ex: “bd 0” (disable breakpoint 0)

  • bl - list breakpoints. Ex.: “bl”

  • p - step. Ex.: “p”

  • ~N - switch vcpu. Ex.: “~0”, “~1”

  • f - fill memory. Ex.: “f x0 L8 0 1 2 3” (fill 8 bytes at x0 with pattern 0 1 2 3)

  • s - search memory. Ex. “s sp L100 fe ff” (search for pattern fe ff at [sp, sp + 100])

Last updated